]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/FGPropulsion.cpp
2a2ef8cb4d1b8b6ae5a1b6df811949f25d92296d
[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 extern short debug_lvl;
61
62 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
63 CLASS IMPLEMENTATION
64 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
65
66
67 FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)
68 {
69   Name = "FGPropulsion";
70   numSelectedFuelTanks = numSelectedOxiTanks = 0;
71   numTanks = numEngines = numThrusters = 0;
72   numOxiTanks = numFuelTanks = 0;
73   Forces  = new FGColumnVector(3);
74   Moments = new FGColumnVector(3);
75
76   if (debug_lvl & 2) cout << "Instantiated: " << Name << endl;
77 }
78
79 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
80
81 FGPropulsion::~FGPropulsion()
82 {
83   for (unsigned int i=0; i<Engines.size(); i++) delete Engines[i];
84   Engines.clear();
85   if (Forces) delete Forces;
86   if (Moments) delete Moments;
87   if (debug_lvl & 2) cout << "Destroyed:    FGPropulsion" << endl;
88 }
89
90 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
91
92 bool FGPropulsion::Run(void) {
93   float PowerAvailable;
94   dt = State->Getdt();
95
96   Forces->InitMatrix();
97   Moments->InitMatrix();
98
99   if (!FGModel::Run()) {
100     for (unsigned int i=0; i<numEngines; i++) {
101       Thrusters[i]->SetdeltaT(dt*rate);
102       PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());
103       Thrusters[i]->Calculate(PowerAvailable);
104       *Forces  += Thrusters[i]->GetBodyForces();  // sum body frame forces
105       *Moments += Thrusters[i]->GetMoments();     // sum body frame moments
106     }
107
108     return false;
109   } else {
110     return true;
111   }
112 }
113
114 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
115
116 bool FGPropulsion::GetSteadyState(void) {
117   float PowerAvailable;
118   float currentThrust = 0, lastThrust=-1;
119   dt = State->Getdt();
120
121   Forces->InitMatrix();
122   Moments->InitMatrix();
123
124   if (!FGModel::Run()) {
125     for (unsigned int i=0; i<numEngines; i++) {
126       Engines[i]->SetTrimMode(true);
127       Thrusters[i]->SetdeltaT(dt*rate);
128       while (pow(currentThrust - lastThrust, 2.0) > currentThrust*0.00010) {
129         PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());
130         lastThrust = currentThrust;
131         currentThrust = Thrusters[i]->Calculate(PowerAvailable);
132       }
133       *Forces  += Thrusters[i]->GetBodyForces();  // sum body frame forces
134       *Moments += Thrusters[i]->GetMoments();     // sum body frame moments
135       Engines[i]->SetTrimMode(false);
136     }
137
138     return false;
139   } else {
140     return true;
141   }
142 }
143
144 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
145
146 bool FGPropulsion::Load(FGConfigFile* AC_cfg)
147 {
148   string token, fullpath;
149   string engineFileName, engType;
150   string thrusterFileName, thrType;
151   string parameter;
152   string enginePath = FDMExec->GetEnginePath();
153   float xLoc, yLoc, zLoc, Pitch, Yaw;
154   int Feed;
155   bool ThrottleAdded = false;
156
157 # ifndef macintosh
158       fullpath = enginePath + "/";
159 # else
160       fullpath = enginePath + ";";
161 # endif
162
163   AC_cfg->GetNextConfigLine();
164
165   while ((token = AC_cfg->GetValue()) != "/PROPULSION") {
166
167     if (token == "AC_ENGINE") {                   // ============ READING ENGINES
168
169       engineFileName = AC_cfg->GetValue("FILE");
170
171       if (debug_lvl > 0) cout << "\n    Reading engine from file: " << fullpath
172                                                 + engineFileName + ".xml"<< endl;
173       FGConfigFile Eng_cfg(fullpath + engineFileName + ".xml");
174
175       if (Eng_cfg.IsOpen()) {
176         Eng_cfg.GetNextConfigLine();
177         engType = Eng_cfg.GetValue();
178
179         FCS->AddThrottle();
180         ThrottleAdded = true;
181
182         if (engType == "FG_ROCKET") {
183           Engines.push_back(new FGRocket(FDMExec, &Eng_cfg));
184         } else if (engType == "FG_PISTON") {
185           Engines.push_back(new FGPiston(FDMExec, &Eng_cfg));
186         } else if (engType == "FG_TURBOJET") {
187           Engines.push_back(new FGTurboJet(FDMExec, &Eng_cfg));
188         } else if (engType == "FG_TURBOSHAFT") {
189           Engines.push_back(new FGTurboShaft(FDMExec, &Eng_cfg));
190         } else if (engType == "FG_TURBOPROP") {
191           Engines.push_back(new FGTurboProp(FDMExec, &Eng_cfg));
192         } else {
193           cerr << "    Unrecognized engine type: " << engType << " found in config file.\n";
194         }
195
196         AC_cfg->GetNextConfigLine();
197         while ((token = AC_cfg->GetValue()) != "/AC_ENGINE") {
198           *AC_cfg >> token;
199           if      (token == "XLOC")  { *AC_cfg >> xLoc; }
200           else if (token == "YLOC")  { *AC_cfg >> yLoc; }
201           else if (token == "ZLOC")  { *AC_cfg >> zLoc; }
202           else if (token == "PITCH") { *AC_cfg >> Pitch;}
203           else if (token == "YAW")   { *AC_cfg >> Yaw;}
204           else if (token == "FEED")  {
205             *AC_cfg >> Feed;
206             Engines[numEngines]->AddFeedTank(Feed);
207             if (debug_lvl > 0) cout << "      Feed tank: " << Feed << endl;
208           } else cerr << "Unknown identifier: " << token << " in engine file: "
209                                                         << engineFileName << endl;
210         }
211
212         if (debug_lvl > 0)  {
213           cout << "      X = " << xLoc << endl;
214           cout << "      Y = " << yLoc << endl;
215           cout << "      Z = " << zLoc << endl;
216           cout << "      Pitch = " << Pitch << endl;
217           cout << "      Yaw = " << Yaw << endl;
218         }
219         
220         Engines[numEngines]->SetPlacement(xLoc, yLoc, zLoc, Pitch, Yaw);
221         numEngines++;
222
223       } else {
224
225         cerr << "Could not read engine config file: " << fullpath
226                                                   + engineFileName + ".xml" << endl;
227         return false;
228       }
229
230     } else if (token == "AC_TANK") {              // ============== READING TANKS
231
232       if (debug_lvl > 0) cout << "\n    Reading tank definition" << endl;
233       Tanks.push_back(new FGTank(AC_cfg));
234       switch(Tanks[numTanks]->GetType()) {
235       case FGTank::ttFUEL:
236         numSelectedFuelTanks++;
237         numFuelTanks++;
238         break;
239       case FGTank::ttOXIDIZER:
240         numSelectedOxiTanks++;
241         numOxiTanks++;
242         break;
243       }
244
245       numTanks++;
246
247     } else if (token == "AC_THRUSTER") {          // ========== READING THRUSTERS
248
249       thrusterFileName = AC_cfg->GetValue("FILE");
250
251       if (debug_lvl > 0) cout << "\n    Reading thruster from file: " <<
252                                     fullpath + thrusterFileName + ".xml" << endl;
253       FGConfigFile Thruster_cfg(fullpath + thrusterFileName + ".xml");
254
255       if (Thruster_cfg.IsOpen()) {
256         Thruster_cfg.GetNextConfigLine();
257         thrType = Thruster_cfg.GetValue();
258
259         if (thrType == "FG_PROPELLER") {
260           Thrusters.push_back(new FGPropeller(FDMExec, &Thruster_cfg));
261         } else if (thrType == "FG_NOZZLE") {
262           Thrusters.push_back(new FGNozzle(FDMExec, &Thruster_cfg));
263         }
264
265         AC_cfg->GetNextConfigLine();
266         while ((token = AC_cfg->GetValue()) != "/AC_THRUSTER") {
267           *AC_cfg >> token;
268           if (token == "XLOC") *AC_cfg >> xLoc;
269           else if (token == "YLOC") *AC_cfg >> yLoc;
270           else if (token == "ZLOC") *AC_cfg >> zLoc;
271           else if (token == "PITCH") *AC_cfg >> Pitch;
272           else if (token == "YAW") *AC_cfg >> Yaw;
273           else cerr << "Unknown identifier: " << token << " in engine file: "
274                                                         << engineFileName << endl;
275         }
276
277         Thrusters[numThrusters]->SetLocation(xLoc, yLoc, zLoc);
278         Thrusters[numThrusters]->SetAnglesToBody(0, Pitch, Yaw);
279         Thrusters[numThrusters]->SetdeltaT(dt*rate);
280
281         numThrusters++;
282
283       } else {
284         cerr << "Could not read thruster config file: " << fullpath
285                                                 + thrusterFileName + ".xml" << endl;
286         return false;
287       }
288
289     }
290     AC_cfg->GetNextConfigLine();
291   }
292
293   if (!ThrottleAdded) FCS->AddThrottle(); // need to have at least one throttle
294
295   return true;
296 }
297
298 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
299
300 string FGPropulsion::GetPropulsionStrings(void)
301 {
302   string PropulsionStrings = "";
303   bool firstime = true;
304
305   for (unsigned int i=0;i<Engines.size();i++) {
306     if (!firstime) {
307       PropulsionStrings += ", ";
308       firstime = false;
309     }
310
311     switch(Engines[i]->GetType()) {
312     case FGEngine::etPiston:
313       PropulsionStrings += (Engines[i]->GetName() + "_PwrAvail");
314       break;
315     case FGEngine::etRocket:
316       PropulsionStrings += (Engines[i]->GetName() + "_ChamberPress");
317       break;
318     case FGEngine::etTurboJet:
319     case FGEngine::etTurboProp:
320     case FGEngine::etTurboShaft:
321       break;
322     default:
323       PropulsionStrings += "INVALID ENGINE TYPE";
324       break;
325     }
326
327     PropulsionStrings += ", ";
328
329     switch(Thrusters[i]->GetType()) {
330     case FGThruster::ttNozzle:
331       PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust");
332       break;
333     case FGThruster::ttRotor:
334       break;
335     case FGThruster::ttPropeller:
336       PropulsionStrings += (Thrusters[i]->GetName() + "_Torque, ");
337       PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust, ");
338       PropulsionStrings += (Thrusters[i]->GetName() + "_RPM");
339       break;
340     default:
341       PropulsionStrings += "INVALID THRUSTER TYPE";
342       break;
343     }    
344   }
345
346   return PropulsionStrings;
347 }
348
349 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
350
351 string FGPropulsion::GetPropulsionValues(void)
352 {
353   char buff[20];
354   string PropulsionValues = "";
355   bool firstime = true;
356
357   for (unsigned int i=0;i<Engines.size();i++) {
358     if (!firstime) {
359       PropulsionValues += ", ";
360       firstime = false;
361     }
362
363     switch(Engines[i]->GetType()) {
364     case FGEngine::etPiston:
365       PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetPowerAvailable(), 10, buff)));
366       break;
367     case FGEngine::etRocket:
368       PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetChamberPressure(), 10, buff)));
369       break;
370     case FGEngine::etTurboJet:
371     case FGEngine::etTurboProp:
372     case FGEngine::etTurboShaft:
373       break;
374     }
375
376     PropulsionValues += ", ";
377
378     switch(Thrusters[i]->GetType()) {
379     case FGThruster::ttNozzle:
380       PropulsionValues += (string(gcvt(((FGNozzle*)Thrusters[i])->GetThrust(), 10, buff)));
381       break;
382     case FGThruster::ttRotor:
383       break;
384     case FGThruster::ttPropeller:
385       PropulsionValues += (string(gcvt(((FGPropeller*)Thrusters[i])->GetTorque(), 10, buff)) + ", ");
386       PropulsionValues += (string(gcvt(((FGPropeller*)Thrusters[i])->GetThrust(), 10, buff)) + ", ");
387       PropulsionValues += (string(gcvt(((FGPropeller*)Thrusters[i])->GetRPM(), 10, buff)));
388       break;
389     }
390   }
391
392   return PropulsionValues;
393 }
394
395 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
396
397 FGColumnVector& FGPropulsion::GetTanksCG(void)
398 {
399   iTank = Tanks.begin();
400   vXYZtank.InitMatrix();
401   while (iTank < Tanks.end()) {
402     vXYZtank(eX) += (*iTank)->GetX()*(*iTank)->GetContents();
403     vXYZtank(eY) += (*iTank)->GetY()*(*iTank)->GetContents();
404     vXYZtank(eZ) += (*iTank)->GetZ()*(*iTank)->GetContents();
405     iTank++;
406   }
407   return vXYZtank;
408 }
409
410 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
411
412 float FGPropulsion::GetTanksWeight(void)
413 {
414   float Tw = 0.0;
415
416   iTank = Tanks.begin();
417   while (iTank < Tanks.end()) {
418     Tw += (*iTank)->GetContents();
419     iTank++;
420   }
421   return Tw;
422 }
423
424 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
425
426 float FGPropulsion::GetTanksIxx(const FGColumnVector& vXYZcg)
427 {
428   float I = 0.0;
429   iTank = Tanks.begin();
430   while (iTank < Tanks.end()) {
431     I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetX() - vXYZcg(eX)) * (*iTank)->GetContents()/(144.0*GRAVITY);
432     iTank++;
433   }
434   return I;
435 }
436
437 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
438
439 float FGPropulsion::GetTanksIyy(const FGColumnVector& vXYZcg)
440 {
441   float I = 0.0;
442   iTank = Tanks.begin();
443   while (iTank < Tanks.end()) {
444     I += ((*iTank)->GetY() - vXYZcg(eY))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*GRAVITY);
445     iTank++;
446   }
447   return I;
448 }
449
450 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
451
452 float FGPropulsion::GetTanksIzz(const FGColumnVector& vXYZcg)
453 {
454   float I = 0.0;
455   iTank = Tanks.begin();
456   while (iTank < Tanks.end()) {
457     I += ((*iTank)->GetZ() - vXYZcg(eZ))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*GRAVITY);
458     iTank++;
459   }
460   return I;
461 }
462
463 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
464
465 float FGPropulsion::GetTanksIxz(const FGColumnVector& vXYZcg)
466 {
467   float I = 0.0;
468   iTank = Tanks.begin();
469   while (iTank < Tanks.end()) {
470     I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*GRAVITY);
471     iTank++;
472   }
473   return I;
474 }
475
476 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
477
478 float FGPropulsion::GetTanksIxy(const FGColumnVector& vXYZcg)
479 {
480   float I = 0.0;
481   iTank = Tanks.begin();
482   while (iTank != Tanks.end()) {
483     I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*GRAVITY);
484     iTank++;
485   }
486   return I;
487 }
488
489 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490
491 void FGPropulsion::Debug(void)
492 {
493     //TODO: Add your source code here
494 }
495