46#include "math/FGFunction.h"
47#include "math/FGRealValue.h"
49#include "FGThruster.h"
50#include "input_output/FGXMLElement.h"
51#include "input_output/string_utilities.h"
62 :
FGEngine(engine_number, input), FDMExec(exec)
66 MilThrust = MaxThrust = 10000.0;
67 TSFC = std::make_unique<FGSimplifiedTSFC>(
this, 0.8);
68 ATSFC = std::make_unique<FGRealValue>(1.7);
71 MaxN1 = MaxN2 = 100.0;
72 Augmented = AugMethod = Injected = 0;
73 BypassRatio = BleedDemand = 0.0;
74 IdleThrustLookup = MilThrustLookup = MaxThrustLookup = InjectionLookup =
nullptr;
75 N1_spinup = 1.0; N2_spinup = 3.0; IgnitionN1 = 5.21; IgnitionN2 = 25.18; N1_start_rate = 1.4; N2_start_rate = 2.0;
76 N1_spindown = 2.0; N2_spindown = 2.0;
78 InjectionTimer = InjWaterNorm = 0.0;
80 disableWindmill =
false;
93 N1 = N2 = InjN1increment = InjN2increment = 0.0;
95 correctedTSFC = TSFC->GetValue();
96 AugmentCmd = InjWaterNorm = 0.0;
97 InletPosition = NozzlePosition = 1.0;
98 Stalled = Seized = Overtemp = Fire = Augmentation = Injection = Reversed =
false;
102 OilTemp_degK = in.TAT_c + 273.0;
115 ThrottlePos = in.ThrottlePos[EngineNumber];
117 if (ThrottlePos > 1.0) {
118 AugmentCmd = ThrottlePos - 1.0;
119 ThrottlePos -= AugmentCmd;
125 if ((phase == tpTrim) && (in.TotalDeltaT > 0)) {
126 if (Running && !Starved) {
128 N1_factor = MaxN1 - IdleN1;
129 N2_factor = MaxN2 - IdleN2;
130 N2 = IdleN2 + ThrottlePos * N2_factor;
131 N1 = IdleN1 + ThrottlePos * N1_factor;
132 OilTemp_degK = 366.0;
141 if (!Running && Cutoff && Starter) {
142 if (phase == tpOff) phase = tpSpinUp;
146 if ((Starter ==
true) || (in.qbar > 30.0)) {
147 if (!Running && !Cutoff && (N2 > 15.0)) phase = tpStart;
150 if (Cutoff && (phase != tpSpinUp)) phase = tpOff;
151 if (in.TotalDeltaT == 0) phase = tpTrim;
152 if (Starved) phase = tpOff;
153 if (Stalled) phase = tpStall;
154 if (Seized) phase = tpSeize;
157 case tpOff: thrust = Off();
break;
158 case tpRun: thrust = Run();
break;
159 case tpSpinUp: thrust = SpinUp();
break;
160 case tpStart: thrust = Start();
break;
161 case tpStall: thrust = Stall();
break;
162 case tpSeize: thrust = Seize();
break;
163 case tpTrim: thrust = Trim();
break;
164 default: thrust = Off();
167 LoadThrusterInputs();
168 Thruster->Calculate(thrust);
175double FGTurbine::Off(
void)
178 FuelFlow_pph =
Seek(&FuelFlow_pph, 0, 1000.0, 10000.0);
180 if (disableWindmill ==
false) {
182 N1 =
Seek(&N1, in.qbar/10.0, N1/2.0 + 0.1, N1/N1_spindown);
183 N2 =
Seek(&N2, in.qbar/15.0, N2/2.0 + 0.1, N2/N2_spindown);
185 N1 =
Seek(&N1, 0, N1/2.0, N1/N1_spindown);
186 N2 =
Seek(&N2, 0, N2/2.0, N2/N2_spindown);
188 EGT_degC =
Seek(&EGT_degC, in.TAT_c, 11.7, 7.3);
189 OilTemp_degK =
Seek(&OilTemp_degK, in.TAT_c + 273.0, 0.2, 0.2);
190 OilPressure_psi = N2 * 0.62;
191 NozzlePosition =
Seek(&NozzlePosition, 1.0, 0.8, 0.8);
192 EPR =
Seek(&EPR, 1.0, 0.2, 0.2);
193 Augmentation =
false;
199double FGTurbine::Run()
201 double idlethrust, milthrust, thrust;
203 idlethrust = MilThrust * IdleThrustLookup->GetValue();
204 milthrust = (MilThrust - idlethrust) * MilThrustLookup->GetValue();
209 N1_factor = MaxN1 - IdleN1;
210 N2_factor = MaxN2 - IdleN2;
211 if ((Injected == 1) && Injection && (InjWaterNorm > 0)) {
212 N1_factor += InjN1increment;
213 N2_factor += InjN2increment;
215 N2 =
Seek(&N2, IdleN2 + ThrottlePos * N2_factor,
216 N2SpoolUp->GetValue(), N2SpoolDown->GetValue());
217 N1 =
Seek(&N1, IdleN1 + ThrottlePos * N1_factor,
218 N1SpoolUp->GetValue(), N1SpoolDown->GetValue());
219 N2norm = (N2 - IdleN2) / N2_factor;
220 thrust = idlethrust + (milthrust * N2norm * N2norm);
221 EGT_degC = in.TAT_c + 363.1 + ThrottlePos * 357.1;
222 OilPressure_psi = N2 * 0.62;
223 OilTemp_degK =
Seek(&OilTemp_degK, 366.0, 1.2, 0.1);
226 correctedTSFC = TSFC->GetValue();
227 FuelFlow_pph =
Seek(&FuelFlow_pph, thrust * correctedTSFC, 1000.0, 10000.0);
228 if (FuelFlow_pph < IdleFF) FuelFlow_pph = IdleFF;
229 NozzlePosition =
Seek(&NozzlePosition, 1.0 - N2norm, 0.8, 0.8);
230 thrust = thrust * (1.0 - BleedDemand);
231 EPR = 1.0 + thrust/MilThrust;
234 if (AugMethod == 1) {
235 if ((ThrottlePos > 0.99) && (N2 > 97.0)) {Augmentation =
true;}
236 else {Augmentation =
false;}
239 if ((Augmented == 1) && Augmentation && (AugMethod < 2)) {
240 thrust = MaxThrustLookup->GetValue() * MaxThrust;
241 FuelFlow_pph =
Seek(&FuelFlow_pph, thrust * ATSFC->GetValue(), 5000.0, 10000.0);
242 NozzlePosition =
Seek(&NozzlePosition, 1.0, 0.8, 0.8);
245 if (AugMethod == 2) {
246 if (AugmentCmd > 0.0) {
248 double tdiff = (MaxThrust * MaxThrustLookup->GetValue()) - thrust;
249 thrust += (tdiff * std::min(AugmentCmd, 1.0));
250 FuelFlow_pph =
Seek(&FuelFlow_pph, thrust * ATSFC->GetValue(), 5000.0, 10000.0);
251 NozzlePosition =
Seek(&NozzlePosition, 1.0, 0.8, 0.8);
253 Augmentation =
false;
257 if ((Injected == 1) && Injection && (InjWaterNorm > 0.0)) {
258 InjectionTimer += in.TotalDeltaT;
259 if (InjectionTimer < InjectionTime) {
260 thrust = thrust * InjectionLookup->GetValue();
261 InjWaterNorm = 1.0 - (InjectionTimer/InjectionTime);
268 if (Cutoff) phase = tpOff;
269 if (Starved) phase = tpOff;
276double FGTurbine::SpinUp(
void)
280 N2 =
Seek(&N2, IgnitionN2, N2_spinup, N2/2.0);
281 N1 =
Seek(&N1, IgnitionN1, N1_spinup, N1/2.0);
282 EGT_degC =
Seek(&EGT_degC, in.TAT_c, 11.7, 7.3);
283 OilPressure_psi = N2 * 0.62;
284 OilTemp_degK =
Seek(&OilTemp_degK, in.TAT_c + 273.0, 0.2, 0.2);
286 NozzlePosition = 1.0;
287 if (Starter ==
false) phase = tpOff;
293double FGTurbine::Start(
void)
295 if ((N2 > 15.0) && !Starved) {
298 N2 =
Seek(&N2, IdleN2, N2_start_rate, N2/2.0);
299 N1 =
Seek(&N1, IdleN1, N1_start_rate, N1/2.0);
300 EGT_degC =
Seek(&EGT_degC, in.TAT_c + 363.1, 21.3, 7.3);
301 FuelFlow_pph = IdleFF * N2 / IdleN2;
302 OilPressure_psi = N2 * 0.62;
303 if ((Starter ==
false) && (in.qbar < 30.0)) phase = tpOff;
322double FGTurbine::Stall(
void)
324 EGT_degC = in.TAT_c + 903.14;
325 FuelFlow_pph = IdleFF;
326 N1 =
Seek(&N1, in.qbar/10.0, 0, N1/10.0);
327 N2 =
Seek(&N2, in.qbar/15.0, 0, N2/10.0);
328 if (ThrottlePos < 0.01) {
337double FGTurbine::Seize(
void)
340 N1 =
Seek(&N1, in.qbar/20.0, 0, N1/15.0);
341 FuelFlow_pph = Cutoff ? 0.0 : IdleFF;
342 OilPressure_psi = 0.0;
343 OilTemp_degK =
Seek(&OilTemp_degK, in.TAT_c + 273.0, 0, 0.2);
350double FGTurbine::Trim()
352 double idlethrust = MilThrust * IdleThrustLookup->GetValue();
353 double milthrust = (MilThrust - idlethrust) * MilThrustLookup->GetValue();
354 double N2 = IdleN2 + ThrottlePos * N2_factor;
355 double N2norm = (N2 - IdleN2) / N2_factor;
356 double thrust = (idlethrust + (milthrust * N2norm * N2norm))
357 * (1.0 - BleedDemand);
359 if (AugMethod == 1) {
360 if ((ThrottlePos > 0.99) && (N2 > 97.0)) {Augmentation =
true;}
361 else {Augmentation =
false;}
364 if ((Augmented == 1) && Augmentation && (AugMethod < 2)) {
365 thrust = MaxThrust * MaxThrustLookup->GetValue();
368 if (AugMethod == 2) {
369 if (AugmentCmd > 0.0) {
370 double tdiff = (MaxThrust * MaxThrustLookup->GetValue()) - thrust;
371 thrust += (tdiff * std::min(AugmentCmd, 1.0));
375 if ((Injected == 1) && Injection) {
376 thrust = thrust * InjectionLookup->GetValue();
386 FuelFlowRate = FuelFlow_pph / 3600.0;
387 FuelExpended = FuelFlowRate * in.TotalDeltaT;
388 if (!Starved) FuelUsedLbs += FuelExpended;
394double FGTurbine::GetPowerAvailable(
void)
const {
395 if( ThrottlePos <= 0.77 )
396 return 64.94*ThrottlePos;
398 return 217.38*ThrottlePos - 117.38;
406 v -= in.TotalDeltaT * decel;
407 if (v < target) v = target;
408 }
else if (v < target) {
409 v += in.TotalDeltaT * accel;
410 if (v > target) v = target;
421 while(function_element) {
423 if (name ==
"IdleThrust" || name ==
"MilThrust" || name ==
"AugThrust"
424 || name ==
"Injection" || name ==
"N1SpoolUp" || name ==
"N1SpoolDown"
425 || name ==
"N2SpoolUp" || name ==
"N2SpoolDown")
426 function_element->
SetAttributeValue(
"name",
string(
"propulsion/engine[#]/") + name);
431 FGEngine::Load(exec, el);
483 string property_prefix = CreateIndexedPropertyName(
"propulsion/engine", EngineNumber);
494 TSFC = std::make_unique<FGSimplifiedTSFC>(
this, atof_locale_c(value));
495 }
catch (InvalidNumber&) {
496 TSFC = std::make_unique<FGFunction>(FDMExec, tsfcElement, to_string(EngineNumber));
504 ATSFC = std::make_unique<FGRealValue>(atof_locale_c(value));
505 }
catch (InvalidNumber&) {
506 ATSFC = std::make_unique<FGFunction>(FDMExec, atsfcElement, to_string((
int)EngineNumber));
513 N1SpoolUp = std::make_shared<FGSpoolUp>(
this, BypassRatio, 1.0);
517 N1SpoolDown = std::make_shared<FGSpoolUp>(
this, BypassRatio, 2.4);
521 N2SpoolUp = std::make_shared<FGSpoolUp>(
this, BypassRatio, 1.0);
525 N2SpoolDown = std::make_shared<FGSpoolUp>(
this, BypassRatio, 3.0);
527 N1_factor = MaxN1 - IdleN1;
528 N2_factor = MaxN2 - IdleN2;
529 OilTemp_degK = in.TAT_c + 273.0;
530 IdleFF = pow(MilThrust, 0.2) * 107.0;
538string FGTurbine::GetEngineLabels(
const string& delimiter)
540 std::ostringstream buf;
542 buf << Name <<
"_N1[" << EngineNumber <<
"]" << delimiter
543 << Name <<
"_N2[" << EngineNumber <<
"]" << delimiter
544 << Thruster->GetThrusterLabels(EngineNumber, delimiter);
551string FGTurbine::GetEngineValues(
const string& delimiter)
553 std::ostringstream buf;
555 buf << N1 << delimiter
557 << Thruster->GetThrusterValues(EngineNumber, delimiter);
564void FGTurbine::bindmodel(FGPropertyManager* PropertyManager)
566 string property_name, base_property_name;
567 base_property_name = CreateIndexedPropertyName(
"propulsion/engine", EngineNumber);
568 property_name = base_property_name +
"/n1";
569 PropertyManager->Tie( property_name.c_str(), &N1);
570 property_name = base_property_name +
"/n2";
571 PropertyManager->Tie( property_name.c_str(), &N2);
572 property_name = base_property_name +
"/injection_cmd";
573 PropertyManager->Tie( property_name.c_str(),
this,
574 &FGTurbine::GetInjection, &FGTurbine::SetInjection);
575 property_name = base_property_name +
"/seized";
576 PropertyManager->Tie( property_name.c_str(), &Seized);
577 property_name = base_property_name +
"/stalled";
578 PropertyManager->Tie( property_name.c_str(), &Stalled);
579 property_name = base_property_name +
"/bleed-factor";
580 PropertyManager->Tie( property_name.c_str(),
this, &FGTurbine::GetBleedDemand, &FGTurbine::SetBleedDemand);
581 property_name = base_property_name +
"/MaxN1";
582 PropertyManager->Tie( property_name.c_str(),
this,
583 &FGTurbine::GetMaxN1, &FGTurbine::SetMaxN1);
584 property_name = base_property_name +
"/MaxN2";
585 PropertyManager->Tie( property_name.c_str(),
this,
586 &FGTurbine::GetMaxN2, &FGTurbine::SetMaxN2);
587 property_name = base_property_name +
"/InjectionTimer";
588 PropertyManager->Tie( property_name.c_str(),
this,
589 &FGTurbine::GetInjectionTimer, &FGTurbine::SetInjectionTimer);
590 property_name = base_property_name +
"/InjWaterNorm";
591 PropertyManager->Tie( property_name.c_str(),
this,
592 &FGTurbine::GetInjWaterNorm, &FGTurbine::SetInjWaterNorm);
593 property_name = base_property_name +
"/InjN1increment";
594 PropertyManager->Tie( property_name.c_str(),
this,
595 &FGTurbine::GetInjN1increment, &FGTurbine::SetInjN1increment);
596 property_name = base_property_name +
"/InjN2increment";
597 PropertyManager->Tie( property_name.c_str(),
this,
598 &FGTurbine::GetInjN2increment, &FGTurbine::SetInjN2increment);
599 property_name = base_property_name +
"/atsfc";
600 PropertyManager->Tie(property_name.c_str(), ATSFC.get(), &FGParameter::GetValue);
601 property_name = base_property_name +
"/tsfc";
602 PropertyManager->Tie(property_name.c_str(), &correctedTSFC);
603 auto node = PropertyManager->GetNode(property_name.c_str(),
false);
604 node->setAttribute(SGPropertyNode::WRITE,
false);
609int FGTurbine::InitRunning(
void)
614 N1_factor = MaxN1 - IdleN1;
615 N2_factor = MaxN2 - IdleN2;
616 N2 = IdleN2 + ThrottlePos * N2_factor;
617 N1 = IdleN1 + ThrottlePos * N1_factor;
642void FGTurbine::Debug(
int from)
644 if (debug_lvl <= 0)
return;
651 cout <<
"\n Engine Name: " << Name << endl;
652 cout <<
" MilThrust: " << MilThrust << endl;
653 cout <<
" MaxThrust: " << MaxThrust << endl;
654 cout <<
" BypassRatio: " << BypassRatio << endl;
655 cout <<
" TSFC: " << TSFC->GetValue() << endl;
656 cout <<
" ATSFC: " << ATSFC->GetValue() << endl;
657 cout <<
" IdleN1: " << IdleN1 << endl;
658 cout <<
" IdleN2: " << IdleN2 << endl;
659 cout <<
" MaxN1: " << MaxN1 << endl;
660 cout <<
" MaxN2: " << MaxN2 << endl;
661 cout <<
" Augmented: " << Augmented << endl;
662 cout <<
" AugMethod: " << AugMethod << endl;
663 cout <<
" Injected: " << Injected << endl;
664 cout <<
" MinThrottle: " << MinThrottle << endl;
669 if (debug_lvl & 2 ) {
670 if (from == 0) cout <<
"Instantiated: FGTurbine" << endl;
671 if (from == 1) cout <<
"Destroyed: FGTurbine" << endl;
673 if (debug_lvl & 4 ) {
675 if (debug_lvl & 8 ) {
677 if (debug_lvl & 16) {
679 if (debug_lvl & 64) {
Element * FindElement(const std::string &el="")
Searches for a specified element.
bool SetAttributeValue(const std::string &key, const std::string &value)
Modifies an attribute.
bool FindElementValueAsBoolean(const std::string &el="")
Searches for the named element and returns the data belonging to it as a bool.
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
std::string GetDataLine(unsigned int i=0)
Gets a line of data belonging to 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 FindElementValueAsNumber(const std::string &el="")
Searches for the named element and returns the data belonging to it as a number.
Base class for all engines.
virtual void ResetToIC(void)
Resets the Engine parameters to the initial conditions.
Encapsulates the JSBSim simulation executive.
void SuspendIntegration(void)
Suspends the simulation and sets the delta T to zero.
std::shared_ptr< FGPropertyManager > GetPropertyManager(void) const
Returns a pointer to the property manager object.
void ResumeIntegration(void)
Resumes the simulation by resetting delta T to the correct value.
std::shared_ptr< FGFunction > GetPreFunction(const std::string &name)
Get one of the "pre" function.
double Seek(double *var, double target, double accel, double decel)
A lag filter.
void Calculate(void)
Calculates the thrust of the engine, and other engine functions.
void ResetToIC(void)
Resets the Engine parameters to the initial conditions.
double CalcFuelNeed(void)
The fuel need is calculated based on power levels and flow rate for that power level.
FGTurbine(FGFDMExec *Executive, Element *el, int engine_number, struct Inputs &input)
Constructor.