web-dev-qa-db-ja.com

ゲーム物理学のためのルンゲクッタ(RK4)統合

Gaffer on Gamesには すばらしい記事RK4統合 の使用についてのより良いゲーム物理学があります。実装は簡単ですが、その背後にある数学は私を混乱させます。私は導関数と積分を概念レベルで理解していますが、長い間方程式を操作していませんでした。

これがガファーの実装の矢面です:

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は、1次または2次導関数だけでなく、高次導関数を使用すると、関数の近似値が大幅に向上するという事実を利用しています。 テイラー級数 がオイラー近似よりもはるかに速く収束するのはそのためです。 (そのページの右側のアニメーションをご覧ください)

具体的には、なぜ0.0f0.5f0.5f1.0fで導関数を平均化するのですか?

ルンゲクッタ法は、単一の点の導関数のみをサンプリングするテイラー級数とは異なり、タイムステップ内のいくつかの点の導関数をサンプリングする関数の近似です。これらの導関数をサンプリングした後、可能な限り最も近い近似値を得るために、各サンプルの重み付け方法を知る必要があります。これを行う簡単な方法は、テイラー級数と一致する定数を選択することです。これにより、ルンゲクッタ方程式の定数が決定されます。

この記事 は私にそれをより明確にしました。 (15)がルンゲクッタ微分であるのに対し、(17)はテイラー級数展開であることに注意してください。

4次までの微分を平均化することは、小さなタイムステップで単純なオイラー積分を行うこととどのように異なりますか?

数学的には、多くのオイラー近似を行うよりも速く収束します。もちろん、十分なオイラー近似があれば、RK4と同等の精度を得ることができますが、必要な計算能力はオイラーの使用を正当化しません。

49
Kai

これは実際の数学としては少し単純化しすぎているかもしれませんが、Runge Kutta統合の直感的なガイドとして意図されています。

ある時点である量t1が与えられた場合、別の時間での量を知りたいt2。 1次微分方程式を使用すると、t1でその量の変化率を知ることができます。他に確かなことはありません。残りは推測しています。

オイラー積分は、推測する最も簡単な方法です。t1で正確にわかっている変化率を使用して、t1からt2まで線形に外挿します。これは通常悪い答えを与えます。 t2がt1から遠い場合、この線形外挿は理想的な答えの曲率に一致しません。 t1からt2までの多くの小さなステップを実行すると、同様の値の減算の問題が発生します。丸め誤差は結果を台無しにします。

したがって、私たちは推測を洗練させます。 1つの方法は、先に進んでこの線形外挿を行い、それが真実からそれほど遠くないことを期待して、微分方程式を使用してt2での変化率の推定値を計算します。これは、t1での(正確な)変化率と平均して、t1t2の間の真の回答の標準的な傾きをよりよく表します。これを使用して、to t1からt2への新しい線形外挿を行います。単純な平均を取るか、またはt1でレートをより重視する必要があるかは明らかではありませんが、計算を行ってエラーを推定することはできませんが、ここには選択肢があります。いずれにせよ、オイラーが与えるよりも良い答えです。

おそらくより良いのは、t1t2の中間の時点までの初期線形外挿を行い、微分方程式を使用してそこでの変化率を計算することです。これは、今説明した平均とほぼ同じくらい良い答えを与えます。次に、これをt1からt2への線形外挿に使用します。これは、t2で数量を検索するためです。これは中点アルゴリズムです。

変化率の中点推定を使用して、t1から中点までの量の別の線形外挿を行うことを想像できます。微分方程式を使用すると、勾配のより良い推定が得られます。これを使用して、最後にt1からt2まで外挿して答えを求めます。これはRunge Kuttaアルゴリズムです。

中間点への3番目の外挿を実行できますか?確かに、それは違法ではありませんが、詳細な分析は、他のエラーの原因が最終結果を支配するように、改善が減少していることを示しています。

Runge Kuttaは微分方程式を最初の点t1に適用し、2回は中点に適用し、1回は最終点t2に適用します。中間点は選択の問題です。勾配の推定を改善するために、t1t2の間の他のポイントを使用することができます。たとえば、t1、t2の3分の1のポイント、t2の2/3のポイント、およびt2で使用できます。 4つの導関数の平均の重みは異なります。実際にはこれは実際には役に立たないが、同じ答えを与えるはずであるが、四捨五入エラーの異なるセットを提供するため、テストの場所があるかもしれない。

33
DarenW

最も簡単な意味でのRK4は、各タイムステップの4つの導関数とポイントに基づく近似関数を作成します。開始点Aの初期条件、タイムステップ/ 2のデータポイントAに基づく最初の近似勾配B、および関数の形状変化を反映するためのBでの勾配の補正値を持つ3番目の近似CであるAからの勾配。最後に、点Cでの補正された勾配に基づく最終勾配。

したがって、基本的にこの方法では、始点、両方のパーツに組み込まれた修正を組み込んで形状を調整する平均中点、および二重に修正された終点を使用して計算できます。これにより、各データポイントからの効果的な寄与が1/6 1/3 1/3および1/6になるため、ほとんどの答えは関数の形状の修正に基づいています。

RK近似の次数(オイラーはRK1と見なされます)は、その精度がより小さなタイムステップでスケーリングする方法に対応していることがわかります。

RK1近似間の関係は線形であるため、10倍の精度では、収束が約10倍向上します。

RK4の場合、精度が10倍になると、収束が約10 ^ 4倍向上します。したがって、計算時間はRK4で直線的に増加しますが、精度は多項的に増加します。

2
Skyler

あなたの質問の理由について:私はかつて、布がノードで相互接続された一連のばねであった布シミュレータを書いたことを思い出します。シミュレータでは、ばねによって加えられる力は、ばねが伸ばされる距離に比例します。力はノードで加速を引き起こし、それはバネを伸ばすノードを動かす速度を引き起こします。 2つの積分(速度を得るために加速度を積分することと、位置を得るために速度を積分すること)があり、それらが不正確な場合、エラーSnowball:エラーが多すぎると、速度が大きすぎて伸びが大きくなり、加速度が大きくなり、システム全体が作成されます。不安定。

グラフィックなしでは説明するのは難しいですが、私は試してみます。f(t)があるとします。ここで、f(0) = 10、f(1) = 20、 f(2) = 30。

間隔0 <t <1でのf(t)の適切な積分により、その間隔で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メソッドは、t0 <t <t0 + dtのf(t)の値を推定する方法にすぎません。積分。

(しかし、他の人が言ったように、より詳細な説明についてはWikipediaの記事を読んでください。RK4は 数値積分 のカテゴリーにあります)

2
Wernsey