Wingflexer: Difference between revisions

From FlightGear wiki
Jump to navigation Jump to search
m (cat)
m (→‎Physical model: explain basic oscillation)
(12 intermediate revisions by 3 users not shown)
Line 1: Line 1:
Wingflexer intro text
[[File:787 wing flex hard landing.gif|thumb|Wingflex after a touchdown at 9 ft/s on a 787-8.]]


This article describes how to add wingflex to your aircraft and how to obtain plausible parameters. The physical model is given at the end.
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 [[Howto:Implement_wing_flex|here]]. However, the actual model animation part is identical and will not be covered.


== How to add to your aircraft ==
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.
 
== Physical model ==
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.


== Obtain plausible parameters ==
These include the wing mass m_w, the wing stiffness K, the damping D, and a scaling factor z_fac.
To make our model produce a convinving dynamic behaviour, you will need to obtain estimates (and fine-tune) a number of 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.
1. Assume a dry wing mass m_dw. Research the wing fuel mass m_fuel.
Line 12: Line 59:
2. Obtain estimates of
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 deflection z_flight in level flight, e.g by comparing photos of the real aircraft on ground and in air,
* the wing's eigenfrequency, perhaps from videos of the wing's oscillation in turbulence,
* 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.
* the deflection with full and empty tanks while sitting on the ground.


3. Compute K to match in-flight deflection with full tanks:
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
  K = g * (m_ac / 2 - (fuel_frac * m_fuel)) / (z_in_flight / z_fac) / m_dw
where
where
m_ac  aircraft mass
g      9.81 m/s^2
z_fac  scaling factor for the deflection, start with 1


m_ac : aircraft mass
4. Compute the natural frequency of this system for full and empty wing tanks:
g    : 9.81 m/s^2
z_fac: scaling factor for the deflection, start with 1
 
4. Compute the eigenfrequency of this system for full and empty wing tanks:
  f_full  = sqrt(K * m_dw / (m_dw + fuel_frac * m_fuel)) / (2 pi)
  f_full  = sqrt(K * m_dw / (m_dw + fuel_frac * m_fuel)) / (2 pi)
  f_empty = sqrt(K) / (2 pi)
  f_empty = sqrt(K) / (2 pi)


Ideally we want our model to match the eigenfrequency, the deflection
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
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.
during a hard landing. Getting real-world data for the latter is difficult.


Here are some relations:
Here are some relations:
* a lower wing mass increases the eigenfrequency, and weakens the touchdown bounce
* A lower wing mass increases the natural frequency, and weakens the touchdown bounce
* a higher stiffness K reduces the deflection and increases the eigenfrequency
* 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
/sim/systems/wingflexer/
/sim/systems/wingflexer/params/
 
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
/sim/systems/wingflexer/params/z-fac
/sim/systems/wingflexer/sink-rate-fps
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 <tt>''[[$FG_ROOT]]/Aircraft/<your aircraft>/Systems/wingflexer-params.xml''</tt> which contains the parameters adjusted to your aircraft:
<syntaxhighlight lang="xml">
<?xml version="1.0" encoding="UTF-8"?>
 
<PropertyList>


== Physical model ==
<params>
  -->
  <m-wing-dry-kg type="double">12000</m-wing-dry-kg>
    g
  <K type="double">259</K>
      +-----+            +-----+
  <D type="double">12</D>
   <--- | m_w |---/\/\/\---|    |
  <fuel-frac type="double">0.375</fuel-frac>
      +-----+            +-----+
  <lift-node-lbs alias="/fdm/jsbsim/forces/fbz-aero-lbs"/>
Lift  wing    spring  fuselage
  <fuel-node-1-kg alias="/consumables/fuel/tank/level-kg"/>
force  mass
   <fuel-node-2-kg alias="/consumables/fuel/tank[1]/level-kg"/>
We integrate
  <fuel-node-3-kg type="double">0</fuel-node-3-kg>
      ..   k      d  .  0.5*F_L      ..
  <fuel-node-4-kg type="double">0</fuel-node-4-kg>
  0 = -z  + --- z + ---- z - ------- - g - z_f
</params>
          m_w     m_w      m_w
 
where
</PropertyList>
z :       deflection
</syntaxhighlight>
k :        wing stiffness
 
d :        damping
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_w = m_dw + fuel_frac * m_fuel
  m_fuel = fuel-node-1-kg + fuel-node-2-kg + fuel-node-3-kg + fuel-node-4-kg
            Total wing mass. Because the fuel is distributed over the wing, we use
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.
            a fraction of the fuel mass in the calculation.
 
  0.5*F_L :  lift force/2 (we look at one wing only)
In your aircraft's [[Aircraft-set.xml|*-set.xml file]], in <code><nowiki><systems></nowiki></code> section, load the parameters and the wingflexer module:
..
<syntaxhighlight lang="xml">
z_f :      acceleration of the frame of reference (fuselage)
<systems>
and write the deflection (z + z_ofs) in meters to /sim/model/wing-flex/z-m.
  <wingflexer include="Systems/wingflexer-params.xml"/>
The offset z_ofs is calculated automatically and ensures that the dry wing
  <property-rule n="100">
(which still has a non-zero mass) creates neutral deflection.
     <name>wing flexer property rule</name>
    <path>Aircraft/Generic/wingflexer.xml</path>
  </property-rule>
</systems>
</syntaxhighlight>
 
The wingflexer writes the deflection to <code>/sim/systems/wingflexer/z-m</code>.
Finally, your model rotate animation has to pick it up and multiply it by z_fac:
<syntaxhighlight lang="xml">
<animation>
  <type>rotate</type>
  <property>sim/systems/wingflexer/z-m</property>
  <factor>10</factor>
  <!-- ... -->
</animation>
</syntaxhighlight>
 
If your aircraft uses JSBSim, you're done now. YASim requires an extra step, described next.
 
== Yasim ==
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.
 
== Implementation details ==
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.
 
== TODO ==
* 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?)
 
== Related content ==
=== Wiki articles ===
* [[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.
 
=== Forum topics ===
* [http://forum.flightgear.org/viewtopic.php?f=30&t=24699 Wing flex -- spring/damper Nasal module] – Development topic


Discretisation by first order finite differences:
=== Source code ===
z_0 - 2 z_1 + z_2    k        d  (z_0 - z_1)  1/2 F_L      ..
* {{fgdata file|Aircraft/Generic/wingflexer.xml}} – [[Autopilot configuration reference|Autopilot/property rule]] part of the implementation
----------------- + --- z_1 + --- ----------- - ------- - g - z_f = 0
* {{fgdata file|Aircraft/Generic/wingflexer.nas}} – Nasal part of the implementation
      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


[[Category:FlightGear feature]]
[[Category:FlightGear feature]]

Revision as of 23:26, 9 March 2017

Wingflex after a touchdown at 9 ft/s on a 787-8.

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.

Physical model

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

where

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

/sim/systems/wingflexer/
/sim/systems/wingflexer/params/

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

/sim/systems/wingflexer/params/z-fac
/sim/systems/wingflexer/sink-rate-fps

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[1]/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 /sim/systems/wingflexer/z-m. 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.

Yasim

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.

Implementation details

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.

TODO

  • 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?)

Related content

Wiki articles

  • 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.

Forum topics

Source code