(25) 《滑板少年达朗贝尔》续:传导的波动
孟子有云“独乐乐不如众乐乐”,达朗贝尔一个人滑滑板有点孤单,若是 5 个人一起滑,会不会产生一些有趣的模式呢。
在本集中,我们终于要解释为什么让达朗贝尔做这两集的模特。这是因为,本集展现的波动行为,就是由数学上的“达朗贝尔方程”所决定的。
在上集中,我们只有 1 个角色,它自己的上下摇摆,只能叫振动。而有了多个角色之后,振动可以在角色之间传导,这种群体的运动模式,被称为波动。
听起来高深,编起来不难,本集的代码量:18 (多次复制) + 8 块积木,来吧!
素材:
还是帅气的达朗伯:
dAlembert.png
舞台背景:Scratch 内置的 Circles
角色的复制和场景布置:
首先我们先上传 1 个 dAlembert.png 角色,将其大小设为 50,方向设为 0,并放到屏幕左侧中部。
然后,在只有这一个角色的时候,搭建它的基础代码(18块积木):
注意,在搭建好上述代码之后,再在角色浏览窗口中,在 dAlembert 的图标上单击右键,然后选择“复制”,复制该角色,如下图所示:
复制后,会出现一个 dAlembert2 角色,这个角色将自动具有我们之前创建的 18 块基础代码,免去了重复录入的麻烦。
然后,在屏幕上移动 dAlembert2 角色,把它摆到第一个 dAlembert 旁边不远处。
按这个办法再复制出 dAlembert3、dAlembert4、dAlembert5,每复制一个,就及时将它们按顺序排列好,成为一横排。
不要一次性复制太多,以免分不清谁是2、谁是3、4、5。
排列后如下图所示(位置稍微有点偏差没有影响):
这时候如果直接点绿旗子运行,已经可以看到 5 个滑板少年自动回归中位的效果。
加入关键的 8 块额外积木:
要制造传导效果,需要加入神奇的 8 块额外积木,下面需要集中注意力,跟着指导逐步操作。
先点击最初的第一个角色,即 dAlembert,加入下图中红圈内的“([dAlembert2] 的 [y坐标])”积木,该积木是由“侦测”栏目中,“([舞台背景] 的 [# 编号])”积木修改而来的:
↑ dAlembert 代码的修改
然后,依次对 dAlembert2、3、4、5 角色添加以下红圈内的积木,一定看准角色编号哦,还要注意都是的“ [y坐标] ”,不要选错。
↑ dAlembert2 角色代码的修改
↑ dAlembert3 角色代码的修改
↑ dAlembert4 角色代码的修改
↑ dAlembert5 角色代码的修改
其实规律并不复杂,对每个角色来说,我们添加的,都是它旁边紧邻的 2 个邻居的 y坐标。对于开头和末尾的角色,自然只有一个邻居。
好嘞,这就大功告成了!可以随便点击一位达朗贝尔角色,看看波动是如果传导演变的吧。
运行:
如果你点最左边的达朗贝尔,你可以发现波动是从左向右传播,正如开篇的动图一样。
如果你点最右边的达朗贝尔,情况正好反过来,可以发现波动是从右往左传播。
如果你仔细观察,波动传播到最边缘后,还会有反射,然后反射波和入射波相互影响,我们在物理中称为干涉,最终在阻尼作用下,各处的振幅都逐渐减小,波动趋于停止。
本程序背后的数学模型就是“达朗贝尔方程”,它在物理中十分常见,从水波、声波、地震波到电磁波、光波、量子物理中的物质波,都有达朗贝尔方程的踪影。因此,程序运行的效果也很像仿真的物理行为。5 个达朗贝尔如同都漂浮在水面上,受到水波影响。
为高年级小朋友的讲解:
像前几集一样,我们还是可以详细解释一下程序中的运动在每次“重复执行”中的逻辑,以便一窥波动现象背后的数学:
以 dAlembert2 角色为例,我们看“重复执行”中的代码。
和上集分析一样,我们知道每次执行,时间都将流逝 dt = 1/FPS
FPS 是动画的帧率,即 1 秒内动画的帧数(也是 1 秒内重复执行的次数),换句话说,上面的关系也可以写成 1 / dt = FPS
然后还是老把戏,用角色的方向作为代表它垂直速度的变量。
体现垂直速度的,就是每次执行时,y坐标的增量,记为 dy,有:
dy / dt = (方向/10) * FPS
如果我们把 y 看成由角色所在处的 x坐标,以及时间 t,这 2 个自变量决定的函数。对于其中一个自变量的导数,称为偏导数,上式又可以用偏导数的符号“∂”,记为:
∂y / ∂t = (方向/10) * FPS
方向 = 10 * ∂y / ∂t / FPS
在这集中,每次执行,方向的增量比较复杂,由四行代码确定。上图红圈中的三行,可以称为“拉普拉斯”运算部分,后面单独的一行,称为阻尼运算部分。
阻尼的作用是让体系保持稳定,不至于出现自我激发、崩溃,这不作为分析的重点。
我们重点看拉普拉斯运算部分。它是右转2次,左转1次。实际上,这因为是写在一行中太长,用的加减积木太多,容易出错,人为拆成 3 行代码的。
实际上逻辑很简单,就是两个邻居的 y坐标加起来,除以 20,作为右转的量(即方向的增加量)。自己的 y坐标,除以 10,作为左转的量(即方向的减少量)。如过分别把左邻的有坐标记为 y左、右邻的y坐标记为 y右,有:
d(方向) = (y左 + y右) / 20 – y / 10
= (y右 – y) / 20 – (y – y左) / 20
在我们的布局中,每 2 个角色的水平间距大约是 100 单位,我们记为 Δx。
我们把 (y右 – y) / Δx,记为 ∂y / ∂x (右半),即 y 对 x 的偏导数,在右半边的值。
(y – y左) / Δx,记为 ∂y / ∂x (左半)
∂y / ∂x (右半) 减去 ∂y / ∂x (左半),再次除以 Δx,就是 y 对 x 的二阶偏导数:∂²y / ∂x²
因此,d(方向) 可整理成:
d(方向) = ∂²y / ∂x² * Δx² / 20
代入 方向 = 10 * ∂y / ∂t / FPS,得到:
d(10 * ∂y / ∂t / FPS) = ∂²y / ∂x² * Δx² / 20
等式两端再除以 dt = 1 / FPS,得到:
∂(10 * ∂y / ∂t / FPS) / ∂t = ∂²y / ∂x² * Δx² * FPS / 20
整理,得到:
∂²y / ∂x² – (200 /Δx² / FPS²) * ∂²y / ∂t² = 0
我们令 c² = Δx² * FPS² / 200
上式化为:
∂²y / ∂x² – (1 /c²) * ∂²y / ∂t² = 0
这便是达朗贝尔方程。它所描述的运动模式,是自然界中非常普遍的波动现象。
达朗贝尔方程是一个二阶偏微分方程,关于如何求解可以参见本站《10个带人们走向现代的物理公式》的第2节。
这里只介绍结论,c 是波动的传播速度,传播方向有沿 x 轴正向、负向两种。在本集中,
c = Δx * FPS / sqrt(200)
对于角色间隔 Δx = 100 单位,动画帧率 FPS = 30 Hz 的情况,c 大约为 212单位/秒。在我们程序中,一个脉冲波从左端传递到右段,大概需要 2秒钟。
小朋友们可以试试,看试验结果是否和数学分析相吻合。