1. 单摆自由振动仿真与相图绘制

无阻尼单摆的建模与数值积分

取摆长 L = 1.0 m、重力加速度 g = 9.81 m/s²,忽略阻尼与摆杆质量。以摆角 θ(rad)为广义坐标,从最低点逆时针为正,运动方程为:

θ'' = -(g/L)·sin(θ)

令状态向量 y = [θ, ω],ω = θ',则化为一阶方程组:

dθ/dt = ω
dω/dt = -(g/L)·sin(θ)

采用四阶龙格–库塔法(RK4)积分,步长 h = 0.005 s,积分时长 20 s。初始条件取 θ₀ = 0.3 rad、ω₀ = 0(小振幅)与 θ₀ = 2.5 rad、ω₀ = 0(大振幅)两组,用于对比周期与相轨迹形态。

import numpy as np

L, g = 1.0, 9.81

def deriv(y):
    theta, omega = y
    return np.array([omega, -(g/L)*np.sin(theta)])

def rk4(y, h):
    k1 = deriv(y)
    k2 = deriv(y + 0.5*h*k1)
    k3 = deriv(y + 0.5*h*k2)
    k4 = deriv(y + h*k3)
    return y + (h/6.0)*(k1 + 2*k2 + 2*k3 + k4)

def simulate(theta0, omega0, T=20.0, h=0.005):
    n = int(T/h)
    y = np.array([theta0, omega0], dtype=float)
    ts = np.zeros(n+1); ys = np.zeros((n+1, 2))
    ts[0] = 0.0; ys[0] = y
    for i in range(n):
        y = rk4(y, h)
        ts[i+1] = (i+1)*h
        ys[i+1] = y
    return ts, ys

ts_s, ys_s = simulate(0.3, 0.0)   # 小振幅
ts_l, ys_l = simulate(2.5, 0.0)   # 大振幅

能量守恒校验与周期估计

单摆总能量(单位质量)为 E = 0.5·L²·ω² + g·L·(1 - cos θ)。无阻尼时 E 应保持常数,可用相对漂移 |E(t) - E(0)| / E(0) 判断积分精度。周期则通过检测 θ 由正变负的过零点间隔来估计。

def energy(theta, omega):
    return 0.5*(L**2)*omega**2 + g*L*(1 - np.cos(theta))

def period_estimate(ts, ys):
    theta = ys[:, 0]
    crossings = []
    for i in range(1, len(theta)):
        if theta[i-1] > 0 and theta[i] <= 0:
            # 线性插值求过零时刻
            t0, t1 = ts[i-1], ts[i]
            th0, th1 = theta[i-1], theta[i]
            crossings.append(t0 + (t1-t0)*th0/(th0-th1))
    if len(crossings) < 2:
        return None
    return np.mean(np.diff(crossings))

for name, ts, ys in [("小振幅 θ₀=0.3", ts_s, ys_s),
                     ("大振幅 θ₀=2.5", ts_l, ys_l)]:
    E0 = energy(ys[0,0], ys[0,1])
    drift = np.max(np.abs(energy(ys[:,0], ys[:,1]) - E0)) / E0
    T = period_estimate(ts, ys)
    print(f"{name}: 周期≈{T:.4f} s, 能量最大相对漂移={drift:.2e}")

预期输出(示例运行结果):小振幅周期约 2.006 s,接近线性近似 2π√(L/g) ≈ 2.006 s;大振幅周期明显增大(约 2.5 s 量级),体现非线性带来的周期–振幅依赖。能量相对漂移应在 1e-8 量级,说明 RK4 在 h=0.005 s 下守恒性良好。

若能量漂移超过 1e-5,优先减小步长 h 或改用辛积分(如 velocity-Verlet),而不是盲目延长积分时间。

相平面轨迹与周期–振幅关系

以 θ 为横轴、ω 为纵轴绘制相图:小振幅轨迹接近椭圆,大振幅轨迹呈明显的非椭圆闭合曲线,且两条轨迹都闭合(无阻尼、无耗散)。周期随振幅增大而增大,可用椭圆积分 T = 4√(L/g)·K(sin(θ₀/2)) 校核。

import matplotlib.pyplot as plt

fig, ax = plt.subplots(1, 2, figsize=(10, 4))
ax[0].plot(ys_s[:,0], ys_s[:,1], label="θ₀=0.3")
ax[0].plot(ys_l[:,0], ys_l[:,1], label="θ₀=2.5")
ax[0].set_xlabel("θ (rad)"); ax[0].set_ylabel("ω (rad/s)")
ax[0].set_title("相平面轨迹"); ax[0].legend(); ax[0].grid(alpha=0.3)

ax[1].plot(ts_s, ys_s[:,0], label="θ₀=0.3")
ax[1].plot(ts_l, ys_l[:,0], label="θ₀=2.5")
ax[1].set_xlabel("t (s)"); ax[1].set_ylabel("θ (rad)")
ax[1].set_title("时间序列"); ax[1].legend(); ax[1].grid(alpha=0.3)
plt.tight_layout(); plt.show()
相平面轨迹(θ–ω) θ ω θ₀=0.3 rad(近椭圆) θ₀=2.5 rad(非椭圆闭合) (0,0) 稳定中心 周期随振幅变化 T(θ₀) θ₀ (rad) T (s) 0 0.5 1.0 1.5 2.0 2.0 2.2 2.4 2.6 2.8 θ₀=0.3 → T≈2.006 s θ₀=2.5 → T≈2.5 s 线性近似 2π√(L/g)

结果判读要点

  • 相轨迹闭合:无阻尼单摆是保守系统,相轨迹为闭合曲线,平衡点 (0,0) 是中心型奇点,不收敛也不发散。
  • 能量守恒:RK4 下能量相对漂移应远小于 1e-5;若明显增大,说明步长过大或方程符号写错。
  • 周期–振幅依赖:小振幅时 T 接近线性值 2.006 s;振幅增大后 T 单调增大,这是 sin θ 非线性项的直接体现,不能用线性模型解释。
  • 大振幅轨迹形态:θ₀ 接近 π 时轨迹趋于分界线(separatrix),周期趋于无穷,仿真中应避免取 θ₀ 过于接近 π 导致数值困难。