チェビシェフフィルタの設計

本稿では、チェビシェフフィルタの設計手順を解説する。 仕様からフィルタ次数を決定し、極を計算し、2次セクションの係数を求める方法を示す。 Python(SciPy)による実装例も掲載する。

設計仕様

チェビシェフI型ローパスフィルタの設計には、以下の4つのパラメータが必要である:

  • $\omega_p$:通過域端周波数(カットオフ周波数)
  • $\omega_s$:阻止域端周波数
  • $R_p$:通過域リップル [dB](通過域での最大減衰量)
  • $A_s$:阻止域減衰量 [dB](阻止域での最小減衰量)
フィルタ仕様の図解
図1: フィルタ設計仕様のパラメータ

基準化について: 設計計算では通過域端周波数を $\omega_p = 1$ rad/s に基準化する。 最終的に周波数スケーリングで実際の周波数に変換する。

次数決定公式

チェビシェフI型の次数公式

与えられた仕様を満たす最小次数 $n$ は、以下の式で計算できる:

\begin{equation} n \geq \dfrac{\cosh^{-1}\left(\sqrt{\dfrac{10^{A_s/10} - 1}{10^{R_p/10} - 1}}\right)}{\cosh^{-1}(\omega_s / \omega_p)} \label{eq:order} \end{equation}
導出: 阻止域端 $\omega = \omega_s$ での減衰量が $A_s$ dB 以上となる条件: $$10\log_{10}(1 + \varepsilon^2 T_n^2(\omega_s/\omega_p)) \geq A_s$$ $\omega_s/\omega_p > 1$ なので双曲線関数表現 $T_n(x) = \cosh(n \cosh^{-1} x)$ を使い、 $\varepsilon = \sqrt{10^{R_p/10} - 1}$ を代入して $n$ について解く。

バターワースとの比較

参考として、バターワースフィルタの次数公式は:

\begin{equation} n_{\text{Butterworth}} \geq \dfrac{\log\left(\sqrt{\dfrac{10^{A_s/10} - 1}{10^{R_p/10} - 1}}\right)}{\log(\omega_s / \omega_p)} \label{eq:order-butter} \end{equation}

チェビシェフの式では $\log$ が $\cosh^{-1}$ に置き換わっている。 $\cosh^{-1}(x) \approx \log(2x)$ により分子はほぼ等しいが、分母が $\log(\omega_s/\omega_p)$ から $\cosh^{-1}(\omega_s/\omega_p)$ に変わるため、同じ仕様をチェビシェフはより低い次数で実現できる(削減の度合いは仕様に依存する)。

数値例

仕様:$R_p = 1$ dB, $A_s = 40$ dB, $\omega_s/\omega_p = 2$

$$ \varepsilon = \sqrt{10^{0.1} - 1} \approx 0.5088 $$ $$ \sqrt{\dfrac{10^{4} - 1}{10^{0.1} - 1}} = \sqrt{\dfrac{9999}{0.2589}} \approx 196.5 $$ $$ n \geq \dfrac{\cosh^{-1}(196.5)}{\cosh^{-1}(2)} = \dfrac{5.98}{1.32} \approx 4.5 $$

したがって $n = 5$ が必要。同じ仕様でバターワースは $n = 8$ が必要となり、チェビシェフの方が低次で済む。

設計手順

ステップ1:次数とリップルパラメータの決定

式\eqref{eq:order}から次数 $n$ を計算(切り上げ)し、リップルパラメータを求める:

$$\varepsilon = \sqrt{10^{R_p/10} - 1}$$

ステップ2:楕円パラメータの計算

極が分布する楕円のパラメータを計算:

$$\eta = \dfrac{1}{n}\sinh^{-1}\left(\dfrac{1}{\varepsilon}\right)$$

楕円の半軸:

$$a = \sinh(\eta), \quad b = \cosh(\eta)$$

ステップ3:極の計算

$m = 0, 1, \ldots, n-1$ に対して:

$$x_m = \dfrac{(2m+1)\pi}{2n}$$ $$p_m = -\sin(x_m) \cdot a + j\cos(x_m) \cdot b$$

(左半平面の極のみを使用)

ステップ4:2次セクションへの分解

複素共役ペアを組み合わせて2次セクションを構成:

$$H_k(s) = \dfrac{\omega_{0,k}^2}{s^2 + \dfrac{\omega_{0,k}}{Q_k}s + \omega_{0,k}^2}$$

ここで:

$$\omega_{0,k} = |p_k|, \quad Q_k = \dfrac{|p_k|}{-2\text{Re}(p_k)}$$

ステップ5:周波数スケーリング

基準フィルタ($\omega_p = 1$)から実際のカットオフ周波数 $\omega_c$ へ:

$$s \to \dfrac{s}{\omega_c}$$

すべての $\omega_0$ を $\omega_c$ 倍する。

ステップ6:ゲイン調整

偶数次の場合、DCゲインが $-R_p$ dB になるよう調整:

$$K = \dfrac{1}{\sqrt{1 + \varepsilon^2}}$$

奇数次の場合、DCゲインは 0 dB なので $K = 1$。

設計例

通過域リップル 1 dB、次数 $n = 6$ のチェビシェフI型基準ローパスフィルタを設計する。

パラメータの計算

$$ \varepsilon = \sqrt{10^{0.1} - 1} \approx 0.5088 $$ $$ \eta = \dfrac{1}{6}\sinh^{-1}\left(\dfrac{1}{0.5088}\right) \approx 0.2384 $$ $$ a = \sinh(0.2384) \approx 0.2406, \quad b = \cosh(0.2384) \approx 1.0287 $$

極の位置

$m$$x_m$極 $p_m$$\omega_0$$Q$
0 $\pi/12 = 15°$ $-0.0623 + j0.9935$ 0.9955 7.99
1 $3\pi/12 = 45°$ $-0.1701 + j0.7275$ 0.7471 2.20
2 $5\pi/12 = 75°$ $-0.2324 + j0.2662$ 0.3534 0.76

(左半平面の極のみ。$m = 3, 4, 5$ は共役極なので省略)

2次セクションの係数

セクション$\omega_0$$Q$分母多項式
1 0.9955 7.99 $s^2 + 0.1246s + 0.9910$
2 0.7471 2.20 $s^2 + 0.3398s + 0.5582$
3 0.3534 0.76 $s^2 + 0.4649s + 0.1249$

接続順序: 縦続接続する場合は、$Q$ 値の低いセクション(セクション3)を入力側に、 $Q$ 値の高いセクション(セクション1)を出力側に配置する。 これによりダイナミックレンジとノイズ特性が最適化される。

Python実装

SciPyによる設計

import numpy as np
from scipy.signal import cheby1, cheby1ord, freqs, tf2zpk

# 仕様
Rp = 1.0    # 通過域リップル [dB]
As = 40.0   # 阻止域減衰量 [dB]
wp = 1.0    # 通過域端周波数 [rad/s]
ws = 2.0    # 阻止域端周波数 [rad/s]

# 次数決定
n, Wn = cheby1ord(wp, ws, Rp, As, analog=True)
print(f"必要次数: {n}")
print(f"カットオフ周波数: {Wn:.4f} rad/s")

# フィルタ設計
b, a = cheby1(n, Rp, Wn, btype='low', analog=True)
print(f"\n分子係数 b: {b}")
print(f"分母係数 a: {a}")

# 極・零点・ゲイン形式
z, p, k = tf2zpk(b, a)
print(f"\n極:")
for i, pole in enumerate(p):
    print(f"  p{i}: {pole:.4f}, |p|={np.abs(pole):.4f}, Q={np.abs(pole)/(-2*pole.real):.2f}")

極から2次セクションへの変換

from scipy.signal import zpk2sos

# 2次セクション形式に変換
sos = zpk2sos(z, p, k)

print("2次セクション (sos):")
print("  [b0, b1, b2, a0, a1, a2]")
for i, section in enumerate(sos):
    print(f"  Section {i+1}: {section}")

# 標準形パラメータへの変換
print("\n標準形パラメータ:")
for i, section in enumerate(sos):
    b0, b1, b2, a0, a1, a2 = section
    omega0 = np.sqrt(a2/a0)
    Q = omega0 / (a1/a0)
    print(f"  Section {i+1}: ω₀ = {omega0:.4f}, Q = {Q:.4f}")

周波数応答のプロット

import matplotlib.pyplot as plt

# 周波数応答
w = np.logspace(-1, 1, 500)
w, H = freqs(b, a, w)

fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8))

# 振幅特性
ax1.semilogx(w, 20*np.log10(np.abs(H)))
ax1.axhline(-Rp, color='r', linestyle='--', label=f'Passband ripple ({-Rp} dB)')
ax1.axhline(-As, color='g', linestyle='--', label=f'Stopband attenuation ({-As} dB)')
ax1.axvline(wp, color='b', linestyle=':', alpha=0.5)
ax1.axvline(ws, color='b', linestyle=':', alpha=0.5)
ax1.set_ylabel('Magnitude [dB]')
ax1.set_ylim(-60, 5)
ax1.legend()
ax1.grid(True)

# 位相特性
ax2.semilogx(w, np.unwrap(np.angle(H)) * 180/np.pi)
ax2.set_xlabel('Frequency [rad/s]')
ax2.set_ylabel('Phase [degrees]')
ax2.grid(True)

plt.tight_layout()
plt.show()

部品値計算(Sallen-Key用)

def sallen_key_components(omega0, Q, R):
    """
    Sallen-Key回路の部品値を計算(R1=R2=R)

    Parameters:
        omega0: 自然角周波数 [rad/s]
        Q: Q値
        R: 抵抗値 [Ω]

    Returns:
        C1, C2: コンデンサ値 [F]
    """
    C2 = 1 / (2 * Q * omega0 * R)
    C1 = 2 * Q / (omega0 * R)
    return C1, C2

# 設計例:1kHz カットオフ、R = 10kΩ
fc = 1000  # Hz
R = 10000  # Ω
omega_scale = 2 * np.pi * fc

print(f"カットオフ周波数: {fc} Hz")
print(f"抵抗: {R/1000} kΩ")
print()

for i, section in enumerate(sos):
    b0, b1, b2, a0, a1, a2 = section
    omega0_norm = np.sqrt(a2/a0)
    Q = omega0_norm / (a1/a0)
    omega0_actual = omega0_norm * omega_scale

    C1, C2 = sallen_key_components(omega0_actual, Q, R)

    print(f"セクション {i+1}:")
    print(f"  ω₀ = {omega0_actual:.1f} rad/s ({omega0_actual/2/np.pi:.1f} Hz)")
    print(f"  Q = {Q:.3f}")
    print(f"  C₁ = {C1*1e9:.2f} nF")
    print(f"  C₂ = {C2*1e9:.2f} nF")
    print()

II型の設計

チェビシェフII型(逆チェビシェフ)の設計も同様の手順だが、 指定するパラメータが異なる。

次数決定公式(II型)

チェビシェフフィルタの次数決定公式は I 型・II 型で共通であり、通過域リップル $R_p$ と阻止域減衰量 $A_s$ の両方を含む(式\eqref{eq:order} と同一):

\begin{equation} n \geq \dfrac{\cosh^{-1}\left(\sqrt{\dfrac{10^{A_s/10} - 1}{10^{R_p/10} - 1}}\right)}{\cosh^{-1}(\omega_s / \omega_p)} \label{eq:order-type2} \end{equation}

II型は通過域が単調(最大平坦)となるため、$R_p$ は通過域端での許容偏差として与える。下の Python 例では通過域仕様に 3 dB を用いている。

Python実装(II型)

from scipy.signal import cheby2, cheby2ord

# 仕様
As = 40.0   # 阻止域減衰量 [dB]
wp = 1.0    # 通過域端周波数 [rad/s]
ws = 2.0    # 阻止域端周波数 [rad/s]

# 次数決定
n, Wn = cheby2ord(wp, ws, 3, As, analog=True)  # 3dB は通過域
print(f"必要次数: {n}")

# フィルタ設計
b, a = cheby2(n, As, Wn, btype='low', analog=True)

# 周波数応答
w = np.logspace(-1, 1, 500)
w, H = freqs(b, a, w)

plt.figure(figsize=(10, 4))
plt.semilogx(w, 20*np.log10(np.abs(H)))
plt.axhline(-As, color='r', linestyle='--', label=f'Stopband ({-As} dB)')
plt.xlabel('Frequency [rad/s]')
plt.ylabel('Magnitude [dB]')
plt.title('Chebyshev Type II Filter')
plt.legend()
plt.grid(True)
plt.ylim(-60, 5)
plt.show()

II型の注意点: II型は虚軸上に零点を持つため、アナログ回路での実装がI型より複雑になる。 零点を実現するにはバイカッド回路や状態変数フィルタが必要となる。 回路編を参照。

周波数変換

基準ローパスフィルタから他のフィルタタイプへの変換:

変換 置換 説明
LP → LP $s \to s/\omega_c$ 周波数スケーリング
LP → HP $s \to \omega_c/s$ ハイパスへ変換
LP → BP $s \to \dfrac{s^2 + \omega_0^2}{Bs}$ バンドパスへ変換($B$は帯域幅)
LP → BS $s \to \dfrac{Bs}{s^2 + \omega_0^2}$ バンドストップへ変換

バンドパス/バンドストップ設計の重要パラメータ

バンドパスフィルタ(BPF)やバンドストップフィルタ(BEF/ノッチ)を設計する際、 以下のパラメータを理解することが重要である。

中心周波数と帯域幅

中心周波数 $f_0$(または $\omega_0$)
通過域(BPF)または阻止域(BEF)の中心となる周波数。 BPFではこの周波数で最大ゲイン、BEFでは最大減衰となる。
帯域幅 $B$(または $\Delta\omega$)
BPFでは通過域の幅、BEFでは阻止域の幅。 リップルレベルでの上限周波数 $f_H$ と下限周波数 $f_L$ の差として定義される。 \begin{equation} B = f_H - f_L \end{equation}

幾何平均中心周波数

フィルタ理論では、中心周波数は上限と下限の幾何平均として定義されることが多い:

\begin{equation} f_0 = \sqrt{f_L \cdot f_H} \end{equation}

これは対数周波数軸で見たときに $f_0$ が $f_L$ と $f_H$ の中央に来ることを意味する。 算術平均 $(f_L + f_H)/2$ とは異なることに注意。

比帯域(Fractional Bandwidth)とQ値

帯域幅を中心周波数で正規化した比帯域と、その逆数であるQ値は、 BPF/BEFの「狭さ」を表す重要な指標である。

\begin{equation} \text{比帯域} = \dfrac{B}{f_0}, \quad Q = \dfrac{f_0}{B} \end{equation}
Q値 比帯域 フィルタの特性 用途例
1 100% 広帯域 オーディオ帯域フィルタ
5 20% 中帯域 RFチャンネルフィルタ
10 10% 狭帯域 IF フィルタ
50 2% 非常に狭い 単一周波数選択
100+ 1%以下 極狭帯域 ノッチフィルタ、水晶フィルタ

LP → BP 変換と次数の関係

$n$ 次のローパスプロトタイプを LP → BP 変換すると、結果のバンドパスフィルタは $2n$ 次 になる。 これは、変換式 $s \to (s^2 + \omega_0^2)/(Bs)$ が各極を2つの極に分裂させるためである。

  • 3次LPF → 6次BPF(3組の共役複素極対)
  • 4次LPF → 8次BPF(4組の共役複素極対)

狭帯域BPFの設計上の注意

Q値が高い(狭帯域な)BPFは、実装が難しくなる。

  • 部品感度:Q値が高いほど、部品のばらつきに対して特性が敏感になる
  • ポールQの増加:変換後の2次セクションのQ値は、元のLPFのQ値にBPFのQ値を掛けた値に近くなる
  • 実用的な限界:アクティブフィルタでは $Q \approx 30$ 程度が実用上限。それ以上は水晶フィルタやSAWフィルタを検討

設計のヒント: 狭帯域BPF($Q > 10$)が必要な場合:

  • LPFプロトタイプのリップルを小さく(0.1 dB以下)してポールQを抑える
  • 状態変数フィルタやバイカッド回路など、高Q対応のトポロジーを選ぶ
  • 非常に高Q($Q > 100$)が必要なら、水晶フィルタやSAWフィルタを検討

Pythonでの各種フィルタ設計

# SciPy での各種フィルタ設計
from scipy.signal import cheby1

n = 4
rp = 1.0

# ローパス
b_lp, a_lp = cheby1(n, rp, 1000, btype='low', analog=True)

# ハイパス
b_hp, a_hp = cheby1(n, rp, 1000, btype='high', analog=True)

# バンドパス(中心1000 rad/s、帯域幅200 rad/s)
# 注:SciPyでは下限・上限周波数を指定
b_bp, a_bp = cheby1(n, rp, [900, 1100], btype='band', analog=True)

# バンドストップ
b_bs, a_bs = cheby1(n, rp, [900, 1100], btype='stop', analog=True)

# Q値と帯域幅の計算例
f_L, f_H = 900, 1100
f_0 = (f_L * f_H) ** 0.5  # 幾何平均中心周波数
B = f_H - f_L             # 帯域幅
Q = f_0 / B               # Q値
print(f"中心周波数: {f_0:.1f} rad/s")
print(f"帯域幅: {B} rad/s")
print(f"Q値: {Q:.2f}")

よくある質問

Q1: チェビシェフフィルタの設計手順はどのようなものか

A: 1)仕様(通過域周波数f_p、リップルA_p、阻止域周波数f_s、減衰量A_s)を決定、2)必要次数n を計算式 n>=acosh(sqrt((10^(A_s/10)-1)/(10^(A_p/10)-1)))/acosh(f_s/f_p) で求める、3)テーブルから正規化素子値を読む、4)周波数スケーリングと負荷変換を適用する、の手順で設計する。

Q2: チェビシェフフィルタの遮断周波数の定義はバターワースとどう違うか

A: バターワースでは遮断周波数で-3dBになるが、チェビシェフタイプIでは遮断周波数を通過域端(等リップル域の端)として定義する。この周波数でゲインがリップル量A_p だけ低下する。設計テーブルや計算式ではこの定義を使うことが多いため注意が必要である。

Q3: チェビシェフ設計テーブルの素子値はどのように使うか

A: テーブルから次数n とリップルε に対応する正規化素子値 g_1, g_2,...,g_{n+1} を読み取る。これらは遮断周波数Ω_c=1rad/s、ソース・負荷抵抗R=1Ω の場合の値である。実際には周波数変換(Ω_c で割る)とインピーダンス変換(R_L 倍する)を適用して実際の素子値を求める。