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;
92 N1 = N2 = InjN1increment = InjN2increment = 0.0;
94 correctedTSFC = TSFC->GetValue();
95 AugmentCmd = InjWaterNorm = 0.0;
96 InletPosition = NozzlePosition = 1.0;
97 Stalled = Seized = Overtemp = Fire = Augmentation = Injection = Reversed =
false;
101 OilTemp_degK = in.TAT_c + 273.0;
114 ThrottlePos = in.ThrottlePos[EngineNumber];
116 if (ThrottlePos > 1.0) {
117 AugmentCmd = ThrottlePos - 1.0;
118 ThrottlePos -= AugmentCmd;
124 if ((phase == tpTrim) && (in.TotalDeltaT > 0)) {
125 if (Running && !Starved) {
127 N1_factor = MaxN1 - IdleN1;
128 N2_factor = MaxN2 - IdleN2;
129 N2 = IdleN2 + ThrottlePos * N2_factor;
130 N1 = IdleN1 + ThrottlePos * N1_factor;
131 OilTemp_degK = 366.0;
140 if (!Running && Cutoff && Starter) {
141 if (phase == tpOff) phase = tpSpinUp;
145 if ((Starter ==
true) || (in.qbar > 30.0)) {
146 if (!Running && !Cutoff && (N2 > 15.0)) phase = tpStart;
149 if (Cutoff && (phase != tpSpinUp)) phase = tpOff;
150 if (in.TotalDeltaT == 0) phase = tpTrim;
151 if (Starved) phase = tpOff;
152 if (Stalled) phase = tpStall;
153 if (Seized) phase = tpSeize;
156 case tpOff: thrust = Off();
break;
157 case tpRun: thrust = Run();
break;
158 case tpSpinUp: thrust = SpinUp();
break;
159 case tpStart: thrust = Start();
break;
160 case tpStall: thrust = Stall();
break;
161 case tpSeize: thrust = Seize();
break;
162 case tpTrim: thrust = Trim();
break;
163 default: thrust = Off();
166 LoadThrusterInputs();
167 Thruster->Calculate(thrust);
174double FGTurbine::Off(
void)
177 FuelFlow_pph =
Seek(&FuelFlow_pph, 0, 1000.0, 10000.0);
179 if (disableWindmill ==
false) {
181 N1 =
Seek(&N1, in.qbar/10.0, N1/2.0 + 0.1, N1/N1_spindown);
182 N2 =
Seek(&N2, in.qbar/15.0, N2/2.0 + 0.1, N2/N2_spindown);
184 N1 =
Seek(&N1, 0, N1/2.0, N1/N1_spindown);
185 N2 =
Seek(&N2, 0, N2/2.0, N2/N2_spindown);
187 EGT_degC =
Seek(&EGT_degC, in.TAT_c, 11.7, 7.3);
188 OilTemp_degK =
Seek(&OilTemp_degK, in.TAT_c + 273.0, 0.2, 0.2);
189 OilPressure_psi = N2 * 0.62;
190 NozzlePosition =
Seek(&NozzlePosition, 1.0, 0.8, 0.8);
191 EPR =
Seek(&EPR, 1.0, 0.2, 0.2);
192 Augmentation =
false;
198double FGTurbine::Run()
200 double idlethrust, milthrust, thrust;
202 idlethrust = MilThrust * IdleThrustLookup->GetValue();
203 milthrust = (MilThrust - idlethrust) * MilThrustLookup->GetValue();
208 N1_factor = MaxN1 - IdleN1;
209 N2_factor = MaxN2 - IdleN2;
210 if ((Injected == 1) && Injection && (InjWaterNorm > 0)) {
211 N1_factor += InjN1increment;
212 N2_factor += InjN2increment;
214 N2 =
Seek(&N2, IdleN2 + ThrottlePos * N2_factor,
215 N2SpoolUp->GetValue(), N2SpoolDown->GetValue());
216 N1 =
Seek(&N1, IdleN1 + ThrottlePos * N1_factor,
217 N1SpoolUp->GetValue(), N1SpoolDown->GetValue());
218 N2norm = (N2 - IdleN2) / N2_factor;
219 thrust = idlethrust + (milthrust * N2norm * N2norm);
220 EGT_degC = in.TAT_c + 363.1 + ThrottlePos * 357.1;
221 OilPressure_psi = N2 * 0.62;
222 OilTemp_degK =
Seek(&OilTemp_degK, 366.0, 1.2, 0.1);
225 correctedTSFC = TSFC->GetValue();
226 FuelFlow_pph =
Seek(&FuelFlow_pph, thrust * correctedTSFC, 1000.0, 10000.0);
227 if (FuelFlow_pph < IdleFF) FuelFlow_pph = IdleFF;
228 NozzlePosition =
Seek(&NozzlePosition, 1.0 - N2norm, 0.8, 0.8);
229 thrust = thrust * (1.0 - BleedDemand);
230 EPR = 1.0 + thrust/MilThrust;
233 if (AugMethod == 1) {
234 if ((ThrottlePos > 0.99) && (N2 > 97.0)) {Augmentation =
true;}
235 else {Augmentation =
false;}
238 if ((Augmented == 1) && Augmentation && (AugMethod < 2)) {
239 thrust = MaxThrustLookup->GetValue() * MaxThrust;
240 FuelFlow_pph =
Seek(&FuelFlow_pph, thrust * ATSFC->GetValue(), 5000.0, 10000.0);
241 NozzlePosition =
Seek(&NozzlePosition, 1.0, 0.8, 0.8);
244 if (AugMethod == 2) {
245 if (AugmentCmd > 0.0) {
247 double tdiff = (MaxThrust * MaxThrustLookup->GetValue()) - thrust;
248 thrust += (tdiff * std::min(AugmentCmd, 1.0));
249 FuelFlow_pph =
Seek(&FuelFlow_pph, thrust * ATSFC->GetValue(), 5000.0, 10000.0);
250 NozzlePosition =
Seek(&NozzlePosition, 1.0, 0.8, 0.8);
252 Augmentation =
false;
256 if ((Injected == 1) && Injection && (InjWaterNorm > 0.0)) {
257 InjectionTimer += in.TotalDeltaT;
258 if (InjectionTimer < InjectionTime) {
259 thrust = thrust * InjectionLookup->GetValue();
260 InjWaterNorm = 1.0 - (InjectionTimer/InjectionTime);
267 if (Cutoff) phase = tpOff;
268 if (Starved) phase = tpOff;
275double FGTurbine::SpinUp(
void)
279 N2 =
Seek(&N2, IgnitionN2, N2_spinup, N2/2.0);
280 N1 =
Seek(&N1, IgnitionN1, N1_spinup, N1/2.0);
281 EGT_degC =
Seek(&EGT_degC, in.TAT_c, 11.7, 7.3);
282 OilPressure_psi = N2 * 0.62;
283 OilTemp_degK =
Seek(&OilTemp_degK, in.TAT_c + 273.0, 0.2, 0.2);
285 NozzlePosition = 1.0;
286 if (Starter ==
false) phase = tpOff;
292double FGTurbine::Start(
void)
294 if ((N2 > 15.0) && !Starved) {
297 N2 =
Seek(&N2, IdleN2, N2_start_rate, N2/2.0);
298 N1 =
Seek(&N1, IdleN1, N1_start_rate, N1/2.0);
299 EGT_degC =
Seek(&EGT_degC, in.TAT_c + 363.1, 21.3, 7.3);
300 FuelFlow_pph = IdleFF * N2 / IdleN2;
301 OilPressure_psi = N2 * 0.62;
302 if ((Starter ==
false) && (in.qbar < 30.0)) phase = tpOff;
321double FGTurbine::Stall(
void)
323 EGT_degC = in.TAT_c + 903.14;
324 FuelFlow_pph = IdleFF;
325 N1 =
Seek(&N1, in.qbar/10.0, 0, N1/10.0);
326 N2 =
Seek(&N2, in.qbar/15.0, 0, N2/10.0);
327 if (ThrottlePos < 0.01) {
336double FGTurbine::Seize(
void)
339 N1 =
Seek(&N1, in.qbar/20.0, 0, N1/15.0);
340 FuelFlow_pph = Cutoff ? 0.0 : IdleFF;
341 OilPressure_psi = 0.0;
342 OilTemp_degK =
Seek(&OilTemp_degK, in.TAT_c + 273.0, 0, 0.2);
349double FGTurbine::Trim()
351 double idlethrust = MilThrust * IdleThrustLookup->GetValue();
352 double milthrust = (MilThrust - idlethrust) * MilThrustLookup->GetValue();
353 double N2 = IdleN2 + ThrottlePos * N2_factor;
354 double N2norm = (N2 - IdleN2) / N2_factor;
355 double thrust = (idlethrust + (milthrust * N2norm * N2norm))
356 * (1.0 - BleedDemand);
358 if (AugMethod == 1) {
359 if ((ThrottlePos > 0.99) && (N2 > 97.0)) {Augmentation =
true;}
360 else {Augmentation =
false;}
363 if ((Augmented == 1) && Augmentation && (AugMethod < 2)) {
364 thrust = MaxThrust * MaxThrustLookup->GetValue();
367 if (AugMethod == 2) {
368 if (AugmentCmd > 0.0) {
369 double tdiff = (MaxThrust * MaxThrustLookup->GetValue()) - thrust;
370 thrust += (tdiff * std::min(AugmentCmd, 1.0));
374 if ((Injected == 1) && Injection) {
375 thrust = thrust * InjectionLookup->GetValue();
385 FuelFlowRate = FuelFlow_pph / 3600.0;
386 FuelExpended = FuelFlowRate * in.TotalDeltaT;
387 if (!Starved) FuelUsedLbs += FuelExpended;
393double FGTurbine::GetPowerAvailable(
void)
const {
394 if( ThrottlePos <= 0.77 )
395 return 64.94*ThrottlePos;
397 return 217.38*ThrottlePos - 117.38;
405 v -= in.TotalDeltaT * decel;
406 if (v < target) v = target;
407 }
else if (v < target) {
408 v += in.TotalDeltaT * accel;
409 if (v > target) v = target;
420 while(function_element) {
422 if (name ==
"IdleThrust" || name ==
"MilThrust" || name ==
"AugThrust"
423 || name ==
"Injection" || name ==
"N1SpoolUp" || name ==
"N1SpoolDown"
424 || name ==
"N2SpoolUp" || name ==
"N2SpoolDown")
425 function_element->
SetAttributeValue(
"name",
string(
"propulsion/engine[#]/") + name);
430 FGEngine::Load(exec, el);
482 string property_prefix = CreateIndexedPropertyName(
"propulsion/engine", EngineNumber);
493 TSFC = std::make_unique<FGSimplifiedTSFC>(
this, atof_locale_c(value));
494 }
catch (InvalidNumber&) {
495 TSFC = std::make_unique<FGFunction>(FDMExec, tsfcElement, to_string(EngineNumber));
503 ATSFC = std::make_unique<FGRealValue>(atof_locale_c(value));
504 }
catch (InvalidNumber&) {
505 ATSFC = std::make_unique<FGFunction>(FDMExec, atsfcElement, to_string((
int)EngineNumber));
512 N1SpoolUp = std::make_shared<FGSpoolUp>(
this, BypassRatio, 1.0);
516 N1SpoolDown = std::make_shared<FGSpoolUp>(
this, BypassRatio, 2.4);
520 N2SpoolUp = std::make_shared<FGSpoolUp>(
this, BypassRatio, 1.0);
524 N2SpoolDown = std::make_shared<FGSpoolUp>(
this, BypassRatio, 3.0);
526 N1_factor = MaxN1 - IdleN1;
527 N2_factor = MaxN2 - IdleN2;
528 OilTemp_degK = in.TAT_c + 273.0;
529 IdleFF = pow(MilThrust, 0.2) * 107.0;
537string FGTurbine::GetEngineLabels(
const string& delimiter)
539 std::ostringstream buf;
541 buf << Name <<
"_N1[" << EngineNumber <<
"]" << delimiter
542 << Name <<
"_N2[" << EngineNumber <<
"]" << delimiter
543 << Thruster->GetThrusterLabels(EngineNumber, delimiter);
550string FGTurbine::GetEngineValues(
const string& delimiter)
552 std::ostringstream buf;
554 buf << N1 << delimiter
556 << Thruster->GetThrusterValues(EngineNumber, delimiter);
563void FGTurbine::bindmodel(FGPropertyManager* PropertyManager)
565 string property_name, base_property_name;
566 base_property_name = CreateIndexedPropertyName(
"propulsion/engine", EngineNumber);
567 property_name = base_property_name +
"/n1";
568 PropertyManager->Tie( property_name.c_str(), &N1);
569 property_name = base_property_name +
"/n2";
570 PropertyManager->Tie( property_name.c_str(), &N2);
571 property_name = base_property_name +
"/injection_cmd";
572 PropertyManager->Tie( property_name.c_str(),
this,
573 &FGTurbine::GetInjection, &FGTurbine::SetInjection);
574 property_name = base_property_name +
"/seized";
575 PropertyManager->Tie( property_name.c_str(), &Seized);
576 property_name = base_property_name +
"/stalled";
577 PropertyManager->Tie( property_name.c_str(), &Stalled);
578 property_name = base_property_name +
"/bleed-factor";
579 PropertyManager->Tie( property_name.c_str(),
this, &FGTurbine::GetBleedDemand, &FGTurbine::SetBleedDemand);
580 property_name = base_property_name +
"/MaxN1";
581 PropertyManager->Tie( property_name.c_str(),
this,
582 &FGTurbine::GetMaxN1, &FGTurbine::SetMaxN1);
583 property_name = base_property_name +
"/MaxN2";
584 PropertyManager->Tie( property_name.c_str(),
this,
585 &FGTurbine::GetMaxN2, &FGTurbine::SetMaxN2);
586 property_name = base_property_name +
"/InjectionTimer";
587 PropertyManager->Tie( property_name.c_str(),
this,
588 &FGTurbine::GetInjectionTimer, &FGTurbine::SetInjectionTimer);
589 property_name = base_property_name +
"/InjWaterNorm";
590 PropertyManager->Tie( property_name.c_str(),
this,
591 &FGTurbine::GetInjWaterNorm, &FGTurbine::SetInjWaterNorm);
592 property_name = base_property_name +
"/InjN1increment";
593 PropertyManager->Tie( property_name.c_str(),
this,
594 &FGTurbine::GetInjN1increment, &FGTurbine::SetInjN1increment);
595 property_name = base_property_name +
"/InjN2increment";
596 PropertyManager->Tie( property_name.c_str(),
this,
597 &FGTurbine::GetInjN2increment, &FGTurbine::SetInjN2increment);
598 property_name = base_property_name +
"/atsfc";
599 PropertyManager->Tie(property_name.c_str(), ATSFC.get(), &FGParameter::GetValue);
600 property_name = base_property_name +
"/tsfc";
601 PropertyManager->Tie(property_name.c_str(), &correctedTSFC);
602 auto node = PropertyManager->GetNode(property_name.c_str(),
false);
603 node->setAttribute(SGPropertyNode::WRITE,
false);
608int FGTurbine::InitRunning(
void)
613 N1_factor = MaxN1 - IdleN1;
614 N2_factor = MaxN2 - IdleN2;
615 N2 = IdleN2 + ThrottlePos * N2_factor;
616 N1 = IdleN1 + ThrottlePos * N1_factor;
641void FGTurbine::Debug(
int from)
643 if (debug_lvl <= 0)
return;
650 cout <<
"\n Engine Name: " << Name << endl;
651 cout <<
" MilThrust: " << MilThrust << endl;
652 cout <<
" MaxThrust: " << MaxThrust << endl;
653 cout <<
" BypassRatio: " << BypassRatio << endl;
654 cout <<
" TSFC: " << TSFC->GetValue() << endl;
655 cout <<
" ATSFC: " << ATSFC->GetValue() << endl;
656 cout <<
" IdleN1: " << IdleN1 << endl;
657 cout <<
" IdleN2: " << IdleN2 << endl;
658 cout <<
" MaxN1: " << MaxN1 << endl;
659 cout <<
" MaxN2: " << MaxN2 << endl;
660 cout <<
" Augmented: " << Augmented << endl;
661 cout <<
" AugMethod: " << AugMethod << endl;
662 cout <<
" Injected: " << Injected << endl;
663 cout <<
" MinThrottle: " << MinThrottle << endl;
668 if (debug_lvl & 2 ) {
669 if (from == 0) cout <<
"Instantiated: FGTurbine" << endl;
670 if (from == 1) cout <<
"Destroyed: FGTurbine" << endl;
672 if (debug_lvl & 4 ) {
674 if (debug_lvl & 8 ) {
676 if (debug_lvl & 16) {
678 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.