কজালিটি, স্ট্যাবিলিটি ও BIBO স্ট্যাবিলিটি
এই পাঠে যা শিখবেন
- কজালিটির সংজ্ঞা এবং কোড দিয়ে একটি সিস্টেম কজাল কিনা তা যাচাই করা
- BIBO স্ট্যাবিলিটির সংজ্ঞা এবং বাউন্ডেড ইনপুট দিয়ে আউটপুট বাউন্ডেড থাকে কিনা তা পরীক্ষা করা
- একটি রিকার্সিভ সিস্টেমের কোয়েফিসিয়েন্ট (pole-এর মান) কীভাবে স্ট্যাবিলিটি নির্ধারণ করে তা বোঝা
- একটি প্রকৃত অস্থির সিস্টেমের সূচকীয় বৃদ্ধি সরাসরি চোখে দেখা, নিরাপদে নিয়ন্ত্রিত একটি ডেমোতে
১ · কজালিটি — ভবিষ্যতের উপর নির্ভরতা নেই
একটি সিস্টেম কজাল (causal) হয় যদি তার আউটপুট y[n] শুধুমাত্র বর্তমান বা
অতীতের ইনপুট (x[n], x[n-1], x[n-2], \ldots) ব্যবহার করে — কখনো ভবিষ্যতের ইনপুট
(x[n+1], x[n+2], \ldots) ব্যবহার করে না। বাস্তব-সময়ের (real-time) যেকোনো সিস্টেমকে
অবশ্যই কজাল হতে হবে, কারণ ভবিষ্যতের ডেটা এখনো আসেইনি। নিচের কোডে দুটো সিস্টেম তুলনা করা হয়েছে — একটি
L12-এর পরিচিত কজাল সিস্টেম, আরেকটি ইচ্ছাকৃতভাবে অ-কজাল (non-causal)।
def system_A(x, n):
"""y[n] = 0.5*x[n] + 0.5*x[n-1] -- শুধু অতীত/বর্তমান স্যাম্পল লাগে"""
xn = x[n]
xn_1 = x[n - 1] if n - 1 >= 0 else 0.0
used_indices = [n] if n - 1 < 0 else [n, n - 1]
return 0.5 * xn + 0.5 * xn_1, used_indices
def system_B(x, n):
"""y[n] = 0.5*x[n] + 0.5*x[n+1] -- একটি ভবিষ্যত স্যাম্পল লাগে!"""
xn = x[n]
xn1 = x[n + 1] if n + 1 < len(x) else 0.0
used_indices = [n] if n + 1 >= len(x) else [n, n + 1]
return 0.5 * xn + 0.5 * xn1, used_indices
x_test = [1, 2, 3, 4, 5, 6]
def check_causality(system, x, name):
causal = True
offenders = []
for n in range(len(x)):
_, used = system(x, n)
for idx in used:
if idx > n:
causal = False
offenders.append((n, idx))
msg = "" if causal else f" (y[{offenders[0][0]}] এর জন্য x[{offenders[0][1]}] লাগে, একটি ভবিষ্যত স্যাম্পল)"
print(f"{name}: causal = {causal}{msg}")
return causal
print("System A: y[n] = 0.5x[n] + 0.5x[n-1]")
check_causality(system_A, x_test, " ফলাফল")
print("System B: y[n] = 0.5x[n] + 0.5x[n+1]")
check_causality(system_B, x_test, " ফলাফল")
causal = True (সব ব্যবহৃত ইনডেক্স
<= n)। System B: causal = False, নির্দিষ্টভাবে ধরা পড়ে
y[0] গণনা করতে x[1] (একটি ভবিষ্যত স্যাম্পল) লাগে।
২ · BIBO স্ট্যাবিলিটি — বাউন্ডেড ইনপুটে বাউন্ডেড আউটপুট
একটি সিস্টেম BIBO স্ট্যাবল হয় যদি প্রতিটি বাউন্ডেড ইনপুট (অর্থাৎ |x[n]| \le M
কোনো সসীম M-এর জন্য, সব n-এ) সবসময় একটি বাউন্ডেড আউটপুট দেয়। একটি সাধারণ
১ম-অর্ডার রিকার্সিভ (IIR-ধরনের) সিস্টেম বিবেচনা করা যাক:
এই a মানটিই এই সিস্টেমের poleসিস্টেমের ট্রান্সফার ফাংশনের একটি বিশেষ মান, যেখানে ফাংশনের মান অসীম হয়ে যায় — M4-এ Z-ট্রান্সফর্মে এর ফরমাল সংজ্ঞা ও বিশ্লেষণ শেখানো হবে। এই সহজ ১ম-অর্ডার সিস্টেমে pole সরাসরি কোয়েফিসিয়েন্ট a-এর সমান।
— BIBO স্ট্যাবিলিটির জন্য জানা টেক্সটবুক শর্ত হলো pole-এর ম্যাগনিটিউড < 1 হতে হবে
(unit circle-এর ভেতরে, M4/L18-এ পূর্ণ প্রমাণসহ)। নিচে দুটো সিস্টেম — একটি স্ট্যাবল (a=0.5)
আর একটি ইচ্ছাকৃতভাবে অস্থির (a=1.5) — একই বাউন্ডেড ইনপুটে চালিয়ে সত্যিকারের ফলাফল দেখা যাক।
লুপটি নিরাপদে মাত্র ১৫টি স্যাম্পলে সীমাবদ্ধ রাখা হয়েছে যাতে অস্থির কেসেও সংখ্যাগুলো
নিয়ন্ত্রণের মধ্যে থাকে।
def run_iir(a, x, n_samples):
"""y[n] = a*y[n-1] + x[n], জিরো ইনিশিয়াল কন্ডিশন"""
y = []
y_prev = 0.0
for n in range(n_samples):
xn = x[n] if n < len(x) else 0.0
yn = a * y_prev + xn
y.append(yn)
y_prev = yn
return y
N_SAMPLES = 15 # লুপ নিয়ন্ত্রিত -- অস্থির কেসেও সংখ্যা নিয়ন্ত্রণের মধ্যে রাখতে
bounded_input = [1.0] * N_SAMPLES # ইউনিট স্টেপ, স্পষ্টভাবে বাউন্ডেড: |x[n]| <= 1
a_stable = 0.5
a_unstable = 1.5
y_stable = run_iir(a_stable, bounded_input, N_SAMPLES)
y_unstable = run_iir(a_unstable, bounded_input, N_SAMPLES)
print(f"System C: y[n] = {a_stable}*y[n-1] + x[n] (pole ম্যাগনিটিউড |{a_stable}| = {abs(a_stable)} < 1)")
print(f"{'n':>3} | {'y[n]':>12}")
for n, v in enumerate(y_stable):
print(f"{n:>3} | {v:>12.6f}")
print("সর্বোচ্চ |y[n]|:", round(max(abs(v) for v in y_stable), 6),
"-> বাউন্ডেড থাকে (স্টেডি-স্টেট = 1/(1-a) =", round(1/(1-a_stable), 4), ")")
print()
print(f"System D: y[n] = {a_unstable}*y[n-1] + x[n] (pole ম্যাগনিটিউড |{a_unstable}| = {abs(a_unstable)} >= 1)")
print(f"{'n':>3} | {'y[n]':>16}")
for n, v in enumerate(y_unstable):
print(f"{n:>3} | {v:>16.4f}")
print("সর্বোচ্চ |y[n]|:", round(max(abs(v) for v in y_unstable), 4),
"-> বাউন্ডেড ইনপুট সত্ত্বেও genuinely UNBOUNDED বৃদ্ধি")
ratio = y_unstable[-1] / y_unstable[-2]
print("y[14]/y[13] অনুপাত =", round(ratio, 4), "(n বাড়ার সাথে সাথে pole-এর মান", a_unstable, "-এর কাছাকাছি যায়)")
a=0.5): আউটপুট মসৃণভাবে
1.0 থেকে বেড়ে 1.999939-এ পৌঁছে স্টেডি-স্টেট মান 2.0-এর কাছাকাছি
স্থির হয়ে যায় — সর্বোচ্চ মান কখনোই 2.0 ছাড়ায় না, সত্যিকারভাবে বাউন্ডেড। System D
(অস্থির, a=1.5): আউটপুট 1.0 থেকে শুরু করে ক্রমাগত বেড়ে মাত্র ১৫তম স্যাম্পলে
(n=14) পৌঁছায় ৮৭৩.৭৮৭৮-এ — একটি সম্পূর্ণ বাউন্ডেড ইনপুট (x[n]=1
সবসময়) থেকে সম্পূর্ণ আনবাউন্ডেড আউটপুট, ঠিক pole ম্যাগনিটিউড 1.5 \ge 1 শর্তের ভবিষ্যদ্বাণী
অনুযায়ী। অনুপাত y[14]/y[13] \approx 1.5017 — pole-এর মান 1.5-এর দিকে দ্রুত
কনভার্জ করছে, যা নিশ্চিত করে বৃদ্ধিটি সত্যিই সূচকীয় (exponential), দৈব নয়।
BIBO স্ট্যাবিলিটি একটি textbook-প্রতিষ্ঠিত, কঠোর শর্ত — একটি রিকার্সিভ সিস্টেমের pole-এর ম্যাগনিটিউড
অবশ্যই ইউনিট সার্কেলের কঠোরভাবে ভেতরে (< 1) থাকতে হবে, নয়তো সিস্টেমটি বাউন্ডেড ইনপুটেও
আনবাউন্ডেড আউটপুট দিতে পারে — উপরের ডেমো এটি সরাসরি সংখ্যা দিয়ে দেখিয়েছে। M4-এ (বিশেষত L18) আমরা এই
একই ধারণা সাধারণ ২য়-অর্ডার সিস্টেমেও প্রসারিত করব, যেখানে pole জটিল সংখ্যা হতে পারে এবং
abs(pole) ব্যবহার করে ম্যাগনিটিউড গণনা করা হবে।
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।
প্র ০১
যদি a = 1.0 ঠিক (pole ম্যাগনিটিউড ঠিক 1, না 1-এর কম না
বেশি) হতো, তাহলে সিস্টেমটি কী আচরণ করবে বলে মনে হয়?
a=1 হলে y[n] = y[n-1] + x[n] — বাউন্ডেড ইনপুট x[n]=1 দিলে
আউটপুট প্রতিটি স্টেপে ঠিক 1 করে বাড়বে (y[n] = n+1), অর্থাৎ রৈখিকভাবে
(linearly) অসীমের দিকে যাবে — এটাও আনবাউন্ডেড, তাই এই সিস্টেমও BIBO স্ট্যাবল নয়, যদিও এটি
a=1.5-এর মতো সূচকীয়ভাবে বাড়ে না। এটাই কারণ স্ট্যাবিলিটির শর্ত কঠোরভাবে
|a| < 1, \le 1 নয়।
প্র ০২
System C ও System D-এর মধ্যে একমাত্র পার্থক্য কোয়েফিসিয়েন্ট a — একটি মাত্র সংখ্যার
পরিবর্তন কীভাবে "সবসময় নিরাপদ" থেকে "সবসময় বিপজ্জনক" আচরণে নিয়ে যেতে পারে?
কারণ রিকার্সিভ সিস্টেমে আউটপুট নিজের আগের মানের উপর নির্ভর করে — প্রতিটি নতুন স্যাম্পল আগের মানকে
a দিয়ে গুণ করে। |a| < 1 হলে বারবার গুণ করলে মান ক্রমশ ছোট হয়ে যায়
(জ্যামিতিক ক্ষয়, geometric decay), কিন্তু |a| > 1 হলে বারবার গুণ করলে মান ক্রমশ বড়
হতে থাকে (জ্যামিতিক বৃদ্ধি)। এই "থ্রেশহোল্ড এফেক্ট" (a=1-এর ঠিক দুই পাশে সম্পূর্ণ ভিন্ন
আচরণ) রিকার্সিভ/IIR সিস্টেমের একটি মৌলিক বৈশিষ্ট্য, আর এটাই কেন IIR ফিল্টার ডিজাইনে (M8) স্ট্যাবিলিটি
চেক করা অপরিহার্য একটি ধাপ।
প্র ০৩
L09-L12-এর FIR-ধরনের সিস্টেমগুলো (যেমন y[n]=0.5x[n]+0.5x[n-1]) কি কখনো BIBO
অস্থির হতে পারে? কেন বা কেন নয়?
না — একটি FIR সিস্টেম (যেখানে আউটপুট শুধু ইনপুটের উপর নির্ভর করে, নিজের আগের আউটপুটের উপর নয়) সবসময়
BIBO স্ট্যাবল, যতক্ষণ এর কোয়েফিসিয়েন্টগুলো (ইমপালস রেসপন্স h[n]) সসীম সংখ্যক এবং প্রতিটি
সসীম মানের হয়। কারণ আউটপুট হলো ইনপুটের সসীম সংখ্যক স্যাম্পলের একটি ওয়েটেড যোগফল মাত্র — কোনো
"ফিডব্যাক" নেই যা মানকে বারবার গুণ করে বাড়িয়ে দিতে পারে। এটাই FIR বনাম IIR-এর একটি বড় ব্যবহারিক
পার্থক্য (M7 বনাম M8-এ বিস্তারিত)।
অনুশীলন
-
চিন্তা করুন: System C-এর (
a=0.5) স্টেডি-স্টেট মান সূত্র1/(1-a)ব্যবহার করে হিসেব করুন যদিa = 0.8হতো তাহলে স্টেডি-স্টেট আউটপুট কত হতো (একইx[n]=1ইনপুটে)।1/(1-0.8) = 1/0.2 = 5.0— অর্থাৎa=0.8হলে সিস্টেম এখনও স্ট্যাবল (|0.8| < 1), কিন্তু স্টেডি-স্টেটে পৌঁছাতে বেশি সময় লাগবে (ধীর ক্ষয়) এবং চূড়ান্ত মানও বড় (৫.০,a=0.5-এর২.০-এর তুলনায়) —aযত1-এর কাছাকাছি, স্টেডি-স্টেট মান তত বড় হয়। -
পরীক্ষা করুন: BIBO কোড সেলে
a_stable = 0.5-কেa_stable = 0.8-এ পরিবর্তন করে Run চেপে চালান — শেষ কয়েকটিy[n]মান কি৫.০-এর কাছাকাছি স্থির হচ্ছে?হ্যাঁ — রান করলে
n=14-এy[n]প্রায় ৪.৮২৪১ দেখাবে (১৫ স্যাম্পলে এখনও পুরোপুরি5.0-এ না পৌঁছালেও ক্রমাগত কাছাকাছি যাচ্ছে) — আপনার হাতে-করা হিসেবের লক্ষ্য মান ৫.০-এর দিকেই স্পষ্টভাবে অগ্রসর হচ্ছে। লক্ষ্য করুনa=0.8-এ ১৫ স্যাম্পল পরওa=0.5-এর (যা1.999939-এ প্রায় পুরোপুরি পৌঁছে গিয়েছিল) তুলনায় স্টেডি-স্টেট থেকে অনেক দূরে —aযত1-এর কাছে যায়, স্টেডি-স্টেটে পৌঁছাতে তত বেশি স্যাম্পল লাগে — এটাই ব্যবহারিক ফিল্টার ডিজাইনে "সেটলিং টাইম" ধারণার ভিত্তি।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পরবর্তী পাঠ — Z-ট্রান্সফর্ম — সংজ্ঞা ও স্বজ্ঞা L14 মডিউল ৪ শুরু — Z-ট্রান্সফর্মের ভিত্তি, যা এই মডিউলের pole/স্ট্যাবিলিটি ধারণাগুলোকে একটি ফরমাল, বীজগাণিতিক টুলে রূপ দেবে।
- কোর্সের সম্পূর্ণ সিলেবাস দেখুন ৫৭টি পাঠ স্যাম্পলিং, কনভোলিউশন, Z-ট্রান্সফর্ম, DTFT/DFT, FFT, FIR/IIR ফিল্টার ডিজাইন, মাল্টিরেট প্রসেসিং, স্পেকট্রাল এস্টিমেশন, র্যান্ডম সিগন্যাল প্রসেসিং, বাস্তব প্রয়োগ ও ক্যাপস্টোন।
- Numerical Methods কোর্স সহোদর কোর্স সাধারণ সংখ্যাগত অ্যালগরিদম, রুট-ফাইন্ডিং, ইন্টিগ্রেশন ও ODE সলভিং-এর গভীর কভারেজ — এই কোর্স সেই একই "হাতে-লেখা" দর্শনের উপর সিগন্যাল-প্রসেসিং-নির্দিষ্ট দিকটি যোগ করে।