Conclusion¶

This series covered a lot of fairly technical ground. We went from a classic flight dynamics reference code in Fortran to an identical implementation in Archimedes, then completely rebuilt the model using hierarchical design patterns, and finally took a whirlwind tour of trim and stability analysis.

After all of this, it’s worth pausing to consider a few takeaways from this tutorial.

(Mostly) Generic Flight Dynamics¶

First, and most importantly, the bulk of what we’ve covered here applies to a broad category of flight vehicles beyond the F-16 or even high-performance military aircraft.

This specific breakdown into subsystems is identical for most conventional aircraft. Even the subsystem models themselves are mostly reusable. All you need to do is supply models of aerodynamics, propulsion, and inertia characteristics (though admittedly, this is still most of the work in flight vehicle modeling). The trim and stability codes are also mostly reusable, and eventually will likely be packaged into fully reusable utilities that operate on RigidBody states or some generic FlightVehicle protocol.

In the event that you have radically different vehicle dynamics, the basic principles still apply and you can hack on this example until it resembles your vehicle.

Hierarchical Modeling¶

If you choose to adopt Archimedes to build your own flight dynamics framework, one of the first questions you’ll face is whether to pursue the hierarchical design pattern or a more traditional set of modular functions.

One of the goals of this series is to give a view into what the hierarchical approach actually looks like for a reasonably complex model. When executed carefully, it can produce clean, maintainable codebases but to be fair, it does involve significantly more code. The general recommendation is to start as simple as possible - experience shows that it’s not that difficult to rewrite a moderately complicated codebase in the hierarchical style, and we all know what they say about premature optimization.

On the other hand, Python is an incredibly flexible language, and Archimedes itself is also fairly flexible (provided you stay within the bounds of functional purity). You may want to develop a framework that looks nothing like either the classic “subroutine” or the “hierarchical” design. Go for it - if you find a style you like, feel free to share on the Discussions page of the GitHub site!

The Role of Autodiff¶

One final comment is on the value of automatic differentiation for this use case. We didn’t focus on it much, but it’s used in two main places: the trim solver, and the linearization.

Linearization is a fairly obvious one, and we call the Jacobian transformation explicitly in that case. However, the trim solver calls root, which is a Newton solver that internally uses automatic differentiation to compute the Jacobian of the residuals in order to find the next iteration of optimization parameters. Other formulations of the trim solve might use least_squares or a full constrained nonlinear program (minimize), both of which also use autodiff to efficiently and accurately compute derivatives.

Automatic differentiation is not strictly necessary in either of these cases. Both are “offline” and fairly inexpensive, so standard finite differencing is fair game - and has been successfully used for decades. The main issue with finite differencing in this setting is numerical accuracy. As we saw in Part 3 stability is assessed by the eigenvalues of the system Jacobians, and the open-loop stability can be very marginal for high-performance aircraft, making accurate estimates critical. Numerical linearization errors propagate through the eigenvalue solver and in extreme cases can give misleading eigenvalue estimates.

Automatic differentiation tends to produce much more stable and accurate derivative estimates, and hence more reliable stability analyses. Just be careful with discontinuous nonlinearities like abs and sign. Realistically, the best of both worlds is to cross check between automatic differentiation and a good finite differencing implementation like scipy.optimize.approx_fprime.

Where to Go From Here¶

If you’re new to Archimedes and confused by some of the conventions and constructions, this is a great time to revisit some of the basics:

When you’re ready to take the F-16 to the next level, try designing a controller and autogenerating C code for it. You can even follow the Hardware Deployment workflow and generate simulation code for benchtop HIL testing of the F-16 with your controller.

And if you have a flight vehicle you’d like to model in Archimedes, the source code for this series is a great place to start.

Finally and most importantly, if you’re using Archimedes for flight dynamics modeling and have questions, comments, or requests, please don’t hesitate to reach out - we want to hear from you!