Orbits with Jolt Physics

I want to simulate an orbiting spacecraft using the Jolt Physics engine (see sfsim homepage for details). The Jolt Physics engine solves difficult problems such as gyroscopic forces, collision detection with linear casting, and special solutions for wheeled vehicles with suspension.

The integration method of the Jolt Physics engine is the semi-implicit Euler method. The following formula shows how speed v and position x are integrated for each time step:

latex formula

The gravitational acceleration by a planet is given by:

latex formula

To test orbiting, one can set the initial conditions of the spacecraft to a perfect circular orbit:

latex formula

The orbital radius R was set to the Earth radius of 6378 km plus 408 km (the height of the ISS). The Earth mass was assumed to be 5.9722e+24 kg. For increased accuracy, the Jolt Physics library was compiled with the option -DDOUBLE_PRECISION=ON.

A full orbit was simulated using different values for the time step. The following plot shows the height deviation from the initial orbital height over time.

Orbits with symplectic Euler

When examining the data one can see that the integration method returns close to the initial after one orbit. The orbital error of the Euler integration method looks like a sine wave. Even for a small timestep of dt = 0.031 s, the maximum orbit deviation is 123.8 m. The following plot shows that for increasing time steps, the maximum error grows linearly.

Euler orbit deviation as a function of time step

For time lapse simulation with a time step of 16 seconds, the errors will exceed 50 km.

A possible solution is to use Runge Kutta 4th order integration instead of symplectic Euler. The 4th order Runge Kutta method can be implemented using a state vector consisting of position and speed:

latex formula

The derivative of the state vector consists of speed and gravitational acceleration:

latex formula

The Runge Kutta 4th order integration method is as follows:

latex formula

The Runge Kutta method can be implemented in Clojure as follows:

(defn runge-kutta
  "Runge-Kutta integration method"
  {:malli/schema [:=> [:cat :some :double [:=> [:cat :some :double] :some] add-schema scale-schema] :some]}
  [y0 dt dy + *]
  (let [dt2 (/ ^double dt 2.0)
        k1  (dy y0                0.0)
        k2  (dy (+ y0 (* dt2 k1)) dt2)
        k3  (dy (+ y0 (* dt2 k2)) dt2)
        k4  (dy (+ y0 (* dt  k3)) dt)]
    (+ y0 (* (/ ^double dt 6.0) (reduce + [k1 (* 2.0 k2) (* 2.0 k3) k4])))))

The following code can be used to test the implementation:

(def add (fn [x y] (+ x y)))
(def scale (fn [s x] (* s x)))

(facts "Runge-Kutta integration method"
       (runge-kutta 42.0 1.0 (fn [_y _dt] 0.0) add scale) => 42.0
       (runge-kutta 42.0 1.0 (fn [_y _dt] 5.0) add scale) => 47.0
       (runge-kutta 42.0 2.0 (fn [_y _dt] 5.0) add scale) => 52.0
       (runge-kutta 42.0 1.0 (fn [_y dt] (* 2.0 dt)) add scale) => 43.0
       (runge-kutta 42.0 2.0 (fn [_y dt] (* 2.0 dt)) add scale) => 46.0
       (runge-kutta 42.0 1.0 (fn [_y dt] (* 3.0 dt dt)) add scale) => 43.0
       (runge-kutta 1.0 1.0 (fn [y _dt] y) add scale) => (roughly (exp 1) 1e-2))

The Jolt Physics library allows to apply impulses to the spacecraft. The idea is to use Runge Kutta 4th order integration to get an accurate estimate of the speed and position of the spacecraft after the next time step. One can apply an impulse before running an Euler step so that the position after the Euler step matches the Runge Kutta estimate. A second impulse then is used after the Euler time step to also make the speed match the Runge Kutta estimate. Given the initial state (x(n), v(n)) and the desired next state (x(n+1), v(n+1)) (obtained from Runge Kutta) the formulas for the two impulses are as follows:

latex formula

The following code shows the implementation of the matching scheme using two speed changes in Clojure:

(defn matching-scheme
  "Use two custom acceleration values to make semi-implicit Euler result match a ground truth after the integration step"
  [y0 dt y1 scale subtract]
  (let [delta-speed0 (scale (/ 1.0 ^double dt) (subtract (subtract (:position y1) (:position y0)) (scale dt (:speed y0))))
        delta-speed1 (subtract (subtract (:speed y1) (:speed y0)) delta-speed0)]
    [delta-speed0 delta-speed1]))

The following plot shows the height deviations observed when using Runge Kutta integration.

Orbits with Runge Kutta 4th order

The following plot of maximum deviation shows that the errors are much smaller.

RK orbit deviation as a function of time step

Although the accuracy of the Runge Kutta matching scheme is higher, a loss of 40 m of height per orbit is undesirable. Inspecting the Jolt Physics source code reveals that the double-precision setting affects position vectors but is not applied to speed and impulse vectors. To test whether double precision speed and impulse vectors would increase the accuracy, a test implementation of the semi-implicit Euler method with Runge Kutta matching scheme was used. The following plot shows that the orbit deviations are now much smaller.

Orbits with Runge Kutta 4th order and double precision

The updated plot of maximum deviation shows that using double precision the error for one orbit is below 1 meter for time steps up to 40 seconds.

RK with double precision orbit deviation as a function of time step

I am currently looking into building a modified Jolt Physics version which uses double precision for speed and impulse vectors. I hope that I will get the Runge Kutta 4th order matching scheme to work so that I get an integrated solution for numerically accurate orbits as well as collision and vehicle simulation.

Update:

Jorrit Rouwé has informed me that he currently does not want to add support for double precision speed values. He also has more detailed information about using Jolt Physics for space simulation on his website.

I have managed to get a prototype working using the moving coordinate system approach. One can perform the Runge Kutta integration using double precision coordinates and speed vectors with the Earth at the centre of the coordinate system. The Jolt Physics integration then happens in a coordinate system which is at the initial position and moving with the initial speed of the spaceship. The first impulse of the matching scheme is applied and then the semi-implicit Euler integration step is performed using Jolt Physics with single precision speed vectors and impulses. Then the second impulse is applied. Finally the position and speed of the double precision moving coordinate system are incremented using the position and speed value of the Jolt Physics body. The position and speed of the Jolt Physics body are then reset to zero and the next iteration begins.

The following plot shows the height deviations observed using this approach:

Orbits using moving coordinate system

The maximum errors for different time steps are shown in the following plot:

Maximum errors with moving coordinate system as a function of time step

Akima splines

Recently I was looking for spline interpolation for creating curves from a set of samples. I knew cubic splines which are piecewise cubic polynomials fitted such that they are continuous up to the second derivative. I almost went ahead and implemented cubic splines using a matrix solver but then I found that the fastmath Clojure library already provides splines. The fastmath spline interpolation module is based on the interpolation module of the Java Smile library. I saved the interpolated samples to a text file and plotted them with Gnuplot.

(require '[fastmath.interpolation :as interpolation])
(use '[clojure.java.shell :only [sh]])

(def px [0 1 3 4 5 8 9])
(def py [0 0 1 7 3 4 6])
(spit "/tmp/points.dat" (apply str (map (fn [x y] (str x " " y "\n")) px py)))

(def cspline (interpolation/cubic-spline px py))
(def x (range 0 9.0 0.01))
(spit "/tmp/cspline.dat" (apply str (map (fn [x y] (str x " " y "\n")) x (map cspline x))))
(sh "gnuplot" "-c" "plot.gp" "/tmp/cspline.png" "/tmp/cspline.dat")
(sh "display" "/tmp/cspline.png")

I used the following Gnuplot script plot.gp for plotting:

set terminal pngcairo size 640,480
set output ARG1
set xlabel "x"
set ylabel "y"
plot ARG2 using 1:2 with lines title "spline", "/tmp/points.dat" using 1:2 with points title "points"

I used a lightweight configuration of the fastmath library without MKL and OpenBLAS. See following deps.edn:

{:deps {org.clojure/clojure {:mvn/version "1.12.1"}
        generateme/fastmath {:mvn/version "2.4.0" :exclusions [com.github.haifengl/smile-mkl org.bytedeco/openblas]}}}

The result is shown in the following figure. One can see that the spline is smooth and passes through all points, however it shows a high degree of oscillation:

cubic spline

However I found another spline algorithm in the fastmath wrappers: The Akima spline. The Akima spline needs at least 5 points and it first computes the gradient of the lines connecting the points. Then for each point it uses a weighted average of the previous and next slope value. The slope values are weighted using the absolute difference of the previous two slopes and the next two slopes, i.e. the curvature. The first and last two points use a special formula: The first and last point use the next or previous slope and the second and second last point use an average of the neighbouring slopes.

(require '[fastmath.interpolation :as interpolation])
(use '[clojure.java.shell :only [sh]])

(def px [0 1 3 4 5 8 9])
(def py [0 0 1 7 3 4 6])
(spit "/tmp/points.dat" (apply str (map (fn [x y] (str x " " y "\n")) px py)))

(def aspline (interpolation/akima-spline px py))
(def x (range 0 9.0 0.01))
(spit "/tmp/aspline.dat" (apply str (map (fn [x y] (str x " " y "\n")) x (map aspline x))))
(sh "gnuplot" "-c" "plot.gp" "/tmp/aspline.png" "/tmp/aspline.dat")
(sh "display" "/tmp/aspline.png")

Akima spline

So if you have a data set which causes cubic splines to oscillate, give Akima splines a try!

Enjoy!

Update: u/joinr showed, how you can use Clojupyter to quickly test a lot of splines.

Flight dynamics model for simulating Venturestar style spacecraft

sfsim space flight simulator screenshot

This is an informational post on how to simulate the physics of atmospheric flight of a Venturestar style single-stage-to-orbit space craft. My dad Gerhard Wedekind is an experienced aerodynamics engineer and I asked him to help with making the aerodynamics of the sfsim space flight simulator realistic to some extent. The information in this post is a write-up of relevant formulas and approximate data he obtained from numerical simulation and estimates from aerodynamics knowledge. The information provided in this article is for general informational purposes only and comes without any warranty, express or implied.

Simulation

Here are a few beautiful snapshots from simulation. The first one shows a Mach box for V = 2 Ma and α = 3°. Venturestar Mach Box for V = 2 Ma and α = 3°

The next one shows a Mach box for V = 4 Ma and α = 3°. Venturestar Mach Box for V = 4 Ma and α = 3°

Finally here is a distribution of the pressure difference between top and bottom of wing. Venturestar Pressure Difference

Coordinate systems

The following drawing shows the body coordinate system (xb, yb, zb) and the wind coordinate system (xw, yw, zw). The wind system is rotated against the body system so that the speed vector (in a stationary atmosphere) points in positive xw.

coordinate systems

Note that lift, drag, and side force are defined in the wind system and not in the body system.

  • A positive lift force points upwards (negative zw) in the wind system.
  • The drag force points backwards (negative xw) in the wind system.
  • A positive side force points starboard (positive yw) in the wind system.

Yaw, pitch, and roll moments on the other hand are specified in the body system.

A coordinate system transformation from body system to wind system can be performed using two angles:

  • α is the angle of attack
  • β is the sideslip angle

When transforming coordinates from body system to wind system, one first rotates by β (sideslip angle) about the body z axis (zb). Then one rotates by α (angle of attack) about the new y axis.

Dynamic pressure

The dynamic pressure q depends on air density ρ and speed V: latex formula

Air density (and temperature) as a function of height can be obtained from Hull’s book “Fundamentals of airplane flight mechanics”.

Forces

Drag consists of zero-lift drag and induced drag: latex formula

Zero-lift drag is computed using the zero-lift drag coefficient CD0 as well as dynamic pressure q and the reference area Sref: latex formula The zero-lift drag coefficient depends on the speed of the aircraft.

Induced drag is determined using the lift coefficient CL, the Oswald factor e, the aspect ratio Λ, as well as q and the reference area Sref. latex formula The Oswald factor e depends on the speed of the aircraft. The lift coefficient depends on the angle of attack α.

The aspect ratio Λ depends on wing span b and wing area S: latex formula

The lift L is computed using the lift coefficient CL, dynamic pressure q, and the reference area Sref: latex formula

The side force Y (and corresponding coefficient) is usually not important but we will look into it later in a future article.

Moments

The pitching moment M is computed using the pitching moment coefficient Cm, the dynamic pressure q, the reference area Sref, and the aerodynamic chord cbar: latex formula The pitching moment coefficient depends on the lift coefficient CL, the position of the neutral point XN, the centre of gravity xref. and the aerodynamic chord cbar: latex formula

The yawing moment N is the product of the yawing moment coefficient Cn, the dynamic pressure q, the reference area Sref, and half the wing span b: latex formula The yawing moment coefficient depends on the side slip angle β.

The rolling moment L (using the same symbol as lift for some reason) is the product of the rolling moment coefficient Cl, the dynamic pressure q, the reference area Sref, and half the wing span b: latex formula The rolling moment coefficient depends on the angle of attack α and the side slip angle β.

Data Sheet

Here are the parameters for the flight model above:

latex formula

Note that xref is defined in a coordinate system where x=0 is at the intersection of the inner leading edges (wing apex). The following picture also shows the position of the aerodynamic chord with length cbar. The center of gravity is at 25% of the aerodynamic chord.

coordinate system origin at intersection of leading edges

Tables

Here is a data table with information for determining the remaining coefficients depending on the airspeed in Mach (Ma). The table shows for each speed:

  • a factor to determine the lift coefficient CL
  • the position XN of the neutral point relative to the aerodynamic chord (note that the center of gravity xref is at the 25% mark of the aerodynamic chord)
  • the Oswald factor e
  • a factor to determine the rolling moment coefficient Cl
  • a factor to determine the yawing moment coefficient Cn
  • the zero-lift drag coefficient CD0

latex formula

The outlier of Clβα for V = 1.2 Ma (0.5971) should be ignored because the value was changing a lot with mesh resolution.

The speed of sound as a function of temperature T is according to Wikipedia: latex formula

For small values of α, the lift coefficient increases linearly with α (where α is specified in radians): latex formula

For small values of α and β, the rolling moment coefficient increases linearly with the product of α and β (where α and β are specified in radians). This is a particular behaviour of delta wing configurations. If there is side slip, the wings generate different amounts of lift causing a significant roll moment: latex formula

For small values of β, the yawing moment coefficient increases linearly with β (where β is specified in radians): latex formula

The following table shows for each speed:

  • the value for α at which the linear relation of CL and α breaks down
  • the maximum value of CL
  • the angle of attack where CL reaches its maximum
  • the drag coefficient for 90° angle of attack

latex formula

Near α=90°, the lift and drag coefficients behave as follows: latex formula

At hypersonic speeds (V/Ma=10.0), lift and induced drag coefficients behave as follows: latex formula

I.e. the coefficients are stabilising at hypersonic speeds!

Control surfaces

The following table shows parameters to determine different moments generated by control surfaces:

latex formula

The side force coefficient for a given rudder angle ζ is: latex formula The yawing moment coefficient for the rudder is: latex formula

The pitching moment coefficient for flaps δF (down is positive) is latex formula

The rolling moment coefficient for ailerons with angle ξ (positive: port aileron up, starboard aileron down) is: latex formula The yawing moment coefficient is latex formula

Angular damping

The formula for roll, pitch, and yaw damping moments (L, M, N) due to roll, pitch, and yaw rates (p, q, r) uses a coefficient matrix: latex formula The coefficients for V = 0 Ma are as follows. Note that damping moments are negligible for higher speeds. latex formula The last (10th) value in the table CLq is the change in the lift coefficient due to the pitch rate q.

Next steps

Using the information, the curves for a full range of angles and speeds need to be fitted and guessed in some places.

Feel free to leave a comment or suggestion below.

The Connascence Software Design Metric explained using Python Code Examples

The following presentation is a short introduction to the connascence software design metric. Connascence is a useful tool to understand and reduce the degree of coupling in software systems and make software more modular.

Click above image to watch the 10 minutes presentation.

You can get the slides of the presentation here: connascence.pdf

See github.com/wedesoft/connascence for source code of slides.

Enjoy!

sfsim page published

I finally managed to get enough of a prototype together to make a page about sfsim (space flight simulator). I was inspired by realistic space flight simulators like Orbiter 2016 and I decided to start a cross-platform project based on LWJGL/OpenGL. The plan is to support vertical launch, space station docking, moon landing, reentry, and landing on a runway in the future. The page features a new trailer demonstrating the aerodynamics prototype:

Also my application as a Steam developer was accepted and the Steam app page for sfsim was approved. You can find the page here. If you are interested in a space flight simulator with realistic physics, just add sfsim to your Steam wishlist to get notified when it is released:

sfsim

Let me know in the comments if there is anything you would like to see in a realistic space flight simulator.