JSBSim Flight Dynamics Model 1.3.0 (09 Apr 2026)
An Open Source Flight Dynamics and Control Software Library in C++
Loading...
Searching...
No Matches
FGFunction Class Reference

Detailed Description

Represents a mathematical function.

The FGFunction class is a powerful and versatile resource that allows algebraic functions to be defined in a JSBSim configuration file. It is similar in concept to MathML (Mathematical Markup Language, www.w3.org/Math/), but simpler and more terse. A function definition consists of an operation, a value, a table, or a property (which evaluates to a value). The currently supported operations are:

  • sum (takes n args)
  • difference (takes n args)
  • product (takes n args)
  • quotient (takes 2 args)
  • pow (takes 2 args)
  • sqrt (takes one argument)
  • toradians (takes one argument)
  • todegrees (takes one argument)
  • exp (takes 2 args)
  • log2 (takes 1 arg)
  • ln (takes 1 arg)
  • log10 (takes 1 arg)
  • abs (takes 1 arg)
  • sin (takes 1 arg)
  • cos (takes 1 arg)
  • tan (takes 1 arg)
  • asin (takes 1 arg)
  • acos (takes 1 arg)
  • atan (takes 1 arg)
  • atan2 (takes 2 args)
  • min (takes n args)
  • max (takes n args)
  • avg (takes n args)
  • fraction
  • mod
  • floor (takes 1 arg)
  • ceil (takes 1 arg)
  • fmod (takes 2 args)
  • roundmultiple (takes 2 args)
  • lt (less than, takes 2 args)
  • le (less equal, takes 2 args)
  • gt (greater than, takes 2 args)
  • ge (greater than, takes 2 args)
  • eq (equal, takes 2 args)
  • nq (not equal, takes 2 args)
  • and (takes n args)
  • or (takes n args)
  • not (takes 1 args)
  • if-then (takes 2-3 args)
  • switch (takes 2 or more args)
  • random (Gaussian distribution random number)
  • urandom (Uniform random number between -1 and +1)
  • pi
  • integer
  • interpolate 1-dimensional (takes a minimum of five arguments, odd number)

An operation is defined in the configuration file as in the following example:

<sum>
<value> 3.14159 </value>
<property> velocities/qbar </property>
<product>
<value> 0.125 </value>
<property> metrics/wingarea </property>
</product>
</sum>

A full function definition, such as is used in the aerodynamics section of a configuration file includes the function element, and other elements. It should be noted that there can be only one non-optional (non-documentation) element - that is, one operation element or one table element - in the top-level function definition. Multiple value and/or property elements cannot be immediate child members of the function element. Almost always, the first operation within the function element will be a product or sum. For example:

<function name="aero/moment/Clr">
<description>Roll moment due to yaw rate</description>
<product>
<property>aero/qbar-area</property>
<property>metrics/bw-ft</property>
<property>aero/bi2vel</property>
<property>velocities/r-aero-rad_sec</property>
<table>
<independentVar>aero/alpha-rad</independentVar>
<tableData>
0.000 0.08
0.094 0.19
</tableData>
</table>
</product>
</function>

The "lowest level" in a function is always a value or a property, which cannot itself contain another element. As shown, operations can contain values, properties, tables, or other operations. In the first above example, the sum element contains all three. What is evaluated is written algebraically as:

3.14159 + qbar + (0.125 * wingarea)

Some operations can take only a single argument. That argument, however, can be an operation (such as sum) which can contain other items. The point to keep in mind is that it evaluates to a single value - which is just what the trigonometric functions require (except atan2, which takes two arguments).

Specific Function Definitions

Note: In the definitions below, a "property" refers to a single property specified within either the <property></property> tag or the shortcut tag, <p></p>. The keyword "value" refers to a single numeric value specified either within the <value></value> tag or the shortcut <v></v> tag. The keyword "table" refers to a single table specified either within the <table></table> tag or the shortcut <t></t> tag. The plural form of any of the three words refers to one or more instances of a property, value, or table.

  • sum, sums the values of all immediate child elements:
    <sum>
    {properties, values, tables, or other function elements}
    </sum>
    Example: Mach + 0.01
    <sum>
    <p> velocities/mach </p>
    <v> 0.01 </v>
    </sum>
  • difference, subtracts the values of all immediate child elements from the value of the first child element:
    <difference>
    {properties, values, tables, or other function elements}
    </difference>
    Example: Mach - 0.01
    <difference>
    <p> velocities/mach </p>
    <v> 0.01 </v>
    </difference>
  • product multiplies together the values of all immediate child elements:
    <product>
    {properties, values, tables, or other function elements}
    </product>
    Example: qbar*S*beta*CY_beta
    <product>
    <property> aero/qbar-psf </property>
    <property> metrics/Sw-sqft </property>
    <property> aero/beta-rad </property>
    <property> aero/coefficient/CY_beta </property>
    </product>
  • quotient, divides the value of the first immediate child element by the second immediate child element:
    <quotient>
    {property, value, table, or other function element}
    {property, value, table, or other function element}
    </quotient>
    Example: (2*GM)/R
    <quotient>
    <product>
    <v> 2.0 </v>
    <p> guidance/executive/gm </p>
    </product>
    <p> position/radius-to-vehicle-ft </p>
    </quotient>
  • pow, raises the value of the first immediate child element to the power of the value of the second immediate child element:
    <pow>
    {property, value, table, or other function element}
    {property, value, table, or other function element}
    </pow>
    Example: Mach^2
    <pow>
    <p> velocities/mach </p>
    <v> 2.0 </v>
    </pow>
  • sqrt, takes the square root of the value of the immediate child element:
    <sqrt>
    {property, value, table, or other function element}
    </sqrt>
    Example: square root of 25
    <sqrt> <v> 25.0 </v> </sqrt>
  • toradians, converts a presumed argument in degrees to radians by multiplying the value of the immediate child element by pi/180:
    <toradians>
    {property, value, table, or other function element}
    </toradians>
    Example: convert 45 degrees to radians
    <toradians> <v> 45 </v> </toradians>
  • todegrees, converts a presumed argument in radians to degrees by multiplying the value of the immediate child element by 180/pi:
    <todegrees>
    {property, value, table, or other function element}
    </todegrees>
    Example: convert 0.5*pi radians to degrees
    <todegrees>
    <product> <v> 0.5 </v> <pi/> </product>
    </todegrees>
  • exp, raises "e" to the power of the immediate child element:
    <exp>
    {property, value, table, or other function element}
    </exp>
    Example: raise "e" to the 1.5 power, e^1.5
    <exp> <v> 1.5 </v> </exp>
  • log2, calculates the log base 2 value of the immediate child element:
    <log2>
    {property, value, table, or other function element}
    </log2>
    Example:
    <log2> <v> 128 </v> </log2>
  • ln, calculates the natural logarithm of the value of the immediate child element:
    <ln>
    {property, value, table, or other function element}
    </ln>
    Example: ln(128)
    <ln> <v> 200 </v> </ln>
  • log10, calculates the base 10 logarithm of the value of the immediate child element
    <log10>
    {property, value, table, or other function element}
    </log10>
    Example log(Mach)
    <log10> <p> velocities/mach </p> </log10>
  • abs calculates the absolute value of the immediate child element
    <abs>
    {property, value, table, or other function element}
    </abs>
    Example:
    <abs> <p> flight-path/gamma-rad </p> </abs>
  • sin, calculates the sine of the value of the immediate child element (the argument is expected to be in radians)
    <sin>
    {property, value, table, or other function element}
    </sin>
    Example:
    <sin> <toradians> <p> fcs/heading-true-degrees </p> </toradians> </sin>
  • cos, calculates the cosine of the value of the immediate child element (the argument is expected to be in radians)
    <cos>
    {property, value, table, or other function element}
    </cos>
    Example:
    <cos> <toradians> <p> fcs/heading-true-degrees </p> </toradians> </cos>
  • tan, calculates the tangent of the value of the immediate child element (the argument is expected to be in radians)
    <tan>
    {property, value, table, or other function element}
    </tan>
    Example:
    <tan> <toradians> <p> fcs/heading-true-degrees </p> </toradians> </tan>
  • asin, calculates the arcsine (inverse sine) of the value of the immediate child element. The value provided should be in the range from -1 to +1. The value returned will be expressed in radians, and will be in the range from -pi/2 to +pi/2.
    <asin>
    {property, value, table, or other function element}
    </asin>
    Example:
    <asin> <v> 0.5 </v> </asin>
  • acos, calculates the arccosine (inverse cosine) of the value of the immediate child element. The value provided should be in the range from -1 to +1. The value returned will be expressed in radians, and will be in the range from 0 to pi.
    <acos>
    {property, value, table, or other function element}
    </acos>
    Example:
    <acos> <v> 0.5 </v> </acos>
  • atan, calculates the inverse tangent of the value of the immediate child element. The value returned will be expressed in radians, and will be in the range from -pi/2 to +pi/2.
    <atan>
    {property, value, table, or other function element}
    </atan>
    Example:
    <atan> <v> 0.5 </v> </atan>
  • atan2 calculates the inverse tangent of the value of the immediate child elements, Y/X (in that order). It even works for X values near zero. The value returned will be expressed in radians, and in the range -pi to +pi.
    <atan2>
    {property, value, table, or other function element} {property, value, table, or other function element}
    </atan2>
    Example: inverse tangent of 0.5/0.25, evaluates to: 1.107 radians
    <atan2> <v> 0.5 </<v> <v> 0.25 </v> </atan2>
  • min returns the smallest value from all the immediate child elements
    <min>
    {properties, values, tables, or other function elements}
    </min>
    Example: returns the lesser of velocity and 2500
    <min>
    <p> velocities/eci-velocity-mag-fps </p>
    <v> 2500.0 </v>
    </min>
  • max returns the largest value from all the immediate child elements
    <max>
    {properties, values, tables, or other function elements}
    </max>
    Example: returns the greater of velocity and 15000
    <max>
    <p> velocities/eci-velocity-mag-fps </p>
    <v> 15000.0 </v>
    </max>
  • avg returns the average value of all the immediate child elements
    <avg>
    {properties, values, tables, or other function elements}
    </avg>
    Example: returns the average of the four numbers below, evaluates to 0.50.
    <avg>
    <v> 0.25 </v>
    <v> 0.50 </v>
    <v> 0.75 </v>
    <v> 0.50 </v>
    </avg>
  • fraction, returns the fractional part of the value of the immediate child element
    <fraction>
    {property, value, table, or other function element}
    </fraction>
    Example: returns the fractional part of pi - or, roughly, 0.1415926...
    <fraction> <pi/> </fraction>
  • integer, returns the integer portion of the value of the immediate child element
    <integer>
    {property, value, table, or other function element}
    </integer>
  • mod returns the remainder from the integer division of the value of the first immediate child element by the second immediate child element, X/Y (X modulo Y). The value returned is the value X-I*Y, for the largest integer I such that if Y is nonzero, the result has the same sign as X and magnitude less than the magnitude of Y. For instance, the expression "5 mod 2" would evaluate to 1 because 5 divided by 2 leaves a quotient of 2 and a remainder of 1, while "9 mod 3" would evaluate to 0 because the division of 9 by 3 has a quotient of 3 and leaves a remainder of 0.
    <mod>
    {property, value, table, or other function element}
    {property, value, table, or other function element}
    </mod>
    Example: 5 mod 2, evaluates to 1
    <mod> <v> 5 </v> <v> 2 </v> </mod>
  • floor returns the largest integral value that is not greater than X.
    <floor>
    {property, value, table, or other function element}
    </floor>
    Examples: floor(2.3) evaluates to 2.0 while floor(-2.3) evaluates to -3.0
  • ceil returns the smallest integral value that is not less than X.
    <ceil>
    {property, value, table, or other function element}
    </ceil>
    Examples: ceil(2.3) evaluates to 3.0 while ceil(-2.3) evaluates to -2.0
  • fmod returns the floating-point remainder of X/Y (rounded towards zero)
    <fmod>
    {property, value, table, or other function element}
    {property, value, table, or other function element}
    </fmod>
    Example: fmod(18.5, 4.2) evaluates to 1.7
  • roundmultiple returns the floating-point rounding of X to a multiple of M. round(X/M) * M
    <roundmultiple>
    {property, value, table, or other function element}
    {property, value, table, or other function element}
    </roundmultiple>
    Example: roundmultiple(93.43, 5.0) evaluates to 95.0
  • lt returns a 1 if the value of the first immediate child element is less than the value of the second immediate child element, returns 0 otherwise
    <lt>
    {property, value, table, or other function element}
    {property, value, table, or other function element}
    </lt>
    Example: returns 1 if thrust is less than 10,000, returns 0 otherwise
    <lt>
    <p> propulsion/engine[2]/thrust-lbs </p>
    <v> 10000.0 </v>
    </lt>
  • le, returns a 1 if the value of the first immediate child element is less than or equal to the value of the second immediate child element, returns 0 otherwise
    <le>
    {property, value, table, or other function element}
    {property, value, table, or other function element}
    </le>
    Example: returns 1 if thrust is less than or equal to 10,000, returns 0 otherwise
    <le>
    <p> propulsion/engine[2]/thrust-lbs </p>
    <v> 10000.0 </v>
    </le>
  • gt returns a 1 if the value of the first immediate child element is greater than the value of the second immediate child element, returns 0 otherwise
    <gt>
    {property, value, table, or other function element}
    {property, value, table, or other function element}
    </gt>
    Example: returns 1 if thrust is greater than 10,000, returns 0 otherwise
    <gt>
    <p> propulsion/engine[2]/thrust-lbs </p>
    <v> 10000.0 </v>
    </gt>
  • ge, returns a 1 if the value of the first immediate child element is greater than or equal to the value of the second immediate child element, returns 0 otherwise
    <ge>
    {property, value, table, or other function element}
    {property, value, table, or other function element}
    </ge>
    Example: returns 1 if thrust is greater than or equal to 10,000, returns 0
    otherwise
    <ge>
    <p> propulsion/engine[2]/thrust-lbs </p>
    <v> 10000.0 </v>
    </ge>
  • eq returns a 1 if the value of the first immediate child element is equal to the second immediate child element, returns 0 otherwise
    <eq>
    {property, value, table, or other function element}
    {property, value, table, or other function element}
    </eq>
    Example: returns 1 if thrust is equal to 10,000, returns 0 otherwise
    <eq>
    <p> propulsion/engine[2]/thrust-lbs </p>
    <v> 10000.0 </v>
    </eq>
  • nq returns a 1 if the value of the first immediate child element is not equal to the value of the second immediate child element, returns 0 otherwise
    <nq>
    {property, value, table, or other function element}
    {property, value, table, or other function element}
    </nq>
    Example: returns 1 if thrust is not 0, returns 0 otherwise
    <nq>
    <p> propulsion/engine[2]/thrust-lbs </p>
    <v> 0.0 </v>
    </nq>
  • and returns a 1 if the values of the immediate child elements are all 1, returns 0 otherwise. Values provided are expected to be either 1 or 0 within machine precision.
    <and>
    {properties, values, tables, or other function elements}
    </and>
    Example: returns 1 if the specified flags are all 1
    <and>
    <p> guidance/first-stage-flight-flag </p>
    <p> control/engines-running-flag </p>
    </and>
  • or returns a 1 if the values of any of the immediate child elements 1, returns 0 otherwise. Values provided are expected to be either 1 or 0 within machine precision.
    <or>
    {properties, values, tables, or other function elements}
    </or>
    Example: returns 1 if any of the specified flags are 1
    <or>
    <p> guidance/first-stage-flight-flag </p>
    <p> control/engines-running-flag </p>
    </or>
  • not, returns the inverse of the value of the supplied immediate child element (e.g., returns 1 if supplied a 0)
    <not>
    {property, value, table, or other function element}
    </not>
    Example: returns 0 if the value of the supplied flag is 1
    <not> <p> guidance/first-stage-flight-flag </p> </not>
  • ifthen if the value of the first immediate child element is 1, then the value of the second immediate child element is returned, otherwise the value of the third child element is returned
    <ifthen>
    {property, value, table, or other function element}
    {property, value, table, or other function element}
    {property, value, table, or other function element}
    </ifthen>
    Example: if flight-mode is greater than 2, then a value of 0.00 is
    returned, otherwise the value of the property control/pitch-lag is
    returned.
    <ifthen>
    <gt> <p> executive/flight-mode </p> <v> 2 </v> </gt>
    <v> 0.00 </v>
    <p> control/pitch-lag </p>
    </ifthen>
  • switch uses the integer value of the first immediate child element as an index to select one of the subsequent immediate child elements to return the value of
    <switch>
    {property, value, table, or other function element}
    {property, value, table, or other function element}
    {property, value, table, or other function element}
    ...
    </switch>
    Example: if flight-mode is 2, the switch function returns 0.50
    <switch>
    <p> executive/flight-mode </p>
    <v> 0.25 </v>
    <v> 0.50 </v>
    <v> 0.75 </v>
    <v> 1.00 </v>
    </switch>
  • random Returns a normal distributed random number. The function, without parameters, returns a normal distributed random value with a distribution defined by the parameters mean = 0.0 and standard deviation (stddev) = 1.0 The Mean of the distribution (its expected value, μ). Which coincides with the location of its peak. Standard deviation (σ): The square root of variance, representing the dispersion of values from the distribution mean. This shall be a positive value (σ>0).
    <random/>
    <random seed="1234"/>
    <random seed="time_now"/>
    <random seed="time_now" mean="0.0" stddev="1.0"/>
  • urandom Returns a uniformly distributed random number. The function, without parameters, returns a random value between the minimum value -1.0 and the maximum value of 1.0 The two maximum and minimum values can be modified using the lower and upper parameters.
    <urandom/>
    <random seed="1234"/>
    <random seed="time_now"/>
    <random seed="time_now" lower="-1.0" upper="1.0"/>
  • pi Takes no argument and returns the value of Pi
    <pi/>
  • interpolate1d returns the result from a 1-dimensional interpolation of the supplied values, with the value of the first immediate child element representing the lookup value into the table, and the following pairs of values representing the independent and dependent values. The first provided child element is expected to be a property. The interpolation does not extrapolate, but holds the highest value if the provided lookup value goes outside of the provided range.
    <interpolate1d>
    {property, value, table, or other function element}
    {property, value, table, or other function element} {property, value, table, or other function element}
    ...
    </interpolate1d>
    Example: If mach is 0.4, the interpolation will return 0.375. If mach is
    1.5, the interpolation will return 0.60.
    <interpolate1d>
    <p> velocities/mach </p>
    <v> 0.00 </v> <v> 0.25 </v>
    <v> 0.80 </v> <v> 0.50 </v>
    <v> 0.90 </v> <v> 0.60 </v>
    </interpolate1d>
    Author
    Jon Berndt

Definition at line 764 of file FGFunction.h.

#include <FGFunction.h>

+ Inheritance diagram for FGFunction:
+ Collaboration diagram for FGFunction:

Public Types

enum class  OddEven { Either , Odd , Even }
 
- Public Types inherited from FGJSBBase
enum  { eL = 1 , eM , eN }
 Moments L, M, N. More...
 
enum  { eP = 1 , eQ , eR }
 Rates P, Q, R. More...
 
enum  { eU = 1 , eV , eW }
 Velocities U, V, W. More...
 
enum  { eX = 1 , eY , eZ }
 Positions X, Y, Z. More...
 
enum  { ePhi = 1 , eTht , ePsi }
 Euler angles Phi, Theta, Psi. More...
 
enum  { eDrag = 1 , eSide , eLift }
 Stability axis forces, Drag, Side force, Lift. More...
 
enum  { eRoll = 1 , ePitch , eYaw }
 Local frame orientation Roll, Pitch, Yaw. More...
 
enum  { eNorth = 1 , eEast , eDown }
 Local frame position North, East, Down. More...
 
enum  { eLat = 1 , eLong , eRad }
 Locations Radius, Latitude, Longitude. More...
 
enum  {
  inNone = 0 , inDegrees , inRadians , inMeters ,
  inFeet
}
 Conversion specifiers. More...
 

Public Member Functions

 FGFunction ()
 Default constructor.
 
 FGFunction (FGFDMExec *fdmex, Element *element, const std::string &prefix="", FGPropertyValue *var=0L)
 Constructor.
 
 FGFunction (std::shared_ptr< FGPropertyManager > pm)
 
 ~FGFunction (void) override
 Destructor Make sure the function is untied before destruction.
 
void cacheValue (bool shouldCache)
 Specifies whether to cache the value of the function, so it is calculated only once per frame.
 
std::string GetName (void) const override
 Retrieves the name of the function.
 
double GetValue (void) const override
 Retrieves the value of the function object.
 
std::string GetValueAsString (void) const
 The value that the function evaluates to, as a string.
 
bool IsConstant (void) const override
 Does the function always return the same result (i.e.
 
- Public Member Functions inherited from FGParameter
double getDoubleValue (void) const
 
- Public Member Functions inherited from FGJSBBase
 FGJSBBase ()
 Constructor for FGJSBBase.
 
virtual ~FGJSBBase ()
 Destructor for FGJSBBase.
 
void disableHighLighting (void)
 Disables highlighting in the console output.
 

Protected Member Functions

virtual void bind (Element *, const std::string &)
 
void CheckMaxArguments (Element *el, unsigned int _max)
 
void CheckMinArguments (Element *el, unsigned int _min)
 
void CheckOddOrEvenArguments (Element *el, OddEven odd_even)
 
std::string CreateOutputNode (Element *el, const std::string &Prefix)
 
void Load (Element *element, FGPropertyValue *var, FGFDMExec *fdmex, const std::string &prefix="")
 

Protected Attributes

bool cached
 
double cachedValue
 
std::vector< FGParameter_ptr > Parameters
 
SGPropertyNode_ptr pNode
 
std::shared_ptr< FGPropertyManager > PropertyManager
 

Additional Inherited Members

- Static Public Member Functions inherited from FGJSBBase
static const std::string & GetVersion (void)
 Returns the version number of JSBSim.
 
static constexpr double KelvinToFahrenheit (double kelvin)
 Converts from degrees Kelvin to degrees Fahrenheit.
 
static constexpr double CelsiusToRankine (double celsius)
 Converts from degrees Celsius to degrees Rankine.
 
static constexpr double RankineToCelsius (double rankine)
 Converts from degrees Rankine to degrees Celsius.
 
static constexpr double KelvinToRankine (double kelvin)
 Converts from degrees Kelvin to degrees Rankine.
 
static constexpr double RankineToKelvin (double rankine)
 Converts from degrees Rankine to degrees Kelvin.
 
static constexpr double FahrenheitToCelsius (double fahrenheit)
 Converts from degrees Fahrenheit to degrees Celsius.
 
static constexpr double CelsiusToFahrenheit (double celsius)
 Converts from degrees Celsius to degrees Fahrenheit.
 
static constexpr double CelsiusToKelvin (double celsius)
 Converts from degrees Celsius to degrees Kelvin.
 
static constexpr double KelvinToCelsius (double kelvin)
 Converts from degrees Kelvin to degrees Celsius.
 
static constexpr double FeetToMeters (double measure)
 Converts from feet to meters.
 
static bool EqualToRoundoff (double a, double b)
 Finite precision comparison.
 
static bool EqualToRoundoff (float a, float b)
 Finite precision comparison.
 
static bool EqualToRoundoff (float a, double b)
 Finite precision comparison.
 
static bool EqualToRoundoff (double a, float b)
 Finite precision comparison.
 
static constexpr double Constrain (double min, double value, double max)
 Constrain a value between a minimum and a maximum value.
 
static constexpr double sign (double num)
 
- Static Public Attributes inherited from FGJSBBase
static char highint [5] = {27, '[', '1', 'm', '\0' }
 highlights text
 
static char halfint [5] = {27, '[', '2', 'm', '\0' }
 low intensity text
 
static char normint [6] = {27, '[', '2', '2', 'm', '\0' }
 normal intensity text
 
static char reset [5] = {27, '[', '0', 'm', '\0' }
 resets text properties
 
static char underon [5] = {27, '[', '4', 'm', '\0' }
 underlines text
 
static char underoff [6] = {27, '[', '2', '4', 'm', '\0' }
 underline off
 
static char fgblue [6] = {27, '[', '3', '4', 'm', '\0' }
 blue text
 
static char fgcyan [6] = {27, '[', '3', '6', 'm', '\0' }
 cyan text
 
static char fgred [6] = {27, '[', '3', '1', 'm', '\0' }
 red text
 
static char fggreen [6] = {27, '[', '3', '2', 'm', '\0' }
 green text
 
static char fgdef [6] = {27, '[', '3', '9', 'm', '\0' }
 default text
 
static short debug_lvl = 1
 
- Static Protected Member Functions inherited from FGJSBBase
static std::string CreateIndexedPropertyName (const std::string &Property, int index)
 
- Static Protected Attributes inherited from FGJSBBase
static constexpr double radtodeg = 180. / M_PI
 
static constexpr double degtorad = M_PI / 180.
 
static constexpr double hptoftlbssec = 550.0
 
static constexpr double psftoinhg = 0.014138
 
static constexpr double psftopa = 47.88
 
static constexpr double fttom = 0.3048
 
static constexpr double ktstofps = 1852./(3600*fttom)
 
static constexpr double fpstokts = 1.0 / ktstofps
 
static constexpr double inchtoft = 1.0/12.0
 
static constexpr double m3toft3 = 1.0/(fttom*fttom*fttom)
 
static constexpr double in3tom3 = inchtoft*inchtoft*inchtoft/m3toft3
 
static constexpr double inhgtopa = 3386.38
 
static constexpr double slugtolb = 32.174049
 Note that definition of lbtoslug by the inverse of slugtolb and not to a different constant you can also get from some tables will make lbtoslug*slugtolb == 1 up to the magnitude of roundoff.
 
static constexpr double lbtoslug = 1.0/slugtolb
 
static constexpr double kgtolb = 2.20462
 
static constexpr double kgtoslug = 0.06852168
 
static const std::string needed_cfg_version = "2.0"
 
static const std::string JSBSim_version = JSBSIM_VERSION " " __DATE__ " " __TIME__
 

Member Enumeration Documentation

◆ OddEven

enum class OddEven
strong

Definition at line 825 of file FGFunction.h.

825{Either, Odd, Even};

Constructor & Destructor Documentation

◆ FGFunction() [1/3]

FGFunction ( )
inline

Default constructor.

Definition at line 768 of file FGFunction.h.

769 : cached(false), cachedValue(-HUGE_VAL), pNode(nullptr), pCopyTo(nullptr) {}

◆ FGFunction() [2/3]

FGFunction ( std::shared_ptr< FGPropertyManager >  pm)
inlineexplicit

Definition at line 771 of file FGFunction.h.

772 : FGFunction()
773 { PropertyManager = pm; }
FGFunction()
Default constructor.
Definition FGFunction.h:768

◆ FGFunction() [3/3]

FGFunction ( FGFDMExec fdmex,
Element element,
const std::string &  prefix = "",
FGPropertyValue var = 0L 
)

Constructor.

When this constructor is called, the XML element pointed to in memory by the element argument is traversed. If other FGParameter-derived objects (values, functions, properties, or tables) are encountered, this instance of the FGFunction object will store a pointer to the found object and pass the relevant Element pointer to the constructor for the new object. In other words, each FGFunction object maintains a list of "child" FGParameter-derived objects which in turn may each contain its own list, and so on. At runtime, each object evaluates its child parameters, which each may have its own child parameters to evaluate.

Parameters
PropertyManagera pointer to the property manager instance.
elementa pointer to the Element object containing the function definition.
prefixan optional prefix to prepend to the name given to the property that represents this function (if given).

Definition at line 209 of file FGFunction.cpp.

211 : FGFunction(fdmex->GetPropertyManager())
212{
213 Load(el, var, fdmex, prefix);
214 CheckMinArguments(el, 1);
215 CheckMaxArguments(el, 1);
216
217 string sCopyTo = el->GetAttributeValue("copyto");
218
219 if (!sCopyTo.empty()) {
220 if (sCopyTo.find("#") != string::npos) {
221 if (is_number(prefix))
222 sCopyTo = replace(sCopyTo,"#",prefix);
223 else {
224 FGXMLLogging log(el, LogLevel::ERROR);
225 log << LogFormat::RED
226 << "Illegal use of the special character '#'\n" << LogFormat::RESET
227 << "The 'copyto' argument in function " << Name << " is ignored.\n";
228 return;
229 }
230 }
231
232 pCopyTo = PropertyManager->GetNode(sCopyTo);
233 if (!pCopyTo) {
234 FGXMLLogging log(el, LogLevel::ERROR);
235 log << LogFormat::RED
236 << "Property \"" << sCopyTo
237 << "\" must be previously defined in function " << Name << LogFormat::RESET
238 << "The 'copyto' argument is ignored.\n";
239 }
240 }
241}
+ Here is the call graph for this function:

◆ ~FGFunction()

~FGFunction ( void  )
override

Destructor Make sure the function is untied before destruction.

Definition at line 952 of file FGFunction.cpp.

953{
954 if (pNode && pNode->isTied())
955 PropertyManager->Untie(pNode);
956
957 Debug(1);
958}

Member Function Documentation

◆ bind()

void bind ( Element el,
const std::string &  Prefix 
)
protectedvirtual

Definition at line 1045 of file FGFunction.cpp.

1046{
1047 string nName = CreateOutputNode(el, Prefix);
1048
1049 if (!nName.empty())
1050 PropertyManager->Tie(nName, this, &FGFunction::GetValue);
1051}
double GetValue(void) const override
Retrieves the value of the function object.

◆ cacheValue()

void cacheValue ( bool  shouldCache)

Specifies whether to cache the value of the function, so it is calculated only once per frame.

If shouldCache is true, then the value of the function is calculated, and a flag is set so further calculations done this frame will use the cached value. In order to turn off caching, cacheValue must be called with a false argument.

Parameters
shouldCachespecifies whether the function should cache the computed value.

Definition at line 974 of file FGFunction.cpp.

975{
976 cached = false; // Must set cached to false prior to calling GetValue(), else
977 // it will _never_ calculate the value;
978 if (cache) {
979 cachedValue = GetValue();
980 cached = true;
981 }
982}
+ Here is the call graph for this function:

◆ CheckMaxArguments()

void CheckMaxArguments ( Element el,
unsigned int  _max 
)
protected

Definition at line 258 of file FGFunction.cpp.

259{
260 if (Parameters.size() > _max) {
261 ostringstream buffer;
262 buffer << el->ReadFrom() << fgred << highint
263 << "<" << el->GetName() << "> should have no more than " << _max
264 << " argument(s)." << reset << endl;
265 throw WrongNumberOfArguments(buffer.str(), Parameters, el);
266 }
267}
static char fgred[6]
red text
Definition FGJSBBase.h:167
static char reset[5]
resets text properties
Definition FGJSBBase.h:157
static char highint[5]
highlights text
Definition FGJSBBase.h:151

◆ CheckMinArguments()

void CheckMinArguments ( Element el,
unsigned int  _min 
)
protected

Definition at line 245 of file FGFunction.cpp.

246{
247 if (Parameters.size() < _min) {
248 ostringstream buffer;
249 buffer << el->ReadFrom() << fgred << highint
250 << "<" << el->GetName() << "> should have at least " << _min
251 << " argument(s)." << reset << endl;
252 throw WrongNumberOfArguments(buffer.str(), Parameters, el);
253 }
254}

◆ CheckOddOrEvenArguments()

void CheckOddOrEvenArguments ( Element el,
OddEven  odd_even 
)
protected

Definition at line 271 of file FGFunction.cpp.

272{
273
274 switch(odd_even) {
275 case OddEven::Even:
276 if (Parameters.size() % 2 == 1) {
277 XMLLogException err(el);
278 err << LogFormat::RED << LogFormat::BOLD
279 << "<" << el->GetName() << "> must have an even number of arguments.\n"
280 << LogFormat::RESET;
281 throw err;
282 }
283 break;
284 case OddEven::Odd:
285 if (Parameters.size() % 2 == 0) {
286 XMLLogException err(el);
287 err << LogFormat::RED << LogFormat::BOLD
288 << "<" << el->GetName() << "> must have an odd number of arguments.\n"
289 << LogFormat::RESET;
290 throw err;
291 }
292 break;
293 default:
294 break;
295 }
296}

◆ CreateOutputNode()

string CreateOutputNode ( Element el,
const std::string &  Prefix 
)
protected

Definition at line 1009 of file FGFunction.cpp.

1010{
1011 string nName;
1012
1013 if ( !Name.empty() ) {
1014 if (Prefix.empty())
1015 nName = PropertyManager->mkPropertyName(Name, false);
1016 else {
1017 if (is_number(Prefix)) {
1018 if (Name.find("#") != string::npos) { // if "#" is found
1019 Name = replace(Name,"#",Prefix);
1020 nName = PropertyManager->mkPropertyName(Name, false);
1021 } else {
1022 FGXMLLogging log(el, LogLevel::ERROR);
1023 log << "Malformed function name with number: " << Prefix
1024 << " and property name: " << Name
1025 << " but no \"#\" sign for substitution.\n";
1026 }
1027 } else {
1028 nName = PropertyManager->mkPropertyName(Prefix + "/" + Name, false);
1029 }
1030 }
1031
1032 pNode = PropertyManager->GetNode(nName, true);
1033 if (pNode->isTied()) {
1034 XMLLogException err(el);
1035 err << "Property " << nName << " has already been successfully bound (late).\n";
1036 throw err;
1037 }
1038 }
1039
1040 return nName;
1041}

◆ GetName()

std::string GetName ( void  ) const
inlineoverridevirtual

Retrieves the name of the function.

Implements FGParameter.

Definition at line 809 of file FGFunction.h.

809{return Name;}

◆ GetValue()

double GetValue ( void  ) const
overridevirtual

Retrieves the value of the function object.

Returns
the total value of the function.

Implements FGParameter.

Definition at line 986 of file FGFunction.cpp.

987{
988 if (cached) return cachedValue;
989
990 double val = Parameters[0]->GetValue();
991
992 if (pCopyTo) pCopyTo->setDoubleValue(val);
993
994 return val;
995}
+ Here is the caller graph for this function:

◆ GetValueAsString()

string GetValueAsString ( void  ) const

The value that the function evaluates to, as a string.

Returns
the value of the function as a string.

Definition at line 999 of file FGFunction.cpp.

1000{
1001 ostringstream buffer;
1002
1003 buffer << setw(9) << setprecision(6) << GetValue();
1004 return buffer.str();
1005}
+ Here is the call graph for this function:

◆ IsConstant()

bool IsConstant ( void  ) const
overridevirtual

Does the function always return the same result (i.e.

does it apply to constant parameters) ?

Reimplemented from FGParameter.

Definition at line 962 of file FGFunction.cpp.

963{
964 for (auto p: Parameters) {
965 if (!p->IsConstant())
966 return false;
967 }
968
969 return true;
970}

◆ Load()

void Load ( Element element,
FGPropertyValue var,
FGFDMExec fdmex,
const std::string &  prefix = "" 
)
protected

Definition at line 315 of file FGFunction.cpp.

317{
318 Name = el->GetAttributeValue("name");
319 Element* element = el->GetElement();
320
321 auto sum = [](const decltype(Parameters)& Parameters)->double {
322 double temp = 0.0;
323
324 for (auto p: Parameters)
325 temp += p->GetValue();
326
327 return temp;
328 };
329
330 while (element) {
331 string operation = element->GetName();
332
333 // data types
334 if (operation == "property" || operation == "p") {
335 string property_name = element->GetDataLine();
336
337 if (var && simgear::strutils::strip(property_name) == "#")
338 Parameters.push_back(var);
339 else {
340 if (property_name.find("#") != string::npos) {
341 if (is_number(Prefix)) {
342 property_name = replace(property_name,"#",Prefix);
343 }
344 else {
345 XMLLogException err(element);
346 err << LogFormat::RED << "Illegal use of the special character '#'\n"
347 << LogFormat::RESET;
348 throw err;
349 }
350 }
351
352 if (element->HasAttribute("apply")) {
353 string function_str = element->GetAttributeValue("apply");
354 auto f = fdmex->GetTemplateFunc(function_str);
355 if (f)
356 Parameters.push_back(new FGFunctionValue(property_name,
357 PropertyManager, f, element));
358 else {
359 FGXMLLogging log(element, LogLevel::ERROR);
360 log << LogFormat::RED << LogFormat::BOLD
361 << " No function by the name " << function_str
362 << " has been defined. This property will "
363 << "not be logged. You should check your configuration file.\n"
364 << LogFormat::RESET;
365 }
366 }
367 else
368 Parameters.push_back(new FGPropertyValue(property_name,
369 PropertyManager, element));
370 }
371 } else if (operation == "value" || operation == "v") {
372 Parameters.push_back(new FGRealValue(element->GetDataAsNumber()));
373 } else if (operation == "pi") {
374 Parameters.push_back(new FGRealValue(M_PI));
375 } else if (operation == "table" || operation == "t") {
376 string call_type = element->GetAttributeValue("type");
377 if (call_type == "internal") {
378 XMLLogException err(el);
379 err << "An internal table cannot be nested within a function.\n";
380 throw err;
381 }
382 Parameters.push_back(new FGTable(PropertyManager, element, Prefix));
383 // operations
384 } else if (operation == "product") {
385 auto f = [](const decltype(Parameters)& Parameters)->double {
386 double temp = 1.0;
387
388 for (auto p: Parameters)
389 temp *= p->GetValue();
390
391 return temp;
392 };
393 Parameters.push_back(VarArgsFn<decltype(f)>(f, fdmex, element, Prefix, var));
394 } else if (operation == "sum") {
395 Parameters.push_back(VarArgsFn<decltype(sum)>(sum, fdmex, element, Prefix, var));
396 } else if (operation == "avg") {
397 auto avg = [&](const decltype(Parameters)& p)->double {
398 return sum(p) / p.size();
399 };
400 Parameters.push_back(VarArgsFn<decltype(avg)>(avg, fdmex, element, Prefix, var));
401 } else if (operation == "difference") {
402 auto f = [](const decltype(Parameters)& Parameters)->double {
403 double temp = Parameters[0]->GetValue();
404
405 for (auto p = Parameters.begin()+1; p != Parameters.end(); ++p)
406 temp -= (*p)->GetValue();
407
408 return temp;
409 };
410 Parameters.push_back(VarArgsFn<decltype(f)>(f, fdmex, element, Prefix, var));
411 } else if (operation == "min") {
412 auto f = [](const decltype(Parameters)& Parameters)->double {
413 double _min = HUGE_VAL;
414
415 for (auto p : Parameters) {
416 double x = p->GetValue();
417 if (x < _min)
418 _min = x;
419 }
420
421 return _min;
422 };
423 Parameters.push_back(VarArgsFn<decltype(f)>(f, fdmex, element, Prefix, var));
424 } else if (operation == "max") {
425 auto f = [](const decltype(Parameters)& Parameters)->double {
426 double _max = -HUGE_VAL;
427
428 for (auto p : Parameters) {
429 double x = p->GetValue();
430 if (x > _max)
431 _max = x;
432 }
433
434 return _max;
435 };
436 Parameters.push_back(VarArgsFn<decltype(f)>(f, fdmex, element, Prefix, var));
437 } else if (operation == "and") {
438 string ctxMsg = element->ReadFrom();
439 auto f = [ctxMsg](const decltype(Parameters)& Parameters)->double {
440 for (auto p : Parameters) {
441 if (!GetBinary(p->GetValue(), ctxMsg)) // As soon as one parameter is false, the expression is guaranteed to be false.
442 return 0.0;
443 }
444
445 return 1.0;
446 };
447 Parameters.push_back(new aFunc<decltype(f), 2>(f, fdmex, element, Prefix,
448 var, MaxArgs));
449 } else if (operation == "or") {
450 string ctxMsg = element->ReadFrom();
451 auto f = [ctxMsg](const decltype(Parameters)& Parameters)->double {
452 for (auto p : Parameters) {
453 if (GetBinary(p->GetValue(), ctxMsg)) // As soon as one parameter is true, the expression is guaranteed to be true.
454 return 1.0;
455 }
456
457 return 0.0;
458 };
459 Parameters.push_back(new aFunc<decltype(f), 2>(f, fdmex, element, Prefix,
460 var, MaxArgs));
461 } else if (operation == "quotient") {
462 auto f = [](const decltype(Parameters)& p)->double {
463 double y = p[1]->GetValue();
464 return y != 0.0 ? p[0]->GetValue()/y : HUGE_VAL;
465 };
466 Parameters.push_back(new aFunc<decltype(f), 2>(f, fdmex, element, Prefix, var));
467 } else if (operation == "pow") {
468 auto f = [](const decltype(Parameters)& p)->double {
469 return pow(p[0]->GetValue(), p[1]->GetValue());
470 };
471 Parameters.push_back(new aFunc<decltype(f), 2>(f, fdmex, element, Prefix, var));
472 } else if (operation == "toradians") {
473 auto f = [](const decltype(Parameters)& p)->double {
474 return p[0]->GetValue()*M_PI/180.;
475 };
476 Parameters.push_back(new aFunc<decltype(f), 1>(f, fdmex, element, Prefix, var));
477 } else if (operation == "todegrees") {
478 auto f = [](const decltype(Parameters)& p)->double {
479 return p[0]->GetValue()*180./M_PI;
480 };
481 Parameters.push_back(new aFunc<decltype(f), 1>(f, fdmex, element, Prefix, var));
482 } else if (operation == "sqrt") {
483 auto f = [](const decltype(Parameters)& p)->double {
484 double x = p[0]->GetValue();
485 return x >= 0.0 ? sqrt(x) : -HUGE_VAL;
486 };
487 Parameters.push_back(new aFunc<decltype(f), 1>(f, fdmex, element, Prefix, var));
488 } else if (operation == "log2") {
489 auto f = [](const decltype(Parameters)& p)->double {
490 double x = p[0]->GetValue();
491 return x > 0.0 ? log10(x)*invlog2val : -HUGE_VAL;
492 };
493 Parameters.push_back(new aFunc<decltype(f), 1>(f, fdmex, element, Prefix, var));
494 } else if (operation == "ln") {
495 auto f = [](const decltype(Parameters)& p)->double {
496 double x = p[0]->GetValue();
497 return x > 0.0 ? log(x) : -HUGE_VAL;
498 };
499 Parameters.push_back(new aFunc<decltype(f), 1>(f, fdmex, element, Prefix, var));
500 } else if (operation == "log10") {
501 auto f = [](const decltype(Parameters)& p)->double {
502 double x = p[0]->GetValue();
503 return x > 0.0 ? log10(x) : -HUGE_VAL;
504 };
505 Parameters.push_back(new aFunc<decltype(f), 1>(f, fdmex, element, Prefix, var));
506 } else if (operation == "sign") {
507 auto f = [](const decltype(Parameters)& p)->double {
508 return p[0]->GetValue() < 0.0 ? -1 : 1; // 0.0 counts as positive.
509 };
510 Parameters.push_back(new aFunc<decltype(f), 1>(f, fdmex, element, Prefix, var));
511 } else if (operation == "exp") {
512 Parameters.push_back(make_MathFn(exp, fdmex, element, Prefix, var));
513 } else if (operation == "abs") {
514 Parameters.push_back(make_MathFn(fabs, fdmex, element, Prefix, var));
515 } else if (operation == "sin") {
516 Parameters.push_back(make_MathFn(sin, fdmex, element, Prefix, var));
517 } else if (operation == "cos") {
518 Parameters.push_back(make_MathFn(cos, fdmex, element, Prefix, var));
519 } else if (operation == "tan") {
520 Parameters.push_back(make_MathFn(tan, fdmex, element, Prefix, var));
521 } else if (operation == "asin") {
522 Parameters.push_back(make_MathFn(asin, fdmex, element, Prefix, var));
523 } else if (operation == "acos") {
524 Parameters.push_back(make_MathFn(acos, fdmex, element, Prefix, var));
525 } else if (operation == "atan") {
526 Parameters.push_back(make_MathFn(atan, fdmex, element, Prefix, var));
527 } else if (operation == "floor") {
528 Parameters.push_back(make_MathFn(floor, fdmex, element, Prefix, var));
529 } else if (operation == "ceil") {
530 Parameters.push_back(make_MathFn(ceil, fdmex, element, Prefix, var));
531 } else if (operation == "fmod") {
532 auto f = [](const decltype(Parameters)& p)->double {
533 double y = p[1]->GetValue();
534 return y != 0.0 ? fmod(p[0]->GetValue(), y) : HUGE_VAL;
535 };
536 Parameters.push_back(new aFunc<decltype(f), 2>(f, fdmex, element, Prefix, var));
537 } else if (operation == "roundmultiple") {
538 if (element->GetNumElements() == 1)
539 Parameters.push_back(make_MathFn(round, fdmex, element, Prefix, var));
540 else {
541 auto f = [](const decltype(Parameters)& p)->double {
542 double multiple = p[1]->GetValue();
543 return round((p[0]->GetValue() / multiple)) * multiple;
544 };
545 Parameters.push_back(new aFunc<decltype(f), 1>(f, fdmex, element, Prefix, var, 2));
546 }
547 } else if (operation == "atan2") {
548 auto f = [](const decltype(Parameters)& p)->double {
549 return atan2(p[0]->GetValue(), p[1]->GetValue());
550 };
551 Parameters.push_back(new aFunc<decltype(f), 2>(f, fdmex, element, Prefix, var));
552 } else if (operation == "mod") {
553 auto f = [](const decltype(Parameters)& p)->double {
554 return static_cast<int>(p[0]->GetValue()) % static_cast<int>(p[1]->GetValue());
555 };
556 Parameters.push_back(new aFunc<decltype(f), 2>(f, fdmex, element, Prefix, var));
557 } else if (operation == "fraction") {
558 auto f = [](const decltype(Parameters)& p)->double {
559 double scratch;
560 return modf(p[0]->GetValue(), &scratch);
561 };
562 Parameters.push_back(new aFunc<decltype(f), 1>(f, fdmex, element, Prefix, var));
563 } else if (operation == "integer") {
564 auto f = [](const decltype(Parameters)& p)->double {
565 double result;
566 modf(p[0]->GetValue(), &result);
567 return result;
568 };
569 Parameters.push_back(new aFunc<decltype(f), 1>(f, fdmex, element, Prefix, var));
570 } else if (operation == "lt") {
571 auto f = [](const decltype(Parameters)& p)->double {
572 return p[0]->GetValue() < p[1]->GetValue() ? 1.0 : 0.0;
573 };
574 Parameters.push_back(new aFunc<decltype(f), 2>(f, fdmex, element, Prefix, var));
575 } else if (operation == "le") {
576 auto f = [](const decltype(Parameters)& p)->double {
577 return p[0]->GetValue() <= p[1]->GetValue() ? 1.0 : 0.0;
578 };
579 Parameters.push_back(new aFunc<decltype(f), 2>(f, fdmex, element, Prefix, var));
580 } else if (operation == "gt") {
581 auto f = [](const decltype(Parameters)& p)->double {
582 return p[0]->GetValue() > p[1]->GetValue() ? 1.0 : 0.0;
583 };
584 Parameters.push_back(new aFunc<decltype(f), 2>(f, fdmex, element, Prefix, var));
585 } else if (operation == "ge") {
586 auto f = [](const decltype(Parameters)& p)->double {
587 return p[0]->GetValue() >= p[1]->GetValue() ? 1.0 : 0.0;
588 };
589 Parameters.push_back(new aFunc<decltype(f), 2>(f, fdmex, element, Prefix, var));
590 } else if (operation == "eq") {
591 auto f = [](const decltype(Parameters)& p)->double {
592 return p[0]->GetValue() == p[1]->GetValue() ? 1.0 : 0.0;
593 };
594 Parameters.push_back(new aFunc<decltype(f), 2>(f, fdmex, element, Prefix, var));
595 } else if (operation == "nq") {
596 auto f = [](const decltype(Parameters)& p)->double {
597 return p[0]->GetValue() != p[1]->GetValue() ? 1.0 : 0.0;
598 };
599 Parameters.push_back(new aFunc<decltype(f), 2>(f, fdmex, element, Prefix, var));
600 } else if (operation == "not") {
601 string ctxMsg = element->ReadFrom();
602 auto f = [ctxMsg](const decltype(Parameters)& p)->double {
603 return GetBinary(p[0]->GetValue(), ctxMsg) ? 0.0 : 1.0;
604 };
605 Parameters.push_back(new aFunc<decltype(f), 1>(f, fdmex, element, Prefix, var));
606 } else if (operation == "ifthen") {
607 string ctxMsg = element->ReadFrom();
608 auto f = [ctxMsg](const decltype(Parameters)& p)->double {
609 if (GetBinary(p[0]->GetValue(), ctxMsg))
610 return p[1]->GetValue();
611 else
612 return p[2]->GetValue();
613 };
614 Parameters.push_back(new aFunc<decltype(f), 3>(f, fdmex, element, Prefix, var));
615 } else if (operation == "random") {
616 double mean = 0.0;
617 double stddev = 1.0;
618 string mean_attr = element->GetAttributeValue("mean");
619 string stddev_attr = element->GetAttributeValue("stddev");
620 if (!mean_attr.empty()) {
621 try {
622 mean = atof_locale_c(mean_attr);
623 } catch (InvalidNumber& e) {
624 XMLLogException err(element);
625 err << e.what() << "\n";
626 throw err;
627 }
628 }
629 if (!stddev_attr.empty()) {
630 try {
631 stddev = atof_locale_c(stddev_attr);
632 } catch (InvalidNumber& e) {
633 XMLLogException err(element);
634 err << e.what() << "\n";
635 throw err;
636 }
637 }
638 auto generator(makeRandomGenerator(element, fdmex));
639 auto f = [generator, mean, stddev]()->double {
640 double value = generator->GetNormalRandomNumber();
641 return value*stddev + mean;
642 };
643 Parameters.push_back(new aFunc<decltype(f), 0>(f, PropertyManager, element,
644 Prefix));
645 } else if (operation == "urandom") {
646 double lower = -1.0;
647 double upper = 1.0;
648 string lower_attr = element->GetAttributeValue("lower");
649 string upper_attr = element->GetAttributeValue("upper");
650 if (!lower_attr.empty()) {
651 try {
652 lower = atof_locale_c(lower_attr);
653 } catch (InvalidNumber &e) {
654 XMLLogException err(element);
655 err << e.what() << "\n";
656 throw err;
657 }
658 }
659 if (!upper_attr.empty()) {
660 try {
661 upper = atof_locale_c(upper_attr);
662 } catch (InvalidNumber &e) {
663 XMLLogException err(element);
664 err << e.what() << "\n";
665 throw err;
666 }
667 }
668 auto generator(makeRandomGenerator(element, fdmex));
669 double a = 0.5*(upper-lower);
670 double b = 0.5*(upper+lower);
671 auto f = [generator, a, b]()->double {
672 double value = generator->GetUniformRandomNumber();
673 return value*a + b;
674 };
675 Parameters.push_back(new aFunc<decltype(f), 0>(f, PropertyManager, element,
676 Prefix));
677 } else if (operation == "switch") {
678 string ctxMsg = element->ReadFrom();
679 auto f = [ctxMsg](const decltype(Parameters)& p)->double {
680 double temp = p[0]->GetValue();
681 if (temp < 0.0) {
682 LogException err;
683 err << ctxMsg << LogFormat::RED << LogFormat::BOLD
684 << "The switch function index (" << temp
685 << ") is negative.\n" << LogFormat::RESET;
686 throw err;
687 }
688 size_t n = p.size()-1;
689 size_t i = static_cast<size_t>(temp+0.5);
690
691 if (i < n)
692 return p[i+1]->GetValue();
693 else {
694 LogException err;
695 err << ctxMsg << LogFormat::RED << LogFormat::BOLD
696 << "The switch function index (" << temp
697 << ") selected a value above the range of supplied values"
698 << "[0:" << n-1 << "]"
699 << " - not enough values were supplied.\n" << LogFormat::RESET;
700 throw err;
701 }
702 };
703 Parameters.push_back(new aFunc<decltype(f), 2>(f, fdmex, element, Prefix,
704 var, MaxArgs));
705 } else if (operation == "interpolate1d") {
706 auto f = [](const decltype(Parameters)& p)->double {
707 // This is using the bisection algorithm. Special care has been
708 // taken to evaluate each parameter only once.
709 size_t n = p.size();
710 double x = p[0]->GetValue();
711 double xmin = p[1]->GetValue();
712 double ymin = p[2]->GetValue();
713 if (x <= xmin) return ymin;
714
715 double xmax = p[n-2]->GetValue();
716 double ymax = p[n-1]->GetValue();
717 if (x >= xmax) return ymax;
718
719 size_t nmin = 0;
720 size_t nmax = (n-3)/2;
721 while (nmax-nmin > 1) {
722 size_t m = (nmax-nmin)/2+nmin;
723 double xm = p[2*m+1]->GetValue();
724 double ym = p[2*m+2]->GetValue();
725 if (x < xm) {
726 xmax = xm;
727 ymax = ym;
728 nmax= m;
729 } else if (x > xm) {
730 xmin = xm;
731 ymin = ym;
732 nmin = m;
733 }
734 else
735 return ym;
736 }
737
738 return ymin + (x-xmin)*(ymax-ymin)/(xmax-xmin);
739 };
740 Parameters.push_back(new aFunc<decltype(f), 5>(f, fdmex, element, Prefix,
741 var, MaxArgs, OddEven::Odd));
742 } else if (operation == "rotation_alpha_local") {
743 // Calculates local angle of attack for skydiver body component.
744 // Euler angles from the intermediate body frame to the local body frame
745 // must be from a z-y-x axis rotation order
746 auto f = [](const decltype(Parameters)& p)->double {
747 double alpha = p[0]->GetValue()*degtorad; //angle of attack of intermediate body frame
748 double beta = p[1]->GetValue()*degtorad; //sideslip angle of intermediate body frame
749 double phi = p[3]->GetValue()*degtorad; //x-axis Euler angle from the intermediate body frame to the local body frame
750 double theta = p[4]->GetValue()*degtorad; //y-axis Euler angle from the intermediate body frame to the local body frame
751 double psi = p[5]->GetValue()*degtorad; //z-axis Euler angle from the intermediate body frame to the local body frame
752
753 FGQuaternion qTb2l(phi, theta, psi);
754 double cos_beta = cos(beta);
755 FGColumnVector3 wind_body(cos(alpha)*cos_beta, sin(beta),
756 sin(alpha)*cos_beta);
757 FGColumnVector3 wind_local = qTb2l.GetT()*wind_body;
758
759 if (fabs(fabs(wind_local(eY)) - 1.0) < 1E-9)
760 return 0.0;
761 else
762 return atan2(wind_local(eZ), wind_local(eX))*radtodeg;
763 };
764 Parameters.push_back(new aFunc<decltype(f), 6>(f, fdmex, element, Prefix, var));
765 } else if (operation == "rotation_beta_local") {
766 // Calculates local angle of sideslip for skydiver body component.
767 // Euler angles from the intermediate body frame to the local body frame
768 // must be from a z-y-x axis rotation order
769 auto f = [](const decltype(Parameters)& p)->double {
770 double alpha = p[0]->GetValue()*degtorad; //angle of attack of intermediate body frame
771 double beta = p[1]->GetValue()*degtorad; //sideslip angle of intermediate body frame
772 double phi = p[3]->GetValue()*degtorad; //x-axis Euler angle from the intermediate body frame to the local body frame
773 double theta = p[4]->GetValue()*degtorad; //y-axis Euler angle from the intermediate body frame to the local body frame
774 double psi = p[5]->GetValue()*degtorad; //z-axis Euler angle from the intermediate body frame to the local body frame
775 FGQuaternion qTb2l(phi, theta, psi);
776 double cos_beta = cos(beta);
777 FGColumnVector3 wind_body(cos(alpha)*cos_beta, sin(beta),
778 sin(alpha)*cos_beta);
779 FGColumnVector3 wind_local = qTb2l.GetT()*wind_body;
780
781 if (fabs(fabs(wind_local(eY)) - 1.0) < 1E-9)
782 return wind_local(eY) > 0.0 ? 0.5*M_PI : -0.5*M_PI;
783
784 double alpha_local = atan2(wind_local(eZ), wind_local(eX));
785 double cosa = cos(alpha_local);
786 double sina = sin(alpha_local);
787 double cosb;
788
789 if (fabs(cosa) > fabs(sina))
790 cosb = wind_local(eX) / cosa;
791 else
792 cosb = wind_local(eZ) / sina;
793
794 return atan2(wind_local(eY), cosb)*radtodeg;
795 };
796 Parameters.push_back(new aFunc<decltype(f), 6>(f, fdmex, element, Prefix, var));
797 } else if (operation == "rotation_gamma_local") {
798 // Calculates local roll angle for skydiver body component.
799 // Euler angles from the intermediate body frame to the local body frame
800 // must be from a z-y-x axis rotation order
801 auto f = [](const decltype(Parameters)& p)->double {
802 double alpha = p[0]->GetValue()*degtorad; //angle of attack of intermediate body frame
803 double beta = p[1]->GetValue()*degtorad; //sideslip angle of intermediate body frame
804 double gamma = p[2]->GetValue()*degtorad; //roll angle of intermediate body frame
805 double phi = p[3]->GetValue()*degtorad; //x-axis Euler angle from the intermediate body frame to the local body frame
806 double theta = p[4]->GetValue()*degtorad; //y-axis Euler angle from the intermediate body frame to the local body frame
807 double psi = p[5]->GetValue()*degtorad; //z-axis Euler angle from the intermediate body frame to the local body frame
808 double cos_alpha = cos(alpha), sin_alpha = sin(alpha);
809 double cos_beta = cos(beta), sin_beta = sin(beta);
810 double cos_gamma = cos(gamma), sin_gamma = sin(gamma);
811 FGQuaternion qTb2l(phi, theta, psi);
812 FGColumnVector3 wind_body_X(cos_alpha*cos_beta, sin_beta,
813 sin_alpha*cos_beta);
814 FGColumnVector3 wind_body_Y(-sin_alpha*sin_gamma-sin_beta*cos_alpha*cos_gamma,
815 cos_beta*cos_gamma,
816 -sin_alpha*sin_beta*cos_gamma+sin_gamma*cos_alpha);
817 FGColumnVector3 wind_local_X = qTb2l.GetT()*wind_body_X;
818 FGColumnVector3 wind_local_Y = qTb2l.GetT()*wind_body_Y;
819 double cosacosb = wind_local_X(eX);
820 double sinb = wind_local_X(eY);
821 double sinacosb = wind_local_X(eZ);
822 double sinc, cosc;
823
824 if (fabs(sinb) < 1E-9) { // cos(beta_local) == 1.0
825 cosc = wind_local_Y(eY);
826
827 if (fabs(cosacosb) > fabs(sinacosb))
828 sinc = wind_local_Y(eZ) / cosacosb;
829 else
830 sinc = -wind_local_Y(eX) / sinacosb;
831 }
832 else if (fabs(fabs(sinb)-1.0) < 1E-9) { // cos(beta_local) == 0.0
833 sinc = wind_local_Y(eZ);
834 cosc = -wind_local_Y(eX);
835 }
836 else {
837 sinc = cosacosb*wind_local_Y(eZ)-sinacosb*wind_local_Y(eX);
838 cosc = (-sinacosb*wind_local_Y(eZ)-cosacosb*wind_local_Y(eX))/sinb;
839 }
840
841 return atan2(sinc, cosc)*radtodeg;
842 };
843 Parameters.push_back(new aFunc<decltype(f), 6>(f, fdmex, element, Prefix, var));
844 } else if (operation == "rotation_bf_to_wf") {
845 // Transforms the input vector from a body frame to a wind frame. The
846 // origin of the vector remains the same.
847 string ctxMsg = element->ReadFrom();
848 auto f = [ctxMsg](const decltype(Parameters)& p)->double {
849 double rx = p[0]->GetValue(); //x component of input vector
850 double ry = p[1]->GetValue(); //y component of input vector
851 double rz = p[2]->GetValue(); //z component of input vector
852 double alpha = p[3]->GetValue()*degtorad; //angle of attack of the body frame
853 double beta = p[4]->GetValue()*degtorad; //sideslip angle of the body frame
854 double gamma = p[5]->GetValue()*degtorad; //roll angle of the body frame
855 int idx = static_cast<int>(p[6]->GetValue());
856
857 if ((idx < 1) || (idx > 3)) {
858 LogException err;
859 err << ctxMsg << LogFormat::RED << LogFormat::BOLD
860 << "The index must be one of the integer value 1, 2 or 3.\n"
861 << LogFormat::RESET;
862 throw err;
863 }
864
865 FGQuaternion qa(eY, -alpha), qb(eZ, beta), qc(eX, -gamma);
866 FGMatrix33 mT = (qa*qb*qc).GetT();
867 FGColumnVector3 r0(rx, ry, rz);
868 FGColumnVector3 r = mT*r0;
869
870 return r(idx);
871 };
872 Parameters.push_back(new aFunc<decltype(f), 7>(f, fdmex, element, Prefix, var));
873 } else if (operation == "rotation_wf_to_bf") {
874 // Transforms the input vector from q wind frame to a body frame. The
875 // origin of the vector remains the same.
876 string ctxMsg = element->ReadFrom();
877 auto f = [ctxMsg](const decltype(Parameters)& p)->double {
878 double rx = p[0]->GetValue(); //x component of input vector
879 double ry = p[1]->GetValue(); //y component of input vector
880 double rz = p[2]->GetValue(); //z component of input vector
881 double alpha = p[3]->GetValue()*degtorad; //angle of attack of the body frame
882 double beta = p[4]->GetValue()*degtorad; //sideslip angle of the body frame
883 double gamma = p[5]->GetValue()*degtorad; //roll angle of the body frame
884 int idx = static_cast<int>(p[6]->GetValue());
885
886 if ((idx < 1) || (idx > 3)) {
887 LogException err;
888 err << ctxMsg << LogFormat::RED << LogFormat::BOLD
889 << "The index must be one of the integer value 1, 2 or 3.\n"
890 << LogFormat::RESET;
891 throw err;
892 }
893
894 FGQuaternion qa(eY, -alpha), qb(eZ, beta), qc(eX, -gamma);
895 FGMatrix33 mT = (qa*qb*qc).GetT();
896 FGColumnVector3 r0(rx, ry, rz);
897 mT.T();
898 FGColumnVector3 r = mT*r0;
899
900 return r(idx);
901 };
902 Parameters.push_back(new aFunc<decltype(f), 7>(f, fdmex, element, Prefix, var));
903 } else if (operation != "description") {
904 FGXMLLogging log(element, LogLevel::ERROR);
905 log << LogFormat::RED << LogFormat::BOLD
906 << "Bad operation <" << operation
907 << "> detected in configuration file\n" << LogFormat::RESET;
908 }
909
910 // Optimize functions applied on constant parameters by replacing them by
911 // their constant result.
912 if (!Parameters.empty()){
913 FGFunction* p = dynamic_cast<FGFunction*>(Parameters.back().ptr());
914
915 if (p && p->IsConstant()) {
916 double constant = p->GetValue();
917 SGPropertyNode_ptr node = p->pNode;
918 string pName = p->GetName();
919 unique_ptr<FGXMLLogging> log;
920
921 Parameters.pop_back();
922 Parameters.push_back(new FGRealValue(constant));
923
924 if (debug_lvl > 0) {
925 log.reset(new FGXMLLogging(element, LogLevel::DEBUG));
926 *log << LogFormat::GREEN << LogFormat::BOLD
927 << "<" << operation << "> is applied on constant parameters.\n"
928 << "It will be replaced by its result (" << constant << ")";
929 }
930
931 if (node) {
932 node->setDoubleValue(constant);
933 node->setAttribute(SGPropertyNode::WRITE, false);
934 if (debug_lvl > 0)
935 *log << " and the property " << pName
936 << " will be unbound and made read only.";
937 }
938
939 if (debug_lvl > 0) *log << LogFormat::RESET << "\n\n";
940 }
941 }
942 element = el->GetNextElement();
943 }
944
945 bind(el, Prefix); // Allow any function to save its value
946
947 Debug(0);
948}

Member Data Documentation

◆ cached

bool cached
protected

Definition at line 828 of file FGFunction.h.

◆ cachedValue

double cachedValue
protected

Definition at line 829 of file FGFunction.h.

◆ Parameters

std::vector<FGParameter_ptr> Parameters
protected

Definition at line 830 of file FGFunction.h.

◆ pNode

SGPropertyNode_ptr pNode
protected

Definition at line 832 of file FGFunction.h.

◆ PropertyManager

std::shared_ptr<FGPropertyManager> PropertyManager
protected

Definition at line 831 of file FGFunction.h.


The documentation for this class was generated from the following files: