はじめに

ADC の値がガタガタするので「とりあえず 10 回平均」を入れる。線はきれいになります。ところが、同じ値をモータの速度制御に戻すと、今度はループが揺れ始める。ローパスフィルタは、いちばんよく使うのに、いちばん代償が見えにくいフィルタです。

この記事のゴールは、ローパスフィルタを「勘の平均」から「要件から計算して決めるもの」に変えることです。ローパスは低い周波数を通し、高い周波数を落とすフィルタです。よく使う 3 種類(移動平均、1 次 IIR、2 次バターワース)を、落ち始める周波数を 20 Hz にそろえて同じ土俵に並べ、ノイズがどれだけ減り、どれだけ遅れ、制御ループの余裕がどれだけ減るかを数字で比べます。実機は使わず、すべて計算と数値シミュレーションで示します。

🗓️ 連載「デジタルフィルタ入門」
  • #1 基礎編 — サンプリング、伝達関数、ボード線図、効き目の測り方、C の骨格
  • #2 ローパス(この記事) — 移動平均、1 次 IIR、2 次バターワースを同じカットオフで比べる
  • #3 ハイパス — DC とドリフトを消す
  • #4 バンドパスとノッチ — Q と Audio EQ Cookbook で狙った周波数を扱う
  • #5 カルマンフィルタ(予定)
  • #6 EKF・UKF(予定)
  • #7 パーティクルフィルタ(予定)
  • #8 適応フィルタ(予定)
  • #9 以降 用途別のフィルタ(予定)— 平滑化(Savitzky–Golay・メディアン・Hampel)、検出(Goertzel・整合フィルタ・ヒルベルト変換)、レート変換(CIC・コム・オールパス)

この記事で分かること: 3 種類のローパスの伝達関数がどこから来るのか、同じカットオフでも減衰、遅れ、ノイズの残り方がなぜ違うのか、ループの中に入れると位相余裕がどれだけ減るのかが分かります。

読み終えたときにできること: fs、落としたい周波数、許せる遅れの 3 つから、移動平均の点数、1 次 IIR の α、2 次バターワースの係数を計算できます。計算した値を C のコードに入れ、ボード線図、ステップ応答、白色ノイズで検証できます。

💡 対象読者と前提

マイコンで ADC の値を読んだことがある方を想定しています。伝達関数やボード線図は次の章で手短に説明するので、#1 基礎編 を読んでいなくても進められます。詳しくは基礎編の z 変換と伝達関数、周波数応答、群遅延、白色ノイズと PSD で導出しています。


📘 最初に道具を 4 つだけ

この記事を読むのに必要な道具を、4 つに絞って再掲します。導出は基礎編に任せ、ここでは読み方だけを押さえます。

伝達関数 H(z)。 マイコンのフィルタは、今の出力を過去の入力と出力の重み付き和で作る差分方程式で書けます。1 サンプルの遅れを z^{-1} という掛け算に置き換えると、この式は出力と入力の比 H(z) = Y(z)/X(z) という 1 つの分数になります。分数の分母を 0 にする点が極、分子を 0 にする点が零点で、極が半径 1 の円(単位円)の内側にあればフィルタは安定です。極が 1 つもない(過去の出力を戻さない)形が FIR、ある形が IIR です。

ボード線図。 H(z) の z に e^{j\omega T} ( \omega = 2\pi f 、T はサンプリング周期)を入れると、周波数 f の正弦波が何倍になり(振幅)、どれだけずれるか(位相)が分かります。この 2 つを、対数の周波数軸で 2 段に描いたのがボード線図です。振幅の倍率 |H| は 20\log_{10}|H| の dB(デシベル)で書き、−3 dB は約 0.707 倍、−20 dB は 0.1 倍です。−3 dB の点をカットオフ周波数 fc と呼びます。−20 dB/decade は、周波数が 10 倍になると振幅が 0.1 倍になる傾きです。

群遅延。 位相を周波数で微分して符号を変えた値 \tau_g = -d\angle H/d\omega で、その周波数付近の信号が何秒遅れて出てくるかを表します。どの周波数でも同じ値なら、波形の形は崩れません。これを直線位相と呼びます。

PSD。 パワースペクトル密度(PSD)は、周波数 1 Hz あたりのパワーの分布です。白色ノイズはすべての周波数に同じパワーが乗った信号で、フィルタを通すと PSD は周波数ごとに |H|^2 倍になります。分散(ばらつきの 2 乗)と標準偏差 σ、RMS(2 乗平均の平方根。平均が 0 のノイズでは σ と同じ)が、ノイズの大きさを表す数字です。

道具がそろったので、3 種類のローパスを作ります。


🔽 ローパスフィルタの 3 つの形

ローパスは高い周波数を落とし、ゆっくりした成分を残します。ここでは fs = 1 kHz(サンプリング周波数。1 秒間に値を取り込む回数)、−3 dB の点を約 20 Hz にそろえた 3 種類を比べます。

💡 ワード解説:時間波形を読む言葉
  • ステップ応答:入力を 0 から 1 へ一度に切り替えたときの出力の動き
  • 過渡と定常状態:入力を変えた直後の、出力が動いている間が過渡。落ち着いたあとが定常状態
  • 行き過ぎ(オーバーシュート):出力が最終値を超えて振れること。超えた量を最終値に対する % で表す。動きと反対の向きへ振れるのがアンダーシュート
  • リンギング:入力を変えたあと、出力が振動しながら収まっていく様子
  • 立ち上がり時間:最終値の 10 % から 90 % まで進む時間
  • 整定時間:最終値の ±2 % のように決めた範囲に収まるまでの時間

移動平均(FIR)

直近 N 点の平均です。もっとも身近なデジタルフィルタで、伝達関数は等比級数(同じ比で続く数列)の和なので、Σ を使わない閉じた形になります。

H(z) = \frac{1}{N}\sum_{k=0}^{N-1} z^{-k} = \frac{1}{N}\cdot\frac{1 - z^{-N}}{1 - z^{-1}}

z = e^{j\omega T} を入れて整理します。分子は e^{-jN\omega T/2} をくくり出し、オイラーの式から出る e^{j\theta} - e^{-j\theta} = 2j\sin\theta を使うと、次の形になります。

\begin{aligned} & 1 - e^{-jN\omega T} \\ & = e^{-jN\omega T/2}\cdot 2j\sin(N\omega T/2) \end{aligned}

分母も、N を 1 に置き換えた同じ形です。先頭の指数の項どうしの比は e^{-j(N-1)\omega T/2} で、絶対値が 1 です。絶対値を取ると消えて、振幅は sinc 関数(sin x / x の形の波)の離散版になります。ディリクレ核と呼ばれる形です。

\left|H(e^{j\omega T})\right| = \left|\frac{\sin(N\omega T/2)}{N\sin(\omega T/2)}\right|

分子の 1 - z^{-N} の零点は、単位円を N 等分した位置に並びます。z = 1 の零点は分母と打ち消し合うので、残りの N − 1 個が振幅の谷、つまり k f_s/N の周波数を作ります。

移動平均 22 点のボード線図、単位円上に並ぶ零点、直線的に立ち上がるステップ応答

振幅の谷と、極零点図で単位円に並ぶ零点の 1 つ 1 つが対応する。ステップ応答は 22 ms かけて直線で立ち上がり、行き過ぎない

−3 dB を 20 Hz に近づける長さは N = 22 で、このとき −3 dB は 20.2 Hz、最初の谷は 45.5 Hz です。係数が左右対称なので直線位相で、遅れは周波数によらず次の値です。

\tau_g = \frac{N-1}{2}\,T = 10.5\ \mathrm{ms}

この式は、先ほど絶対値で消えた項の位相 -(N-1)\omega T/2 が ω に比例することから出ます。微分すれば、 \omega の係数がそのまま群遅延です。

N を決める目安も計算しておきます。N が大きいとき、 |H| が 1/√2 になるのは f \approx 0.443\, f_s/N のところです。逆に解くと N \approx 0.443\, f_s/f_c で、fs = 1 kHz、fc = 20 Hz なら 22.15、つまり N = 22 です。

図の位相が途中で跳ねているのは、振幅の符号が谷で反転するためで、群遅延が乱れているわけではありません。一方で弱点もあります。阻止域(落としたい周波数帯)の山が最大 −13 dB 程度までしか下がらず、高い周波数を強く落とす用途には向きません。

✅ 谷を狙って置くテクニック

谷の位置が fs/N で決まることは武器になります。fs = 1 kHz で N = 20 にすると、平均する長さがちょうど 50 Hz の 1 周期(20 ms)になり、50 Hz とその高調波(整数倍の周波数の成分)に零点が乗ります。N = 100 なら 50 Hz と 60 Hz の両方が谷に入ります。

移動平均は N 点ぶんのメモリを使います。次の 1 次 IIR は、変数 1 個で似た効果を出します。

1 次 IIR(指数移動平均)

マイコンでいちばん使われるのは、おそらく次の 1 行です。変数 1 個で RC ローパスと同じ働きをします。

y[n] = y[n-1] + \alpha\left(x[n] - y[n-1]\right)

入力との差の α 倍だけ追いかける、という素直な式です。基礎編の 連続時間から離散時間へ で、抵抗 R とコンデンサ C の RC ローパスの微分方程式から導いた式と同じ形です。過去の入力の重みが 1 サンプルごとに 1-\alpha 倍ずつ指数関数的に小さくなるので、指数移動平均とも呼びます。z 変換すると伝達関数が出て、極は z = 1-\alpha の 1 個です。

H(z) = \frac{\alpha}{1 - (1-\alpha)\,z^{-1}}

これはアナログの RC ローパス G(s) = 1/(RCs + 1) の親戚です。そこで α を RC から決めます。連続時間で極 s を持つ応答は e^{st} の形で変化し、s が負なら減衰します。サンプリング周期 T ごとに見ると、値は毎回 e^{sT} 倍になります。1 次 IIR の極 z = 1-\alpha も「1 サンプルごとに何倍になるか」を表す数だったので、 z = e^{sT} が離散時間の極に当たります。RC の極 s = -1/RC を入れると z = e^{-T/RC} で、これを 1-\alpha と等しいと置くと、次の α が出ます。

\alpha = 1 - e^{-T/RC} = 1 - e^{-2\pi f_c T}

右の形は f_c = 1/(2\pi RC) を入れたものです。連続時間の極を z = e^{sT} で離散時間の極へ移すこの対応は、後の「制御ループに入れると何が起きるか」でも、モータの極を移すときに使います。

−3 dB をぴったり fc に合わせたいときは、 |H|^2 = 1/2 を解きます。上の H(z) に z = e^{j\omega T} を入れ、 \omega = 2\pi f_c 、 c = \cos(2\pi f_c T) と置いて、分母の絶対値の 2 乗を計算します。

|H|^2 = \frac{\alpha^2}{1 - 2(1-\alpha)c + (1-\alpha)^2}

これを 1/2 と置いて分母を払うと、α の 2 次方程式になります。

\alpha^2 + 2(1-c)\,\alpha - 2(1-c) = 0

α は正の数なので、解の公式の + の側を取ると次の式です。

\alpha = -(1-c) + \sqrt{(1-c)^2 + 2(1-c)}

fc = 20 Hz、fs = 1 kHz では、どの決め方でも近い値になります。基礎編で導いた後退差分(隣のサンプルとの差で微分を近似する方法)の式はやや低めに出ます。

α の決め方 α 実際の −3 dB
厳密解(上の式) 0.11794 20.00 Hz
1 − exp(−2π fc T) 0.11809 20.03 Hz
T/(RC + T)(後退差分) 0.11164 18.86 Hz

表の厳密解 α = 0.11794 で特性を描くと、次の図になります。

1 次 IIR ローパスのボード線図、z = 0.88 付近に 1 個の極がある極零点図、なだらかに近づくステップ応答

振幅の傾きは fc の上で −20 dB/decade。極が 1 個なので、ステップ応答は行き過ぎずに指数関数で近づく。図の右端で振幅が寝ているのは fs/2 が近いため

低周波の群遅延は (1-\alpha)/\alpha サンプルで、この例では 7.5 ms です。この式は、分母を低い周波数で近似すると出ます。 \theta = \omega T が小さいとき e^{-j\theta} \approx 1 - j\theta なので、分母 1 - (1-\alpha)e^{-j\theta} は \alpha + j(1-\alpha)\theta になり、位相は -(1-\alpha)\theta/\alpha です。θ で微分すれば、サンプル数の遅れが出ます。計算はかけ算 1 回、メモリは 1 変数で済みます。

時定数で見ると、fc = 20 Hz は \tau = 1/(2\pi f_c) \approx 8\ \mathrm{ms} に当たります。上の図のステップ応答に 63 % の線は引いていませんが、計算すると入力を変えてから 8 ms で 63 %、40 ms で 99 % まで追いつきます。応答は 1 - e^{-t/\tau} なので、10 % から 90 % までの時間は \tau \ln 9 = 17.5 ms で、次の比較の表の 18 ms はこの値です。

1 次 IIR は軽い代わりに、fc の上の傾きが −20 dB/decade にとどまります。もっと急に落としたいときの基本形が、次の 2 次バターワースです。

2 次バターワース(双一次変換)

1 次より急に落とすには、次数を 2 に上げます。2 次の形はいくつもありますが、最初の候補になるのがバターワースです。通過域(通したい周波数帯)をできるだけ平らに保つのがバターワース特性で、最大平坦特性とも呼びます。振幅に波打ちを作らず、0 Hz から単調に落ちていきます。設計の元にするアナログの 2 次のフィルタ(プロトタイプ)は、制御工学の標準 2 次系で減衰比を \zeta = 1/\sqrt{2} にしたものと同じです。

G(s) = \frac{\omega_c^2}{s^2 + \sqrt{2}\,\omega_c s + \omega_c^2}

標準 2 次系の分母は s^2 + 2\zeta\omega_c s + \omega_c^2 です。 \zeta (減衰比)は振動の収まりやすさを表す値で、小さいほど振動的になります。

このアナログの式は、そのままではマイコンで計算できません。デジタルへ移すのが双一次変換で、 s を次の式で置き換えます。

s \leftarrow \frac{2}{T}\cdot\frac{1 - z^{-1}}{1 + z^{-1}}

s と z の関係が分子・分母とも 1 次の分数になっているので、双一次(bilinear)変換と呼びます。この変換は s 平面の虚軸を単位円にそのまま写すので、安定なアナログフィルタは安定なデジタルフィルタになります。代わりに周波数軸が歪みます。アナログの周波数 \omega_a とデジタルの周波数 \omega_d の関係は次のとおりです。

\omega_a = \frac{2}{T}\tan\frac{\omega_d T}{2}

この式の出どころは簡単です。 z = e^{j\theta} ( \theta = \omega_d T )を変換の式に入れ、分子と分母から e^{-j\theta/2} をくくり出すと、次のようになります。

\frac{1 - e^{-j\theta}}{1 + e^{-j\theta}} = j\tan\frac{\theta}{2}

これに 2/T を掛けた値が s = j\omega_a なので、上の関係が出ます。 \theta が小さいうちは \tan(\theta/2) \approx \theta/2 で \omega_a \approx \omega_d ですが、fs/2 に近づくほど tan が伸びます。

そこで、あらかじめ fc を \tan で引き伸ばしておきます。これがプリワープです。 K = \tan(\pi f_c / f_s) と置くと、 G(s) の中の s/\omega_c は次の W に置き換わります。

W = \frac{1}{K}\cdot\frac{1 - z^{-1}}{1 + z^{-1}}

G(s) の分子と分母を \omega_c^2 で割ると 1/(W^2 + \sqrt{2}W + 1) です。分子と分母に K^2(1 + z^{-1})^2 を掛けて分数を払います。

H(z) = \frac{K^2 (1 + z^{-1})^2}{\mathrm{Den}(z)} \begin{aligned} \mathrm{Den}(z) = {} & (1 - z^{-1})^2 + \sqrt{2}K(1 - z^{-2}) \\ & + K^2(1 + z^{-1})^2 \end{aligned}

z^{-1} のべきごとに集め、定数項の D で全体を割って分母の先頭を 1 にすると、係数は次のようになります。

D = 1 + \sqrt{2}\,K + K^2 b_0 = b_2 = \frac{K^2}{D}, \quad b_1 = 2b_0 a_1 = \frac{2(K^2-1)}{D} a_2 = \frac{1 - \sqrt{2}\,K + K^2}{D}

fc = 20 Hz、fs = 1 kHz で計算の流れを追います。 K = \tan(0.02\pi) = 0.0629147 なので、 K^2 = 0.0039583 、 \sqrt{2}K = 0.0889748 、D = 1.0929330 です。これを上の式に入れると、次の表の値になります。

Q は山や谷の鋭さを表す値で、#4 で定義します。この式の結果は scipy.signal.butter の出力、および Audio EQ Cookbook(W3C が公開している biquad の係数式集)の LPF に Q = 1/√2 を入れた結果と、倍精度(64 ビットの浮動小数点数)の丸め誤差の範囲で一致します。

係数 値 係数 値
b0 0.0036217 a1 −1.8226949
b1 0.0072434 a2 0.8371817
b2 0.0036217 極 0.91135 ± 0.08141j

この係数で計算した特性が次の図です。左上の振幅が fc の手前まで平らなことと、右上の極が 1 組(2 個)あることを見てください。

2 次バターワースのボード線図、z = −1 の零点と z = 1 近くの極の図、わずかに行き過ぎるステップ応答

fc の上で −40 dB/decade に落ちる。双一次変換の零点は z = −1 に 2 個重なるので、fs/2 に向かって振幅は 0 へ落ち込む。ステップ応答は 4.3 % だけ行き過ぎる

位相は fc でちょうど −90° を通り、高い周波数へ向かって −180° に近づきます。極は 0.91135 ± 0.08141j で、実軸から離れた複素数の組です。この組がステップ応答に振動の成分を持ち込むので、4.3 % の行き過ぎが出ます。1 次 IIR の極は実軸の上の 1 個だったので、行き過ぎませんでした。

プリワープを省くと、fc を上げるほど狙いとのずれが広がります。

狙いの fc プリワープあり プリワープなし
20 Hz 20.0 Hz 19.97 Hz
100 Hz 100.0 Hz 96.9 Hz
200 Hz 200.0 Hz 178.6 Hz
400 Hz 400.0 Hz 286.0 Hz

これで同じカットオフのローパスが 3 種類そろいました。次の小節で並べて比べます。

3 つを同じ土俵で比べる

ここまでの 3 種類を、−3 dB を 20 Hz にそろえたまま 1 枚に重ねます。この図で見比べるのは、左の振幅で高い周波数がどこまで落ちるか、中央の群遅延で周波数ごとにどれだけ遅れるか、右のステップ応答で動き方がどう違うか、の 3 点です。

3 種類のローパスの振幅特性、群遅延、ステップ応答を並べた図

左で切れ味、中央で遅れ、右で過渡の形を見る。振幅はバターワースが素直に落ち、遅れは 1 次 IIR がもっとも小さい

図から読める差を数字にしたのが次の表です。表の状態変数は、次のサンプルまで覚えておく値です。

項目 移動平均 22 点 1 次 IIR 2 次バターワース
−3 dB 20.2 Hz 20.0 Hz 20.0 Hz
100 Hz の減衰 −21.3 dB −14.0 dB −28.5 dB
200 Hz の減衰 −22.7 dB −19.5 dB −42.5 dB
低周波の群遅延 10.5 ms 7.5 ms 11.2 ms
10〜90 % 立ち上がり 17 ms 18 ms 17 ms
行き過ぎ 0 % 0 % 4.3 %
必要な状態変数 22 点ぶん 1 個 2 個

低周波の群遅延も式で読めます。アナログのプロトタイプの位相は、低い周波数で -\sqrt{2}\,\omega/\omega_c なので、群遅延は \sqrt{2}/\omega_c \approx 0.225/f_c 秒です。fc = 20 Hz で 11.3 ms で、表の 11.2 ms に近い値です。

バターワースの群遅延は fc の少し下で 13.6 ms まで膨らみます。カットオフ付近の成分だけが余計に遅れるので、これが波形の形の変化として現れます。移動平均は常に 10.5 ms です。

3 種類がそろったところで、次の章では、制御ループに入れたときの影響を別の図で見ます。


📊 ナイキスト線図で見る

フィルタを制御ループに入れたときの安定性は、ボード線図だけでは読み取りにくいものです。ボード線図は振幅と位相を別々のグラフに分けて描きます。ナイキスト線図は、同じ情報を複素平面の 1 本の曲線にまとめた図です。 複素平面は、複素数を横軸が実部、縦軸が虚部の点で表す平面です。 周波数を 0 から f_s/2 まで動かしながら、 H(e^{j\omega T}) の点を描いていきます。原点からの距離が振幅、実軸からの角度が位相です。

ローパス自身のナイキスト線図

まず、ローパス 1 本だけをこの図に描きます。この図で見るのは、周波数を上げたときに曲線がどこから出発してどこへ向かうかです。灰色の円は半径 1 の単位円で、内側へ入るほど振幅は小さくなります。黒丸に周波数を添え、矢印で周波数が上がる向きを示しました。

2 次バターワースローパスの周波数応答を複素平面に描いた図。1 から出発して時計回りに原点へ巻き込む

0 Hz の 1 から出発し、時計回りに原点へ巻き込む。原点からの距離が振幅、実軸からの角度が位相

ローパスは 0 Hz で 1 から出発し、位相を遅らせながら原点へ巻き込みます。20 Hz の点が虚軸の上にあるのは、2 次バターワースの位相が fc でちょうど −90° だからです。

形の読み方が分かったところで、次の小節ではこの図を制御ループに使います。

制御ループに入れると何が起きるか

センサのフィルタは、制御ループの中に入ると安定性を変えます。この小節では、その変化を位相余裕とゲイン余裕の数字で確かめます。制御ループは、出力を測り、目標との差から次の操作を決める、を繰り返す仕組みです。モータの速度制御を例に、速度センサへ LPF を入れた場合を計算します。モータは、ゲイン K、時定数 τ の 1 次遅れ G(s) で表します。

G(s) = \frac{K}{\tau s + 1},\quad K = 1,\ \tau = 50\ \mathrm{ms}

これを 1 ms 周期の PI 制御で動かします。PI 制御は、目標との差に比例した量と、差を積分した量を足して操作量(モータへの指令)を決める方式です。マイコンの操作量は、次の更新まで同じ値に保たれます。この階段状の保持がゼロ次ホールドです。

ゼロ次ホールドを前提に、プラント(制御対象)を離散化(差分方程式の形に変換)します。1 次遅れの極 s = -1/\tau は、1 次 IIR の節と同じ z = e^{sT} の対応で z = p = e^{-T/\tau} に移ります。操作量 u が 1 サンプルの間一定なら、出力はその間に最終値 Ku へ向かって、残りの差の 1-p の割合だけ進みます。残りの差が p 倍になるので、次の差分方程式です。

y[n+1] = p\,y[n] + K(1-p)\,u[n]

今のサンプルの u[n] が出力に現れるのは、次のサンプルの y[n+1] です。両辺を z 変換して比を取ると、この 1 サンプルが分子の z^{-1} になります。

P(z) = \frac{K(1-p)\,z^{-1}}{1 - p\,z^{-1}},\quad p = e^{-T/\tau}

z = 1 を入れると分子と分母の 1-p が消えて K になるので、一定の入力に対する倍率は連続時間のモータと同じです。操作量の計算に手間取り、出すのがさらに 1 サンプル遅れる場合は z^{-1} がもう 1 個増えますが、この記事の計算には入れていません。2 次以上のプラントも含めた離散化の一般形は、参考に挙げた制御の教科書に譲ります。

次は PI 制御そのものです。積分は基礎編の 連続時間から離散時間へ の置き換え \int \to T\sum をそのまま使います。積分した値を I[n] 、目標との差を e[n] と書くと、1 サンプル前までの和に今の値を足す形の I[n] = I[n-1] + T\,e[n] です。z 変換すると遅れの項が z^{-1} の掛け算になるので、積分器は T/(1 - z^{-1}) です。これに比例の項を足したものが、PI 制御の伝達関数 C(z) です。

C(z) = K_p + \frac{K_i T}{1 - z^{-1}}

比例のゲインは K_p = 3 、積分のゲインは K_i = 60 です。 K_p/K_i を \tau に合わせて、プラントの極を PI のゼロでほぼ打ち消しています。センサの LPF を F(z) とすると、ループを一周した伝達関数(ループを 1 か所で切って見る形なので、開ループ伝達関数と呼ぶ)は L = C P F です。フィードバックをつないだ全体を閉ループと呼び、その分母は 1 + L なので、 L = -1 になる周波数があると、信号が一周して同じ形で戻り、減衰しなくなります。

💡 ワード解説:位相余裕とゲイン余裕
  • 位相余裕(PM): |L| = 1 の周波数(ゲイン交差)で、位相があと何度遅れると −180° に届くか
  • ゲイン余裕(GM):位相が −180° になる周波数で、ゲインをあと何 dB 上げると |L| = 1 に届くか

どちらも −1 点までの「距離」を別の測り方で表したものです。開ループが不安定でないこの例では、ナイキスト線図の曲線が −1 点を囲まなければ閉ループは安定です。

フィルタなし、LPF 20 Hz、LPF 10 Hz の 3 通りについて、開ループ L を描いたのが次の図です。左のナイキスト線図は −1 点の近くを拡大したもので、灰色の破線が単位円です。

フィルタなし、LPF 20 Hz、LPF 10 Hz の開ループのナイキスト線図とボード線図

左の曲線が −1 点(赤の十字)へ寄っていく様子を見る。丸印が単位円と交わるゲイン交差で、この点が −1 に近づくほど位相余裕が小さい

fc を下げるほど曲線は −1 点へ近づき、右のボード線図では位相が −180° を通る周波数が下がっていきます。LPF なしを含む 5 通りで余裕を計算すると、次の表になります。

センサの LPF 位相余裕 ゲイン余裕 −1 までの最短距離
なし 88.4° 30.4 dB 0.97
100 Hz 80.9° 20.3 dB 0.86
50 Hz 72.8° 15.6 dB 0.76
20 Hz 48.0° 8.6 dB 0.51
10 Hz 15.7° 3.0 dB 0.20

このループのゲイン交差は約 9.6 Hz です。fc = 20 Hz の LPF はゲイン交差の 2 倍の周波数にあり、振幅はほとんど減らしません。それでも位相余裕は 40° 減ります。交差周波数 fgc での 2 次バターワースの位相遅れが、次の式で効くからです。

\phi = \arctan\frac{\sqrt{2}\,r}{1 - r^2},\quad r = \frac{f_{gc}}{f_c}

r = 0.47 を入れると 40° で、表の差と合います。ゲイン余裕の 8.6 dB も時間領域で検算できます。ゲインを 8.6 dB 上げたループをシミュレーションすると振幅がほぼ一定の振動になり、0.3 dB 下げると減衰、0.3 dB 上げると発散しました。

滑らかにするほど制御は不安定に寄ります。 これを時間波形で見たのが次の図です。

上段は目標値ステップに対する速度応答、下段はセンサノイズを足したときの操作量

上段で LPF 10 Hz の揺れの大きさと長さを見る。下段ではフィルタなしの操作量だけがガタついている

上段では、LPF 10 Hz の揺れが 600 ms たっても残っています。下段でフィルタなしの線だけがガタつくのは、σ = 0.02 のセンサノイズが比例のゲイン 3 倍で操作量へ出るためです。この差を数字で比べます。次の表のノイズ RMS は、センサに σ = 0.02 のガウスノイズ(平均の近くに多い釣り鐘形の分布に従うノイズ)を足したときの定常状態の値です。

センサの LPF 行き過ぎ ±2 % に収まる時間 操作量のノイズ RMS
なし 0 % 63 ms 0.061
20 Hz 23.5 % 113 ms 0.016
10 Hz 74.8 % 738 ms 0.010

LPF は操作量のガタつきを 1/4 にしますが、代わりに行き過ぎが 0 % から 23.5 % になります。どこでバランスさせるかが設計です。

✅ 設計の目安

この例では、fc をゲイン交差の 5 倍(50 Hz)にすると位相余裕の減少は約 16°、10 倍(100 Hz)で約 8° です。ループに入れる LPF は、まずゲイン交差の 5〜10 倍から試し、位相余裕を計算してから下げていく順番が安全です。

次の章では、ループから離れて、ノイズそのものがフィルタでどれだけ減るかを計算します。


🎲 白色ノイズを通す

実際のセンサノイズは、あらゆる周波数が混ざった信号です。その代表である白色ノイズを 3 つのローパスに通します。条件は、fs = 1 kHz、N = 2^16 点、σ = 1 のガウス白色ノイズです(乱数列を決める初期値のシードは固定)。理論はこの記事の冒頭のとおりで、PSD は |H|^2 倍になり、分散はインパルス応答の 2 乗和倍になります。導出と測り方は基礎編の 白色ノイズと PSD と Welch 法 にまとめました。

\sigma_y^2 = \sigma^2 \sum_{n=0}^{\infty} h[n]^2

時間波形

次の図は、同じ 1 本の白色ノイズを 3 つのフィルタに通し、過渡が収まったあとの 0.5 秒ぶんを切り出したものです(8000 サンプル目から)。縦軸は 4 段共通なので、高さの差がそのまま振幅の差です。見比べるのは、波の高さと、線の細かさ(どれくらいの速さで動いているか)の 2 つです。

生の白色ノイズと、移動平均 22 点、1 次 IIR、2 次バターワースを通した時間波形の 4 段の図

縦軸は 4 段共通。どのフィルタも振幅は約 1/5 になる。線の細かさは 1 次 IIR がいちばん残り、2 次バターワースがいちばん滑らか

いちばん上の生の白色ノイズは、毎サンプル独立に値が決まります。前の値が次の値の手がかりにならない、つまり相関(2 つの値がどれだけ連動するかを −1〜1 で表す量)がありません。隣のサンプルどうしの相関は 0.003 で、ほぼ 0 です。

下の 3 段では細かい動きが消え、ゆっくりした揺れだけが残ります。これがノイズの中の 20 Hz 以下の成分です。出力は過去の入力の重み付き和なので隣のサンプルと似た値になり、隣どうしの相関は移動平均で 0.954、1 次 IIR で 0.881、2 次バターワースで 0.993 まで上がります。1 次 IIR の線に細かいギザギザが残るのは、20 Hz より上の落ち方がゆるやかだからです。残った揺れは入力より遅れて出てきます。「3 つを同じ土俵で比べる」で見た群遅延です。

図の中の数字は出力の標準偏差で、RMS 比はそれを生のノイズの標準偏差 0.999 で割った値です。分散比(出力の分散を入力の分散で割った値)とあわせてまとめると次のとおりです。

フィルタ 分散比 RMS 比 見た目
生の白色ノイズ 1 1 毎サンプルばらばらに跳ねる
移動平均 22 点 0.0450 0.212 ゆっくりうねり、細かな角が残る
1 次 IIR 20 Hz 0.0622 0.249 うねりに細かいギザギザが乗る
2 次バターワース 20 Hz 0.0438 0.209 ゆっくりうねるだけ

表の値はこの乱数列のシミュレーションの値で、理論値との比較は「分散は何分の 1 になるか」の表で行います。時間で見えた違いは、どの周波数がどれだけ残ったかの違いです。次の小節で、周波数ごとに確かめます。

Welch 法の PSD と理論値

時間波形で見えた違いを、周波数ごとの数字にします。シミュレーションの出力から PSD を推定し、理論の計算と重なるかを確かめます。推定には、短い区間の FFT(信号を周波数成分に分ける計算)を平均する Welch 法を使います。1 回の長い FFT ではノイズのギザギザが減らないからです。条件はハン窓(区間の端を 0 に絞る重み)、4096 点、50 % オーバーラップ(区間を半分ずつ重ねて取ること)で、理由は基礎編の Welch 法 で説明しています。

理論値は、入力の PSD に |H|^2 を掛けて計算した値です。σ = 1 の生のノイズの水準は 10\log_{10}(2/f_s) = -27.0 dB です。次の図では、シミュレーションの結果を実線、理論値を破線で重ねました。見るのは、実線が破線の上に乗るかどうかです。

生の白色ノイズとローパス 3 種の出力の PSD に理論曲線を重ねた図

ノイズの細かいギザギザを除けば、シミュレーションの曲線は破線の上を走る。移動平均の谷の位置までそのまま出ている

シミュレーションと理論の差は、1 次 IIR と 2 次バターワースの平均で約 0.7 dB でした(谷の深い移動平均は対数の差が発散するので除いています)。実線が破線に乗るということは、ボード線図の形がそのままノイズのスペクトルの形になるということです。

PSD の形が理論どおりだと分かったので、次の小節では、その面積である分散が入力の何分の 1 になるかを数字にします。

分散は何分の 1 になるか

ノイズがどれだけ減るかを 1 つの数字で言うために、出力の分散を比べます。あわせて、帯域の広さを 1 つの数字で比べるのが等価雑音帯域幅(ENBW)です。同じ出力パワーになる理想の長方形フィルタの幅を表します。白色ノイズでは分散比が \sum h[n]^2 なので、全帯域の幅 f_s/2 にこの比を掛けて、 B_n = (f_s/2)\sum h[n]^2 (ピークのゲインが 1 のとき)で求まります。

フィルタ 分散比(理論) 分散比(シミュレーション) ENBW
移動平均 22 点 0.0455 0.0450 22.7 Hz
1 次 IIR 20 Hz 0.0627 0.0622 31.3 Hz
2 次バターワース LPF 20 Hz 0.0443 0.0438 22.2 Hz

理論の列は手で計算できます。移動平均のインパルス応答は 1/N が N 個なので、2 乗和は N \cdot (1/N)^2 = 1/N です。N = 22 で 0.0455 です。

1 次 IIR のインパルス応答は h[n] = \alpha(1-\alpha)^n です。2 乗和は比が (1-\alpha)^2 の等比級数なので、閉じた形になります。

\sum_{n=0}^{\infty} h[n]^2 = \frac{\alpha^2}{1-(1-\alpha)^2} = \frac{\alpha}{2-\alpha}

α = 0.11794 を入れると 0.0627 で、表の値です。

ENBW はカットオフとの比で覚えられます。アナログの 1 次は |H|^2 = 1/(1 + (f/f_c)^2) 、2 次バターワースは |H|^2 = 1/(1 + (f/f_c)^4) で、0 から無限大まで積分するとそれぞれ fc の \pi/2 倍と \pi/(2\sqrt{2}) \approx 1.11 倍です。同じ −3 dB でも、1 次 IIR は裾が広いぶん ENBW が 31.3 Hz と大きく、ノイズが残ります。

RMS で見ると、20 Hz の 2 次バターワースでノイズは 0.209 倍です。ENBW は fc に比例し、RMS はその平方根に比例します。一方で遅れは 1/fc に比例します。

📌 ノイズと遅れの交換レート

白色ノイズが相手なら、RMS を半分にするには fc を 1/4 にする必要があり、遅れは 4 倍になります。「もう少しだけ静かに」の代償は意外に大きいのです。

ノイズと遅れの関係が数字になりました。次の章では、ここまでの式を設計の手順にまとめます。


🧪 設計手順と実装

ローパスの設計は、4 段の手順で進めます。要件を書き出し、式で候補を計算し、係数にして、検証する。この順番を守ると、「なんとなく 10 回平均」から抜け出せます。

  1. 要件:fs、残したい信号の上限、落としたいノイズの周波数と減衰量、許せる遅れを書き出す
  2. 式:移動平均なら N \approx 0.443\, f_s/f_c 、1 次 IIR なら \alpha = 1 - e^{-2\pi f_c T} 、2 次バターワースなら K と D から係数を計算する
  3. 係数:C の初期化子や alpha の定数にする
  4. 検証:ボード線図で減衰、ステップ応答で動き、白色ノイズで分散比を確かめる

設計例 1:傾き表示

加速度センサで傾きを表示する場面で、手順を通します。要件は、fs = 200 Hz、手の振動の 10 Hz を −14 dB(1/5)以下に落とす、ゆっくりした傾きの変化は 1 Hz まで残す、遅れは 100 ms 以内、とします。fc は残す上限より少し上の 2 Hz を試します。

1 次 IIR の α は次のとおりです。

\alpha = 1 - e^{-2\pi \cdot 2 / 200} = 0.0609

2 次バターワースは K = \tan(\pi \cdot 2/200) = 0.03143 、D = 1.04543 から、b0 = 0.00094469、a1 = −1.9111971、a2 = 0.9149758 です。2 つの候補を要件と突き合わせると次の表になります。遅れの式は、1 次 IIR が (1-\alpha)/\alpha サンプル、2 次バターワースが FAQ で触れる約 0.225/fc 秒です。

項目 1 次 IIR 2 次バターワース 要件
−3 dB 2.00 Hz 2.00 Hz 2 Hz
1 Hz の減衰 −0.97 dB −0.26 dB 残す
10 Hz の減衰 −14.1 dB −28.1 dB −14 dB 以下
低周波の遅れ 77 ms 113 ms 100 ms 以内

10 Hz は 1 次 IIR でぎりぎり要件を満たし、遅れも収まります。2 次バターワースは減衰に余裕がありますが、遅れが要件を超えます。この要件なら 1 次 IIR です。

次の図で検証します。左の振幅が計算どおりかを見て、右で実際の波形を見ます。右の入力は、0.5 秒で傾きが 0 から 1 へ変わる段差に、10 Hz の振動と小さなノイズを足したものです。

左は fs 200 Hz の 1 次 IIR と 2 次バターワースの振幅特性。右は傾きの段差に手の振動を足した入力と 2 つのフィルタの出力の時間波形

右の灰色が入力。1 次 IIR には 10 Hz の小さな揺れが残るが、段差への追従は 2 次より早い。どちらを取るかは要件で決まる

右の図で、1 次 IIR の線には振幅が約 1/5 になった 10 Hz の揺れが残っています。揺れをさらに小さくしたくなったら、要件の遅れを見直す番です。これが「どこでバランスさせるか」の中身です。

設計例 2:エンコーダの速度

もう 1 つ、移動平均の例です。エンコーダの速度を 1 ms ごとに計算し、カウントの刻みを 10 点の移動平均でならします。N = 10、fs = 1 kHz を入れると、−3 dB は 44.5 Hz、最初の谷は fs/N = 100 Hz、遅れは (N-1)T/2 = 4.5 ms、白色ノイズの分散比は 1/N = 0.1 です。分解能の計算は、活用事例の章で続けます。

C のコードに入れる値

基礎編の C の biquad の biquad_t に、次の係数を入れます。biquad_step() と biquad_reset() はそのまま使えます。

// 2 次バターワース LPF(fc = 20 Hz, fs = 1 kHz)
static biquad_t lpf = {
    0.0036216815f, 0.0072433630f, 0.0036216815f,
    -1.8226949252f, 0.8371816513f, 0.0f, 0.0f
};

1 次 IIR は 1 行で書けます。α の値は表のとおりです。

y += alpha * (x - y);   // alpha は次の表から
条件 種類 値
fs 1 kHz、fc 20 Hz 1 次 IIR α = 0.11794
fs 1 kHz、fc 20 Hz 移動平均 N = 22
fs 200 Hz、fc 2 Hz 1 次 IIR α = 0.0609
fs 1 kHz、−3 dB 44.5 Hz 移動平均 N = 10

FPU のないマイコンでは、基礎編の 固定小数点の 1 次 IIR を使います。shift を 1 つ決めると \alpha = 2^{-\mathrm{shift}} なので、α は 2 のべき乗にしか選べません。狙いの α にいちばん近いものを選び、実際の −3 dB を計算し直します。fs = 1 kHz で 20 Hz を狙うと α = 0.11794 なので、近いのは shift = 3(α = 1/8)で、−3 dB は 21.3 Hz です。shift = 6(α = 1/64)なら −3 dB は約 2.5 Hz です。

設計の手順がそろいました。次の章で、よくある場面に当てはめます。


💡 活用事例

ローパスを、電子工作でよくある場面に当てはめます。まず表で全体を見て、そのあと 1 つずつ理由を説明します。

用途 フィルタ 設計値の例
傾き表示 LPF(1 次 IIR) fs 200 Hz、fc 2 Hz、α = 0.061
PID の D 項 LPF ゲイン交差の 5〜10 倍から
エンコーダの速度 移動平均 fs 1 kHz、N = 10
温度センサ LPF(HPF は不適) 変化の速さに合わせる

加速度センサの傾き表示。 KXR94-2050 のデジタル水平器 のように、重力の向きから角度を出す用途です。ほしいのは静かな重力成分で、手の振動は不要です。fs = 200 Hz、fc = 2 Hz の 1 次 IIR なら α = 0.061、遅れは約 80 ms で、目で見る表示には十分です。ジャイロと組み合わせる話は #5 のカルマンフィルタにつながります。

PID の D 項。 PID 制御は、比例(P)、積分(I)、微分(D)の 3 項で操作量を決める方式で、D 項はその微分の項です。微分は高い周波数を増幅します。1 サンプルの差分をとるとノイズの標準偏差は √2 倍になり、さらに 1/T が掛かります。fs = 1 kHz なら 1,414 倍です。そのため D 項には LPF が付き物です。ただし LPF の遅れは位相余裕を削るので、先ほどの表の考え方で fc を決めます。

エンコーダの速度。 1000 パルス/回転を 4 逓倍(A 相と B 相の両方のエッジを数えて分解能を 4 倍にすること)し、1 ms ごとに差分をとると、1 カウントが 15 rpm に相当します。移動平均を 10 点とると分解能は 1.5 rpm です。カウント c の差分の移動平均は (c[n] - c[n-10]) / (10 * T) と同じなので、リングバッファ(古い値から順に上書きする配列)1 本で書けます。遅れは 4.5 ms です。

温度センサのドリフト。 「ドリフトだから HPF(ハイパスフィルタ)」は誤用の代表です。温度そのものがゆっくり動く信号なので、HPF を通すと測りたい値が消えてしまいます(#3 で扱います)。ここで使うのは LPF で、ADC のノイズを落とします。電源投入時のドリフトは、フィルタではなく校正や待ち時間の問題です。

どの場面でも、何を残して何を捨てるかからフィルタを選んでいます。次の章で、この考え方を手順にまとめます。


🧭 選び方

フィルタの選び方を、判断の順に並べます。最初に問うのは、消したいものが特定の周波数かどうかです。

flowchart TD A{"消したいのは
特定の周波数?"} -- はい --> B["ノッチ(#4)
または谷を合わせた移動平均"] A -- いいえ --> C{"波形の形を
保ちたい?"} C -- はい --> D["FIR
移動平均・firwin"] C -- いいえ --> E["まず 1 次 IIR
切れ味が足りなければ
2 次バターワース"]

図の分かれ道のほかに、遅れやメモリの条件で決まることもあります。条件ごとの向き不向きは次のとおりです。

判断の軸 向いている選択 理由
遅れを許せない 1 次 IIR、高い fc 同じ fc で群遅延が小さい
直線位相が必要 移動平均、firwin 全周波数の遅れが同じ
メモリが少ない 1 次 IIR、biquad 状態は 1〜2 個
高域を深く落とす バターワース、FIR 減衰の傾きが急
fc/fs が 1/1000 より小さい 間引き(サンプルを減らす処理)のあとで設計 極が 1 に寄り数値が厳しい

firwin は SciPy の FIR 設計関数で、基礎編の 直線位相が要るなら FIR で扱っています。ループの中に入れるフィルタは、ボード線図だけでなく位相余裕を計算して決めます。逆に、表示やログのようにループの外で使うフィルタは、遅れの心配が少ないので強めにかけられます。

フィルタを選んで動かしたあと、思いどおりにならないときは、次の章の表から原因を探します。


🛠️ トラブルシューティング

実装で起きやすい症状を、原因と対策の組にしてまとめます。

症状 よくある原因 対策
出力が発散する 極が単位円の外。係数の符号違いや丸め 係数から極を計算する。a1, a2 の符号を見直す
思ったより効かない fc/fs の比を別の fs で計算している 実際の呼び出し周期で計算し直す
fc が狙いより低い プリワープをしていない K = tan(π fc/fs) を使う
値が遅れて付いてくる 群遅延 fc を上げる。次数を下げる
起動直後に大きく振れる 状態変数が 0 から始まる 最初の値で biquad_reset() する
値が一定の位置で止まる 整数のまま計算している 内部に小数ビットを持たせる(基礎編の Q16 のコード)

float の丸めだけでも、fc が低いと効いてきます。fs = 1 kHz の 2 次バターワース LPF で、係数を float に丸めたときの DC ゲイン(0 Hz でのゲイン)を計算すると次のようになります。

fc a2 の値 float 係数の DC ゲイン
20 Hz 0.83718 0.9999997
1 Hz 0.99115 0.9991
0.1 Hz 0.99911 0.9458

0.1 Hz では DC ゲインが 5 % 以上ずれます。 1 + a_1 + a_2 が 0 に近い小さな数になり、float の分解能では表せなくなるためです。fc/fs が極端に小さいときは、double を使うか、先に移動平均で間引いて fs を下げてから設計します。


✅ まとめ

  • 同じ fc でも、移動平均は谷と直線位相、1 次 IIR は軽さ、2 次バターワースは切れ味が持ち味
  • 2 次バターワースの係数は、双一次変換とプリワープから K と D の式で求まる
  • ナイキスト線図で見ると、ループに入れた LPF は開ループを −1 点へ近づける。fc = 20 Hz で位相余裕は 88.4° から 48.0° へ下がった
  • 白色ノイズの PSD は理論の |H|² をなぞり、分散はインパルス応答の 2 乗和で決まる。RMS を半分にする代償は遅れ 4 倍
  • 設計は、要件、式、係数、検証の順に進める

ここまでで、要件からローパスの係数を計算し、代償を数字で説明できるようになりました。次の一手は、手元のセンサで要件を書き出し、この記事の表と同じ 4 行を自分の値で埋めてみることです。#3 ハイパスフィルタの設計 では逆に、低い周波数を落とすフィルタを同じ手順で設計します。


よくある質問(FAQ)

Q. 移動平均と 1 次 IIR、どちらを使えばいいですか?

A. 迷ったら 1 次 IIR が手軽です。変数 1 個で済み、同じ −3 dB なら遅れも小さくなります。特定の周波数に谷を置きたいときや、遅れを周波数によらず一定にしたいときは移動平均を選びます。ノイズを減らす力は移動平均のほうが上で、同じ −3 dB で分散比は 0.0455 対 0.0627 です。

Q. カットオフ周波数はどう決めればいいですか?

A. 残したい信号の一番速い成分より高く、消したいノイズより低い位置が候補です。そのうえで、遅れが許せるかを群遅延で見ます。2 次バターワースの低周波の遅れは、約 0.225/fc 秒です(fc = 20 Hz で 11.2 ms)。制御ループの中で使うなら、位相余裕の計算まで行います。

Q. 位相余裕を減らさずに LPF を入れられますか?

A. 減らさないことはできませんが、減りを小さくできます。fc をゲイン交差の 5〜10 倍に置くと、この記事の例では位相余裕の減少が約 16°〜8° で済みます。fc を下げるほど急に減り、ゲイン交差の 2 倍では 40° 減ります。

Q. ノイズの RMS を半分にするにはどうすればいいですか?

A. 白色ノイズが相手なら fc を 1/4 にします。RMS は ENBW の平方根に比例し、ENBW は fc に比例するからです。代わりに遅れは 4 倍になります。遅れが許せないときは、ADC のオーバーサンプリング(必要より高い fs で読むこと)など、フィルタの外の対策も考えます。


関連記事

この連載:

フィルタの計算:

センサの入口:


参考

取得日はいずれも 2026-11-05 です。図と数値はすべて筆者が Python(NumPy 2.4.6、SciPy 1.17.1、Matplotlib 3.11.2)で計算したものです。

理論

係数の式

設計ツール(SciPy v1.18.0 Manual)