JSBSim Flight Dynamics Model  1.1.11 (13 Feb 2022)
An Open Source Flight Dynamics and Control Software Library in C++
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 
27 FUNCTIONAL DESCRIPTION
28 --------------------------------------------------------------------------------
29 
30 This class descends from the FGEngine class and models a turbine engine based
31 on parameters given in the engine config file for this class
32 
33 HISTORY
34 --------------------------------------------------------------------------------
35 03/11/2003 DPC Created
36 09/08/2003 DPC Changed Calculate() and added engine phases
37 
38 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
39 INCLUDES
40 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
41 
42 #include <iostream>
43 #include <sstream>
44 
45 #include "FGFDMExec.h"
46 #include "math/FGFunction.h"
47 #include "FGTurbine.h"
48 #include "FGThruster.h"
49 #include "input_output/FGXMLElement.h"
50 
51 using namespace std;
52 
53 namespace JSBSim {
54 
55 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
56 CLASS IMPLEMENTATION
57 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
58 
59 FGTurbine::FGTurbine(FGFDMExec* exec, Element *el, int engine_number, struct Inputs& input)
60  : FGEngine(engine_number, input), FDMExec(exec)
61 {
62  Type = etTurbine;
63 
64  MilThrust = MaxThrust = 10000.0;
65  TSFC = 0.8;
66  ATSFC = 1.7;
67  IdleN1 = 30.0;
68  IdleN2 = 60.0;
69  MaxN1 = MaxN2 = 100.0;
70  Augmented = AugMethod = Injected = 0;
71  BypassRatio = BleedDemand = 0.0;
72  IdleThrustLookup = MilThrustLookup = MaxThrustLookup = InjectionLookup = 0;
73  N1_spinup = 1.0; N2_spinup = 3.0; IgnitionN1 = 5.21; IgnitionN2 = 25.18; N1_start_rate = 1.4; N2_start_rate = 2.0;
74  N1_spindown = 2.0; N2_spindown = 2.0;
75  InjectionTime = 30.0;
76  InjectionTimer = InjWaterNorm = 0.0;
77  EPR = 1.0;
78  disableWindmill = false;
79 
80  Load(exec, el);
81  Debug(0);
82 }
83 
84 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
85 
87 {
88  // Delete those functions that have requested the construction of a FGSpoolUp
89  // instance. FGModelFunctions will manage the destruction of the other
90  // instances.
91  if (dynamic_cast<FGSpoolUp*>(N1SpoolUp)) delete N1SpoolUp;
92  if (dynamic_cast<FGSpoolUp*>(N1SpoolDown)) delete N1SpoolDown;
93  if (dynamic_cast<FGSpoolUp*>(N2SpoolUp)) delete N2SpoolUp;
94  if (dynamic_cast<FGSpoolUp*>(N2SpoolDown)) delete N2SpoolDown;
95 
96  Debug(1);
97 }
98 
99 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
100 
102 {
103 
105 
106  N1 = N2 = InjN1increment = InjN2increment = 0.0;
107  N2norm = 0.0;
108  correctedTSFC = TSFC;
109  AugmentCmd = InjWaterNorm = 0.0;
110  InletPosition = NozzlePosition = 1.0;
111  Stalled = Seized = Overtemp = Fire = Augmentation = Injection = Reversed = false;
112  Cutoff = true;
113  phase = tpOff;
114  EGT_degC = in.TAT_c;
115  OilTemp_degK = in.TAT_c + 273.0;
116 }
117 
118 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
119 // The main purpose of Calculate() is to determine what phase the engine should
120 // be in, then call the corresponding function.
121 
123 {
124  double thrust;
125 
126  RunPreFunctions();
127 
128  ThrottlePos = in.ThrottlePos[EngineNumber];
129 
130  if (ThrottlePos > 1.0) {
131  AugmentCmd = ThrottlePos - 1.0;
132  ThrottlePos -= AugmentCmd;
133  } else {
134  AugmentCmd = 0.0;
135  }
136 
137  // When trimming is finished check if user wants engine OFF or RUNNING
138  if ((phase == tpTrim) && (in.TotalDeltaT > 0)) {
139  if (Running && !Starved) {
140  phase = tpRun;
141  N1_factor = MaxN1 - IdleN1;
142  N2_factor = MaxN2 - IdleN2;
143  N2 = IdleN2 + ThrottlePos * N2_factor;
144  N1 = IdleN1 + ThrottlePos * N1_factor;
145  OilTemp_degK = 366.0;
146  Cutoff = false;
147  } else {
148  phase = tpOff;
149  Cutoff = true;
150  EGT_degC = in.TAT_c;
151  }
152  }
153 
154  if (!Running && Cutoff && Starter) {
155  if (phase == tpOff) phase = tpSpinUp;
156  }
157 
158  // start
159  if ((Starter == true) || (in.qbar > 30.0)) {
160  if (!Running && !Cutoff && (N2 > 15.0)) phase = tpStart;
161  }
162 
163  if (Cutoff && (phase != tpSpinUp)) phase = tpOff;
164  if (in.TotalDeltaT == 0) phase = tpTrim;
165  if (Starved) phase = tpOff;
166  if (Stalled) phase = tpStall;
167  if (Seized) phase = tpSeize;
168 
169  switch (phase) {
170  case tpOff: thrust = Off(); break;
171  case tpRun: thrust = Run(); break;
172  case tpSpinUp: thrust = SpinUp(); break;
173  case tpStart: thrust = Start(); break;
174  case tpStall: thrust = Stall(); break;
175  case tpSeize: thrust = Seize(); break;
176  case tpTrim: thrust = Trim(); break;
177  default: thrust = Off();
178  }
179 
180  Thruster->Calculate(thrust); // allow thruster to modify thrust (i.e. reversing)
181 
182  RunPostFunctions();
183 }
184 
185 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
186 
187 double FGTurbine::Off(void)
188 {
189  Running = false;
190  FuelFlow_pph = Seek(&FuelFlow_pph, 0, 1000.0, 10000.0);
191  // some engines have inlets that close when they are off. So, if a flag is true disable windmilling
192  if (disableWindmill == false) {
193  // Need a small non-zero increment for acceleration otherwise acceleration will be 0 if N1 = 0
194  N1 = Seek(&N1, in.qbar/10.0, N1/2.0 + 0.1, N1/N1_spindown);
195  N2 = Seek(&N2, in.qbar/15.0, N2/2.0 + 0.1, N2/N2_spindown);
196  } else {
197  N1 = Seek(&N1, 0, N1/2.0, N1/N1_spindown);
198  N2 = Seek(&N2, 0, N2/2.0, N2/N2_spindown);
199  }
200  EGT_degC = Seek(&EGT_degC, in.TAT_c, 11.7, 7.3);
201  OilTemp_degK = Seek(&OilTemp_degK, in.TAT_c + 273.0, 0.2, 0.2);
202  OilPressure_psi = N2 * 0.62;
203  NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
204  EPR = Seek(&EPR, 1.0, 0.2, 0.2);
205  Augmentation = false;
206  return 0.0;
207 }
208 
209 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
210 
211 double FGTurbine::Run()
212 {
213  double idlethrust, milthrust, thrust;
214  double T = in.Temperature;
215 
216  idlethrust = MilThrust * IdleThrustLookup->GetValue();
217  milthrust = (MilThrust - idlethrust) * MilThrustLookup->GetValue();
218 
219  Running = true;
220  Starter = false;
221 
222  N1_factor = MaxN1 - IdleN1;
223  N2_factor = MaxN2 - IdleN2;
224  if ((Injected == 1) && Injection && (InjWaterNorm > 0)) {
225  N1_factor += InjN1increment;
226  N2_factor += InjN2increment;
227  }
228  N2 = Seek(&N2, IdleN2 + ThrottlePos * N2_factor,
229  N2SpoolUp->GetValue(), N2SpoolDown->GetValue());
230  N1 = Seek(&N1, IdleN1 + ThrottlePos * N1_factor,
231  N1SpoolUp->GetValue(), N1SpoolDown->GetValue());
232  N2norm = (N2 - IdleN2) / N2_factor;
233  thrust = idlethrust + (milthrust * N2norm * N2norm);
234  EGT_degC = in.TAT_c + 363.1 + ThrottlePos * 357.1;
235  OilPressure_psi = N2 * 0.62;
236  OilTemp_degK = Seek(&OilTemp_degK, 366.0, 1.2, 0.1);
237 
238  if (!Augmentation) {
239  correctedTSFC = TSFC * sqrt(T/389.7) * (0.84 + (1-N2norm)*(1-N2norm));
240  FuelFlow_pph = Seek(&FuelFlow_pph, thrust * correctedTSFC, 1000.0, 10000.0);
241  if (FuelFlow_pph < IdleFF) FuelFlow_pph = IdleFF;
242  NozzlePosition = Seek(&NozzlePosition, 1.0 - N2norm, 0.8, 0.8);
243  thrust = thrust * (1.0 - BleedDemand);
244  EPR = 1.0 + thrust/MilThrust;
245  }
246 
247  if (AugMethod == 1) {
248  if ((ThrottlePos > 0.99) && (N2 > 97.0)) {Augmentation = true;}
249  else {Augmentation = false;}
250  }
251 
252  if ((Augmented == 1) && Augmentation && (AugMethod < 2)) {
253  thrust = MaxThrustLookup->GetValue() * MaxThrust;
254  FuelFlow_pph = Seek(&FuelFlow_pph, thrust * ATSFC, 5000.0, 10000.0);
255  NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
256  }
257 
258  if (AugMethod == 2) {
259  if (AugmentCmd > 0.0) {
260  Augmentation = true;
261  double tdiff = (MaxThrust * MaxThrustLookup->GetValue()) - thrust;
262  thrust += (tdiff * AugmentCmd);
263  FuelFlow_pph = Seek(&FuelFlow_pph, thrust * ATSFC, 5000.0, 10000.0);
264  NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
265  } else {
266  Augmentation = false;
267  }
268  }
269 
270  if ((Injected == 1) && Injection && (InjWaterNorm > 0.0)) {
271  InjectionTimer += in.TotalDeltaT;
272  if (InjectionTimer < InjectionTime) {
273  thrust = thrust * InjectionLookup->GetValue();
274  InjWaterNorm = 1.0 - (InjectionTimer/InjectionTime);
275  } else {
276  Injection = false;
277  InjWaterNorm = 0.0;
278  }
279  }
280 
281  if (Cutoff) phase = tpOff;
282  if (Starved) phase = tpOff;
283 
284  return thrust;
285 }
286 
287 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288 
289 double FGTurbine::SpinUp(void)
290 {
291  Running = false;
292  FuelFlow_pph = 0.0;
293  N2 = Seek(&N2, IgnitionN2, N2_spinup, N2/2.0);
294  N1 = Seek(&N1, IgnitionN1, N1_spinup, N1/2.0);
295  EGT_degC = Seek(&EGT_degC, in.TAT_c, 11.7, 7.3);
296  OilPressure_psi = N2 * 0.62;
297  OilTemp_degK = Seek(&OilTemp_degK, in.TAT_c + 273.0, 0.2, 0.2);
298  EPR = 1.0;
299  NozzlePosition = 1.0;
300  if (Starter == false) phase = tpOff;
301  return 0.0;
302 }
303 
304 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
305 
306 double FGTurbine::Start(void)
307 {
308  if ((N2 > 15.0) && !Starved) { // minimum 15% N2 needed for start
309  Cranking = true; // provided for sound effects signal
310  if (N2 < IdleN2) {
311  N2 = Seek(&N2, IdleN2, N2_start_rate, N2/2.0);
312  N1 = Seek(&N1, IdleN1, N1_start_rate, N1/2.0);
313  EGT_degC = Seek(&EGT_degC, in.TAT_c + 363.1, 21.3, 7.3);
314  FuelFlow_pph = IdleFF * N2 / IdleN2;
315  OilPressure_psi = N2 * 0.62;
316  if ((Starter == false) && (in.qbar < 30.0)) phase = tpOff; // aborted start
317  }
318  else {
319  phase = tpRun;
320  Running = true;
321  Starter = false;
322  Cranking = false;
323  }
324  }
325  else { // no start if N2 < 15%
326  phase = tpOff;
327  Starter = false;
328  }
329 
330  return 0.0;
331 }
332 
333 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
334 
335 double FGTurbine::Stall(void)
336 {
337  EGT_degC = in.TAT_c + 903.14;
338  FuelFlow_pph = IdleFF;
339  N1 = Seek(&N1, in.qbar/10.0, 0, N1/10.0);
340  N2 = Seek(&N2, in.qbar/15.0, 0, N2/10.0);
341  if (ThrottlePos < 0.01) {
342  phase = tpRun; // clear the stall with throttle to idle
343  Stalled = false;
344  }
345  return 0.0;
346 }
347 
348 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
349 
350 double FGTurbine::Seize(void)
351 {
352  N2 = 0.0;
353  N1 = Seek(&N1, in.qbar/20.0, 0, N1/15.0);
354  FuelFlow_pph = Cutoff ? 0.0 : IdleFF;
355  OilPressure_psi = 0.0;
356  OilTemp_degK = Seek(&OilTemp_degK, in.TAT_c + 273.0, 0, 0.2);
357  Running = false;
358  return 0.0;
359 }
360 
361 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362 
363 double FGTurbine::Trim()
364 {
365  double idlethrust = MilThrust * IdleThrustLookup->GetValue();
366  double milthrust = (MilThrust - idlethrust) * MilThrustLookup->GetValue();
367  double N2 = IdleN2 + ThrottlePos * N2_factor;
368  double N2norm = (N2 - IdleN2) / N2_factor;
369  double thrust = (idlethrust + (milthrust * N2norm * N2norm))
370  * (1.0 - BleedDemand);
371 
372  if (AugMethod == 1) {
373  if ((ThrottlePos > 0.99) && (N2 > 97.0)) {Augmentation = true;}
374  else {Augmentation = false;}
375  }
376 
377  if ((Augmented == 1) && Augmentation && (AugMethod < 2)) {
378  thrust = MaxThrust * MaxThrustLookup->GetValue();
379  }
380 
381  if (AugMethod == 2) {
382  if (AugmentCmd > 0.0) {
383  double tdiff = (MaxThrust * MaxThrustLookup->GetValue()) - thrust;
384  thrust += (tdiff * AugmentCmd);
385  }
386  }
387 
388  if ((Injected == 1) && Injection) {
389  thrust = thrust * InjectionLookup->GetValue();
390  }
391 
392  return thrust;
393 }
394 
395 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
396 
398 {
399  FuelFlowRate = FuelFlow_pph / 3600.0; // Calculates flow in lbs/sec from lbs/hr
400  FuelExpended = FuelFlowRate * in.TotalDeltaT; // Calculates fuel expended in this time step
401  if (!Starved) FuelUsedLbs += FuelExpended;
402  return FuelExpended;
403 }
404 
405 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
406 
407 double FGTurbine::GetPowerAvailable(void) {
408  if( ThrottlePos <= 0.77 )
409  return 64.94*ThrottlePos;
410  else
411  return 217.38*ThrottlePos - 117.38;
412 }
413 
414 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
415 
416 double FGTurbine::Seek(double *var, double target, double accel, double decel) {
417  double v = *var;
418  if (v > target) {
419  v -= in.TotalDeltaT * decel;
420  if (v < target) v = target;
421  } else if (v < target) {
422  v += in.TotalDeltaT * accel;
423  if (v > target) v = target;
424  }
425  return v;
426 }
427 
428 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
429 
430 bool FGTurbine::Load(FGFDMExec* exec, Element *el)
431 {
432  Element* function_element = el->FindElement("function");
433 
434  while(function_element) {
435  string name = function_element->GetAttributeValue("name");
436  if (name == "IdleThrust" || name == "MilThrust" || name == "AugThrust"
437  || name == "Injection" || name == "N1SpoolUp" || name == "N1SpoolDown"
438  || name == "N2SpoolUp" || name == "N2SpoolDown")
439  function_element->SetAttributeValue("name", string("propulsion/engine[#]/") + name);
440 
441  function_element = el->FindNextElement("function");
442  }
443 
444  FGEngine::Load(exec, el);
445 
446  ResetToIC();
447 
448  if (el->FindElement("milthrust"))
449  MilThrust = el->FindElementValueAsNumberConvertTo("milthrust","LBS");
450  if (el->FindElement("maxthrust"))
451  MaxThrust = el->FindElementValueAsNumberConvertTo("maxthrust","LBS");
452  if (el->FindElement("bypassratio"))
453  BypassRatio = el->FindElementValueAsNumber("bypassratio");
454  if (el->FindElement("bleed"))
455  BleedDemand = el->FindElementValueAsNumber("bleed");
456  if (el->FindElement("tsfc"))
457  TSFC = el->FindElementValueAsNumber("tsfc");
458  if (el->FindElement("atsfc"))
459  ATSFC = el->FindElementValueAsNumber("atsfc");
460  if (el->FindElement("ignitionn1"))
461  IgnitionN1 = el->FindElementValueAsNumber("ignitionn1");
462  if (el->FindElement("ignitionn2"))
463  IgnitionN2 = el->FindElementValueAsNumber("ignitionn2");
464  if (el->FindElement("idlen1"))
465  IdleN1 = el->FindElementValueAsNumber("idlen1");
466  if (el->FindElement("idlen2"))
467  IdleN2 = el->FindElementValueAsNumber("idlen2");
468  if (el->FindElement("maxn1"))
469  MaxN1 = el->FindElementValueAsNumber("maxn1");
470  if (el->FindElement("maxn2"))
471  MaxN2 = el->FindElementValueAsNumber("maxn2");
472  if (el->FindElement("n1spinup"))
473  N1_spinup = el->FindElementValueAsNumber("n1spinup");
474  if (el->FindElement("n2spinup"))
475  N2_spinup = el->FindElementValueAsNumber("n2spinup");
476  if (el->FindElement("n1startrate"))
477  N1_start_rate = el->FindElementValueAsNumber("n1startrate");
478  if (el->FindElement("n2startrate"))
479  N2_start_rate = el->FindElementValueAsNumber("n2startrate");
480  if (el->FindElement("n1spindown"))
481  N1_spindown = el->FindElementValueAsNumber("n1spindown");
482  if (el->FindElement("n2spindown"))
483  N2_spindown = el->FindElementValueAsNumber("n2spindown");
484  if (el->FindElement("augmented"))
485  Augmented = (int)el->FindElementValueAsNumber("augmented");
486  if (el->FindElement("augmethod"))
487  AugMethod = (int)el->FindElementValueAsNumber("augmethod");
488  if (el->FindElement("injected"))
489  Injected = (int)el->FindElementValueAsNumber("injected");
490  if (el->FindElement("injection-time")){
491  InjectionTime = el->FindElementValueAsNumber("injection-time");
492  InjWaterNorm =1.0;
493  }
494  if (el->FindElement("injection-N1-inc"))
495  InjN1increment = el->FindElementValueAsNumber("injection-N1-inc");
496  if (el->FindElement("injection-N2-inc"))
497  InjN2increment = el->FindElementValueAsNumber("injection-N2-inc");
498  if (el->FindElement("disable-windmill"))
499  disableWindmill = el->FindElementValueAsBoolean("disable-windmill");
500  string property_prefix = CreateIndexedPropertyName("propulsion/engine", EngineNumber);
501 
502  IdleThrustLookup = GetPreFunction(property_prefix+"/IdleThrust");
503  MilThrustLookup = GetPreFunction(property_prefix+"/MilThrust");
504  MaxThrustLookup = GetPreFunction(property_prefix+"/AugThrust");
505  InjectionLookup = GetPreFunction(property_prefix+"/Injection");
506 
507  // Pre-calculations and initializations
508  N1SpoolUp = GetPreFunction(property_prefix+"/N1SpoolUp");
509  if (!N1SpoolUp)
510  N1SpoolUp = new FGSpoolUp(this, BypassRatio, 1.0);
511 
512  N1SpoolDown = GetPreFunction(property_prefix+"/N1SpoolDown");
513  if (!N1SpoolDown)
514  N1SpoolDown = new FGSpoolUp(this, BypassRatio, 2.4);
515 
516  N2SpoolUp = GetPreFunction(property_prefix+"/N2SpoolUp");
517  if (!N2SpoolUp)
518  N2SpoolUp = new FGSpoolUp(this, BypassRatio, 1.0);
519 
520  N2SpoolDown = GetPreFunction(property_prefix+"/N2SpoolDown");
521  if (!N2SpoolDown)
522  N2SpoolDown = new FGSpoolUp(this, BypassRatio, 3.0);
523 
524  N1_factor = MaxN1 - IdleN1;
525  N2_factor = MaxN2 - IdleN2;
526  OilTemp_degK = in.TAT_c + 273.0;
527  IdleFF = pow(MilThrust, 0.2) * 107.0; // just an estimate
528 
529  bindmodel(exec->GetPropertyManager());
530  return true;
531 }
532 
533 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
534 
535 string FGTurbine::GetEngineLabels(const string& delimiter)
536 {
537  std::ostringstream buf;
538 
539  buf << Name << "_N1[" << EngineNumber << "]" << delimiter
540  << Name << "_N2[" << EngineNumber << "]" << delimiter
541  << Thruster->GetThrusterLabels(EngineNumber, delimiter);
542 
543  return buf.str();
544 }
545 
546 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
547 
548 string FGTurbine::GetEngineValues(const string& delimiter)
549 {
550  std::ostringstream buf;
551 
552  buf << N1 << delimiter
553  << N2 << delimiter
554  << Thruster->GetThrusterValues(EngineNumber, delimiter);
555 
556  return buf.str();
557 }
558 
559 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
560 
561 void FGTurbine::bindmodel(FGPropertyManager* PropertyManager)
562 {
563  string property_name, base_property_name;
564  base_property_name = CreateIndexedPropertyName("propulsion/engine", EngineNumber);
565  property_name = base_property_name + "/n1";
566  PropertyManager->Tie( property_name.c_str(), &N1);
567  property_name = base_property_name + "/n2";
568  PropertyManager->Tie( property_name.c_str(), &N2);
569  property_name = base_property_name + "/injection_cmd";
570  PropertyManager->Tie( property_name.c_str(), (FGTurbine*)this,
571  &FGTurbine::GetInjection, &FGTurbine::SetInjection);
572  property_name = base_property_name + "/seized";
573  PropertyManager->Tie( property_name.c_str(), &Seized);
574  property_name = base_property_name + "/stalled";
575  PropertyManager->Tie( property_name.c_str(), &Stalled);
576  property_name = base_property_name + "/bleed-factor";
577  PropertyManager->Tie( property_name.c_str(), (FGTurbine*)this, &FGTurbine::GetBleedDemand, &FGTurbine::SetBleedDemand);
578  property_name = base_property_name + "/MaxN1";
579  PropertyManager->Tie( property_name.c_str(), (FGTurbine*)this,
580  &FGTurbine::GetMaxN1, &FGTurbine::SetMaxN1);
581  property_name = base_property_name + "/MaxN2";
582  PropertyManager->Tie( property_name.c_str(), (FGTurbine*)this,
583  &FGTurbine::GetMaxN2, &FGTurbine::SetMaxN2);
584  property_name = base_property_name + "/InjectionTimer";
585  PropertyManager->Tie( property_name.c_str(), (FGTurbine*)this,
586  &FGTurbine::GetInjectionTimer, &FGTurbine::SetInjectionTimer);
587  property_name = base_property_name + "/InjWaterNorm";
588  PropertyManager->Tie( property_name.c_str(), (FGTurbine*)this,
589  &FGTurbine::GetInjWaterNorm, &FGTurbine::SetInjWaterNorm);
590  property_name = base_property_name + "/InjN1increment";
591  PropertyManager->Tie( property_name.c_str(), (FGTurbine*)this,
592  &FGTurbine::GetInjN1increment, &FGTurbine::SetInjN1increment);
593  property_name = base_property_name + "/InjN2increment";
594  PropertyManager->Tie( property_name.c_str(), (FGTurbine*)this,
595  &FGTurbine::GetInjN2increment, &FGTurbine::SetInjN2increment);
596 }
597 
598 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
599 
600 int FGTurbine::InitRunning(void)
601 {
602  FDMExec->SuspendIntegration();
603  Cutoff=false;
604  Running=true;
605  N1_factor = MaxN1 - IdleN1;
606  N2_factor = MaxN2 - IdleN2;
607  N2 = IdleN2 + ThrottlePos * N2_factor;
608  N1 = IdleN1 + ThrottlePos * N1_factor;
609  Calculate();
610  FDMExec->ResumeIntegration();
611  return phase=tpRun;
612 }
613 
614 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
615 // The bitmasked value choices are as follows:
616 // unset: In this case (the default) JSBSim would only print
617 // out the normally expected messages, essentially echoing
618 // the config files as they are read. If the environment
619 // variable is not set, debug_lvl is set to 1 internally
620 // 0: This requests JSBSim not to output any messages
621 // whatsoever.
622 // 1: This value explicity requests the normal JSBSim
623 // startup messages
624 // 2: This value asks for a message to be printed out when
625 // a class is instantiated
626 // 4: When this value is set, a message is displayed when a
627 // FGModel object executes its Run() method
628 // 8: When this value is set, various runtime state variables
629 // are printed out periodically
630 // 16: When set various parameters are sanity checked and
631 // a message is printed out when they go out of bounds
632 
633 void FGTurbine::Debug(int from)
634 {
635  if (debug_lvl <= 0) return;
636 
637  if (debug_lvl & 1) { // Standard console startup message output
638  if (from == 0) { // Constructor
639 
640  }
641  if (from == 2) { // called from Load()
642  cout << "\n Engine Name: " << Name << endl;
643  cout << " MilThrust: " << MilThrust << endl;
644  cout << " MaxThrust: " << MaxThrust << endl;
645  cout << " BypassRatio: " << BypassRatio << endl;
646  cout << " TSFC: " << TSFC << endl;
647  cout << " ATSFC: " << ATSFC << endl;
648  cout << " IdleN1: " << IdleN1 << endl;
649  cout << " IdleN2: " << IdleN2 << endl;
650  cout << " MaxN1: " << MaxN1 << endl;
651  cout << " MaxN2: " << MaxN2 << endl;
652  cout << " Augmented: " << Augmented << endl;
653  cout << " AugMethod: " << AugMethod << endl;
654  cout << " Injected: " << Injected << endl;
655  cout << " MinThrottle: " << MinThrottle << endl;
656 
657  cout << endl;
658  }
659  }
660  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
661  if (from == 0) cout << "Instantiated: FGTurbine" << endl;
662  if (from == 1) cout << "Destroyed: FGTurbine" << endl;
663  }
664  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
665  }
666  if (debug_lvl & 8 ) { // Runtime state variables
667  }
668  if (debug_lvl & 16) { // Sanity checking
669  }
670  if (debug_lvl & 64) {
671  if (from == 0) { // Constructor
672  }
673  }
674 }
675 }
JSBSim::FGFDMExec
Encapsulates the JSBSim simulation executive.
Definition: FGFDMExec.h:185
JSBSim::FGFDMExec::SuspendIntegration
void SuspendIntegration(void)
Suspends the simulation and sets the delta T to zero.
Definition: FGFDMExec.h:548
JSBSim::Element::GetAttributeValue
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
Definition: FGXMLElement.cpp:260
JSBSim::Element::FindElement
Element * FindElement(const std::string &el="")
Searches for a specified element.
Definition: FGXMLElement.cpp:389
JSBSim::Element::FindElementValueAsNumber
double FindElementValueAsNumber(const std::string &el="")
Searches for the named element and returns the data belonging to it as a number.
Definition: FGXMLElement.cpp:429
JSBSim::Element::FindElementValueAsBoolean
bool FindElementValueAsBoolean(const std::string &el="")
Searches for the named element and returns the data belonging to it as a bool.
Definition: FGXMLElement.cpp:446
JSBSim::Element::FindElementValueAsNumberConvertTo
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.
Definition: FGXMLElement.cpp:480
JSBSim::FGFDMExec::GetPropertyManager
FGPropertyManager * GetPropertyManager(void)
Returns a pointer to the property manager object.
Definition: FGFDMExec.cpp:1121
JSBSim::FGFDMExec::ResumeIntegration
void ResumeIntegration(void)
Resumes the simulation by resetting delta T to the correct value.
Definition: FGFDMExec.h:551
JSBSim::FGTurbine::ResetToIC
void ResetToIC(void)
Resets the Engine parameters to the initial conditions.
Definition: FGTurbine.cpp:101
JSBSim::Element::SetAttributeValue
bool SetAttributeValue(const std::string &key, const std::string &value)
Modifies an attribute.
Definition: FGXMLElement.cpp:268
JSBSim::FGTurbine::FGTurbine
FGTurbine(FGFDMExec *Executive, Element *el, int engine_number, struct Inputs &input)
Constructor.
Definition: FGTurbine.cpp:59
JSBSim::FGTurbine::CalcFuelNeed
double CalcFuelNeed(void)
The fuel need is calculated based on power levels and flow rate for that power level.
Definition: FGTurbine.cpp:397
JSBSim::FGTurbine::Calculate
void Calculate(void)
Calculates the thrust of the engine, and other engine functions.
Definition: FGTurbine.cpp:122
JSBSim::FGEngine::Inputs
Definition: FGEngine.h:106
JSBSim::FGSpoolUp
Definition: FGTurbine.h:327
JSBSim::FGFunction::GetValue
double GetValue(void) const override
Retrieves the value of the function object.
Definition: FGFunction.cpp:925
JSBSim::FGEngine::ResetToIC
virtual void ResetToIC(void)
Resets the Engine parameters to the initial conditions.
Definition: FGEngine.cpp:77
JSBSim::FGTurbine::~FGTurbine
~FGTurbine()
Destructor.
Definition: FGTurbine.cpp:86
JSBSim::Element::FindNextElement
Element * FindNextElement(const std::string &el="")
Searches for the next element as specified.
Definition: FGXMLElement.cpp:407
JSBSim::FGEngine
Base class for all engines.
Definition: FGEngine.h:103
JSBSim::FGTurbine::Seek
double Seek(double *var, double target, double accel, double decel)
A lag filter.
Definition: FGTurbine.cpp:416
JSBSim::Element
Definition: FGXMLElement.h:143
JSBSim::FGModelFunctions::GetPreFunction
FGFunction * GetPreFunction(const std::string &name)
Get one of the "pre" function.
Definition: FGModelFunctions.cpp:141