跳轉到

4.1 FIR 濾波器#

概念說明#

濾波器改變訊號的頻率內容:留低去高(低通)、留高去低(高通)、留中間(帶通)、去中間(帶陷)。FIR(finite impulse response,有限脈衝響應)濾波器是最直觀的一種:輸出只是當前與過去輸入的加權和:

\[ y[n] = \sum_{k=0}^{M-1} b_k\, x[n-k] = b_0 x[n] + b_1 x[n-1] + \cdots + b_{M-1} x[n-M+1] \]

係數 \(b_0, \dots, b_{M-1}\) 就是濾波器的脈衝響應——輸入一個單位脈衝 \(\delta[n]\) ,輸出恰好是這組係數,長度有限( \(M\) 個樣本),故名 FIR。

FIR 最重要的性質:

  1. 天生穩定:沒有回授(不把過去的輸出加回來),不論係數為何都不會發散。
  2. 可做線性相位:若係數對稱( \(b_k = b_{M-1-k}\) ),所有頻率的延遲時間相同,波形形狀不因濾波而扭曲——這對音樂與波形顯示至關重要。線性相位的代價是群延遲 \((M-1)/2\) 個樣本。
  3. 設計容易:窗函式法(window method)只需「理想濾波器的脈衝響應 × 窗函式」,幾行程式即可;更精確可用 Parks–McClellan(Remez)最佳化。

窗函式法:理想低通的脈衝響應是 sinc 函式

\[ h_{ideal}[n] = \frac{2 f_c}{f_s}\, \mathrm{sinc}\!\left(\frac{2 f_c (n - (M-1)/2)}{f_s}\right), \quad n = 0 \dots M-1 \]

截斷(乘矩形窗)會造成吉布斯振盪與洩漏,改用 Hann、Hamming、Blackman 等錐形窗可大幅壓制旁瓣。實作上一般直接呼叫 scipy.signal.firwin。

演算法步驟:設計與套用 FIR 低通#

  1. 規格化:決定截止頻率 \(f_c\) 、濾波器階數 \(M-1\) 、窗型。
  2. 以 sinc 公式(或 firwin)計算係數 \(b_k\) ,並正規化使直流增益為 1。
  3. 用「滑動加權和」逐樣本濾波;長訊號可用 FFT 卷積(卷積定理)加速。
  4. 驗證:對掃頻訊號觀察哪些頻率被衰減;或直接以 FFT 比較濾波前後頻譜。

Python 範例#

import numpy as np

def firwin_lowpass(numtaps, cutoff, fs):
    M = numtaps
    n = np.arange(M)
    mid = (M - 1) / 2
    h = (2 * cutoff / fs) * np.sinc(2 * cutoff * (n - mid) / fs)
    h *= np.hamming(M)                      # Hamming 窗壓制旁瓣
    return h / h.sum()                      # 正規化直流增益 = 1

fs = 8000
h = firwin_lowpass(numtaps=101, cutoff=1000, fs=fs)
print(f"濾波器係數:中心係數 h[50]={h[50]:.4f},對稱檢查 {np.allclose(h, h[::-1])}")

# 套用:混合 500 Hz(應保留)與 3000 Hz(應去除)
t = np.arange(0, 0.05, 1/fs)
x = np.sin(2*np.pi*500*t) + np.sin(2*np.pi*3000*t)
y = np.convolve(x, h)[:len(x)]

def amp_at(sig, f, fs):
    N = len(sig)
    return abs(np.fft.rfft(sig * np.hanning(N))[int(f/fs*N)]) / N * 4

print(f"濾波前 500 Hz 振幅 {amp_at(x, 500, fs):.3f}, 3000 Hz 振幅 {amp_at(x, 3000, fs):.3f}")
print(f"濾波後 500 Hz 振幅 {amp_at(y, 500, fs):.3f}, 3000 Hz 振幅 {amp_at(y, 3000, fs):.3f}")

# 頻率響應的數值檢查(用 FFT of h)
H = np.abs(np.fft.rfft(h, 4096))
freqs = np.fft.rfftfreq(4096, 1/fs)
for f in [200, 1000, 1500, 3000]:
    idx = int(f/fs*4096)
    print(f"|H({f:4d} Hz)| = {H[idx]:.3f}   ({20*np.log10(H[idx]+1e-12):6.1f} dB)")

輸出:

濾波器係數:中心係數 h[50]=0.1233,對稱檢查 True
濾波前 500 Hz 振幅 1.000, 3000 Hz 振幅 0.998
濾波後 500 Hz 振幅 0.999, 3000 Hz 振幅 0.049
濾波後只留下 500 Hz 成分(衰減 3000 Hz 約 26 dB)
|H( 200 Hz)| = 1.000   (   0.0 dB)
|H(1000 Hz)| = 0.500   (  -6.0 dB)
|H(1500 Hz)| = 0.042   ( -27.5 dB)
|H(3000 Hz)| = 0.001   ( -60.3 dB)

500 Hz 幾乎無損通過,3000 Hz 被衰減約 26 dB(短訊號邊界效應使實測略低於理論 −60 dB)。頻率響應確認:1 kHz(截止頻率)處增益 0.5(−6 dB),越往上衰減越深。若把 numtaps 提高到 201,過渡帶會更陡——這是 FIR 的核心取捨:規格越嚴、階數越高、延遲與計算量越大。

複雜度分析#

直接卷積每個輸出樣本需 \(M\) 次乘加,總時間 \(O(N M)\) 、空間 \(O(M)\) (存延遲線)。以 101 階濾波器處理 8 kHz 即時音訊,每秒 80 萬次乘加,手機或微控制器輕鬆勝任;這也是為何嵌入式降噪、音訊前處理偏好 FIR。長訊號與長濾波器( \(M > 100\) 左右)可用 FFT 卷積(overlap-add)降到 \(O(N \log N)\) 。FIR 相較 IIR(4.2 節):達到同樣陡峭的響應需要更高階數(更高延遲與計算量),但換來無條件穩定與線性相位。

練習#

  1. 設計階數 51、101、201 的 1 kHz 低通 FIR,畫出(或列表比較)三者的頻率響應,說明階數對過渡帶寬度的影響。
  2. 用 sinc × Hamming 窗自行實作高通濾波器(提示:理想高通 = 全通 − 低通,即「脈衝減 sinc」),並驗證 3 kHz 通、500 Hz 衰減。
  3. 對方波訊號分別用「線性相位 FIR」與「把係數乘 1.05 做微幅非對稱擾動」的濾波器處理,觀察波形是否產生相位失真(波形不對稱、過衝位置移動)。