1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 Module: FGPropulsion.cpp
6 Purpose: Encapsulates the set of engines, tanks, and thrusters associated
9 ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
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
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
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.
25 Further information about the GNU General Public License can also be found on
26 the world wide web at http://www.gnu.org.
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:
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.
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.
48 --------------------------------------------------------------------------------
51 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
53 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
55 #include "FGPropulsion.h"
57 static const char *IdSrc = "$Id$";
58 static const char *IdHdr = ID_PROPULSION;
60 extern short debug_lvl;
62 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
64 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
67 FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)
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);
76 if (debug_lvl & 2) cout << "Instantiated: " << Name << endl;
79 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
81 FGPropulsion::~FGPropulsion()
83 for (unsigned int i=0; i<Engines.size(); i++) delete Engines[i];
85 if (Forces) delete Forces;
86 if (Moments) delete Moments;
87 if (debug_lvl & 2) cout << "Destroyed: FGPropulsion" << endl;
90 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
92 bool FGPropulsion::Run(void) {
97 Moments->InitMatrix();
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
114 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
116 bool FGPropulsion::GetSteadyState(void) {
117 float PowerAvailable;
118 float currentThrust = 0, lastThrust=-1;
121 Forces->InitMatrix();
122 Moments->InitMatrix();
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);
133 *Forces += Thrusters[i]->GetBodyForces(); // sum body frame forces
134 *Moments += Thrusters[i]->GetMoments(); // sum body frame moments
135 Engines[i]->SetTrimMode(false);
144 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
146 bool FGPropulsion::LoadPropulsion(FGConfigFile* AC_cfg)
148 string token, fullpath;
149 string engineFileName, engType;
150 string thrusterFileName, thrType;
152 string enginePath = FDMExec->GetEnginePath();
153 float xLoc, yLoc, zLoc, Pitch, Yaw;
157 fullpath = enginePath + "/";
159 fullpath = enginePath + ";";
162 AC_cfg->GetNextConfigLine();
164 while ((token = AC_cfg->GetValue()) != "/PROPULSION") {
166 if (token == "AC_ENGINE") { // ============ READING ENGINES
168 engineFileName = AC_cfg->GetValue("FILE");
170 cout << "\n Reading engine from file: " << fullpath
171 + engineFileName + ".xml"<< endl;
172 FGConfigFile Eng_cfg(fullpath + engineFileName + ".xml");
174 if (Eng_cfg.IsOpen()) {
175 Eng_cfg.GetNextConfigLine();
176 engType = Eng_cfg.GetValue();
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));
191 cerr << " Unrecognized engine type: " << engType << " found in config file.\n";
194 AC_cfg->GetNextConfigLine();
195 while ((token = AC_cfg->GetValue()) != "/AC_ENGINE") {
197 if (token == "XLOC") { *AC_cfg >> xLoc; cout << " X = " << xLoc << endl;}
198 else if (token == "YLOC") { *AC_cfg >> yLoc; cout << " Y = " << yLoc << endl;}
199 else if (token == "ZLOC") { *AC_cfg >> zLoc; cout << " Z = " << zLoc << endl;}
200 else if (token == "PITCH") { *AC_cfg >> Pitch; cout << " Pitch = " << Pitch << endl;}
201 else if (token == "YAW") { *AC_cfg >> Yaw; cout << " Yaw = " << Yaw << endl;}
202 else if (token == "FEED") {
204 Engines[numEngines]->AddFeedTank(Feed);
205 cout << " Feed tank: " << Feed << endl;
206 } else cerr << "Unknown identifier: " << token << " in engine file: "
207 << engineFileName << endl;
210 Engines[numEngines]->SetPlacement(xLoc, yLoc, zLoc, Pitch, Yaw);
215 cerr << "Could not read engine config file: " << fullpath
216 + engineFileName + ".xml" << endl;
220 } else if (token == "AC_TANK") { // ============== READING TANKS
222 cout << "\n Reading tank definition" << endl;
223 Tanks.push_back(new FGTank(AC_cfg));
224 switch(Tanks[numTanks]->GetType()) {
226 numSelectedFuelTanks++;
229 case FGTank::ttOXIDIZER:
230 numSelectedOxiTanks++;
237 } else if (token == "AC_THRUSTER") { // ========== READING THRUSTERS
239 thrusterFileName = AC_cfg->GetValue("FILE");
241 cout << "\n Reading thruster from file: " <<
242 fullpath + thrusterFileName + ".xml" << endl;
243 FGConfigFile Thruster_cfg(fullpath + thrusterFileName + ".xml");
245 if (Thruster_cfg.IsOpen()) {
246 Thruster_cfg.GetNextConfigLine();
247 thrType = Thruster_cfg.GetValue();
249 if (thrType == "FG_PROPELLER") {
250 Thrusters.push_back(new FGPropeller(FDMExec, &Thruster_cfg));
251 } else if (thrType == "FG_NOZZLE") {
252 Thrusters.push_back(new FGNozzle(FDMExec, &Thruster_cfg));
255 AC_cfg->GetNextConfigLine();
256 while ((token = AC_cfg->GetValue()) != "/AC_THRUSTER") {
258 if (token == "XLOC") *AC_cfg >> xLoc;
259 else if (token == "YLOC") *AC_cfg >> yLoc;
260 else if (token == "ZLOC") *AC_cfg >> zLoc;
261 else if (token == "PITCH") *AC_cfg >> Pitch;
262 else if (token == "YAW") *AC_cfg >> Yaw;
263 else cerr << "Unknown identifier: " << token << " in engine file: "
264 << engineFileName << endl;
267 Thrusters[numThrusters]->SetLocation(xLoc, yLoc, zLoc);
268 Thrusters[numThrusters]->SetAnglesToBody(0, Pitch, Yaw);
269 Thrusters[numThrusters]->SetdeltaT(dt*rate);
274 cerr << "Could not read thruster config file: " << fullpath
275 + thrusterFileName + ".xml" << endl;
280 AC_cfg->GetNextConfigLine();
286 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
288 string FGPropulsion::GetPropulsionStrings(void)
290 string PropulsionStrings = "";
291 bool firstime = true;
293 for (unsigned int i=0;i<Engines.size();i++) {
295 PropulsionStrings += ", ";
299 switch(Engines[i]->GetType()) {
300 case FGEngine::etPiston:
301 PropulsionStrings += (Engines[i]->GetName() + "_PwrAvail");
303 case FGEngine::etRocket:
304 PropulsionStrings += (Engines[i]->GetName() + "_ChamberPress");
306 case FGEngine::etTurboJet:
307 case FGEngine::etTurboProp:
308 case FGEngine::etTurboShaft:
311 PropulsionStrings += "INVALID ENGINE TYPE";
315 PropulsionStrings += ", ";
317 switch(Thrusters[i]->GetType()) {
318 case FGThruster::ttNozzle:
319 PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust");
321 case FGThruster::ttRotor:
323 case FGThruster::ttPropeller:
324 PropulsionStrings += (Thrusters[i]->GetName() + "_Torque, ");
325 PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust, ");
326 PropulsionStrings += (Thrusters[i]->GetName() + "_RPM");
329 PropulsionStrings += "INVALID THRUSTER TYPE";
334 return PropulsionStrings;
337 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
339 string FGPropulsion::GetPropulsionValues(void)
342 string PropulsionValues = "";
343 bool firstime = true;
345 for (unsigned int i=0;i<Engines.size();i++) {
347 PropulsionValues += ", ";
351 switch(Engines[i]->GetType()) {
352 case FGEngine::etPiston:
353 PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetPowerAvailable(), 10, buff)));
355 case FGEngine::etRocket:
356 PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetChamberPressure(), 10, buff)));
358 case FGEngine::etTurboJet:
359 case FGEngine::etTurboProp:
360 case FGEngine::etTurboShaft:
364 PropulsionValues += ", ";
366 switch(Thrusters[i]->GetType()) {
367 case FGThruster::ttNozzle:
368 PropulsionValues += (string(gcvt(((FGNozzle*)Thrusters[i])->GetThrust(), 10, buff)));
370 case FGThruster::ttRotor:
372 case FGThruster::ttPropeller:
373 PropulsionValues += (string(gcvt(((FGPropeller*)Thrusters[i])->GetTorque(), 10, buff)) + ", ");
374 PropulsionValues += (string(gcvt(((FGPropeller*)Thrusters[i])->GetThrust(), 10, buff)) + ", ");
375 PropulsionValues += (string(gcvt(((FGPropeller*)Thrusters[i])->GetRPM(), 10, buff)));
380 return PropulsionValues;
383 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
385 void FGPropulsion::Debug(void)
387 //TODO: Add your source code here