如何用代码模拟自由落体

发表时间

当学习图形化编程(比如 Python 或者 Scratch)时,能写出模拟自然界的物理现象会很有趣,比如最常见的小球自由落体现象。为了写出逼真的小球下落轨迹,首先要了解背后的原理。

目录


原理

我们的图形化程序是基于帧来显示动画的。每隔一段时间,屏幕内容更新一次,称为一帧。为了模拟出自由落体的动画,我们的程序需要计算出每帧小球出现的位置。

想象一下用一个照相机,在小球下落过程中,每隔一段等长的时间,对小球的位置拍个照片。经过一段时间后,这些照片上小球的位置,就是我们要计算的数值。

模型

最简单的模型,是小球从静止状态自由下落。将重力加速度记为 $g_0$ ,我们知道在任意时刻 $t$,小球的速度是 $$v(t)=g_0t=g_0nT$$

$T$ 为相邻两帧的间隔时间。上式中 $g_0$, $T$ 都为常量,我们可以合并为一个新的常量 $g_1$,这样 $v(n)$ 构成了一个离散序列:

$$ v(n)=g_1n$$或者$$ v(n)=v(n-1)+g_1 \tag{1}$$

速度 $v(n)$ 是个等差数列,随时间变化的曲线如下图中的红线:

为了简化问题,假设第 $n$ 帧到第 $n+1$ 帧之间,小球保持 $v(n)$ 匀速,那么在两帧之间走过的路程为 $$\Delta y(n)=v(n)T=g_1nT=gn$$

这里得到了第 $n$ 帧内,小球走过的路程。而第 $n$ 帧的小球位置 $y(n)$ 是前 $n$ 帧内走过路程的累积:$$ y(n) = y(n-1)+ gn \tag{2}$$

这里 $g$ 是一个常量,和真正的重力加速度的数值 $9.8 m/s^2$ 已经没有关系,但是仍然起到了加速度的作用:这个值越大,小球下落的越快。位置 $y(n)$ 的级差是等差数列,随时间变化的曲线如下图中的红线:

这个曲线近似是抛物线 。在连续时间模型下,$y(n)$ 的级差对应路程 $s(t)$ 的导数,也就是瞬时速度 $v(t)$. 级差是等差数列,则对应瞬时速度 $v(t)$是线性递增函数。

更深入的研究,请参看 蛙跳积分法

实现

用下面的伪代码可以实现上面的 $(2)$ 式:

var y=0, n=0, g=1
while(小球未落地)
    y+=(n++)*g

这就是自由落体的代码实现。如下图所示:

(点击动画重新播放)

落地反弹

如何模拟当小球接触到地面后的反弹?

理想条件下,小球弹起的能量保持不变,速度数值不变,方向变为竖直向上。为了便于计算速度,将 上节的下落过程 改写为下面的伪代码:

var y=0, v=0, g=1
while(小球未落地)
    v+=g
    y+=v

这里 位置 $y$ 和速度 $v$ 是量纲不同的变量,不能直接相加,但这里这么写纯粹为了计算数值,效果和 上节 相同。接下来可以写小球反弹的场景:

var y=0, v=0, g=1
while(true)
    if(小球触碰地面){
        v=-v
    }
    v+=g
    y+=v
效果如下图:

考虑损耗

由于摩擦的存在和小球的形变,反弹的一瞬间,有能量的损失,所以速度从数值上会减少。假设减少的数量和速度成正比,则剩余的速度是原速度乘上一个常数,记为 $f, 0<f<1$,那么上面的伪代码就变为:

var y=0, v=0, g=1, f=0.6
while(true)
    if(小球触碰地面){
        v=-f*v
    }
    v+=g
    y+=v

效果如下图:

(点击动画重新播放)

(完)


除非特别说明,本站文章均系原创,并采用 署名协议 CC-BY 授权。
欢迎转载,惟请保留原文链接:https://lfhacks.com/t/simulate-gravity