HOWTO · Python
在 Python 中實現低通濾波器
學習如何使用 SciPy 巴特沃斯濾波器、移動平均或高斯平滑在 Python 中濾波取樣資料,並理解截止頻率與取樣限制。
本頁內容
低通濾波器會讓較低頻率的成分通過,並衰減較高頻率的成分;它不一定會完全移除截止頻率以上的所有成分。處理取樣資料時,截止頻率與取樣率必須使用相同的頻率單位。本指南示範如何使用 NumPy 和 SciPy 對一維訊號進行濾波或平滑,共有三種方法。
以下範例皆為可獨立執行的完整範例,但本文並未在此執行,也未呈現其結果。執行前,請先在 Python 環境中安裝 NumPy、SciPy 和 Matplotlib。
使用 SciPy 設計截止頻率明確的巴特沃斯濾波器
巴特沃斯濾波器的通帶具有最大平坦特性。截止頻率必須低於奈奎斯特頻率,也就是取樣率的一半。範例中的 fs 為每秒 500 個樣本,截止頻率則為 100 Hz。將 fs 傳給 scipy.signal.butter,即可使用相同單位指定截止頻率。階數會影響轉換帶的陡峭程度:階數越高,衰減斜率越陡,但對暫態與數值行為也會更敏感。
此範例使用二階節(second-order sections),並透過 sosfiltfilt 先正向、再反向濾波。這能避免離線分析中的相位延遲,但需要同時取得前後方向的資料,也可能影響有限長度訊號的端點。若要處理串流或即時資料,請使用 sosfilt 等因果濾波器,並將其相位延遲與啟動暫態納入考量。
import matplotlib.pyplot as plt
import numpy as np
from scipy.signal import butter, sosfiltfilt
fs = 500.0
cutoff = 100.0
order = 4
time = np.arange(500) / fs
signal = np.sin(2 * np.pi * 10 * time) + 0.5 * np.sin(2 * np.pi * 180 * time)
sections = butter(order, cutoff, btype="lowpass", fs=fs, output="sos")
filtered = sosfiltfilt(sections, signal)
plt.plot(time, signal, label="input")
plt.plot(time, filtered, label="filtered")
plt.xlabel("Time (seconds)")
plt.ylabel("Amplitude")
plt.legend()
plt.tight_layout()
plt.show()
請依據訊號特性和想保留的頻率調整 cutoff 與 order。sosfiltfilt 適用於離線資料;其結果不能與因果即時濾波器的結果互換。
套用移動平均低通濾波器
移動平均會以固定視窗中的平均值取代每個點。這是一種簡單的平滑方法,並不是具有指定截止頻率響應的巴特沃斯設計。使用 NumPy 的 valid 卷積模式時,結果只會包含完整視窗,因此長度會比輸入少 window_size - 1 個樣本。繪圖時,請相應地對齊時間值。
import matplotlib.pyplot as plt
import numpy as np
fs = 100.0
window_size = 5
time = np.arange(100) / fs
signal = np.sin(2 * np.pi * 3 * time) + 0.2 * np.sin(2 * np.pi * 25 * time)
weights = np.ones(window_size) / window_size
smoothed = np.convolve(signal, weights, mode="valid")
smoothed_time = time[window_size - 1:]
plt.plot(time, signal, label="input")
plt.plot(smoothed_time, smoothed, label="moving average")
plt.xlabel("Time (seconds)")
plt.ylabel("Amplitude")
plt.legend()
plt.tight_layout()
plt.show()
請選擇大於零且不超過訊號長度的視窗大小。視窗越大,平均的樣本越多,平滑效果也越強,但訊號變化會變得更寬,視窗結果的對齊位置也會移動。若要採用置中對齊,解讀時間值時請將視窗延遲納入考量。
使用高斯濾波器平滑取樣資料
一維高斯濾波器會使用高斯形狀的核心,對鄰近樣本加權。在 scipy.ndimage.gaussian_filter1d 中,sigma 的單位是樣本數,而非秒或赫茲。若有需要,可使用取樣率將所需的時間尺度換算成樣本數。高斯平滑適合用來一般性地平滑資料,但不會產生具有明確指定值的陡峭截止頻率。
import matplotlib.pyplot as plt
import numpy as np
from scipy.ndimage import gaussian_filter1d
fs = 100.0
sigma_seconds = 0.04
time = np.arange(100) / fs
signal = np.sin(2 * np.pi * 3 * time) + 0.2 * np.sin(2 * np.pi * 25 * time)
smoothed = gaussian_filter1d(signal, sigma=sigma_seconds * fs)
plt.plot(time, signal, label="input")
plt.plot(time, smoothed, label="Gaussian smoothed")
plt.xlabel("Time (seconds)")
plt.ylabel("Amplitude")
plt.legend()
plt.tight_layout()
plt.show()
此範例將 0.04 秒的平滑尺度換算為四個樣本。預設行為會以反射訊號的方式處理端點;如果資料的端點模型不同,可以選擇其他 mode,並謹慎解讀端點附近的結果。
選擇濾波器並理解其限制
若需要明確的頻率響應,且已知取樣率,請使用巴特沃斯設計。若需要直接以視窗平滑,可使用移動平均;若適合採用平滑的局部加權,則可使用高斯平滑。這些方法的頻率響應、延遲和端點行為各不相同,因此請將結果與原始資料比較,並確認任務所需的重要特徵仍清楚可見。
對取樣資料而言,奈奎斯特頻率是取樣率的一半。低通截止頻率必須低於奈奎斯特頻率,而取樣率也必須足以表示感興趣的頻率。濾波器無法還原取樣時未記錄的資訊。離線正反向濾波可降低相位偏移;因果濾波則適合串流處理,但會帶來延遲和啟動行為。對有限長度的資料而言,端點附近的濾波結果也更容易受到填補方式與初始條件影響。
常見問題
低通濾波器的作用是什麼?
低通濾波器會依據其頻率響應讓較低頻率的成分通過,並衰減較高頻率的成分。截止頻率表示該響應中的轉換位置;這不代表所有較高頻率都會完全消失。
什麼時候適合使用低通濾波器?
當較高頻率的變化對你的任務而言屬於雜訊,且已知取樣率與截止頻率時,可以使用低通濾波器。請確認平滑處理不會移除訊號中有意義的快速變化。
巴特沃斯濾波器與移動平均有什麼差異?
巴特沃斯濾波器是根據截止頻率、取樣率與階數設計的。移動平均則使用固定樣本數的視窗,具有不同的頻率響應;其視窗長度不能直接取代巴特沃斯濾波器的截止頻率。
這些濾波器能用於即時資料嗎?
因果濾波器能在樣本到達時逐一處理,但必須考量其相位延遲與啟動暫態。巴特沃斯範例中的正反向濾波需要完整資料記錄,適用於離線處理。若能妥善管理視窗及其對齊方式,移動平均也可以隨著樣本到達持續更新。
可以使用哪些 Python 函式庫?
NumPy 提供陣列與卷積功能;SciPy 則提供巴特沃斯濾波器設計與高斯平滑函式。Matplotlib 可用來繪製輸入訊號與濾波後的訊號,以便檢視結果。