1 Musings about the Design of a Wind Tunnel Simulator
The basic idea is to start with the JSBSim simulator, and make minor
modifications so as to implement wind tunnel mode.
Let’s review the principles of operation in the
normal integrator mode, where we time-step the equations of
motion. We will discuss it from two points of view, namely what
should happen, and what actually happens in the current
(July 2008) code. Note that what we call “time stepping” is called
“propagation” in the code.
: Time-Stepping the Equation of Motion
As an “induction hypothesis” we assume that we already have valid
position and rate data for the old point N. Our tasks include
advancing to the new point N+1, and printing out the results (not
necessarily in that order).
- We evaluate the aerodynamics functions at point N. These
functions take as input the positions and rates at point N, and
produce as outputs the forces and accelerations. That is, we
calculate the second derivatives as a function of the zeroth
derivatives and the first derivatives.
- We should print out the results. This is the appropriate place
to do so, because it is the first time we have full information about
point N, namely the positions, rates, and forces. This is what
should happen, but not what the current code actually does, as far as
I can tell.
- We integrate to find the rate at point N+1, shown in blue in
the figure, calculated from the rate at point N and the acceleration
at point N.
- We integrate to find the position at point N+1. This is
slightly tricky, because we could use the old rate (shown by the slope
of the red line) and/or the new rate (shown by the slope of the blue
line). In the example shown in figure 1, the old rate is
an overestimate of the average rate, whereas the new rate is an
underestimate of the average rate. The average rate is the average
over the interval from point N to point N+1, as shown by slope of
the dashed green line in the figure.
- We advance the time variable. This can be considered another
example of integrating the equations of motion, according to the rule
t = ∫dt. This may seem almost trivial, but we mustn’t forget
to do it. Similarly we advance the point-counter from N to N+1,
so that N+1 becomes the “current” point.
- At this point the current code prints out the results. This is
somewhat problematic, because we don’t have force or acceleration data
for the new current point (N+1). Those variables still have data from
point N hanging around.
Here are the proposed principles of operation for
wind tunnel mode. You can compare and contrast this with the
conventional integrator mode (item A). We start by
describing basic wind-tunnel mode. (For some possible
non-basic features see item E and
We run the script, including any property-setting directives.
In basic wind-tunnel mode, we assume the script sets all relevant
positions and rates for point N. See item C for more on this.
- We calculate forces, moments, and accelerations for point N,
by evaluating the aerodynamic functions, based on the current
positions and rates.
- We print results to the output file.
- We advance the time variable (t). Similarly we advance the
point-counter from N to N+1.
In wind tunnel mode, if any position or any rate is not
set by the script, it remains stuck at its previous value. Being
stuck may seem weird, especially if the rates are non-zero, but it
is not completely unphysical, for reasons discussed in
In wind tunnel mode, there is no requirement that
the new positions and rates be related to the old positions and rates
via any equation of motion. This is not as unphysical as it might
seem. For example, if we have unchanging positions and nonzero rates,
it might correspond to the flight path shown in
: Position and Rate Remaining Stuck
As a creeping feature, we could have a fancy
wind-tunnel mode where the script just sets the positions, and we
calculate rates by differentiation so that the rates are consistent
with the positions, and with the equations of motion. I’m not sure
this is desirable or even practical.
Alternatively, as a creeping feature, we could have a
fancy wind-tunnel mode where the script specifies the rates, and we
calculate the positions by integration, so that the positions are
consistent with the rates and with the equations of motion. I’m not
sure this is worth the trouble.
We would need to offer a choice of integration methods, just as the
existing code does in non-wind-tunnel mode.
It pays to be flexible about reference frames. Some things are
more natural in one reference frame, and some things are more natural
in another. JSBSim already does a lot of switching between reference
frames. This is as it should be, and always will be.
The natural reference frame for the user interface for
a wind tunnel is an earth-fixed frame such as ECEF. Physically, the
wind tunnel uses a jig to hold the aircraft in a given
attitude relative to the earth. Therefore the software needs to have
a mode that dictates attitude ... in the earth-fixed frame.
We want setting of each variable to be independent, and
to commute with the setting of other variables, in the earth-fixed
In the existing code, many crucial variables
cannot be set from a script. Implementing wind tunnel mode
will require making these things settable.
In the existing code, the fundamental representation of
velocities etc. uses a body-fixed reference frame. Other
representations are derived from this body-fixed representation,
and rarely (if ever) the other way around. This choice of frame
has the advantage that is natural from a pilot’s point of view.
One disadvantage is that it is not an inertial frame. Doing physics
in a non-inertial frame is tricky, but it can be done. In particular,
the equations of motion contain must contain correction terms for the
centrifugal field, for Coriolis effects, et cetera.
Another disadvantage is that, simply put, it is not the ECEF frame,
i.e. it is not the natural frame for the wind tunnel user interface,
as mentioned in item H.
JSBSim does in fact have code to implement the
leading-order centrifugal and Coriolis terms associated with the
rotation of the body frame of reference.
However, everyone should beware that only the leading-order terms are
implemented, and there are lots of other terms. Some of the
unimplemented terms are not very small compared to the implemented
For one thing, the familiar centrifugal and Coriolis terms only cover
the case of steady rotation around a fixed axis. If the rotation rate
is changing, or if the rotation axis is changing, all bets are off.
I reckon the existing code is good enough for ordinary aircraft and
for ground vehicles, but a stated goal of the JSBSim project is to be
able to handle spacecraft. I suspect that if you want to accurately
model a spacecraft or a high-precision inertial navigation system, the
equation of motion code would need major repairs.
I don’t want to make a big deal out of all this. I’m just saying that
there is a price to be paid whenever you choose to use a non-inertial
The existing null integrator (which the code calls the
"none" integrator) is an odd duck. There is, as far as I can tell, no
documentation as to what it is supposed to do, so we must
consider various hypotheses:
One hypothesis is that the null integrator is supposed to represent a
vehicle subjected to no forces, such as a freely floating space
capsule. Alas, the "none" integrator, as implemented in the existing
code, does not correctly represent this. It is implemented using zero
lines of code, which means that it leaves out the centrifugal and
Coriolis terms that the correct equation of motion must have (even in
the absence of applied forces).
Another hypothesis is that the null integrator might leave the
aircraft attitude frozen in some earth-fixed frame. This is wishful
thinking; it is not what happens. In particular, if the aircraft
attitude is changing (due to natural angular motion and/or due to
being set by the script) then the aircraft’s momentum vector will
magically change. That is, in the absence of forces, the vector’s
projection onto the body axes will remain constant, but the actual
physical momentum will change ... in violation of the most sacred
basic laws of physics.
Remember that the momentum vector has physical and
geometric reality, quite independent of its projection onto any set
of axes. See reference 1 for details on this.
This also means that if you use a script to set the aircraft velocity and
then set the attitude, you get a different result than if you did
things in the other order, in violation of the commutativity objective
expressed in item I.
You can optionally view non-commutativity as just an extreme version
of the previous problem: Setting the attitude corresponds to a
near-infinite rate of attitude change, and would require near-infinite
correction terms in the equation of motion. The "none" integrator
cannot handle any nonzero rate, let alone a near-infinite rate.
Also item F would require wind-tunnel mode to use non-null
To summarize: we have seen numerous reasons why wind-tunnel mode
cannot be implemented simply by selecting the null integrator.
2 Next Steps
Here’s how I see things going forward:
The most crucial change is to arrange that in the “propagate” step,
in wind tunnel mode, we use something other than the body frame.
Using the body frame is inconsistent with the goal of letting scripts
set the body attitude. An earth-fixed frame is the logical choice
(although almost any frame other than the body frame would be
This does not require a major rewrite. The changes affect only wind
tunnel mode; ordinary integrator mode is completely unaffected. The
code changes are confined to a couple of existing functions and the new
Basically I’m hoping to add a couple of lines in FGFDMExec.cpp, which
take effect only in wind tunnel mode, to convert the body frame
projections to ECEF projections before running the script, and to
convert ECEF to body frame after the dust settles.
There should also be some conditionals in FGPropagate.cpp to avoid
The printouts need to be rescheduled to the proper point in the
We also need to write the variable-setting functions. Each such
function should set both the body-frame projections and the
ECEF projections, not one or the other.
I reckon there should be a variable somewhere to specify whether we
are in wind tunnel mode or not. I think this should be a new,
separate variable, not entangled with the existing enumeration of
integrators (eIntegrateType), since as discussed in item F
there are situations where wind tunnel mode needs integrators.
“Introduction to Vectors”