]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/FGSimTurbine.cpp
Curt Olson:
[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   return 0.0; 
135 }
136
137 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
138
139 double FGSimTurbine::Run(void)
140 {
141   double idlethrust, milthrust, thrust;
142   double N2norm;   // 0.0 = idle N2, 1.0 = maximum N2
143   idlethrust = MilThrust * ThrustTables[0]->TotalValue();
144   milthrust = (MilThrust - idlethrust) * ThrustTables[1]->TotalValue();
145
146   Running = true;
147   Starter = false;
148  
149   N2 = Seek(&N2, IdleN2 + ThrottleCmd * N2_factor, delay, delay * 3.0);
150   N1 = Seek(&N1, IdleN1 + ThrottleCmd * N1_factor, delay, delay * 2.4);
151   N2norm = (N2 - IdleN2) / N2_factor;
152   thrust = idlethrust + (milthrust * N2norm * N2norm); 
153   thrust = thrust * (1.0 - BleedDemand);
154   EGT_degC = TAT + 363.1 + ThrottleCmd * 357.1;
155   OilPressure_psi = N2 * 0.62;
156   OilTemp_degK = Seek(&OilTemp_degK, 366.0, 1.2, 0.1);
157   EPR = 1.0 + thrust/MilThrust;
158
159   if (!Augmentation) {
160     FuelFlow_pph = Seek(&FuelFlow_pph, thrust * TSFC, 1000.0, 100000);
161     if (FuelFlow_pph < IdleFF) FuelFlow_pph = IdleFF;
162     NozzlePosition = Seek(&NozzlePosition, 1.0 - N2norm, 0.8, 0.8);
163   }
164
165   if (AugMethod == 1) {
166     if ((ThrottleCmd > 0.99) && (N2 > 97.0)) {Augmentation = true;} 
167     else {Augmentation = false;}
168   }
169
170   if ((Augmented == 1) && Augmentation) {
171     thrust = MaxThrust * ThrustTables[2]->TotalValue();
172     FuelFlow_pph = Seek(&FuelFlow_pph, thrust * ATSFC, 5000.0, 10000.0);
173     NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
174   }
175
176   if ((Injected == 1) && Injection)
177     thrust = thrust * ThrustTables[3]->TotalValue(); 
178
179   ConsumeFuel();
180   if (Cutoff) phase = tpOff;
181   if (Starved) phase = tpOff;
182
183   return thrust;
184 }
185         
186 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187
188 double FGSimTurbine::SpinUp(void)
189 {
190   Running = false;
191   FuelFlow_pph = 0.0;
192   N2 = Seek(&N2, 25.18, 3.0, N2/2.0);
193   N1 = Seek(&N1, 5.21, 1.0, N1/2.0);
194   EGT_degC = Seek(&EGT_degC, TAT, 11.7, 7.3);
195   OilPressure_psi = N2 * 0.62;
196   OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0.2, 0.2);
197   EPR = 1.0;
198   NozzlePosition = 1.0;
199
200   return 0.0;
201 }
202
203 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
204
205 double FGSimTurbine::Start(void)
206 {
207   if ((N2 > 15.0) && !Starved) {       // minimum 15% N2 needed for start
208     Cranking = true;                   // provided for sound effects signal
209     if (N2 < IdleN2) {
210       N2 = Seek(&N2, IdleN2, 2.0, N2/2.0);
211       N1 = Seek(&N1, IdleN1, 1.4, N1/2.0);
212       EGT_degC = Seek(&EGT_degC, TAT + 363.1, 21.3, 7.3);
213       FuelFlow_pph = Seek(&FuelFlow_pph, IdleFF, 103.7, 103.7);
214       OilPressure_psi = N2 * 0.62;
215       }
216     else {
217       phase = tpRun;
218       Running = true;
219       Starter = false;
220       Cranking = false;
221       } 
222     }
223   else {                 // no start if N2 < 15%
224     phase = tpOff;
225     Starter = false;
226     }
227
228   return 0.0; 
229 }
230
231 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
232
233 double FGSimTurbine::Stall(void)
234 {
235   double qbar = Translation->Getqbar();
236   EGT_degC = TAT + 903.14;
237   FuelFlow_pph = IdleFF;
238   N1 = Seek(&N1, qbar/10.0, 0, N1/10.0); 
239   N2 = Seek(&N2, qbar/15.0, 0, N2/10.0);
240   if (ThrottleCmd == 0) phase = tpRun;        // clear the stall with throttle
241
242   return 0.0; 
243 }
244
245 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
246
247 double FGSimTurbine::Seize(void)
248 {
249     double qbar = Translation->Getqbar();
250     N2 = 0.0;
251     N1 = Seek(&N1, qbar/20.0, 0, N1/15.0);
252     FuelFlow_pph = IdleFF;
253     OilPressure_psi = 0.0;
254     OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0, 0.2);
255     Running = false;
256     return 0.0; 
257 }
258
259 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
260
261 double FGSimTurbine::Trim(void)
262 {
263     double idlethrust, milthrust, thrust;
264     idlethrust = MilThrust * ThrustTables[0]->TotalValue();
265     milthrust = (MilThrust - idlethrust) * ThrustTables[1]->TotalValue();
266     thrust = idlethrust + (milthrust * ThrottleCmd * ThrottleCmd);
267     return thrust; 
268 }
269
270 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
271
272 double FGSimTurbine::CalcFuelNeed(void)
273 {
274   return FuelFlow_pph /3600 * State->Getdt() * Propulsion->GetRate();
275 }
276
277 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
278
279 double FGSimTurbine::GetPowerAvailable(void) {
280   if( ThrottleCmd <= 0.77 )
281     return 64.94*ThrottleCmd;
282   else
283     return 217.38*ThrottleCmd - 117.38;
284 }
285
286 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
287
288 double FGSimTurbine::Seek(double *var, double target, double accel, double decel) {
289   double v = *var;
290   if (v > target) {
291     v -= dt * decel;
292     if (v < target) v = target;
293   } else if (v < target) {
294     v += dt * accel;
295     if (v > target) v = target;
296   }
297   return v;
298 }
299
300 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
301
302 void FGSimTurbine::SetDefaults(void)
303 {
304   Name = "Not defined";
305   Type = etSimTurbine;
306   MilThrust = 10000.0;
307   MaxThrust = 10000.0;
308   BypassRatio = 0.0;
309   TSFC = 0.8;
310   ATSFC = 1.7;
311   IdleN1 = 30.0;
312   IdleN2 = 60.0;
313   MaxN1 = 100.0;
314   MaxN2 = 100.0;
315   Augmented = 0;
316   AugMethod = 0;
317   Injected = 0;
318   BleedDemand = 0.0;
319   ThrottleCmd = 0.0;
320   InletPosition = 1.0;
321   NozzlePosition = 1.0;
322   Augmentation = false;
323   Injection = false;
324   Reversed = false;
325   Cutoff = true;
326   phase = tpOff;
327   Stalled = false;
328   Seized = false;
329   Overtemp = false;
330   Fire = false;
331   EGT_degC = 0.0;
332 }
333
334 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
335
336 bool FGSimTurbine::Load(FGConfigFile *Eng_cfg)
337 {
338   string token;
339
340   Name = Eng_cfg->GetValue("NAME");
341   Eng_cfg->GetNextConfigLine();
342   int counter=0;
343
344   while (Eng_cfg->GetValue() != string("/FG_SIMTURBINE")) {
345     *Eng_cfg >> token;
346
347     if (token[0] == '<') token.erase(0,1); // Tables are read "<TABLE"
348
349     if      (token == "MILTHRUST") *Eng_cfg >> MilThrust;
350     else if (token == "MAXTHRUST") *Eng_cfg >> MaxThrust;
351     else if (token == "BYPASSRATIO") *Eng_cfg >> BypassRatio;
352     else if (token == "TSFC") *Eng_cfg >> TSFC;
353     else if (token == "ATSFC") *Eng_cfg >> ATSFC;
354     else if (token == "IDLEN1") *Eng_cfg >> IdleN1;
355     else if (token == "IDLEN2") *Eng_cfg >> IdleN2;
356     else if (token == "MAXN1") *Eng_cfg >> MaxN1;
357     else if (token == "MAXN2") *Eng_cfg >> MaxN2;
358     else if (token == "AUGMENTED") *Eng_cfg >> Augmented;
359     else if (token == "AUGMETHOD") *Eng_cfg >> AugMethod;
360     else if (token == "INJECTED") *Eng_cfg >> Injected;
361     else if (token == "MINTHROTTLE") *Eng_cfg >> MinThrottle;
362     else if (token == "TABLE") {
363       if (counter++ == 0) Debug(2); // print engine specs prior to table read
364       ThrustTables.push_back( new FGCoefficient(FDMExec) );
365       ThrustTables.back()->Load(Eng_cfg);
366     }
367     else cerr << "Unhandled token in Engine config file: " << token << endl;
368   }
369
370   // Pre-calculations and initializations
371
372   delay = 60.0 / (BypassRatio + 3.0);
373   N1_factor = MaxN1 - IdleN1;
374   N2_factor = MaxN2 - IdleN2;
375   OilTemp_degK = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556 + 273.0;
376   IdleFF = pow(MilThrust, 0.2) * 107.0;  // just an estimate
377
378   return true;
379 }
380
381
382 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
383 //    The bitmasked value choices are as follows:
384 //    unset: In this case (the default) JSBSim would only print
385 //       out the normally expected messages, essentially echoing
386 //       the config files as they are read. If the environment
387 //       variable is not set, debug_lvl is set to 1 internally
388 //    0: This requests JSBSim not to output any messages
389 //       whatsoever.
390 //    1: This value explicity requests the normal JSBSim
391 //       startup messages
392 //    2: This value asks for a message to be printed out when
393 //       a class is instantiated
394 //    4: When this value is set, a message is displayed when a
395 //       FGModel object executes its Run() method
396 //    8: When this value is set, various runtime state variables
397 //       are printed out periodically
398 //    16: When set various parameters are sanity checked and
399 //       a message is printed out when they go out of bounds
400
401 void FGSimTurbine::Debug(int from)
402 {
403   if (debug_lvl <= 0) return;
404
405   if (debug_lvl & 1) { // Standard console startup message output
406     if (from == 0) { // Constructor
407
408     }
409     if (from == 2) { // called from Load()
410       cout << "\n    Engine Name: "         << Name << endl;
411       cout << "      MilThrust:   "         << MilThrust << endl;
412       cout << "      MaxThrust:   "         << MaxThrust << endl;
413       cout << "      BypassRatio: "         << BypassRatio << endl;
414       cout << "      TSFC:        "         << TSFC << endl;
415       cout << "      ATSFC:       "         << ATSFC << endl;
416       cout << "      IdleN1:      "         << IdleN1 << endl;
417       cout << "      IdleN2:      "         << IdleN2 << endl;
418       cout << "      MaxN1:       "         << MaxN1 << endl;
419       cout << "      MaxN2:       "         << MaxN2 << endl;
420       cout << "      Augmented:   "         << Augmented << endl;
421       cout << "      AugMethod:   "         << AugMethod << endl;
422       cout << "      Injected:    "         << Injected << endl;
423       cout << "      MinThrottle: "         << MinThrottle << endl;
424
425       cout << endl;
426     }
427   }
428   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
429     if (from == 0) cout << "Instantiated: FGSimTurbine" << endl;
430     if (from == 1) cout << "Destroyed:    FGSimTurbine" << endl;
431   }
432   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
433   }
434   if (debug_lvl & 8 ) { // Runtime state variables
435   }
436   if (debug_lvl & 16) { // Sanity checking
437   }
438   if (debug_lvl & 64) {
439     if (from == 0) { // Constructor
440       cout << IdSrc << endl;
441       cout << IdHdr << endl;
442     }
443   }
444 }
445 }