ハイパスフィルタの設計とPython実装

ハイパスフィルタの理論(遮断周波数・阻止帯域)をZ変換と周波数応答から解説し、scipy.signalを用いたIIR/FIR設計とPythonによる可視化コードを紹介します。

ハイパスフィルタとは

ハイパスフィルタ(高域通過フィルタ)は、設定した遮断周波数より高い周波数成分を通過させ、低い周波数成分を減衰させるフィルタです。

直流成分(DC)の除去、振動センサの低周波ドリフト抑制、画像処理でのエッジ強調など、幅広い分野で活用されています。

主要パラメータ

パラメータ説明
\(f_c\)遮断周波数(-3dB点)
\(\omega_c\)遮断角周波数(\(\omega_c = 2\pi f_c\))
\(N\)フィルタ次数(大きいほど遷移帯域が急峻)
通過帯域\(f > f_c\) の周波数範囲
阻止帯域\(f < f_c\) の周波数範囲

次数 \(N\) が大きいほど遮断特性が急峻になりますが、位相遅れや数値的不安定性のリスクも増します。

周波数応答の導出

ローパス→ハイパス変換

ハイパスフィルタはローパスフィルタ(LPF)のプロトタイプから周波数変換によって設計できます。

アナログ領域でのローパス→ハイパス変換は、複素変数 \(s\) を以下のように置き換えます。

\[ s \rightarrow \frac{\omega_c^2}{s} \tag{1}\]

\(N\) 次のバターワース LPF の伝達関数

\[H_{LP}(s) = \frac{1}{\prod_{k=1}^{N}(s - s_k)} \tag{2}\]

に変換 \((1)\) を適用すると、同次のバターワースハイパスフィルタが得られます。1次の場合は次式になります。

\[H_{HP}(s) = \frac{s}{s + \omega_c} \tag{3}\]

式 \((3)\) は「微分器 + 1次ローパス」の構造を持ち、\(s \to 0\)(直流)で出力がゼロ、\(s \to \infty\)(高周波)で出力が1に近づくことを示しています。

離散時間ハイパスフィルタ(双一次変換)

式 \((3)\) を双一次変換(Bilinear Transform)でデジタル領域に変換します。

\[s = \frac{2}{T} \cdot \frac{1 - z^{-1}}{1 + z^{-1}} \tag{4}\]

これを式 \((3)\) に代入すると、1次デジタルハイパスフィルタの伝達関数が得られます。

\[H(z) = \frac{1 - z^{-1}}{1 + \alpha z^{-1}} \cdot \frac{1}{1 + \frac{1}{\alpha}} \tag{5}\]

ここで \(\alpha = 1 - 2f_c / f_s\)(プリワーピング係数)です。実用上は scipy.signal がこの計算を自動的に行います。

Pythonによる実装

scipy.signalを用いたIIRハイパスフィルタ

import numpy as np
import matplotlib.pyplot as plt
from scipy import signal

# --- パラメータ設定 ---
fs = 1000.0      # サンプリング周波数 [Hz]
fc = 100.0       # 遮断周波数 [Hz]
order = 4        # フィルタ次数

# --- バターワース ハイパスフィルタの設計 ---
nyq = fs / 2.0   # ナイキスト周波数
wn = fc / nyq    # 正規化遮断周波数

b, a = signal.butter(order, wn, btype='high')

# --- 周波数応答の計算 ---
w, h = signal.freqz(b, a, worN=8000, fs=fs)

# --- プロット ---
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8))

# ゲイン特性 (dB)
ax1.semilogx(w, 20 * np.log10(np.abs(h) + 1e-10))
ax1.axvline(fc, color='r', linestyle='--', label=f'$f_c$ = {fc} Hz')
ax1.axhline(-3, color='gray', linestyle=':', label='-3 dB')
ax1.set_xlabel('Frequency [Hz]')
ax1.set_ylabel('Gain [dB]')
ax1.set_title(f'Butterworth Highpass Filter (order={order})')
ax1.legend()
ax1.grid(True, which='both', alpha=0.3)
ax1.set_xlim([1, nyq])
ax1.set_ylim([-80, 5])

# 位相特性
ax2.semilogx(w, np.angle(h, deg=True))
ax2.axvline(fc, color='r', linestyle='--')
ax2.set_xlabel('Frequency [Hz]')
ax2.set_ylabel('Phase [degrees]')
ax2.set_title('Phase Response')
ax2.grid(True, which='both', alpha=0.3)
ax2.set_xlim([1, nyq])

plt.tight_layout()
plt.savefig('highpass_response.png', dpi=150, bbox_inches='tight')
plt.show()

FIRハイパスフィルタの設計

IIRフィルタは位相が非線形ですが、FIRフィルタは線形位相を実現できます。音声・医療信号処理など位相の保存が重要な場面で有用です。

from scipy.signal import firwin, freqz

# --- FIR ハイパスフィルタ ---
numtaps = 101    # フィルタ係数の数(奇数推奨)
fir_hpf = firwin(
    numtaps,
    fc,
    pass_zero=False,  # ハイパス指定
    fs=fs,
    window='hamming'
)

w_fir, h_fir = freqz(fir_hpf, worN=8000, fs=fs)

# IIRとFIRの比較プロット
plt.figure(figsize=(10, 5))
plt.semilogx(w, 20 * np.log10(np.abs(h) + 1e-10),
             label='IIR Butterworth (order=4)', linewidth=2)
plt.semilogx(w_fir, 20 * np.log10(np.abs(h_fir) + 1e-10),
             label=f'FIR Hamming (taps={numtaps})', linewidth=2, linestyle='--')
plt.axvline(fc, color='r', linestyle=':', alpha=0.7, label=f'$f_c$ = {fc} Hz')
plt.axhline(-3, color='gray', linestyle=':', alpha=0.7)
plt.xlabel('Frequency [Hz]')
plt.ylabel('Gain [dB]')
plt.title('Highpass Filter Comparison: IIR vs FIR')
plt.legend()
plt.grid(True, which='both', alpha=0.3)
plt.xlim([1, nyq])
plt.ylim([-80, 5])
plt.tight_layout()
plt.show()

信号への適用例

実際のノイズ混じり信号にハイパスフィルタを適用します。

# --- テスト信号の生成 ---
t = np.linspace(0, 1.0, int(fs), endpoint=False)  # 1秒分

# 目的信号: 200 Hz のサイン波(高周波成分)
signal_pure = np.sin(2 * np.pi * 200 * t)

# ノイズ: 5 Hz の低周波ドリフト + ホワイトノイズ
noise = (
    2.0 * np.sin(2 * np.pi * 5 * t) +   # 低周波ドリフト(大振幅)
    0.3 * np.random.randn(len(t))         # ホワイトノイズ
)

x_noisy = signal_pure + noise

# --- フィルタ適用 ---
# lfilter: 因果的フィルタ(リアルタイム処理向け、位相遅れあり)
y_lfilter = signal.lfilter(b, a, x_noisy)

# filtfilt: ゼロ位相フィルタ(オフライン処理向け、位相遅れなし)
y_filtfilt = signal.filtfilt(b, a, x_noisy)

# --- 比較プロット ---
fig, axes = plt.subplots(3, 1, figsize=(12, 8), sharex=True)

axes[0].plot(t[:300], x_noisy[:300], alpha=0.8, label='ノイズ混じり信号(低周波ドリフトあり)')
axes[0].set_ylabel('Amplitude')
axes[0].set_title('Input Signal (with low-frequency drift)')
axes[0].legend()
axes[0].grid(True, alpha=0.3)

axes[1].plot(t[:300], y_lfilter[:300], color='orange', label='lfilter (因果的)')
axes[1].plot(t[:300], signal_pure[:300], color='gray', linestyle='--', alpha=0.6, label='真の信号')
axes[1].set_ylabel('Amplitude')
axes[1].set_title('After lfilter (位相遅れあり)')
axes[1].legend()
axes[1].grid(True, alpha=0.3)

axes[2].plot(t[:300], y_filtfilt[:300], color='green', label='filtfilt (ゼロ位相)')
axes[2].plot(t[:300], signal_pure[:300], color='gray', linestyle='--', alpha=0.6, label='真の信号')
axes[2].set_ylabel('Amplitude')
axes[2].set_xlabel('Time [s]')
axes[2].set_title('After filtfilt (ゼロ位相)')
axes[2].legend()
axes[2].grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig('highpass_filtering_result.png', dpi=150, bbox_inches='tight')
plt.show()

IIR vs FIR 設計の比較

特性IIR(バターワース等)FIR
位相特性非線形(位相歪みあり)線形位相が実現可能
フィルタ係数数少ない(\(2N+1\)程度)多い(数十〜数百)
計算コスト低い高い(タップ数依存)
安定性設計によっては不安定常に安定
遮断特性低次でも急峻タップ数増加で改善
遅延非定数定数遅延(\((N-1)/2\)サンプル)
適した用途リアルタイム処理音声・医療信号処理

設計指針:

  • リアルタイムで計算コストを抑えたい → IIR(バターワース/チェビシェフ)
  • 位相の線形性が重要(音声・医療信号) → FIR(Hamming/Kaiser窓)
  • オフライン処理で位相遅れを完全除去 → filtfilt(IIR/FIR共通)

次数と遮断特性の影響

# 次数の違いによる周波数応答の比較
fig, ax = plt.subplots(figsize=(10, 6))

for ord_n in [1, 2, 4, 8]:
    b_n, a_n = signal.butter(ord_n, wn, btype='high')
    w_n, h_n = signal.freqz(b_n, a_n, worN=8000, fs=fs)
    ax.semilogx(w_n, 20 * np.log10(np.abs(h_n) + 1e-10), label=f'order={ord_n}')

ax.axhline(-3, color='gray', linestyle=':', label='-3 dB')
ax.axvline(fc, color='r', linestyle='--', alpha=0.5, label=f'$f_c$ = {fc} Hz')
ax.set_xlabel('Frequency [Hz]')
ax.set_ylabel('Gain [dB]')
ax.set_title('Effect of Filter Order on Highpass Response')
ax.legend()
ax.grid(True, which='both', alpha=0.3)
ax.set_xlim([1, nyq])
ax.set_ylim([-80, 5])
plt.tight_layout()
plt.show()

次数1では遷移帯域が緩やかで、次数8では急峻な遮断特性が得られます。ただし IIR フィルタでは次数が高くなるほど位相遅れと数値的不安定性のリスクが増すため、次数8以下が実用的な目安です。

ハイパスフィルタの実用例

用途\(f_c\) の目安備考
音声のDC除去(マイク補正)20〜80 HzDC 成分による信号飽和を防ぐ
加速度センサのドリフト除去0.1〜1 Hz重力成分(定常成分)を除去
心電図(ECG)のベースライン0.5〜1 Hz呼吸による低周波変動を除去
画像のエッジ強調2次元HPFで輪郭を強調(鮮鋭化)
振動解析の低周波ノイズ除去1〜10 Hz機械振動の直流バイアスや電源ハム波を除去

関連記事

参考文献


関連ツール