41 #include "FGFDMExec.h"
42 #include "FGPropeller.h"
43 #include "input_output/FGXMLElement.h"
44 #include "models/FGMassBalance.h"
57 Element *table_element, *local_element;
61 MaxPitch = MinPitch = P_Factor = Pitch = Advance = MinRPM = MaxRPM = 0.0;
68 CtFactor = CpFactor = 1.0;
70 cThrust = cPower = CtMach = CpMach = 0;
76 Sense_multiplier = 1.0;
79 Sense_multiplier = -1.0;
104 if (name ==
"C_THRUST") {
105 cThrust =
new FGTable(PropertyManager, table_element);
106 }
else if (name ==
"C_POWER") {
107 cPower =
new FGTable(PropertyManager, table_element);
108 }
else if (name ==
"CT_MACH") {
109 CtMach =
new FGTable(PropertyManager, table_element);
110 }
else if (name ==
"CP_MACH") {
111 CpMach =
new FGTable(PropertyManager, table_element);
113 cerr <<
"Unknown table type: " << name <<
" in propeller definition." << endl;
115 }
catch (std::string& str) {
116 throw(
"Error loading propeller table:" + name +
". " + str);
119 if( (cPower == 0) || (cThrust == 0)){
120 cerr <<
"Propeller configuration must contain C_THRUST and C_POWER tables!" << endl;
126 SetSense(Sense >= 0.0 ? 1.0 : -1.0);
133 cerr <<
"P-Factor value in propeller configuration file must be greater than zero" << endl;
142 vTorque.InitMatrix();
143 D4 = Diameter*Diameter*Diameter*Diameter;
147 string property_name, base_property_name;
148 base_property_name = CreateIndexedPropertyName(
"propulsion/engine", EngineNum);
149 property_name = base_property_name +
"/engine-rpm";
151 property_name = base_property_name +
"/advance-ratio";
152 PropertyManager->
Tie( property_name.c_str(), &J );
153 property_name = base_property_name +
"/blade-angle";
154 PropertyManager->
Tie( property_name.c_str(), &Pitch );
155 property_name = base_property_name +
"/thrust-coefficient";
157 property_name = base_property_name +
"/propeller-rpm";
159 property_name = base_property_name +
"/helical-tip-Mach";
161 property_name = base_property_name +
"/constant-speed-mode";
164 property_name = base_property_name +
"/prop-induced-velocity_fps";
167 property_name = base_property_name +
"/propeller-power-ftlbps";
168 PropertyManager->
Tie( property_name.c_str(), &PowerRequired );
169 property_name = base_property_name +
"/propeller-torque-ftlb";
171 property_name = base_property_name +
"/propeller-sense";
172 PropertyManager->
Tie( property_name.c_str(), &Sense );
193 FGThruster::ResetToIC();
217 double omega, PowerAvailable;
219 double Vel = localAeroVel(eU);
220 double rho = in.Density;
221 double RPS = RPM/60.0;
224 double Area = 0.25*Diameter*Diameter*M_PI;
225 double Vtip = RPS * Diameter * M_PI;
226 HelicalTipMach = sqrt(Vtip*Vtip + Vel*Vel) / in.Soundspeed;
228 if (RPS > 0.01) J = Vel / (Diameter * RPS);
229 else J = Vel / Diameter;
233 if (MaxPitch == MinPitch) {
234 ThrustCoeff = cThrust->GetValue(J);
236 ThrustCoeff = cThrust->GetValue(J, Pitch);
240 ThrustCoeff *= CtFactor;
243 if (CtMach) ThrustCoeff *= CtMach->GetValue(HelicalTipMach);
245 Thrust = ThrustCoeff*RPS*RPS*D4*rho;
252 double Vel2sum = Vel*abs(Vel) + 2.0*Thrust/(rho*Area);
255 Vinduced = 0.5 * (-Vel + sqrt(Vel2sum));
257 Vinduced = 0.5 * (-Vel - sqrt(-Vel2sum));
262 if (P_Factor > 0.0001) {
263 double tangentialVel = localAeroVel.
Magnitude(eV, eW);
265 if (tangentialVel > 0.0001) {
269 double angle = atan2(tangentialVel, Vel+Vinduced);
270 double factor = Sense * P_Factor * angle / tangentialVel;
271 SetActingLocationY( GetLocationY() + factor * localAeroVel(eW));
272 SetActingLocationZ( GetLocationZ() + factor * localAeroVel(eV));
276 omega = RPS*2.0*M_PI;
279 vTorque(eX) = -Sense*EnginePower / max(0.01, omega);
287 if (omega > 0.01) ExcessTorque = PowerAvailable / omega;
288 else ExcessTorque = PowerAvailable / 1.0;
290 RPM = (RPS + ((ExcessTorque / Ixx) / (2.0 * M_PI)) * in.TotalDeltaT) * 60.0;
292 if (RPM < 0.0) RPM = 0.0;
296 vMn = in.PQRi*(mT*vH) + mT*vTorque;
307 if (MaxPitch == MinPitch) {
308 cPReq = cPower->GetValue(J);
312 if (ConstantSpeed != 0) {
321 double rpmReq = MinRPM + (MaxRPM - MinRPM) * Advance;
322 double dRPM = rpmReq - RPM;
325 if (RPM > 200) Pitch -= dRPM * in.TotalDeltaT;
326 if (Pitch < MinPitch) Pitch = MinPitch;
327 else if (Pitch > MaxPitch) Pitch = MaxPitch;
333 double PitchReq = MinPitch - ( MinPitch - ReversePitch ) * Reverse_coef;
336 if (RPM > 200) Pitch += (PitchReq - Pitch) / 200;
338 Pitch += (MaxRPM - RPM) / 50;
339 if (Pitch < ReversePitch) Pitch = ReversePitch;
340 else if (Pitch > MaxPitch) Pitch = MaxPitch;
346 Pitch += (MaxPitch - Pitch) / 300;
353 cPReq = cPower->GetValue(J, Pitch);
360 if (CpMach) cPReq *= CpMach->GetValue(HelicalTipMach);
362 double RPS = RPM / 60.0;
363 double local_RPS = RPS < 0.01 ? 0.01 : RPS;
365 PowerRequired = cPReq*local_RPS*local_RPS*local_RPS*D5*in.Density;
367 return PowerRequired;
376 double p_pitch = Thrust * Sense * (GetActingLocationZ() - GetLocationZ()) / 12.0;
378 double p_yaw = Thrust * Sense * (GetActingLocationY() - GetLocationY()) / 12.0;
387 std::ostringstream buf;
389 buf << Name <<
" Torque (engine " <<
id <<
")" << delimeter
390 << Name <<
" PFactor Pitch (engine " <<
id <<
")" << delimeter
391 << Name <<
" PFactor Yaw (engine " <<
id <<
")" << delimeter
392 << Name <<
" Thrust (engine " <<
id <<
" in lbs)" << delimeter;
394 buf << Name <<
" Pitch (engine " <<
id <<
")" << delimeter;
395 buf << Name <<
" RPM (engine " <<
id <<
")";
404 std::ostringstream buf;
407 buf << vTorque(eX) << delimeter
408 << vPFactor(ePitch) << delimeter
409 << vPFactor(eYaw) << delimeter
410 << Thrust << delimeter;
412 buf << Pitch << delimeter;
437 void FGPropeller::Debug(
int from)
439 if (debug_lvl <= 0)
return;
443 cout <<
"\n Propeller Name: " << Name << endl;
444 cout <<
" IXX = " << Ixx << endl;
445 cout <<
" Diameter = " << Diameter <<
" ft." << endl;
446 cout <<
" Number of Blades = " << numBlades << endl;
447 cout <<
" Gear Ratio = " << GearRatio << endl;
448 cout <<
" Minimum Pitch = " << MinPitch << endl;
449 cout <<
" Maximum Pitch = " << MaxPitch << endl;
450 cout <<
" Minimum RPM = " << MinRPM << endl;
451 cout <<
" Maximum RPM = " << MaxRPM << endl;
473 if (debug_lvl & 2 ) {
474 if (from == 0) cout <<
"Instantiated: FGPropeller" << endl;
475 if (from == 1) cout <<
"Destroyed: FGPropeller" << endl;
477 if (debug_lvl & 4 ) {
479 if (debug_lvl & 8 ) {
481 if (debug_lvl & 16) {
483 if (debug_lvl & 64) {