龙格库塔(RK4)整合游戏物理

Gaffer on Games有一篇关于使用RK4集成获得更好游戏物理效果的文章 。 实现很简单,但是背后的math让我困惑。 我理解概念层面的导数和积分,但很长一段时间没有操纵方程。

这是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?的衍生物1.0f? 如何平均导数到4阶不同于使用更小时间步长进行简单欧拉集成?


在阅读下面接受的答案和其他几篇文章后,我对RK4的工作原理有了一个了解。 回答我自己的问题:

任何人都可以简单地解释RK4是如何工作的?

RK4利用了这样一个事实,即如果我们使用它的高阶导数而不是一阶导数或二阶导数,我们可以得到更好的函数近似。 这就是为什么泰勒级数收敛比欧拉近似快得多。 (看看该页面右侧的animation)

具体而言,为什么我们平均0.0f0.5f0.5f1.0f的衍生物?

Runge-Kutta方法是一个函数的近似值,它在一个时间步长内对几个点的导数进行采样,而不像泰勒级数只对单点的导数进行采样。 在对这些衍生物进行采样之后,我们需要知道如何对每个样本进行权衡以获得最接近的可能性。 一个简单的方法是select与泰勒级数一致的常数,这就是确定龙格 – 库塔方程常数的方法。

这篇文章使我更清楚。 注意(15)是泰勒级数展开式, (17)是龙格 – 库塔推导。

如何平均导数到4阶不同于使用更小时间步长进行简单欧拉集成?

在math上,它收敛的速度比做许多欧拉近似要快得多。 当然,有了足够的欧拉近似,我们可以获得与RK4相等的精度,但是所需的计算能力并不能certificate使用欧拉。

就实际的math而言,这可能有点过于简单,但意味着对Runge Kutta集成的直观指导。

t1某一时刻给定一些数量,我们想知道在另一个时间t2的数量。 用一阶微分方程,我们可以知道t1时刻的变化率。 没有什么我们可以肯定知道的; 剩下的就是猜测。

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

所以我们改进我们的猜测。 一种方法是继续前进,然后进行线性外推,然后希望离真值不太远,用微分方程计算t2的变化率的估计值。 这在t1处的(精确的)变化率的平均值更好地代表了t1t2之间的真实答案的典型斜率。 我们用这个来做一个新的线性外推从t1t2 。 如果我们应该采取简单的平均值,或者在t1给予更多的权重,而没有用math来估计错误,这是不明显的,但是这里有一个select。 无论如何,这是一个比欧拉更好的答案。

也许更好的办法是把我们的初始线性外推到t1t2之间的一个时间点,然后用微分方程来计算那里的变化率。 这与上述的平均水平差不多。 然后用这个从t1t2的线性外推,因为我们的目的是在t2find数量。 这是中点algorithm。

你可以想象使用变化率的中点估计来对从t1到中点的数量进行另一个线性外推。 用微分方程,我们可以更好地估计那里的斜率。 使用这个,我们结束从t1一直到t2我们想要一个答案。 这是Runge Kuttaalgorithm。

我们可以做三分之一的中点吗? 当然,这不是非法的,但是详细的分析显示出减less的改善,使得其他的错误来源支配着最终的结果。

Runge Kutta将微分方程应用于初始点t1,两次到中点,一次在最终点t2。 中间点是一个select的问题。 有可能使用t1t2之间的其他点来做出改进的斜率估计。 例如,我们可以使用t1 ,t2点的三分之一点,t2的另一个2/3点, t2 。 四种衍生物的平均权重将不同。 实际上这并没有什么帮助,但在testing中可能有一席之地,因为它应该给出相同的答案,但会提供一组不同的舍入错误。

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

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

f(t)在0 <t <1的区间内的正确积分会给出在该区间内f(t)图下的曲面。

矩形规则的积分近似表示矩形,其中宽度是三angular洲的时间,长度是f(t)的新值,因此在0 <t <1的区间内,将产生20 * 1 = 20,并在下一个区间1

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

为了得到更准确的表面积分(积分),可以采用更小的t间隔,例如f(0),f(0.5),f(1),f(1.5)和f(2)。

如果你还在追踪我,那么RK4方法就是估计f(t)的值的一种方法,t0 <t <t0 + dt是由比我更聪明的人发明的,以便得到精确的积分估计值。

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

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

所以基本上这个方法可以让你使用一个起点,一个平均的中点,两个部分都有校正来校正形状,还有一个双重校正的终点。 这使得每个数据点的有效贡献是1/6 1/3 1/3和1/6,所以大部分答案都是基于对函数形状的修正。

事实certificate,RK逼近(Euler被认为是RK1)的阶数对应于其精度如何随着更小的时间步长而缩放。

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

对于RK4来说,10倍的精度可以使你的收敛速度提高10 ^ 4倍。 所以当你的计算时间在RK4中线性增加时,它会多项式地增加你的精度。