পাঠ ৩৫ · ৫৭-এর মধ্যে · মডিউল ৮
Home / Courses / Digital Signal Processing / IIR স্ট্রাকচার

IIR ফিল্টার — রিকার্সিভ স্ট্রাকচার

IIR filters — recursive structures
৯ মিনিট পড়া মধ্যম · Intermediate Python কোডসহ সম্পূর্ণ বাংলায়

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

  • IIR ফিল্টারের সাধারণ ডিফারেন্স ইকুয়েশন এবং কেন এতে ফিডব্যাক টার্ম থাকে
  • একটি প্রথম-অর্ডার IIR লো-পাস ফিল্টার হাতে-কলমে সিমুলেট করা এবং সত্যিকারের স্মুথিং আচরণ দেখা
  • ইমপালস রেসপন্স কম্পিউট করে দেখা কেন এটি কখনও ঠিক শূন্যে পৌঁছায় না — FIR-এর সসীম ইমপালস রেসপন্সের সাথে সরাসরি তুলনা
  • M8-এর বাকি পাঠগুলো (Butterworth, বাইলিনিয়ার ট্রান্সফর্ম, ডাইরেক্ট ফর্ম) কোথায় ফিট করবে তার একটি রোডম্যাপ

১ · IIR ফিল্টার কী — সাধারণ রূপ

M7-এ (L30) আমরা দেখেছি একটি FIR ফিল্টারের আউটপুট শুধু ইনপুটের সসীমসংখ্যক অতীত মানের উপর নির্ভর করে। একটি IIR ফিল্টারInfinite Impulse Responseএমন একটি ডিজিটাল ফিল্টার যার আউটপুট গণনায় নিজের অতীত আউটপুট মানও ব্যবহৃত হয় (ফিডব্যাক) — ফলে এর ইমপালস রেসপন্স তাত্ত্বিকভাবে অসীম দৈর্ঘ্যের। এর থেকে ভিন্ন — এটি আউটপুট গণনায় নিজের অতীত আউটপুট মানও ব্যবহার করে। সাধারণ রূপ:

$$y[n] = \sum_{k=0}^{M} b_k\,x[n-k] \;-\; \sum_{k=1}^{N} a_k\,y[n-k]$$

ডানদিকের দ্বিতীয় সামেশনটিই নতুন — এটি ফিডব্যাক বা রিকার্সিভ টার্ম। Z-ট্রান্সফর্মের ভাষায় (M4) এর মানে ট্রান্সফার ফাংশনের ডিনোমিনেটরে z-এর পাওয়ার থাকে, অর্থাৎ সিস্টেমটির পোল আছে (শুধু জিরো নয়, যেমন FIR-এর ক্ষেত্রে) — L18-এ শেখা পোল-জিরো বিশ্লেষণ এখানে সরাসরি প্রযোজ্য, এবং BIBO স্ট্যাবিলিটির জন্য (L13) প্রতিটি পোলের মান ইউনিট সার্কেলের ভেতরে থাকতে হবে।

ফিডব্যাক
আউটপুট নিজের অতীত মানের উপর নির্ভর করে — একটি স্মৃতিসম্পন্ন লুপ।
অসীম ইমপালস রেসপন্স
একটি একক ইমপালস ইনপুট দিলে আউটপুট তাত্ত্বিকভাবে কখনও ঠিক শূন্যে পৌঁছায় না।
কম অর্ডারে শার্প রেসপন্স
একই শার্পনেসের জন্য FIR-এর চেয়ে অনেক কম কোয়েফিশিয়েন্ট লাগে — কিন্তু স্ট্যাবিলিটি নিশ্চিত করতে হয়।

২ · একটি সত্যিকারের ডেমো — প্রথম-অর্ডার IIR লো-পাস

সবচেয়ে সহজ IIR ফিল্টার হলো একটি প্রথম-অর্ডার লো-পাস — এটি একটি এক্সপোনেনশিয়াল মুভিং অ্যাভারেজ-এর মতোই কাজ করে:

$$y[n] = a\,y[n-1] + (1-a)\,x[n], \qquad 0 < a < 1$$

এখানে a যত ১-এর কাছাকাছি, ফিল্টার তত বেশি "স্মৃতি" রাখে (বেশি স্মুথিং, বেশি লো-পাস আচরণ)। নিচের কোড সেলে একটি টেস্ট সিগন্যাল — একটি ধীর ৩ Hz উপাদান আর একটি দ্রুত ১৮ Hz উপাদানের যোগফল — এই ফিল্টারের মধ্য দিয়ে a = 0.8 নিয়ে পাস করানো হয়েছে, স্যাম্পল-বাই-স্যাম্পল, ঠিক যেভাবে একটি বাস্তব ডিভাইসে এটি বাস্তবায়িত হয়।

Python
import math

a = 0.8          # ফিডব্যাক কোয়েফিশিয়েন্ট (0 < a < 1)
fs = 50.0        # স্যাম্পল রেট (Hz)
N = 20

# টেস্ট সিগন্যাল: ধীর ৩ Hz + দ্রুত ১৮ Hz উপাদানের যোগফল
x = [math.sin(2 * math.pi * 3 * n / fs) + 0.5 * math.sin(2 * math.pi * 18 * n / fs)
     for n in range(N)]

y = [0.0] * N
y_prev = 0.0
for n in range(N):
    y[n] = a * y_prev + (1 - a) * x[n]
    y_prev = y[n]

print(f"{'n':>3} | {'x[n]':>8} | {'y[n]':>8}")
for n in range(N):
    print(f"{n:>3} | {x[n]:>8.4f} | {y[n]:>8.4f}")

    
লক্ষ্য করুন — y[n]-এর মান x[n]-এর তুলনায় অনেক মসৃণভাবে পরিবর্তিত হচ্ছে (যেমন n=6 থেকে n=9 পর্যন্ত x লাফিয়ে ১.১৯ থেকে -০.২২-এ নামলেও y ধীরে ধীরে ০.৬৫ থেকে ০.৪০-এ নামছে)। এটাই লো-পাস আচরণ — দ্রুত পরিবর্তন (উচ্চ ফ্রিকোয়েন্সি) কমে যাচ্ছে, ধীর পরিবর্তন (নিম্ন ফ্রিকোয়েন্সি) বজায় থাকছে — ঠিক যেমন একটি ফিডব্যাক-ভিত্তিক স্মুথার কাজ করার কথা।

৩ · ইমপালস রেসপন্স — কখনও ঠিক শূন্য নয়

L30-এ দেখা হয়েছিল একটি সসীম-দৈর্ঘ্যের FIR ফিল্টারের ইমপালস রেসপন্স তার ট্যাপ-সংখ্যার পরে ঠিক শূন্যে পৌঁছে যায়। একই a = 0.8 ফিল্টারে একটি একক ইমপালস ([1, 0, 0, ...]) পাস করিয়ে দেখা যাক এর ইমপালস রেসপন্স কেমন আচরণ করে।

Python
M = 20
impulse = [1.0 if n == 0 else 0.0 for n in range(M)]

h = [0.0] * M
y_prev = 0.0
for n in range(M):
    h[n] = a * y_prev + (1 - a) * impulse[n]
    y_prev = h[n]

print("ইমপালস রেসপন্স h[n], n=0..19:")
for n in range(M):
    print(f"{n:>2}: {h[n]:.10f}")

print()
print("শেষ ৫টি স্যাম্পলের মধ্যে সর্বনিম্ন |মান|:", min(abs(v) for v in h[-5:]))
print("শেষ ১০টি স্যাম্পলের কোনোটি কি ঠিক শূন্য?", any(v == 0.0 for v in h[-10:]))

    
কোড চালালে দেখা যায় h[0] = 0.2, h[1] = 0.16, h[2] = 0.128... প্রতিটি মান আগেরটির a = 0.8 গুণ — একটি জ্যামিতিক (geometric) ক্রম, বন্ধ-রূপে h[n] = (1-a)\,a^n। n=19-এ পৌঁছেও h[19] ≈ 0.00288 — অত্যন্ত ছোট, কিন্তু ঠিক শূন্য নয়, এবং শেষ ১০টি স্যাম্পলের কোনোটিই ঠিক শূন্য নয়। তাত্ত্বিকভাবে n → ∞ পর্যন্ত এই ক্রম চলতে থাকবে (যদিও ব্যবহারিকভাবে দ্রুত নগণ্য হয়ে যায়) — এটাই "Infinite Impulse Response" নামের কারণ, এবং L30-এর FIR ইমপালস রেসপন্সের (যা তার ট্যাপ-সংখ্যার পরে ঠিক শূন্য) সাথে এর মৌলিক পার্থক্য।
মূল কথা · Key takeaway

IIR ফিল্টারের ফিডব্যাক একে "স্মৃতিসম্পন্ন" করে তোলে — তাত্ত্বিকভাবে অসীম দৈর্ঘ্যের ইমপালস রেসপন্স দিয়ে FIR-এর তুলনায় কম কোয়েফিশিয়েন্টে শার্প ফ্রিকোয়েন্সি রেসপন্স অর্জন করা যায়। কিন্তু এই সুবিধার মূল্য আছে — ফিডব্যাক মানেই পোল, আর পোল মানেই স্ট্যাবিলিটি নিশ্চিত করার দায়িত্ব (L13, L18)। M8-এর বাকি পাঠগুলো এই দায়িত্বটি সঠিকভাবে পালন করার প্রমাণিত পদ্ধতি শেখাবে — L36-এ Butterworth অ্যানালগ প্রোটোটাইপ দিয়ে শুরু করে, L38-এ বাইলিনিয়ার ট্রান্সফর্ম দিয়ে সেটিকে ডিজিটাল ডোমেইনে আনা, আর L39-এ এটি বাস্তবায়নের দুটি প্রমিত উপায় (Direct Form I ও II)।

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

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

প্র ০১ a-এর মান ০-এর কাছাকাছি করলে (যেমন a = 0.1) ফিল্টারের আচরণ কেমন হবে বলে আপনার ধারণা?

a ছোট হলে ফিডব্যাক টার্মের প্রভাব কমে যায় আর (1-a) (ইনপুটের সরাসরি অংশ) বেড়ে যায় — ফিল্টার আউটপুট প্রায় সরাসরি ইনপুট অনুসরণ করবে, অর্থাৎ খুব কম স্মুথিং হবে। চরম ক্ষেত্রে a = 0 হলে y[n] = x[n] — কোনো ফিল্টারিংই হয় না। এটি ইমপালস রেসপন্সেও দেখা যাবে: h[n] = (1-a)a^n খুব দ্রুত ক্ষয় পাবে (প্রায় FIR-এর মতো আচরণ করবে, যদিও তাত্ত্বিকভাবে এখনও অসীম দৈর্ঘ্যের)।

প্র ০২ ইমপালস রেসপন্স তাত্ত্বিকভাবে কখনও শূন্যে পৌঁছায় না — তাহলে ব্যবহারিকভাবে একটি IIR ফিল্টারকে কি "সসীম দৈর্ঘ্যের" হিসেবে ট্রিট করা নিরাপদ?

ব্যবহারিকভাবে হ্যাঁ, একটি সীমা পর্যন্ত — যেহেতু |a| < 1 হলে h[n] = (1-a)a^n এক্সপোনেনশিয়ালি ক্ষয় পায়, একটি নির্দিষ্ট পয়েন্টের পর মান ফ্লোটিং-পয়েন্ট নির্ভুলতার সীমার নিচে চলে যায় (বাস্তবে "শূন্য")। কিন্তু গাণিতিকভাবে এটি কখনও ঠিক শূন্য হয় না — এটাই FIR বনাম IIR-এর একটি মৌলিক, তাত্ত্বিক পার্থক্য, শুধু ব্যবহারিক আনুমানিকতার প্রশ্ন নয়।

প্র ০৩ যদি a = 1.2 (অর্থাৎ ১-এর বেশি) নেওয়া হতো, তাহলে কী ঘটত বলে আপনার মনে হয়?

এটি অস্থিতিশীল (BIBO unstable) হয়ে যেত — L13-তে শেখা নিয়ম অনুযায়ী, এই ফিল্টারের একমাত্র পোল z = a-তে অবস্থিত (Z-ট্রান্সফর্মের ডিনোমিনেটর 1 - a z^-1 = 0 সমাধান করে)। |a| < 1 হলে পোল ইউনিট সার্কেলের ভেতরে (স্থিতিশীল), কিন্তু a = 1.2 হলে |a| > 1 — পোল ইউনিট সার্কেলের বাইরে, ফলে ইমপালস রেসপন্স ক্ষয় না পেয়ে বরং প্রতি স্যাম্পলে বৃদ্ধি পেয়ে দ্রুত অসীমের দিকে চলে যাবে।

অনুশীলন

  1. চিন্তা করুন: উপরের প্রথম কোড সেলে a = 0.8-কে a = 0.5-এ বদলালে y[n]-এর মান x[n]-এর কতটা কাছাকাছি থাকবে বলে আপনার ধারণা — বেশি স্মুথিং হবে নাকি কম?

    কম স্মুথিং হবে। a = 0.5 মানে ফিডব্যাকের ওজন কমে যায় আর বর্তমান ইনপুটের ওজন (1-a = 0.5) বেড়ে যায় — ফলে আউটপুট ইনপুটের পরিবর্তনের সাথে অনেক বেশি দ্রুত সাড়া দেবে, a = 0.8-এর তুলনায় অনেক কম মসৃণ।

  2. পরীক্ষা করুন: দ্বিতীয় কোড সেলে a-এর মান 0.8 থেকে 0.5 করে Run চাপুন এবং ইমপালস রেসপন্সের ক্ষয়ের হার তুলনা করুন।

    রান করলে দেখা যাবে h[n] = 0.5 \times 0.5^n অনেক দ্রুত ক্ষয় পায় — h[5] ≈ 0.0156 (যেখানে a=0.8-এ h[5] ≈ 0.0655 ছিল)। ছোট a মানে দ্রুত-ক্ষয়প্রাপ্ত "স্মৃতি" — ফিল্টার কম সংখ্যক অতীত স্যাম্পল মনে রাখে, যদিও তাত্ত্বিকভাবে এখনও অসীম দৈর্ঘ্যের।

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

আগের পাঠ
FIR ফিল্টার ডিজাইন ট্রেড-অফ — অর্ডার বনাম পারফরম্যান্স