JSBSim Flight Dynamics Model 1.2.3 (07 Jun 2025)
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
82 Load(exec, el);
83 Debug(0);
84}
85
86//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
87
89{
91
92 N1 = N2 = InjN1increment = InjN2increment = 0.0;
93 N2norm = 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;
98 Cutoff = true;
99 phase = tpOff;
100 EGT_degC = in.TAT_c;
101 OilTemp_degK = in.TAT_c + 273.0;
102}
103
104//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105// The main purpose of Calculate() is to determine what phase the engine should
106// be in, then call the corresponding function.
107
109{
110 double thrust;
111
112 RunPreFunctions();
113
114 ThrottlePos = in.ThrottlePos[EngineNumber];
115
116 if (ThrottlePos > 1.0) {
117 AugmentCmd = ThrottlePos - 1.0;
118 ThrottlePos -= AugmentCmd;
119 } else {
120 AugmentCmd = 0.0;
121 }
122
123 // When trimming is finished check if user wants engine OFF or RUNNING
124 if ((phase == tpTrim) && (in.TotalDeltaT > 0)) {
125 if (Running && !Starved) {
126 phase = tpRun;
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;
132 Cutoff = false;
133 } else {
134 phase = tpOff;
135 Cutoff = true;
136 EGT_degC = in.TAT_c;
137 }
138 }
139
140 if (!Running && Cutoff && Starter) {
141 if (phase == tpOff) phase = tpSpinUp;
142 }
143
144 // start
145 if ((Starter == true) || (in.qbar > 30.0)) {
146 if (!Running && !Cutoff && (N2 > 15.0)) phase = tpStart;
147 }
148
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;
154
155 switch (phase) {
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();
164 }
165
166 LoadThrusterInputs();
167 Thruster->Calculate(thrust); // allow thruster to modify thrust (i.e. reversing)
168
169 RunPostFunctions();
170}
171
172//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
173
174double FGTurbine::Off(void)
175{
176 Running = false;
177 FuelFlow_pph = Seek(&FuelFlow_pph, 0, 1000.0, 10000.0);
178 // some engines have inlets that close when they are off. So, if a flag is true disable windmilling
179 if (disableWindmill == false) {
180 // Need a small non-zero increment for acceleration otherwise acceleration will be 0 if N1 = 0
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);
183 } else {
184 N1 = Seek(&N1, 0, N1/2.0, N1/N1_spindown);
185 N2 = Seek(&N2, 0, N2/2.0, N2/N2_spindown);
186 }
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;
193 return 0.0;
194}
195
196//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
197
198double FGTurbine::Run()
199{
200 double idlethrust, milthrust, thrust;
201
202 idlethrust = MilThrust * IdleThrustLookup->GetValue();
203 milthrust = (MilThrust - idlethrust) * MilThrustLookup->GetValue();
204
205 Running = true;
206 Starter = false;
207
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;
213 }
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);
223
224 if (!Augmentation) {
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;
231 }
232
233 if (AugMethod == 1) {
234 if ((ThrottlePos > 0.99) && (N2 > 97.0)) {Augmentation = true;}
235 else {Augmentation = false;}
236 }
237
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);
242 }
243
244 if (AugMethod == 2) {
245 if (AugmentCmd > 0.0) {
246 Augmentation = true;
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);
251 } else {
252 Augmentation = false;
253 }
254 }
255
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);
261 } else {
262 Injection = false;
263 InjWaterNorm = 0.0;
264 }
265 }
266
267 if (Cutoff) phase = tpOff;
268 if (Starved) phase = tpOff;
269
270 return thrust;
271}
272
273//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
274
275double FGTurbine::SpinUp(void)
276{
277 Running = false;
278 FuelFlow_pph = 0.0;
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);
284 EPR = 1.0;
285 NozzlePosition = 1.0;
286 if (Starter == false) phase = tpOff;
287 return 0.0;
288}
289
290//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
291
292double FGTurbine::Start(void)
293{
294 if ((N2 > 15.0) && !Starved) { // minimum 15% N2 needed for start
295 Cranking = true; // provided for sound effects signal
296 if (N2 < IdleN2) {
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; // aborted start
303 }
304 else {
305 phase = tpRun;
306 Running = true;
307 Starter = false;
308 Cranking = false;
309 }
310 }
311 else { // no start if N2 < 15%
312 phase = tpOff;
313 Starter = false;
314 }
315
316 return 0.0;
317}
318
319//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
320
321double FGTurbine::Stall(void)
322{
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) {
328 phase = tpRun; // clear the stall with throttle to idle
329 Stalled = false;
330 }
331 return 0.0;
332}
333
334//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
335
336double FGTurbine::Seize(void)
337{
338 N2 = 0.0;
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);
343 Running = false;
344 return 0.0;
345}
346
347//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
348
349double FGTurbine::Trim()
350{
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);
357
358 if (AugMethod == 1) {
359 if ((ThrottlePos > 0.99) && (N2 > 97.0)) {Augmentation = true;}
360 else {Augmentation = false;}
361 }
362
363 if ((Augmented == 1) && Augmentation && (AugMethod < 2)) {
364 thrust = MaxThrust * MaxThrustLookup->GetValue();
365 }
366
367 if (AugMethod == 2) {
368 if (AugmentCmd > 0.0) {
369 double tdiff = (MaxThrust * MaxThrustLookup->GetValue()) - thrust;
370 thrust += (tdiff * std::min(AugmentCmd, 1.0));
371 }
372 }
373
374 if ((Injected == 1) && Injection) {
375 thrust = thrust * InjectionLookup->GetValue();
376 }
377
378 return thrust;
379}
380
381//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
382
384{
385 FuelFlowRate = FuelFlow_pph / 3600.0; // Calculates flow in lbs/sec from lbs/hr
386 FuelExpended = FuelFlowRate * in.TotalDeltaT; // Calculates fuel expended in this time step
387 if (!Starved) FuelUsedLbs += FuelExpended;
388 return FuelExpended;
389}
390
391//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
392
393double FGTurbine::GetPowerAvailable(void) const {
394 if( ThrottlePos <= 0.77 )
395 return 64.94*ThrottlePos;
396 else
397 return 217.38*ThrottlePos - 117.38;
398}
399
400//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
401
402double FGTurbine::Seek(double *var, double target, double accel, double decel) {
403 double v = *var;
404 if (v > target) {
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;
410 }
411 return v;
412}
413
414//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
415
416bool FGTurbine::Load(FGFDMExec* exec, Element *el)
417{
418 Element* function_element = el->FindElement("function");
419
420 while(function_element) {
421 string name = function_element->GetAttributeValue("name");
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);
426
427 function_element = el->FindNextElement("function");
428 }
429
430 FGEngine::Load(exec, el);
431
432 ResetToIC();
433
434 if (el->FindElement("milthrust"))
435 MilThrust = el->FindElementValueAsNumberConvertTo("milthrust","LBS");
436 if (el->FindElement("maxthrust"))
437 MaxThrust = el->FindElementValueAsNumberConvertTo("maxthrust","LBS");
438 if (el->FindElement("bypassratio"))
439 BypassRatio = el->FindElementValueAsNumber("bypassratio");
440 if (el->FindElement("bleed"))
441 BleedDemand = el->FindElementValueAsNumber("bleed");
442 if (el->FindElement("ignitionn1"))
443 IgnitionN1 = el->FindElementValueAsNumber("ignitionn1");
444 if (el->FindElement("ignitionn2"))
445 IgnitionN2 = el->FindElementValueAsNumber("ignitionn2");
446 if (el->FindElement("idlen1"))
447 IdleN1 = el->FindElementValueAsNumber("idlen1");
448 if (el->FindElement("idlen2"))
449 IdleN2 = el->FindElementValueAsNumber("idlen2");
450 if (el->FindElement("maxn1"))
451 MaxN1 = el->FindElementValueAsNumber("maxn1");
452 if (el->FindElement("maxn2"))
453 MaxN2 = el->FindElementValueAsNumber("maxn2");
454 if (el->FindElement("n1spinup"))
455 N1_spinup = el->FindElementValueAsNumber("n1spinup");
456 if (el->FindElement("n2spinup"))
457 N2_spinup = el->FindElementValueAsNumber("n2spinup");
458 if (el->FindElement("n1startrate"))
459 N1_start_rate = el->FindElementValueAsNumber("n1startrate");
460 if (el->FindElement("n2startrate"))
461 N2_start_rate = el->FindElementValueAsNumber("n2startrate");
462 if (el->FindElement("n1spindown"))
463 N1_spindown = el->FindElementValueAsNumber("n1spindown");
464 if (el->FindElement("n2spindown"))
465 N2_spindown = el->FindElementValueAsNumber("n2spindown");
466 if (el->FindElement("augmented"))
467 Augmented = (int)el->FindElementValueAsNumber("augmented");
468 if (el->FindElement("augmethod"))
469 AugMethod = (int)el->FindElementValueAsNumber("augmethod");
470 if (el->FindElement("injected"))
471 Injected = (int)el->FindElementValueAsNumber("injected");
472 if (el->FindElement("injection-time")){
473 InjectionTime = el->FindElementValueAsNumber("injection-time");
474 InjWaterNorm =1.0;
475 }
476 if (el->FindElement("injection-N1-inc"))
477 InjN1increment = el->FindElementValueAsNumber("injection-N1-inc");
478 if (el->FindElement("injection-N2-inc"))
479 InjN2increment = el->FindElementValueAsNumber("injection-N2-inc");
480 if (el->FindElement("disable-windmill"))
481 disableWindmill = el->FindElementValueAsBoolean("disable-windmill");
482 string property_prefix = CreateIndexedPropertyName("propulsion/engine", EngineNumber);
483
484 IdleThrustLookup = GetPreFunction(property_prefix+"/IdleThrust");
485 MilThrustLookup = GetPreFunction(property_prefix+"/MilThrust");
486 MaxThrustLookup = GetPreFunction(property_prefix+"/AugThrust");
487 InjectionLookup = GetPreFunction(property_prefix+"/Injection");
488
489 JSBSim::Element* tsfcElement = el->FindElement("tsfc");
490 if (tsfcElement) {
491 string value = tsfcElement->GetDataLine();
492 try {
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));
496 }
497 }
498
499 JSBSim::Element* atsfcElement = el->FindElement("atsfc");
500 if (atsfcElement) {
501 string value = atsfcElement->GetDataLine();
502 try {
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));
506 }
507 }
508
509 // Pre-calculations and initializations
510 N1SpoolUp = GetPreFunction(property_prefix+"/N1SpoolUp");
511 if (!N1SpoolUp)
512 N1SpoolUp = std::make_shared<FGSpoolUp>(this, BypassRatio, 1.0);
513
514 N1SpoolDown = GetPreFunction(property_prefix+"/N1SpoolDown");
515 if (!N1SpoolDown)
516 N1SpoolDown = std::make_shared<FGSpoolUp>(this, BypassRatio, 2.4);
517
518 N2SpoolUp = GetPreFunction(property_prefix+"/N2SpoolUp");
519 if (!N2SpoolUp)
520 N2SpoolUp = std::make_shared<FGSpoolUp>(this, BypassRatio, 1.0);
521
522 N2SpoolDown = GetPreFunction(property_prefix+"/N2SpoolDown");
523 if (!N2SpoolDown)
524 N2SpoolDown = std::make_shared<FGSpoolUp>(this, BypassRatio, 3.0);
525
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; // just an estimate
530
531 bindmodel(exec->GetPropertyManager().get());
532 return true;
533}
534
535//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
536
537string FGTurbine::GetEngineLabels(const string& delimiter)
538{
539 std::ostringstream buf;
540
541 buf << Name << "_N1[" << EngineNumber << "]" << delimiter
542 << Name << "_N2[" << EngineNumber << "]" << delimiter
543 << Thruster->GetThrusterLabels(EngineNumber, delimiter);
544
545 return buf.str();
546}
547
548//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
549
550string FGTurbine::GetEngineValues(const string& delimiter)
551{
552 std::ostringstream buf;
553
554 buf << N1 << delimiter
555 << N2 << delimiter
556 << Thruster->GetThrusterValues(EngineNumber, delimiter);
557
558 return buf.str();
559}
560
561//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
562
563void FGTurbine::bindmodel(FGPropertyManager* PropertyManager)
564{
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);
604}
605
606//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
607
608int FGTurbine::InitRunning(void)
609{
610 FDMExec->SuspendIntegration();
611 Cutoff=false;
612 Running=true;
613 N1_factor = MaxN1 - IdleN1;
614 N2_factor = MaxN2 - IdleN2;
615 N2 = IdleN2 + ThrottlePos * N2_factor;
616 N1 = IdleN1 + ThrottlePos * N1_factor;
617 Calculate();
618 FDMExec->ResumeIntegration();
619 return phase=tpRun;
620}
621
622//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
623// The bitmasked value choices are as follows:
624// unset: In this case (the default) JSBSim would only print
625// out the normally expected messages, essentially echoing
626// the config files as they are read. If the environment
627// variable is not set, debug_lvl is set to 1 internally
628// 0: This requests JSBSim not to output any messages
629// whatsoever.
630// 1: This value explicity requests the normal JSBSim
631// startup messages
632// 2: This value asks for a message to be printed out when
633// a class is instantiated
634// 4: When this value is set, a message is displayed when a
635// FGModel object executes its Run() method
636// 8: When this value is set, various runtime state variables
637// are printed out periodically
638// 16: When set various parameters are sanity checked and
639// a message is printed out when they go out of bounds
640
641void FGTurbine::Debug(int from)
642{
643 if (debug_lvl <= 0) return;
644
645 if (debug_lvl & 1) { // Standard console startup message output
646 if (from == 0) { // Constructor
647
648 }
649 if (from == 2) { // called from Load()
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;
664
665 cout << endl;
666 }
667 }
668 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
669 if (from == 0) cout << "Instantiated: FGTurbine" << endl;
670 if (from == 1) cout << "Destroyed: FGTurbine" << endl;
671 }
672 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
673 }
674 if (debug_lvl & 8 ) { // Runtime state variables
675 }
676 if (debug_lvl & 16) { // Sanity checking
677 }
678 if (debug_lvl & 64) {
679 if (from == 0) { // Constructor
680 }
681 }
682}
683}
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:88
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