龙格库塔(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.0f
, 0.5f
, 0.5f
和1.0f?
的衍生物1.0f?
如何平均导数到4阶不同于使用更小时间步长进行简单欧拉集成?
在阅读下面接受的答案和其他几篇文章后,我对RK4的工作原理有了一个了解。 回答我自己的问题:
任何人都可以简单地解释RK4是如何工作的?
RK4利用了这样一个事实,即如果我们使用它的高阶导数而不是一阶导数或二阶导数,我们可以得到更好的函数近似。 这就是为什么泰勒级数收敛比欧拉近似快得多。 (看看该页面右侧的animation)
具体而言,为什么我们平均0.0f
, 0.5f
, 0.5f
和1.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
处的(精确的)变化率的平均值更好地代表了t1
和t2
之间的真实答案的典型斜率。 我们用这个来做一个新的线性外推从t1
到t2
。 如果我们应该采取简单的平均值,或者在t1
给予更多的权重,而没有用math来估计错误,这是不明显的,但是这里有一个select。 无论如何,这是一个比欧拉更好的答案。
也许更好的办法是把我们的初始线性外推到t1
和t2
之间的一个时间点,然后用微分方程来计算那里的变化率。 这与上述的平均水平差不多。 然后用这个从t1
到t2
的线性外推,因为我们的目的是在t2
find数量。 这是中点algorithm。
你可以想象使用变化率的中点估计来对从t1
到中点的数量进行另一个线性外推。 用微分方程,我们可以更好地估计那里的斜率。 使用这个,我们结束从t1
一直到t2
我们想要一个答案。 这是Runge Kutta
algorithm。
我们可以做三分之一的中点吗? 当然,这不是非法的,但是详细的分析显示出减less的改善,使得其他的错误来源支配着最终的结果。
Runge Kutta将微分方程应用于初始点t1,两次到中点,一次在最终点t2。 中间点是一个select的问题。 有可能使用t1
和t2
之间的其他点来做出改进的斜率估计。 例如,我们可以使用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中线性增加时,它会多项式地增加你的精度。