পাঠ ০২ · ৫৭-এর মধ্যে · মডিউল ১
Home / Courses / Digital Signal Processing / ফাউন্ডেশন

কন্টিনিউয়াস বনাম ডিসক্রিট সিগন্যাল — স্যাম্পলিং-এর ভিত্তি

Continuous vs discrete signals — sampling basics
৯ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • কন্টিনিউয়াস-টাইম $x(t)$ ও ডিসক্রিট-টাইম $x[n]$ সিগন্যালের গাণিতিক পার্থক্য
  • স্যাম্পল রেট $f_s$, স্যাম্পলিং পিরিয়ড $T_s = 1/f_s$, এবং $x[n] = x(nT_s)$ সম্পর্ক
  • একটি সত্যিকারের, চলমান ডেমো — একটি সাইন-তরঙ্গকে সত্যিই স্যাম্পল করে ডিসক্রিট তালিকা বানানো
  • কেন স্যাম্পলগুলোর মাঝের মান "হারিয়ে" যায় এবং এটি কেন গুরুত্বপূর্ণ (M2-এ অ্যালিয়াসিং-এর ভিত্তি)

১ · কন্টিনিউয়াস-টাইম সিগন্যাল কী

একটি কন্টিনিউয়াস-টাইম সিগন্যালContinuous-time signalএমন একটি সিগন্যাল $x(t)$ যা প্রতিটি বাস্তব সংখ্যা $t$-এর জন্য সংজ্ঞায়িত — সময়ের অক্ষে কোনো ফাঁক নেই। $x(t)$ হলো এমন একটি ফাংশন যা সময়ের প্রতিটি মুহূর্তে ($t$ যেকোনো বাস্তব সংখ্যা হতে পারে — $1.0$, $1.001$, $1.0001$, ...) একটি মান দেয়। বাস্তব-জগতের প্রায় সব ভৌত রাশি — বাতাসের চাপ (শব্দ), ভোল্টেজ, তাপমাত্রা — কন্টিনিউয়াস-টাইম, কারণ সময় নিজেই কন্টিনিউয়াস। গাণিতিকভাবে এমন একটি সিগন্যাল $x(t) = \sin(2\pi f t)$ আকারে লেখা যায়, যেখানে $t$ যেকোনো বাস্তব মান নিতে পারে।

সমস্যা হলো — একটি কম্পিউটার বা মাইক্রোকন্ট্রোলার অসীম সংখ্যক মান সংরক্ষণ করতে পারে না। $t = 0$ থেকে $t = 1$ সেকেন্ডের মধ্যেও অসীম সংখ্যক $t$ মান আছে ($0.1$, $0.11$, $0.111$, ...) — তাই একটি কন্টিনিউয়াস সিগন্যালকে হুবহু ডিজিটাল মেমোরিতে রাখা অসম্ভব। এখানেই স্যাম্পলিং দরকার হয়।

২ · ডিসক্রিট-টাইম সিগন্যাল ও স্যাম্পলিং

স্যাম্পলিংSamplingএকটি কন্টিনিউয়াস সিগন্যাল $x(t)$-কে নির্দিষ্ট সময় বিরতিতে ($T_s$ সেকেন্ড পরপর) মেপে একটি সসীম-ঘনত্বের সংখ্যার তালিকা $x[n]$ বানানোর প্রক্রিয়া। মানে $x(t)$-কে প্রতি $T_s$ সেকেন্ড পরপর একবার "মাপা" — ফলাফল একটি ডিসক্রিট-টাইম সিগন্যাল $x[n]$, যেখানে $n = 0, 1, 2, \ldots$ শুধু পূর্ণসংখ্যা। সম্পর্কটি হলো:

$$x[n] = x(nT_s), \qquad T_s = \frac{1}{f_s}$$

যেখানে $f_s$ হলো স্যাম্পল রেট (প্রতি সেকেন্ডে কতগুলো স্যাম্পল, একক Hz)। খেয়াল করুন — $x[n]$ একটি সাধারণ Python list-এর মতোই আচরণ করে: $n$ একটি ইনডেক্স, আর $x[n]$ সেই ইনডেক্সের মান। এই কোর্সের বাকি সবকিছু — কনভোলিউশন, Z-ট্রান্সফর্ম, DFT — এই $x[n]$ তালিকার উপরই কাজ করে, $x(t)$-এর উপর নয়।

$x(t)$ — কন্টিনিউয়াস
প্রতিটি বাস্তব $t$-এর জন্য সংজ্ঞায়িত, অসীম রেজোলিউশন, কিন্তু ডিজিটাল মেমোরিতে সংরক্ষণযোগ্য নয়।
$x[n]$ — ডিসক্রিট
শুধু পূর্ণসংখ্যা $n$-এর জন্য সংজ্ঞায়িত, একটি সসীম তালিকা, সরাসরি Python list-এ সংরক্ষণযোগ্য।
$T_s = 1/f_s$
দুটো পরপর স্যাম্পলের মধ্যে সময়ের ব্যবধান — $f_s$ বেশি হলে $T_s$ কম, স্যাম্পলগুলো ঘনভাবে নেওয়া হয়।

৩ · একটি সত্যিকারের ডেমো — সাইন-তরঙ্গ স্যাম্পল করা

ধরা যাক একটি সিগন্যাল প্রকৃতপক্ষে ৩ Hz-এ কম্পিত হচ্ছে (কন্টিনিউয়াস, প্রতি মুহূর্তে একটি মান আছে), আর আমরা এটিকে ২০ Hz রেটে, মোট ০.৫ সেকেন্ড ধরে স্যাম্পল করছি। নিচের কোড সেল math.sin-এর উপর একটি লিস্ট কমপ্রিহেনশন দিয়ে প্রকৃত ডিসক্রিট স্যাম্পলগুলো বানায় এবং প্রতিটি স্যাম্পলের সময় ও মান একটি টেবিলে দেখায়।

Python
import math

f = 3.0        # সিগন্যালের প্রকৃত ফ্রিকোয়েন্সি (Hz) -- একটি কন্টিনিউয়াস ভৌত রাশি ধরে নিচ্ছি
fs = 20.0      # স্যাম্পল রেট (Hz)
T = 0.5        # মোট সময়কাল (সেকেন্ড)
N = int(fs * T)  # মোট স্যাম্পল সংখ্যা

# x[n] = x(n*Ts) = sin(2*pi*f*n/fs) -- সরাসরি সংজ্ঞা থেকে
samples = [math.sin(2 * math.pi * f * n / fs) for n in range(N)]

print(f"N = {N} samples, Ts = 1/fs = {1/fs} s")
print(f"{'n':>3} | {'t=n*Ts (s)':>10} | {'x[n]':>10}")
for n in range(N):
    t = n / fs
    print(f"{n:>3} | {t:>10.3f} | {samples[n]:>10.6f}")

    
আউটপুট থেকে দেখা যায় — N = 10 টি স্যাম্পল পাওয়া যায় ($f_s \times T = 20 \times 0.5$), $T_s = 0.05$ সেকেন্ড, আর $x[0] = 0.000000$, $x[1] = 0.809017$, $x[2] = 0.951057$, ..., $x[5] = -1.000000$ (সিগন্যালের সর্বনিম্ন বিন্দু, $t = 0.25$ সেকেন্ডে, যা ৩ Hz তরঙ্গের ঠিক তিন-চতুর্থাংশ পিরিয়ড)। এই ১০টি সংখ্যাই এখন থেকে "সিগন্যাল" — মূল কন্টিনিউয়াস $\sin(2\pi \cdot 3t)$ ফাংশনটি আর সরাসরি পাওয়া যাচ্ছে না, শুধু এই তালিকা।

৪ · স্যাম্পলগুলোর মাঝে কী থাকে

এখানেই একটি গুরুত্বপূর্ণ, প্রায়ই ভুল বোঝা ধারণা আসে। কন্টিনিউয়াস সিগন্যাল $x(t)$ দুটো স্যাম্পলের মাঝেও সংজ্ঞায়িত থাকে — যেমন $n=0$ ($t=0$) আর $n=1$ ($t=0.05$)-এর ঠিক মাঝখানে, $t = 0.025$ সেকেন্ডে, $x(t)$-এর একটি প্রকৃত মান আছে। কিন্তু ডিসক্রিট সিগন্যাল $x[n]$-এ $n=0.5$ বলে কিছু নেই — ইনডেক্স শুধু পূর্ণসংখ্যা। নিচের কোড সেল ঠিক এই বিন্দুর "প্রকৃত" মান গণনা করে দেখায়, শুধু তুলনার জন্য (এটি খুবই ঘন রেটে, ৪০০ Hz-এ, রেফারেন্স পয়েন্ট বানিয়ে অনুকরণ করা হয়েছে — বাস্তব হার্ডওয়্যার কখনোই এই মান দেখে না)।

Python
import math

f = 3.0
fs = 20.0
T = 0.5

# "প্রকৃত" কন্টিনিউয়াস তরঙ্গের একটি খুব ঘন রেফারেন্স -- শুধু ইলাস্ট্রেশনের জন্য,
# বাস্তব হার্ডওয়্যার এই পয়েন্টগুলো কখনোই দেখে না
dense_rate = 400.0
dense = [math.sin(2 * math.pi * f * k / dense_rate) for k in range(int(dense_rate * T))]
print(f"dense reference points (কখনো observe করা হয় না): {len(dense)}টি, রেট {dense_rate} Hz")

# n=0 আর n=1 স্যাম্পলের ঠিক মাঝের সময়
t_between = 0.5 / fs
true_between = math.sin(2 * math.pi * f * t_between)
print(f"t = {t_between:.4f}s (n=0 আর n=1-এর ঠিক মাঝে): কন্টিনিউয়াস মান = {true_between:.6f}")
print("কিন্তু ডিসক্রিট সিগন্যাল x[n]-এ n=0.5 বলে কিছু নেই -- এই মান কখনো ডেটাতে থাকে না")

    
গণনা দেখায় $t = 0.025$ সেকেন্ডে কন্টিনিউয়াস তরঙ্গের প্রকৃত মান ০.৪৫৩৯৯০ — এটি $x[0]=0$ আর $x[1]=0.809017$-এর মাঝামাঝি একটি মান (যদিও সরল গড় নয়, কারণ সাইন রৈখিক নয়)। এই মান আমাদের স্যাম্পল তালিকায় কখনোই নেই এবং কখনো থাকবেও না — কেবল স্যাম্পল রেট আরও বাড়ালে (নিচের অনুশীলনে দেখুন) নতুন স্যাম্পল পয়েন্ট এর কাছাকাছি জায়গায় বসতে পারে, কিন্তু ঠিক $t=0.025$s-এর মান কখনোই সরাসরি পরিমাপ করা হবে না যদি না $f_s$ ঠিক সেই মুহূর্তে একটি স্যাম্পল বসায়।
মূল কথা · Key takeaway

স্যাম্পলিং একটি একমুখী তথ্য-সংকোচন — অসীম কন্টিনিউয়াস তথ্য থেকে একটি সসীম ডিসক্রিট তালিকা তৈরি হয়, আর সেই প্রক্রিয়ায় স্যাম্পলগুলোর মাঝের সব তথ্য হারিয়ে যায়। এই তালিকা কতটা ভালোভাবে মূল সিগন্যালকে প্রতিনিধিত্ব করে তা নির্ভর করে $f_s$ কতটা বড় তার উপর — এই প্রশ্নের সঠিক উত্তরই নাইকুইস্ট-শ্যানন স্যাম্পলিং থিওরেম (M2, L05), আর ভুল উত্তর হলে যা ঘটে তা অ্যালিয়াসিং (L01-এর ডেমো, বিস্তারিত M2-এর L06-এ)।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ কেন আমরা কন্টিনিউয়াস সিগন্যালকে $x(t)$ (বন্ধনী দিয়ে) আর ডিসক্রিট সিগন্যালকে $x[n]$ (স্কয়ার ব্র্যাকেট দিয়ে) লিখি — এই নোটেশনের পার্থক্যটা কি শুধু ঐতিহ্য, নাকি অর্থবহ?

অর্থবহ। $x(t)$-এ $t$ যেকোনো বাস্তব সংখ্যা হতে পারে (কন্টিনিউয়াস ডোমেইন), তাই এটি একটি ফাংশনের মতো বন্ধনী দিয়ে লেখা হয়। $x[n]$-এ $n$ শুধু পূর্ণসংখ্যা (ডিসক্রিট ডোমেইন), যেন এটি একটি তালিকা বা সিকোয়েন্সের ইনডেক্স — Python-এ x[n] লেখার সাথে সরাসরি মেলে। এই নোটেশন পার্থক্যটা দেখেই বোঝা যায় কোন ডোমেইনে কাজ চলছে।

প্র ০২ উপরের ডেমোতে $f_s = 20$ Hz-এ $N = 10$টি স্যাম্পল পাওয়া গেল $T = 0.5$ সেকেন্ডে। যদি $f_s$ দ্বিগুণ করে ৪০ Hz করা হয় (একই $T = 0.5$s রেখে), তাহলে $T_s$ আর $N$ কত হবে?

$T_s = 1/f_s = 1/40 = 0.025$ সেকেন্ড (আগের অর্ধেক), আর $N = f_s \times T = 40 \times 0.5 = 20$টি স্যাম্পল (আগের দ্বিগুণ)। আকর্ষণীয় ব্যাপার — নতুন $n=1$ স্যাম্পলটি ঠিক $t = 0.025$s-এ বসে, যা উপরের অংশ ৪-এর কোড সেলে গণনা করা "মাঝের" বিন্দু! অর্থাৎ $f_s$ বাড়ালে আগের "না-দেখা" মুহূর্তগুলোর কাছাকাছি (বা ঠিক তার উপর) নতুন প্রকৃত স্যাম্পল বসে — কিন্তু তখনও তাদের মাঝেও নতুন "না-দেখা" মুহূর্ত থেকে যায়।

প্র ০৩ একটি ফ্লিপবুক (কার্টুন বই যেখানে পাতা উল্টালে ছবি নড়াচড়া করে মনে হয়) কীভাবে কন্টিনিউয়াস বনাম ডিসক্রিট সিগন্যালের এই পার্থক্যের একটি বাস্তব উদাহরণ?

একটি ব্যক্তির প্রকৃত নড়াচড়া কন্টিনিউয়াস — শরীরের অবস্থান প্রতিটি মুহূর্তে সংজ্ঞায়িত। ফ্লিপবুকের প্রতিটি পাতা একটি "স্যাম্পল" — একটি নির্দিষ্ট মুহূর্তের ছবি, যেমন $x[n]$। পাতাগুলোর মাঝে আসলে কী ঘটেছিল তা বইয়ে নেই — মস্তিষ্ক দ্রুত পাতা উল্টানোর সময় সেই "মাঝের" অংশ নিজে থেকে অনুমান করে (ইন্টারপোলেট করে) মসৃণ নড়াচড়ার বিভ্রম তৈরি করে। পাতার সংখ্যা কম হলে (কম $f_s$) নড়াচড়া থমথমে (jerky) লাগে — ঠিক যেমন কম স্যাম্পল রেটে একটি ডিজিটাল সিগন্যাল মূল কন্টিনিউয়াস তরঙ্গকে খারাপভাবে প্রতিনিধিত্ব করে।

অনুশীলন

  1. চিন্তা করুন: ৩ নং অংশের কোড সেলে f = 3.0-কে f = 5.0-এ বদলালে (fs = 20 Hz অপরিবর্তিত রেখে), x[5]-এর মান কত হবে বলে আপনার ধারণা? সূত্র sin(2*pi*f*n/fs) দিয়ে $n=5$-এর জন্য নিজে হিসেব করার চেষ্টা করুন।

    $x[5] = \sin(2\pi \times 5 \times 5 / 20) = \sin(2\pi \times 1.25) = \sin(2.5\pi)$। যেহেতু সাইন-তরঙ্গ $2\pi$ পিরিয়ডিক, $2.5\pi = 0.5\pi + 2\pi$, তাই এটি $\sin(0.5\pi) = 1.0$-এর সমান। অর্থাৎ x[5] = 1.0 (সর্বোচ্চ বিন্দু)।

  2. পরীক্ষা করুন: ৩ নং অংশের কোড সেলে f = 3.0-কে f = 5.0-এ পরিবর্তন করে Run চেপে আপনার হিসেব যাচাই করুন।

    রান করলে সত্যিই x[5] = 1.000000 দেখাবে (সরাসরি Python-এ চালিয়ে যাচাই করা হয়েছে)। আরও লক্ষ্য করুন — $f=5$ Hz আর $f_s=20$ Hz হওয়ায় প্রতি পিরিয়ডে ঠিক $20/5=4$টি স্যাম্পল পড়ে, তাই x[1]=1.0, x[3]=-1.0, x[5]=1.0, x[7]=-1.0 — একটি পরিষ্কার, পুনরাবৃত্ত প্যাটার্ন।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

  • কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ স্যাম্পলিং, কনভোলিউশন, Z-ট্রান্সফর্ম, DTFT/DFT, FFT, FIR/IIR ফিল্টার ডিজাইন, মাল্টিরেট প্রসেসিং, স্পেকট্রাল এস্টিমেশন, র‍্যান্ডম সিগন্যাল প্রসেসিং, বাস্তব প্রয়োগ ও ক্যাপস্টোন — বাকি পাঠগুলো শীঘ্রই যুক্ত হবে।
  • Math for AI & ML কোর্স সহোদর কোর্স ট্রিগোনোমেট্রিক ফাংশন, কমপ্লেক্স সংখ্যা ও লিনিয়ার অ্যালজেব্রার ভিত্তি — এই পাঠের সাইন-তরঙ্গের গাণিতিক ভিত্তি সেখান থেকে আরও গভীরভাবে বোঝা যাবে।
  • সব Courses দেখুন ABCL TECH C, C++, Python, Java, JavaScript, DSA, Machine Learning, Deep Learning, System Design, Cybersecurity, Cloud Computing & DevOps, এবং আরও অনেক কোর্স — সব এক জায়গায়।
আগের পাঠ
DSP কী এবং কেন এটি গুরুত্বপূর্ণ