48 #include "FGTurboProp.h" 49 #include "FGPropeller.h" 51 #include "math/FGFunction.h" 52 #include "input_output/FGXMLElement.h" 58 IDENT(IdSrc,
"$Id: FGTurboProp.cpp,v 1.36 2017/02/26 11:41:28 bcoconni Exp $");
59 IDENT(IdHdr,ID_TURBOPROP);
67 ITT_N1(NULL), EnginePowerRPM_N1(NULL), EnginePowerVC(NULL),
68 CombustionEfficiency_N1(NULL)
80 delete EnginePowerRPM_N1;
81 if (dynamic_cast<FGTable*>(EnginePowerVC))
83 delete CombustionEfficiency_N1;
91 MaxStartingTime = 999999;
96 while(function_element) {
98 if (name ==
"EnginePowerVC")
99 function_element->
SetAttributeValue(
"name",
string(
"propulsion/engine[#]/") + name);
104 FGEngine::Load(exec, el);
105 thrusterType = Thruster->GetType();
107 string property_prefix = CreateIndexedPropertyName(
"propulsion/engine", EngineNumber);
120 BetaRangeThrottleEnd =
Constrain(0.0, BetaRangeThrottleEnd, 0.99999);
127 cerr << el->
ReadFrom() <<
"Note: 'idlefuelflow' is obsolete, " 128 <<
"use the 'CombustionEfficiency_N1' table instead." << endl;
146 while (table_element) {
148 if (!EnginePowerVC && name ==
"EnginePowerVC") {
149 EnginePowerVC =
new FGTable(PropertyManager, table_element);
151 <<
"Note: Using the EnginePowerVC without enclosed <function> tag is deprecated" 153 }
else if (name ==
"EnginePowerRPM_N1") {
154 EnginePowerRPM_N1 =
new FGTable(PropertyManager, table_element);
155 }
else if (name ==
"ITT_N1") {
156 ITT_N1 =
new FGTable(PropertyManager, table_element);
157 }
else if (name ==
"CombustionEfficiency_N1") {
158 CombustionEfficiency_N1 =
new FGTable(PropertyManager, table_element);
160 cerr << el->
ReadFrom() <<
"Unknown table type: " << name
161 <<
" in turboprop definition." << endl;
169 N1_factor = MaxN1 - IdleN1;
170 OilTemp_degK = in.TAT_c + 273.0;
174 if (! CombustionEfficiency_N1) {
175 CombustionEfficiency_N1 =
new FGTable(6);
176 *CombustionEfficiency_N1 << 60.0 << 12.0/52.0;
177 *CombustionEfficiency_N1 << 82.0 << 12.0/30.0;
178 *CombustionEfficiency_N1 << 96.0 << 12.0/16.0;
179 *CombustionEfficiency_N1 << 100.0 << 1.0;
180 *CombustionEfficiency_N1 << 104.0 << 1.5;
181 *CombustionEfficiency_N1 << 110.0 << 6.0;
184 bindmodel(PropertyManager);
196 ThrottlePos = in.ThrottlePos[EngineNumber];
200 RPM = Thruster->GetEngineRPM();
201 if (thrusterType == FGThruster::ttPropeller) {
202 ((
FGPropeller*)Thruster)->SetAdvance(in.PropAdvance[EngineNumber]);
203 ((
FGPropeller*)Thruster)->SetFeather(in.PropFeather[EngineNumber]);
206 ((
FGPropeller*)Thruster)->SetReverseCoef(ThrottlePos);
212 if (ThrottlePos < BetaRangeThrottleEnd) {
216 ThrottlePos = (ThrottlePos-BetaRangeThrottleEnd)/(1-BetaRangeThrottleEnd) * ReverseMaxPower;
222 if ((phase == tpTrim) && (in.TotalDeltaT > 0)) {
223 if (Running && !Starved) {
226 OilTemp_degK = 366.0;
231 Eng_ITT_degC = in.TAT_c;
232 Eng_Temperature = in.TAT_c;
233 OilTemp_degK = in.TAT_c+273.15;
237 if (!Running && Starter) {
238 if (phase == tpOff) {
240 if (StartTime < 0) StartTime=0;
243 if (!Running && !Cutoff && (N1 > 15.0)) {
247 if (Cutoff && (phase != tpSpinUp)) phase = tpOff;
248 if (in.TotalDeltaT == 0) phase = tpTrim;
249 if (Starved) phase = tpOff;
250 if (Condition >= 10) {
256 if (Ielu_max_torque > 0.0) {
259 if (thrusterType == FGThruster::ttPropeller) {
261 }
else if (thrusterType == FGThruster::ttRotor) {
262 torque = ((
FGRotor*)(Thruster))->GetTorque();
266 if ( abs(torque) > Ielu_max_torque && ThrottlePos >= OldThrottle ) {
267 ThrottlePos = OldThrottle - 0.1 * in.TotalDeltaT;
268 Ielu_intervent =
true;
269 }
else if ( Ielu_intervent && ThrottlePos >= OldThrottle) {
270 ThrottlePos = OldThrottle + 0.05 * in.TotalDeltaT;
271 Ielu_intervent =
true;
273 Ielu_intervent =
false;
276 Ielu_intervent =
false;
278 OldThrottle = ThrottlePos;
282 case tpOff: HP = Off();
break;
283 case tpRun: HP = Run();
break;
284 case tpSpinUp: HP = SpinUp();
break;
285 case tpStart: HP = Start();
break;
289 LoadThrusterInputs();
290 Thruster->Calculate(HP * hptoftlbssec);
297 double FGTurboProp::Off(
void)
299 Running =
false; EngStarting =
false;
301 FuelFlow_pph = Seek(&FuelFlow_pph, 0, 800.0, 800.0);
304 N1 = ExpSeek(&N1, in.qbar/15.0, Idle_Max_Delay*2.5, Idle_Max_Delay * 5);
306 OilTemp_degK = ExpSeek(&OilTemp_degK,273.15 + in.TAT_c, 400 , 400);
308 Eng_Temperature = ExpSeek(&Eng_Temperature,in.TAT_c,300,400);
309 double ITT_goal = ITT_N1->GetValue(N1,0.1) + ((N1>20) ? 0.0 : (20-N1)/20.0 * Eng_Temperature);
310 Eng_ITT_degC = ExpSeek(&Eng_ITT_degC,ITT_goal,ITT_Delay,ITT_Delay*1.2);
312 OilPressure_psi = (N1/100.0*0.25+(0.1-(OilTemp_degK-273.15)*0.1/80.0)*N1/100.0) / 7692.0e-6;
314 if (RPM>5)
return -0.012;
320 double FGTurboProp::Run(
void)
324 Running =
true; Starter =
false; EngStarting =
false;
328 N1 = ExpSeek(&N1, IdleN1 + ThrottlePos * N1_factor, Idle_Max_Delay, Idle_Max_Delay * 2.4);
330 EngPower_HP = EnginePowerRPM_N1->GetValue(RPM,N1);
331 EngPower_HP *= EnginePowerVC->GetValue();
332 if (EngPower_HP > MaxPower) EngPower_HP = MaxPower;
334 CombustionEfficiency = CombustionEfficiency_N1->GetValue(N1);
335 FuelFlow_pph = PSFC / CombustionEfficiency * EngPower_HP;
337 Eng_Temperature = ExpSeek(&Eng_Temperature,Eng_ITT_degC,300,400);
338 double ITT_goal = ITT_N1->GetValue((N1-old_N1)*300+N1,1);
339 Eng_ITT_degC = ExpSeek(&Eng_ITT_degC,ITT_goal,ITT_Delay,ITT_Delay*1.2);
341 OilPressure_psi = (N1/100.0*0.25+(0.1-(OilTemp_degK-273.15)*0.1/80.0)*N1/100.0) / 7692.0e-6;
344 OilTemp_degK = Seek(&OilTemp_degK, 353.15, 0.4-N1*0.001, 0.04);
346 if (Cutoff) phase = tpOff;
347 if (Starved) phase = tpOff;
354 double FGTurboProp::SpinUp(
void)
357 Running =
false; EngStarting =
true;
360 if (!GeneratorPower) {
367 N1 = ExpSeek(&N1, StarterN1, Idle_Max_Delay * 6, Idle_Max_Delay * 2.4);
369 Eng_Temperature = ExpSeek(&Eng_Temperature,in.TAT_c,300,400);
370 double ITT_goal = ITT_N1->GetValue(N1,0.1) + ((N1>20) ? 0.0 : (20-N1)/20.0 * Eng_Temperature);
371 Eng_ITT_degC = ExpSeek(&Eng_ITT_degC,ITT_goal,ITT_Delay,ITT_Delay*1.2);
373 OilTemp_degK = ExpSeek(&OilTemp_degK,273.15 + in.TAT_c, 400 , 400);
375 OilPressure_psi = (N1/100.0*0.25+(0.1-(OilTemp_degK-273.15)*0.1/80.0)*N1/100.0) / 7692.0e-6;
377 EngPower_HP = EnginePowerRPM_N1->GetValue(RPM,N1);
378 EngPower_HP *= EnginePowerVC->GetValue();
379 if (EngPower_HP > MaxPower) EngPower_HP = MaxPower;
381 if (StartTime>=0) StartTime+=in.TotalDeltaT;
382 if (StartTime > MaxStartingTime && MaxStartingTime > 0) {
392 double FGTurboProp::Start(
void)
394 double EngPower_HP = 0.0;
397 if ((N1 > 15.0) && !Starved) {
401 EngPower_HP = EnginePowerRPM_N1->GetValue(RPM,N1);
402 EngPower_HP *= EnginePowerVC->GetValue();
403 if (EngPower_HP > MaxPower) EngPower_HP = MaxPower;
404 N1 = ExpSeek(&N1, IdleN1*1.1, Idle_Max_Delay*4, Idle_Max_Delay * 2.4);
405 CombustionEfficiency = CombustionEfficiency_N1->GetValue(N1);
406 FuelFlow_pph = PSFC / CombustionEfficiency * EngPower_HP;
407 Eng_Temperature = ExpSeek(&Eng_Temperature,Eng_ITT_degC,300,400);
408 double ITT_goal = ITT_N1->GetValue((N1-old_N1)*300+N1,1);
409 Eng_ITT_degC = ExpSeek(&Eng_ITT_degC,ITT_goal,ITT_Delay,ITT_Delay*1.2);
411 OilPressure_psi = (N1/100.0*0.25+(0.1-(OilTemp_degK-273.15)*0.1/80.0)*N1/100.0) / 7692.0e-6;
412 OilTemp_degK = Seek(&OilTemp_degK, 353.15, 0.4-N1*0.001, 0.04);
434 FuelFlowRate = FuelFlow_pph / 3600.0;
435 FuelExpended = FuelFlowRate * in.TotalDeltaT;
436 if (!Starved) FuelUsedLbs += FuelExpended;
442 double FGTurboProp::Seek(
double *var,
double target,
double accel,
double decel)
446 v -= in.TotalDeltaT * decel;
447 if (v < target) v = target;
448 }
else if (v < target) {
449 v += in.TotalDeltaT * accel;
450 if (v > target) v = target;
457 double FGTurboProp::ExpSeek(
double *var,
double target,
double accel_tau,
double decel_tau)
462 v = (v - target) * exp ( -in.TotalDeltaT / decel_tau) + target;
463 }
else if (v < target) {
464 v = (target - v) * (1 - exp ( -in.TotalDeltaT / accel_tau)) + v;
471 void FGTurboProp::SetDefaults(
void)
486 Ielu_intervent=
false;
488 Idle_Max_Delay = 1.0;
490 ThrottlePos = OldThrottle = 0.0;
492 ReverseMaxPower = 0.0;
493 BetaRangeThrottleEnd = 0.0;
494 CombustionEfficiency = 1.0;
500 string FGTurboProp::GetEngineLabels(
const string& delimiter)
502 std::ostringstream buf;
504 buf << Name <<
"_N1[" << EngineNumber <<
"]" << delimiter
505 << Name <<
"_PwrAvail[" << EngineNumber <<
"]" << delimiter
506 << Thruster->GetThrusterLabels(EngineNumber, delimiter);
513 string FGTurboProp::GetEngineValues(
const string& delimiter)
515 std::ostringstream buf;
517 buf << N1 << delimiter
519 << Thruster->GetThrusterValues(EngineNumber,delimiter);
526 int FGTurboProp::InitRunning(
void)
528 double dt = in.TotalDeltaT;
529 in.TotalDeltaT = 0.0;
541 string property_name, base_property_name;
542 base_property_name = CreateIndexedPropertyName(
"propulsion/engine", EngineNumber);
543 property_name = base_property_name +
"/n1";
544 PropertyManager->
Tie( property_name.c_str(), &N1);
545 property_name = base_property_name +
"/reverser";
546 PropertyManager->
Tie( property_name.c_str(), &Reversed);
547 property_name = base_property_name +
"/power-hp";
548 PropertyManager->
Tie( property_name.c_str(), &HP);
549 property_name = base_property_name +
"/itt-c";
550 PropertyManager->
Tie( property_name.c_str(), &Eng_ITT_degC);
551 property_name = base_property_name +
"/engtemp-c";
552 PropertyManager->
Tie( property_name.c_str(), &Eng_Temperature);
553 property_name = base_property_name +
"/ielu_intervent";
554 PropertyManager->
Tie( property_name.c_str(), &Ielu_intervent);
555 property_name = base_property_name +
"/combustion_efficiency";
556 PropertyManager->
Tie( property_name.c_str(), &CombustionEfficiency);
578 void FGTurboProp::Debug(
int from)
580 if (debug_lvl <= 0)
return;
587 cout <<
"\n ****MUJ MOTOR TURBOPROP****\n";
588 cout <<
"\n Engine Name: " << Name << endl;
589 cout <<
" IdleN1: " << IdleN1 << endl;
590 cout <<
" MaxN1: " << MaxN1 << endl;
595 if (debug_lvl & 2 ) {
596 if (from == 0) cout <<
"Instantiated: FGTurboProp" << endl;
597 if (from == 1) cout <<
"Destroyed: FGTurboProp" << endl;
599 if (debug_lvl & 4 ) {
601 if (debug_lvl & 8 ) {
603 if (debug_lvl & 16) {
605 if (debug_lvl & 64) {
607 cout << IdSrc << endl;
608 cout << IdHdr << endl;
~FGTurboProp()
Destructor.
static double Constrain(double min, double value, double max)
Constrain a value between a minimum and a maximum value.
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
double CalcFuelNeed(void)
The fuel need is calculated based on power levels and flow rate for that power level.
FGPropeller models a propeller given the tabular data for Ct (thrust) and Cp (power), indexed by the advance ratio "J".
Element * FindElement(const std::string &el="")
Searches for a specified element.
double FindElementValueAsNumber(const std::string &el="")
Searches for the named element and returns the data belonging to it as a number.
Models a helicopter rotor.
FGPropertyManager * GetPropertyManager(void)
Returns a pointer to the property manager object.
FGFunction * GetPreFunction(const std::string &name)
Get one of the "pre" function.
void Tie(const std::string &name, bool *pointer, bool useDefault=true)
Tie a property to an external bool variable.
bool SetAttributeValue(const std::string &key, const std::string &value)
Modifies an attribute.
std::string ReadFrom(void) const
Return a string that contains a description of the location where the current XML element was read fr...
Base class for all engines.
Element * FindNextElement(const std::string &el="")
Searches for the next element as specified.
Encapsulates the JSBSim simulation executive.
void Calculate(void)
Calculates the thrust of the engine, and other engine functions.