JOVANA
Library Glossary Getting Started Three Levels Fields How it works Mission
Join the mission
All guides

數位濾波器:FIR 與 IIR,以及如何設計

這條學習路徑到目前為止的一切——取樣、z 轉換、極點與零點、頻率響應——都是為了打造同一台機器:數位濾波器。在這裡我們終於把數學變成能在真實硬體上跑的程式碼。你會認識兩大家族——**FIR** 與 **IIR**,搞懂為什麼一個堅不可摧、另一個便宜卻難馴,並親手走過兩者的設計流程。

濾波器只是一串樣本的加權和

想像一個雜訊很多的溫度讀數,明明房間幾乎沒變,數字卻每秒上下亂跳。最古老的招數就是把最近幾筆讀數平均一下:用昨天的值把今天的值磨平。這種直覺——*把鄰近的樣本組合起來,讓訊號變平滑或變銳利*——就是數位濾波器的全部精神。濾波器拿一串輸入的離散時間樣本 x[n],把輸入的縮放、延遲副本(有時還加上它自己過去的輸出)加總起來,產生輸出 y[n]。

在這條路徑裡我們在乎的每個濾波器都是線性非時變的——也就是一個LTI 系統——而這是個美妙的限制。它代表整個濾波器可以被一個物件完整描述:它的脈衝響應 h[n],也就是你用一個值為 1 的單一樣本去戳它時得到的輸出。給濾波器任何輸入,輸出就是 x[n] 與 h[n] 的卷積。所以整場遊戲就是:選對 h[n]。

Difference equation (the recipe a filter actually runs):

  y[n] = b0*x[n] + b1*x[n-1] + b2*x[n-2] + ...   (feed-forward: input taps)
       - a1*y[n-1] - a2*y[n-2] - ...             (feedback: output taps)

  b coefficients -> ZEROS      a coefficients -> POLES

  If all a's are zero  ->  no feedback  ->  FIR  (finite memory)
  If any a is nonzero  ->  feedback     ->  IIR  (infinite memory)
一條差分方程式統治所有數位濾波器。有沒有 **a**(迴授)項,就是 FIR 與 IIR 的全部分野。

FIR:堅不可摧、誠實,但有點貴

有限脈衝響應濾波器完全沒有迴授。它的脈衝響應就是 b 係數那串清單——丟進一個 1,輸出就是 b0、b1、b2…,之後永遠是死寂的零。這個「有限」給你兩項超能力。第一,FIR 濾波器 永遠穩定:沒有迴授迴路,就沒有東西會失控暴衝,所以有界的輸入永遠不會產生無界的輸出。第二,只要你把係數做成對稱的,濾波器就有完全線性的相位——每個頻率都被延遲同樣的樣本數,因此訊號的形狀被完整保留、不會被抹糊。

看看第 3 階介紹的極點—零點圖,故事很乾淨:FIR 濾波器只有零點(外加一堆無關緊要、坐落在原點的極點,不影響穩定性)。只有零點,你能在頻譜上刻出凹槽,卻永遠造不出尖銳的共振峰——所以要做出陡峭的截止,就得用很多係數。在音訊取樣率下,一個近乎磚牆的低通濾波器很容易需要 100 個以上的抽頭,而每個抽頭都是對每一個樣本做一次乘加運算。這就是 FIR 稅:行為穩如磐石,但算術量很大。

5-point moving-average FIR  (all b = 1/5, no feedback):

  y[n] = (x[n] + x[n-1] + x[n-2] + x[n-3] + x[n-4]) / 5

  Impulse response h = [0.2, 0.2, 0.2, 0.2, 0.2]

  Frequency response  H(e^jw) magnitude:
  |H|
  1.0 *._
      |  \._          nulls at f = fs/5, 2fs/5  (zeros on unit circle)
      |     \.
      |       \.    .-'\.        low-pass, but GENTLE roll-off
      |         '-'    '-.__
  0.0 +------------------------> frequency
樸實的移動平均就是一個 FIR 低通。它的零點剛好落在單位圓上,在頻譜上打出精確的零點——很方便,但通帶會下垂、滾降也很慵懶。

IIR:便宜、銳利,但危險

現在把迴授打開。無限脈衝響應濾波器把自己過去的輸出餵回加總裡,而那個迴路就是全部的差別。因為每個輸出在迴路裡徘徊、慢慢衰減,單一個輸入的戳動基本上會永遠迴響下去——所以叫無限脈衝響應。回報是驚人的效率:一個IIR 濾波器只要 4 到 8 個係數,就能比得上 100 個抽頭的 FIR 的選擇性,因為迴授讓你能放置極點

在極點—零點圖上,極點就是峰:把一個極點拖到靠近單位圓,頻率響應就會在那個角度衝高,幾乎不花成本地給你一個尖銳的共振或陡峭的帶緣。但這就是刀鋒所在——極點落在單位圓上或圓外,就是一個不穩定的濾波器。 那個迴授迴路,正是所有效率的來源,屆時會無止境地放大自己的輸出,數字就爆掉了。所以 IIR 設計的生死,就繫於讓每一個極點都嚴格地留在單位圓內。

One-pole IIR low-pass (the workhorse smoother):

  y[n] = a * y[n-1] + (1 - a) * x[n]      with   0 < a < 1

  - Single pole at z = a, on the real axis, inside the unit circle.
  - a near 1  -> pole hugs the circle -> very smooth, slow, long memory.
  - a near 0  -> pole near origin     -> barely filters at all.

  Impulse response (set x = 1 at n=0):
    h = (1-a) * [1, a, a^2, a^3, a^4, ...]   <- decays forever (INFINITE)

  Two adds, two multiplies, one stored value -> a whole low-pass filter.
單極點 IIR 低通——有時稱為指數移動平均——是世上最便宜又實用的濾波器。移動那唯一的極點 **a**,你就在平滑強度與反應速度之間取捨。

設計 FIR:窗函數法

你到底怎麼挑係數?對 FIR 來說,最直覺的路線是窗函數法,它直接從前幾階的傅立葉概念延伸而來。先寫下你夢寐以求的頻率響應——例如一個完美的磚牆低通,通帶為 1、阻帶為 0。對它做反傅立葉轉換,你會得到理想的脈衝響應:一個 sinc 函數,惱人的是它向兩邊無限延伸。你沒辦法跑一個無限長的濾波器,所以必須把它切短。

  1. 指定理想響應(截止頻率,低通/高通/帶通),並反轉換成理想的 sinc 脈衝響應 h_ideal[n]。
  2. 截斷成 N 個抽頭。突然切斷等同於乘上一個矩形窗——而那個硬邊緣會造成頻譜洩漏,表現為通帶與阻帶裡擺動的漣波(吉布斯現象)。
  3. 改為套上更平滑的窗——Hamming、Hann、Blackman、Kaiser。把 h_ideal[n] 乘上一個漸縮的窗函數,讓係數在邊緣溫和地淡出到零,用稍寬一點的過渡帶換取大幅降低的漣波。
  4. 驗證得到的頻率響應。若阻帶不夠深或過渡帶太寬,就增加 N 或換窗,反覆迭代。(Kaiser 窗讓你能獨立調整漣波與過渡帶。)

設計 IIR:向類比借光

IIR 設計走的是一條完全不同、相當優雅的捷徑:工程師花了一個世紀把類比濾波器磨到爐火純青,何必重新發明?標準流程是從經典的類比原型出發——Butterworth(通帶最平坦)、Chebyshev(更陡,代價是通帶漣波)、或橢圓型(最陡,兩帶都有漣波)——在連續的 s 域裡設計它(那裡的極點與零點都很清楚),再把它映射到離散的 z 平面。

最常用的映射是雙線性轉換:s ← (2/T)·(1−z⁻¹)/(1+z⁻¹)。它有一個美妙的性質:它把整個穩定的 s 平面左半平面映射到單位圓內部,所以穩定的類比濾波器會自動變成穩定的數位濾波器——沒有極點能溜到圓外。代價是頻率扭曲:這個映射把無限長的類比頻率軸擠進有限的數位頻率軸,使靠近頻帶頂端的頻率被彎折。你可以在設計前對關鍵頻率做預扭曲來修正它,讓截止頻率精準落在你要的位置。

The two design flows side by side:

  FIR (window method)            IIR (analog-prototype mapping)
  -------------------            -----------------------------
  desired |H(f)| spec            choose Butterworth/Chebyshev/elliptic
        |                                    |
  inverse FT -> sinc h[n]        design analog poles/zeros in s-plane
        |                                    |
  truncate to N taps             pre-warp critical frequencies
        |                                    |
  apply window (Hamming...)      bilinear transform  s -> z
        |                                    |
  -> linear-phase FIR            -> cascade of biquads (stable IIR)
通往濾波器的兩條路。FIR 設計直接從你想要的頻譜雕出係數;IIR 設計則繼承一個久經驗證的類比響應,再把它映射進 z 平面。

卷積:FIR 究竟如何執行

撥開設計理論,一個運轉中的 FIR 濾波器就只是同一個動作永遠重複:卷積。把係數清單 h[] 想成一個沿著輸入滑動的小模板。每來一個新樣本,你就把翻轉後的模板對齊到最近的那幾筆輸入上,逐對相乘、加總,那個總和就是你的下一個輸出。滑一步、再重複。工程師稱這為乘加(MAC)迴圈,它是整個 DSP 裡執行次數最多的指令。

// Direct-form FIR in C: convolution as a MAC loop
float fir(float x_new, const float h[], float state[], int N) {
    // shift the delay line (oldest sample falls off the end)
    for (int i = N - 1; i > 0; i--) state[i] = state[i - 1];
    state[0] = x_new;

    float y = 0.0f;
    for (int i = 0; i < N; i++)
        y += h[i] * state[i];   // multiply-accumulate: the heart of DSP
    return y;
}
十幾行就是一整個 FIR 濾波器。內層迴圈純粹是乘加——這正是為什麼 DSP 晶片內建專用的 MAC 單元,每個時脈週期就處理一個抽頭。

這裡也正是這條路徑各條線索收束之處。直接卷積每個輸出樣本要花 N 次乘法,對長濾波器來說會變得殘酷——所以對非常長的 FIR,工程師改在頻域裡算卷積,用 FFT 把頻譜相乘(快速卷積),因為頻域裡的相乘就是時域裡的卷積。同時,同一個卷積透過 z 轉換來看就變成單純的多項式相乘,而那個多項式的根正是濾波器的零點。取樣、z 轉換、頻率響應、卷積——它們從來不是分開的主題,而是望向同一台機器的四扇窗。