39#include "FGPropeller.h"
40#include "input_output/FGXMLElement.h"
41#include "input_output/FGLog.h"
54 Element *table_element, *local_element;
58 MaxPitch = MinPitch = P_Factor = Advance = MinRPM = MaxRPM = 0.0;
65 CtFactor = CpFactor = 1.0;
67 cThrust = cPower = CtMach = CpMach = cThrustRPM = cPowerRPM = 0;
72 Sense_multiplier = 1.0;
75 Sense_multiplier = -1.0;
100 if (name ==
"C_THRUST") {
101 cThrust =
new FGTable(PropertyManager, table_element);
102 }
else if (name ==
"C_POWER") {
103 cPower =
new FGTable(PropertyManager, table_element);
104 }
else if (name ==
"CT_MACH") {
105 CtMach =
new FGTable(PropertyManager, table_element);
106 }
else if (name ==
"CP_MACH") {
107 CpMach =
new FGTable(PropertyManager, table_element);
108 }
else if (name ==
"CT_RPM_FACTOR") {
109 cThrustRPM =
new FGTable(PropertyManager, table_element);
110 }
else if (name ==
"CP_RPM_FACTOR") {
111 cPowerRPM =
new FGTable(PropertyManager, table_element);
114 log <<
"Unknown table type: " << name <<
" in propeller definition.\n";
118 err <<
"Error loading propeller table:" << name <<
". " << e.what() <<
"\n";
122 if( (cPower ==
nullptr) || (cThrust ==
nullptr)){
124 err <<
"Propeller configuration must contain C_THRUST and C_POWER tables!\n";
131 SetSense(Sense >= 0.0 ? 1.0 : -1.0);
139 err <<
"P-Factor value in propeller configuration file must be greater than zero\n";
148 vTorque.InitMatrix();
149 D4 = Diameter*Diameter*Diameter*Diameter;
153 string property_name, base_property_name;
154 base_property_name = CreateIndexedPropertyName(
"propulsion/engine", EngineNum);
155 property_name = base_property_name +
"/engine-rpm";
157 property_name = base_property_name +
"/advance-ratio";
158 PropertyManager->Tie( property_name.c_str(), &J );
159 property_name = base_property_name +
"/blade-angle";
160 PropertyManager->Tie( property_name.c_str(), &Pitch );
161 property_name = base_property_name +
"/thrust-coefficient";
163 property_name = base_property_name +
"/propeller-rpm";
165 property_name = base_property_name +
"/helical-tip-Mach";
167 property_name = base_property_name +
"/constant-speed-mode";
170 property_name = base_property_name +
"/prop-induced-velocity_fps";
173 property_name = base_property_name +
"/propeller-power-ftlbps";
174 PropertyManager->Tie( property_name.c_str(), &PowerRequired );
175 property_name = base_property_name +
"/propeller-torque-ftlb";
177 property_name = base_property_name +
"/propeller-sense";
178 PropertyManager->Tie( property_name.c_str(), &Sense );
201 FGThruster::ResetToIC();
207void FGPropeller::InitDynamics(
void)
234 double omega, PowerAvailable;
236 double Vel = localAeroVel(eU);
237 double rho = in.Density;
238 double RPS = RPM/60.0;
241 double Area = 0.25*Diameter*Diameter*M_PI;
242 double Vtip = RPS * Diameter * M_PI;
243 HelicalTipMach = sqrt(Vtip*Vtip + Vel*Vel) / in.Soundspeed;
245 if (RPS > 0.01) J = Vel / (Diameter * RPS);
246 else J = Vel / Diameter;
250 if (MaxPitch == MinPitch) {
253 ThrustCoeff = cThrust->
GetValue(J, Pitch);
257 ThrustCoeff *= CtFactor;
260 if (CtMach) ThrustCoeff *= CtMach->
GetValue(HelicalTipMach);
263 if (cThrustRPM) ThrustCoeff *= cThrustRPM->
GetValue(RPM);
265 Thrust = ThrustCoeff*RPS*RPS*D4*rho;
272 double Vel2sum = Vel*abs(Vel) + 2.0*Thrust/(rho*Area);
275 Vinduced = 0.5 * (-Vel + sqrt(Vel2sum));
277 Vinduced = 0.5 * (-Vel - sqrt(-Vel2sum));
282 if (P_Factor > 0.0001) {
283 double tangentialVel = localAeroVel.
Magnitude(eV, eW);
285 if (tangentialVel > 0.0001) {
289 double angle = atan2(tangentialVel, Vel+Vinduced);
290 double factor = Sense * P_Factor * angle / tangentialVel;
291 SetActingLocationY( GetLocationY() + factor * localAeroVel(eW));
292 SetActingLocationZ( GetLocationZ() + factor * localAeroVel(eV));
296 omega = RPS*2.0*M_PI;
299 vTorque(eX) = -Sense*EnginePower / max(0.01, omega);
307 if (omega > 0.01) ExcessTorque = PowerAvailable / omega;
308 else ExcessTorque = PowerAvailable / 1.0;
310 RPM = (RPS + ((ExcessTorque / Ixx) / (2.0 * M_PI)) * in.TotalDeltaT) * 60.0;
312 if (RPM < 0.0) RPM = 0.0;
316 vMn = in.PQRi*(mT*vH) + mT*vTorque;
327 if (MaxPitch == MinPitch) {
332 if (ConstantSpeed != 0) {
341 double rpmReq = MinRPM + (MaxRPM - MinRPM) * Advance;
342 double dRPM = rpmReq - RPM;
345 if (RPM > 200) Pitch -= dRPM * in.TotalDeltaT;
346 if (Pitch < MinPitch) Pitch = MinPitch;
347 else if (Pitch > MaxPitch) Pitch = MaxPitch;
353 double PitchReq = MinPitch - ( MinPitch - ReversePitch ) * Reverse_coef;
356 if (RPM > 200) Pitch += (PitchReq - Pitch) / 200;
358 Pitch += (MaxRPM - RPM) / 50;
359 if (Pitch < ReversePitch) Pitch = ReversePitch;
360 else if (Pitch > MaxPitch) Pitch = MaxPitch;
366 Pitch += (MaxPitch - Pitch) / 300;
380 if (CpMach) cPReq *= CpMach->
GetValue(HelicalTipMach);
383 if (cPowerRPM) cPReq *= cPowerRPM->
GetValue(RPM);
385 double RPS = RPM / 60.0;
386 double local_RPS = RPS < 0.01 ? 0.01 : RPS;
388 PowerRequired = cPReq*local_RPS*local_RPS*local_RPS*D5*in.Density;
390 return PowerRequired;
399 double p_pitch = Thrust * Sense * (GetActingLocationZ() - GetLocationZ()) / 12.0;
401 double p_yaw = Thrust * Sense * (GetActingLocationY() - GetLocationY()) / 12.0;
410 std::ostringstream buf;
412 buf << Name <<
" Torque (engine " <<
id <<
")" << delimeter
413 << Name <<
" PFactor Pitch (engine " <<
id <<
")" << delimeter
414 << Name <<
" PFactor Yaw (engine " <<
id <<
")" << delimeter
415 << Name <<
" Thrust (engine " <<
id <<
" in lbs)" << delimeter;
417 buf << Name <<
" Pitch (engine " <<
id <<
")" << delimeter;
418 buf << Name <<
" RPM (engine " <<
id <<
")";
427 std::ostringstream buf;
430 buf << vTorque(eX) << delimeter
431 << vPFactor(ePitch) << delimeter
432 << vPFactor(eYaw) << delimeter
433 << Thrust << delimeter;
435 buf << Pitch << delimeter;
460void FGPropeller::Debug(
int from)
462 if (debug_lvl <= 0)
return;
467 log <<
"\n Propeller Name: " << Name <<
"\n";
468 log <<
" IXX = " << Ixx <<
"\n";
469 log <<
" Diameter = " << Diameter <<
" ft." <<
"\n";
470 log <<
" Number of Blades = " << numBlades <<
"\n";
471 log <<
" Gear Ratio = " << GearRatio <<
"\n";
472 log <<
" Minimum Pitch = " << MinPitch <<
"\n";
473 log <<
" Maximum Pitch = " << MaxPitch <<
"\n";
474 log <<
" Minimum RPM = " << MinRPM <<
"\n";
475 log <<
" Maximum RPM = " << MaxRPM <<
"\n";
478 if (debug_lvl & 2 ) {
479 FGLogging log(LogLevel::DEBUG);
480 if (from == 0) log <<
"Instantiated: FGPropeller\n";
481 if (from == 1) log <<
"Destroyed: FGPropeller\n";
483 if (debug_lvl & 4 ) {
485 if (debug_lvl & 8 ) {
487 if (debug_lvl & 16) {
489 if (debug_lvl & 64) {
Element * FindElement(const std::string &el="")
Searches for a specified element.
double GetAttributeValueAsNumber(const std::string &key)
Retrieves an attribute value as a double precision real number.
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
Element * GetParent(void)
Returns a pointer to the parent of an element.
double FindElementValueAsNumberConvertTo(const std::string &el, const std::string &target_units)
Searches for the named element and converts and returns the data belonging to it.
Element * FindNextElement(const std::string &el="")
Searches for the next element as specified.
double GetDataAsNumber(void)
Converts the element data to a number.
bool HasAttribute(const std::string &key)
Determines if an element has the supplied attribute.
double FindElementValueAsNumber(const std::string &el="")
Searches for the named element and returns the data belonging to it as a number.
This class implements a 3 element column vector.
double Magnitude(void) const
Length of the vector.
Encapsulates the JSBSim simulation executive.
std::shared_ptr< FGPropertyManager > GetPropertyManager(void) const
Returns a pointer to the property manager object.
Handles matrix math operations.
FGMatrix33 Transposed(void) const
Transposed matrix.
void SetInducedVelocity(double Vi)
Set the propeller induced velocity.
~FGPropeller()
Destructor for FGPropeller - deletes the FGTable objects.
double Calculate(double EnginePower)
Calculates and returns the thrust produced by this propeller.
double GetPowerRequired(void)
Retrieves the power required (or "absorbed") by the propeller - i.e.
int GetConstantSpeed(void) const
Returns a non-zero value if the propeller is constant speed.
double GetRPM(void) const
Retrieves the RPMs of the propeller.
std::string GetThrusterValues(int id, const std::string &delimeter)
Generate the values for the thruster standard CSV output.
void ResetToIC(void)
Reset the initial conditions.
void SetCtFactor(double ctf)
Sets coefficient of thrust multiplier.
void SetConstantSpeed(int mode)
Sets propeller into constant speed mode, or manual pitch mode.
FGColumnVector3 GetPFactor(void) const
Retrieves the P-Factor constant.
void SetCpFactor(double cpf)
Sets coefficient of power multiplier.
double GetInducedVelocity(void) const
Get the propeller induced velocity.
void SetSense(double s)
Sets the rotation sense of the propeller.
double GetHelicalTipMach(void) const
Retrieves the Mach number at the propeller tips.
std::string GetThrusterLabels(int id, const std::string &delimeter)
Generate the labels for the thruster standard CSV output.
double GetTorque(void) const
Retrieves the Torque in foot-pounds (Don't you love the English system?)
double GetEngineRPM(void) const
Calculates the RPMs of the engine based on gear ratio.
FGPropeller(FGFDMExec *exec, Element *el, int num=0)
Constructor for FGPropeller.
bool IsVPitch(void) const
Returns true of this propeller is variable pitch.
double GetThrustCoefficient(void) const
Retrieves the thrust coefficient.
double GetValue(void) const
Get the current table value.
Base class for specific thrusting devices such as propellers, nozzles, etc.
Main namespace for the JSBSim Flight Dynamics Model.