X-Developer Cross-platform development in C++, Flight Simulation

5May/11Off

Analyzing how X-Plane propagates your position

No, this is not a "it's been a while"-post. You probably all know what I've been working on.

Instead, this is a "fancy engineering stuff" post.

Let's discuss briefly how X-Plane knows where your planes is. X-Plane, as we all know, calculates the forces that act on your airplane. The force that the engine applies to your airframe, for example. When you think back to your 9th grade physics class, you will recall that force is mass times acceleration. Or in other words, if you assume the mass of the airplane constant, force is a direct measure for the acceleration of your airplane.

Now recall that when you integrate acceleration over time, you get the speed. So by knowing the forces that X-Plane calculates based on the effect of the air on your plane, X-Plane knows the acceleration on your plane, and if you step forward a little discrete timestep ("one frame") and integrate this acceleration over time, X-Plane knows the speed of your plane.

Position (or, more accurately, distance) is velocity integrated over time. So when you progress another little discrete timestep and integrate the speed, you get the distance the plane has travelled. Add this distance to the point where your flight started and voila, X-Plane knows where your plane is now.

Okay, why do I care about this? When developing plugins for simulating, say, an FMC, I come across the need to know several parameters all the time, and these are, among others, position, groundspeed and true track (in X-Plane's jargon called "hpath"). The question I was asking myself was "I can get this out of the datarefs, of course. But could I possibly get this data like the real units do, from accelerometers and gyros?"

So what I tried to do is: Get the position out of X-Plane using ONLY a simulated accelerometer. The accelerometer is easy: X-Plane provides three datarefs to get the three local accelerations (sim/flightmodel/position/local_ax, .../local_ay, .../local_az).

So starting with nothing but an initial position and heading, I set up a flightloop callback that is called every frame, and in each callback I did what I know X-Plane must also do: Integrate the local accelerations twice and propagate from the last known position.

The first approach was like this:

  • get speed by explicit Euler integration of the acceleration
  • get distance by another explicit Euler integration of the speed
  • calculate the Place/Bearing/Distance point from the last known location (in Lat/Lon) by using the last known hpath and the distance I just calculated
  • Set this PBD point as the new position and start over

Now this proved to be a bad idea: Position of X-Plane and my calculated position diverged rather quickly. After a minute of flight, I was more than a mile off.

I decided to scratch all the fancy great circle maths (needed for the Lat/Lon calculation), and stay in X-Plane's OpenGL coordinate system as long as I could.

My new approach was calculating the position entirely in this coordinate system and useĀ XPLMLocalToWorld() only as a finalizer when displaying the coordinates.

Much better! I was down to like a mile per 10 minutes of flight. Completely useless if you want to cross the pond based on this navigation, but hey, I'm learning here!

Now I began messing with the integration methods. Explicit Euler is a very rough approximation. I briefly thought about using some pre-calculations and using a Runge-Kutta integration, but then I thought I could just save the last acceleration data in a list and use a multistep method. Adams-Bashfort is the most straightforward to use.

So now I had my setup:

  • push the acceleration into the list of acceleration history (and drop the oldest out of the history)
  • get speed by an Adams-Bashfort integration of the acceleration history
  • push this speed into the speed history and drop the oldest speed
  • do another Adams-Bashfort integration, this time on the speed history, which gives the travelled distance
  • add the travelled distanced onto the local OpenGL coordinates
  • transform to world coordinates and write those to datarefs

The result is w00t! I flew the little Cirrus jet in bumpy weather for like an hour, before calculating the difference between my position and X-Plane's. The difference was less than 500 meters. Now this is a navigation system you can fly cross-the-pond with!

So what is all this about? It's the proof that you can simulate navigation in X-Plane WITHOUT using all the data that X-Plane gives you, but you don't have in real life applications. An FMS in the real world can't ask the plane for the groundspeed (unless you have a GPS receiver, of course), it can only ask accelerometers, laser gyros, air data sensors, etc.
What my little experiment shows, is that you can do this in X-Plane and simulate an Inertial Reference Unit that allows you to navigate based solely on the output of the three datarefs, our simulated accelerometer.

However, there is one small problem you have to catch: X-Plane changes it's openGL reference frame as you travel (everytime you see new scenery being loaded, there also occurs a shift in the coordinate reference). So I need a little trick: Watch the datarefs for the reference point, and if they change, do an XPLMWorldToLocal() transform of my estimated position and overwrite my integrated position with these new local coordinates. Note that this does NOT reset the position to the "true" position, it just changes the reference frame in which my second integration is running.

So now on to even more advanced FMS simulations for X-Plane!

  • del.icio.us
  • Digg
  • email
  • Facebook
  • Google Buzz
  • Identi.ca
  • MisterWong
  • MySpace
  • Orkut
  • Print
  • Reddit
  • RSS
  • Slashdot
  • StumbleUpon
  • Technorati
  • Twitter
Comments (0) Trackbacks (0)

Sorry, the comment form is closed at this time.

Trackbacks are disabled.