Quentin Santos

Obsessed with computers since 2002

Author: Quentin Santos

  • Solving Kepler’s Equation 5 Million Times a Second

    Solving Kepler’s Equation 5 Million Times a Second

    I know it is a controversial opinion, but you might need to know where things are when running a simulation. As a bonus, it helps you in knowing what to draw on the screen.

    Of course, you can just use a position vector (x, y, z) where x, y and z are the coordinates of the object. But things have the inconvenient tendency not to stay in the same place for all eternity. So we’ll want to know where that object is at the given time.

    Now, the more generic approach is to run a physics simulation. We compute the acceleration of the object, update its speed depending on the acceleration and update its position depending on its speed. By the way, use Runge-Kutta 4 for this, not Euler’s method.

    Gravity accelerates the Moon towards the Earth, so its speed will tilt counter-clockwise in the picture (source)

    That would work for things in orbit too. But we can do much better in this case. This one guy, Johannes Kepler found simpler formulas to describe the movement of two orbiting objects (e.g. the Sun and the Earth, or the Earth and the Moon). Basically, the trajectories will be ellipses, and we can deduce the position of an object in its orbit at any given time.

    The orbits of planet1 and planet2 are ellipses such that one focus is the Sun (source)
    The area swept by an orbiting object is always the same during a fixed duration (source)

    We can describe the position of the object in its orbit as the angle between the direction of the periapsis (where the planet is closest to its sun) and the direction to the object, taken at the relevant focus. This is the true anomaly. Everything is an illusion, so we also like to pretend the ellipse is actually a circle and define the eccentric anomaly. But these angles are not linear with time. So we also define the mean anomaly, which works like an angle (goes from 0 to 2π) but is linear with time. Once we know the direction of the object, we will only need to know its distance, r.

    And here are the formulas to get from time to the true anomaly, and how we then obtain the distance from focus (e is the eccentricity of the ellipse):

    • mean anomaly (M): M = M₀ + n × (t – t₀)
    • eccentric anomaly (E): M = E – e × sin E
    • true anomaly (f): $latex \displaystyle f=2\arctan\sqrt{\frac{1+e}{1-e}} \tan\frac E2$
    • distance from focus (r): $latex \displaystyle r=\frac p{1 + e \cos f}$

    You won’t be calculating this in your head, but the expressions are pretty easy to translate to working code. Well, except for one. Notice how the eccentric anomaly is not expressed as a function of the mean anomaly? Well, that’s the hard part. And it’s called Kepler’s equation.

    Kepler’s equation in all its glory

    We do not know a simple way to express E as a formula depending only on e and M. Instead, we must proceed by successive approximations until we decide we are close enough. For this, we will need two things:

    • a starting value E₀ for E
    • a way to improve the current approximation of E

    Most introductory books and online articles I have found will tell you to take E₀ = M. This has been obsolete since 1978. It works well enough, but fails in corner cases (near-parabolic orbits around periapsis). And modern starting values are close enough to limit the number of improvements you then need to make. I reviewed 21 papers, selected the 3 most relevant ones, and implemented 21 methods for picking starting values (3 papers for the hyperbolic case with 5 methods for the hyperbolic case).

    To improve the starting value, old references will make you do E := M + e sin E, but this is pretty naive. Most modern references will use Newton’s method, which helps you solve an equation faster as long as you know its first derivative. But you can go further by using the second derivative using Halley’s method. You can go arbitrarily far using Householder’s method.

    Great, now I have 21 × 4 = 84 approaches to try (5 × 3 = 15 for the hyperbolic case). Which one is the most accurate? Which one is the fastest? And, more importantly, can I find a fast and accurate approach?

    You can spend years studying the theoretical properties of these functions. Or, we just try them for real. It is the most efficient way to know how they actually behave on real hardware with real implementations of numbers.

    I wrote a benchmark tool to test both the accuracy and the speed of each approach. It turns out that only a handful of approaches are accurate enough for my taste:

    # Elliptical case
    ## Naive method
    ## Newton's method
    ## Halley's method
         580 c  3.580e-16  gooding_10
         764 c  3.926e-16  gooding_11
         577 c  3.604e-16  mikkola_1
         742 c  3.653e-16  mikkola_2
    ## Householder's third order method
         606 c  3.645e-16  gooding_10
         809 c  3.623e-16  gooding_11
         641 c  3.935e-16  mikkola_1
         764 c  3.904e-16  mikkola_2
    
    # Hyperbolic case
    ## Newton's method
    ## Halley's method
        1454 c  3.731e-15  mikkola_1
        1578 c  3.725e-15  mikkola_2
    ## Householder's third order method
        1704 c  3.618e-15  mikkola_1
        1757 c  3.618e-15  mikkola_2

    The first column is the number of CPU cycles per solve of Kepler’s equation. The second column is the worst relative error over the test set. The third column is a short name for the method for picking a starting value for E.

    As we can see above, no approach seems to work well enough with the naive improvement, or with Newton’s method. And using third derivatives does not do much. gooding_11 and mikkola_2 are relatively slow. This leaves gooding_10 and mikkola_1. I picked mikkola_1 because the paper also treated the hyperbolic case. It comes from A cubic approximation for Kepler’s equation by Seppo Mikkola.

    And after all this, I have a very robust way to know where stuff is at any time! Of course, you should not forget to take care of floating point precision issues when implementing all of this…

    Appendix: References

    Appendix: Full benchmark

    # Elliptical case
    ## Naive method
         264 c  2.500e-01  smith_1
         276 c  5.303e-01  smith_2
         360 c  2.000e-01  smith_3
         444 c  9.701e-02  smith_4
         385 c  1.667e-01  smith_5
         480 c  6.495e+01  smith_6
         246 c  2.500e-01  gooding_1
         299 c  2.000e-01  gooding_2
         356 c  1.667e-01  gooding_3
         246 c  5.303e-01  gooding_4
         460 c  9.701e-02  gooding_5
         253 c  2.417e-01  gooding_6
         325 c  7.497e-02  gooding_7
         334 c  7.497e-02  gooding_7b
         378 c  1.277e-01  gooding_8
         423 c  7.499e-02  gooding_9
         455 c  2.376e-01  gooding_10
         608 c  8.020e-02  gooding_11
         286 c  1.439e-01  gooding_12
         448 c  4.342e-01  mikkola_1
         629 c  4.426e-01  mikkola_2
    ## Newton's method
         522 c  8.517e-03  smith_1
         539 c  1.379e-02  smith_2
         578 c  8.111e-03  smith_3
         697 c  8.111e-03  smith_4
         706 c  8.111e-03  smith_5
         900 c  1.028e+02  smith_6
         481 c  8.517e-03  gooding_1
         583 c  8.111e-03  gooding_2
         561 c  8.111e-03  gooding_3
         476 c  1.379e-02  gooding_4
         686 c  8.111e-03  gooding_5
         537 c  3.528e-02  gooding_6
         536 c  1.378e-02  gooding_7
         585 c  1.378e-02  gooding_7b
         702 c  2.524e-04  gooding_8
         680 c  1.379e-02  gooding_9
         731 c  1.117e-10  gooding_10
         940 c  2.072e-08  gooding_11
         528 c  5.673e-03  gooding_12
         697 c  1.825e-06  mikkola_1
         815 c  1.825e-06  mikkola_2
    ## Halley's method
         395 c  1.250e-01  smith_1
         419 c  2.553e-03  smith_2
         488 c  6.250e-02  smith_3
         596 c  1.710e-02  smith_4
         557 c  4.167e-02  smith_5
         989 c  5.130e+01  smith_6
         429 c  1.250e-01  gooding_1
         503 c  6.250e-02  gooding_2
         524 c  4.167e-02  gooding_3
         426 c  2.553e-03  gooding_4
         587 c  1.710e-02  gooding_5
         410 c  6.127e-03  gooding_6
         467 c  2.548e-03  gooding_7
         440 c  2.548e-03  gooding_7b
         508 c  9.153e-05  gooding_8
         552 c  2.550e-03  gooding_9
         598 c  3.580e-16  gooding_10
         821 c  3.926e-16  gooding_11
         430 c  1.028e-03  gooding_12
         594 c  3.604e-16  mikkola_1
         742 c  3.653e-16  mikkola_2
    ## Householder's third order method
         438 c  1.562e-02  smith_1
         439 c  6.779e-04  smith_2
         501 c  7.812e-03  smith_3
         667 c  2.138e-03  smith_4
         533 c  5.208e-03  smith_5
        1053 c  6.535e+01  smith_6
         453 c  1.562e-02  gooding_1
         501 c  7.812e-03  gooding_2
         594 c  5.208e-03  gooding_3
         429 c  6.779e-04  gooding_4
         595 c  2.138e-03  gooding_5
         454 c  1.638e-03  gooding_6
         526 c  6.736e-04  gooding_7
         585 c  6.736e-04  gooding_7b
         583 c  9.493e-09  gooding_8
         652 c  6.741e-04  gooding_9
         681 c  3.645e-16  gooding_10
         846 c  3.623e-16  gooding_11
         486 c  2.724e-04  gooding_12
         651 c  3.935e-16  mikkola_1
         752 c  3.904e-16  mikkola_2
    
    # Hyperbolic case
    ## Newton's method
         780 c  7.245e+25  basic
        1064 c  1.421e-03  mikkola_1
        1201 c  1.970e-04  mikkola_2
        1014 c  8.559e-01  gooding
         892 c  1.515e+19  pfelger
    ## Halley's method
        1134 c  1.729e+17  basic
        1396 c  3.731e-15  mikkola_1
        1526 c  3.725e-15  mikkola_2
        1265 c  9.160e+10  gooding
        1237 c  1.791e+13  pfelger
    ## Householder's third order method
        1260 c  1.323e+07  basic
        1631 c  3.618e-15  mikkola_1
        1595 c  3.618e-15  mikkola_2
        1467 c  2.276e+17  gooding
        1365 c  9.997e+01  pfelger