轨道力学
有没有人有一个实施轨道力学的例子(最好是在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
是物体j
和i
之间的矢量位移。
“跳蛙”方法非常有效和稳定,适用于任何动态粒子/场系统,包括等离子体。 对于重力,它很简单。 以下是您在单个行星上进行单次迭代所做的所有事情(单体问题,固定太阳周围的单个行星):
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,重力非常弱,它需要同样弱的速度或真正特殊的质量来获得比曲率更多的东西。