ナイキスト線図は、開ループ伝達関数 $G(j\omega)$ を複素平面上にプロットした図です。ボード線図がゲインと位相を別々に表示するのに対し、ナイキスト線図は両方の情報を1つの図に統合します。特に、$(-1, 0)$ 点との位置関係から閉ループ系の安定性を判別できるのが大きな特徴です。
本記事では、ナイキスト線図の描き方、基本要素の軌跡、$(-1, 0)$ 点の意味、Pythonでの描画までを解説します。
本記事の内容
- ナイキスト線図の定義と描き方
- 基本要素のナイキスト線図
- $(-1, 0)$ 点と安定性の関係
- 安定判別への橋渡し
- Pythonでの描画
前提知識
この記事を読む前に、以下の記事を読んでおくと理解が深まります。
ナイキスト線図とは
定義
ナイキスト線図は、角周波数 $\omega$ を $0$ から $\infty$ まで変化させたときの $G(j\omega)$ の軌跡を複素平面(横軸: 実部、縦軸: 虚部)上に描いたものです。
$$ G(j\omega) = \text{Re}[G(j\omega)] + j \cdot \text{Im}[G(j\omega)] $$
各周波数 $\omega$ に対して、
- 原点から点 $G(j\omega)$ までの距離 = ゲイン $|G(j\omega)|$
- 実軸正方向からの角度 = 位相 $\angle G(j\omega)$
です。
ボード線図との関係
| 情報 | ボード線図 | ナイキスト線図 |
|---|---|---|
| ゲイン | 縦軸(dB) | 原点からの距離 |
| 位相 | 縦軸(deg) | 実軸からの角度 |
| 周波数 | 横軸 | 曲線上の点(パラメータ) |
基本要素のナイキスト線図
1次遅れ要素: $G(s) = \frac{1}{\tau s + 1}$
$$ G(j\omega) = \frac{1}{j\omega\tau + 1} = \frac{1 – j\omega\tau}{1 + (\omega\tau)^2} $$
実部と虚部は
$$ \text{Re} = \frac{1}{1 + (\omega\tau)^2}, \quad \text{Im} = \frac{-\omega\tau}{1 + (\omega\tau)^2} $$
軌跡は中心 $(1/2, 0)$、半径 $1/2$ の半円(下半面)です。
これは $\text{Re}^2 + \text{Im}^2 = \text{Re}$ より
$$ \left(\text{Re} – \frac{1}{2}\right)^2 + \text{Im}^2 = \frac{1}{4} $$
と確認できます。
- $\omega = 0$: $G(0) = 1$(実軸上の点 $(1, 0)$)
- $\omega = 1/\tau$: $G = \frac{1}{2} – j\frac{1}{2}$(ゲイン $\frac{1}{\sqrt{2}}$, 位相 $-45°$)
- $\omega \to \infty$: $G \to 0$(原点に収束)
積分要素: $G(s) = \frac{1}{s}$
$$ G(j\omega) = \frac{1}{j\omega} = -\frac{j}{\omega} $$
軌跡は負の虚軸上の直線です。$\omega = 0$ で $-j\infty$、$\omega \to \infty$ で原点に向かいます。
2次遅れ要素: $G(s) = \frac{\omega_n^2}{s^2 + 2\zeta\omega_n s + \omega_n^2}$
$$ G(j\omega) = \frac{\omega_n^2}{(j\omega)^2 + 2\zeta\omega_n(j\omega) + \omega_n^2} = \frac{\omega_n^2}{\omega_n^2 – \omega^2 + 2j\zeta\omega_n\omega} $$
$\zeta$ が小さいとき、$\omega \approx \omega_n$ 付近で虚部が大きくなり、共振ピークに対応するループが現れます。
$(-1, 0)$ 点と安定性
なぜ $(-1, 0)$ 点が重要か
閉ループ伝達関数は
$$ G_{cl}(s) = \frac{L(s)}{1 + L(s)} $$
ここで $L(s)$ は開ループ伝達関数です。閉ループ系が不安定になる条件は $1 + L(s) = 0$、つまり $L(s) = -1$ です。
周波数領域で考えると、$L(j\omega_0) = -1$ となる $\omega_0$ が存在すれば、閉ループ系は安定限界にあります。$L(j\omega_0) = -1$ とは、ナイキスト線図上で $(-1, 0)$ を通ることに他なりません。
直感的な理解
$L(j\omega_0) = -1$ の意味: * ゲイン $|L(j\omega_0)| = 1$(振幅が変わらない) * 位相 $\angle L(j\omega_0) = -180°$(完全に反転)
フィードバック系では出力が符号反転して戻ってきますが、さらに位相が $-180°$ ずれると、正のフィードバック(自己強化)になります。ゲインが1以上なら振幅が増大し、系は発散します。
ナイキストの安定判別法(概要)
開ループ伝達関数 $L(s)$ が安定(すべての極が左半面)な場合、閉ループ系が安定であるための条件は
$$ \text{ナイキスト線図が点 } (-1, 0) \text{ を反時計回りに囲まないこと} $$
ナイキスト線図が $(-1, 0)$ の左側を通るほど安定余裕が小さく、右側を大きく通るほど安定余裕が大きいと判断できます。
Pythonでの実装
基本要素のナイキスト線図
import numpy as np
import matplotlib.pyplot as plt
import control as ctrl
fig, axes = plt.subplots(2, 2, figsize=(12, 10))
systems = {
'1st Order: 1/(s+1)': ctrl.tf([1], [1, 1]),
'Integrator: 1/s': ctrl.tf([1], [1, 0]),
'2nd Order (ζ=0.3): ωn=2': ctrl.tf([4], [1, 1.2, 4]),
'2nd Order (ζ=0.7): ωn=2': ctrl.tf([4], [1, 2.8, 4]),
}
omega = np.logspace(-2, 2, 1000)
for ax, (name, G) in zip(axes.flat, systems.items()):
mag, phase, w = ctrl.frequency_response(G, omega)
re = np.real(mag)
im = np.imag(mag)
ax.plot(re, im, 'b', linewidth=2, label='$\\omega$: 0→∞')
ax.plot(re, -im, 'b--', linewidth=1, alpha=0.5, label='$\\omega$: 0→-∞')
# (-1,0)点
ax.plot(-1, 0, 'r+', markersize=15, markeredgewidth=2)
# 始点と終点のマーク
ax.plot(re[0], im[0], 'go', markersize=8, label=f'ω≈0')
ax.plot(re[-1], im[-1], 'rs', markersize=8, label=f'ω→∞')
ax.set_xlabel('Real')
ax.set_ylabel('Imaginary')
ax.set_title(name)
ax.grid(True, alpha=0.3)
ax.legend(fontsize=7)
ax.set_aspect('equal')
ax.axhline(y=0, color='k', linewidth=0.5)
ax.axvline(x=0, color='k', linewidth=0.5)
plt.tight_layout()
plt.show()
ゲインを変化させたナイキスト線図と安定性
import numpy as np
import matplotlib.pyplot as plt
import control as ctrl
# プラント: P(s) = 1 / (s(s+1)(0.5s+1))
P = ctrl.tf([1], np.polymul(np.polymul([1, 0], [1, 1]), [0.5, 1]))
gains = [0.5, 1.0, 1.5, 2.0]
omega = np.logspace(-2, 2, 2000)
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))
for K in gains:
L = K * P # 開ループ伝達関数
mag, phase, w = ctrl.frequency_response(L, omega)
re = np.real(mag)
im = np.imag(mag)
ax1.plot(re, im, linewidth=2, label=f'K={K}')
# 閉ループのステップ応答
G_cl = ctrl.feedback(L, 1)
try:
t, y = ctrl.step_response(G_cl, T=np.linspace(0, 15, 500))
ax2.plot(t, y, linewidth=2, label=f'K={K}')
except Exception:
pass
# (-1,0)点のマーク
ax1.plot(-1, 0, 'r+', markersize=20, markeredgewidth=3, label='(-1, 0)')
ax1.set_xlabel('Real')
ax1.set_ylabel('Imaginary')
ax1.set_title('Nyquist Plot: KP(s)')
ax1.grid(True, alpha=0.3)
ax1.legend()
ax1.set_xlim([-3, 1])
ax1.set_ylim([-3, 1])
ax1.axhline(y=0, color='k', linewidth=0.5)
ax1.axvline(x=0, color='k', linewidth=0.5)
ax2.axhline(y=1.0, color='k', linestyle='--', alpha=0.3)
ax2.set_xlabel('Time [s]')
ax2.set_ylabel('Output y(t)')
ax2.set_title('Closed-loop Step Response')
ax2.legend()
ax2.grid(True, alpha=0.3)
plt.tight_layout()
plt.show()
python-controlの nyquist_plot 関数
import numpy as np
import matplotlib.pyplot as plt
import control as ctrl
# 開ループ伝達関数
L = ctrl.tf([10], np.polymul(np.polymul([1, 0], [1, 1]), [0.5, 1]))
# python-controlのナイキスト線図描画
fig, ax = plt.subplots(1, 1, figsize=(8, 8))
omega = np.logspace(-2, 2, 1000)
mag, phase, w = ctrl.frequency_response(L, omega)
re = np.real(mag)
im = np.imag(mag)
ax.plot(re, im, 'b', linewidth=2, label='$\\omega > 0$')
ax.plot(re, -im, 'b--', linewidth=1, alpha=0.5, label='$\\omega < 0$')
ax.plot(-1, 0, 'r+', markersize=20, markeredgewidth=3, label='(-1, 0)')
# 矢印で方向を示す
mid = len(re) // 4
ax.annotate('', xy=(re[mid+1], im[mid+1]),
xytext=(re[mid], im[mid]),
arrowprops=dict(arrowstyle='->', color='blue', lw=2))
ax.set_xlabel('Real')
ax.set_ylabel('Imaginary')
ax.set_title('Nyquist Plot: $L(s) = 10/(s(s+1)(0.5s+1))$')
ax.grid(True, alpha=0.3)
ax.legend(fontsize=10)
ax.set_aspect('equal')
ax.axhline(y=0, color='k', linewidth=0.5)
ax.axvline(x=0, color='k', linewidth=0.5)
plt.tight_layout()
plt.show()
まとめ
本記事では、ナイキスト線図の描き方と読み方について解説しました。
- ナイキスト線図は $G(j\omega)$ の軌跡を複素平面上に描いたもの
- 原点からの距離がゲイン、実軸からの角度が位相に対応する
- $(-1, 0)$ 点は閉ループ系の安定限界を表す臨界点
- ナイキスト線図が $(-1, 0)$ を囲むかどうかで閉ループ系の安定性を判別できる
次のステップとして、以下の記事も参考にしてください。