12

Orbital Mechanics (できれば XNA) を実装した例はありますか? 私が現在使用しているコードは以下のとおりですが、実行時に「正しく感じられません」。オブジェクトは惑星に対してわずかに曲がるだけであり、変数をどれだけ微調整しても、軌道または部分軌道にさえ入ることができません。

shot.Position += shot.Velocity;  

foreach (Sprite planet in planets)  
{  
  Vector2 directionToPlanet = (planet.Position - shot.Position);  
  directionToPlanet.Normalize();  

  float distance = Vector2.DistanceSquared(shot.Position, planet.Position);  

  float gPull = (float)(planet.gravityStrength * (planet.Mass * shot.Mass) / distance) + planet.gravityField;  
  shot.Position += new Vector2(directionToPlanet.X * gPull, directionToPlanet.Y * gPull);  
} 

位置ではなく速度を更新する必要があることを指摘するための編集マーキングメンデルトの答えは正しいです。gPull の計算を次のように変更する必要もありました。

float gPull = shot.Mass * planet.Mass / distanceSqr * planet.gStr;
4

5 に答える 5

8

Newton-Raphson 反復法は、この問題を解決するための安定した方法ではありません (つまり、微分方程式の単純な積分器を使用して正しく取得することはできません)。2 次 (またはそれ以上)のソリューションを使用することを検討してください。

数値解析の観点からすると、軌道力学の問題は連立微分方程式の集合を解く問題に帰着します。

x_i'' + G m_i \sum_{i != j} m_j r_ji/(|r_ji|)^3 = 0

ここで、xは物体の位置を表す 3 つのベクトル、mは同じ物体の質量、 は物体とr_ji = x_j - x_iの間のベクトル変位です。ji

于 2009-03-17T20:17:52.157 に答える
5

「リープフロッグ」法は非常に効率的で安定しており、プラズマを含むあらゆる動的粒子/フィールドシステムに適しています。重力については、それは簡単です。これが、単一の惑星での単一の反復に対して行うすべてのことです(1体の問題、静止した太陽の周りの単一の惑星):

    public void Push()
    {
        Position += Gravity.dT * Velocity;
        Velocity += Gravity.dT * GravityAccelerationVector(Position);
    }

ここで、「Gravity.dT」は、任意の時間の尺度での均一な時間ステップです。System.Windows.Vectorを使用していますが、基本的な乗算と加算をサポートしている限り、任意のカスタムVectorクラスで問題ありません。秘訣は、位置と速度が「同時に」ないことです。これは、ほとんどの積分方法で非常に一般的です。むしろ、それらはよろめきます。反復Nの位置は、反復N-1/2の速度に基づいて更新されますが、反復N + 1/2の速度は、反復Nの位置に基づいて更新されます。

N体バージョンは次のようになります。

    public static void PushPlanets(Planet[] planets)
    {
        // Position Push at iteration N + 0:
        foreach(var p in planets)
            p.Position += Gravity.dT * p.Velocity; // Velocity from N - 1/2

        // Velocity Push at iteration N + 1/2:
        foreach (var p in planets)
        {
            Vector TotalGravity = new Vector(0,0);
            foreach (var pN in planets)
            {
                if (pN == p) continue;
                TotalGravity += pN.Mass * p.Mass * GravityAccelerationVector(p.Position - pN.Position);
            }
            TotalGravity += Sun.Mass * p.Mass * GravityAccelerationVector(p.Position); // Solar acceleration
            p.Velocity += Gravity.dT * TotalGravity;
        }

どこ

    public static Vector GravityAccelerationVector(Vector position)
    {
        return Vector.Multiply(-G / position.LengthSquared / position.Length, position);
    }

N体は、単一の重力源の代わりにいくつかあるため、より複雑になります。ただし、コード形式は同じです。各惑星の位置はN-1 / 2速度によってプッシュされ、次に新しい位置に基づいて各惑星の総重力加速度を計算し、次に各惑星の速度をその総加速度によってプッシュします。 。

他の方法は、高次の方法でさえ、位置速度に基づいて次のステップを同時に線形に投影するため、不安定なことがよくあります。これは、システムにエネルギーを追加する側で常にエラーになり、軌道は徐々にさらに外側に移動します。他の方法では、この自然なエラーを過剰に補償し、システムからエネルギーを取り除くことができます。一般に、エネルギーに中立なソリューションが必要です。リープフロッグ法は、軌道の位相に関しては徐々に誤りますが、全体的なエネルギーに関しては誤りがありません。

于 2011-05-03T15:20:18.123 に答える
3

通過する物体は軌道に入りません。軌道の特徴の 1 つは、同じ速度で (軌道を回っている物体に対して) 同じポイントに戻ることです。実効無限から始めた場合は、実効無限に戻ります。

軌道に入るには、重力とは関係のない方法である時点で速度を変更するか、おそらく追加の大きな物体を用意する必要があります。同様に、物体を地表から軌道に打ち上げることはできません。衛星が目的の高度に到達したら、何か (最後のロケット燃焼など) を行う必要があります。それ以外の場合は、地表にある発射地点に戻ろうとします。

私の最悪のデバッグ経験のいくつかは、プログラムが問題なく、テスト データまたは計算がオフになったときでした。何を探すべきかを確認してください。

于 2009-03-17T21:12:39.407 に答える