JSBSim Flight Dynamics Model 1.0 (23 February 2013)
An Open Source Flight Dynamics and Control Software Library in C++

FGPropeller Class Reference

FGPropeller models a propeller given the tabular data for Ct and Cp, indexed by the advance ratio "J". More...

#include <FGPropeller.h>

Inheritance diagram for FGPropeller:
Collaboration diagram for FGPropeller:

List of all members.

Public Member Functions

 FGPropeller (FGFDMExec *exec, Element *el, int num=0)
 Constructor for FGPropeller.
 ~FGPropeller ()
 Destructor for FGPropeller - deletes the FGTable objects.
double Calculate (double EnginePower)
 Calculates and returns the thrust produced by this propeller.
int GetConstantSpeed (void) const
double GetCpFactor (void) const
 Retrieves the coefficient of power multiplier.
FGTableGetCpMachTable (void) const
 Retrieves propeller power Mach effects factor.
FGTableGetCPowerTable (void) const
 Retrieves propeller power table.
double GetCtFactor (void) const
 Retrieves the coefficient of thrust multiplier.
FGTableGetCThrustTable (void) const
 Retrieves propeller thrust table.
FGTableGetCtMachTable (void) const
 Retrieves propeller thrust Mach effects factor.
double GetDiameter (void) const
 Retrieves the propeller diameter.
double GetEngineRPM (void) const
 Calculates the RPMs of the engine based on gear ratio.
bool GetFeather (void) const
double GetHelicalTipMach (void) const
double GetInducedVelocity (void) const
double GetIxx (void) const
 Retrieves the propeller moment of inertia.
FGColumnVector3 GetPFactor (void) const
double GetPitch (void) const
 Retrieves the pitch of the propeller in degrees.
double GetPowerRequired (void)
 Retrieves the power required (or "absorbed") by the propeller - i.e.
bool GetReverse (void) const
double GetReverseCoef (void) const
double GetRPM (void) const
 Retrieves the RPMs of the propeller.
double GetThrustCoefficient (void) const
string GetThrusterLabels (int id, const string &delimeter)
string GetThrusterValues (int id, const string &delimeter)
double GetTorque (void) const
 Retrieves the Torque in foot-pounds (Don't you love the English system?)
bool IsVPitch (void) const
 Returns true of this propeller is variable pitch.
void SetAdvance (double advance)
void SetConstantSpeed (int mode)
 Sets propeller into constant speed mode, or manual pitch mode.
void SetCpFactor (double cpf)
 Sets coefficient of power multiplier.
void SetCtFactor (double ctf)
 Sets coefficient of thrust multiplier.
void SetEngineRPM (double rpm)
 Sets the Revolutions Per Minute for the propeller using the engine gear ratio.
void SetFeather (bool f)
void SetInducedVelocity (double Vi)
void SetPFactor (double pf)
 Sets the P-Factor constant.
void SetPitch (double pitch)
 This commands the pitch of the blade to change to the value supplied.
void SetReverse (bool r)
void SetReverseCoef (double c)
void SetRPM (double rpm)
 Sets the Revolutions Per Minute for the propeller.
void SetSense (double s)
 Sets the rotation sense of the propeller.

Detailed Description

Configuration File Format:

<sense> {1 | -1} </sense> 
<propeller name="{string}">
  <ixx> {number} </ixx>
  <diameter unit="IN"> {number} </diameter>
  <numblades> {number} </numblades>
  <gearratio> {number} </gearratio>
  <minpitch> {number} </minpitch>
  <maxpitch> {number} </maxpitch>
  <minrpm> {number} </minrpm>
  <maxrpm> {number} </maxrpm>
  <constspeed> {number} </constspeed>
  <reversepitch> {number} </reversepitch>
  <p_factor> {number} </p_factor>
  <ct_factor> {number} </ct_factor>
  <cp_factor> {number} </cp_factor>

  <table name="C_THRUST" type="internal">
    <tableData>
      {numbers}
    </tableData>
  </table>

  <table name="C_POWER" type="internal">
    <tableData>
      {numbers}
    </tableData>
  </table>

  <table name="CT_MACH" type="internal">
    <tableData>
      {numbers}
    </tableData>
  </table>

  <table name="CP_MACH" type="internal">
    <tableData>
      {numbers}
    </tableData>
  </table>


</propeller>

Configuration Parameters:

    <ixx>           - Propeller rotational inertia.
    <diameter>      - Propeller disk diameter.
    <numblades>     - Number of blades.
    <gearratio>     - Ratio of (engine rpm) / (prop rpm).
    <minpitch>      - Minimum blade pitch angle.
    <maxpitch>      - Maximum blade pitch angle.
    <minrpm>        - Minimum rpm target for constant speed propeller.
    <maxrpm>        - Maximum rpm target for constant speed propeller.
    <constspeed>    - 1 = constant speed mode, 0 = manual pitch mode. 
    <reversepitch>  - Blade pitch angle for reverse.
    <sense>         - Direction of rotation (1=clockwise as viewed from cockpit,
                        -1=anti-clockwise as viewed from cockpit). Sense is
                       specified in the parent tag of the propeller.
    <p_factor>      - P factor.
    <ct_factor>     - A multiplier for the coefficients of thrust.
    <cp_factor>     - A multiplier for the coefficients of power.

Two tables are needed. One for coefficient of thrust (Ct) and one for coefficient of power (Cp).

Two tables are optional. They apply a factor to Ct and Cp based on the helical tip Mach.

Several references were helpful, here:

  • Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics", Wiley & Sons, 1979 ISBN 0-471-03032-5
  • Edwin Hartman, David Biermann, "The Aerodynamic Characteristics of Full Scale Propellers Having 2, 3, and 4 Blades of Clark Y and R.A.F. 6 Airfoil Sections", NACA Report TN-640, 1938 (?)
  • Various NACA Technical Notes and Reports
Author:
Jon S. Berndt
Version:
Id:
FGPropeller.h,v 1.20 2011/10/31 14:54:41 bcoconni Exp
See also:
FGEngine
FGThruster

Definition at line 154 of file FGPropeller.h.


Constructor & Destructor Documentation

FGPropeller ( FGFDMExec exec,
Element el,
int  num = 0 
)
Parameters:
execa pointer to the main executive object
ela pointer to the thruster config file XML element
numthe number of this propeller

Definition at line 60 of file FGPropeller.cpp.

References Element::FindElement(), Element::FindElementValueAsNumber(), Element::FindElementValueAsNumberConvertTo(), Element::FindNextElement(), Element::GetAttributeValue(), Element::GetDataAsNumber(), FGPropeller::GetEngineRPM(), Element::GetParent(), FGFDMExec::GetPropertyManager(), FGPropeller::GetRPM(), FGPropeller::SetConstantSpeed(), FGPropeller::SetCpFactor(), FGPropeller::SetCtFactor(), FGPropeller::SetSense(), and FGPropertyManager::Tie().

                       : FGThruster(exec, prop_element, num)
{
  string token;
  Element *table_element, *local_element;
  string name="";
  FGPropertyManager* PropertyManager = exec->GetPropertyManager();

  MaxPitch = MinPitch = P_Factor = Pitch = Advance = MinRPM = MaxRPM = 0.0;
  Sense = 1; // default clockwise rotation
  ReversePitch = 0.0;
  Reversed = false;
  Feathered = false;
  Reverse_coef = 0.0;
  GearRatio = 1.0;
  CtFactor = CpFactor = 1.0;
  ConstantSpeed = 0;
  cThrust = cPower = CtMach = CpMach = 0;
  Vinduced = 0.0;

  if (prop_element->FindElement("ixx"))
    Ixx = prop_element->FindElementValueAsNumberConvertTo("ixx", "SLUG*FT2");
  if (prop_element->FindElement("diameter"))
    Diameter = prop_element->FindElementValueAsNumberConvertTo("diameter", "FT");
  if (prop_element->FindElement("numblades"))
    numBlades = (int)prop_element->FindElementValueAsNumber("numblades");
  if (prop_element->FindElement("gearratio"))
    GearRatio = prop_element->FindElementValueAsNumber("gearratio");
  if (prop_element->FindElement("minpitch"))
    MinPitch = prop_element->FindElementValueAsNumber("minpitch");
  if (prop_element->FindElement("maxpitch"))
    MaxPitch = prop_element->FindElementValueAsNumber("maxpitch");
  if (prop_element->FindElement("minrpm"))
    MinRPM = prop_element->FindElementValueAsNumber("minrpm");
  if (prop_element->FindElement("maxrpm")) {
    MaxRPM = prop_element->FindElementValueAsNumber("maxrpm");
    ConstantSpeed = 1;
    }
  if (prop_element->FindElement("constspeed"))
    ConstantSpeed = (int)prop_element->FindElementValueAsNumber("constspeed");
  if (prop_element->FindElement("reversepitch"))
    ReversePitch = prop_element->FindElementValueAsNumber("reversepitch");
  while((table_element = prop_element->FindNextElement("table")) != 0) {
    name = table_element->GetAttributeValue("name");
    try {
      if (name == "C_THRUST") {
        cThrust = new FGTable(PropertyManager, table_element);
      } else if (name == "C_POWER") {
        cPower = new FGTable(PropertyManager, table_element);
      } else if (name == "CT_MACH") {
        CtMach = new FGTable(PropertyManager, table_element);
      } else if (name == "CP_MACH") {
        CpMach = new FGTable(PropertyManager, table_element);
      } else {
        cerr << "Unknown table type: " << name << " in propeller definition." << endl;
      }
    } catch (std::string str) {
      throw("Error loading propeller table:" + name + ". " + str);
    }
  }
  if( (cPower == 0) || (cThrust == 0)){
      cerr << "Propeller configuration must contain C_THRUST and C_POWER tables!" << endl;
  }

  local_element = prop_element->GetParent()->FindElement("sense");
  if (local_element) {
    double Sense = local_element->GetDataAsNumber();
    SetSense(Sense >= 0.0 ? 1.0 : -1.0);
  }
  local_element = prop_element->GetParent()->FindElement("p_factor");
  if (local_element) {
    P_Factor = local_element->GetDataAsNumber();
  }
  if (P_Factor < 0) {
    cerr << "P-Factor value in propeller configuration file must be greater than zero" << endl;
  }
  if (prop_element->FindElement("ct_factor"))
    SetCtFactor( prop_element->FindElementValueAsNumber("ct_factor") );
  if (prop_element->FindElement("cp_factor"))
    SetCpFactor( prop_element->FindElementValueAsNumber("cp_factor") );

  Type = ttPropeller;
  RPM = 0;
  vTorque.InitMatrix();
  D4 = Diameter*Diameter*Diameter*Diameter;
  D5 = D4*Diameter;
  Pitch = MinPitch;

  string property_name, base_property_name;
  base_property_name = CreateIndexedPropertyName("propulsion/engine", EngineNum);
  property_name = base_property_name + "/engine-rpm";
  PropertyManager->Tie( property_name.c_str(), this, &FGPropeller::GetEngineRPM );
  property_name = base_property_name + "/advance-ratio";
  PropertyManager->Tie( property_name.c_str(), &J );
  property_name = base_property_name + "/blade-angle";
  PropertyManager->Tie( property_name.c_str(), &Pitch );
  property_name = base_property_name + "/thrust-coefficient";
  PropertyManager->Tie( property_name.c_str(), this, &FGPropeller::GetThrustCoefficient );
  property_name = base_property_name + "/propeller-rpm";
  PropertyManager->Tie( property_name.c_str(), this, &FGPropeller::GetRPM );
  property_name = base_property_name + "/helical-tip-Mach";
  PropertyManager->Tie( property_name.c_str(), this, &FGPropeller::GetHelicalTipMach );
  property_name = base_property_name + "/constant-speed-mode";
  PropertyManager->Tie( property_name.c_str(), this, &FGPropeller::GetConstantSpeed,
                      &FGPropeller::SetConstantSpeed );
  property_name = base_property_name + "/prop-induced-velocity_fps";
  PropertyManager->Tie( property_name.c_str(), this, &FGPropeller::GetInducedVelocity,
                      &FGPropeller::SetInducedVelocity );

  Debug(0);
}

Here is the call graph for this function:


Member Function Documentation

double Calculate ( double  EnginePower) [virtual]

Given the excess power available from the engine (in foot-pounds), the thrust is calculated, as well as the current RPM. The RPM is calculated by integrating the torque provided by the engine over what the propeller "absorbs" (essentially the "drag" of the propeller).

Parameters:
PowerAvailablethis is the excess power provided by the engine to accelerate the prop. It could be negative, dictating that the propeller would be slowed.
Returns:
the thrust in pounds

Reimplemented from FGThruster.

Definition at line 195 of file FGPropeller.cpp.

References FGPropeller::GetPowerRequired(), FGColumnVector3::Magnitude(), and FGMatrix33::Transposed().

{
  FGColumnVector3 localAeroVel = Transform().Transposed() * in.AeroUVW;
  double omega, PowerAvailable;

  double Vel = localAeroVel(eU);
  double rho = in.Density;
  double RPS = RPM/60.0;

  // Calculate helical tip Mach
  double Area = 0.25*Diameter*Diameter*M_PI;
  double Vtip = RPS * Diameter * M_PI;
  HelicalTipMach = sqrt(Vtip*Vtip + Vel*Vel) / in.Soundspeed;

  PowerAvailable = EnginePower - GetPowerRequired();

  if (RPS > 0.0) J = Vel / (Diameter * RPS); // Calculate J normally
  else           J = Vel / Diameter;

  if (MaxPitch == MinPitch) {    // Fixed pitch prop
    ThrustCoeff = cThrust->GetValue(J);
  } else {                       // Variable pitch prop
    ThrustCoeff = cThrust->GetValue(J, Pitch);
  }

  // Apply optional scaling factor to Ct (default value = 1)
  ThrustCoeff *= CtFactor;

  // Apply optional Mach effects from CT_MACH table
  if (CtMach) ThrustCoeff *= CtMach->GetValue(HelicalTipMach);

  Thrust = ThrustCoeff*RPS*RPS*D4*rho;

  // Induced velocity in the propeller disk area. This formula is obtained
  // from momentum theory - see B. W. McCormick, "Aerodynamics, Aeronautics,
  // and Flight Mechanics" 1st edition, eqn. 6.15 (propeller analysis chapter).
  // Since Thrust and Vel can both be negative we need to adjust this formula
  // To handle sign (direction) separately from magnitude.
  double Vel2sum = Vel*abs(Vel) + 2.0*Thrust/(rho*Area);
  
  if( Vel2sum > 0.0)
    Vinduced = 0.5 * (-Vel + sqrt(Vel2sum));
  else
    Vinduced = 0.5 * (-Vel - sqrt(-Vel2sum));

  // We need to drop the case where the downstream velocity is opposite in
  // direction to the aircraft velocity. For example, in such a case, the
  // direction of the airflow on the tail would be opposite to the airflow on
  // the wing tips. When such complicated airflows occur, the momentum theory
  // breaks down and the formulas above are no longer applicable
  // (see H. Glauert, "The Elements of Airfoil and Airscrew Theory",
  // 2nd edition, ยง16.3, pp. 219-221)

  if ((Vel+2.0*Vinduced)*Vel < 0.0) {
    // The momentum theory is no longer applicable so let's assume the induced
    // saturates to -0.5*Vel so that the total velocity Vel+2*Vinduced equals 0.
    Vinduced = -0.5*Vel;
  }
    
  // P-factor is simulated by a shift of the acting location of the thrust.
  // The shift is a multiple of the angle between the propeller shaft axis
  // and the relative wind that goes through the propeller disk.
  if (P_Factor > 0.0001) {
    double tangentialVel = localAeroVel.Magnitude(eV, eW);

    if (tangentialVel > 0.0001) {
      double angle = atan2(tangentialVel, localAeroVel(eU));
      double factor = Sense * P_Factor * angle / tangentialVel;
      SetActingLocationY( GetLocationY() + factor * localAeroVel(eW));
      SetActingLocationZ( GetLocationZ() + factor * localAeroVel(eV));
    }
  }

  omega = RPS*2.0*M_PI;

  vFn(eX) = Thrust;

  // The Ixx value and rotation speed given below are for rotation about the
  // natural axis of the engine. The transform takes place in the base class
  // FGForce::GetBodyForces() function.

  vH(eX) = Ixx*omega*Sense;
  vH(eY) = 0.0;
  vH(eZ) = 0.0;

  if (omega > 0.0) ExcessTorque = PowerAvailable / omega;
  else             ExcessTorque = PowerAvailable / 1.0;

  RPM = (RPS + ((ExcessTorque / Ixx) / (2.0 * M_PI)) * deltaT) * 60.0;

  if (RPM < 0.0) RPM = 0.0; // Engine won't turn backwards

  // Transform Torque and momentum first, as PQR is used in this
  // equation and cannot be transformed itself.
  vMn = in.PQR*(Transform()*vH) + Transform()*vTorque;

  return Thrust; // return thrust in pounds
}

Here is the call graph for this function:

double GetPowerRequired ( void  ) [virtual]

the power required to keep spinning the propeller at the current velocity, air density, and rotational rate.

Reimplemented from FGThruster.

Definition at line 296 of file FGPropeller.cpp.

Referenced by FGPropeller::Calculate().

{
  double cPReq, J;
  double rho = in.Density;
  double Vel = in.AeroUVW(eU);
  double RPS = RPM / 60.0;

  if (RPS != 0.0) J = Vel / (Diameter * RPS);
  else            J = Vel / Diameter;

  if (MaxPitch == MinPitch) {   // Fixed pitch prop
    cPReq = cPower->GetValue(J);

  } else {                      // Variable pitch prop

    if (ConstantSpeed != 0) {   // Constant Speed Mode

      // do normal calculation when propeller is neither feathered nor reversed
      // Note:  This method of feathering and reversing was added to support the
      //        turboprop model.  It's left here for backward compatablity, but
      //        now feathering and reversing should be done in Manual Pitch Mode.
      if (!Feathered) {
        if (!Reversed) {

          double rpmReq = MinRPM + (MaxRPM - MinRPM) * Advance;
          double dRPM = rpmReq - RPM;
          // The pitch of a variable propeller cannot be changed when the RPMs are
          // too low - the oil pump does not work.
          if (RPM > 200) Pitch -= dRPM * deltaT;
          if (Pitch < MinPitch)       Pitch = MinPitch;
          else if (Pitch > MaxPitch)  Pitch = MaxPitch;

        } else { // Reversed propeller

          // when reversed calculate propeller pitch depending on throttle lever position
          // (beta range for taxing full reverse for braking)
          double PitchReq = MinPitch - ( MinPitch - ReversePitch ) * Reverse_coef;
          // The pitch of a variable propeller cannot be changed when the RPMs are
          // too low - the oil pump does not work.
          if (RPM > 200) Pitch += (PitchReq - Pitch) / 200;
          if (RPM > MaxRPM) {
            Pitch += (MaxRPM - RPM) / 50;
            if (Pitch < ReversePitch) Pitch = ReversePitch;
            else if (Pitch > MaxPitch)  Pitch = MaxPitch;
          }
        }

      } else { // Feathered propeller
               // ToDo: Make feathered and reverse settings done via FGKinemat
        Pitch += (MaxPitch - Pitch) / 300; // just a guess (about 5 sec to fully feathered)
      }

    } else { // Manual Pitch Mode, pitch is controlled externally

    }

    cPReq = cPower->GetValue(J, Pitch);
  }

  // Apply optional scaling factor to Cp (default value = 1)
  cPReq *= CpFactor;

  // Apply optional Mach effects from CP_MACH table
  if (CpMach) cPReq *= CpMach->GetValue(HelicalTipMach);

  double local_RPS = RPS < 0.01 ? 0.01 : RPS; 

  PowerRequired = cPReq*local_RPS*RPS*local_RPS*D5*rho;
  vTorque(eX) = -Sense*PowerRequired / (local_RPS*2.0*M_PI);

  return PowerRequired;
}

Here is the caller graph for this function:

void SetPitch ( double  pitch) [inline]

This call is meant to be issued either from the cockpit or by the flight control system (perhaps to maintain constant RPM for a constant-speed propeller). This value will be limited to be within whatever is specified in the config file for Max and Min pitch. It is also one of the lookup indices to the power and thrust tables for variable-pitch propellers.

Parameters:
pitchthe pitch of the blade in degrees.

Reimplemented from FGForce.

Definition at line 187 of file FGPropeller.h.

{Pitch = pitch;}
void SetRPM ( double  rpm) [inline, virtual]

Normally the propeller instance will calculate its own rotational velocity, given the Torque produced by the engine and integrating over time using the standard equation for rotational acceleration "a": a = Q/I , where Q is Torque and I is moment of inertia for the propeller.

Parameters:
rpmthe rotational velocity of the propeller

Reimplemented from FGThruster.

Definition at line 172 of file FGPropeller.h.

{RPM = rpm;}
void SetSense ( double  s) [inline]
Parameters:
sthis value should be +/- 1 ONLY. +1 indicates clockwise rotation as viewed by someone standing behind the engine looking forward into the direction of flight.

Definition at line 207 of file FGPropeller.h.

Referenced by FGPropeller::FGPropeller().

{ Sense = s;}

Here is the caller graph for this function:


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