]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/FGPropulsion.cpp
Synced with latest JSBSim as of June 5, 2001.
[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::LoadPropulsion(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
156 # ifndef macintosh
157       fullpath = enginePath + "/";
158 # else
159       fullpath = enginePath + ";";
160 # endif
161
162   AC_cfg->GetNextConfigLine();
163
164   while ((token = AC_cfg->GetValue()) != "/PROPULSION") {
165
166     if (token == "AC_ENGINE") {                   // ============ READING ENGINES
167
168       engineFileName = AC_cfg->GetValue("FILE");
169
170       if (debug_lvl > 0) cout << "\n    Reading engine from file: " << fullpath
171                                                 + engineFileName + ".xml"<< endl;
172       FGConfigFile Eng_cfg(fullpath + engineFileName + ".xml");
173
174       if (Eng_cfg.IsOpen()) {
175         Eng_cfg.GetNextConfigLine();
176         engType = Eng_cfg.GetValue();
177
178         FCS->AddThrottle();
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   return true;
292 }
293
294 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
295
296 string FGPropulsion::GetPropulsionStrings(void)
297 {
298   string PropulsionStrings = "";
299   bool firstime = true;
300
301   for (unsigned int i=0;i<Engines.size();i++) {
302     if (!firstime) {
303       PropulsionStrings += ", ";
304       firstime = false;
305     }
306
307     switch(Engines[i]->GetType()) {
308     case FGEngine::etPiston:
309       PropulsionStrings += (Engines[i]->GetName() + "_PwrAvail");
310       break;
311     case FGEngine::etRocket:
312       PropulsionStrings += (Engines[i]->GetName() + "_ChamberPress");
313       break;
314     case FGEngine::etTurboJet:
315     case FGEngine::etTurboProp:
316     case FGEngine::etTurboShaft:
317       break;
318     default:
319       PropulsionStrings += "INVALID ENGINE TYPE";
320       break;
321     }
322
323     PropulsionStrings += ", ";
324
325     switch(Thrusters[i]->GetType()) {
326     case FGThruster::ttNozzle:
327       PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust");
328       break;
329     case FGThruster::ttRotor:
330       break;
331     case FGThruster::ttPropeller:
332       PropulsionStrings += (Thrusters[i]->GetName() + "_Torque, ");
333       PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust, ");
334       PropulsionStrings += (Thrusters[i]->GetName() + "_RPM");
335       break;
336     default:
337       PropulsionStrings += "INVALID THRUSTER TYPE";
338       break;
339     }    
340   }
341
342   return PropulsionStrings;
343 }
344
345 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346
347 string FGPropulsion::GetPropulsionValues(void)
348 {
349   char buff[20];
350   string PropulsionValues = "";
351   bool firstime = true;
352
353   for (unsigned int i=0;i<Engines.size();i++) {
354     if (!firstime) {
355       PropulsionValues += ", ";
356       firstime = false;
357     }
358
359     switch(Engines[i]->GetType()) {
360     case FGEngine::etPiston:
361       PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetPowerAvailable(), 10, buff)));
362       break;
363     case FGEngine::etRocket:
364       PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetChamberPressure(), 10, buff)));
365       break;
366     case FGEngine::etTurboJet:
367     case FGEngine::etTurboProp:
368     case FGEngine::etTurboShaft:
369       break;
370     }
371
372     PropulsionValues += ", ";
373
374     switch(Thrusters[i]->GetType()) {
375     case FGThruster::ttNozzle:
376       PropulsionValues += (string(gcvt(((FGNozzle*)Thrusters[i])->GetThrust(), 10, buff)));
377       break;
378     case FGThruster::ttRotor:
379       break;
380     case FGThruster::ttPropeller:
381       PropulsionValues += (string(gcvt(((FGPropeller*)Thrusters[i])->GetTorque(), 10, buff)) + ", ");
382       PropulsionValues += (string(gcvt(((FGPropeller*)Thrusters[i])->GetThrust(), 10, buff)) + ", ");
383       PropulsionValues += (string(gcvt(((FGPropeller*)Thrusters[i])->GetRPM(), 10, buff)));
384       break;
385     }
386   }
387
388   return PropulsionValues;
389 }
390
391 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
392
393 FGColumnVector& FGPropulsion::GetTanksCG(void)
394 {
395   iTank = Tanks.begin();
396   vXYZtank.InitMatrix();
397   while (iTank < Tanks.end()) {
398     vXYZtank(eX) += (*iTank)->GetX()*(*iTank)->GetContents();
399     vXYZtank(eY) += (*iTank)->GetY()*(*iTank)->GetContents();
400     vXYZtank(eZ) += (*iTank)->GetZ()*(*iTank)->GetContents();
401     iTank++;
402   }
403   return vXYZtank;
404 }
405
406 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
407
408 float FGPropulsion::GetTanksWeight(void)
409 {
410   float Tw = 0.0;
411
412   iTank = Tanks.begin();
413   while (iTank < Tanks.end()) {
414     Tw += (*iTank)->GetContents();
415     iTank++;
416   }
417   return Tw;
418 }
419
420 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
421
422 float FGPropulsion::GetTanksIxx(const FGColumnVector& vXYZcg)
423 {
424   float I = 0.0;
425   iTank = Tanks.begin();
426   while (iTank < Tanks.end()) {
427     I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetX() - vXYZcg(eX)) * (*iTank)->GetContents()/(144.0*GRAVITY);
428     iTank++;
429   }
430   return I;
431 }
432
433 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
434
435 float FGPropulsion::GetTanksIyy(const FGColumnVector& vXYZcg)
436 {
437   float I = 0.0;
438   iTank = Tanks.begin();
439   while (iTank < Tanks.end()) {
440     I += ((*iTank)->GetY() - vXYZcg(eY))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*GRAVITY);
441     iTank++;
442   }
443   return I;
444 }
445
446 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
447
448 float FGPropulsion::GetTanksIzz(const FGColumnVector& vXYZcg)
449 {
450   float I = 0.0;
451   iTank = Tanks.begin();
452   while (iTank < Tanks.end()) {
453     I += ((*iTank)->GetZ() - vXYZcg(eZ))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*GRAVITY);
454     iTank++;
455   }
456   return I;
457 }
458
459 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
460
461 float FGPropulsion::GetTanksIxz(const FGColumnVector& vXYZcg)
462 {
463   float I = 0.0;
464   iTank = Tanks.begin();
465   while (iTank < Tanks.end()) {
466     I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*GRAVITY);
467     iTank++;
468   }
469   return I;
470 }
471
472 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
473
474 float FGPropulsion::GetTanksIxy(const FGColumnVector& vXYZcg)
475 {
476   float I = 0.0;
477   iTank = Tanks.begin();
478   while (iTank != Tanks.end()) {
479     I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*GRAVITY);
480     iTank++;
481   }
482   return I;
483 }
484
485 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
486
487 void FGPropulsion::Debug(void)
488 {
489     //TODO: Add your source code here
490 }
491