45 #include "FGFDMExec.h"
46 #include "math/FGFunction.h"
47 #include "FGTurbine.h"
48 #include "FGThruster.h"
49 #include "input_output/FGXMLElement.h"
60 :
FGEngine(engine_number, input), FDMExec(exec)
64 MilThrust = MaxThrust = 10000.0;
69 MaxN1 = MaxN2 = 100.0;
70 Augmented = AugMethod = Injected = 0;
71 BypassRatio = BleedDemand = 0.0;
72 IdleThrustLookup = MilThrustLookup = MaxThrustLookup = InjectionLookup = 0;
73 N1_spinup = 1.0; N2_spinup = 3.0; IgnitionN1 = 5.21; IgnitionN2 = 25.18; N1_start_rate = 1.4; N2_start_rate = 2.0;
74 N1_spindown = 2.0; N2_spindown = 2.0;
76 InjectionTimer = InjWaterNorm = 0.0;
78 disableWindmill =
false;
91 if (
dynamic_cast<FGSpoolUp*
>(N1SpoolUp))
delete N1SpoolUp;
92 if (
dynamic_cast<FGSpoolUp*
>(N1SpoolDown))
delete N1SpoolDown;
93 if (
dynamic_cast<FGSpoolUp*
>(N2SpoolUp))
delete N2SpoolUp;
94 if (
dynamic_cast<FGSpoolUp*
>(N2SpoolDown))
delete N2SpoolDown;
106 N1 = N2 = InjN1increment = InjN2increment = 0.0;
108 correctedTSFC = TSFC;
109 AugmentCmd = InjWaterNorm = 0.0;
110 InletPosition = NozzlePosition = 1.0;
111 Stalled = Seized = Overtemp = Fire = Augmentation = Injection = Reversed =
false;
115 OilTemp_degK = in.TAT_c + 273.0;
128 ThrottlePos = in.ThrottlePos[EngineNumber];
130 if (ThrottlePos > 1.0) {
131 AugmentCmd = ThrottlePos - 1.0;
132 ThrottlePos -= AugmentCmd;
138 if ((phase == tpTrim) && (in.TotalDeltaT > 0)) {
139 if (Running && !Starved) {
141 N1_factor = MaxN1 - IdleN1;
142 N2_factor = MaxN2 - IdleN2;
143 N2 = IdleN2 + ThrottlePos * N2_factor;
144 N1 = IdleN1 + ThrottlePos * N1_factor;
145 OilTemp_degK = 366.0;
154 if (!Running && Cutoff && Starter) {
155 if (phase == tpOff) phase = tpSpinUp;
159 if ((Starter ==
true) || (in.qbar > 30.0)) {
160 if (!Running && !Cutoff && (N2 > 15.0)) phase = tpStart;
163 if (Cutoff && (phase != tpSpinUp)) phase = tpOff;
164 if (in.TotalDeltaT == 0) phase = tpTrim;
165 if (Starved) phase = tpOff;
166 if (Stalled) phase = tpStall;
167 if (Seized) phase = tpSeize;
170 case tpOff: thrust = Off();
break;
171 case tpRun: thrust = Run();
break;
172 case tpSpinUp: thrust = SpinUp();
break;
173 case tpStart: thrust = Start();
break;
174 case tpStall: thrust = Stall();
break;
175 case tpSeize: thrust = Seize();
break;
176 case tpTrim: thrust = Trim();
break;
177 default: thrust = Off();
180 Thruster->Calculate(thrust);
187 double FGTurbine::Off(
void)
190 FuelFlow_pph =
Seek(&FuelFlow_pph, 0, 1000.0, 10000.0);
192 if (disableWindmill ==
false) {
194 N1 =
Seek(&N1, in.qbar/10.0, N1/2.0 + 0.1, N1/N1_spindown);
195 N2 =
Seek(&N2, in.qbar/15.0, N2/2.0 + 0.1, N2/N2_spindown);
197 N1 =
Seek(&N1, 0, N1/2.0, N1/N1_spindown);
198 N2 =
Seek(&N2, 0, N2/2.0, N2/N2_spindown);
200 EGT_degC =
Seek(&EGT_degC, in.TAT_c, 11.7, 7.3);
201 OilTemp_degK =
Seek(&OilTemp_degK, in.TAT_c + 273.0, 0.2, 0.2);
202 OilPressure_psi = N2 * 0.62;
203 NozzlePosition =
Seek(&NozzlePosition, 1.0, 0.8, 0.8);
204 EPR =
Seek(&EPR, 1.0, 0.2, 0.2);
205 Augmentation =
false;
211 double FGTurbine::Run()
213 double idlethrust, milthrust, thrust;
214 double T = in.Temperature;
216 idlethrust = MilThrust * IdleThrustLookup->
GetValue();
217 milthrust = (MilThrust - idlethrust) * MilThrustLookup->
GetValue();
222 N1_factor = MaxN1 - IdleN1;
223 N2_factor = MaxN2 - IdleN2;
224 if ((Injected == 1) && Injection && (InjWaterNorm > 0)) {
225 N1_factor += InjN1increment;
226 N2_factor += InjN2increment;
228 N2 =
Seek(&N2, IdleN2 + ThrottlePos * N2_factor,
229 N2SpoolUp->GetValue(), N2SpoolDown->GetValue());
230 N1 =
Seek(&N1, IdleN1 + ThrottlePos * N1_factor,
231 N1SpoolUp->GetValue(), N1SpoolDown->GetValue());
232 N2norm = (N2 - IdleN2) / N2_factor;
233 thrust = idlethrust + (milthrust * N2norm * N2norm);
234 EGT_degC = in.TAT_c + 363.1 + ThrottlePos * 357.1;
235 OilPressure_psi = N2 * 0.62;
236 OilTemp_degK =
Seek(&OilTemp_degK, 366.0, 1.2, 0.1);
239 correctedTSFC = TSFC * sqrt(T/389.7) * (0.84 + (1-N2norm)*(1-N2norm));
240 FuelFlow_pph =
Seek(&FuelFlow_pph, thrust * correctedTSFC, 1000.0, 10000.0);
241 if (FuelFlow_pph < IdleFF) FuelFlow_pph = IdleFF;
242 NozzlePosition =
Seek(&NozzlePosition, 1.0 - N2norm, 0.8, 0.8);
243 thrust = thrust * (1.0 - BleedDemand);
244 EPR = 1.0 + thrust/MilThrust;
247 if (AugMethod == 1) {
248 if ((ThrottlePos > 0.99) && (N2 > 97.0)) {Augmentation =
true;}
249 else {Augmentation =
false;}
252 if ((Augmented == 1) && Augmentation && (AugMethod < 2)) {
253 thrust = MaxThrustLookup->
GetValue() * MaxThrust;
254 FuelFlow_pph =
Seek(&FuelFlow_pph, thrust * ATSFC, 5000.0, 10000.0);
255 NozzlePosition =
Seek(&NozzlePosition, 1.0, 0.8, 0.8);
258 if (AugMethod == 2) {
259 if (AugmentCmd > 0.0) {
261 double tdiff = (MaxThrust * MaxThrustLookup->
GetValue()) - thrust;
262 thrust += (tdiff * AugmentCmd);
263 FuelFlow_pph =
Seek(&FuelFlow_pph, thrust * ATSFC, 5000.0, 10000.0);
264 NozzlePosition =
Seek(&NozzlePosition, 1.0, 0.8, 0.8);
266 Augmentation =
false;
270 if ((Injected == 1) && Injection && (InjWaterNorm > 0.0)) {
271 InjectionTimer += in.TotalDeltaT;
272 if (InjectionTimer < InjectionTime) {
273 thrust = thrust * InjectionLookup->
GetValue();
274 InjWaterNorm = 1.0 - (InjectionTimer/InjectionTime);
281 if (Cutoff) phase = tpOff;
282 if (Starved) phase = tpOff;
289 double FGTurbine::SpinUp(
void)
293 N2 =
Seek(&N2, IgnitionN2, N2_spinup, N2/2.0);
294 N1 =
Seek(&N1, IgnitionN1, N1_spinup, N1/2.0);
295 EGT_degC =
Seek(&EGT_degC, in.TAT_c, 11.7, 7.3);
296 OilPressure_psi = N2 * 0.62;
297 OilTemp_degK =
Seek(&OilTemp_degK, in.TAT_c + 273.0, 0.2, 0.2);
299 NozzlePosition = 1.0;
300 if (Starter ==
false) phase = tpOff;
306 double FGTurbine::Start(
void)
308 if ((N2 > 15.0) && !Starved) {
311 N2 =
Seek(&N2, IdleN2, N2_start_rate, N2/2.0);
312 N1 =
Seek(&N1, IdleN1, N1_start_rate, N1/2.0);
313 EGT_degC =
Seek(&EGT_degC, in.TAT_c + 363.1, 21.3, 7.3);
314 FuelFlow_pph = IdleFF * N2 / IdleN2;
315 OilPressure_psi = N2 * 0.62;
316 if ((Starter ==
false) && (in.qbar < 30.0)) phase = tpOff;
335 double FGTurbine::Stall(
void)
337 EGT_degC = in.TAT_c + 903.14;
338 FuelFlow_pph = IdleFF;
339 N1 =
Seek(&N1, in.qbar/10.0, 0, N1/10.0);
340 N2 =
Seek(&N2, in.qbar/15.0, 0, N2/10.0);
341 if (ThrottlePos < 0.01) {
350 double FGTurbine::Seize(
void)
353 N1 =
Seek(&N1, in.qbar/20.0, 0, N1/15.0);
354 FuelFlow_pph = Cutoff ? 0.0 : IdleFF;
355 OilPressure_psi = 0.0;
356 OilTemp_degK =
Seek(&OilTemp_degK, in.TAT_c + 273.0, 0, 0.2);
363 double FGTurbine::Trim()
365 double idlethrust = MilThrust * IdleThrustLookup->
GetValue();
366 double milthrust = (MilThrust - idlethrust) * MilThrustLookup->
GetValue();
367 double N2 = IdleN2 + ThrottlePos * N2_factor;
368 double N2norm = (N2 - IdleN2) / N2_factor;
369 double thrust = (idlethrust + (milthrust * N2norm * N2norm))
370 * (1.0 - BleedDemand);
372 if (AugMethod == 1) {
373 if ((ThrottlePos > 0.99) && (N2 > 97.0)) {Augmentation =
true;}
374 else {Augmentation =
false;}
377 if ((Augmented == 1) && Augmentation && (AugMethod < 2)) {
378 thrust = MaxThrust * MaxThrustLookup->
GetValue();
381 if (AugMethod == 2) {
382 if (AugmentCmd > 0.0) {
383 double tdiff = (MaxThrust * MaxThrustLookup->
GetValue()) - thrust;
384 thrust += (tdiff * AugmentCmd);
388 if ((Injected == 1) && Injection) {
389 thrust = thrust * InjectionLookup->
GetValue();
399 FuelFlowRate = FuelFlow_pph / 3600.0;
400 FuelExpended = FuelFlowRate * in.TotalDeltaT;
401 if (!Starved) FuelUsedLbs += FuelExpended;
407 double FGTurbine::GetPowerAvailable(
void) {
408 if( ThrottlePos <= 0.77 )
409 return 64.94*ThrottlePos;
411 return 217.38*ThrottlePos - 117.38;
419 v -= in.TotalDeltaT * decel;
420 if (v < target) v = target;
421 }
else if (v < target) {
422 v += in.TotalDeltaT * accel;
423 if (v > target) v = target;
434 while(function_element) {
436 if (name ==
"IdleThrust" || name ==
"MilThrust" || name ==
"AugThrust"
437 || name ==
"Injection" || name ==
"N1SpoolUp" || name ==
"N1SpoolDown"
438 || name ==
"N2SpoolUp" || name ==
"N2SpoolDown")
439 function_element->
SetAttributeValue(
"name",
string(
"propulsion/engine[#]/") + name);
444 FGEngine::Load(exec, el);
500 string property_prefix = CreateIndexedPropertyName(
"propulsion/engine", EngineNumber);
510 N1SpoolUp =
new FGSpoolUp(
this, BypassRatio, 1.0);
514 N1SpoolDown =
new FGSpoolUp(
this, BypassRatio, 2.4);
518 N2SpoolUp =
new FGSpoolUp(
this, BypassRatio, 1.0);
522 N2SpoolDown =
new FGSpoolUp(
this, BypassRatio, 3.0);
524 N1_factor = MaxN1 - IdleN1;
525 N2_factor = MaxN2 - IdleN2;
526 OilTemp_degK = in.TAT_c + 273.0;
527 IdleFF = pow(MilThrust, 0.2) * 107.0;
535 string FGTurbine::GetEngineLabels(
const string& delimiter)
537 std::ostringstream buf;
539 buf << Name <<
"_N1[" << EngineNumber <<
"]" << delimiter
540 << Name <<
"_N2[" << EngineNumber <<
"]" << delimiter
541 << Thruster->GetThrusterLabels(EngineNumber, delimiter);
548 string FGTurbine::GetEngineValues(
const string& delimiter)
550 std::ostringstream buf;
552 buf << N1 << delimiter
554 << Thruster->GetThrusterValues(EngineNumber, delimiter);
561 void FGTurbine::bindmodel(FGPropertyManager* PropertyManager)
563 string property_name, base_property_name;
564 base_property_name = CreateIndexedPropertyName(
"propulsion/engine", EngineNumber);
565 property_name = base_property_name +
"/n1";
566 PropertyManager->Tie( property_name.c_str(), &N1);
567 property_name = base_property_name +
"/n2";
568 PropertyManager->Tie( property_name.c_str(), &N2);
569 property_name = base_property_name +
"/injection_cmd";
570 PropertyManager->Tie( property_name.c_str(), (
FGTurbine*)
this,
571 &FGTurbine::GetInjection, &FGTurbine::SetInjection);
572 property_name = base_property_name +
"/seized";
573 PropertyManager->Tie( property_name.c_str(), &Seized);
574 property_name = base_property_name +
"/stalled";
575 PropertyManager->Tie( property_name.c_str(), &Stalled);
576 property_name = base_property_name +
"/bleed-factor";
577 PropertyManager->Tie( property_name.c_str(), (
FGTurbine*)
this, &FGTurbine::GetBleedDemand, &FGTurbine::SetBleedDemand);
578 property_name = base_property_name +
"/MaxN1";
579 PropertyManager->Tie( property_name.c_str(), (
FGTurbine*)
this,
580 &FGTurbine::GetMaxN1, &FGTurbine::SetMaxN1);
581 property_name = base_property_name +
"/MaxN2";
582 PropertyManager->Tie( property_name.c_str(), (
FGTurbine*)
this,
583 &FGTurbine::GetMaxN2, &FGTurbine::SetMaxN2);
584 property_name = base_property_name +
"/InjectionTimer";
585 PropertyManager->Tie( property_name.c_str(), (
FGTurbine*)
this,
586 &FGTurbine::GetInjectionTimer, &FGTurbine::SetInjectionTimer);
587 property_name = base_property_name +
"/InjWaterNorm";
588 PropertyManager->Tie( property_name.c_str(), (
FGTurbine*)
this,
589 &FGTurbine::GetInjWaterNorm, &FGTurbine::SetInjWaterNorm);
590 property_name = base_property_name +
"/InjN1increment";
591 PropertyManager->Tie( property_name.c_str(), (
FGTurbine*)
this,
592 &FGTurbine::GetInjN1increment, &FGTurbine::SetInjN1increment);
593 property_name = base_property_name +
"/InjN2increment";
594 PropertyManager->Tie( property_name.c_str(), (
FGTurbine*)
this,
595 &FGTurbine::GetInjN2increment, &FGTurbine::SetInjN2increment);
600 int FGTurbine::InitRunning(
void)
605 N1_factor = MaxN1 - IdleN1;
606 N2_factor = MaxN2 - IdleN2;
607 N2 = IdleN2 + ThrottlePos * N2_factor;
608 N1 = IdleN1 + ThrottlePos * N1_factor;
633 void FGTurbine::Debug(
int from)
635 if (debug_lvl <= 0)
return;
642 cout <<
"\n Engine Name: " << Name << endl;
643 cout <<
" MilThrust: " << MilThrust << endl;
644 cout <<
" MaxThrust: " << MaxThrust << endl;
645 cout <<
" BypassRatio: " << BypassRatio << endl;
646 cout <<
" TSFC: " << TSFC << endl;
647 cout <<
" ATSFC: " << ATSFC << endl;
648 cout <<
" IdleN1: " << IdleN1 << endl;
649 cout <<
" IdleN2: " << IdleN2 << endl;
650 cout <<
" MaxN1: " << MaxN1 << endl;
651 cout <<
" MaxN2: " << MaxN2 << endl;
652 cout <<
" Augmented: " << Augmented << endl;
653 cout <<
" AugMethod: " << AugMethod << endl;
654 cout <<
" Injected: " << Injected << endl;
655 cout <<
" MinThrottle: " << MinThrottle << endl;
660 if (debug_lvl & 2 ) {
661 if (from == 0) cout <<
"Instantiated: FGTurbine" << endl;
662 if (from == 1) cout <<
"Destroyed: FGTurbine" << endl;
664 if (debug_lvl & 4 ) {
666 if (debug_lvl & 8 ) {
668 if (debug_lvl & 16) {
670 if (debug_lvl & 64) {