45 #include "math/FGFunction.h" 46 #include "FGTurbine.h" 47 #include "FGThruster.h" 48 #include "input_output/FGXMLElement.h" 54 IDENT(IdSrc,
"$Id: FGTurbine.cpp,v 1.48 2015/12/02 04:25:23 dpculp Exp $");
55 IDENT(IdHdr,ID_TURBINE);
63 :
FGEngine(engine_number, input), FDMExec(exec)
67 MilThrust = MaxThrust = 10000.0;
72 MaxN1 = MaxN2 = 100.0;
73 Augmented = AugMethod = Injected = 0;
74 BypassRatio = BleedDemand = 0.0;
75 IdleThrustLookup = MilThrustLookup = MaxThrustLookup = InjectionLookup = 0;
76 N1_spinup = 1.0; N2_spinup = 3.0;
78 InjectionTimer = InjWaterNorm = 0.0;
99 N1 = N2 = InjN1increment = InjN2increment = 0.0;
101 correctedTSFC = TSFC;
102 AugmentCmd = InjWaterNorm = 0.0;
103 InletPosition = NozzlePosition = 1.0;
104 Stalled = Seized = Overtemp = Fire = Augmentation = Injection = Reversed =
false;
108 OilTemp_degK = in.TAT_c + 273.0;
121 ThrottlePos = in.ThrottlePos[EngineNumber];
123 if (ThrottlePos > 1.0) {
124 AugmentCmd = ThrottlePos - 1.0;
125 ThrottlePos -= AugmentCmd;
131 if ((phase == tpTrim) && (in.TotalDeltaT > 0)) {
132 if (Running && !Starved) {
134 N1_factor = MaxN1 - IdleN1;
135 N2_factor = MaxN2 - IdleN2;
136 N2 = IdleN2 + ThrottlePos * N2_factor;
137 N1 = IdleN1 + ThrottlePos * N1_factor;
138 OilTemp_degK = 366.0;
147 if (!Running && Cutoff && Starter) {
148 if (phase == tpOff) phase = tpSpinUp;
152 if ((Starter ==
true) || (in.qbar > 30.0)) {
153 if (!Running && !Cutoff && (N2 > 15.0)) phase = tpStart;
156 if (Cutoff && (phase != tpSpinUp)) phase = tpOff;
157 if (in.TotalDeltaT == 0) phase = tpTrim;
158 if (Starved) phase = tpOff;
159 if (Stalled) phase = tpStall;
160 if (Seized) phase = tpSeize;
163 case tpOff: thrust = Off();
break;
164 case tpRun: thrust = Run();
break;
165 case tpSpinUp: thrust = SpinUp();
break;
166 case tpStart: thrust = Start();
break;
167 case tpStall: thrust = Stall();
break;
168 case tpSeize: thrust = Seize();
break;
169 case tpTrim: thrust = Trim();
break;
170 default: thrust = Off();
173 Thruster->Calculate(thrust);
180 double FGTurbine::Off(
void)
183 FuelFlow_pph =
Seek(&FuelFlow_pph, 0, 1000.0, 10000.0);
184 N1 =
Seek(&N1, in.qbar/10.0, N1/2.0, N1/2.0);
185 N2 =
Seek(&N2, in.qbar/15.0, N2/2.0, N2/2.0);
186 EGT_degC =
Seek(&EGT_degC, in.TAT_c, 11.7, 7.3);
187 OilTemp_degK =
Seek(&OilTemp_degK, in.TAT_c + 273.0, 0.2, 0.2);
188 OilPressure_psi = N2 * 0.62;
189 NozzlePosition =
Seek(&NozzlePosition, 1.0, 0.8, 0.8);
190 EPR =
Seek(&EPR, 1.0, 0.2, 0.2);
191 Augmentation =
false;
197 double FGTurbine::Run()
199 double idlethrust, milthrust, thrust;
201 double sigma = in.DensityRatio;
202 double T = in.Temperature;
204 idlethrust = MilThrust * IdleThrustLookup->
GetValue();
205 milthrust = (MilThrust - idlethrust) * MilThrustLookup->
GetValue();
211 double n = N2norm + 0.1;
213 spoolup = delay / (1 + 3 * (1-n)*(1-n)*(1-n) + (1 - sigma));
214 N1_factor = MaxN1 - IdleN1;
215 N2_factor = MaxN2 - IdleN2;
216 if ((Injected == 1) && Injection && (InjWaterNorm > 0)) {
217 N1_factor += InjN1increment;
218 N2_factor += InjN2increment;
220 N2 =
Seek(&N2, IdleN2 + ThrottlePos * N2_factor, spoolup, spoolup * 3.0);
221 N1 =
Seek(&N1, IdleN1 + ThrottlePos * N1_factor, spoolup, spoolup * 2.4);
222 N2norm = (N2 - IdleN2) / N2_factor;
223 thrust = idlethrust + (milthrust * N2norm * N2norm);
224 EGT_degC = in.TAT_c + 363.1 + ThrottlePos * 357.1;
225 OilPressure_psi = N2 * 0.62;
226 OilTemp_degK =
Seek(&OilTemp_degK, 366.0, 1.2, 0.1);
229 correctedTSFC = TSFC * sqrt(T/389.7) * (0.84 + (1-N2norm)*(1-N2norm));
230 FuelFlow_pph =
Seek(&FuelFlow_pph, thrust * correctedTSFC, 1000.0, 10000.0);
231 if (FuelFlow_pph < IdleFF) FuelFlow_pph = IdleFF;
232 NozzlePosition =
Seek(&NozzlePosition, 1.0 - N2norm, 0.8, 0.8);
233 thrust = thrust * (1.0 - BleedDemand);
234 EPR = 1.0 + thrust/MilThrust;
237 if (AugMethod == 1) {
238 if ((ThrottlePos > 0.99) && (N2 > 97.0)) {Augmentation =
true;}
239 else {Augmentation =
false;}
242 if ((Augmented == 1) && Augmentation && (AugMethod < 2)) {
243 thrust = MaxThrustLookup->
GetValue() * MaxThrust;
244 FuelFlow_pph =
Seek(&FuelFlow_pph, thrust * ATSFC, 5000.0, 10000.0);
245 NozzlePosition =
Seek(&NozzlePosition, 1.0, 0.8, 0.8);
248 if (AugMethod == 2) {
249 if (AugmentCmd > 0.0) {
251 double tdiff = (MaxThrust * MaxThrustLookup->
GetValue()) - thrust;
252 thrust += (tdiff * AugmentCmd);
253 FuelFlow_pph =
Seek(&FuelFlow_pph, thrust * ATSFC, 5000.0, 10000.0);
254 NozzlePosition =
Seek(&NozzlePosition, 1.0, 0.8, 0.8);
256 Augmentation =
false;
260 if ((Injected == 1) && Injection && (InjWaterNorm > 0.0)) {
261 InjectionTimer += in.TotalDeltaT;
262 if (InjectionTimer < InjectionTime) {
263 thrust = thrust * InjectionLookup->
GetValue();
264 InjWaterNorm = 1.0 - (InjectionTimer/InjectionTime);
271 if (Cutoff) phase = tpOff;
272 if (Starved) phase = tpOff;
279 double FGTurbine::SpinUp(
void)
283 N2 =
Seek(&N2, 25.18, N2_spinup, N2/2.0);
284 N1 =
Seek(&N1, 5.21, N1_spinup, N1/2.0);
285 EGT_degC =
Seek(&EGT_degC, in.TAT_c, 11.7, 7.3);
286 OilPressure_psi = N2 * 0.62;
287 OilTemp_degK =
Seek(&OilTemp_degK, in.TAT_c + 273.0, 0.2, 0.2);
289 NozzlePosition = 1.0;
290 if (Starter ==
false) phase = tpOff;
296 double FGTurbine::Start(
void)
298 if ((N2 > 15.0) && !Starved) {
301 N2 =
Seek(&N2, IdleN2, 2.0, N2/2.0);
302 N1 =
Seek(&N1, IdleN1, 1.4, N1/2.0);
303 EGT_degC =
Seek(&EGT_degC, in.TAT_c + 363.1, 21.3, 7.3);
304 FuelFlow_pph = IdleFF * N2 / IdleN2;
305 OilPressure_psi = N2 * 0.62;
306 if ((Starter ==
false) && (in.qbar < 30.0)) phase = tpOff;
325 double FGTurbine::Stall(
void)
327 EGT_degC = in.TAT_c + 903.14;
328 FuelFlow_pph = IdleFF;
329 N1 =
Seek(&N1, in.qbar/10.0, 0, N1/10.0);
330 N2 =
Seek(&N2, in.qbar/15.0, 0, N2/10.0);
331 if (ThrottlePos < 0.01) {
340 double FGTurbine::Seize(
void)
343 N1 =
Seek(&N1, in.qbar/20.0, 0, N1/15.0);
344 FuelFlow_pph = Cutoff ? 0.0 : IdleFF;
345 OilPressure_psi = 0.0;
346 OilTemp_degK =
Seek(&OilTemp_degK, in.TAT_c + 273.0, 0, 0.2);
353 double FGTurbine::Trim()
355 double idlethrust = MilThrust * IdleThrustLookup->
GetValue();
356 double milthrust = (MilThrust - idlethrust) * MilThrustLookup->
GetValue();
357 double N2 = IdleN2 + ThrottlePos * N2_factor;
358 double N2norm = (N2 - IdleN2) / N2_factor;
359 double thrust = (idlethrust + (milthrust * N2norm * N2norm))
360 * (1.0 - BleedDemand);
362 if (AugMethod == 1) {
363 if ((ThrottlePos > 0.99) && (N2 > 97.0)) {Augmentation =
true;}
364 else {Augmentation =
false;}
367 if ((Augmented == 1) && Augmentation && (AugMethod < 2)) {
368 thrust = MaxThrust * MaxThrustLookup->
GetValue();
371 if (AugMethod == 2) {
372 if (AugmentCmd > 0.0) {
373 double tdiff = (MaxThrust * MaxThrustLookup->
GetValue()) - thrust;
374 thrust += (tdiff * AugmentCmd);
378 if ((Injected == 1) && Injection) {
379 thrust = thrust * InjectionLookup->
GetValue();
389 FuelFlowRate = FuelFlow_pph / 3600.0;
390 FuelExpended = FuelFlowRate * in.TotalDeltaT;
391 if (!Starved) FuelUsedLbs += FuelExpended;
397 double FGTurbine::GetPowerAvailable(
void) {
398 if( ThrottlePos <= 0.77 )
399 return 64.94*ThrottlePos;
401 return 217.38*ThrottlePos - 117.38;
409 v -= in.TotalDeltaT * decel;
410 if (v < target) v = target;
411 }
else if (v < target) {
412 v += in.TotalDeltaT * accel;
413 if (v > target) v = target;
424 while(function_element) {
426 if (name ==
"IdleThrust" || name ==
"MilThrust" || name ==
"AugThrust" || name ==
"Injection")
427 function_element->
SetAttributeValue(
"name",
string(
"propulsion/engine[#]/") + name);
432 FGEngine::Load(exec, el);
475 string property_prefix = CreateIndexedPropertyName(
"propulsion/engine", EngineNumber);
484 delay = 90.0 / (BypassRatio + 3.0);
485 N1_factor = MaxN1 - IdleN1;
486 N2_factor = MaxN2 - IdleN2;
487 OilTemp_degK = in.TAT_c + 273.0;
488 IdleFF = pow(MilThrust, 0.2) * 107.0;
496 string FGTurbine::GetEngineLabels(
const string& delimiter)
498 std::ostringstream buf;
500 buf << Name <<
"_N1[" << EngineNumber <<
"]" << delimiter
501 << Name <<
"_N2[" << EngineNumber <<
"]" << delimiter
502 << Thruster->GetThrusterLabels(EngineNumber, delimiter);
509 string FGTurbine::GetEngineValues(
const string& delimiter)
511 std::ostringstream buf;
513 buf << N1 << delimiter
515 << Thruster->GetThrusterValues(EngineNumber, delimiter);
524 string property_name, base_property_name;
525 base_property_name = CreateIndexedPropertyName(
"propulsion/engine", EngineNumber);
526 property_name = base_property_name +
"/n1";
527 PropertyManager->
Tie( property_name.c_str(), &N1);
528 property_name = base_property_name +
"/n2";
529 PropertyManager->
Tie( property_name.c_str(), &N2);
530 property_name = base_property_name +
"/injection_cmd";
531 PropertyManager->
Tie( property_name.c_str(), (
FGTurbine*)
this,
532 &FGTurbine::GetInjection, &FGTurbine::SetInjection);
533 property_name = base_property_name +
"/seized";
534 PropertyManager->
Tie( property_name.c_str(), &Seized);
535 property_name = base_property_name +
"/stalled";
536 PropertyManager->
Tie( property_name.c_str(), &Stalled);
537 property_name = base_property_name +
"/bleed-factor";
538 PropertyManager->
Tie( property_name.c_str(), (
FGTurbine*)
this, &FGTurbine::GetBleedDemand, &FGTurbine::SetBleedDemand);
539 property_name = base_property_name +
"/MaxN1";
540 PropertyManager->
Tie( property_name.c_str(), (
FGTurbine*)
this,
541 &FGTurbine::GetMaxN1, &FGTurbine::SetMaxN1);
542 property_name = base_property_name +
"/MaxN2";
543 PropertyManager->
Tie( property_name.c_str(), (
FGTurbine*)
this,
544 &FGTurbine::GetMaxN2, &FGTurbine::SetMaxN2);
545 property_name = base_property_name +
"/InjectionTimer";
546 PropertyManager->
Tie( property_name.c_str(), (
FGTurbine*)
this,
547 &FGTurbine::GetInjectionTimer, &FGTurbine::SetInjectionTimer);
548 property_name = base_property_name +
"/InjWaterNorm";
549 PropertyManager->
Tie( property_name.c_str(), (
FGTurbine*)
this,
550 &FGTurbine::GetInjWaterNorm, &FGTurbine::SetInjWaterNorm);
551 property_name = base_property_name +
"/InjN1increment";
552 PropertyManager->
Tie( property_name.c_str(), (
FGTurbine*)
this,
553 &FGTurbine::GetInjN1increment, &FGTurbine::SetInjN1increment);
554 property_name = base_property_name +
"/InjN2increment";
555 PropertyManager->
Tie( property_name.c_str(), (
FGTurbine*)
this,
556 &FGTurbine::GetInjN2increment, &FGTurbine::SetInjN2increment);
561 int FGTurbine::InitRunning(
void)
566 N1_factor = MaxN1 - IdleN1;
567 N2_factor = MaxN2 - IdleN2;
568 N2 = IdleN2 + ThrottlePos * N2_factor;
569 N1 = IdleN1 + ThrottlePos * N1_factor;
594 void FGTurbine::Debug(
int from)
596 if (debug_lvl <= 0)
return;
603 cout <<
"\n Engine Name: " << Name << endl;
604 cout <<
" MilThrust: " << MilThrust << endl;
605 cout <<
" MaxThrust: " << MaxThrust << endl;
606 cout <<
" BypassRatio: " << BypassRatio << endl;
607 cout <<
" TSFC: " << TSFC << endl;
608 cout <<
" ATSFC: " << ATSFC << endl;
609 cout <<
" IdleN1: " << IdleN1 << endl;
610 cout <<
" IdleN2: " << IdleN2 << endl;
611 cout <<
" MaxN1: " << MaxN1 << endl;
612 cout <<
" MaxN2: " << MaxN2 << endl;
613 cout <<
" Augmented: " << Augmented << endl;
614 cout <<
" AugMethod: " << AugMethod << endl;
615 cout <<
" Injected: " << Injected << endl;
616 cout <<
" MinThrottle: " << MinThrottle << endl;
621 if (debug_lvl & 2 ) {
622 if (from == 0) cout <<
"Instantiated: FGTurbine" << endl;
623 if (from == 1) cout <<
"Destroyed: FGTurbine" << endl;
625 if (debug_lvl & 4 ) {
627 if (debug_lvl & 8 ) {
629 if (debug_lvl & 16) {
631 if (debug_lvl & 64) {
633 cout << IdSrc << endl;
634 cout << IdHdr << endl;
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
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 SuspendIntegration(void)
Suspends the simulation and sets the delta T to zero.
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. ...
This class models a turbine engine.
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.
double GetValue(void) const
Retrieves the value of the function object.
FGPropertyManager * GetPropertyManager(void)
Returns a pointer to the property manager object.
void ResetToIC(void)
Resets the Engine parameters to the initial conditions.
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.
double CalcFuelNeed(void)
The fuel need is calculated based on power levels and flow rate for that power level.
void ResumeIntegration(void)
Resumes the simulation by resetting delta T to the correct value.
Base class for all engines.
Element * FindNextElement(const std::string &el="")
Searches for the next element as specified.
Encapsulates the JSBSim simulation executive.
virtual void ResetToIC(void)
Resets the Engine parameters to the initial conditions.