Runge-Kutta(RK4)积分在游戏物理中的应用

55

Gaffer on Games有一篇关于使用RK4 integration来提高游戏物理效果的优秀文章。实现很简单,但其中的数学让我感到困惑。我在概念层面上理解导数和积分,但已经很久没有操作方程了。

以下是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.0f0.5f0.5f1.0f处对导数进行平均?将导数平均到第四阶与使用较小时间步长进行简单欧拉积分有何不同?


阅读下面的答案和其他文章后,我了解了RK4的工作原理。回答我的问题: “有人能简单地解释一下RK4是如何工作的吗?” RK4利用这样一个事实:如果我们使用高阶导数而不仅仅是一阶或二阶导数,我们可以更好地逼近一个函数。这就是为什么泰勒级数比欧拉逼近收敛得快的原因。(看一下页面右侧的动画) 具体来说,为什么我们要在0.0f0.5f0.5f1.0f处对导数求平均值?
Runge-Kutta方法是一个函数的近似,它在时间步长内对多个点的导数进行采样,而泰勒级数只对单个点的导数进行采样。采样这些导数后,我们需要知道如何加权每个样本以获得最接近的近似。一种简单的方法是选择与泰勒级数相符的常数,这就是如何确定Runge-Kutta方程的常数。 这篇文章使我更加清楚。请注意,(15)是泰勒级数展开,而(17)是Runge-Kutta推导。 将导数平均到第4阶与使用较小的时间步长进行简单的欧拉积分有什么不同? 从数学上讲,它的收敛速度比做许多欧拉逼近要快得多。当然,通过足够的欧拉逼近,我们可以获得与RK4相等的精度,但需要的计算能力不足以证明使用欧拉法。

加权平均是泰勒级数展开的一种形式。这里有一个相当不错的解释(链接:https://web.archive.org/web/20140402231620/http://pathfinder.scar.utoronto.ca/~dyer/csca57/book_P/node50.html)。 - plinth
1
说实话,我会选择使用Verlet。它可以让事情变得更简单,并且在约束方面具有高稳定性。 - RCIX
我认为对于游戏来说,速度/稳定性比准确性更重要。 RK4是四阶的,太多了吗? - ccook
注意:上面的代码是不正确的,并且已经在第一个链接的网站上进行了修改(我已经编辑过,但尚未获得批准)。 - user146043
3个回答

37

这可能有点过于简化实际的数学,但旨在作为对 Runge Kutta 积分的直观指南。

假设我们在某个时间 t1 时已经知道某个量,现在想知道在另一个时间 t2 时该量的值。对于一阶微分方程,我们可以知道在 t1 处该数量的变化速率。除此之外,我们无法确切地知道任何信息;剩下的是猜测。

Euler积分是最简单的猜测方法:从 t1 线性外推到 t2,使用在 t1 处准确知道的变化速率。但通常得出的答案并不好。如果 t2 远离 t1,这种线性外推将无法匹配理想答案中的任何曲率。如果我们从 t1 到 t2取许多小步,那么就会面临相似值相减的问题。舍入误差将破坏结果。

因此,我们需要改进我们的猜测方法。一种方法是仍然进行线性外推,然后希望它与真实值不会相差太远,使用微分方程计算 t2 处的变化速率的估计值。这个估计值与在 t1 处(精确的)变化速率平均后更好地表示了真实答案在 t1t2之间的典型斜率。我们使用这个估计值从 t1t2 进行新的线性外推。并不清楚应该简单取平均值还是给予 t1 处的速率更大的权重,而不进行估计错误的数学运算,但有一个选择。无论如何,这比Euler积分得出的答案更好。

也许更好的方法是将我们最初的线性外推计算到t1t2之间的时间中点,并使用微分方程计算那里的变化率。这几乎可以得出与上述平均值相同的答案。然后,使用这个答案进行从t1t2的线性外推,因为我们的目的是找到在t2处的数量。 这就是中点算法。

您可以想象使用变化率的中点估计值对数量进行另一次从t1到中点的线性外推。通过微分方程,我们会得到一个更好的斜率估计值。使用这个值,我们最后从t1一直线性外推到我们想要的t2处。 这就是Runge-Kutta算法。

我们能对中点进行第三次外推吗? 当然,这并不违法,但详细分析显示出收益递减,以至于其他误差来源支配了最终结果。

Runge-Kutta算法将微分方程应用于初始点t1,两次应用于中点,以及一次应用于最终点t2。 中间点是可选择的。在t1t2之间,可以使用其他点来进行提高斜率的估计。例如,我们可以使用t1,一个距离t2的三分之一的点,另一个距离t2的2/3的点,以及在t2处。这四个导数的平均值的权重将不同。 在实践中,这并没有真正帮助,但可能在测试中发挥作用,因为它应该给出相同的答案,但会提供不同的舍入误差集。


4
太好了!感谢您抽出时间用简单的语言解释,这将帮助许多人。 - Kai
1
很好的解释。让我补充一点,以这种方式执行龙格-库塔(“经典RK4”)不会为您提供t2处误差的任何估计值。当您进行游戏物理时,这很少是一个问题,因为t1和t2无论如何都是固定的(由绘制帧的时间确定)。但是,如果您对物理系统的精确轨迹感兴趣,您可能希望将时间步长适应误差估计:如果误差在您的容忍范围内,则可以(甚至更好:增加下一个时间步长),如果不是,则丢弃结果并尝试使用较低的时间步长再次尝试。 - Alexandre C.
1
希望您能解释数学的整体剩余部分。 :) 我理解需要精确、公式化的定义,但在我直观地理解一些新方法的核心之前(它为什么存在?解决了什么问题?),我就感到迷失了。 - CIFilter
1
点赞和好评激励我将这个答案重写成一篇带插图的博客文章。请访问http://wigglewave.wordpress.com/2012/11/09/intuitive-description-of-runge-kutta-integration/。 - DarenW

4
在最简单的意义上,RK4是基于每个时间步长的4阶导数和点所构建的近似函数:您在起始点A的初始条件,基于数据点A在您的时间步长/2处和从A出发的斜率的第一次近似斜率B,第三次近似C,其具有校正值以反映函数形状在B处的变化,最后一个基于在点C处校正的斜率的最终斜率。
因此,基本上这种方法让您使用起始点、平均中点(其中两个部分都内置了校正来调整形状)和经过双重校正的终点进行计算。这使得每个数据点的有效贡献为1/6 1/3 1/3和1/6,因此大多数答案都基于您对函数形状的校正。
事实证明,RK逼近的顺序(欧拉被认为是RK1)与其精度如何随着更小的时间步长而缩放的关系相对应。
RK1逼近之间的关系是线性的,因此对于10倍的精度,您获得大约10倍的更好收敛性。
对于RK4,10倍的精度将使您获得大约10^4倍的更好收敛性。因此,虽然您在RK4中的计算时间呈线性增长,但它会呈多项式增长您的准确度。

你所说的“精度”,是指时间步长,对吗? - Llamageddon

3
关于你的问题为什么:我记得曾经写过一个布料模拟器,其中布料是一系列在节点处相互连接的弹簧。在模拟器中,弹簧施加的力与弹簧拉伸的程度成正比。该力会在节点处产生加速度,进而产生速度,移动节点并拉伸弹簧。有两个积分(将加速度积分以获得速度和将速度积分以获得位置),如果它们不准确,则误差会滚雪球式增加:过多的加速度会导致过多的速度,从而导致过度拉伸,进而导致更多的加速度,使整个系统不稳定。
很难没有图形来解释,但我会尝试:假设你有f(t),其中f(0)=10,f(1)=20,f(2)=30。
正确地对f(t)在区间0
矩形法则积分近似使用矩形来表示曲面,其中宽度为时间差delta,长度为f(t)的新值。因此,在0<t<1的区间内,将产生20 * 1 = 20的结果,在下一个区间1<t<2中将产生30 * 1 = 30的结果。如果您将这些点绘制出来并通过它们绘制一条线,您会发现它实际上是三角形,表面积为30(单位),因此欧拉积分是不足够准确的。为了更准确地估计曲面(积分),您可以采用更小的时间间隔t,例如评估f(0),f(0.5),f(1),f(1.5)和f(2)。如果您还在跟着我,那么RK4方法就是一种估算f(t)值的方法,其中t0<t<t0+dt,由比我聪明的人发明,用于获得积分的准确估计。(但正如其他人所说,请阅读维基百科文章以获取更详细的解释。RK4属于数值积分类别numerical integration

感谢您的所有解释,我认为这是对我的问题的很好的介绍。特别是,您知道RK4为什么有效吗?我可以看出在多个时间步长上平均斜率将产生准确的结果,但RK4平均导数的斜率,这让我感到困惑。 - Kai

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接