53

Gaffer on Games 有一篇很棒的文章,介绍了使用RK4 集成来获得更好的游戏物理效果。实现很简单,但它背后的数学让我感到困惑。我在概念层面上了解导数和积分,但很长时间没有操纵方程了。

这是 Gaffer 实现的主要内容:

void integrate(State &state, float t, float dt)
{
     Derivative a = evaluate(state, t, 0.0f, Derivative());
     Derivative b = evaluate(state, t+dt*0.5f, dt*0.5f, a);
     Derivative c = evaluate(state, t+dt*0.5f, dt*0.5f, b);
     Derivative d = evaluate(state, t+dt, dt, c);

     const float dxdt = 1.0f/6.0f * (a.dx + 2.0f*(b.dx + c.dx) + d.dx);
     const float dvdt = 1.0f/6.0f * (a.dv + 2.0f*(b.dv + c.dv) + d.dv)

     state.x = state.x + dxdt * dt;
     state.v = state.v + dvdt * dt;
}

谁能简单地解释一下 RK4 是如何工作的?具体来说,为什么我们要对0.0f, 0.5f,处的导数进行平均0.5f,以及1.0f?对 4 阶导数进行平均与用更小时间步进行简单的欧拉积分有何不同?


在阅读了下面公认的答案以及其他几篇文章后,我对 RK4 的工作原理有了一定的了解。回答我自己的问题:

谁能简单地解释一下 RK4 是如何工作的?

RK4 利用了这样一个事实,即如果我们使用函数的高阶导数而不仅仅是一阶或二阶导数,我们可以获得更好的函数逼近。这就是泰勒级数 比欧拉近似收敛得快得多的原因。(看看那个页面右侧的动画)

具体来说,为什么我们要对 、 、 和 处的导0.0f0.5f进行0.5f平均1.0f

Runge-Kutta 方法是一个函数的近似值,它在一个时间步长内对多个点的导数进行采样,而泰勒级数仅对单个点的导数进行采样。在对这些导数进行采样后,我们需要知道如何对每个样本进行称重以获得最接近的近似值。一个简单的方法是选择与泰勒级数一致的常数,这是确定龙格-库塔方程常数的方法。

这篇文章让我更清楚了。注意(15)泰勒级数展开是怎样的,而(17)龙格-库塔推导是怎样的。

对高达 4 阶的导数求平均与用更小时间步进行简单的欧拉积分有何不同?

从数学上讲,它的收敛速度比许多欧拉近似要快得多。当然,通过足够的欧拉近似值,我们可以获得与 RK4 相同的精度,但所需的计算能力并不能证明使用欧拉是合理的。

4

3 回答 3

34

就实际数学而言,这可能有点过于简单,但意味着作为Runge Kutta集成的直观指南。

给定某个时间的某个数量t1,我们想知道另一个时间的数量t2。通过一阶微分方程,我们可以知道该量在 处的变化率t1。我们无法确定其他任何事情。其余的都是猜测。

欧拉积分是最简单的猜测方法:t1使用精确已知的变化率从 t2线性外推t1。这通常给出一个不好的答案。如果 t2 远离 t1,则此线性外推将无法匹配理想答案中的任何曲率。如果我们从 t1 到 采取许多小步骤t2,我们将遇到相似值相减的问题。舍入错误会破坏结果。

所以我们完善我们的猜测。一种方法是继续进行这种线性外推,然后希望它与事实相差不远,使用微分方程计算 变化率的估计值t2。这与 处的(准确)变化率平均t1,更好地代表了真实答案在t1和之间的典型斜率t2。我们使用它从 tot1到to 进行新的线性外推t2。如果我们应该取简单的平均值,或者在t1不做数学来估计误差,我们应该对 率给予更多的权重,这并不明显,但这里有一个选择。无论如何,这是一个比欧拉给出的更好的答案。

t1也许更好的是,将我们的初始线性外推到和之间的时间点t2,并使用微分方程计算那里的变化率。这给出了与刚刚描述的平均值大致一样好的答案。t1然后将其用于从到的线性外推t2,因为我们的目的是找到 处的数量t2。这是中点算法。

您可以想象使用变化率的中点估计值对从中t1点到中点的数量进行另一个线性外推。通过微分方程,我们可以更好地估计那里的斜率。使用这个,我们从t1一路推断到t2我们想要答案的地方。这就是Runge Kutta算法。

我们可以对中点进行第三次外推吗?当然,这不是非法的,但详细的分析表明改进正在减少,因此其他错误来源主导了最终结果。

Runge Kutta 将微分方程应用于初始点 t1,两次应用于中点,一次应用于终点 t2。中间点是一个选择问题。可以使用介于t1和之间的其他点t2来对斜率进行改进的估计。例如,我们可以使用t1,指向 t2 三分之一处的点,指向 的另一个 2/3 处t2,以及 处t2。四个导数的平均值的权重将不同。在实践中,这并没有真正的帮助,但可能在测试中占有一席之地,因为它应该给出相同的答案,但会提供一组不同的舍入错误。

于 2009-11-06T19:08:26.033 回答
3

RK4 在最简单的意义上是制作一个近似函数,它基于 4 个导数和每个时间步长的点:您在起点 A 的初始条件,基于您的时间步长/2 的数据点 A 的第一个近似斜率 B 和来自 A 的斜率,第三个近似值 C ,它具有 B 处斜率的校正值,以反映函数的形状变化,最后是基于 C 点校正斜率的最终斜率。

所以基本上这种方法可以让你计算使用一个起点,一个平均中点,在两个部分都有校正以调整形状,以及一个双重校正的端点。这使得每个数据点的有效贡献为 1/6 1/3 1/3 和 1/6,因此您的大部分答案都是基于您对函数形状的修正。

事实证明,RK 近似的阶数(欧拉被认为是 RK1)对应于它的精度如何随着更小的时间步长扩展。

RK1 近似值之间的关系是线性的,因此对于 10 倍的精度,您可以获得大约 10 倍更好的收敛性。

对于 RK4,10 倍的精度会产生大约 10^4 倍的收敛性。因此,虽然您的计算时间在 RK4 中线性增加,但它会以多项式方式增加您的准确性。

于 2013-09-27T18:35:33.880 回答
2

至于你的问题为什么:我记得曾经写过一个布料模拟器,其中布料是一系列在节点处相互连接的弹簧。在模拟器中,弹簧施加的力与弹簧的拉伸程度成正比。力会在节点处引起加速度,从而产生移动节点的速度,从而拉伸弹簧。有两个积分(积分加速度得到速度,积分速度得到位置),如果它们不准确,误差就会滚雪球:加速度过大会导致速度过大,导致拉伸过大导致加速度更大,使整个系统不稳定。

没有图形很难解释,但我会尝试:假设你有 f(t),其中 f(0) = 10,f(1) = 20,f(2) = 30。

f(t) 在区间 0 < t < 1 上的适当积分将为您提供该区间内 f(t) 图形下的表面。

矩形规则积分用一个矩形近似该曲面,其中宽度是时间增量,长度是 f(t) 的新值,因此在区间 0 < t < 1 中,它将产生 20 * 1 = 20,在下一个区间 1

现在,如果您要绘制这些点并通过它们画一条线,您会发现它实际上是三角形的,表面为 30(单位),因此欧拉积分不足。

为了更准确地估计表面(积分),您可以采用更小的 t 间隔,例如在 f(0)、f(0.5)、f(1)、f(1.5) 和 f(2) 处进行评估。

如果你还在关注我,那么 RK4 方法只是一种估计 f(t) 值的方法,因为 t0 < t < t0+dt 是由比我更聪明的人发明的,用于准确估计积分。

(但正如其他人所说,阅读维基百科文章以获得更详细的解释。RK4属于数值积分类别)

于 2009-11-03T16:11:31.540 回答