]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/FGSimTurbine.cpp
Adjust the turbine names for N1, N2 and EGT_degC to match those already specified...
[flightgear.git] / src / FDM / JSBSim / FGSimTurbine.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3  Module:       FGSimTurbine.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 (davidculp2@comcast.net) ---------
9
10  This program is free software; you can redistribute it and/or modify it under
11  the terms of the GNU 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 General Public License for more
18  details.
19
20  You should have received a copy of the GNU 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 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 <vector>
43 #include "FGSimTurbine.h"
44
45 namespace JSBSim {
46
47 static const char *IdSrc = "$Id$";
48 static const char *IdHdr = ID_SIMTURBINE;
49
50 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
51 CLASS IMPLEMENTATION
52 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
53
54
55 FGSimTurbine::FGSimTurbine(FGFDMExec* exec, FGConfigFile* cfg) : FGEngine(exec)
56 {
57   SetDefaults();
58
59   Load(cfg);
60   Debug(0);
61 }
62
63 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
64
65 FGSimTurbine::~FGSimTurbine()
66 {
67   Debug(1);
68 }
69
70 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
71 // The main purpose of Calculate() is to determine what phase the engine should
72 // be in, then call the corresponding function. 
73
74 double FGSimTurbine::Calculate(double dummy)
75 {
76   TAT = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556;
77   dt = State->Getdt() * Propulsion->GetRate();
78   ThrottleCmd = FCS->GetThrottleCmd(EngineNumber);
79
80   // When trimming is finished check if user wants engine OFF or RUNNING
81   if ((phase == tpTrim) && (dt > 0)) {
82     if (Running && !Starved) {
83       phase = tpRun;
84       N2 = IdleN2;
85       N1 = IdleN1;
86       OilTemp_degK = 366.0;  
87       Cutoff = false;
88       }
89     else {
90       phase = tpOff;
91       Cutoff = true;
92       EGT_degC = TAT; 
93       }
94     }
95   
96   if (!Running && Cutoff && Starter) {
97      if (phase == tpOff) phase = tpSpinUp;
98      }
99   if (!Running && !Cutoff && (N2 > 15.0)) phase = tpStart;
100   if (Cutoff && (phase != tpSpinUp)) phase = tpOff;
101   if (dt == 0) phase = tpTrim;
102   if (Starved) phase = tpOff;
103   if (Stalled) phase = tpStall;
104   if (Seized) phase = tpSeize;
105   
106   switch (phase) {
107     case tpOff:    Thrust = Off(); break;
108     case tpRun:    Thrust = Run(); break;
109     case tpSpinUp: Thrust = SpinUp(); break;
110     case tpStart:  Thrust = Start(); break;
111     case tpStall:  Thrust = Stall(); break;
112     case tpSeize:  Thrust = Seize(); break;
113     case tpTrim:   Thrust = Trim(); break;
114     default: Thrust = Off();
115   }   
116
117   return Thrust;  
118 }
119
120 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
121
122 double FGSimTurbine::Off(void)
123 {
124   double qbar = Translation->Getqbar();
125   Running = false;
126   FuelFlow_pph = Seek(&FuelFlow_pph, 0, 1000.0, 10000.0);
127   N1 = Seek(&N1, qbar/10.0, N1/2.0, N1/2.0);
128   N2 = Seek(&N2, qbar/15.0, N2/2.0, N2/2.0);
129   EGT_degC = Seek(&EGT_degC, TAT, 11.7, 7.3);
130   OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0.2, 0.2);  
131   OilPressure_psi = N2 * 0.62;
132   NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
133   EPR = Seek(&EPR, 1.0, 0.2, 0.2);
134   Augmentation = false;
135   return 0.0; 
136 }
137
138 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
139
140 double FGSimTurbine::Run(void)
141 {
142   double idlethrust, milthrust, thrust;
143   double N2norm;   // 0.0 = idle N2, 1.0 = maximum N2
144   idlethrust = MilThrust * ThrustTables[0]->TotalValue();
145   milthrust = (MilThrust - idlethrust) * ThrustTables[1]->TotalValue();
146
147   Running = true;
148   Starter = false;
149  
150   N2 = Seek(&N2, IdleN2 + ThrottleCmd * N2_factor, delay, delay * 3.0);
151   N1 = Seek(&N1, IdleN1 + ThrottleCmd * N1_factor, delay, delay * 2.4);
152   N2norm = (N2 - IdleN2) / N2_factor;
153   thrust = idlethrust + (milthrust * N2norm * N2norm); 
154   thrust = thrust * (1.0 - BleedDemand);
155   EGT_degC = TAT + 363.1 + ThrottleCmd * 357.1;
156   OilPressure_psi = N2 * 0.62;
157   OilTemp_degK = Seek(&OilTemp_degK, 366.0, 1.2, 0.1);
158   EPR = 1.0 + thrust/MilThrust;
159
160   if (!Augmentation) {
161     FuelFlow_pph = Seek(&FuelFlow_pph, thrust * TSFC, 1000.0, 100000);
162     if (FuelFlow_pph < IdleFF) FuelFlow_pph = IdleFF;
163     NozzlePosition = Seek(&NozzlePosition, 1.0 - N2norm, 0.8, 0.8);
164   }
165
166   if (AugMethod == 1) {
167     if ((ThrottleCmd > 0.99) && (N2 > 97.0)) {Augmentation = true;} 
168     else {Augmentation = false;}
169   }
170
171   if ((Augmented == 1) && Augmentation) {
172     thrust = MaxThrust * ThrustTables[2]->TotalValue();
173     FuelFlow_pph = Seek(&FuelFlow_pph, thrust * ATSFC, 5000.0, 10000.0);
174     NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
175   }
176
177   if ((Injected == 1) && Injection)
178     thrust = thrust * ThrustTables[3]->TotalValue(); 
179
180   ConsumeFuel();
181   if (Cutoff) phase = tpOff;
182   if (Starved) phase = tpOff;
183
184   return thrust;
185 }
186         
187 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
188
189 double FGSimTurbine::SpinUp(void)
190 {
191   Running = false;
192   FuelFlow_pph = 0.0;
193   N2 = Seek(&N2, 25.18, 3.0, N2/2.0);
194   N1 = Seek(&N1, 5.21, 1.0, N1/2.0);
195   EGT_degC = Seek(&EGT_degC, TAT, 11.7, 7.3);
196   OilPressure_psi = N2 * 0.62;
197   OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0.2, 0.2);
198   EPR = 1.0;
199   NozzlePosition = 1.0;
200
201   return 0.0;
202 }
203
204 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
205
206 double FGSimTurbine::Start(void)
207 {
208   if ((N2 > 15.0) && !Starved) {       // minimum 15% N2 needed for start
209     Cranking = true;                   // provided for sound effects signal
210     if (N2 < IdleN2) {
211       N2 = Seek(&N2, IdleN2, 2.0, N2/2.0);
212       N1 = Seek(&N1, IdleN1, 1.4, N1/2.0);
213       EGT_degC = Seek(&EGT_degC, TAT + 363.1, 21.3, 7.3);
214       FuelFlow_pph = Seek(&FuelFlow_pph, IdleFF, 103.7, 103.7);
215       OilPressure_psi = N2 * 0.62;
216       }
217     else {
218       phase = tpRun;
219       Running = true;
220       Starter = false;
221       Cranking = false;
222       } 
223     }
224   else {                 // no start if N2 < 15%
225     phase = tpOff;
226     Starter = false;
227     }
228
229   return 0.0; 
230 }
231
232 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
233
234 double FGSimTurbine::Stall(void)
235 {
236   double qbar = Translation->Getqbar();
237   EGT_degC = TAT + 903.14;
238   FuelFlow_pph = IdleFF;
239   N1 = Seek(&N1, qbar/10.0, 0, N1/10.0); 
240   N2 = Seek(&N2, qbar/15.0, 0, N2/10.0);
241   if (ThrottleCmd == 0) phase = tpRun;        // clear the stall with throttle
242
243   return 0.0; 
244 }
245
246 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
247
248 double FGSimTurbine::Seize(void)
249 {
250     double qbar = Translation->Getqbar();
251     N2 = 0.0;
252     N1 = Seek(&N1, qbar/20.0, 0, N1/15.0);
253     FuelFlow_pph = IdleFF;
254     OilPressure_psi = 0.0;
255     OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0, 0.2);
256     Running = false;
257     return 0.0; 
258 }
259
260 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
261
262 double FGSimTurbine::Trim(void)
263 {
264     double idlethrust, milthrust, thrust;
265     idlethrust = MilThrust * ThrustTables[0]->TotalValue();
266     milthrust = (MilThrust - idlethrust) * ThrustTables[1]->TotalValue();
267     thrust = idlethrust + (milthrust * ThrottleCmd * ThrottleCmd);
268     return thrust; 
269 }
270
271 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
272
273 double FGSimTurbine::CalcFuelNeed(void)
274 {
275   return FuelFlow_pph /3600 * State->Getdt() * Propulsion->GetRate();
276 }
277
278 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
279
280 double FGSimTurbine::GetPowerAvailable(void) {
281   if( ThrottleCmd <= 0.77 )
282     return 64.94*ThrottleCmd;
283   else
284     return 217.38*ThrottleCmd - 117.38;
285 }
286
287 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288
289 double FGSimTurbine::Seek(double *var, double target, double accel, double decel) {
290   double v = *var;
291   if (v > target) {
292     v -= dt * decel;
293     if (v < target) v = target;
294   } else if (v < target) {
295     v += dt * accel;
296     if (v > target) v = target;
297   }
298   return v;
299 }
300
301 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
302
303 void FGSimTurbine::SetDefaults(void)
304 {
305   Name = "Not defined";
306   Type = etSimTurbine;
307   MilThrust = 10000.0;
308   MaxThrust = 10000.0;
309   BypassRatio = 0.0;
310   TSFC = 0.8;
311   ATSFC = 1.7;
312   IdleN1 = 30.0;
313   IdleN2 = 60.0;
314   MaxN1 = 100.0;
315   MaxN2 = 100.0;
316   Augmented = 0;
317   AugMethod = 0;
318   Injected = 0;
319   BleedDemand = 0.0;
320   ThrottleCmd = 0.0;
321   InletPosition = 1.0;
322   NozzlePosition = 1.0;
323   Augmentation = false;
324   Injection = false;
325   Reversed = false;
326   Cutoff = true;
327   phase = tpOff;
328   Stalled = false;
329   Seized = false;
330   Overtemp = false;
331   Fire = false;
332   EGT_degC = 0.0;
333 }
334
335 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
336
337 bool FGSimTurbine::Load(FGConfigFile *Eng_cfg)
338 {
339   string token;
340
341   Name = Eng_cfg->GetValue("NAME");
342   Eng_cfg->GetNextConfigLine();
343   int counter=0;
344
345   while (Eng_cfg->GetValue() != string("/FG_SIMTURBINE")) {
346     *Eng_cfg >> token;
347
348     if (token[0] == '<') token.erase(0,1); // Tables are read "<TABLE"
349
350     if      (token == "MILTHRUST") *Eng_cfg >> MilThrust;
351     else if (token == "MAXTHRUST") *Eng_cfg >> MaxThrust;
352     else if (token == "BYPASSRATIO") *Eng_cfg >> BypassRatio;
353     else if (token == "TSFC") *Eng_cfg >> TSFC;
354     else if (token == "ATSFC") *Eng_cfg >> ATSFC;
355     else if (token == "IDLEN1") *Eng_cfg >> IdleN1;
356     else if (token == "IDLEN2") *Eng_cfg >> IdleN2;
357     else if (token == "MAXN1") *Eng_cfg >> MaxN1;
358     else if (token == "MAXN2") *Eng_cfg >> MaxN2;
359     else if (token == "AUGMENTED") *Eng_cfg >> Augmented;
360     else if (token == "AUGMETHOD") *Eng_cfg >> AugMethod;
361     else if (token == "INJECTED") *Eng_cfg >> Injected;
362     else if (token == "MINTHROTTLE") *Eng_cfg >> MinThrottle;
363     else if (token == "TABLE") {
364       if (counter++ == 0) Debug(2); // print engine specs prior to table read
365       ThrustTables.push_back( new FGCoefficient(FDMExec) );
366       ThrustTables.back()->Load(Eng_cfg);
367     }
368     else cerr << "Unhandled token in Engine config file: " << token << endl;
369   }
370
371   // Pre-calculations and initializations
372
373   delay = 60.0 / (BypassRatio + 3.0);
374   N1_factor = MaxN1 - IdleN1;
375   N2_factor = MaxN2 - IdleN2;
376   OilTemp_degK = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556 + 273.0;
377   IdleFF = pow(MilThrust, 0.2) * 107.0;  // just an estimate
378
379   return true;
380 }
381
382
383 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
384 //    The bitmasked value choices are as follows:
385 //    unset: In this case (the default) JSBSim would only print
386 //       out the normally expected messages, essentially echoing
387 //       the config files as they are read. If the environment
388 //       variable is not set, debug_lvl is set to 1 internally
389 //    0: This requests JSBSim not to output any messages
390 //       whatsoever.
391 //    1: This value explicity requests the normal JSBSim
392 //       startup messages
393 //    2: This value asks for a message to be printed out when
394 //       a class is instantiated
395 //    4: When this value is set, a message is displayed when a
396 //       FGModel object executes its Run() method
397 //    8: When this value is set, various runtime state variables
398 //       are printed out periodically
399 //    16: When set various parameters are sanity checked and
400 //       a message is printed out when they go out of bounds
401
402 void FGSimTurbine::Debug(int from)
403 {
404   if (debug_lvl <= 0) return;
405
406   if (debug_lvl & 1) { // Standard console startup message output
407     if (from == 0) { // Constructor
408
409     }
410     if (from == 2) { // called from Load()
411       cout << "\n    Engine Name: "         << Name << endl;
412       cout << "      MilThrust:   "         << MilThrust << endl;
413       cout << "      MaxThrust:   "         << MaxThrust << endl;
414       cout << "      BypassRatio: "         << BypassRatio << endl;
415       cout << "      TSFC:        "         << TSFC << endl;
416       cout << "      ATSFC:       "         << ATSFC << endl;
417       cout << "      IdleN1:      "         << IdleN1 << endl;
418       cout << "      IdleN2:      "         << IdleN2 << endl;
419       cout << "      MaxN1:       "         << MaxN1 << endl;
420       cout << "      MaxN2:       "         << MaxN2 << endl;
421       cout << "      Augmented:   "         << Augmented << endl;
422       cout << "      AugMethod:   "         << AugMethod << endl;
423       cout << "      Injected:    "         << Injected << endl;
424       cout << "      MinThrottle: "         << MinThrottle << endl;
425
426       cout << endl;
427     }
428   }
429   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
430     if (from == 0) cout << "Instantiated: FGSimTurbine" << endl;
431     if (from == 1) cout << "Destroyed:    FGSimTurbine" << endl;
432   }
433   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
434   }
435   if (debug_lvl & 8 ) { // Runtime state variables
436   }
437   if (debug_lvl & 16) { // Sanity checking
438   }
439   if (debug_lvl & 64) {
440     if (from == 0) { // Constructor
441       cout << IdSrc << endl;
442       cout << IdHdr << endl;
443     }
444   }
445 }
446 }