双摆(Double Pendulum)是经典力学中的混沌系统。它在单摆的末端再铰接一个摆,整个系统由两个二阶非线性微分方程描述,对初始条件极其敏感——初始角度的微小差异(如 0.001 弧度)会在数秒内导致完全不同的运动轨迹。这是"蝴蝶效应"最直观的物理演示之一。
本项目使用 拉格朗日力学 推导运动方程,四阶龙格-库塔法(RK4) 进行数值积分,HTML5 Canvas 实现实时可视化渲染。
取 \(\theta_1\) 和 \(\theta_2\) 为广义坐标,分别表示上摆杆和下摆杆与竖直方向(向下)的夹角,逆时针为正。
╱ 支点 O (原点)
╱
l₁ ╱ θ₁ = 摆杆1 与竖直夹角
╱
● m₁ (x₁, y₁)
\
l₂ \ θ₂ = 摆杆2 与竖直夹角
\
● m₂ (x₂, y₂)
摆锤 1 的笛卡尔坐标(原点在支点,y 轴向上):
\[ \begin{aligned} x_1 &= l_1 \sin\theta_1 \\ y_1 &= -l_1 \cos\theta_1 \end{aligned} \]摆锤 2 的笛卡尔坐标:
\[ \begin{aligned} x_2 &= l_1 \sin\theta_1 + l_2 \sin\theta_2 \\ y_2 &= -l_1 \cos\theta_1 - l_2 \cos\theta_2 \end{aligned} \]对时间求导得到速度:
\[ \begin{aligned} \dot{x}_1 &= l_1 \dot{\theta}_1 \cos\theta_1 \\ \dot{y}_1 &= l_1 \dot{\theta}_1 \sin\theta_1 \\[4pt] \dot{x}_2 &= l_1 \dot{\theta}_1 \cos\theta_1 + l_2 \dot{\theta}_2 \cos\theta_2 \\ \dot{y}_2 &= l_1 \dot{\theta}_1 \sin\theta_1 + l_2 \dot{\theta}_2 \sin\theta_2 \end{aligned} \]速度平方:
\[ \begin{aligned} v_1^2 &= \dot{x}_1^2 + \dot{y}_1^2 = l_1^2 \dot{\theta}_1^2 \\[4pt] v_2^2 &= \dot{x}_2^2 + \dot{y}_2^2 = l_1^2\dot{\theta}_1^2 + l_2^2\dot{\theta}_2^2 + 2l_1l_2\dot{\theta}_1\dot{\theta}_2\cos(\theta_1 - \theta_2) \end{aligned} \]动能 \(T\):
\[ T = \frac{1}{2}m_1 v_1^2 + \frac{1}{2}m_2 v_2^2 \]势能 \(V\)(取支点 O 为势能零点):
拉格朗日量:
\[ L = T - V \]代入欧拉-拉格朗日方程:
\[ \frac{d}{dt}\frac{\partial L}{\partial \dot{\theta}_i} - \frac{\partial L}{\partial \theta_i} = 0, \qquad i = 1, 2 \]得到两个耦合的二阶非线性微分方程,整理为显式形式:
| 特征 | 说明 |
|---|---|
| 分母 | 两式共享同一分母 \(2m_1 + m_2 - m_2\cos(2\Delta\theta)\) |
| 奇异性 | 分母仅在极端参数下趋近于零,正常参数不会发生 |
| 退化为单摆 | 当 \(m_2 \to 0\) 时,\(\ddot{\theta}_1 \approx -\dfrac{g}{l_1}\sin\theta_1\) |
| 混沌来源 | 非线性耦合项 \(\sin(\theta_1 - \theta_2)\) 和乘积项使系统对初值极度敏感 |
将两个二阶 ODE 转化为四个一阶 ODE:
\[ \mathbf{y} = \begin{bmatrix} y_0 \\ y_1 \\ y_2 \\ y_3 \end{bmatrix} = \begin{bmatrix} \theta_1 \\ \theta_2 \\ \dot{\theta}_1 \\ \dot{\theta}_2 \end{bmatrix}, \qquad \frac{d\mathbf{y}}{dt} = \mathbf{f}(\mathbf{y}) = \begin{bmatrix} \dot{\theta}_1 \\ \dot{\theta}_2 \\ \ddot{\theta}_1(\theta_1, \theta_2, \dot{\theta}_1, \dot{\theta}_2) \\ \ddot{\theta}_2(\theta_1, \theta_2, \dot{\theta}_1, \dot{\theta}_2) \end{bmatrix} \]每步计算四个中间斜率:
\[ \begin{aligned} \mathbf{k}_1 &= \mathbf{f}(\mathbf{y}_n) \\[3pt] \mathbf{k}_2 &= \mathbf{f}\big(\mathbf{y}_n + \tfrac{h}{2}\mathbf{k}_1\big) \\[3pt] \mathbf{k}_3 &= \mathbf{f}\big(\mathbf{y}_n + \tfrac{h}{2}\mathbf{k}_2\big) \\[3pt] \mathbf{k}_4 &= \mathbf{f}(\mathbf{y}_n + h\mathbf{k}_3) \end{aligned} \]加权更新:
| 方法 | 局部截断误差 | 优点 | 缺点 |
|---|---|---|---|
| 欧拉法 | \(O(h^2)\) | 简单 | 能量漂移严重,需极小步长 |
| Verlet / 辛积分 | \(O(h^2)\) | 长期能量守恒好 | 速度依赖力时需处理 |
| RK4 | \(O(h^5)\) | 精度高,实现适中 | 每步 4 次函数求值 |
RK4 的 \(O(h^5)\) 局部截断误差使其在 \(h = \tfrac{1}{240}\) 步长下已非常精确。
┌──────────────────────────────────────────────────┐ │ HTML / Canvas 页面 │ │ │ │ ┌──────────┐ ┌──────────────┐ ┌─────────────┐ │ │ │ 信息面板 │ │ 参数面板 │ │ 按钮控制 │ │ │ │ θ₁, θ₂ │ │ l₁,l₂,m₁,m₂ │ │ 暂停/轨迹 │ │ │ │ ω₁, ω₂ │ │ g, 速度 │ │ 混沌/重置 │ │ │ │ FPS │ │ (实时可调) │ │ │ │ │ └──────────┘ └──────────────┘ └─────────────┘ │ │ │ │ ┌──────────────────────────────────────────────┐ │ │ │ 渲染引擎 (Canvas 2D) │ │ │ │ ┌─────────┐ ┌──────────┐ ┌─────────────┐ │ │ │ │ │ 摆杆+锤 │ │ 发光辉光 │ │ HSLA 轨迹 │ │ │ │ │ │ (线条+圆)│ │ (径向渐变)│ │ (渐变拖尾) │ │ │ │ │ └─────────┘ └──────────┘ └─────────────┘ │ │ │ └──────────────────┬───────────────────────────┘ │ │ │ │ │ ┌──────────────────▼───────────────────────────┐ │ │ │ 物理引擎 │ │ │ │ ┌──────────────────────┐ ┌───────────────┐ │ │ │ │ │ Pendulum 类 │ │ params 全局 │ │ │ │ │ │ - theta1, theta2 │ │ 参数对象 │ │ │ │ │ │ - omega1, omega2 │ │ (l1,l2,m1, │ │ │ │ │ │ - derivatives() │ │ m2,g,speed) │ │ │ │ │ │ - step(dt) / RK4 │ └───────────────┘ │ │ │ │ │ - getPositions() │ │ │ │ │ │ - trail[] 轨迹缓存 │ │ │ │ │ └──────────────────────┘ │ │ │ └──────────────────────────────────────────────┘ │ └──────────────────────────────────────────────────┘
| 功能 | 操作 | 说明 |
|---|---|---|
| 拖拽摆锤 | 鼠标按住摆锤 2 拖动 | 锁定角度,角速度归零,从任意初始状态释放 |
| 暂停/继续 | 按钮或空格键 | 暂停物理模拟,仔细分析当前状态 |
| 轨迹开关 | 按钮切换 | 显示或隐藏摆锤 2 的运动轨迹 |
| 混沌模式 | 按钮切换 | 显示 6 个初始角偏移 0.001 rad 的副本,直观展示蝴蝶效应 |
| 重置 | 按钮 | 恢复初始角度,清空轨迹,从初始状态重新开始 |
右侧面板提供多个实时滑块,所有参数 即时生效,无需暂停或重置:
混沌模式下,系统生成 6 个与主摆参数完全相同的摆,但初始角度各偏移 ±0.001 弧度:
初始角差异最大仅 0.006 rad(约 0.34°)
↓
由于运动方程的非线性耦合
↓
数秒内 6 个摆的轨迹完全分道扬镳
↓
直观展示混沌系统对初值的极端敏感性
这是洛伦兹(Edward Lorenz)"蝴蝶效应"最优雅的物理可视化——确定性方程产生不可预测的行为。
simulation/
├── pom.xml
└── src/
└── main/
└── resources/
├── double-pendulum.html ← 双摆模拟器
└── 双摆模拟器设计文档.html ← 本文档
纯静态 HTML 文件,无需编译、无需后端、无需 npm install。用浏览器直接打开即可运行。