]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/FGPropulsion.cpp
Syncing with the very latest JSBSim development code.
[flightgear.git] / src / FDM / JSBSim / FGPropulsion.cpp
1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2
3  Module:       FGPropulsion.cpp
4  Author:       Jon S. Berndt
5  Date started: 08/20/00
6  Purpose:      Encapsulates the set of engines, tanks, and thrusters associated
7                with this aircraft
8
9  ------------- Copyright (C) 2000  Jon S. Berndt (jsb@hal-pc.org) -------------
10
11  This program is free software; you can redistribute it and/or modify it under
12  the terms of the GNU General Public License as published by the Free Software
13  Foundation; either version 2 of the License, or (at your option) any later
14  version.
15
16  This program is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
18  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
19  details.
20
21  You should have received a copy of the GNU General Public License along with
22  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
23  Place - Suite 330, Boston, MA  02111-1307, USA.
24
25  Further information about the GNU General Public License can also be found on
26  the world wide web at http://www.gnu.org.
27
28 FUNCTIONAL DESCRIPTION
29 --------------------------------------------------------------------------------
30 The Propulsion class is the container for the entire propulsion system, which is
31 comprised of engines, tanks, and "thrusters" (the device that transforms the
32 engine power into a force that acts on the aircraft, such as a nozzle or
33 propeller). Once the Propulsion class gets the config file, it reads in
34 information which is specific to a type of engine. Then:
35
36 1) The appropriate engine type instance is created
37 2) A thruster object is instantiated, and is linked to the engine
38 3) At least one tank object is created, and is linked to an engine.
39
40 At Run time each engines Calculate() method is called to return the excess power
41 generated during that iteration. The drag from the previous iteration is sub-
42 tracted to give the excess power available for thrust this pass. That quantity
43 is passed to the thrusters associated with a particular engine - perhaps with a
44 scaling mechanism (gearing?) to allow the engine to give its associated thrust-
45 ers specific distributed portions of the excess power.
46
47 HISTORY
48 --------------------------------------------------------------------------------
49 08/20/00   JSB   Created
50
51 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
52 INCLUDES
53 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
54
55 #include "FGPropulsion.h"
56
57 static const char *IdSrc = "$Id$";
58 static const char *IdHdr = ID_PROPULSION;
59
60 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
61 CLASS IMPLEMENTATION
62 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
63
64
65 FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)
66 {
67   Name = "FGPropulsion";
68   numSelectedFuelTanks = numSelectedOxiTanks = 0;
69   numTanks = numEngines = numThrusters = 0;
70   numOxiTanks = numFuelTanks = 0;
71   Forces  = new FGColumnVector3(3);
72   Moments = new FGColumnVector3(3);
73
74   if (debug_lvl & 2) cout << "Instantiated: " << Name << endl;
75 }
76
77 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
78
79 FGPropulsion::~FGPropulsion()
80 {
81   for (unsigned int i=0; i<Engines.size(); i++) delete Engines[i];
82   Engines.clear();
83   if (Forces) delete Forces;
84   if (Moments) delete Moments;
85   if (debug_lvl & 2) cout << "Destroyed:    FGPropulsion" << endl;
86 }
87
88 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
89
90 bool FGPropulsion::Run(void) {
91   float PowerAvailable;
92   dt = State->Getdt();
93
94   Forces->InitMatrix();
95   Moments->InitMatrix();
96
97   if (!FGModel::Run()) {
98     for (unsigned int i=0; i<numEngines; i++) {
99       Thrusters[i]->SetdeltaT(dt*rate);
100       PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());
101       Thrusters[i]->Calculate(PowerAvailable);
102       *Forces  += Thrusters[i]->GetBodyForces();  // sum body frame forces
103       *Moments += Thrusters[i]->GetMoments();     // sum body frame moments
104     }
105
106     return false;
107   } else {
108     return true;
109   }
110 }
111
112 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113
114 bool FGPropulsion::GetSteadyState(void) {
115   float PowerAvailable;
116   float currentThrust = 0, lastThrust=-1;
117   dt = State->Getdt();
118
119   Forces->InitMatrix();
120   Moments->InitMatrix();
121
122   if (!FGModel::Run()) {
123     for (unsigned int i=0; i<numEngines; i++) {
124       Engines[i]->SetTrimMode(true);
125       Thrusters[i]->SetdeltaT(dt*rate);
126       while (pow(currentThrust - lastThrust, 2.0) > currentThrust*0.00010) {
127         PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());
128         lastThrust = currentThrust;
129         currentThrust = Thrusters[i]->Calculate(PowerAvailable);
130       }
131       *Forces  += Thrusters[i]->GetBodyForces();  // sum body frame forces
132       *Moments += Thrusters[i]->GetMoments();     // sum body frame moments
133       Engines[i]->SetTrimMode(false);
134     }
135
136     return false;
137   } else {
138     return true;
139   }
140 }
141
142 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
143
144 bool FGPropulsion::Load(FGConfigFile* AC_cfg)
145 {
146   string token, fullpath;
147   string engineFileName, engType;
148   string thrusterFileName, thrType;
149   string parameter;
150   string enginePath = FDMExec->GetEnginePath();
151   float xLoc, yLoc, zLoc, Pitch, Yaw;
152   int Feed;
153   bool ThrottleAdded = false;
154
155 # ifndef macintosh
156       fullpath = enginePath + "/";
157 # else
158       fullpath = enginePath + ";";
159 # endif
160
161   AC_cfg->GetNextConfigLine();
162
163   while ((token = AC_cfg->GetValue()) != "/PROPULSION") {
164
165     if (token == "AC_ENGINE") {                   // ============ READING ENGINES
166
167       engineFileName = AC_cfg->GetValue("FILE");
168
169       if (debug_lvl > 0) cout << "\n    Reading engine from file: " << fullpath
170                                                 + engineFileName + ".xml"<< endl;
171       FGConfigFile Eng_cfg(fullpath + engineFileName + ".xml");
172
173       if (Eng_cfg.IsOpen()) {
174         Eng_cfg.GetNextConfigLine();
175         engType = Eng_cfg.GetValue();
176
177         FCS->AddThrottle();
178         ThrottleAdded = true;
179
180         if (engType == "FG_ROCKET") {
181           Engines.push_back(new FGRocket(FDMExec, &Eng_cfg));
182         } else if (engType == "FG_PISTON") {
183           Engines.push_back(new FGPiston(FDMExec, &Eng_cfg));
184         } else if (engType == "FG_TURBOJET") {
185           Engines.push_back(new FGTurboJet(FDMExec, &Eng_cfg));
186         } else if (engType == "FG_TURBOSHAFT") {
187           Engines.push_back(new FGTurboShaft(FDMExec, &Eng_cfg));
188         } else if (engType == "FG_TURBOPROP") {
189           Engines.push_back(new FGTurboProp(FDMExec, &Eng_cfg));
190         } else {
191           cerr << "    Unrecognized engine type: " << engType << " found in config file.\n";
192         }
193
194         AC_cfg->GetNextConfigLine();
195         while ((token = AC_cfg->GetValue()) != "/AC_ENGINE") {
196           *AC_cfg >> token;
197           if      (token == "XLOC")  { *AC_cfg >> xLoc; }
198           else if (token == "YLOC")  { *AC_cfg >> yLoc; }
199           else if (token == "ZLOC")  { *AC_cfg >> zLoc; }
200           else if (token == "PITCH") { *AC_cfg >> Pitch;}
201           else if (token == "YAW")   { *AC_cfg >> Yaw;}
202           else if (token == "FEED")  {
203             *AC_cfg >> Feed;
204             Engines[numEngines]->AddFeedTank(Feed);
205             if (debug_lvl > 0) cout << "      Feed tank: " << Feed << endl;
206           } else cerr << "Unknown identifier: " << token << " in engine file: "
207                                                         << engineFileName << endl;
208         }
209
210         if (debug_lvl > 0)  {
211           cout << "      X = " << xLoc << endl;
212           cout << "      Y = " << yLoc << endl;
213           cout << "      Z = " << zLoc << endl;
214           cout << "      Pitch = " << Pitch << endl;
215           cout << "      Yaw = " << Yaw << endl;
216         }
217         
218         Engines[numEngines]->SetPlacement(xLoc, yLoc, zLoc, Pitch, Yaw);
219         numEngines++;
220
221       } else {
222
223         cerr << "Could not read engine config file: " << fullpath
224                                                   + engineFileName + ".xml" << endl;
225         return false;
226       }
227
228     } else if (token == "AC_TANK") {              // ============== READING TANKS
229
230       if (debug_lvl > 0) cout << "\n    Reading tank definition" << endl;
231       Tanks.push_back(new FGTank(AC_cfg));
232       switch(Tanks[numTanks]->GetType()) {
233       case FGTank::ttFUEL:
234         numSelectedFuelTanks++;
235         numFuelTanks++;
236         break;
237       case FGTank::ttOXIDIZER:
238         numSelectedOxiTanks++;
239         numOxiTanks++;
240         break;
241       }
242
243       numTanks++;
244
245     } else if (token == "AC_THRUSTER") {          // ========== READING THRUSTERS
246
247       thrusterFileName = AC_cfg->GetValue("FILE");
248
249       if (debug_lvl > 0) cout << "\n    Reading thruster from file: " <<
250                                     fullpath + thrusterFileName + ".xml" << endl;
251       FGConfigFile Thruster_cfg(fullpath + thrusterFileName + ".xml");
252
253       if (Thruster_cfg.IsOpen()) {
254         Thruster_cfg.GetNextConfigLine();
255         thrType = Thruster_cfg.GetValue();
256
257         if (thrType == "FG_PROPELLER") {
258           Thrusters.push_back(new FGPropeller(FDMExec, &Thruster_cfg));
259         } else if (thrType == "FG_NOZZLE") {
260           Thrusters.push_back(new FGNozzle(FDMExec, &Thruster_cfg));
261         }
262
263         AC_cfg->GetNextConfigLine();
264         while ((token = AC_cfg->GetValue()) != "/AC_THRUSTER") {
265           *AC_cfg >> token;
266           if (token == "XLOC") *AC_cfg >> xLoc;
267           else if (token == "YLOC") *AC_cfg >> yLoc;
268           else if (token == "ZLOC") *AC_cfg >> zLoc;
269           else if (token == "PITCH") *AC_cfg >> Pitch;
270           else if (token == "YAW") *AC_cfg >> Yaw;
271           else cerr << "Unknown identifier: " << token << " in engine file: "
272                                                         << engineFileName << endl;
273         }
274
275         Thrusters[numThrusters]->SetLocation(xLoc, yLoc, zLoc);
276         Thrusters[numThrusters]->SetAnglesToBody(0, Pitch, Yaw);
277         Thrusters[numThrusters]->SetdeltaT(dt*rate);
278
279         numThrusters++;
280
281       } else {
282         cerr << "Could not read thruster config file: " << fullpath
283                                                 + thrusterFileName + ".xml" << endl;
284         return false;
285       }
286
287     }
288     AC_cfg->GetNextConfigLine();
289   }
290
291   if (!ThrottleAdded) FCS->AddThrottle(); // need to have at least one throttle
292
293   return true;
294 }
295
296 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
297
298 string FGPropulsion::GetPropulsionStrings(void)
299 {
300   string PropulsionStrings = "";
301   bool firstime = true;
302
303   for (unsigned int i=0;i<Engines.size();i++) {
304     if (!firstime) {
305       PropulsionStrings += ", ";
306       firstime = false;
307     }
308
309     switch(Engines[i]->GetType()) {
310     case FGEngine::etPiston:
311       PropulsionStrings += (Engines[i]->GetName() + "_PwrAvail");
312       break;
313     case FGEngine::etRocket:
314       PropulsionStrings += (Engines[i]->GetName() + "_ChamberPress");
315       break;
316     case FGEngine::etTurboJet:
317     case FGEngine::etTurboProp:
318     case FGEngine::etTurboShaft:
319       break;
320     default:
321       PropulsionStrings += "INVALID ENGINE TYPE";
322       break;
323     }
324
325     PropulsionStrings += ", ";
326
327     switch(Thrusters[i]->GetType()) {
328     case FGThruster::ttNozzle:
329       PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust");
330       break;
331     case FGThruster::ttRotor:
332       break;
333     case FGThruster::ttPropeller:
334       PropulsionStrings += (Thrusters[i]->GetName() + "_Torque, ");
335       PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust, ");
336       PropulsionStrings += (Thrusters[i]->GetName() + "_RPM");
337       break;
338     default:
339       PropulsionStrings += "INVALID THRUSTER TYPE";
340       break;
341     }    
342   }
343
344   return PropulsionStrings;
345 }
346
347 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
348
349 string FGPropulsion::GetPropulsionValues(void)
350 {
351   char buff[20];
352   string PropulsionValues = "";
353   bool firstime = true;
354
355   for (unsigned int i=0;i<Engines.size();i++) {
356     if (!firstime) {
357       PropulsionValues += ", ";
358       firstime = false;
359     }
360
361     switch(Engines[i]->GetType()) {
362     case FGEngine::etPiston:
363       PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetPowerAvailable(), 10, buff)));
364       break;
365     case FGEngine::etRocket:
366       PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetChamberPressure(), 10, buff)));
367       break;
368     case FGEngine::etTurboJet:
369     case FGEngine::etTurboProp:
370     case FGEngine::etTurboShaft:
371       break;
372     }
373
374     PropulsionValues += ", ";
375
376     switch(Thrusters[i]->GetType()) {
377     case FGThruster::ttNozzle:
378       PropulsionValues += (string(gcvt(((FGNozzle*)Thrusters[i])->GetThrust(), 10, buff)));
379       break;
380     case FGThruster::ttRotor:
381       break;
382     case FGThruster::ttPropeller:
383       PropulsionValues += (string(gcvt(((FGPropeller*)Thrusters[i])->GetTorque(), 10, buff)) + ", ");
384       PropulsionValues += (string(gcvt(((FGPropeller*)Thrusters[i])->GetThrust(), 10, buff)) + ", ");
385       PropulsionValues += (string(gcvt(((FGPropeller*)Thrusters[i])->GetRPM(), 10, buff)));
386       break;
387     }
388   }
389
390   return PropulsionValues;
391 }
392
393 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
394
395 FGColumnVector3& FGPropulsion::GetTanksCG(void)
396 {
397   iTank = Tanks.begin();
398   vXYZtank.InitMatrix();
399   while (iTank < Tanks.end()) {
400     vXYZtank(eX) += (*iTank)->GetX()*(*iTank)->GetContents();
401     vXYZtank(eY) += (*iTank)->GetY()*(*iTank)->GetContents();
402     vXYZtank(eZ) += (*iTank)->GetZ()*(*iTank)->GetContents();
403     iTank++;
404   }
405   return vXYZtank;
406 }
407
408 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
409
410 float FGPropulsion::GetTanksWeight(void)
411 {
412   float Tw = 0.0;
413
414   iTank = Tanks.begin();
415   while (iTank < Tanks.end()) {
416     Tw += (*iTank)->GetContents();
417     iTank++;
418   }
419   return Tw;
420 }
421
422 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
423
424 float FGPropulsion::GetTanksIxx(const FGColumnVector3& vXYZcg)
425 {
426   float I = 0.0;
427   iTank = Tanks.begin();
428   while (iTank < Tanks.end()) {
429     I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetX() - vXYZcg(eX)) * (*iTank)->GetContents()/(144.0*GRAVITY);
430     iTank++;
431   }
432   return I;
433 }
434
435 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
436
437 float FGPropulsion::GetTanksIyy(const FGColumnVector3& vXYZcg)
438 {
439   float I = 0.0;
440   iTank = Tanks.begin();
441   while (iTank < Tanks.end()) {
442     I += ((*iTank)->GetY() - vXYZcg(eY))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*GRAVITY);
443     iTank++;
444   }
445   return I;
446 }
447
448 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
449
450 float FGPropulsion::GetTanksIzz(const FGColumnVector3& vXYZcg)
451 {
452   float I = 0.0;
453   iTank = Tanks.begin();
454   while (iTank < Tanks.end()) {
455     I += ((*iTank)->GetZ() - vXYZcg(eZ))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*GRAVITY);
456     iTank++;
457   }
458   return I;
459 }
460
461 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
462
463 float FGPropulsion::GetTanksIxz(const FGColumnVector3& vXYZcg)
464 {
465   float I = 0.0;
466   iTank = Tanks.begin();
467   while (iTank < Tanks.end()) {
468     I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*GRAVITY);
469     iTank++;
470   }
471   return I;
472 }
473
474 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
475
476 float FGPropulsion::GetTanksIxy(const FGColumnVector3& vXYZcg)
477 {
478   float I = 0.0;
479   iTank = Tanks.begin();
480   while (iTank != Tanks.end()) {
481     I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*GRAVITY);
482     iTank++;
483   }
484   return I;
485 }
486
487 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
488
489 void FGPropulsion::Debug(void)
490 {
491     //TODO: Add your source code here
492 }
493