【问题标题】:Two-body orbit modelling problems二体轨道建模问题
【发布时间】:2016-03-29 20:02:25
【问题描述】:

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

我正在尝试为简单的轨道模拟(两个物体)实现一个模型。

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

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

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

现在,我怀疑问题在于我如何从轨道平面中的两个状态向量转换为将它们旋转到参考系。我正在使用this document 的第 6 步中的方程式创建以下代码(但应用单独的旋转矩阵 [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 坐标时,我得到了:

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

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

所以正如我所说,我相当确定不是轨道计算代码行为异常,而是旋转代码中的一些错误。但我不确定在哪里缩小范围,因为我对 numpy 和矩阵数学一般都很陌生。


更新:基于stochastic's answer,我转置了矩阵(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 系统的数据,我使用来自国际空间站的特定状态向量(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 轨道是非常圆形的)。所以我有点不知道问题的根源是什么。

【问题讨论】:

    标签: python numpy matrix vector orbital-mechanics


    【解决方案1】:

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

    在仔细研究了您正在进行的轨道模拟之后(请参阅 cmets 中的 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定义中的-符号移到第二行正弦项,如上图

    【讨论】:

    • 谢谢,这确实澄清了一些事情——但不幸的是,我仍然得到了意想不到的结果。我在上面添加了更多信息,可能会澄清一些事情。
    • 另外,很抱歉很厚,但你说“事实证明它们是轴的旋转,而不是矢量”,我不清楚其中的含义。这是否意味着有一个中间步骤,而不是直接将旋转矩阵应用于向量?
    • 没问题。每个旋转矩阵都可以用两种方式解释:它可以被认为是在一个方向上旋转矢量或在相反方向上旋转轴。这里唯一的问题是旋转矩阵定义中的哪个正弦项前面应该有一个减号。我将尝试进一步澄清答案
    • 啊哈!好的,完全有道理。但是我会假设混淆轴/矢量旋转只会导致旋转方向错误,而不是我看到的有点疯狂的图?
    • 正确。我怀疑您的升交点经度和近点角的参数计算不正确。要获得椭圆形路径,这两个角度在整个轨道上应该几乎相同。是吗?
    【解决方案2】:

    我打算将 stochastic 的答案标记为正确,因为 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() 时,轨道元素的值与第一次调用略有不同,更重要的是,这些值与“当前”位置和速度状态向量没有 100% 正确匹配!

    因此,在对这个 bug 进行了几天的努力之后,我通过重构的形式进行了一些 yak-sshinging,现在一切正常。

    【讨论】:

      猜你喜欢
      • 2010-11-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-01
      • 2010-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多