減衰振動と強制振動の理論を丁寧に導出する

現実の振動系には必ず減衰(エネルギー散逸)が存在し、外部から強制力が加わることもあります。減衰振動と強制振動は、機械振動の設計、地震応答解析、電気回路のフィルタ設計など、工学のあらゆる分野で重要です。

特に共振現象は、橋の崩壊(タコマナローズ橋事件)から楽器の音色まで、劇的な効果をもたらします。本記事では、減衰振動の3つのケースと強制振動の定常解を、微分方程式の解法とともに丁寧に導出します。

本記事の内容

  • 減衰振動の運動方程式と3つのケース
  • 強制振動と定常解の導出
  • 共振現象の数学的記述
  • Pythonでの可視化

前提知識

減衰振動

運動方程式

速度に比例する減衰力 $F_d = -c\dot{x}$ を加えると:

$$ m\ddot{x} + c\dot{x} + kx = 0 $$

$\gamma = c/(2m)$(減衰係数)、$\omega_0 = \sqrt{k/m}$(固有角振動数)とおくと:

$$ \begin{equation} \ddot{x} + 2\gamma\dot{x} + \omega_0^2 x = 0 \end{equation} $$

特性方程式

$x = e^{\lambda t}$ を仮定すると:

$$ \lambda^2 + 2\gamma\lambda + \omega_0^2 = 0 \implies \lambda = -\gamma \pm \sqrt{\gamma^2 – \omega_0^2} $$

$\gamma$ と $\omega_0$ の大小関係で3つのケースに分かれます。

ケース1: 不足減衰($\gamma < \omega_0$)

減衰振動数 $\omega_d = \sqrt{\omega_0^2 – \gamma^2}$ とおくと:

$$ \begin{equation} x(t) = Ae^{-\gamma t}\cos(\omega_d t + \phi) \end{equation} $$

振動しながら指数関数的に減衰します。最もよく見られるケースです。

ケース2: 臨界減衰($\gamma = \omega_0$)

$$ \begin{equation} x(t) = (C_1 + C_2 t)e^{-\gamma t} \end{equation} $$

振動せずに最も速く平衡位置に戻ります。ドアクローザーやショックアブソーバーの理想的な設計です。

ケース3: 過減衰($\gamma > \omega_0$)

$$ \begin{equation} x(t) = C_1 e^{\lambda_1 t} + C_2 e^{\lambda_2 t} \end{equation} $$

$\lambda_1, \lambda_2$ はともに負の実数。振動せずにゆっくりと平衡に戻ります。

減衰比(ダンピング比)

$$ \zeta = \frac{\gamma}{\omega_0} = \frac{c}{2\sqrt{mk}} $$

$\zeta < 1$: 不足減衰、$\zeta = 1$: 臨界減衰、$\zeta > 1$: 過減衰。

強制振動

運動方程式

外力 $F(t) = F_0\cos\Omega t$ が加わる場合:

$$ \begin{equation} \ddot{x} + 2\gamma\dot{x} + \omega_0^2 x = \frac{F_0}{m}\cos\Omega t \end{equation} $$

定常解の導出

十分時間が経った後の定常解(過渡解は減衰して消える)を求めます。

$x_p(t) = X\cos(\Omega t – \delta)$ と仮定し、代入すると:

$$ \begin{equation} X = \frac{F_0/m}{\sqrt{(\omega_0^2 – \Omega^2)^2 + (2\gamma\Omega)^2}} \end{equation} $$

位相遅れ:

$$ \begin{equation} \tan\delta = \frac{2\gamma\Omega}{\omega_0^2 – \Omega^2} \end{equation} $$

共振

振幅 $X$ が最大になる周波数は、$\frac{dX}{d\Omega} = 0$ から:

$$ \Omega_{\text{res}} = \sqrt{\omega_0^2 – 2\gamma^2} \quad (\gamma < \omega_0/\sqrt{2} \text{ のとき}) $$

減衰が小さいとき $\Omega_{\text{res}} \approx \omega_0$ で、このとき振幅は $X_{\max} \approx F_0/(2m\gamma\omega_0)$ と非常に大きくなります。

Pythonでの実装

import numpy as np
import matplotlib.pyplot as plt
from scipy.integrate import odeint

omega_0 = 2 * np.pi  # 固有角振動数
t = np.linspace(0, 10, 2000)

fig, axes = plt.subplots(2, 2, figsize=(14, 10))

# 左上: 3種の減衰振動
zeta_values = [0.1, 0.5, 1.0, 2.0]
labels = ['不足減衰 (ζ=0.1)', '不足減衰 (ζ=0.5)', '臨界減衰 (ζ=1.0)', '過減衰 (ζ=2.0)']

for zeta, label in zip(zeta_values, labels):
    gamma = zeta * omega_0

    def eom(state, t):
        x, v = state
        return [v, -2*gamma*v - omega_0**2 * x]

    sol = odeint(eom, [1.0, 0.0], t)
    axes[0,0].plot(t, sol[:, 0], linewidth=2, label=label)

axes[0,0].axhline(y=0, color='k', linewidth=0.5)
axes[0,0].set_xlabel('時間 [s]', fontsize=12)
axes[0,0].set_ylabel('変位 x', fontsize=12)
axes[0,0].set_title('減衰振動の3ケース', fontsize=14)
axes[0,0].legend(fontsize=9)
axes[0,0].grid(True, alpha=0.3)

# 右上: 共振曲線(振幅-周波数応答)
Omega = np.linspace(0.01, 3 * omega_0, 500)
F0_m = 1.0

for zeta in [0.05, 0.1, 0.3, 0.5, 1.0]:
    gamma = zeta * omega_0
    X = F0_m / np.sqrt((omega_0**2 - Omega**2)**2 + (2*gamma*Omega)**2)
    axes[0,1].plot(Omega / omega_0, X, linewidth=2, label=f'ζ={zeta}')

axes[0,1].set_xlabel(r'$\Omega / \omega_0$', fontsize=12)
axes[0,1].set_ylabel('振幅 X', fontsize=12)
axes[0,1].set_title('共振曲線(周波数応答)', fontsize=14)
axes[0,1].legend(fontsize=10)
axes[0,1].grid(True, alpha=0.3)
axes[0,1].set_xlim(0, 3)

# 左下: 位相-周波数応答
for zeta in [0.05, 0.1, 0.3, 0.5, 1.0]:
    gamma = zeta * omega_0
    delta = np.arctan2(2*gamma*Omega, omega_0**2 - Omega**2)
    axes[1,0].plot(Omega / omega_0, np.degrees(delta), linewidth=2, label=f'ζ={zeta}')

axes[1,0].set_xlabel(r'$\Omega / \omega_0$', fontsize=12)
axes[1,0].set_ylabel('位相遅れ δ [°]', fontsize=12)
axes[1,0].set_title('位相-周波数応答', fontsize=14)
axes[1,0].legend(fontsize=10)
axes[1,0].grid(True, alpha=0.3)
axes[1,0].set_xlim(0, 3)

# 右下: 強制振動の時間応答(過渡+定常)
zeta = 0.1
gamma = zeta * omega_0
Omega_force = omega_0 * 0.9
F0 = 1.0

def forced_eom(state, t):
    x, v = state
    return [v, -2*gamma*v - omega_0**2*x + F0*np.cos(Omega_force*t)]

sol = odeint(forced_eom, [0.0, 0.0], t)
axes[1,1].plot(t, sol[:, 0], 'b-', linewidth=1.5, label='過渡+定常応答')

# 定常解のみ
X_ss = F0 / np.sqrt((omega_0**2 - Omega_force**2)**2 + (2*gamma*Omega_force)**2)
delta_ss = np.arctan2(2*gamma*Omega_force, omega_0**2 - Omega_force**2)
x_steady = X_ss * np.cos(Omega_force * t - delta_ss)
axes[1,1].plot(t, x_steady, 'r--', linewidth=1.5, label='定常解のみ', alpha=0.7)

axes[1,1].set_xlabel('時間 [s]', fontsize=12)
axes[1,1].set_ylabel('変位 x', fontsize=12)
axes[1,1].set_title(f'強制振動 (ζ={zeta}, Ω/ω₀=0.9)', fontsize=14)
axes[1,1].legend(fontsize=10)
axes[1,1].grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

まとめ

  • 減衰振動: $\ddot{x} + 2\gamma\dot{x} + \omega_0^2 x = 0$
  • 3ケース: 不足減衰($\zeta<1$, 振動減衰)、臨界減衰($\zeta=1$, 最速収束)、過減衰($\zeta>1$, 緩やかな収束)
  • 強制振動の定常解: $X = F_0/m / \sqrt{(\omega_0^2-\Omega^2)^2 + (2\gamma\Omega)^2}$
  • 共振: $\Omega \approx \omega_0$ で振幅が最大化。減衰が小さいほど鋭い共振

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