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?
?
以下の受け入れられた回答と他のいくつかの記事を読んだ後、RK4の仕組みを理解しました。私自身の質問に答えるには:
RK4 の仕組みを簡単に説明できる人はいますか?
RK4 は、関数の 1 次導関数または 2 次導関数だけでなく、高次の導関数を使用すると、関数のより優れた近似を得ることができるという事実を利用しています。これが、テイラー級数 がオイラー近似よりもはるかに速く収束する理由です。(そのページの右側にあるアニメーションを見てください)
具体的には、なぜ0.0f
、0.5f
、0.5f
、およびで導関数を平均化するの1.0f
でしょうか?
ルンゲクッタ法は、単一点の導関数のみをサンプリングするテイラー級数とは異なり、時間ステップ内の複数の点の導関数をサンプリングする関数の近似です。これらの導関数をサンプリングした後、可能な限り最も近い近似値を得るために、各サンプルを重み付けする方法を知る必要があります。これを行う簡単な方法は、テイラー級数と一致する定数を選択することです。これは、ルンゲ クッタ方程式の定数を決定する方法です。
この記事は私にとってそれをより明確にしました。がルンゲ・クッタ導関数であるの
(15)
に対し、 はテイラー級数展開であることに注意してください。(17)
微分を 4 次まで平均化することは、時間ステップを小さくして単純なオイラー積分を行うこととどう違うのでしょうか?
数学的には、多くのオイラー近似を行うよりもはるかに速く収束します。もちろん、十分なオイラー近似を使用すると、RK4 と同等の精度を得ることができますが、必要な計算能力がオイラーの使用を正当化するものではありません。