周波数応答とボード線図

周波数応答は、LTIシステムが各周波数の正弦波入力に対してどのように応答するかを表す特性です。ボード線図はこの周波数応答をゲインと位相の2つのグラフで視覚化したもので、制御系の設計や安定性解析に不可欠なツールです。

本記事では、周波数応答の数学的な意味、ゲインと位相の定義、ボード線図の構成、Pythonでの描画までを解説します。

本記事の内容

  • 正弦波入力に対するLTIシステムの定常応答
  • 周波数伝達関数 $G(j\omega)$ の意味
  • ゲイン $|G(j\omega)|$ と dB 表示
  • 位相 $\angle G(j\omega)$ の意味
  • ボード線図の構成とPythonでの描画

前提知識

この記事を読む前に、以下の記事を読んでおくと理解が深まります。

周波数応答とは

正弦波入力に対する定常応答

安定なLTIシステムに正弦波入力

$$ u(t) = A \sin(\omega t) $$

を加えると、過渡応答が減衰した後の定常状態での出力は

$$ \begin{equation} y_{ss}(t) = A |G(j\omega)| \sin\bigl(\omega t + \angle G(j\omega)\bigr) \end{equation} $$

となります。ここで $G(j\omega)$ は伝達関数 $G(s)$ において $s = j\omega$ と置いたものです。

つまり、LTIシステムは正弦波入力の周波数を変えず振幅と位相だけを変えるという性質を持ちます。

周波数伝達関数

$G(j\omega)$ は一般に複素数です。

$$ G(j\omega) = \text{Re}[G(j\omega)] + j \cdot \text{Im}[G(j\omega)] $$

極形式で書くと

$$ G(j\omega) = |G(j\omega)| e^{j\angle G(j\omega)} $$

  • ゲイン $|G(j\omega)|$ : 振幅比(入力振幅に対する出力振幅の比)
  • 位相 $\angle G(j\omega)$ : 位相のずれ(出力がどれだけ遅れるか/進むか)

導出

伝達関数 $G(s)$ のシステムに $u(t) = A e^{j\omega t}$ を入力します(複素正弦波)。

出力のラプラス変換は

$$ Y(s) = G(s) \cdot \frac{A}{s – j\omega} $$

$G(s)$ が安定(すべての極が左半面)であれば、$t \to \infty$ で過渡項は消え、定常出力は留数定理より

$$ y_{ss}(t) = A G(j\omega) e^{j\omega t} $$

実部を取ると

$$ y_{ss}(t) = A |G(j\omega)| \cos\bigl(\omega t + \angle G(j\omega)\bigr) $$

$\sin$ 入力に対しても同様に上の式が成り立ちます。

ゲインと dB 表示

ゲインの計算

ゲイン $|G(j\omega)|$ は $G(j\omega)$ の絶対値です。

$$ |G(j\omega)| = \sqrt{\text{Re}[G(j\omega)]^2 + \text{Im}[G(j\omega)]^2} $$

デシベル表示

ボード線図ではゲインをデシベル (dB)で表します。

$$ \begin{equation} \text{Gain [dB]} = 20 \log_{10} |G(j\omega)| \end{equation} $$

ゲイン比 dB 値 意味
0.01 -40 dB 振幅が1/100
0.1 -20 dB 振幅が1/10
1 0 dB 振幅が同じ
2 約 6 dB 振幅が2倍
10 20 dB 振幅が10倍
100 40 dB 振幅が100倍

dB 表示の利点は、直列結合のゲインが足し算になることです。

$$ |G_1 G_2|_{\text{dB}} = |G_1|_{\text{dB}} + |G_2|_{\text{dB}} $$

位相

位相 $\angle G(j\omega)$ は次のように計算します。

$$ \angle G(j\omega) = \arctan \frac{\text{Im}[G(j\omega)]}{\text{Re}[G(j\omega)]} $$

位相の単位は度 [deg] またはラジアン [rad] ですが、ボード線図では通常 [deg] を使います。

直列結合のとき

$$ \angle (G_1 G_2) = \angle G_1 + \angle G_2 $$

位相も足し算になります。

ボード線図の構成

ボード線図は2つのグラフからなります。

ゲイン線図(上段): – 横軸: 角周波数 $\omega$ [rad/s] — 対数スケール – 縦軸: ゲイン [dB]

位相線図(下段): – 横軸: 角周波数 $\omega$ [rad/s] — 対数スケール – 縦軸: 位相 [deg]

横軸を対数スケールにする理由は、周波数が数桁にわたる広い範囲を1つのグラフに収めるためです。1桁分の周波数変化(例: 1→10 rad/s)を1デカードと呼びます。

基本要素の周波数応答

比例要素: $G(s) = K$

$$ G(j\omega) = K $$

$$ |G(j\omega)| = K, \quad \angle G(j\omega) = 0° $$

ゲインは $20\log_{10} K$ [dB] の水平線、位相は 0° の水平線です。

積分要素: $G(s) = \frac{1}{s}$

$$ G(j\omega) = \frac{1}{j\omega} = -\frac{j}{\omega} $$

$$ |G(j\omega)| = \frac{1}{\omega}, \quad \angle G(j\omega) = -90° $$

ゲインは $-20$ dB/dec の直線($\omega$ が10倍になるとゲインが 20 dB 下がる)、位相は常に $-90°$ です。

1次遅れ要素: $G(s) = \frac{1}{\tau s + 1}$

$$ G(j\omega) = \frac{1}{j\omega\tau + 1} $$

$$ |G(j\omega)| = \frac{1}{\sqrt{1 + (\omega\tau)^2}} $$

$$ \angle G(j\omega) = -\arctan(\omega\tau) $$

折点周波数 $\omega_c = \frac{1}{\tau}$ が特性的な境界です。

帯域 ゲイン 位相
$\omega \ll \omega_c$ $\approx 0$ dB $\approx 0°$
$\omega = \omega_c$ $-3$ dB $-45°$
$\omega \gg \omega_c$ $-20$ dB/dec で減衰 $\to -90°$

Pythonでの実装

基本要素のボード線図

import numpy as np
import matplotlib.pyplot as plt
import control as ctrl

# 基本要素の定義
systems = {
    'Proportional (K=5)': ctrl.tf([5], [1]),
    'Integrator (1/s)': ctrl.tf([1], [1, 0]),
    '1st Order (τ=0.5)': ctrl.tf([1], [0.5, 1]),
    'Differentiator (s)': ctrl.tf([1, 0], [0.01, 1]),  # 近似的な微分器
}

fig, axes = plt.subplots(2, 2, figsize=(14, 10))
omega = np.logspace(-2, 2, 1000)

for idx, (name, G) in enumerate(systems.items()):
    row = idx // 2
    col = idx % 2
    ax_gain = axes[row, col]

    mag, phase, w = ctrl.frequency_response(G, omega)
    mag_db = 20 * np.log10(np.abs(mag))
    phase_deg = np.degrees(np.angle(mag))

    # ゲイン線図のみ表示(簡略化)
    ax_gain.semilogx(w, mag_db, 'b', linewidth=2)
    ax_gain.set_ylabel('Gain [dB]')
    ax_gain.set_xlabel('Frequency [rad/s]')
    ax_gain.set_title(f'Bode Plot: {name}')
    ax_gain.grid(True, which='both', alpha=0.3)
    ax_gain.axhline(y=0, color='k', linewidth=0.5)

plt.tight_layout()
plt.show()

正弦波入力と定常応答の可視化

import numpy as np
import matplotlib.pyplot as plt
import control as ctrl

# 1次遅れ系
tau = 0.5
G = ctrl.tf([1], [tau, 1])

# 3つの周波数で正弦波応答を確認
omegas = [0.5, 2.0, 10.0]

fig, axes = plt.subplots(len(omegas), 1, figsize=(12, 10))

for ax, omega in zip(axes, omegas):
    # G(jω)の計算
    Gjw = 1 / (1j * omega * tau + 1)
    gain = np.abs(Gjw)
    phase = np.angle(Gjw)
    gain_db = 20 * np.log10(gain)

    # 時間応答のシミュレーション
    t = np.linspace(0, 4 * 2 * np.pi / omega, 1000)
    u = np.sin(omega * t)
    t_out, y_out = ctrl.forced_response(G, T=t, U=u)

    # 定常応答(理論値)
    y_ss = gain * np.sin(omega * t + phase)

    ax.plot(t, u, 'b--', linewidth=1, alpha=0.5, label='Input $u(t)$')
    ax.plot(t_out, y_out, 'r', linewidth=2, label='Output $y(t)$')
    ax.plot(t, y_ss, 'g--', linewidth=1.5, label=f'Steady-state (|G|={gain:.3f}, ∠G={np.degrees(phase):.1f}°)')
    ax.set_xlabel('Time [s]')
    ax.set_ylabel('Amplitude')
    ax.set_title(f'ω = {omega} rad/s, Gain = {gain_db:.1f} dB, Phase = {np.degrees(phase):.1f}°')
    ax.legend(fontsize=8)
    ax.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

ボード線図の描画(ゲイン + 位相)

import numpy as np
import matplotlib.pyplot as plt
import control as ctrl

# 伝達関数: G(s) = 10 / ((s+1)(0.2s+1))
G = ctrl.tf([10], np.polymul([1, 1], [0.2, 1]))

omega = np.logspace(-2, 3, 1000)
mag, phase, w = ctrl.frequency_response(G, omega)
mag_db = 20 * np.log10(np.abs(mag))
phase_deg = np.degrees(np.unwrap(np.angle(mag)))

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

# ゲイン線図
ax1.semilogx(w, mag_db, 'b', linewidth=2)
ax1.axhline(y=0, color='k', linewidth=0.5)
ax1.set_ylabel('Gain [dB]')
ax1.set_title('Bode Plot: $G(s) = 10 / ((s+1)(0.2s+1))$')
ax1.grid(True, which='both', alpha=0.3)

# 折点周波数のマーク
for wc, label in [(1.0, 'ω=1/τ₁=1'), (5.0, 'ω=1/τ₂=5')]:
    ax1.axvline(x=wc, color='r', linestyle=':', alpha=0.5)
    ax1.annotate(label, xy=(wc, 15), fontsize=9, color='red')

# 位相線図
ax2.semilogx(w, phase_deg, 'b', linewidth=2)
ax2.axhline(y=-90, color='gray', linestyle=':', alpha=0.5)
ax2.axhline(y=-180, color='r', linestyle='--', alpha=0.5)
ax2.set_xlabel('Frequency [rad/s]')
ax2.set_ylabel('Phase [deg]')
ax2.grid(True, which='both', alpha=0.3)

plt.tight_layout()
plt.show()

まとめ

本記事では、周波数応答とボード線図について解説しました。

  • LTIシステムは正弦波入力の周波数を保ち、振幅と位相だけを変える
  • $G(j\omega)$ のゲインは振幅比、位相は位相のずれを表す
  • ゲインの dB 表示により直列結合が足し算になり、ボード線図が直感的になる
  • 基本要素(比例・積分・1次遅れ)のボード線図を理解することが応用の基礎

次のステップとして、以下の記事も参考にしてください。