運動量保存則と衝突問題

運動量保存則はエネルギー保存則と並ぶ物理学の根幹的な法則です。特に衝突問題では、力の時間変化の詳細がわからなくても、衝突前後の状態を結びつけることができます。

本記事の内容

  • 運動量の定義と力積
  • 運動量保存則の導出
  • 弾性衝突と非弾性衝突
  • 反発係数
  • 2体衝突の速度公式
  • Pythonでの衝突シミュレーション

前提知識

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

運動量の定義

質量 $m$、速度 $\bm{v}$ の質点の運動量(momentum)は次のように定義されます。

$$ \bm{p} = m\bm{v} $$

運動量はベクトル量であり、運動の「勢い」を表します。質量が大きいほど、速度が大きいほど、運動量は大きくなります。

力積と運動量の関係

ニュートンの第2法則は運動量を用いて次のように書けます。

$$ \bm{F} = m\bm{a} = m\frac{d\bm{v}}{dt} = \frac{d(m\bm{v})}{dt} = \frac{d\bm{p}}{dt} $$

両辺を時間で積分すると力積(impulse)が得られます。

$$ \begin{align} \int_{t_1}^{t_2} \bm{F} \, dt &= \int_{t_1}^{t_2} \frac{d\bm{p}}{dt} \, dt \\ &= \bm{p}(t_2) – \bm{p}(t_1) \\ &= \Delta\bm{p} \end{align} $$

$$ \boxed{\bm{J} = \int_{t_1}^{t_2} \bm{F} \, dt = \Delta\bm{p}} $$

力積は運動量の変化に等しいという関係です。短時間に大きな力が作用する衝突現象では、この関係が特に有用です。

運動量保存則の導出

2つの質点が相互作用する系を考えます。質点1が質点2から受ける力を $\bm{F}_{12}$、質点2が質点1から受ける力を $\bm{F}_{21}$ とします。

ニュートンの第3法則(作用・反作用の法則)より:

$$ \bm{F}_{12} = -\bm{F}_{21} $$

各質点の運動方程式は:

$$ \frac{d\bm{p}_1}{dt} = \bm{F}_{12}, \quad \frac{d\bm{p}_2}{dt} = \bm{F}_{21} $$

両辺を加えると:

$$ \begin{align} \frac{d\bm{p}_1}{dt} + \frac{d\bm{p}_2}{dt} &= \bm{F}_{12} + \bm{F}_{21} \\ \frac{d}{dt}(\bm{p}_1 + \bm{p}_2) &= \bm{0} \end{align} $$

よって、外力がない系では全運動量は一定です。

$$ \boxed{\bm{p}_1 + \bm{p}_2 = m_1\bm{v}_1 + m_2\bm{v}_2 = \text{const}} $$

これが運動量保存則です。$N$ 個の質点系に拡張すると:

$$ \sum_{i=1}^N \bm{p}_i = \text{const} \quad (\text{外力が0のとき}) $$

弾性衝突と非弾性衝突

衝突は力学的エネルギーが保存されるかどうかで分類されます。

分類 運動量 運動エネルギー
弾性衝突 保存 保存 ビリヤード球
非弾性衝突 保存 一部損失 自動車の衝突
完全非弾性衝突 保存 最大損失 粘土球の衝突(合体)

反発係数

反発係数(coefficient of restitution)$e$ は衝突の「跳ね返り具合」を表します。

$$ \boxed{e = -\frac{v_1′ – v_2′}{v_1 – v_2} = \frac{\text{衝突後の相対速度}}{\text{衝突前の相対速度}}} $$

ここで $v_1, v_2$ は衝突前、$v_1′, v_2’$ は衝突後の速度です(1次元)。

  • $e = 1$: 弾性衝突(エネルギー保存)
  • $0 < e < 1$: 非弾性衝突
  • $e = 0$: 完全非弾性衝突(合体)

2体衝突の速度公式

1次元の2体衝突を考えます。運動量保存則と反発係数の定義を連立させます。

$$ m_1 v_1 + m_2 v_2 = m_1 v_1′ + m_2 v_2′ \quad \cdots (1) $$

$$ e = -\frac{v_1′ – v_2′}{v_1 – v_2} \quad \cdots (2) $$

式(2)より:

$$ v_1′ – v_2′ = -e(v_1 – v_2) \quad \cdots (2′) $$

式(1)より:

$$ m_1(v_1 – v_1′) = m_2(v_2′ – v_2) \quad \cdots (1′) $$

式(2′)から $v_2′ = v_1′ + e(v_1 – v_2)$ を式(1)に代入すると:

$$ \begin{align} m_1 v_1 + m_2 v_2 &= m_1 v_1′ + m_2 [v_1′ + e(v_1 – v_2)] \\ m_1 v_1 + m_2 v_2 &= (m_1 + m_2) v_1′ + m_2 e(v_1 – v_2) \end{align} $$

$v_1’$ について整理すると:

$$ \boxed{v_1′ = \frac{m_1 v_1 + m_2 v_2 + m_2 e(v_2 – v_1)}{m_1 + m_2}} $$

同様に $v_2’$ は:

$$ \boxed{v_2′ = \frac{m_1 v_1 + m_2 v_2 + m_1 e(v_1 – v_2)}{m_1 + m_2}} $$

特殊な場合

弾性衝突($e=1$) の場合:

$$ v_1′ = \frac{(m_1 – m_2)v_1 + 2m_2 v_2}{m_1 + m_2}, \quad v_2′ = \frac{(m_2 – m_1)v_2 + 2m_1 v_1}{m_1 + m_2} $$

等質量の弾性衝突($m_1 = m_2, e=1$) の場合:

$$ v_1′ = v_2, \quad v_2′ = v_1 $$

速度が完全に交換されます。

Pythonでの実装

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import Circle
from matplotlib.animation import FuncAnimation

# --- 2体衝突の速度公式 ---
def collision_velocity(m1, m2, v1, v2, e):
    """衝突後の速度を計算"""
    v1_after = (m1*v1 + m2*v2 + m2*e*(v2 - v1)) / (m1 + m2)
    v2_after = (m1*v1 + m2*v2 + m1*e*(v1 - v2)) / (m1 + m2)
    return v1_after, v2_after

fig, axes = plt.subplots(1, 3, figsize=(16, 5))

# --- (1) 反発係数ごとの衝突後速度 ---
m1, m2 = 2.0, 1.0
v1, v2 = 3.0, -1.0
e_values = np.linspace(0, 1, 100)
v1_after = [(m1*v1 + m2*v2 + m2*e*(v2 - v1)) / (m1 + m2) for e in e_values]
v2_after = [(m1*v1 + m2*v2 + m1*e*(v1 - v2)) / (m1 + m2) for e in e_values]

axes[0].plot(e_values, v1_after, 'b-', linewidth=2, label='$v_1\'$')
axes[0].plot(e_values, v2_after, 'r-', linewidth=2, label='$v_2\'$')
axes[0].axhline(y=v1, color='b', linestyle='--', alpha=0.4, label=f'$v_1 = {v1}$')
axes[0].axhline(y=v2, color='r', linestyle='--', alpha=0.4, label=f'$v_2 = {v2}$')
axes[0].set_xlabel('反発係数 $e$')
axes[0].set_ylabel('衝突後の速度 [m/s]')
axes[0].set_title(f'反発係数と衝突後速度 ($m_1={m1}$, $m_2={m2}$)')
axes[0].legend()
axes[0].grid(True, alpha=0.3)

# --- (2) エネルギー損失 ---
KE_before = 0.5*m1*v1**2 + 0.5*m2*v2**2
KE_loss = []
for e in e_values:
    v1a, v2a = collision_velocity(m1, m2, v1, v2, e)
    KE_after = 0.5*m1*v1a**2 + 0.5*m2*v2a**2
    KE_loss.append((KE_before - KE_after) / KE_before * 100)

axes[1].plot(e_values, KE_loss, 'g-', linewidth=2)
axes[1].set_xlabel('反発係数 $e$')
axes[1].set_ylabel('エネルギー損失 [%]')
axes[1].set_title('反発係数と運動エネルギー損失')
axes[1].grid(True, alpha=0.3)
axes[1].set_ylim(0, max(KE_loss)*1.1)

# --- (3) 衝突シミュレーション(位置の時間変化) ---
m1, m2 = 1.0, 2.0
v1_init, v2_init = 4.0, -1.0
x1_init, x2_init = 0.0, 5.0
e = 0.8

dt = 0.01
t_max = 4.0
t = np.arange(0, t_max, dt)
x1 = np.zeros_like(t)
x2 = np.zeros_like(t)
x1[0], x2[0] = x1_init, x2_init
vel1, vel2 = v1_init, v2_init

for i in range(1, len(t)):
    x1[i] = x1[i-1] + vel1*dt
    x2[i] = x2[i-1] + vel2*dt
    # 衝突判定(質点が同じ位置に達したとき)
    if x1[i] >= x2[i] and vel1 > vel2:
        vel1, vel2 = collision_velocity(m1, m2, vel1, vel2, e)

axes[2].plot(t, x1, 'b-', linewidth=2, label=f'質点1 ($m_1={m1}$)')
axes[2].plot(t, x2, 'r-', linewidth=2, label=f'質点2 ($m_2={m2}$)')
axes[2].set_xlabel('時間 [s]')
axes[2].set_ylabel('位置 [m]')
axes[2].set_title(f'衝突シミュレーション ($e={e}$)')
axes[2].legend()
axes[2].grid(True, alpha=0.3)

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

# 数値確認
v1a, v2a = collision_velocity(1.0, 2.0, 4.0, -1.0, 0.8)
print(f"衝突後: v1' = {v1a:.2f} m/s, v2' = {v2a:.2f} m/s")
p_before = 1.0*4.0 + 2.0*(-1.0)
p_after = 1.0*v1a + 2.0*v2a
print(f"運動量: 衝突前 = {p_before:.2f}, 衝突後 = {p_after:.2f}")

まとめ

本記事では、運動量保存則と衝突問題について解説しました。

  • 運動量: $\bm{p} = m\bm{v}$、力積は運動量変化に等しい
  • 運動量保存則: 外力がない系では $\sum \bm{p}_i = \text{const}$
  • 反発係数 $e$ で衝突の種類が決まる($e=1$: 弾性、$e=0$: 完全非弾性)
  • 2体衝突の速度公式は運動量保存と反発係数の連立で導出
  • エネルギー損失は $e$ が小さいほど大きい

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