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"
56 #include "FGPropertyManager.h"
58 #if defined (__APPLE__)
59 /* Not all systems have the gcvt function */
60 inline char* gcvt (double value, int ndigits, char *buf) {
61 /* note that this is not exactly what gcvt is supposed to do! */
62 snprintf (buf, ndigits+1, "%f", value);
69 static const char *IdSrc = "$Id$";
70 static const char *IdHdr = ID_PROPULSION;
72 extern short debug_lvl;
75 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
79 FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)
81 Name = "FGPropulsion";
83 numSelectedFuelTanks = numSelectedOxiTanks = 0;
84 numTanks = numEngines = numThrusters = 0;
85 numOxiTanks = numFuelTanks = 0;
87 ActiveEngine = -1; // -1: ALL, 0: Engine 1, 1: Engine 2 ...
94 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
96 FGPropulsion::~FGPropulsion()
98 for (unsigned int i=0; i<Engines.size(); i++) delete Engines[i];
104 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106 bool FGPropulsion::Run(void)
108 double PowerAvailable;
111 vForces.InitMatrix();
112 vMoments.InitMatrix();
114 if (!FGModel::Run()) {
115 for (unsigned int i=0; i<numEngines; i++) {
116 Thrusters[i]->SetdeltaT(dt*rate);
117 PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());
118 Thrusters[i]->Calculate(PowerAvailable);
119 vForces += Thrusters[i]->GetBodyForces(); // sum body frame forces
120 vMoments += Thrusters[i]->GetMoments(); // sum body frame moments
128 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
130 bool FGPropulsion::GetSteadyState(void)
132 double PowerAvailable;
133 double currentThrust = 0, lastThrust=-1;
135 int steady_count,j=0;
138 vForces.InitMatrix();
139 vMoments.InitMatrix();
141 if (!FGModel::Run()) {
142 for (unsigned int i=0; i<numEngines; i++) {
143 Engines[i]->SetTrimMode(true);
144 Thrusters[i]->SetdeltaT(dt*rate);
147 while (!steady && j < 6000) {
148 PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());
149 lastThrust = currentThrust;
150 currentThrust = Thrusters[i]->Calculate(PowerAvailable);
151 if (fabs(lastThrust-currentThrust) < 0.0001) {
153 if (steady_count > 120) { steady=true; }
159 vForces += Thrusters[i]->GetBodyForces(); // sum body frame forces
160 vMoments += Thrusters[i]->GetMoments(); // sum body frame moments
161 Engines[i]->SetTrimMode(false);
170 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
172 bool FGPropulsion::ICEngineStart(void)
174 double PowerAvailable;
178 vForces.InitMatrix();
179 vMoments.InitMatrix();
181 for (unsigned int i=0; i<numEngines; i++) {
182 Engines[i]->SetTrimMode(true);
183 Thrusters[i]->SetdeltaT(dt*rate);
185 while (!Engines[i]->GetRunning() && j < 2000) {
186 PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());
187 Thrusters[i]->Calculate(PowerAvailable);
190 vForces += Thrusters[i]->GetBodyForces(); // sum body frame forces
191 vMoments += Thrusters[i]->GetMoments(); // sum body frame moments
192 Engines[i]->SetTrimMode(false);
197 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
199 bool FGPropulsion::Load(FGConfigFile* AC_cfg)
201 string token, fullpath;
202 string engineFileName, engType;
203 string thrusterFileName, thrType;
205 string enginePath = FDMExec->GetEnginePath();
206 double xLoc, yLoc, zLoc, Pitch, Yaw;
207 double P_Factor = 0, Sense = 0.0;
209 bool ThrottleAdded = false;
212 fullpath = enginePath + "/";
214 fullpath = enginePath + ";";
217 AC_cfg->GetNextConfigLine();
219 while ((token = AC_cfg->GetValue()) != string("/PROPULSION")) {
221 if (token == "AC_ENGINE") { // ============ READING ENGINES
223 engineFileName = AC_cfg->GetValue("FILE");
225 if (debug_lvl > 0) cout << "\n Reading engine from file: " << fullpath
226 + engineFileName + ".xml"<< endl;
227 FGConfigFile Eng_cfg(fullpath + engineFileName + ".xml");
229 if (Eng_cfg.IsOpen()) {
230 Eng_cfg.GetNextConfigLine();
231 engType = Eng_cfg.GetValue();
234 ThrottleAdded = true;
236 if (engType == "FG_ROCKET") {
237 Engines.push_back(new FGRocket(FDMExec, &Eng_cfg));
238 } else if (engType == "FG_PISTON") {
239 Engines.push_back(new FGPiston(FDMExec, &Eng_cfg));
240 } else if (engType == "FG_TURBINE") {
241 Engines.push_back(new FGTurbine(FDMExec, &Eng_cfg));
242 } else if (engType == "FG_SIMTURBINE") {
243 Engines.push_back(new FGSimTurbine(FDMExec, &Eng_cfg));
245 cerr << fgred << " Unrecognized engine type: " << underon << engType
246 << underoff << " found in config file." << fgdef << endl;
250 AC_cfg->GetNextConfigLine();
251 while ((token = AC_cfg->GetValue()) != string("/AC_ENGINE")) {
253 if (token == "XLOC") { *AC_cfg >> xLoc; }
254 else if (token == "YLOC") { *AC_cfg >> yLoc; }
255 else if (token == "ZLOC") { *AC_cfg >> zLoc; }
256 else if (token == "PITCH") { *AC_cfg >> Pitch;}
257 else if (token == "YAW") { *AC_cfg >> Yaw;}
258 else if (token == "FEED") {
260 Engines[numEngines]->AddFeedTank(Feed);
261 if (debug_lvl > 0) cout << " Feed tank: " << Feed << endl;
262 } else cerr << "Unknown identifier: " << token << " in engine file: "
263 << engineFileName << endl;
267 cout << " X = " << xLoc << endl;
268 cout << " Y = " << yLoc << endl;
269 cout << " Z = " << zLoc << endl;
270 cout << " Pitch = " << Pitch << endl;
271 cout << " Yaw = " << Yaw << endl;
274 Engines[numEngines]->SetPlacement(xLoc, yLoc, zLoc, Pitch, Yaw);
275 Engines[numEngines]->SetEngineNumber(numEngines);
280 cerr << fgred << "\n Could not read engine config file: " << underon <<
281 fullpath + engineFileName + ".xml" << underoff << fgdef << endl;
285 } else if (token == "AC_TANK") { // ============== READING TANKS
287 if (debug_lvl > 0) cout << "\n Reading tank definition" << endl;
288 Tanks.push_back(new FGTank(AC_cfg));
289 switch(Tanks[numTanks]->GetType()) {
291 numSelectedFuelTanks++;
294 case FGTank::ttOXIDIZER:
295 numSelectedOxiTanks++;
302 } else if (token == "AC_THRUSTER") { // ========== READING THRUSTERS
304 thrusterFileName = AC_cfg->GetValue("FILE");
306 if (debug_lvl > 0) cout << "\n Reading thruster from file: " <<
307 fullpath + thrusterFileName + ".xml" << endl;
308 FGConfigFile Thruster_cfg(fullpath + thrusterFileName + ".xml");
310 if (Thruster_cfg.IsOpen()) {
311 Thruster_cfg.GetNextConfigLine();
312 thrType = Thruster_cfg.GetValue();
314 if (thrType == "FG_PROPELLER") {
315 Thrusters.push_back(new FGPropeller(FDMExec, &Thruster_cfg));
316 } else if (thrType == "FG_NOZZLE") {
317 Thrusters.push_back(new FGNozzle(FDMExec, &Thruster_cfg ));
318 } else if (thrType == "FG_DIRECT") {
319 Thrusters.push_back(new FGThruster( FDMExec, &Thruster_cfg) );
322 AC_cfg->GetNextConfigLine();
323 while ((token = AC_cfg->GetValue()) != string("/AC_THRUSTER")) {
325 if (token == "XLOC") *AC_cfg >> xLoc;
326 else if (token == "YLOC") *AC_cfg >> yLoc;
327 else if (token == "ZLOC") *AC_cfg >> zLoc;
328 else if (token == "PITCH") *AC_cfg >> Pitch;
329 else if (token == "YAW") *AC_cfg >> Yaw;
330 else if (token == "P_FACTOR") *AC_cfg >> P_Factor;
331 else if (token == "SENSE") *AC_cfg >> Sense;
332 else cerr << "Unknown identifier: " << token << " in engine file: "
333 << engineFileName << endl;
336 Thrusters[numThrusters]->SetLocation(xLoc, yLoc, zLoc);
337 Thrusters[numThrusters]->SetAnglesToBody(0, Pitch, Yaw);
338 if (thrType == "FG_PROPELLER" && P_Factor > 0.001) {
339 ((FGPropeller*)Thrusters[numThrusters])->SetPFactor(P_Factor);
340 if (debug_lvl > 0) cout << " P-Factor: " << P_Factor << endl;
341 ((FGPropeller*)Thrusters[numThrusters])->SetSense(fabs(Sense)/Sense);
342 if (debug_lvl > 0) cout << " Sense: " << Sense << endl;
344 Thrusters[numThrusters]->SetdeltaT(dt*rate);
345 Thrusters[numThrusters]->SetThrusterNumber(numThrusters);
349 cerr << "Could not read thruster config file: " << fullpath
350 + thrusterFileName + ".xml" << endl;
355 AC_cfg->GetNextConfigLine();
358 if (!ThrottleAdded) FCS->AddThrottle(); // need to have at least one throttle
363 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
365 string FGPropulsion::GetPropulsionStrings(void)
367 string PropulsionStrings = "";
368 bool firstime = true;
371 for (unsigned int i=0;i<Engines.size();i++) {
372 if (firstime) firstime = false;
373 else PropulsionStrings += ", ";
375 sprintf(buffer, "%d", i);
377 switch(Engines[i]->GetType()) {
378 case FGEngine::etPiston:
379 PropulsionStrings += (Engines[i]->GetName() + "_PwrAvail[" + buffer + "]");
381 case FGEngine::etRocket:
382 PropulsionStrings += (Engines[i]->GetName() + "_ChamberPress[" + buffer + "]");
384 case FGEngine::etTurbine:
386 case FGEngine::etSimTurbine:
387 PropulsionStrings += (Engines[i]->GetName() + "_N1[" + buffer + "], ");
388 PropulsionStrings += (Engines[i]->GetName() + "_N2[" + buffer + "]");
391 PropulsionStrings += "INVALID ENGINE TYPE";
395 PropulsionStrings += ", ";
397 FGPropeller* Propeller = (FGPropeller*)Thrusters[i];
398 switch(Thrusters[i]->GetType()) {
399 case FGThruster::ttNozzle:
400 PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "]");
402 case FGThruster::ttRotor:
404 case FGThruster::ttPropeller:
405 PropulsionStrings += (Thrusters[i]->GetName() + "_Torque[" + buffer + "], ");
406 PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Roll[" + buffer + "], ");
407 PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Pitch[" + buffer + "], ");
408 PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Yaw[" + buffer + "], ");
409 PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "], ");
410 if (Propeller->IsVPitch())
411 PropulsionStrings += (Thrusters[i]->GetName() + "_Pitch[" + buffer + "], ");
412 PropulsionStrings += (Thrusters[i]->GetName() + "_RPM[" + buffer + "]");
414 case FGThruster::ttDirect:
415 PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "]");
418 PropulsionStrings += "INVALID THRUSTER TYPE";
423 return PropulsionStrings;
426 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
428 string FGPropulsion::GetPropulsionValues(void)
431 string PropulsionValues = "";
432 bool firstime = true;
434 for (unsigned int i=0;i<Engines.size();i++) {
435 if (firstime) firstime = false;
436 else PropulsionValues += ", ";
438 switch(Engines[i]->GetType()) {
439 case FGEngine::etPiston:
440 PropulsionValues += (string(gcvt(((FGPiston*)Engines[i])->GetPowerAvailable(), 10, buff)));
442 case FGEngine::etRocket:
443 PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetChamberPressure(), 10, buff)));
445 case FGEngine::etTurbine:
447 case FGEngine::etSimTurbine:
448 PropulsionValues += (string(gcvt(((FGSimTurbine*)Engines[i])->GetN1(), 10, buff))) + ", ";
449 PropulsionValues += (string(gcvt(((FGSimTurbine*)Engines[i])->GetN2(), 10, buff)));
453 PropulsionValues += ", ";
455 switch(Thrusters[i]->GetType()) {
456 case FGThruster::ttNozzle:
457 PropulsionValues += (string(gcvt(((FGNozzle*)Thrusters[i])->GetThrust(), 10, buff)));
459 case FGThruster::ttRotor:
461 case FGThruster::ttDirect:
462 PropulsionValues += (string(gcvt(((FGThruster*)Thrusters[i])->GetThrust(), 10, buff)));
464 case FGThruster::ttPropeller:
465 FGPropeller* Propeller = (FGPropeller*)Thrusters[i];
466 FGColumnVector3 vPFactor = Propeller->GetPFactor();
467 PropulsionValues += string(gcvt(Propeller->GetTorque(), 10, buff)) + ", ";
468 PropulsionValues += string(gcvt(vPFactor(eRoll), 10, buff)) + ", ";
469 PropulsionValues += string(gcvt(vPFactor(ePitch), 10, buff)) + ", ";
470 PropulsionValues += string(gcvt(vPFactor(eYaw), 10, buff)) + ", ";
471 PropulsionValues += string(gcvt(Propeller->GetThrust(), 10, buff)) + ", ";
472 if (Propeller->IsVPitch())
473 PropulsionValues += string(gcvt(Propeller->GetPitch(), 10, buff)) + ", ";
474 PropulsionValues += string(gcvt(Propeller->GetRPM(), 10, buff));
479 return PropulsionValues;
482 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484 FGColumnVector3& FGPropulsion::GetTanksMoment(void)
486 iTank = Tanks.begin();
487 vXYZtank.InitMatrix();
488 while (iTank < Tanks.end()) {
489 vXYZtank(eX) += (*iTank)->GetX()*(*iTank)->GetContents();
490 vXYZtank(eY) += (*iTank)->GetY()*(*iTank)->GetContents();
491 vXYZtank(eZ) += (*iTank)->GetZ()*(*iTank)->GetContents();
497 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
499 double FGPropulsion::GetTanksWeight(void)
503 iTank = Tanks.begin();
504 while (iTank < Tanks.end()) {
505 Tw += (*iTank)->GetContents();
511 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
513 double FGPropulsion::GetTanksIxx(const FGColumnVector3& vXYZcg)
516 iTank = Tanks.begin();
517 while (iTank < Tanks.end()) {
518 I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetX() - vXYZcg(eX)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
524 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
526 double FGPropulsion::GetTanksIyy(const FGColumnVector3& vXYZcg)
529 iTank = Tanks.begin();
530 while (iTank < Tanks.end()) {
531 I += ((*iTank)->GetY() - vXYZcg(eY))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
537 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
539 double FGPropulsion::GetTanksIzz(const FGColumnVector3& vXYZcg)
542 iTank = Tanks.begin();
543 while (iTank < Tanks.end()) {
544 I += ((*iTank)->GetZ() - vXYZcg(eZ))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
550 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
552 double FGPropulsion::GetTanksIxz(const FGColumnVector3& vXYZcg)
555 iTank = Tanks.begin();
556 while (iTank < Tanks.end()) {
557 I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
563 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
565 double FGPropulsion::GetTanksIxy(const FGColumnVector3& vXYZcg)
568 iTank = Tanks.begin();
569 while (iTank != Tanks.end()) {
570 I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
576 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
578 void FGPropulsion::SetMagnetos(int setting)
580 if (ActiveEngine < 0) {
581 for (unsigned i=0; i<Engines.size(); i++) {
582 ((FGPiston*)Engines[i])->SetMagnetos(setting);
585 ((FGPiston*)Engines[ActiveEngine])->SetMagnetos(setting);
589 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
591 void FGPropulsion::SetStarter(int setting)
593 if (ActiveEngine < 0) {
594 for (unsigned i=0; i<Engines.size(); i++) {
596 Engines[i]->SetStarter(false);
598 Engines[i]->SetStarter(true);
602 Engines[ActiveEngine]->SetStarter(false);
604 Engines[ActiveEngine]->SetStarter(true);
608 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
610 void FGPropulsion::SetCutoff(int setting)
612 if (ActiveEngine < 0) {
613 for (unsigned i=0; i<Engines.size(); i++) {
615 ((FGSimTurbine*)Engines[i])->SetCutoff(false);
617 ((FGSimTurbine*)Engines[i])->SetCutoff(true);
621 ((FGSimTurbine*)Engines[ActiveEngine])->SetCutoff(false);
623 ((FGSimTurbine*)Engines[ActiveEngine])->SetCutoff(true);
627 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
629 void FGPropulsion::SetActiveEngine(int engine)
631 if (engine >= Engines.size() || engine < 0)
634 ActiveEngine = engine;
637 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
639 void FGPropulsion::bind(void)
641 typedef double (FGPropulsion::*PMF)(int) const;
642 typedef int (FGPropulsion::*iPMF)(void) const;
644 PropertyManager->Tie("propulsion/magneto_cmd", this,
645 (iPMF)0, &FGPropulsion::SetMagnetos, true);
646 PropertyManager->Tie("propulsion/starter_cmd", this,
647 (iPMF)0, &FGPropulsion::SetStarter, true);
648 PropertyManager->Tie("propulsion/cutoff_cmd", this,
649 (iPMF)0, &FGPropulsion::SetCutoff, true);
651 PropertyManager->Tie("forces/fbx-prop-lbs", this,1,
652 (PMF)&FGPropulsion::GetForces);
653 PropertyManager->Tie("forces/fby-prop-lbs", this,2,
654 (PMF)&FGPropulsion::GetForces);
655 PropertyManager->Tie("forces/fbz-prop-lbs", this,3,
656 (PMF)&FGPropulsion::GetForces);
657 PropertyManager->Tie("moments/l-prop-lbsft", this,1,
658 (PMF)&FGPropulsion::GetMoments);
659 PropertyManager->Tie("moments/m-prop-lbsft", this,2,
660 (PMF)&FGPropulsion::GetMoments);
661 PropertyManager->Tie("moments/n-prop-lbsft", this,3,
662 (PMF)&FGPropulsion::GetMoments);
664 PropertyManager->Tie("propulsion/active_engine", this,
665 (iPMF)&FGPropulsion::GetActiveEngine, &FGPropulsion::SetActiveEngine, true);
668 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
670 void FGPropulsion::unbind(void)
672 PropertyManager->Untie("propulsion/magneto_cmd");
673 PropertyManager->Untie("propulsion/starter_cmd");
674 PropertyManager->Untie("propulsion/cutoff_cmd");
675 PropertyManager->Untie("propulsion/active_engine");
676 PropertyManager->Untie("forces/fbx-prop-lbs");
677 PropertyManager->Untie("forces/fby-prop-lbs");
678 PropertyManager->Untie("forces/fbz-prop-lbs");
679 PropertyManager->Untie("moments/l-prop-lbsft");
680 PropertyManager->Untie("moments/m-prop-lbsft");
681 PropertyManager->Untie("moments/n-prop-lbsft");
684 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
685 // The bitmasked value choices are as follows:
686 // unset: In this case (the default) JSBSim would only print
687 // out the normally expected messages, essentially echoing
688 // the config files as they are read. If the environment
689 // variable is not set, debug_lvl is set to 1 internally
690 // 0: This requests JSBSim not to output any messages
692 // 1: This value explicity requests the normal JSBSim
694 // 2: This value asks for a message to be printed out when
695 // a class is instantiated
696 // 4: When this value is set, a message is displayed when a
697 // FGModel object executes its Run() method
698 // 8: When this value is set, various runtime state variables
699 // are printed out periodically
700 // 16: When set various parameters are sanity checked and
701 // a message is printed out when they go out of bounds
703 void FGPropulsion::Debug(int from)
705 if (debug_lvl <= 0) return;
707 if (debug_lvl & 1) { // Standard console startup message output
708 if (from == 0) { // Constructor
712 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
713 if (from == 0) cout << "Instantiated: FGPropulsion" << endl;
714 if (from == 1) cout << "Destroyed: FGPropulsion" << endl;
716 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
718 if (debug_lvl & 8 ) { // Runtime state variables
720 if (debug_lvl & 16) { // Sanity checking
722 if (debug_lvl & 64) {
723 if (from == 0) { // Constructor
724 cout << IdSrc << endl;
725 cout << IdHdr << endl;