JSBSim Flight Dynamics Model 1.2.4 (07 Feb 2026)
An Open Source Flight Dynamics and Control Software Library in C++
Loading...
Searching...
No Matches
FGTurbine.cpp
1/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3 Module: FGTurbine.cpp
4 Author: David Culp
5 Date started: 03/11/2003
6 Purpose: This module models a turbine engine.
7
8 ------------- Copyright (C) 2003 David Culp (daveculp@cox.net) ---------
9
10 This program is free software; you can redistribute it and/or modify it under
11 the terms of the GNU Lesser General Public License as published by the Free Software
12 Foundation; either version 2 of the License, or (at your option) any later
13 version.
14
15 This program is distributed in the hope that it will be useful, but WITHOUT
16 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
17 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
18 details.
19
20 You should have received a copy of the GNU Lesser General Public License along with
21 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
22 Place - Suite 330, Boston, MA 02111-1307, USA.
23
24 Further information about the GNU Lesser General Public License can also be found on
25 the world wide web at http://www.gnu.org.
26
27FUNCTIONAL DESCRIPTION
28--------------------------------------------------------------------------------
29
30This class descends from the FGEngine class and models a turbine engine based
31on parameters given in the engine config file for this class
32
33HISTORY
34--------------------------------------------------------------------------------
3503/11/2003 DPC Created
3609/08/2003 DPC Changed Calculate() and added engine phases
37
38%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39INCLUDES
40%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
41
42#include <iostream>
43#include <sstream>
44
45#include "FGFDMExec.h"
46#include "math/FGFunction.h"
47#include "math/FGRealValue.h"
48#include "FGTurbine.h"
49#include "FGThruster.h"
50#include "input_output/FGXMLElement.h"
51#include "input_output/string_utilities.h"
52
53using namespace std;
54
55namespace JSBSim {
56
57/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
58CLASS IMPLEMENTATION
59%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
60
61FGTurbine::FGTurbine(FGFDMExec* exec, Element *el, int engine_number, struct Inputs& input)
62 : FGEngine(engine_number, input), FDMExec(exec)
63{
64 Type = etTurbine;
65
66 MilThrust = MaxThrust = 10000.0;
67 TSFC = std::make_unique<FGSimplifiedTSFC>(this, 0.8);
68 ATSFC = std::make_unique<FGRealValue>(1.7);
69 IdleN1 = 30.0;
70 IdleN2 = 60.0;
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;
77 InjectionTime = 30.0;
78 InjectionTimer = InjWaterNorm = 0.0;
79 EPR = 1.0;
80 disableWindmill = false;
81 ThrottlePos = 0.0;
82
83 Load(exec, el);
84 Debug(0);
85}
86
87//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
88
90{
92
93 N1 = N2 = InjN1increment = InjN2increment = 0.0;
94 N2norm = 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;
99 Cutoff = true;
100 phase = tpOff;
101 EGT_degC = in.TAT_c;
102 OilTemp_degK = in.TAT_c + 273.0;
103}
104
105//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106// The main purpose of Calculate() is to determine what phase the engine should
107// be in, then call the corresponding function.
108
110{
111 double thrust;
112
113 RunPreFunctions();
114
115 ThrottlePos = in.ThrottlePos[EngineNumber];
116
117 if (ThrottlePos > 1.0) {
118 AugmentCmd = ThrottlePos - 1.0;
119 ThrottlePos -= AugmentCmd;
120 } else {
121 AugmentCmd = 0.0;
122 }
123
124 // When trimming is finished check if user wants engine OFF or RUNNING
125 if ((phase == tpTrim) && (in.TotalDeltaT > 0)) {
126 if (Running && !Starved) {
127 phase = tpRun;
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;
133 Cutoff = false;
134 } else {
135 phase = tpOff;
136 Cutoff = true;
137 EGT_degC = in.TAT_c;
138 }
139 }
140
141 if (!Running && Cutoff && Starter) {
142 if (phase == tpOff) phase = tpSpinUp;
143 }
144
145 // start
146 if ((Starter == true) || (in.qbar > 30.0)) {
147 if (!Running && !Cutoff && (N2 > 15.0)) phase = tpStart;
148 }
149
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;
155
156 switch (phase) {
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();
165 }
166
167 LoadThrusterInputs();
168 Thruster->Calculate(thrust); // allow thruster to modify thrust (i.e. reversing)
169
170 RunPostFunctions();
171}
172
173//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
174
175double FGTurbine::Off(void)
176{
177 Running = false;
178 FuelFlow_pph = Seek(&FuelFlow_pph, 0, 1000.0, 10000.0);
179 // some engines have inlets that close when they are off. So, if a flag is true disable windmilling
180 if (disableWindmill == false) {
181 // Need a small non-zero increment for acceleration otherwise acceleration will be 0 if N1 = 0
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);
184 } else {
185 N1 = Seek(&N1, 0, N1/2.0, N1/N1_spindown);
186 N2 = Seek(&N2, 0, N2/2.0, N2/N2_spindown);
187 }
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;
194 return 0.0;
195}
196
197//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
198
199double FGTurbine::Run()
200{
201 double idlethrust, milthrust, thrust;
202
203 idlethrust = MilThrust * IdleThrustLookup->GetValue();
204 milthrust = (MilThrust - idlethrust) * MilThrustLookup->GetValue();
205
206 Running = true;
207 Starter = false;
208
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;
214 }
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);
224
225 if (!Augmentation) {
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;
232 }
233
234 if (AugMethod == 1) {
235 if ((ThrottlePos > 0.99) && (N2 > 97.0)) {Augmentation = true;}
236 else {Augmentation = false;}
237 }
238
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);
243 }
244
245 if (AugMethod == 2) {
246 if (AugmentCmd > 0.0) {
247 Augmentation = true;
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);
252 } else {
253 Augmentation = false;
254 }
255 }
256
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);
262 } else {
263 Injection = false;
264 InjWaterNorm = 0.0;
265 }
266 }
267
268 if (Cutoff) phase = tpOff;
269 if (Starved) phase = tpOff;
270
271 return thrust;
272}
273
274//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275
276double FGTurbine::SpinUp(void)
277{
278 Running = false;
279 FuelFlow_pph = 0.0;
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);
285 EPR = 1.0;
286 NozzlePosition = 1.0;
287 if (Starter == false) phase = tpOff;
288 return 0.0;
289}
290
291//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
292
293double FGTurbine::Start(void)
294{
295 if ((N2 > 15.0) && !Starved) { // minimum 15% N2 needed for start
296 Cranking = true; // provided for sound effects signal
297 if (N2 < IdleN2) {
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; // aborted start
304 }
305 else {
306 phase = tpRun;
307 Running = true;
308 Starter = false;
309 Cranking = false;
310 }
311 }
312 else { // no start if N2 < 15%
313 phase = tpOff;
314 Starter = false;
315 }
316
317 return 0.0;
318}
319
320//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
321
322double FGTurbine::Stall(void)
323{
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) {
329 phase = tpRun; // clear the stall with throttle to idle
330 Stalled = false;
331 }
332 return 0.0;
333}
334
335//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
336
337double FGTurbine::Seize(void)
338{
339 N2 = 0.0;
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);
344 Running = false;
345 return 0.0;
346}
347
348//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
349
350double FGTurbine::Trim()
351{
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);
358
359 if (AugMethod == 1) {
360 if ((ThrottlePos > 0.99) && (N2 > 97.0)) {Augmentation = true;}
361 else {Augmentation = false;}
362 }
363
364 if ((Augmented == 1) && Augmentation && (AugMethod < 2)) {
365 thrust = MaxThrust * MaxThrustLookup->GetValue();
366 }
367
368 if (AugMethod == 2) {
369 if (AugmentCmd > 0.0) {
370 double tdiff = (MaxThrust * MaxThrustLookup->GetValue()) - thrust;
371 thrust += (tdiff * std::min(AugmentCmd, 1.0));
372 }
373 }
374
375 if ((Injected == 1) && Injection) {
376 thrust = thrust * InjectionLookup->GetValue();
377 }
378
379 return thrust;
380}
381
382//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
383
385{
386 FuelFlowRate = FuelFlow_pph / 3600.0; // Calculates flow in lbs/sec from lbs/hr
387 FuelExpended = FuelFlowRate * in.TotalDeltaT; // Calculates fuel expended in this time step
388 if (!Starved) FuelUsedLbs += FuelExpended;
389 return FuelExpended;
390}
391
392//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
393
394double FGTurbine::GetPowerAvailable(void) const {
395 if( ThrottlePos <= 0.77 )
396 return 64.94*ThrottlePos;
397 else
398 return 217.38*ThrottlePos - 117.38;
399}
400
401//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
402
403double FGTurbine::Seek(double *var, double target, double accel, double decel) {
404 double v = *var;
405 if (v > target) {
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;
411 }
412 return v;
413}
414
415//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
416
417bool FGTurbine::Load(FGFDMExec* exec, Element *el)
418{
419 Element* function_element = el->FindElement("function");
420
421 while(function_element) {
422 string name = function_element->GetAttributeValue("name");
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);
427
428 function_element = el->FindNextElement("function");
429 }
430
431 FGEngine::Load(exec, el);
432
433 ResetToIC();
434
435 if (el->FindElement("milthrust"))
436 MilThrust = el->FindElementValueAsNumberConvertTo("milthrust","LBS");
437 if (el->FindElement("maxthrust"))
438 MaxThrust = el->FindElementValueAsNumberConvertTo("maxthrust","LBS");
439 if (el->FindElement("bypassratio"))
440 BypassRatio = el->FindElementValueAsNumber("bypassratio");
441 if (el->FindElement("bleed"))
442 BleedDemand = el->FindElementValueAsNumber("bleed");
443 if (el->FindElement("ignitionn1"))
444 IgnitionN1 = el->FindElementValueAsNumber("ignitionn1");
445 if (el->FindElement("ignitionn2"))
446 IgnitionN2 = el->FindElementValueAsNumber("ignitionn2");
447 if (el->FindElement("idlen1"))
448 IdleN1 = el->FindElementValueAsNumber("idlen1");
449 if (el->FindElement("idlen2"))
450 IdleN2 = el->FindElementValueAsNumber("idlen2");
451 if (el->FindElement("maxn1"))
452 MaxN1 = el->FindElementValueAsNumber("maxn1");
453 if (el->FindElement("maxn2"))
454 MaxN2 = el->FindElementValueAsNumber("maxn2");
455 if (el->FindElement("n1spinup"))
456 N1_spinup = el->FindElementValueAsNumber("n1spinup");
457 if (el->FindElement("n2spinup"))
458 N2_spinup = el->FindElementValueAsNumber("n2spinup");
459 if (el->FindElement("n1startrate"))
460 N1_start_rate = el->FindElementValueAsNumber("n1startrate");
461 if (el->FindElement("n2startrate"))
462 N2_start_rate = el->FindElementValueAsNumber("n2startrate");
463 if (el->FindElement("n1spindown"))
464 N1_spindown = el->FindElementValueAsNumber("n1spindown");
465 if (el->FindElement("n2spindown"))
466 N2_spindown = el->FindElementValueAsNumber("n2spindown");
467 if (el->FindElement("augmented"))
468 Augmented = (int)el->FindElementValueAsNumber("augmented");
469 if (el->FindElement("augmethod"))
470 AugMethod = (int)el->FindElementValueAsNumber("augmethod");
471 if (el->FindElement("injected"))
472 Injected = (int)el->FindElementValueAsNumber("injected");
473 if (el->FindElement("injection-time")){
474 InjectionTime = el->FindElementValueAsNumber("injection-time");
475 InjWaterNorm =1.0;
476 }
477 if (el->FindElement("injection-N1-inc"))
478 InjN1increment = el->FindElementValueAsNumber("injection-N1-inc");
479 if (el->FindElement("injection-N2-inc"))
480 InjN2increment = el->FindElementValueAsNumber("injection-N2-inc");
481 if (el->FindElement("disable-windmill"))
482 disableWindmill = el->FindElementValueAsBoolean("disable-windmill");
483 string property_prefix = CreateIndexedPropertyName("propulsion/engine", EngineNumber);
484
485 IdleThrustLookup = GetPreFunction(property_prefix+"/IdleThrust");
486 MilThrustLookup = GetPreFunction(property_prefix+"/MilThrust");
487 MaxThrustLookup = GetPreFunction(property_prefix+"/AugThrust");
488 InjectionLookup = GetPreFunction(property_prefix+"/Injection");
489
490 JSBSim::Element* tsfcElement = el->FindElement("tsfc");
491 if (tsfcElement) {
492 string value = tsfcElement->GetDataLine();
493 try {
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));
497 }
498 }
499
500 JSBSim::Element* atsfcElement = el->FindElement("atsfc");
501 if (atsfcElement) {
502 string value = atsfcElement->GetDataLine();
503 try {
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));
507 }
508 }
509
510 // Pre-calculations and initializations
511 N1SpoolUp = GetPreFunction(property_prefix+"/N1SpoolUp");
512 if (!N1SpoolUp)
513 N1SpoolUp = std::make_shared<FGSpoolUp>(this, BypassRatio, 1.0);
514
515 N1SpoolDown = GetPreFunction(property_prefix+"/N1SpoolDown");
516 if (!N1SpoolDown)
517 N1SpoolDown = std::make_shared<FGSpoolUp>(this, BypassRatio, 2.4);
518
519 N2SpoolUp = GetPreFunction(property_prefix+"/N2SpoolUp");
520 if (!N2SpoolUp)
521 N2SpoolUp = std::make_shared<FGSpoolUp>(this, BypassRatio, 1.0);
522
523 N2SpoolDown = GetPreFunction(property_prefix+"/N2SpoolDown");
524 if (!N2SpoolDown)
525 N2SpoolDown = std::make_shared<FGSpoolUp>(this, BypassRatio, 3.0);
526
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; // just an estimate
531
532 bindmodel(exec->GetPropertyManager().get());
533 return true;
534}
535
536//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
537
538string FGTurbine::GetEngineLabels(const string& delimiter)
539{
540 std::ostringstream buf;
541
542 buf << Name << "_N1[" << EngineNumber << "]" << delimiter
543 << Name << "_N2[" << EngineNumber << "]" << delimiter
544 << Thruster->GetThrusterLabels(EngineNumber, delimiter);
545
546 return buf.str();
547}
548
549//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
550
551string FGTurbine::GetEngineValues(const string& delimiter)
552{
553 std::ostringstream buf;
554
555 buf << N1 << delimiter
556 << N2 << delimiter
557 << Thruster->GetThrusterValues(EngineNumber, delimiter);
558
559 return buf.str();
560}
561
562//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
563
564void FGTurbine::bindmodel(FGPropertyManager* PropertyManager)
565{
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);
605}
606
607//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
608
609int FGTurbine::InitRunning(void)
610{
611 FDMExec->SuspendIntegration();
612 Cutoff=false;
613 Running=true;
614 N1_factor = MaxN1 - IdleN1;
615 N2_factor = MaxN2 - IdleN2;
616 N2 = IdleN2 + ThrottlePos * N2_factor;
617 N1 = IdleN1 + ThrottlePos * N1_factor;
618 Calculate();
619 FDMExec->ResumeIntegration();
620 return phase=tpRun;
621}
622
623//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
624// The bitmasked value choices are as follows:
625// unset: In this case (the default) JSBSim would only print
626// out the normally expected messages, essentially echoing
627// the config files as they are read. If the environment
628// variable is not set, debug_lvl is set to 1 internally
629// 0: This requests JSBSim not to output any messages
630// whatsoever.
631// 1: This value explicity requests the normal JSBSim
632// startup messages
633// 2: This value asks for a message to be printed out when
634// a class is instantiated
635// 4: When this value is set, a message is displayed when a
636// FGModel object executes its Run() method
637// 8: When this value is set, various runtime state variables
638// are printed out periodically
639// 16: When set various parameters are sanity checked and
640// a message is printed out when they go out of bounds
641
642void FGTurbine::Debug(int from)
643{
644 if (debug_lvl <= 0) return;
645
646 if (debug_lvl & 1) { // Standard console startup message output
647 if (from == 0) { // Constructor
648
649 }
650 if (from == 2) { // called from Load()
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;
665
666 cout << endl;
667 }
668 }
669 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
670 if (from == 0) cout << "Instantiated: FGTurbine" << endl;
671 if (from == 1) cout << "Destroyed: FGTurbine" << endl;
672 }
673 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
674 }
675 if (debug_lvl & 8 ) { // Runtime state variables
676 }
677 if (debug_lvl & 16) { // Sanity checking
678 }
679 if (debug_lvl & 64) {
680 if (from == 0) { // Constructor
681 }
682 }
683}
684}
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.
Definition FGEngine.h:104
virtual void ResetToIC(void)
Resets the Engine parameters to the initial conditions.
Definition FGEngine.cpp:77
Encapsulates the JSBSim simulation executive.
Definition FGFDMExec.h:184
void SuspendIntegration(void)
Suspends the simulation and sets the delta T to zero.
Definition FGFDMExec.h:555
std::shared_ptr< FGPropertyManager > GetPropertyManager(void) const
Returns a pointer to the property manager object.
Definition FGFDMExec.h:421
void ResumeIntegration(void)
Resumes the simulation by resetting delta T to the correct value.
Definition FGFDMExec.h:558
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.
Definition FGTurbine.cpp:89
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.
Definition FGTurbine.cpp:61