轨道力学

13

有没有人有实现轨道力学的例子(最好是在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);  
} 

编辑 感谢Mendelt指出我需要更新速度,而不是位置。我还需要更改gPull的计算方法。

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

关于您的编辑:gPull的系数应对于所有质量相同(即 gPull = G * mass1 * mass2 / distance^2)。如果planet.gStr是行星的表面重力,则不是您想要的!这里的G是常数:G = 6.6e-11 m^3/kg/s^2(SI单位制)。 - dmckee --- ex-moderator kitten
@dmckee 是的,但我希望不同的行星对物体有更强或更弱的引力。 - user60456
5个回答

10

有趣的是,这给了我一个漂亮的正弦波...虽然不完全是我要找的,但这是我的方程的结果。 - user60456
@Joe:如果你绘制一个在圆形轨道上的物体的位置的单个分量(比如x)与时间的关系图,你会期望看到一个正弦波(可能带有相位差)。 - dmckee --- ex-moderator kitten
5
链接已移至http://www.mendeltsiebenga.com/2009/01/fun-with-planets.html。 - Jason Owen
源代码的RAR文件也不可用,即使您使用archive.org。 - oPless

8

牛顿-拉弗森迭代法不是解决这个问题的稳定方法(也就是说,使用如此简单的积分器无法正确得出结果)。考虑使用二阶(或更高阶)解决方案:龙格-库塔方法是好的,并且在这种情况下相当容易实现。

从数值分析的角度来看,轨道力学问题归结为解决一组耦合微分方程:

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

其中x是表示物体位置的三维向量,m是相应物体的质量,r_ji = x_j - x_i是物体ji之间的向量位移。


@Earwiker:是的。已经过了很长时间,但我记得我的NR轨道模拟器每个轨道都会累积几个百分点的径向误差。但它也破坏了能量和角动量的守恒。我们物理学家对此非常沮丧... - dmckee --- ex-moderator kitten
噢,我知道,我也是物理学出身的! :) - Daniel Earwicker
当然,逐渐变化的轨道不一定会在现实世界中违反守恒定律,例如月球距离地球比数十亿年前更远(由于潮汐效应而非近似积分)。 - Daniel Earwicker
Runge-Kutta方法实际上也不是一种一致的方法。它看起来很完美,但深入分析后可以发现,如果你只是使用更细的时间/分辨率步骤,那么它并不能保持基本量的守恒,而更简单的代码却能够做到。话虽如此,对于大多数目的来说,它仍然是一个很好的选择。 - Alex
我在另一个答案中提到的跳跃法可以解决能量守恒问题。相位(沿轨道的位置)会逐渐累积误差,但能量将无限期保持不变。 - James
显示剩余3条评论

5

“跳跃法”方法非常高效和稳定,适用于任何动态粒子/场系统,包括等离子体。对于重力问题,方法很简单。下面是在一个行星上进行一次迭代的步骤(单体问题,单个行星绕着静止的太阳运转):

    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-body版本如下:

    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-Body问题更加复杂,因为不只有一个引力源,而是有多个。但代码格式相同:每颗行星的位置都会被N-1/2速度推动,然后我们根据新的位置计算每颗行星的总引力加速度,最后再将每颗行星的速度推动到该总加速度上。
其他方法,即使是高阶的方法,通常也不稳定,因为它们同时基于位置和速度线性地预测下一步。这始终会在给系统添加能量的一面出现误差,并且轨道会逐渐向外移动。其他方法可能会过度补偿这种自然误差并从系统中删除能量。通常,我们需要一种能量中性解决方案。Leap Frog方法在轨道相位方面会逐渐出现误差,但总体能量不会出错。

3
一个通过的物体不会进入轨道。轨道的一个特征是,您将以相同的速度返回到相同的点(相对于被轨道绕行的物体)。如果您从无限远处开始,您将回到无限远处。
为了进入轨道,您需要在某个时刻以与重力无关的方式改变速度,或者可能有额外的大型物体。同样,您不能从表面发射物体进入轨道:一旦卫星达到所需高度,您必须拥有某些东西(例如最后的火箭推力)。否则它将试图返回到发射点,即地面。
我的一些最糟糕的调试经验是当程序没问题,而我的测试数据或计算错误时。确保您知道要查找什么。

如果“经过的物体”和“轨道物体”以相同的速度在与其它物体相同距离上移动,它们之间有什么区别? - Daniel Earwicker
我的印象是“经过的物体”来自遥远的地方。当然,与轨道物体的区别在于速度。当然,我可能误解了OP的意思。 - David Thornley
我相信你对此是错误的,因为Triton被认为是一颗被捕获的卫星 - 它曾经只是经过而已;现在它正在轨道上运行。如果我理解正确,无论物体离一个更大的物体有多远,只要速度和距离合适,它就可能进入轨道。 - P Daddy
简单来说,如果你把一根绳子的两端系在一起,你就有了一个环,但是如果你把一端系在绳子的中间,你仍然有一个环。要轨道运行,并不需要返回原点。 - P Daddy
你们的COM相关的东西都超出了我的理解范围(我讨厌COM!):·) - P Daddy
显示剩余2条评论

1

A) 我们不知道你的输入值是什么。

B) 你可能想使用比牛顿-拉弗森更好的近似方法。

C) 在现实生活中,传递物体通常不会进入轨道,重力非常微弱,需要同样微弱的速度或真正特殊的质量才能获得更多的曲率。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接