2

背景をあまり読みたくない場合は、以下の更新 2 にスキップしてください。

単純な軌道シミュレーション (2 体) のモデルを実装しようとしています。

しかし、私が書いたコードを使用しようとすると、結果から生成されたプロットはかなり奇妙に見えます。

プログラムは、初期状態ベクトル (位置と速度) を使用してケプラー軌道要素を計算します。これは次の位置を計算するために使用され、次の 2 つの状態ベクトルとして返されます。

これは正常に機能しているようで、プロットを軌道面に保持している限り、それ自体で正しくプロットされます。しかし、軌道がどのように見えるか(obvs)のクールな3Dビューを見ることができるように、プロットを参照フレーム(親体)に回転させたいと思います。

現時点では、バグは軌道面の 2 つの状態ベクトルから参照フレームへの回転に変換する方法にあると思われます。このドキュメントのステップ 6 の方程式を使用して、次のコードを作成しています (ただし、個々の回転マトリックスを適用しています [ここからコピー])。

from numpy import sin, cos, matrix, newaxis, asarray, squeeze, dot

def Rx(theta):
    """
    Return a rotation matrix for the X axis and angle *theta*
    """
    return matrix([
        [1, 0,           0           ],
        [0, cos(theta), -sin(theta)  ],
        [0, sin(theta), cos(theta)   ],
    ], dtype="float64")

def Rz(theta):
    """
    Return a rotation matrix for the Z axis and angle *theta*
    """
    return matrix([
        [cos(theta), -sin(theta),   0],
        [sin(theta), cos(theta),    0],
        [0,          0,             1],
    ], dtype="float64")

def rotate1(vector, O, i, w):
    # The starting value of *vector* is just a 1-dimensional numpy
    # array.
    # Transform into a column vector.
    vector = vector[:, newaxis]
    # Perform the rotation
    R = Rz(-O) * Rx(-i) * Rz(-w)
    res2 = dot(R, vector)
    # Transform back into a row vector (because that's what
    # the rest of the program uses)
    return squeeze(asarray(res2))

(文脈上、これは私が軌道モデルに使用している完全なクラスです。)

結果から X 座標と Y 座標をプロットすると、次のようになります。

ここに画像の説明を入力

しかし、回転行列を に変更するとR = Rz(-O) * Rx(-i)、より妥当なプロットが得られます (ただし、明らかに 1 つの回転が失われ、中心が少しずれています)。

ここに画像の説明を入力

そして、それをさらに に減らすとR = Rx(-i)、予想どおり、次のようになります。

ここに画像の説明を入力

私が言ったように、奇妙な振る舞いをしているのは軌道計算コードではなく、回転コードの何らかのエラーであると確信しています。しかし、一般的にnumpyと行列数学の両方にかなり慣れていないため、これをどこに絞り込めばよいかわかりません。


更新:確率論の答えに基づいて、行列を転置しました(R = Rz(-O).T * Rx(-i).T * Rz(-w).T)が、このプロットを得ました:

ここに画像の説明を入力

これは、画面座標への変換が何らかの形で間違っているのではないかと思いましたが、私には正しいように見えます(そして、回転が少ないより正確なプロットと同じコードです)つまり:

def recenter(v_position, viewport_width, viewport_height):
    x, y, z = v_position
    # the size of the viewport in meters
    bounds = 20000000
    # viewport_width is the screen pixels (800)
    scale = viewport_width/bounds
    # Perform the scaling operation
    x *= scale
    y *= scale
    # recenter to screen X and Y measured from the top-left corner
    # of the viewport
    x += viewport_width/2
    y = viewport_height/2 - y
    # Cast to int, because we don't care about pixel fractions
    return int(x), int(y)


更新 2

確率論の助けを借りて、方程式の実装と回転をトリプルチェックしましたが、軌道を正しく取得することはできません。それらは基本的に上記のプロットと同じように見えます。

NASA Horizo​​n のシステムからのデータを使用して、ISS からの特定の状態ベクトル (2457380.183935185 = AD 2015-Dec-23 16:24:52.0000 (TDB)) を使用して軌道を設定し、同じ状態のケプラー軌道要素に対してそれらをチェックしました。これにより、次の結果が生成されます。

inclination :
  0.900246137041
  0.900246137041
true_anomaly :
  0.11497063007
  0.0982485984565
long_of_asc_node :
  3.80727461492
  3.80727461492
eccentricity :
  0.000429082122137
  0.000501850615905
semi_major_axis :
  6778560.7037
  6779057.01374
mean_anomaly :
  0.114872215066
  0.0981501816537
argument_of_periapsis :
  0.843226618347
  0.85994864996

上の値は私の (計算された) 値で、下の値は NASA の値です。明らかに、浮動小数点の精度エラーが予想されますが、mean_anomalyとの変動はtrue_anomaly予想よりも大きく感じました。(私は現在float128、64ビットシステムで数値を使用してすべてのnumpy計算を実行しています).

さらに、結果として得られる軌道は、上記の (かなり) 風変わりな最初のプロットのように見えます (この LEO ISS 軌道がかなり円形であることはわかっていますが)。そのため、問題の原因が何であるかについて少し困惑しています。

4

2 に答える 2

2

少なくとも 2 つの問題があると思います。

あなたが行っている軌道シミュレーションを詳しく調べた後 (コメントからのこの追加ドキュメントを参照)、主な問題は、最終的なプロットが楕円のように見えるはずであるという最初は非常に合理的であるが、まだ真実ではない仮定だと思います。周回する物体は必ずしも単一の平面にとどまるとは限らないため、一般的にはそうではありません。

もう1つの問題は、あなたが説明したドキュメント(以下を参照)に従って、回転行列が本来あるべきものの転置であることだと思います。

転置回転行列について

引用したドキュメントでは、R_x と R_z が軸の右手回転であるか、乗算するベクトルの右手回転であるかを直接指定していませんが、式 9 (または 10) から把握できます。ベクトルではなく、軸の右手回転であることがわかります。つまり、次のように定義する必要があります。

    return matrix([
        [1, 0,           0           ],
        [0, cos(theta), sin(theta)  ],
        [0,-sin(theta), cos(theta)   ],
    ], dtype="float64")

このような代わりに:

    return matrix([
        [1, 0,           0           ],
        [0, cos(theta),-sin(theta)  ],
        [0, sin(theta), cos(theta)   ],
    ], dtype="float64")

これは、式 9 を紙に手書きで再現することでわかりました。

  • その方程式で、ベクトルr (t) の最初のコンポーネントを見てください。
  • 2 つの用語があります。1 つは o_x を含み、もう 1 つは o_y を含みます。
  • o_y を乗算するものを見てください。それは: -(sin(omega)*cos(Omega)+cos(omega)*cos(i)*sin(Omega))です。
  • その先頭のマイナス記号が鍵です。これは、Rz マトリックスの最初の行のマイナス記号から来ています。
  • 式 9 の Omega、i、および omega はすべて否定されているため、R_z の 2 行目にマイナス記号が必要であることを意味します。これは、R_z がベクトルではなく、軸の右手回転を表すことを意味します。
  • 同様に、最後の項の o_y コンポーネントを見ると、R_x の 2 行目にマイナス記号が必要であることがわかります。これは、軸の R_z と R_x の両方の右手回転を意味します (正気に感謝します)。

Rx および Rz 関数は現在、軸ではなくベクトルの右手回転を定義しています。

これは、次のいずれかで修正できます (3 つすべてが同等です)。

  • オイラー角のマイナス記号を削除します。Rz(O) * Rx(i) * Rz(w)

  • 回転行列の転置:Rz(-O).T * Rx(-i).T * Rz(-w).T

  • -上記のように、Rx と Rz の定義の符号を 2 行目の正弦項に移動します。

于 2015-12-23T12:14:34.247 に答える
0

私はストキャスティクスの答えを正しいものとしてマークするつもりです。なぜなら、a) 彼は非常に役に立ち、ポイントに値し、b) 彼のアドバイスは根本的に正しかったからです。

ただし、奇妙なプロットのソースは、実際にはリンクされたOrbitクラスの次の行になりました。

    self.v_position = self.rotate(v_position, self.long_of_asc_node, self.inclination, self.argument_of_periapsis)
    self.v_velocity = self.rotate(v_velocity, self.long_of_asc_node, self.inclination, self.argument_of_periapsis)

self.v_position速度ベクトルを回転させる呼び出しが発生する前に、プロパティが更新されることに注意してください。@propertyコードを読んでいると、計算をより明確にするために、すべての軌道要素値メソッドをデコレーターでラップすることに賢明に決めたことに気付くかもしれません。

しかしもちろん、これは、プロパティにアクセスするたびにメソッドが呼び出され、値が再計算されることも意味します。したがって、 の 2 番目の呼び出しself.rotate()は、最初の呼び出しとはわずかに異なる軌道要素の値で発生し、さらに重要なことに、「現在の」位置および速度の状態ベクトルと 100% 正しく一致しない値で発生します!

このバグに頭を悩ませた数日後、リファクタリングの形で行っていたヤクの毛刈りから問題を解決し、今ではすべて完全に機能しています。

于 2015-12-24T23:08:16.423 に答える