Does anyone have an example of implementing Orbital Mechanics (preferably in XNA)? The code I am currently using is below, but it doesn\'t \"feel right\" when it executes. The
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.
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.
Newton-Raphson iteration is not a stable way to solve this problem (that is you can't get it right using so simple an integrator for the differential equation). Consider using a second (or higher) order solution: Runge-Kutta is good and is fairly easy to implement in this case.
From the point of view of numeric analysis, the problem of orbital mechanics reduces to that of solving the set of coupled differential equations:
x_i'' + G m_i \sum_{i != j} m_j r_ji/(|r_ji|)^3 = 0
where the x
's are three-vectors representing the positions of the bodies, the m
's are the masses of the same bodies, and r_ji = x_j - x_i
is the vector displacement between bodies j
and i
.
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.
In the last line you're updating the position of the shot. You should be updating the velocity.
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)