2次デジタルローパスフィルタの導出
アナログ伝達関数から離散時間実装へ
デジタルフィルタは現代の信号処理の中核である。オーディオから制御まで、特に効率的で広く使われているのが2次IIRフィルタ(バイクアッド)である。
本記事では、アナログ伝達関数からデジタルフィルタがどう得られ、それがどのようにコードに直接対応するかを段階的に示す。
実践: デジタルフィルタの設計 – カットオフとサンプリング周波数からバイクアッド係数(計算機付き)
IIRフィルタとは(簡潔に)
IIR(無限インパルス応答)フィルタは、過去の出力サンプルを用いて現在の出力を計算する。計算量が少なくても強いフィルタ特性が得られる。
1. アナログの出発点
正規化された2次ローパスは次で与えられる。
\[ G(s) = \frac{1}{a s^2 + b s + 1} \]
ここで\(a\)は主にカットオフ周波数、\(b\)は減衰すなわちQに関係する。
2. 双一次変換
離散化には双一次変換を用いる。
\[ s = \frac{2}{T_s}\cdot\frac{1-z^{-1}}{1+z^{-1}} \]
\(c = \frac{2}{T_s}\)とすると、z領域では
\[ H(z) = \frac{z^{-2} + 2z^{-1} + 1}{(a c^2 - b c + 1) z^{-2} + (2 - 2a c^2) z^{-1} + (b c + a c^2 + 1)} \]
3. 差分方程式(IIR、2次)
入力\(U_E[k]\)、出力\(U_A[k]\)として
\[ U_A[k] = U_E[k] + 2U_E[k-1] + U_E[k-2] - vU_A[k-1] - uU_A[k-2] \]
ただし
\[ u = a c^2 - b c + 1,\quad v = 2 - 2a c^2,\quad w = b c + a c^2 + 1 \]
これは古典的なバイクアッドIIRである。正規化すれば標準的な\(b_0, b_1, b_2\)および\(a_1, a_2\)表記にも書き換えられる(下記)。
数式モデルからコードへ
入力\(x[k]\)、出力\(y[k]\)とした差分方程式の一般形:
\[ y[k] = b_0 x[k] + b_1 x[k-1] + b_2 x[k-2] - a_1 y[k-1] - a_2 y[k-2] \]
これは数学的な記述である。実行可能なコードにするにはメモリと処理順に落とし込む。
1. 各項の意味
- \(x[k]\) – 現在の入力サンプル
- \(x[k-1]\), \(x[k-2]\) – 過去の入力
- \(y[k-1]\), \(y[k-2]\) – 過去の出力
重要:CPUは自動的に「過去」を覚えない。変数に保存する必要がある。
2. 状態(メモリ)の定義
過去の値には通常次を用いる。
x1 = x[k-1]
x2 = x[k-2]
y1 = y[k-1]
y2 = y[k-2]
これがフィルタの状態である。
3. 式をそのままコードへ
式はほぼそのまま写せる。
y = b0 * x
+ b1 * x1
+ b2 * x2
- a1 * y1
- a2 * y2;
同じ差分方程式をコード形で書いただけである。
4. 状態の更新
出力計算後、次サンプル用にシフトする。
x2 = x1;
x1 = x;
y2 = y1;
y1 = y;
これにより今回の値が次回の「過去」になる。
5. サンプルごとの流れ
各入力サンプルで同じサイクルを繰り返す。
- 新しい入力\(x[k]\)を読む
- 出力\(y[k]\)を計算
- 状態を更新
通常はbiquad_process()のような関数がこれを担う。
6. 直感
フィルタは直近の値を覚え、係数で重み付けする。フィードフォワードは現在・過去入力(\(b_0, b_1, b_2\))、フィードバックは過去出力(\(a_1, a_2\))。これが典型的なフィルタ挙動(例:ローパス)を生む。
7. よくある誤り
- 出力後に状態を更新しない → 誤動作や不安定
- 状態シフトの順序が間違っている
- 実装で\(a_1, a_2\)の符号を忘れる(標準形では減算として現れる)
- 再帰が正規形を期待しているのに非正規化係数を使う
式→コードの要点:式を書く → 状態を保持 → 各サンプル計算 → 状態シフト。直接形IIのIIRバイクアッドの基本である。
コード実装(2次IIR)
導出した差分方程式はそのままソフトウェアに落とせる。2次IIR(バイクアッド)は状態変数が少なく効率的である。
一般形と係数
\[ y[k] = b_0 x[k] + b_1 x[k-1] + b_2 x[k-2] - a_1 y[k-1] - a_2 y[k-2] \]
- \(b_0, b_1, b_2\) – フィードフォワード(分子/入力経路)
- \(a_1, a_2\) – フィードバック(分母/再帰。正規化後は\(a_0=1\)が一般的)
Cの例(組み込み/MCU)
typedef struct {
float b0, b1, b2;
float a1, a2;
float x1, x2;
float y1, y2;
} Biquad;
float biquad_process(Biquad *f, float x) {
float y = f->b0 * x
+ f->b1 * f->x1
+ f->b2 * f->x2
- f->a1 * f->y1
- f->a2 * f->y2;
/* 状態更新 */
f->x2 = f->x1;
f->x1 = x;
f->y2 = f->y1;
f->y1 = y;
return y;
}
利点:サンプルあたり演算が少なく、実行時間が予測しやすい。リアルタイムDSPやMCUに適する。
Pythonの例(解析/シミュレーション)
class Biquad:
def __init__(self, b0, b1, b2, a1, a2):
self.b0, self.b1, self.b2 = b0, b1, b2
self.a1, self.a2 = a1, a2
self.x1 = self.x2 = 0.0
self.y1 = self.y2 = 0.0
def process(self, x):
y = (self.b0 * x +
self.b1 * self.x1 +
self.b2 * self.x2 -
self.a1 * self.y1 -
self.a2 * self.y2)
self.x2 = self.x1
self.x1 = x
self.y2 = self.y1
self.y1 = y
return y
導出との対応
導出ではアナログの\(a\)、\(b\)、\(c=2/T_s\)、離散係数\(u,v,w\)が現れる。そこから\(H(z)\)を作り、実装では標準バイクアッド形の\(b_0,b_1,b_2,a_1,a_2\)へ写す。通常は分母の先頭係数で正規化(\(a_0=1\))する。
重要:リアルタイムの再帰は常にこの正規化係数で動く。
実務上の注意
- 数値:高周波や低減衰では丸め誤差の影響が大きくなる。
- 固定小数点と浮動小数点:FPUのないMCUはスケーリングした固定小数が多い。
- 初期値:\(x_1,x_2,y_1,y_2\)は通常0から(静止開始)。
- オーバーフロー:高ゲインや整数演算では飽和に注意。
実装のまとめ
2次IIRの実装は構造が単純で効率的である。難しいのは係数の正しい計算と正規化である。バイクアッドはオーディオ、制御、リアルタイムDSPの標準である。
パラメータ選択とツール
アナログ\(G(s)\)の連続パラメータ\(a,b\)はカットオフと減衰から選び、\(T_s\)はサンプリング周波数から決まる。設計・検証にはPython/NumPy、MATLAB/Simulink、DSPツールなどが使われる。
まとめ
本導出は、アナログ記述からデジタルローパスが系統的に得られることを示す。 バイクアッド構造により、組み込み、オーディオ、制御にそのまま使える効率的な実装が得られる。
係数の正しい計算と正規化が重要であり、実際の周波数応答を決める。
詳しくは次の記事も参照: カットオフ周波数からバイクアッド係数を求める
著者: Ruedi von Kryentech
作成: 2026年4月6日 · 最終更新: 2026年4月6日
最終更新時点の技術的内容。