FIRフィルタとIIRフィルタの比較:特性・設計・Python実装

FIR(有限インパルス応答)フィルタとIIR(無限インパルス応答)フィルタの理論的な違い、周波数特性、安定性、位相特性を比較し、Pythonによる設計と実装例を紹介します。

はじめに

デジタルフィルタは、離散時間信号から特定の周波数成分を抽出・除去する処理の基盤です。デジタルフィルタは大きく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 比較

特性FIRIIR
安定性常に安定設計に依存(極の配置が必要)
線形位相対称係数で保証一般に非線形位相
フィルタ次数高次数が必要(急峻なカットオフ)低次数で急峻な特性が可能
計算コスト次数に比例して増加少ない係数で実現可能
設計手法窓関数法、最小二乗法、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(双一次変換)

関連記事

参考文献

  • 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