はじめに
チェビシェフフィルタは、通過域(I型)または阻止域(II型)に等リップルを許容することで、同次数のバターワースフィルタよりも急峻な遷移帯域を実現するIIRフィルタです。
バターワースフィルタ が通過域で最大限に平坦な特性を持つのに対し、チェビシェフフィルタはその平坦性を犠牲にして遷移の鋭さを優先します。本記事ではI型とII型それぞれの数学的基礎から、SciPyを使った実践的な設計・実装までを解説します。
チェビシェフ多項式
チェビシェフフィルタの周波数特性は、チェビシェフ多項式 \(T_N(x)\) に基づいています。
\[T_N(x) = \begin{cases} \cos(N \arccos x) & |x| \leq 1 \\ \cosh(N \operatorname{arccosh} x) & |x| > 1 \end{cases} \tag{1}\]低次のチェビシェフ多項式は次のとおりです。
| 次数 \(N\) | \(T_N(x)\) |
|---|---|
| 0 | \(1\) |
| 1 | \(x\) |
| 2 | \(2x^2 - 1\) |
| 3 | \(4x^3 - 3x\) |
| 4 | \(8x^4 - 8x^2 + 1\) |
\(|x| \leq 1\) の範囲でチェビシェフ多項式は \(-1\) から \(+1\) の間を等振幅で振動する性質があり、これがフィルタに等リップル特性をもたらします。
なぜチェビシェフ多項式なのか:最小最大性(ミニマックス性)
チェビシェフフィルタが等リップル多項式としてチェビシェフ多項式を選ぶのは、単に「振動する関数だから」ではありません。その背後には、チェビシェフ自身が1854年に証明した次の定理があります。
チェビシェフの最小最大定理:区間 \([-1,1]\) 上で、最高次係数が \(1\) の(モニックな)\(N\) 次多項式のうち、絶対値の最大値(sup ノルム)を最小化するものは
\[ \tilde{T}_N(x) = \frac{1}{2^{N-1}} T_N(x) \]であり、そのときの最小値は \(2^{1-N}\) である。
証明の骨子(背理法):\(T_N(x) = \cos(N\arccos x)\) は、区間内の \(N+1\) 個の点で交互に符号が反転する極値を取ります(等振幅極値、equioscillation)。極値点とそこでの値を次のように書きます。
\[ x_m = \cos\!\left(\frac{m\pi}{N}\right), \qquad T_N(x_m) = (-1)^m \qquad (m=0,1,\ldots,N) \]いま \(\tilde{T}_N\) より小さい sup ノルムを持つモニック多項式 \(q(x)\) が存在すると仮定し、差を
\[ \Delta(x) = \tilde{T}_N(x) - q(x) \]とおきます。両者ともモニックなので最高次項が相殺し、\(\Delta(x)\) の次数は \(N-1\) 以下です。\(q\) の sup ノルムは極値の絶対値(\(=1\) )より小さいという仮定なので、上式の \(N+1\) 個の点における \(\Delta\) の値の符号は、そこでの \(T_N\) の符号のまま交互に反転します。符号が \(N+1\) 点で交互に反転する連続関数は区間内に少なくとも \(N\) 個の零点を持たねばなりませんが、これは次数 \(N-1\) 以下の多項式が持てる零点数の上限(\(N-1\) 個)を超えており矛盾します。したがって \(\tilde{T}_N\) が唯一の最小化多項式です。
この定理が意味するのは、「通過域リップル \(R_p\) の範囲に収めるという制約の下で、遷移帯域を最も急峻にする \(N\) 次多項式近似はチェビシェフ多項式以外にあり得ない」ということです。つまりチェビシェフフィルタは、多項式で表現される振幅特性の中で理論上最適な選択です(有理関数まで許せば、さらに急峻にできる 楕円フィルタ が存在します。楕円フィルタはこのチェビシェフの理論を、単一周期・多項式から二重周期・有理関数へ一般化したゾロタレフ有理関数に基づいており、詳細は楕円フィルタの記事にまとめています)。
数値検証:上の証明の主張(モニックなチェビシェフ多項式から少しでもずれると sup ノルムが増加する)を、実際に確かめます。\(N=5\) のモニック・チェビシェフ多項式
\[ \tilde{T}_5(x) = T_5(x)/2^4 \]に、ランダムな低次多項式を微小係数 \(\varepsilon_p\) で加えて sup ノルムの変化を見ます。
import numpy as np
from numpy.polynomial import chebyshev as C
N = 5
x = np.linspace(-1, 1, 400001)
coeffs = np.zeros(N + 1); coeffs[N] = 1.0
monic_cheb = C.chebval(x, coeffs) / 2**(N - 1)
sup_cheb = np.max(np.abs(monic_cheb))
rng = np.random.default_rng(1)
direction = rng.normal(size=N)
direction /= np.linalg.norm(direction)
powers = np.vstack([x**i for i in range(N)])
print(f"モニック・チェビシェフ T_5/2^4 の sup ノルム = {sup_cheb:.8f} (理論値 2^-4 = {2**(1-N):.8f})")
for eps_p in [0.0, 0.001, 0.005, 0.01, 0.05, -0.001, -0.01]:
perturbed = monic_cheb + eps_p * (direction @ powers)
sup_p = np.max(np.abs(perturbed))
print(f" eps={eps_p:+.4f}: sup ノルム = {sup_p:.8f} (差分 {sup_p - sup_cheb:+.8f})")
実行結果:
モニック・チェビシェフ T_5/2^4 の sup ノルム = 0.06250000 (理論値 2^-4 = 0.06250000)
eps=+0.0000: sup ノルム = 0.06250000 (差分 +0.00000000)
eps=+0.0010: sup ノルム = 0.06309459 (差分 +0.00059459)
eps=+0.0050: sup ノルム = 0.06547294 (差分 +0.00297294)
eps=+0.0100: sup ノルム = 0.06844589 (差分 +0.00594589)
eps=+0.0500: sup ノルム = 0.09222943 (差分 +0.02972943)
eps=-0.0010: sup ノルム = 0.06361524 (差分 +0.00111524)
eps=-0.0100: sup ノルム = 0.07365243 (差分 +0.01115243)
ランダムに選んだどの摂動方向・符号でも sup ノルムは厳密に増加しており(差分は常に正)、\(\varepsilon_p=0\) (=チェビシェフ多項式そのもの)が局所的な最小点になっていることが数値的に確認できます。
下図は \(N=6\) のチェビシェフ多項式 \(T_6(x)\) の等振幅極値(\(N+1=7\) 個)を示したものです。\(|x|\leq 1\) では \(\pm 1\) の間を等振幅で往復し、\(|x|>1\) では急峻に発散する様子が確認できます。

チェビシェフI型フィルタ
振幅特性
\(N\) 次チェビシェフI型ローパスフィルタの振幅二乗関数は次の式で定義されます。
\[|H(j\Omega)|^2 = \frac{1}{1 + \varepsilon^2 T_N^2\!\left(\dfrac{\Omega}{\Omega_p}\right)} \tag{2}\]ここで、
- \(\varepsilon\) : リップル係数(\(\varepsilon > 0\) )
- \(\Omega_p\) : 通過域端の角周波数
- \(T_N\) : \(N\) 次チェビシェフ多項式
通過域(\(\Omega \leq \Omega_p\) )では、
\[ T_N(\Omega/\Omega_p) \in [-1, 1] \]となり、振幅は \(1/\sqrt{1+\varepsilon^2}\) から \(1\) の間を等振幅でリップルします。通過域リップル \(R_p\) [dB] とリップル係数の関係は次のとおりです。
\[\varepsilon = \sqrt{10^{R_p/10} - 1} \tag{3}\]エッジケース:DC利得は次数の偶奇で変わる
式(2)で \(\Omega=0\) を代入すると、DC(直流、\(\Omega=0\) )における利得は \(T_N(0)\) の値だけで決まります。\(T_N(0)=\cos(N\arccos 0)=\cos(N\pi/2)\) なので、
- \(N\) が奇数:\(N\pi/2\) は \(\pi/2\) の奇数倍で \(\cos(N\pi/2)=0\) となり、\(|H(j0)|^2=1\) (DC利得はちょうど \(0\) dB、完全通過)
- \(N\) が偶数:\(\cos(N\pi/2)=\pm 1\) となり、\(|H(j0)|^2=1/(1+\varepsilon^2)\) (DC利得は通過域リップルの下限 \(-R_p\) dB そのもの)
これは初学者が見落としやすい落とし穴です。「通過域では利得が \(0\) dB 付近でリップルする」と考えて、偶数次のフィルタでも \(\Omega=0\) で \(0\) dB が出ると誤解しがちですが、偶数次では DC ゲインそのものが \(-R_p\) dB からスタートします。実際に数値で確認します。
import numpy as np
from scipy import signal
fs = 100_000
fp = 100
rp = 1.0
eps = np.sqrt(10**(rp / 10) - 1)
print(f"{'N':<4}{'T_N(0)':>10}{'理論DC利得[dB]':>18}{'実測DC利得[dB]':>18}")
for N in [3, 4, 5, 6, 7, 8]:
TN0 = np.cos(N * np.pi / 2)
H2 = 1 / (1 + eps**2 * TN0**2)
gain_theory_db = 10 * np.log10(H2)
sos = signal.cheby1(N, rp, fp, btype='low', fs=fs, output='sos')
_, h = signal.sosfreqz(sos, worN=[1e-6], fs=fs)
gain_meas_db = 20 * np.log10(np.abs(h[0]))
print(f"{N:<4}{TN0:>10.3f}{gain_theory_db:>18.4f}{gain_meas_db:>18.4f}")
実行結果:
N T_N(0) 理論DC利得[dB] 実測DC利得[dB]
3 -0.000 0.0000 0.0000
4 1.000 -1.0000 -1.0000
5 0.000 0.0000 -0.0000
6 -1.000 -1.0000 -1.0000
7 -0.000 0.0000 0.0000
8 1.000 -1.0000 -1.0000
理論値と scipy.signal.cheby1 の実測値が完全に一致し、奇数次(\(N=3,5,7\)
)は DC利得ちょうど \(0\)
dB、偶数次(\(N=4,6,8\)
)は DC利得ちょうど \(-R_p=-1\)
dB になることが確認できます。この偶奇差はチェビシェフI型に固有の性質で、バターワース(式(1)より \(\Omega=0\)
で常に \(|H|=1\)
)にはありません。直流成分を正確に \(0\)
dB で通したい用途(DC結合の計装アンプ段など)では、偶数次のチェビシェフI型を選ぶ際にこの減衰を見込んでおく必要があります。
極の配置
チェビシェフI型フィルタの極は、楕円上に配置されます。\(k = 1, 2, \ldots, N\) について
\[\sigma_k = -\sinh\!\left(\frac{\operatorname{arcsinh}(1/\varepsilon)}{N}\right)\sin\theta_k \tag{4}\]\[\omega_k = \cosh\!\left(\frac{\operatorname{arcsinh}(1/\varepsilon)}{N}\right)\cos\theta_k \tag{5}\]ただし \(\theta_k = \dfrac{\pi(2k-1)}{2N}\) です。安定な左半平面の極は
\[ s_k = \sigma_k + j\omega_k \]のみを採用します。
式(4)(5)の導出
正規化(\(\Omega_p=1\) )した振幅二乗関数の分母を \(0\) にする \(s\) (極)を求めます。\(H(s)H(-s)\) の分母は解析接続 \(\Omega \to -js\) により \(1+\varepsilon^2 T_N^2(-js)\) となるので、極は次の方程式の解です。
\[ T_N(-js) = \pm \frac{j}{\varepsilon} \]ここで \(-js = \cos\theta\) (\(\theta = u+jv\) 、\(u,v\) は実数)と置換します。チェビシェフ多項式の定義 \(T_N(\cos\theta)=\cos(N\theta)\) は複素 \(\theta\) へ解析接続してもそのまま成立するため、
\[ \cos(Nu+jNv) = \cos(Nu)\cosh(Nv) - j\sin(Nu)\sinh(Nv) = \pm\frac{j}{\varepsilon} \]を得ます。右辺は純虚数なので実部はゼロでなければなりません。\(\cosh(Nv) > 0\) は常に成り立つため、
\[ \cos(Nu) = 0 \ \Longrightarrow\ u_k = \theta_k = \frac{(2k-1)\pi}{2N} \qquad (k=1,\ldots,N) \]が要求されます。\(\theta_k \in (0,\pi)\) の範囲でこれは \(N\) 個の解を与えます。虚部の等式
\[ -\sin(N\theta_k)\sinh(Nv)=\pm \frac{1}{\varepsilon} \]に \(\sin(N\theta_k)=\sin\!\left(\frac{(2k-1)\pi}{2}\right)=\pm 1\) を代入すると \(\sinh(Nv)=1/\varepsilon\) (符号は \(v\) の符号選択に吸収されます)となり、
\[ v = \frac{1}{N}\operatorname{arcsinh}\!\left(\frac{1}{\varepsilon}\right) \]が定まります。最後に \(s = j\cos\theta = j\cos(u+jv) = \sin u \sinh v + j\cos u \cosh v\) を展開すると、\(\theta_k\in(0,\pi)\) の範囲では常に \(\sin\theta_k>0\) なので
\[ \sigma_k = -\sinh(v)\sin\theta_k \leq 0, \qquad \omega_k = \cosh(v)\cos\theta_k \]となり、\(k=1,\ldots,N\) の解がそのまま安定な左半平面の極(式(4)(5))を与えることが分かります(\(2N\) 個ある解のうち、\(\theta_k\in(0,\pi)\) を満たす半分が自動的に安定側として選ばれています)。
数値検証:この導出式と scipy.signal.cheb1ap が返す解析的プロトタイプの極を、\(N=6\)
、\(R_p=1\)
dB で比較します。
import numpy as np
from scipy import signal
N = 6
rp = 1.0
eps = np.sqrt(10**(rp / 10) - 1)
v = np.arcsinh(1 / eps) / N
k = np.arange(1, N + 1)
theta = np.pi * (2 * k - 1) / (2 * N)
poles_formula = -np.sinh(v) * np.sin(theta) + 1j * np.cosh(v) * np.cos(theta)
_, poles_scipy, _ = signal.cheb1ap(N, rp)
print("導出式による極 :", np.round(np.sort_complex(poles_formula), 6))
print("cheb1apによる極 :", np.round(np.sort_complex(poles_scipy), 6))
print("最大絶対誤差 :", np.max(np.abs(np.sort_complex(poles_formula) - np.sort_complex(poles_scipy))))
実行結果:
導出式による極 : [-0.232063-0.727227j -0.232063-0.266184j -0.169882+0.266184j
-0.169882+0.727227j -0.062181-0.993411j -0.062181+0.993411j]
cheb1apによる極 : [-0.232063-0.727227j -0.232063-0.266184j -0.169882+0.266184j
-0.169882+0.727227j -0.062181-0.993411j -0.062181+0.993411j]
最大絶対誤差 : 1.3472894910096233e-16
導出式とSciPyの結果は浮動小数点誤差(\(10^{-16}\) オーダー)の範囲で完全に一致しました。下図は、この \(N=6\) のチェビシェフI型の極(楕円上)と、同次数のバターワースの極(円上)を重ねて描いたものです。チェビシェフI型の極は虚軸に近い狭い楕円上に集まっており、これが同次数でもバターワースより急峻な遷移帯域を生む理由です。

エッジケース:高次・低リップルでの極の虚軸接近:楕円の半短軸は \(\sinh(v)=\sinh(\operatorname{arcsinh}(1/\varepsilon)/N)\) で決まります。\(N\) を大きくする、あるいは \(R_p\) (したがって \(\varepsilon\) )を小さくすると \(v\to 0\) に近づき、\(\sinh(v)\approx v\) と近似できるため極の実部(減衰)は \(O(1/N)\) で小さくなります。つまり高次・低リップル設計ほど極が虚軸に接近し、Q値(共振の鋭さ)が高くなります。これは実装上、直接形(Direct Form)の伝達関数係数が桁落ちしやすくなることを意味し、 楕円フィルタ の記事と同様、\(N\) が大きい場合は二次セクション(SOS)形式での実装を推奨します。
チェビシェフII型フィルタ
チェビシェフII型(逆チェビシェフ)フィルタは、阻止域に等リップルを持ち、通過域は単調です。振幅二乗関数は次のとおりです。
\[|H(j\Omega)|^2 = \frac{1}{1 + \left[\varepsilon^2 T_N^2\!\left(\dfrac{\Omega_s}{\Omega}\right)\right]^{-1}} \tag{6}\]ここで \(\Omega_s\) は阻止域端の角周波数です。通過域が単調なので、位相特性がI型より滑らかになります。
エッジケース:cheby2のWnパラメータが指すのは阻止域端
scipy.signal.cheby1とscipy.signal.cheby2はどちらも「カットオフ周波数」に相当する引数Wnを1つ取りますが、その意味はI型とII型で異なります。
cheby1(N, rp, Wn, ...):Wnは式(2)の \(\Omega_p\) (通過域端、利得が \(-R_p\) dB に達する点)cheby2(N, rs, Wn, ...):Wnは式(6)の \(\Omega_s\) (阻止域端、利得が \(-R_s\) dB に達する点)
同じ「Wn」という引数名なのに指している帯域端が違うため、「cheby1と同じ感覚でWn=通過域端のつもりでcheby2を呼ぶ」という誤りが起こりがちです。実際に阻止域端 150 Hz、阻止域減衰 40 dB で6次のチェビシェフII型を設計し、各周波数での利得を確認します。
import numpy as np
from scipy import signal
fs = 1000
N = 6
rs = 40.0
fs_stop = 150 # cheby2に渡すWnは「阻止域端」=ここでrsぶん減衰する周波数
sos = signal.cheby2(N, rs, fs_stop, btype='low', fs=fs, output='sos')
freqs = np.array([50, 100, 130, 140, 149, 150, 160, 200])
_, h = signal.sosfreqz(sos, worN=freqs, fs=fs)
gdb = 20 * np.log10(np.abs(h))
for f, g in zip(freqs, gdb):
print(f"f={f:4d} Hz ゲイン={g:8.3f} dB")
実行結果:
f= 50 Hz ゲイン= -0.000 dB
f= 100 Hz ゲイン= -0.759 dB
f= 130 Hz ゲイン= -15.531 dB
f= 140 Hz ゲイン= -24.903 dB
f= 149 Hz ゲイン= -37.759 dB
f= 150 Hz ゲイン= -40.000 dB
f= 160 Hz ゲイン= -43.434 dB
f= 200 Hz ゲイン= -66.189 dB
指定したfs_stop=150Hzでちょうど-rs=-40.0dBになっており、Wnが阻止域端であることが確認できます。同時に注目すべきは、通過域は指定したWnよりかなり手前から劣化し始めている点です。100 Hz(阻止域端の2/3の位置)ですでに \(-0.759\)
dB の減衰が生じており、「Wnまで平坦」という誤解も禁物です。チェビシェフII型は通過域リップルパラメータを持たず、通過域端を明示的に指定する仕組みがないため、「どこまでが実質的に平坦な通過域か」は \(N\)
・\(R_s\)
・Wnの組み合わせで決まる遷移帯域の形状から読み取る必要があります。厳密に通過域端を指定したい場合は、scipy.signal.cheb2ordに通過域端・阻止域端の両方を渡して次数とWnを自動計算させるのが安全です。
I型とII型の特性比較
| 特性 | チェビシェフI型 | チェビシェフII型 |
|---|---|---|
| 通過域 | 等リップル | 単調(平坦) |
| 阻止域 | 単調 | 等リップル |
| 遷移帯域 | バターワースより急峻 | バターワースより急峻 |
| 位相特性 | 非線形(I型より非線形) | 比較的滑らか |
| 用途 | ノイズ除去の急峻遮断 | 通過域平坦性重視 |
フィルタ次数の決定
所望の仕様(通過域リップル \(R_p\) 、阻止域減衰 \(R_s\) 、通過域端 \(\Omega_p\) 、阻止域端 \(\Omega_s\) )から必要な次数を求めます。
\[N \geq \frac{\operatorname{arccosh}\!\left(\sqrt{\dfrac{10^{R_s/10}-1}{10^{R_p/10}-1}}\right)}{\operatorname{arccosh}(\Omega_s/\Omega_p)} \tag{7}\]同じ仕様に対して、チェビシェフフィルタはバターワースフィルタよりも低い次数で仕様を満足できます。
式(7)の導出
阻止域端 \(\Omega_s\) において、要求される減衰量 \(R_s\) [dB] を満たす条件は、式(2)の \(\Omega_p\) を基準とした \(\varepsilon\) (式(3))に加えて、阻止域減衰から定義される
\[ \varepsilon_s = \sqrt{10^{R_s/10}-1} \]を導入すると、次のように書けます。
\[ |H(j\Omega_s)|^2 = \frac{1}{1+\varepsilon^2 T_N^2(\Omega_s/\Omega_p)} \leq \frac{1}{1+\varepsilon_s^2} \]両辺の分母を比較すると、
\[ \varepsilon^2 T_N^2(\Omega_s/\Omega_p) \geq \varepsilon_s^2 \]となります。阻止域端は通過域端より高域(比が \(1\) より大きい)なので \(T_N(x) = \cosh(N\operatorname{arccosh} x)\) が正かつ単調増加であり、そのまま平方根を取って
\[ T_N(\Omega_s/\Omega_p) \geq \frac{\varepsilon_s}{\varepsilon} \quad\Longleftrightarrow\quad \cosh\!\big(N\operatorname{arccosh}(\Omega_s/\Omega_p)\big) \geq \frac{\varepsilon_s}{\varepsilon} \]を得ます。\(\operatorname{arccosh}\) は単調増加関数なので両辺に適用でき、
\[ N\operatorname{arccosh}(\Omega_s/\Omega_p) \geq \operatorname{arccosh}\!\left(\frac{\varepsilon_s}{\varepsilon}\right) \]したがって
\[ N \geq \frac{\operatorname{arccosh}(\varepsilon_s/\varepsilon)}{\operatorname{arccosh}(\Omega_s/\Omega_p)} \]となります。ここで
\[ \frac{\varepsilon_s}{\varepsilon} = \sqrt{\frac{\varepsilon_s^2}{\varepsilon^2}} = \sqrt{\frac{10^{R_s/10}-1}{10^{R_p/10}-1}} \]を代入すれば式(7)に一致します。等号は仕様をちょうど満たす実数次数を与えるため、実際に採用する次数はこれ以上の最小の整数(切り上げ)です。
Python実装
SciPyによるチェビシェフI型フィルタ設計
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
# --- フィルタ仕様 ---
fs = 1000 # サンプリング周波数 [Hz]
fp = 100 # 通過域端 [Hz]
rp = 1.0 # 通過域リップル [dB]
orders = [2, 4, 6]
fig, axes = plt.subplots(2, 1, figsize=(10, 8))
for N in orders:
# チェビシェフI型ローパスフィルタ
sos = signal.cheby1(N, rp, fp, btype='low', fs=fs, output='sos')
w, h = signal.sosfreqz(sos, worN=4096, fs=fs)
axes[0].plot(w, 20 * np.log10(np.abs(h) + 1e-12), label=f'N={N}')
axes[1].plot(w, np.degrees(np.unwrap(np.angle(h))), label=f'N={N}')
axes[0].set_xlabel('Frequency [Hz]')
axes[0].set_ylabel('Magnitude [dB]')
axes[0].set_title('Chebyshev Type I - Magnitude Response (rp=1dB)')
axes[0].set_xlim(0, 500)
axes[0].set_ylim(-80, 5)
axes[0].axvline(fp, color='gray', linestyle='--', alpha=0.5, label=f'fp={fp}Hz')
axes[0].axhline(-rp, color='r', linestyle=':', alpha=0.5, label=f'-{rp}dB ripple')
axes[0].legend()
axes[0].grid(True, alpha=0.3)
axes[1].set_xlabel('Frequency [Hz]')
axes[1].set_ylabel('Phase [degrees]')
axes[1].set_title('Chebyshev Type I - Phase Response')
axes[1].set_xlim(0, 500)
axes[1].legend()
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
チェビシェフII型フィルタ設計
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
fs = 1000
fs_stop = 150 # 阻止域端 [Hz]
rs = 40.0 # 阻止域減衰量 [dB]
orders = [2, 4, 6]
fig, axes = plt.subplots(2, 1, figsize=(10, 8))
for N in orders:
# チェビシェフII型ローパスフィルタ
sos = signal.cheby2(N, rs, fs_stop, btype='low', fs=fs, output='sos')
w, h = signal.sosfreqz(sos, worN=4096, fs=fs)
axes[0].plot(w, 20 * np.log10(np.abs(h) + 1e-12), label=f'N={N}')
axes[1].plot(w, np.degrees(np.unwrap(np.angle(h))), label=f'N={N}')
axes[0].set_xlabel('Frequency [Hz]')
axes[0].set_ylabel('Magnitude [dB]')
axes[0].set_title('Chebyshev Type II - Magnitude Response (rs=40dB)')
axes[0].set_xlim(0, 500)
axes[0].set_ylim(-80, 5)
axes[0].axvline(fs_stop, color='gray', linestyle='--', alpha=0.5, label=f'fs={fs_stop}Hz')
axes[0].axhline(-rs, color='r', linestyle=':', alpha=0.5, label=f'-{rs}dB')
axes[0].legend()
axes[0].grid(True, alpha=0.3)
axes[1].set_xlabel('Frequency [Hz]')
axes[1].set_ylabel('Phase [degrees]')
axes[1].set_title('Chebyshev Type II - Phase Response')
axes[1].set_xlim(0, 500)
axes[1].legend()
axes[1].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
バターワースとの次数比較
from scipy.signal import buttord, cheb1ord, cheb2ord
import numpy as np
# フィルタ仕様
fp = 100 # 通過域端 [Hz]
fs_stop = 150 # 阻止域端 [Hz]
rp = 1.0 # 通過域リップル [dB]
rs = 40.0 # 阻止域減衰量 [dB]
fs = 1000 # サンプリング周波数
# バターワースの必要次数
N_butter, Wn_butter = buttord(fp, fs_stop, rp, rs, fs=fs)
# チェビシェフI型の必要次数
N_cheby1, Wn_cheby1 = cheb1ord(fp, fs_stop, rp, rs, fs=fs)
# チェビシェフII型の必要次数
N_cheby2, Wn_cheby2 = cheb2ord(fp, fs_stop, rp, rs, fs=fs)
print(f"バターワース : {N_butter}次")
print(f"チェビシェフI型 : {N_cheby1}次")
print(f"チェビシェフII型: {N_cheby2}次")
実行結果:
バターワース : 12次
チェビシェフI型 : 6次
チェビシェフII型: 6次
同じ仕様(通過域端100Hz、阻止域端150Hz、通過域リップル1dB、阻止域減衰40dB)に対して、バターワースが12次必要なのに対し、チェビシェフはI型・II型ともに6次で仕様を満たせます。次数はそのまま伝達関数の状態変数の数(=実装コスト)に直結するため、この条件ではチェビシェフを使うことでバターワースの半分の演算量・メモリで同じ仕様を達成できることになります。
この6次のチェビシェフI型フィルタが本当に仕様を満たしているかを検証します。
from scipy import signal
import numpy as np
sos1 = signal.cheby1(N_cheby1, rp, Wn_cheby1, btype='low', fs=fs, output='sos')
_, h = signal.sosfreqz(sos1, worN=[fp, fs_stop], fs=fs)
gdb = 20 * np.log10(np.abs(h))
print(f"cheby1 N={N_cheby1}: gain@fp={gdb[0]:.3f}dB (要求 -{rp}dB), gain@fs_stop={gdb[1]:.3f}dB (要求 <=-{rs}dB)")
実行結果:
cheby1 N=6: gain@fp=-1.000dB (要求 -1.0dB), gain@fs_stop=-41.324dB (要求 <=-40.0dB)
通過域端でちょうど要求どおり \(-1.000\) dB、阻止域端では要求 \(-40.0\) dB に対して \(-41.324\) dB と1.3dB強の余裕を持って仕様を満たしていることが確認できます。なお、バターワース・チェビシェフI型・チェビシェフII型・楕円フィルタの4種を横並びで比較した次数表は 楕円フィルタの記事 にまとめているので、そちらも参照してください(楕円フィルタは同条件でさらに少ない次数になります)。
ノイズ除去への応用
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal
fs = 1000
t = np.arange(0, 1, 1/fs)
clean = np.sin(2 * np.pi * 10 * t) + 0.5 * np.sin(2 * np.pi * 30 * t)
noisy = clean + 0.8 * np.random.randn(len(t))
# バターワース(4次)
sos_butter = signal.butter(4, 100, fs=fs, output='sos')
y_butter = signal.sosfiltfilt(sos_butter, noisy)
# チェビシェフI型(4次、1dBリップル)
sos_cheby1 = signal.cheby1(4, 1, 100, fs=fs, output='sos')
y_cheby1 = signal.sosfiltfilt(sos_cheby1, noisy)
# チェビシェフII型(4次、40dB減衰)
sos_cheby2 = signal.cheby2(4, 40, 150, fs=fs, output='sos')
y_cheby2 = signal.sosfiltfilt(sos_cheby2, noisy)
fig, axes = plt.subplots(4, 1, figsize=(10, 12), sharex=True)
axes[0].plot(t, noisy, alpha=0.5, label='Noisy'); axes[0].plot(t, clean, 'k', label='Original')
axes[0].set_title('Input Signal'); axes[0].legend(); axes[0].grid(True, alpha=0.3)
axes[1].plot(t, y_butter, label='Butterworth N=4'); axes[1].plot(t, clean, 'k', lw=1.5)
axes[1].set_title('Butterworth (N=4)'); axes[1].legend(); axes[1].grid(True, alpha=0.3)
axes[2].plot(t, y_cheby1, label='Chebyshev I N=4, rp=1dB'); axes[2].plot(t, clean, 'k', lw=1.5)
axes[2].set_title('Chebyshev Type I (N=4, rp=1dB)'); axes[2].legend(); axes[2].grid(True, alpha=0.3)
axes[3].plot(t, y_cheby2, label='Chebyshev II N=4, rs=40dB'); axes[3].plot(t, clean, 'k', lw=1.5)
axes[3].set_title('Chebyshev Type II (N=4, rs=40dB)')
axes[3].set_xlabel('Time [s]'); axes[3].legend(); axes[3].grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
他のIIRフィルタとの比較
| フィルタ | 通過域 | 阻止域 | 遷移帯域 | 位相特性 |
|---|---|---|---|---|
| バターワース | 最大平坦 | 単調減少 | 広い | 比較的滑らか |
| チェビシェフI型 | 等リップル | 単調減少 | バターワースより狭い | 非線形 |
| チェビシェフII型 | 単調減少 | 等リップル | バターワースより狭い | 比較的滑らか |
| 楕円(Cauer) | 等リップル | 等リップル | 最も狭い | 最も非線形 |
急峻な遮断が必要で通過域のリップルが許容できる場合はI型、通過域の平坦性を保ちつつ阻止域を改善したい場合はII型が適しています。
近年の研究動向
古典的な整数次チェビシェフフィルタは、通過域リップル・阻止域減衰・遷移帯域幅という3つの仕様を式(2)(6)(7)の閉形式で満たす設計として1930年代以降確立していますが、次数 \(N\) は必然的に整数にしかなれず、「\(N\) 次では過剰、\(N+1\) 次では過大」という中途半端な要求に対しては次数を1つ余分に消費せざるを得ません。この制約に対し、2024年に Daryani と Aggarwal は、次数を実数 \(1+\alpha\) (\(0<\alpha<1\) )のように連続的に扱う分数次(fractional-order)チェビシェフローパスフィルタの設計に、粒子群最適化(PSO)・ホタルアルゴリズム(FA)・グレイウルフ最適化(GWO)といった自然界に着想を得たメタヒューリスティック最適化アルゴリズムを適用し、理想的な分数次チェビシェフ特性に近い振幅応答を実現する係数を求める手法を提案しました。さらに、求めた係数を実際にOTA(Operational Transconductance Amplifier)およびCCII(第2世代カレントコンベヤ)ベースのアナログ回路トポロジーで実装し、SPICEシミュレーションにより理想特性との平均二乗誤差がCCII構成で\(-48.67\) dB、OTA構成で\(-62.8\) dBという高精度で一致することを確認しています(Daryani & Aggarwal, 2024, Integration, the VLSI Journal)。
この研究は、本記事で扱った整数次のチェビシェフI型設計を置き換えるものではなく、次数という離散パラメータを連続化することで、整数次では実現できない「中間的な」遷移帯域の鋭さを実現する拡張と位置づけられます。組み込み用途で演算量が固定次数に強く制約される場合は本記事の整数次設計が引き続き主流ですが、アナログ回路設計や、次数を実数パラメータとして最適化ループに組み込みたい研究用途では、分数次アプローチが今後選択肢として広がっていく可能性があります。
まとめ
- チェビシェフフィルタはチェビシェフ多項式の等振幅特性を利用した等リップルIIRフィルタ
- I型は通過域に等リップル、II型は阻止域に等リップルを持つ
- チェビシェフ多項式が等リップルの構成要素に選ばれるのは、区間 \([-1,1]\) 上のモニック多項式の中で sup ノルムを最小化するという最小最大定理(equioscillation theorem)による
- I型フィルタのDC利得は次数の偶奇で変わり、奇数次は \(0\) dB、偶数次は \(-R_p\) dB になる
- 同次数でバターワースより急峻な遷移帯域を実現できる(本記事の実行例ではバターワース12次に対しチェビシェフI型・II型はいずれも6次)
- SciPyでは
signal.cheby1()/signal.cheby2()で設計、signal.cheb1ord()/signal.cheb2ord()で必要次数を自動計算できる
関連記事
- ローパスフィルタの設計と比較:移動平均・バターワース・チェビシェフ - 移動平均・バターワース・チェビシェフを周波数応答・群遅延・ステップ応答で比較しています。
- バターワースフィルタの設計原理とPython実装 - チェビシェフと同系統のIIRフィルタで、通過域が最大平坦なバターワースを解説しています。
- FIRフィルタとIIRフィルタの比較 - チェビシェフ(IIR)とFIRフィルタの設計思想の違いを解説しています。
- ノッチフィルタの設計とPython実装 - 特定周波数を除去するIIRフィルタの応用例を解説しています。
- 指数移動平均(EMA)フィルタの周波数特性 - 最も単純な1次IIRフィルタであるEMAの周波数特性を解説しています。
- 高速フーリエ変換(FFT)の仕組みとPython実装 - フィルタの周波数特性を解析するFFTの詳細を解説しています。
- 適応フィルタ(LMS/RLS)の理論とPython実装 - 固定設計のチェビシェフと対比して、パラメータが自動調整される適応フィルタを解説しています。
- ベッセルフィルタの理論とPython実装 - チェビシェフよりロールオフは緩いものの、群遅延がほぼ平坦で位相歪みを最小化したいときに選ぶ姉妹IIRです。
- 楕円フィルタ(Cauer)の理論とPython実装 - 通過域・阻止域の両方にリップルを許容し、同次数で最も急峻な遷移帯域を達成するチェビシェフの発展形です。
- ハイパスフィルタの設計とPython実装 - チェビシェフプロトタイプを周波数変換でハイパスに展開する設計手順を解説しています。
- バンドパスフィルタの設計とPython実装 - チェビシェフ型でバンドパスを構成する場合の通過域リップル設計の実例を示しています。
- ウィーナーフィルタの理論とPython実装 - チェビシェフが「指定通過域・阻止域要件」から設計するのに対し、ウィーナーは「SNRから最適帯域を自動設計」する点を対比できます。
- サビツキー・ゴーレイフィルタの理論とPython実装 - チェビシェフがIIR、サビツキー・ゴーレイがFIR平滑化と、設計思想を対比できる代表例です。
- Z変換と離散時間システムの理論 - チェビシェフの離散化と極零点配置(楕円上に配置された極)を理解する土台です。
- デジタルフィルタ設計指針ハブ:選定の3軸と特性比較 — 本記事のチェビシェフを他のフィルタ群と比較しながら選定する際の指針として活用できます。
参考文献
- Chebyshev, P. L. (1854). Théorie des mécanismes connus sous le nom de parallélogrammes. Mémoires des Savants Étrangers présentés à l’Académie de Saint-Pétersbourg, 7, 539-586.
- Proakis, J. G., & Manolakis, D. G. (2007). Digital Signal Processing (4th ed.). Pearson.
- Oppenheim, A. V., & Schafer, R. W. (2009). Discrete-Time Signal Processing (3rd ed.). Prentice Hall.
- Daryani, R., & Aggarwal, B. (2024). Nature inspired algorithm based design of near ideal fractional order low pass Chebyshev filters and their realization using OTAs and CCII. Integration, the VLSI Journal, 97, 102185. https://doi.org/10.1016/j.vlsi.2024.102185
- SciPy scipy.signal.cheby1 documentation
- SciPy scipy.signal.cheby2 documentation
- SciPy scipy.signal.cheb1ap documentation
関連ツール
- DevToolBox - 開発者向け無料ツール集 - JSON整形、正規表現テスターなど85種類以上の開発者向けツール
- CalcBox - 暮らしの計算ツール - 統計計算、複利計算など61種類以上の計算ツール