12

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

5 回答 5

9

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

You might want to take a look at the code in this blogpost http://blog.mendeltsiebenga.com/post/Fun-with-planets.aspx No xna, but working orbital mechanics. (although i never got rid of the screen-flicker)

于 2009-03-17T20:18:54.963 回答
8

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

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

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

其中x's 是代表物体位置的三个向量,m's 是相同物体的质量,是物体和r_ji = x_j - x_i之间的矢量位移。ji

于 2009-03-17T20:17:52.157 回答
5

The "leap frog" method is very efficient and stable, and works well for any dynamic particle/field system, including plasmas. For gravity, it's simple. Here is all you do for a single iteration on a single planet (1-body problem, single planet around stationary sun):

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

Where "Gravity.dT" is a uniform time step, in an arbitrary measure of time. I'm using System.Windows.Vector, but any custom Vector class will do, as long as it supports basic multiplication and addition. The trick is that the Position and Velocity aren't at the "same time", which is very common for most integration methods. Rather, they're staggered. The Position on iteration N is updated based on the Velocity from iteration N - 1/2, but then the Velocity at iteration N+1/2 is updated based on the Position at iteration N.

The N-body version looks like this:

    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;
        }

Where

    public static Vector GravityAccelerationVector(Vector position)
    {
        return Vector.Multiply(-G / position.LengthSquared / position.Length, position);
    }

The N-body is only more complicated because instead of a single gravitational source, there are several. The code format is the same, though: each planet's position gets pushed by the N-1/2 Velocity, then we figure out the total gravity acceleration on each planet based on the new positions, then we push each planet's Velocity by that total acceleration.

Other methods, even high order methods, are often unstable because they linearly project the next step based on position and velocity at the same time. This will always err on the side of adding energy to the system, and the orbits will gradually move further and further outward. Other methods can overcompensate for this natural error and remove energy from the system. In general, one wants an energy neutral solution. The leap frog method will gradually err in terms of phase of the orbits, but not in overall energy.

于 2011-05-03T15:20:18.123 回答
3

A passing object will not enter orbit. One characteristic of an orbit is that you will return to the same point (relative to the body being orbited) with the same velocity. If you started from effective infinity, you'll go back to effective infinity.

In order to enter orbit, you will need to change the velocity at some point in a way unrelated to gravity, or perhaps have additional large bodies. Similarly, you can't launch an object into orbit from the surface: you have to have something (like a last rocket burn) once the satellite reaches the desired altitude. Otherwise it will try to return to the launch point, which is on the surface.

Some of my worst debugging experiences were when the program was fine and my test data or calculations were off. Make sure you know what to look for.

于 2009-03-17T21:12:39.407 回答
1

A) We have no idea what your input values are.

B) You might want to use a better approximation than Newton-Raphson.

C) Passing objects do not generally fall into orbit IRL, gravity is extremely weak, it takes equally weak velocities or truly exceptional masses to get much more than curvature.

于 2009-03-17T20:21:23.273 回答