Wingflexer: Difference between revisions

From FlightGear wiki
Jump to navigation Jump to search
(final version)
Line 176: Line 176:
=== Autopilot/Property rules implementation ===
=== Autopilot/Property rules implementation ===
Code lives in Aircraft/Generic/wingflexer.xml
Code lives in Aircraft/Generic/wingflexer.xml
The ODE x" + ax' + bx + c = 0 is integrated by DampedOsciFilterImplementation in FG/src/autopilot/digitalfilter.cxx.
The ODE x" + ax' + bx + c = 0 is integrated by DampedOsciFilterImplementation in FG/src/autopilot/digitalfilter.cxx.



Revision as of 00:03, 11 March 2015

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 in a turn, during turbulence, or on touchdown. This article describes the Wingflexer module, which aims at animating the 3-D model of a wing in a somewhat realistic fashion. 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 (the 787) below.

Introduced in FG 3.5, there are two implementations available. One uses autopilot/property rules, is therefore very optimized and should be your first choice. The other 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 maths 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

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. 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 convinving 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/params/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 $YourAircraft/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. This is done by

 m_fuel = fuel-frac * (fuel-node-1 + fuel-node-2 + fuel-node-3 + fuel-node-4).

Include the averaging weight 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 $yourAircraft-set.xml, 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

Autopilot/Property rules implementation

Code lives in Aircraft/Generic/wingflexer.xml

The ODE x" + ax' + bx + c = 0 is integrated by DampedOsciFilterImplementation in FG/src/autopilot/digitalfilter.cxx.

Nasal implementation

Code lives in Aircraft/Generic/wingflexer.nas

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