はじめに
デジタルフィルタは、離散時間信号から特定の周波数成分を抽出・除去する処理の基盤です。デジタルフィルタは大きくFIR(Finite Impulse Response: 有限インパルス応答)フィルタとIIR(Infinite Impulse Response: 無限インパルス応答)フィルタの2種類に分類されます。
本記事では、両者の数学的定義、特性の違い、設計方法を解説し、SciPyを使ったPython実装で周波数応答と位相特性を比較します。
FIRフィルタ
定義
FIRフィルタの出力は、現在および過去の入力値の重み付き和で表されます。
\[y[n] = \sum_{k=0}^{M} b_k \, x[n-k] \tag{1}\]ここで \(b_k\) はフィルタ係数、\(M\) はフィルタ次数です。インパルス応答は有限の \(M+1\) サンプルで完結します。
伝達関数
Z変換により伝達関数は次のようになります。
\[H(z) = \sum_{k=0}^{M} b_k \, z^{-k} \tag{2}\]FIRフィルタは分母が1(全零点モデル)であるため、常に安定です。
線形位相特性
FIRフィルタの最大の利点は、係数が対称(\(b_k = b_{M-k}\))または反対称であれば線形位相が保証されることです。線形位相とは、すべての周波数成分が同じ時間だけ遅延することを意味し、信号の波形が歪みません。
IIRフィルタ
定義
IIRフィルタは再帰構造を持ち、過去の出力値もフィードバックされます。
\[y[n] = \sum_{k=0}^{M} b_k \, x[n-k] - \sum_{k=1}^{N} a_k \, y[n-k] \tag{3}\]伝達関数
\[H(z) = \frac{\sum_{k=0}^{M} b_k \, z^{-k}}{1 + \sum_{k=1}^{N} a_k \, z^{-k}} = \frac{B(z)}{A(z)} \tag{4}\]分母多項式 \(A(z)\) の存在により、インパルス応答は理論上無限に続きます。分母の極がすべて単位円内にある場合にのみ安定です。
FIR vs IIR 比較
| 特性 | FIR | IIR |
|---|---|---|
| 安定性 | 常に安定 | 設計に依存(極の配置が必要) |
| 線形位相 | 対称係数で保証 | 一般に非線形位相 |
| フィルタ次数 | 高次数が必要(急峻なカットオフ) | 低次数で急峻な特性が可能 |
| 計算コスト | 次数に比例して増加 | 少ない係数で実現可能 |
| 設計手法 | 窓関数法、最小二乗法、Parks-McClellan | バターワース、チェビシェフ、楕円 |
| アナログ対応 | 対応なし | アナログフィルタから変換可能 |
Python実装:ローパスフィルタの設計と比較
以下のコードでは、カットオフ周波数100HzのローパスフィルタをFIR・IIRの両方で設計し、周波数応答を比較します。
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
# --- パラメータ ---
fs = 1000 # サンプリング周波数 [Hz]
fc = 100 # カットオフ周波数 [Hz]
nyq = fs / 2 # ナイキスト周波数
# --- FIRフィルタ設計(窓関数法) ---
fir_order = 50
fir_coeff = signal.firwin(fir_order + 1, fc / nyq)
# --- IIRフィルタ設計(バターワース4次) ---
iir_order = 4
iir_sos = signal.butter(iir_order, fc / nyq, output='sos')
# --- 周波数応答の計算 ---
w_fir, h_fir = signal.freqz(fir_coeff, worN=2048, fs=fs)
w_iir, h_iir = signal.sosfreqz(iir_sos, worN=2048, fs=fs)
# --- 振幅特性のプロット ---
fig, axes = plt.subplots(2, 1, figsize=(10, 8))
# 振幅特性
axes[0].plot(w_fir, 20 * np.log10(np.abs(h_fir) + 1e-12), label=f'FIR (order={fir_order})')
axes[0].plot(w_iir, 20 * np.log10(np.abs(h_iir) + 1e-12), label=f'IIR Butterworth (order={iir_order})')
axes[0].set_xlabel('Frequency [Hz]')
axes[0].set_ylabel('Magnitude [dB]')
axes[0].set_title('Magnitude Response')
axes[0].set_xlim(0, 500)
axes[0].set_ylim(-80, 5)
axes[0].axvline(fc, color='gray', linestyle='--', alpha=0.5, label=f'Cutoff ({fc} Hz)')
axes[0].legend()
axes[0].grid(True, alpha=0.3)
# 位相特性
angles_fir = np.unwrap(np.angle(h_fir))
angles_iir = np.unwrap(np.angle(h_iir))
axes[1].plot(w_fir, np.degrees(angles_fir), label=f'FIR (order={fir_order})')
axes[1].plot(w_iir, np.degrees(angles_iir), label=f'IIR Butterworth (order={iir_order})')
axes[1].set_xlabel('Frequency [Hz]')
axes[1].set_ylabel('Phase [degrees]')
axes[1].set_title('Phase Response')
axes[1].set_xlim(0, 500)
axes[1].legend()
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
位相特性の考察
上記のプロットで確認できる重要な違いは以下のとおりです。
- FIRフィルタ: 通過域で位相が周波数に対して直線的に変化します(線形位相)。これは群遅延が一定であることを意味し、パルス波形などの時間的な形状が保存されます。
- IIRフィルタ: 位相が非線形に変化します。カットオフ付近で位相の変化が急になり、群遅延が周波数によって異なります。ただし
filtfiltを使えばゼロ位相フィルタリングが可能です。
実用的な選択指針
- 波形の忠実な再現が必要(心電図、音声、地震波形)→ FIR(線形位相)
- リアルタイム処理で計算コストを抑えたい → IIR(低次数)
- 安定性を絶対に保証したい → FIR
- アナログフィルタの特性を再現したい → IIR(双一次変換)
関連記事
- 指数移動平均(EMA)フィルタの周波数特性 - EMAはIIRフィルタの一種で、最も基本的な1次IIRフィルタです。
- 高速フーリエ変換(FFT)の仕組みとPython実装 - フィルタの周波数特性を解析するFFTの詳細を解説しています。
- 移動平均フィルタの種類と比較 - FIRフィルタの最も基本的な形である移動平均フィルタの種類と特性を比較しています。
- ローパスフィルタの設計と比較 - バターワース・チェビシェフ等のIIRフィルタの周波数応答を比較しています。
- カルマンフィルタの理論とPython実装 - 状態空間モデルに基づくフィルタリング手法を解説しています。
参考文献
- Oppenheim, A. V., & Schafer, R. W. (2009). Discrete-Time Signal Processing (3rd ed.). Prentice Hall.
- Parks, T. W., & Burrus, C. S. (1987). Digital Filter Design. Wiley.
- SciPy Signal Processing documentation