二维碰撞的矢量分解求解
在经典力学的学习中,碰撞问题是动量守恒定律和能量守恒定律的核心应用场景。一维碰撞相对直观,但在实际物理世界中,碰撞往往发生在二维或三维空间。处理二维碰撞问题的关键在于矢量分解:将复杂的二维运动转化为相互独立的一维运动进行求解。
本文将系统介绍如何利用矢量分解法求解二维弹性与非弹性碰撞问题,并提供清晰的数学推导与代码实现示例。
当两个物体(质量分别为 $m_1$ 和 $m_2$)在二维平面内发生碰撞时,系统在不受外力(或外力远小于内力)的情况下,满足动量守恒定律。
假设碰撞前的速度矢量分别为 $\vec{v}_1$ 和 $\vec{v}_2$,碰撞后的速度矢量分别为 $\vec{v}_1'$ 和 $\vec{v}_2'$。根据动量守恒:
$$m_1\vec{v}_1 + m_2\vec{v}_2 = m_1\vec{v}_1' + m_2\vec{v}_2'$$
由于矢量方程在直角坐标系中可以按分量独立计算,我们可以将上述矢量方程分解为 $x$ 轴和 $y$ 轴两个方向的标量方程:
$x$ 轴方向动量守恒:
$$m_1 v_{1x} + m_2 v_{2x} = m_1 v_{1x}' + m_2 v_{2x}'$$$y$ 轴方向动量守恒:
$$m_1 v_{1y} + m_2 v_{2y} = m_1 v_{1y}' + m_2 v_{2y}'$$
如果是完全弹性碰撞,系统还满足机械能守恒定律:
$$\frac{1}{2}m_1 v_1^2 + \frac{1}{2}m_2 v_2^2 = \frac{1}{2}m_1 (v_1')^2 + \frac{1}{2}m_2 (v_2')^2$$
坐标系的巧妙选择:碰撞面与法线方向
虽然可以直接在固定的全局直角坐标系($x-y$ 轴)中列方程,但在实际计算中,选择**碰撞法线方向(Normal)和切线方向(Tangent)**作为坐标轴会极大地简化问题。
- 法线方向($n$ 轴):沿着两物体碰撞瞬间接触点的公法线。碰撞过程中的巨大作用力主要沿此方向产生,因此动量守恒和能量交换主要发生在这个方向。
- 切线方向($t$ 轴):垂直于法线方向。若忽略摩擦力,切线方向上没有外力作用,因此两物体在切线方向上的分速度在碰撞前后保持不变。
简化步骤:
- 确定碰撞瞬间两球心连线方向作为法线单位矢量 $\hat{n}$。
- 确定垂直于法线的方向作为切线单位矢量 $\hat{t}$。
- 将初速度投影到 $\hat{n}$ 和 $\hat{t}$ 上:
$$v_{1n} = \vec{v}1 \cdot \hat{n}, \quad v{1t} = \vec{v}1 \cdot \hat{t}$$
$$v{2n} = \vec{v}2 \cdot \hat{n}, \quad v{2t} = \vec{v}_2 \cdot \hat{t}$$ - 在切线方向上,速度不变:
$$v_{1t}' = v_{1t}, \quad v_{2t}' = v_{2t}$$ - 在法线方向上,应用一维弹性(或非弹性)碰撞公式求解新速度 $v_{1n}'$ 和 $v_{2n}'$。
- 将求出的法线分量和切线分量合成,转换回全局坐标系。
弹性碰撞的法线分量计算公式
对于一维弹性碰撞(即法线方向上的碰撞),已知质量 $m_1, m_2$ 和碰撞前的法线速度 $v_{1n}, v_{2n}$,碰撞后的法线速度公式为:
$$v_{1n}' = \frac{(m_1 - m_2)v_{1n} + 2m_2 v_{2n}}{m_1 + m_2}$$
$$v_{2n}' = \frac{(m_2 - m_1)v_{2n} + 2m_1 v_{1n}}{m_1 + m_2}$$
结合切线分量,最终物体的速度矢量为:
$$\vec{v}1' = v{1n}'\hat{n} + v_{1t}'\hat{t}$$
$$\vec{v}2' = v{2n}'\hat{n} + v_{2t}'\hat{t}$$
编程实现示例(Python)
下面是一个使用 Python 实现二维弹性碰撞的简明代码示例。该代码利用向量的点积与投影,完成了坐标系的转换与碰撞求解。
import numpy as np
def resolve_2d_collision(m1, v1, m2, v2, x1, x2):
"""
计算两个圆形物体在二维平面内的弹性碰撞
m1, m2: 质量
v1, v2: 速度矢量 (numpy array, 长度为2)
x1, x2: 位置矢量 (numpy array, 长度为2)
"""
# 1. 计算法线方向矢量(从物体1指向物体2)
n = x2 - x1
dist = np.linalg.norm(n)
if dist == 0:
return v1, v2 # 重合时暂不处理
n = n / dist # 单位法向量
# 2. 计算切线方向矢量
t = np.array([-n[1], n[0]])
# 3. 将速度投影到法线和切线方向
v1n = np.dot(v1, n)
v1t = np.dot(v1, t)
v2n = np.dot(v2, n)
v2t = np.dot(v2, t)
# 4. 利用一维弹性碰撞公式计算法线方向碰撞后的速度
v1n_prime = (v1n * (m1 - m2) + 2 * m2 * v2n) / (m1 + m2)
v2n_prime = (v2n * (m2 - m1) + 2 * m1 * v1n) / (m1 + m2)
# 5. 切线方向速度保持不变
v1t_prime = v1t
v2t_prime = v2t
# 6. 将标量速度转换回全局坐标系下的矢量
v1_prime = v1n_prime * n + v1t_prime * t
v2_prime = v2n_prime * n + v2t_prime * t
return v1_prime, v2_prime
# 测试示例
m1, m2 = 1.0, 2.0
v1 = np.array([3.0, 1.0])
v2 = np.array([-1.0, 2.0])
x1 = np.array([0.0, 0.0])
x2 = np.array([1.0, 1.0])
v1_p, v2_p = resolve_2d_collision(m1, v1, m2, v2, x1, x2)
print("碰撞后物体1速度:", v1_p)
print("碰撞后物体2速度:", v2_p)
总结
二维碰撞的矢量分解求解法本质上是“化繁为简”的思想体现。通过合理选择法线与切线坐标系,我们将一个复杂的二维耦合运动,解耦为切线方向的“匀速运动”和法线方向的“一维碰撞”。这种方法不仅在理论物理推导中十分高效,也是游戏引擎、物理模拟(如分子动力学模拟)中处理刚体碰撞的标准算法。