48 #include "FGTurboProp.h"
49 #include "FGPropeller.h"
51 #include "math/FGFunction.h"
52 #include "input_output/FGXMLElement.h"
64 ITT_N1(NULL), EnginePowerRPM_N1(NULL), EnginePowerVC(NULL),
65 CombustionEfficiency_N1(NULL)
77 delete EnginePowerRPM_N1;
78 if (
dynamic_cast<FGTable*
>(EnginePowerVC))
80 delete CombustionEfficiency_N1;
88 MaxStartingTime = 999999;
93 while(function_element) {
95 if (name ==
"EnginePowerVC")
96 function_element->
SetAttributeValue(
"name",
string(
"propulsion/engine[#]/") + name);
101 FGEngine::Load(exec, el);
102 thrusterType = Thruster->GetType();
104 string property_prefix = CreateIndexedPropertyName(
"propulsion/engine", EngineNumber);
117 BetaRangeThrottleEnd =
Constrain(0.0, BetaRangeThrottleEnd, 0.99999);
124 cerr << el->
ReadFrom() <<
"Note: 'idlefuelflow' is obsolete, "
125 <<
"use the 'CombustionEfficiency_N1' table instead." << endl;
143 while (table_element) {
144 string name = table_element->GetAttributeValue(
"name");
145 if (!EnginePowerVC && name ==
"EnginePowerVC") {
150 table_element->SetAttributeValue(
"name",
string(
"propulsion/engine[#]/") + name);
151 EnginePowerVC =
new FGTable(PropertyManager, table_element,
152 to_string((
int)EngineNumber));
153 table_element->SetAttributeValue(
"name", name);
154 cerr << table_element->ReadFrom()
155 <<
"Note: Using the EnginePowerVC without enclosed <function> tag is deprecated"
157 }
else if (name ==
"EnginePowerRPM_N1") {
158 EnginePowerRPM_N1 =
new FGTable(PropertyManager, table_element);
159 }
else if (name ==
"ITT_N1") {
160 ITT_N1 =
new FGTable(PropertyManager, table_element);
161 }
else if (name ==
"CombustionEfficiency_N1") {
162 CombustionEfficiency_N1 =
new FGTable(PropertyManager, table_element);
164 cerr << el->
ReadFrom() <<
"Unknown table type: " << name
165 <<
" in turboprop definition." << endl;
173 N1_factor = MaxN1 - IdleN1;
174 OilTemp_degK = in.TAT_c + 273.0;
178 if (! CombustionEfficiency_N1) {
179 CombustionEfficiency_N1 =
new FGTable(6);
180 *CombustionEfficiency_N1 << 60.0 << 12.0/52.0;
181 *CombustionEfficiency_N1 << 82.0 << 12.0/30.0;
182 *CombustionEfficiency_N1 << 96.0 << 12.0/16.0;
183 *CombustionEfficiency_N1 << 100.0 << 1.0;
184 *CombustionEfficiency_N1 << 104.0 << 1.5;
185 *CombustionEfficiency_N1 << 110.0 << 6.0;
188 bindmodel(PropertyManager);
200 ThrottlePos = in.ThrottlePos[EngineNumber];
204 RPM = Thruster->GetEngineRPM();
205 if (thrusterType == FGThruster::ttPropeller) {
206 ((
FGPropeller*)Thruster)->SetAdvance(in.PropAdvance[EngineNumber]);
207 ((
FGPropeller*)Thruster)->SetFeather(in.PropFeather[EngineNumber]);
210 ((
FGPropeller*)Thruster)->SetReverseCoef(ThrottlePos);
216 if (ThrottlePos < BetaRangeThrottleEnd) {
220 ThrottlePos = (ThrottlePos-BetaRangeThrottleEnd)/(1-BetaRangeThrottleEnd) * ReverseMaxPower;
226 if ((phase == tpTrim) && (in.TotalDeltaT > 0)) {
227 if (Running && !Starved) {
230 OilTemp_degK = 366.0;
235 Eng_ITT_degC = in.TAT_c;
236 Eng_Temperature = in.TAT_c;
237 OilTemp_degK = in.TAT_c+273.15;
241 if (!Running && Starter) {
242 if (phase == tpOff) {
244 if (StartTime < 0) StartTime=0;
247 if (!Running && !Cutoff && (N1 > 15.0)) {
251 if (Cutoff && (phase != tpSpinUp)) phase = tpOff;
252 if (in.TotalDeltaT == 0) phase = tpTrim;
253 if (Starved) phase = tpOff;
254 if (Condition >= 10) {
260 if (Ielu_max_torque > 0.0) {
263 if (thrusterType == FGThruster::ttPropeller) {
265 }
else if (thrusterType == FGThruster::ttRotor) {
266 torque = ((
FGRotor*)(Thruster))->GetTorque();
270 if ( abs(torque) > Ielu_max_torque && ThrottlePos >= OldThrottle ) {
271 ThrottlePos = OldThrottle - 0.1 * in.TotalDeltaT;
272 Ielu_intervent =
true;
273 }
else if ( Ielu_intervent && ThrottlePos >= OldThrottle) {
274 ThrottlePos = OldThrottle + 0.05 * in.TotalDeltaT;
275 Ielu_intervent =
true;
277 Ielu_intervent =
false;
280 Ielu_intervent =
false;
282 OldThrottle = ThrottlePos;
286 case tpOff: HP = Off();
break;
287 case tpRun: HP = Run();
break;
288 case tpSpinUp: HP = SpinUp();
break;
289 case tpStart: HP = Start();
break;
293 LoadThrusterInputs();
295 double power = HP * hptoftlbssec;
296 if (RPM <= 0.1) power = max(power, 0.0);
297 Thruster->Calculate(power);
304 double FGTurboProp::Off(
void)
306 Running =
false; EngStarting =
false;
308 FuelFlow_pph = Seek(&FuelFlow_pph, 0, 800.0, 800.0);
311 N1 = ExpSeek(&N1, in.qbar/15.0, Idle_Max_Delay*2.5, Idle_Max_Delay * 5);
313 OilTemp_degK = ExpSeek(&OilTemp_degK,273.15 + in.TAT_c, 400 , 400);
315 Eng_Temperature = ExpSeek(&Eng_Temperature,in.TAT_c,300,400);
316 double ITT_goal = ITT_N1->GetValue(N1,0.1) + ((N1>20) ? 0.0 : (20-N1)/20.0 * Eng_Temperature);
317 Eng_ITT_degC = ExpSeek(&Eng_ITT_degC,ITT_goal,ITT_Delay,ITT_Delay*1.2);
319 OilPressure_psi = (N1/100.0*0.25+(0.1-(OilTemp_degK-273.15)*0.1/80.0)*N1/100.0) / 7692.0e-6;
321 if (RPM>5)
return -0.012;
327 double FGTurboProp::Run(
void)
331 Running =
true; Starter =
false; EngStarting =
false;
335 N1 = ExpSeek(&N1, IdleN1 + ThrottlePos * N1_factor, Idle_Max_Delay, Idle_Max_Delay * 2.4);
337 EngPower_HP = EnginePowerRPM_N1->GetValue(RPM,N1);
338 EngPower_HP *= EnginePowerVC->GetValue();
339 if (EngPower_HP > MaxPower) EngPower_HP = MaxPower;
341 CombustionEfficiency = CombustionEfficiency_N1->GetValue(N1);
342 FuelFlow_pph = PSFC / CombustionEfficiency * EngPower_HP;
344 Eng_Temperature = ExpSeek(&Eng_Temperature,Eng_ITT_degC,300,400);
345 double ITT_goal = ITT_N1->GetValue((N1-old_N1)*300+N1,1);
346 Eng_ITT_degC = ExpSeek(&Eng_ITT_degC,ITT_goal,ITT_Delay,ITT_Delay*1.2);
348 OilPressure_psi = (N1/100.0*0.25+(0.1-(OilTemp_degK-273.15)*0.1/80.0)*N1/100.0) / 7692.0e-6;
351 OilTemp_degK = Seek(&OilTemp_degK, 353.15, 0.4-N1*0.001, 0.04);
353 if (Cutoff) phase = tpOff;
354 if (Starved) phase = tpOff;
361 double FGTurboProp::SpinUp(
void)
364 Running =
false; EngStarting =
true;
367 if (!GeneratorPower) {
374 N1 = ExpSeek(&N1, StarterN1, Idle_Max_Delay * 6, Idle_Max_Delay * 2.4);
376 Eng_Temperature = ExpSeek(&Eng_Temperature,in.TAT_c,300,400);
377 double ITT_goal = ITT_N1->GetValue(N1,0.1) + ((N1>20) ? 0.0 : (20-N1)/20.0 * Eng_Temperature);
378 Eng_ITT_degC = ExpSeek(&Eng_ITT_degC,ITT_goal,ITT_Delay,ITT_Delay*1.2);
380 OilTemp_degK = ExpSeek(&OilTemp_degK,273.15 + in.TAT_c, 400 , 400);
382 OilPressure_psi = (N1/100.0*0.25+(0.1-(OilTemp_degK-273.15)*0.1/80.0)*N1/100.0) / 7692.0e-6;
384 EngPower_HP = EnginePowerRPM_N1->GetValue(RPM,N1);
385 EngPower_HP *= EnginePowerVC->GetValue();
386 if (EngPower_HP > MaxPower) EngPower_HP = MaxPower;
388 if (StartTime>=0) StartTime+=in.TotalDeltaT;
389 if (StartTime > MaxStartingTime && MaxStartingTime > 0) {
399 double FGTurboProp::Start(
void)
401 double EngPower_HP = 0.0;
404 if ((N1 > 15.0) && !Starved) {
408 EngPower_HP = EnginePowerRPM_N1->GetValue(RPM,N1);
409 EngPower_HP *= EnginePowerVC->GetValue();
410 if (EngPower_HP > MaxPower) EngPower_HP = MaxPower;
411 N1 = ExpSeek(&N1, IdleN1*1.1, Idle_Max_Delay*4, Idle_Max_Delay * 2.4);
412 CombustionEfficiency = CombustionEfficiency_N1->GetValue(N1);
413 FuelFlow_pph = PSFC / CombustionEfficiency * EngPower_HP;
414 Eng_Temperature = ExpSeek(&Eng_Temperature,Eng_ITT_degC,300,400);
415 double ITT_goal = ITT_N1->GetValue((N1-old_N1)*300+N1,1);
416 Eng_ITT_degC = ExpSeek(&Eng_ITT_degC,ITT_goal,ITT_Delay,ITT_Delay*1.2);
418 OilPressure_psi = (N1/100.0*0.25+(0.1-(OilTemp_degK-273.15)*0.1/80.0)*N1/100.0) / 7692.0e-6;
419 OilTemp_degK = Seek(&OilTemp_degK, 353.15, 0.4-N1*0.001, 0.04);
441 FuelFlowRate = FuelFlow_pph / 3600.0;
442 FuelExpended = FuelFlowRate * in.TotalDeltaT;
443 if (!Starved) FuelUsedLbs += FuelExpended;
449 double FGTurboProp::Seek(
double *var,
double target,
double accel,
double decel)
453 v -= in.TotalDeltaT * decel;
454 if (v < target) v = target;
455 }
else if (v < target) {
456 v += in.TotalDeltaT * accel;
457 if (v > target) v = target;
464 double FGTurboProp::ExpSeek(
double *var,
double target,
double accel_tau,
double decel_tau)
469 v = (v - target) * exp ( -in.TotalDeltaT / decel_tau) + target;
470 }
else if (v < target) {
471 v = (target - v) * (1 - exp ( -in.TotalDeltaT / accel_tau)) + v;
478 void FGTurboProp::SetDefaults(
void)
493 Ielu_intervent=
false;
495 Idle_Max_Delay = 1.0;
497 ThrottlePos = OldThrottle = 0.0;
499 ReverseMaxPower = 0.0;
500 BetaRangeThrottleEnd = 0.0;
501 CombustionEfficiency = 1.0;
507 string FGTurboProp::GetEngineLabels(
const string& delimiter)
509 std::ostringstream buf;
511 buf << Name <<
"_N1[" << EngineNumber <<
"]" << delimiter
512 << Name <<
"_PwrAvail[" << EngineNumber <<
"]" << delimiter
513 << Thruster->GetThrusterLabels(EngineNumber, delimiter);
520 string FGTurboProp::GetEngineValues(
const string& delimiter)
522 std::ostringstream buf;
524 buf << N1 << delimiter
526 << Thruster->GetThrusterValues(EngineNumber,delimiter);
533 int FGTurboProp::InitRunning(
void)
535 double dt = in.TotalDeltaT;
536 in.TotalDeltaT = 0.0;
546 void FGTurboProp::bindmodel(FGPropertyManager* PropertyManager)
548 string property_name, base_property_name;
549 base_property_name = CreateIndexedPropertyName(
"propulsion/engine", EngineNumber);
550 property_name = base_property_name +
"/n1";
551 PropertyManager->Tie( property_name.c_str(), &N1);
552 property_name = base_property_name +
"/reverser";
553 PropertyManager->Tie( property_name.c_str(), &Reversed);
554 property_name = base_property_name +
"/power-hp";
555 PropertyManager->Tie( property_name.c_str(), &HP);
556 property_name = base_property_name +
"/itt-c";
557 PropertyManager->Tie( property_name.c_str(), &Eng_ITT_degC);
558 property_name = base_property_name +
"/engtemp-c";
559 PropertyManager->Tie( property_name.c_str(), &Eng_Temperature);
560 property_name = base_property_name +
"/ielu_intervent";
561 PropertyManager->Tie( property_name.c_str(), &Ielu_intervent);
562 property_name = base_property_name +
"/combustion_efficiency";
563 PropertyManager->Tie( property_name.c_str(), &CombustionEfficiency);
585 void FGTurboProp::Debug(
int from)
587 if (debug_lvl <= 0)
return;
594 cout <<
"\n ****MUJ MOTOR TURBOPROP****\n";
595 cout <<
"\n Engine Name: " << Name << endl;
596 cout <<
" IdleN1: " << IdleN1 << endl;
597 cout <<
" MaxN1: " << MaxN1 << endl;
602 if (debug_lvl & 2 ) {
603 if (from == 0) cout <<
"Instantiated: FGTurboProp" << endl;
604 if (from == 1) cout <<
"Destroyed: FGTurboProp" << endl;
606 if (debug_lvl & 4 ) {
608 if (debug_lvl & 8 ) {
610 if (debug_lvl & 16) {
612 if (debug_lvl & 64) {