Skip to content

速度与数值积分 ​

已知每个位置的风速,如何画出粒子的下一位置?如果速度始终为 10 m/s,60 秒的位移是 600 m。速度随位置和时间变化时,可以把大段时间切成小步,每步重新查询速度,再累积位移。这就是数值积分(numerical integration)的基本想法。

一阶导数与积分相互连接 ​

dx/dt = v(x,t) 表示位置随时间的局部变化率等于速度。Euler 法(Euler method)使用本步起点的速度,假设它在本小步中保持不变:

dxdt=v(x,t),xn+1=xn+v(xn,tn)Δt
符号 / 英文含义单位
x / position平面位置,或带明确定义的坐标本段为 m
v / velocity速度向量m/s
Δt / time step一次推进的模拟时长s
dx/dt / time derivative位置相对于时间的变化率m/s
ω / angular velocity绕中心旋转的角速度rad/s

如果一步迈得太远,就会跳过速度变化明显的区域。屏幕帧率高并不自动保证模拟准确:时间倍率很大时,每帧对应的模拟步长仍可能很长。

手算:绕圆运动为何慢慢跑偏 ​

在平面设 v(x,y)=(-ωy,ωx),其中 ω=0.01 rad/s。它处处沿圆的切线方向,理想轨迹保持离原点的距离不变。粒子从 (1000,0) m 出发,取 Δt=10 s:

text
起点速度 = (0,10) m/s
Euler下一点 = (1000,100) m
离中心距离 = sqrt(1000²+100²) ≈ 1004.99 m

一次就向外偏了约 5 m。原因是使用起点切线代替了整段弧线;减小步长能减小这种离散误差,但不会让有限步长的 Euler 变为精确圆周运动。

中点法(midpoint method,一种二阶 Runge–Kutta / RK2)先预测半步位置,再用中点的速度走完整一步:

ts
type XY = readonly [number, number]
const velocity = ([x, y]: XY): XY => [-0.01*y, 0.01*x]
function midpointStep(p: XY, dt: number): XY {
  const a = velocity(p)
  const mid: XY = [p[0] + a[0]*dt/2, p[1] + a[1]*dt/2]
  const b = velocity(mid)
  return [p[0] + b[0]*dt, p[1] + b[1]*dt]
}
midpointStep([1000, 0], 10) // [995,100],半径约1000.0125 m

它改善了本例误差,但仍非精确解。若速度场随时间变化,第一次查询用 t,第二次应使用 t+Δt/2。更高阶方法仍依赖正确的坐标、单位、采样和步长。

U/V 怎样更新经纬度 ​

先采用球形地球近似,半径 R,纬度 φ、经度 λ,U/V 分别为局部东向和北向速度。沿纬圈和经线的小位移对应:

Δλ≈UΔtRcos⁡φ,Δφ≈VΔtR

右边单位为弧度。北纬 60° 向东 10 m/s,60 s 后经度约增加 0.01079°。这不是给经度加 600,而是先将米制位移转为角位移。极区 cosφ 接近零,经度参数退化;本简化公式适合远离极区的小步长区域演示,精密全球推进应选择适合的椭球或三维方法。

本书风粒子实验实际使用区域球面近似和 Euler 推进。这里的 RK2 是独立数学例子,说明改进方向,并不意味着实验提供了算法切换。

自检:时间倍率与粒子数 ​

原来每一步为 1 s,将模拟速度调为 100 倍时,能否直接改成每步 100 s?粒子数从 1024 增至 4096,速度应如何变化?

答案与理由

可以产生某种动画,但误差可能显著增加。更稳妥的方式是增加若干子步,并限制每步穿过的网格距离;具体阈值取决于场变化与精度要求。粒子数只改变采样密度和计算成本,不应改变物理速度。还应分别记录真实经过的时间、展示倍率和实际完成的模拟时间,避免卡顿时误读结果。

下一步:精度、误差与数值检查。回到主课:GPU 风粒子。

气象学 · 数学基础 · 地理可视化