C# 轨道力学
有没有人有实施轨道力学的例子(最好是XNA)?我目前使用的代码如下所示,但在执行时“感觉不正确”。物体只是稍微向行星弯曲,无论我如何调整变量,我都无法让它进入轨道,甚至部分轨道C# 轨道力学,c#,xna,physics,C#,Xna,Physics,有没有人有实施轨道力学的例子(最好是XNA)?我目前使用的代码如下所示,但在执行时“感觉不正确”。物体只是稍微向行星弯曲,无论我如何调整变量,我都无法让它进入轨道,甚至部分轨道 shot.Position += shot.Velocity; foreach (Sprite planet in planets) { Vector2 directionToPlanet = (planet.Position - shot.Position); directionToPlane
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);
}
编辑
标记门德尔的答案是正确的,因为它指出我需要更新速度,而不是位置。我还需要将gPull的计算更改为
float gPull = shot.Mass * planet.Mass / distanceSqr * planet.gStr;
这不是一个解决这个问题的稳定方法(也就是说,你不能用这么简单的微分方程积分器得到正确的结果)。考虑使用第二(或更高)阶解:是好的,在这种情况下是相当容易实现的。
从数值分析的角度来看,轨道力学问题归结为求解耦合微分方程组的问题:
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
之间的向量位移。你应该更新速度
你可能想看看这篇博文中的代码,不是xna,而是工作轨道力学。(尽管我从未摆脱屏幕闪烁)A)我们不知道您的输入值是什么
B) 您可能希望使用比Newton Raphson更好的近似值
C) 经过的物体通常不会进入轨道IRL,重力非常弱,需要同样弱的速度或真正异常的质量才能获得比曲率大得多的能量。经过的物体不会进入轨道。轨道的一个特征是,您将以相同的速度返回到同一点(相对于正在轨道运行的物体)。如果你从有效无限开始,你会回到有效无限 为了进入轨道,你需要以一种与重力无关的方式改变某个点的速度,或者可能有额外的大型物体。类似地,你不能将物体从表面发射到轨道上:一旦卫星达到所需高度,你必须有某种东西(比如最后一次火箭燃烧)。否则,它将尝试返回地面上的发射点 我最糟糕的调试经历是当程序运行良好,测试数据或计算中断时。确保你知道要寻找什么。这种“蛙跳”方法非常有效和稳定,适用于任何动态粒子/场系统,包括等离子体。对于重力来说,这很简单。以下是您在单个行星上进行单个迭代所做的全部工作(单体问题,围绕静止太阳的单个行星): 其中“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;
}
在哪里
N体更为复杂,因为不是单个引力源,而是多个引力源。代码格式是一样的:每个行星的位置都被N-1/2的速度推动,然后我们根据新的位置计算出每个行星上的总重力加速度,然后我们通过总加速度推动每个行星的速度
其他方法,即使是高阶方法,也往往不稳定,因为它们同时基于位置和速度线性预测下一步。这在给系统增加能量方面总是错误的,轨道将逐渐向外移动。其他方法可以过度补偿这种自然误差,并从系统中移除能量。一般来说,人们需要一种能量中性的解决方案。蛙跳法在轨道的相位方面会逐渐出错,但在总能量方面不会出错。有趣的是,这给了我一个很好的正弦波……这不完全是我想要的,但这是我研究的结果equation@Joe:如果绘制圆形轨道中对象的单个位置分量(如x),则为正弦波(加上可能的阶段)是你所期望的…链接已经移动到了。而且源代码的rar也不可用。即使你使用archive.org。如果“经过的物体”和“轨道物体”以相同的速度与另一个物体保持相同的距离,它们之间有什么区别?我的印象是“经过的物体”来自很远的地方。它和轨道物体之间的区别当然是速度。当然,我可能误解了OP。很肯定你错了,因为Triton®声波风廓线仪被认为是一颗被捕获的卫星,它正在经过;现在它在绕轨道运行。如果我理解正确,不管物体离我们有多远当它靠近一个更大的物体时,如果速度和距离合适,它可能会进入轨道。简单地说,如果你拿一根绳子并把两端绑在一起,你就有一个环,但是如果你把绳子的一端绑在中间,你仍然有一个环。要进入轨道,你不需要回到原点。@P Daddy:引力相互作用完全是时间reversal不变量。要捕获“经过的物体”,需要推力或与第三个物体的相互作用。而且所有两个物体的引力相互作用路径都是圆锥截面(在COM框架中)。没错,但你可以在不借助Runge Kutta的情况下获得一些轨道。它不会停留在同一轨道上那么久
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);
}