双体轨道建模问题

时间:2015-12-23 11:33:27

标签: python numpy matrix vector orbital-mechanics

如果您不想阅读太多背景,请跳至下面的更新2.

我试图为简单的轨道模拟实现模型(两个体)。

然而,当我尝试使用我编写的代码时,从结果中生成的图看起来很奇怪。

程序使用初始状态向量(位置和速度)来计算开普勒轨道元素,然后用于计算下一个位置,并作为下两个状态向量返回。

这似乎工作正常,并且只要我将轨迹保持在轨道平面上,就可以正确绘制。但我想将绘图旋转到参考框架(父体),以便我可以看到轨道外观(obvs)的酷3D视图。

现在,我怀疑这个错误是我如何从轨道平面中的两个状态向量转换为将它们旋转到参照系。我正在使用this document的第6步中的等式来创建以下代码(但应用单独的roation matricies [copied from here]):

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))

(对于上下文,this is the full class我用于轨道模型。)

当我从结果中绘制X和Y坐标时,我得到了这个:

enter image description here

但是当我将旋转矩阵更改为R = Rz(-O) * Rx(-i)时,我得到了这个更合理的情节(尽管显然缺少一个旋转,并略微偏离中心):

enter image description here

当我将其进一步减少到R = Rx(-i)时,正如人们所期望的那样,我得到了这个:

enter image description here

正如我所说,我很确定轨道计算代码不是表现得很奇怪,而是旋转代码中的一些错误。但是我不知道在哪里缩小范围,因为我对numpy和矩阵数学都很新。

<小时/> 更新:基于stochastic's answer我转换了matricies(R = Rz(-O).T * Rx(-i).T * Rz(-w).T),但随后得到了这个情节:

enter image description here

这让我想知道我转换到屏幕坐标是否有点错误 - 但它看起来对我来说是正确的(并且与更正确的旋转更少的图形相同)即:

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系统的数据,我建立了一个具有来自国际空间站的特定状态向量的轨道(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_anomalytrue_anomaly的变化确实比我预期的要大。 (我目前正在使用64位系统上的float128数字运行我的所有numpy计算。)

此外,由此产生的轨道看起来仍然像上面的(相当)偏心的第一个图(尽管我知道这个LEO ISS轨道非常圆形)。所以我对问题的根源是什么感到有点难过。

2 个答案:

答案 0 :(得分:1)

我相信你至少有两个问题。

仔细观察你正在进行的轨道模拟(参见评论中的this additional document),我认为主要的问题是最初非常合理但却不真实的假设,即最终的情节应该是看起来像一个椭圆形。一般而言,它不会,因为轨道体不一定会留在一个平面上。

我认为另一个问题是,根据您描述的文档(见下文),您的旋转矩阵是它们应该是什么的转置。

转置旋转矩阵

你引用的文件并没有直接指明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)的第一个分量。
  • 有两个术语:一个带有o_x,另一个带有o_y。
  • 看看多重o_y的事情。它是:-(sin(omega)*cos(Omega)+cos(omega)*cos(i)*sin(Omega))
  • 领先的减号是关键。它来自Rz矩阵第一行的减号。
  • 由于等式9中的Omega,i和omega都被否定,这意味着减号需要位于R_z的第二行,这意味着R_z代表轴的右旋转,而不是矢量。
  • 同样,我们可以查看最后一个术语的o_y组件,并看到减号需要位于R_x的第二行,意思是(谢天谢地),R_z和R_x的右手旋转都是轴。

您的Rx和Rz函数当前正在定义向量的右旋旋转,而不是轴。

您可以通过以下方式解决此问题(所有三个都是等效的):

  • 删除欧拉角上的减号:Rz(O) * Rx(i) * Rz(w)

  • 转置您的轮播矩阵:Rz(-O).T * Rx(-i).T * Rz(-w).T

  • 将Rx和Rz定义中的-符号移动到第二行正弦项,如上所示

答案 1 :(得分: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装饰器中,以使计算更加清晰。

但是,当然,这也意味着每次访问属性时都会调用方法 - 并重新计算值。所以对self.rotate()的第二次调用恰好与第一次调用的轨道元素值略有不同,更重要的是,与#34;当前&#34正确匹配的值100% ;位置和速度状态向量!

所以经过几天对这个虫子的撞击之后,我从一点点的牦牛皮中找到了它,我正在以重构的形式进行,现在一切都很完美。