轨道力学

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

在最后一行中,您将更新镜头的位置。 你应该更新速度。

您可能需要查看此博客中的代码http://blog.mendeltsiebenga.com/post/Fun-with-planets.aspx没有xna,但是工作轨道机制。 (虽然我从来没有摆脱屏幕闪烁)

Newton-Raphson迭代不是一种解决这个问题的稳定方法(也就是说,使用如此简单的微分方程积分器,你无法做到正确)。 考虑使用第二个(或更高)订单解决方案: Runge-Kutta很好,在这种情况下很容易实现。

从数值分析的角度来看,轨道力学问题减少到求解耦合微分方程组的问题:

 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之间的矢量位移。

“跳蛙”方法非常有效和稳定,适用于任何动态粒子/场系统,包括等离子体。 对于重力,它很简单。 以下是您在单个行星上进行单次迭代所做的所有事情(单体问题,固定太阳周围的单个行星):

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

其中“Gravity.dT”是一个统一的时间步长,在任意时间段内。 我正在使用System.Windows.Vector,但任何自定义Vector类都可以,只要它支持基本的乘法和加法。 诀窍是位置和速度不是“同时”,这对于大多数集成方法来说非常常见。 相反,它们是错开的。 基于迭代N-1/2的速度更新迭代N上的位置,但是然后基于迭代N处的位置更新迭代N + 1/2的速度。

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速度推动,然后我们根据新位置计算出每个行星上的总重力加速度,然后我们将每个行星的速度推到总加速度。

其他方法,甚至是高阶方法,通常都是不稳定的,因为它们同时基于位置速度线性投影下一步。 这总是在向系统增加能量方面犯错,并且轨道将逐渐向外进一步向外移动。 其他方法可以过度补偿这种自然误差并从系统中去除能量。 一般来说,人们需要能量中性的解决方案。 跳蛙方法将逐渐在轨道相位上出错,但在整体能量方面则不然。

传递的物体不会进入轨道。 轨道的一个特征是你将以相同的速度返回相同的点(相对于被轨道运行的物体)。 如果你从有效无穷大开始,你将回到有效的无穷大。

为了进入轨道,你需要以某种方式改变速度,使其与重力无关,或者可能有更多的大体。 同样,你不能从地面发射一个物体进入轨道:一旦卫星达到所需的高度,你必须有一些东西(如最后一次火箭燃烧)。 否则它将尝试返回到表面上的发射点。

我最糟糕的一些调试经验是程序运行良好,我的测试数据或计算结果都没有。 确保你知道要寻找什么。

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

B)你可能想要使用比Newton-Raphson更好的近似值。

C)通过物体通常不会进入轨道IRL,重力非常弱,它需要同样弱的速度或真正特殊的质量来获得比曲率更多的东西。