The Wingflexer module aims at animating the 3-D model of a wing in a somewhat realistic fashion. Wings of large aspect ratio tend to behave similar to a spring. They bend under load and oscillate for a while when the load changes, for example when entering a turn, during turbulence, or on touchdown. The method used is a significant improvement over what has been described here. However, the actual model animation part is identical and will not be covered.
Including this in your aircraft is fairly straightforward, but obtaining plausible parameters can require some research and trial-and-error. We will give an example (for the 787) below.
Introduced in FG 3.5, there are two implementations available. The first, which this article is focused on, uses autopilot/property rules. It is therefore very optimized and should be your first choice. The second implementation uses Nasal. It is a bit more flexible in the sense that it could also be applied to AI aircraft.
This section describes the physical model. You don't need to fully understand the math here to be able to use Wingflexer, but you should understand the parameters involved -- you will need to adapt them to your aircraft.
We use a simple spring-mass-damper system sketched below to model a flexible wing:
--> |<---- z --->| g +-----+ +-----+ <--- | m_w |---/\/\/\---| | +-----+ +-----+ Lift wing spring fuselage force mass
Lift is trying to pull the wing upwards (to the left in the sketch), which is countered by gravity acting on the wing mass. The wing's inertia, in combination with its stiffness and damping characteristics, will create damped oscillations after an initial deflection.
Mathematically speaking, the wing's motion, measured by the deflection z(t), is governed by the following parameters:
k wing stiffness d damping m_w = m_dw + fuel_frac * m_fuel Total wing mass = dry wing mass + fuel mass. Because the fuel is distributed over the wing, we use a fraction of the fuel mass in the calculation. 0.5*F_L lift force/2 (we look at one wing only) .. z_f acceleration of the frame of reference (fuselage)
We integrate the equation of motion
.. k d . 0.5*F_L .. 0 = -z + --- z + ---- z - ------- - g - z_f m_w m_w m_w
and write the deflection (z + z_ofs) in meters to /sim/systems/wingflexer/z-m. The offset z_ofs is calculated automatically and ensures that the dry wing (which still has a non-zero mass) creates a neutral deflection.
Discretisation by first order finite differences leads to
z_0 - 2 z_1 + z_2 k d (z_0 - z_1) 1/2 F_L .. ----------------- + --- z_1 + --- ----------- - ------- - g - z_f = 0 dt^2 m_w m_w dt m_w
It is convenient to divide k and d by a (constant) reference mass:
K = k / m_dw D = d / m_dw
Obtaining plausible parameters
To make our model produce a convincing dynamic behaviour, you will need to obtain estimates and fine-tune the parameters.
These include the wing mass m_w, the wing stiffness K, the damping D, and a scaling factor z_fac. There's a python script wingflexer.py which assists you in fine-tuning. It will quickly simulate the dynamics of the model with your parameters. So how to estimate the parameters?
1. Assume a dry wing mass m_dw. Research the wing fuel mass m_fuel.
2. Obtain estimates of
- the deflection z_flight in level flight, e.g by comparing photos of the real aircraft on ground and in air,
- the wing's natural frequency, perhaps from videos of the wing's oscillation in turbulence,
- the deflection with full and empty tanks while sitting on the ground.
3. Compute K to match in-flight deflection with full tanks:
K = g * (m_ac / 2 - (fuel_frac * m_fuel)) / (z_in_flight / z_fac) / m_dw
m_ac aircraft mass g 9.81 m/s^2 z_fac scaling factor for the deflection, start with 1
4. Compute the natural frequency of this system for full and empty wing tanks:
f_full = sqrt(K * m_dw / (m_dw + fuel_frac * m_fuel)) / (2 pi) f_empty = sqrt(K) / (2 pi)
Ideally we want our model to match the wing's natural frequency, the wing's deflection while sitting on the ground with full or empty tanks, and the deflection (bounce) during a hard landing. Getting real-world data for the latter is difficult.
Here are some relations:
- A lower wing mass increases the natural frequency, and weakens the touchdown bounce
- A higher stiffness K reduces the deflection and increases the natural frequency
Enable developer options
By default, Wingflexer and the user-tunable parameters live in
There are two properties disabled by default which are only useful when you're tuning the parameters. To enable them, uncomment the developer section in Aircraft/Generic/wingflexer.xml. This will activate
Z-fac simply scales the output. Once you're happy with the results, include this factor in the animation. Sink-rate-fps allows you to simulate a touchdown at given vertical speed.
It will become clear in the next section why these two settings are useful.
An example: the 787
The 787 is known for its very flexible wings; the deflection in unaccelerated flight is quoted as z = 3 m. One wing tank of FG's 787-8 holds 23,000 kg of fuel. Because the fuel is distributed over the wing, we use a fraction of the fuel mass in the calculation: fuel_frac = 0.75. For the same reason we don't use the true wing mass, but rather something that makes our model look plausible.
So assuming a wing mass of 12000 kg, we get K=25.9 and f_empty = 0.5 Hz. That frequency might be a bit low, videos of a 777 wing in turbulence show about 2-3 Hz. (I didn't research 787 videos).
To increase it, we could either reduce m_dw or increase K. A lower m_dw results in a rather weak bounce on touchdown which might look odd. A higher K reduces the deflection z_flight, but we can simply scale the animation to account for that. We'll multiply the deflection z by a factor z_fac to get an angle for the <rotate> animation later on anyway. So repeat 3. and 4. using e.g. z_fac = 10. Now K = 259 and f_empty=2.6 Hz. While our model spring now only deflects to 0.3 m instead of 3 m, the animation scale factor will make sure the wing bends to 3 m. This way, we can match both natural frequency and observed deflection, and still get a realistic bounce on touch down. Finally, adjust D such that an impulse is damped out after about one or two oscillations; D = 12 seems to work OK in our example.
It's difficult to get real-world data on the deflection during touchdown. Touchdown at more than 10 ft/s is considered a hard landing and could result in some significant wing bending. There's a video of a hard landing of an A346 (http://avherald.com/h?article=471e70e9), showing the wings bend perhaps 1 m.
To assist you in tuning parameters for the touchdown bounce you can initialize your wing mass with a (touchdown) vertical speed via /sim/systems/wingflexer/sink-rate-fps, and then observe the deflection and oscillation. This avoids you having to fly too many touch-and-go's while developing ;)
Finally, our model outputs the deflection in meters, but the <rotate> animation expects an angle. It is up to you convert appropriately, depending on your wing span and number of segments in the animation. Also don't forget to include z_fac.
How to add to your aircraft
Create a file $FG_ROOT/Aircraft/<your aircraft>/Systems/wingflexer-params.xml which contains the parameters adjusted to your aircraft:
<?xml version="1.0" encoding="UTF-8"?> <PropertyList> <params> <m-wing-dry-kg type="double">12000</m-wing-dry-kg> <K type="double">259</K> <D type="double">12</D> <fuel-frac type="double">0.375</fuel-frac> <lift-node-lbs alias="/fdm/jsbsim/forces/fbz-aero-lbs"/> <fuel-node-1-kg alias="/consumables/fuel/tank/level-kg"/> <fuel-node-2-kg alias="/consumables/fuel/tank/level-kg"/> <fuel-node-3-kg type="double">0</fuel-node-3-kg> <fuel-node-4-kg type="double">0</fuel-node-4-kg> </params> </PropertyList>
Also adjust the property node aliases for the wing fuel tanks. Wingflexer supports up to four tanks in total. Since we're currently only solving one equation and hence get only one deflection which is used for both wings, we have to average the wing mass. Internally, m_fuel is simply the sum of all given fuel nodes,
m_fuel = fuel-node-1-kg + fuel-node-2-kg + fuel-node-3-kg + fuel-node-4-kg
so you must include the weighting factor in fuel-frac (e.g. 1/2 if you provide 2 fuel nodes). If you have more than 4 wing tanks in total, use another property rule to compute the average.
In your aircraft's *-set.xml file, in
<systems> section, load the parameters and the wingflexer module:
<systems> <wingflexer include="Systems/wingflexer-params.xml"/> <property-rule n="100"> <name>wing flexer property rule</name> <path>Aircraft/Generic/wingflexer.xml</path> </property-rule> </systems>
The wingflexer writes the deflection to
Finally, your model rotate animation has to pick it up and multiply it by z_fac:
<animation> <type>rotate</type> <property>sim/systems/wingflexer/z-m</property> <factor>10</factor> <!-- ... --> </animation>
If your aircraft uses JSBSim, you're done now. YASim requires an extra step, described next.
Older Yasim does not write the lift to the property tree. But you can create a helper function which computes the lift as
lift_force_lbs = aircraft_weight_lbs * load_factor - total_weight_on_wheels_lbs
and point the <lift-node-lbs> alias in wingflexer-params.xml to it.
More recent Yasim does write the force, but it needs its sign inverted as wingflexer expects z is positive downwards, and converted to LBF.
In Nasal that would be something like:
As an expression:
<expression> <product> <property>fdm/yasim/forces/f-z-lift</property> <value>-0.224809</value><!-- invert and convert from Newton to LBF --> </product> </expression>
If the pilot has low framerate, wingflexer can in some configurations become unstable and do uncontrollable oscillations. If you have that issue it can help to load wingflexer as an autopilot module instead of property-rule. This will make it run at FDM rate instead of framerate.
The autopilot/Property rules implementation lives in Aircraft/Generic/wingflexer.xml
The ODE x" + ax' + bx + c = 0 is integrated by DampedOsciFilterImplementation in FG/src/autopilot/digitalfilter.cxx.
- write Yasim helper
- input for fuselage acceleration should rather be acceleration at CG instead of the pilot's location -- is there a property?
- add wingflexer.py (to where?)
- Howto:Implement wing flex – An older way to add wing flex, though the wingflexer need to be animated in a similar way, but based on /sim/model/wing-flex/z-m.
- Wingflex Shader - A shader that can animate the wingflex.
- Wing flex -- spring/damper Nasal module – Development topic