Purpose: Encapsulates the set of engines and tanks associated
with this aircraft
- ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
+ ------------- Copyright (C) 2000 Jon S. Berndt (jon@jsbsim.org) -------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGPropulsion.h"
-#include <models/propulsion/FGRocket.h>
-#include <models/propulsion/FGTurbine.h>
-#include <models/propulsion/FGPiston.h>
-#include <models/propulsion/FGElectric.h>
-#include <models/propulsion/FGTurboProp.h>
-#include <input_output/FGPropertyManager.h>
-#include <input_output/FGXMLParse.h>
-#include <math/FGColumnVector3.h>
+#include "models/FGFCS.h"
+#include "models/FGMassBalance.h"
+#include "models/propulsion/FGThruster.h"
+#include "models/propulsion/FGRocket.h"
+#include "models/propulsion/FGTurbine.h"
+#include "models/propulsion/FGPiston.h"
+#include "models/propulsion/FGElectric.h"
+#include "models/propulsion/FGTurboProp.h"
+#include "models/propulsion/FGTank.h"
+#include "input_output/FGPropertyManager.h"
+#include "input_output/FGXMLParse.h"
+#include "math/FGColumnVector3.h"
+#include <iostream>
#include <sstream>
+#include <cstdlib>
+
+using namespace std;
namespace JSBSim {
-static const char *IdSrc = "$Id$";
+static const char *IdSrc = "$Id: FGPropulsion.cpp,v 1.45 2011/02/13 00:42:45 jberndt Exp $";
static const char *IdHdr = ID_PROPULSION;
extern short debug_lvl;
-using std::ifstream;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
{
Name = "FGPropulsion";
+ InitializedEngines = 0;
numSelectedFuelTanks = numSelectedOxiTanks = 0;
numTanks = numEngines = 0;
numOxiTanks = numFuelTanks = 0;
ActiveEngine = -1; // -1: ALL, 0: Engine 1, 1: Engine 2 ...
tankJ.InitMatrix();
- refuel = false;
+ refuel = dump = false;
+ DumpRate = 0.0;
fuel_freeze = false;
TotalFuelQuantity = 0.0;
IsBound =
HaveRocketEngine =
HaveTurboPropEngine =
HaveElectricEngine = false;
+ HasInitializedEngines = false;
Debug(0);
}
{
for (unsigned int i=0; i<Engines.size(); i++) delete Engines[i];
Engines.clear();
- unbind();
+ for (unsigned int i=0; i<Tanks.size(); i++) delete Tanks[i];
+ Tanks.clear();
Debug(1);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+bool FGPropulsion::InitModel(void)
+{
+ bool result = true;
+
+ if (!FGModel::InitModel()) return false;
+
+ for (unsigned int i=0; i<numTanks; i++) Tanks[i]->ResetToIC();
+
+ for (unsigned int i=0; i<numEngines; i++) {
+ switch (Engines[i]->GetType()) {
+ case FGEngine::etPiston:
+ ((FGPiston*)Engines[i])->ResetToIC();
+ try {
+ if (HasInitializedEngines && (InitializedEngines & i)) InitRunning(i);
+ } catch (string str) {
+ cerr << str << endl;
+ result = false;
+ }
+ break;
+ case FGEngine::etTurbine:
+ ((FGTurbine*)Engines[i])->ResetToIC();
+ try {
+ if (HasInitializedEngines && (InitializedEngines & i)) InitRunning(i);
+ } catch (string str) {
+ cerr << str << endl;
+ result = false;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ return result;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
bool FGPropulsion::Run(void)
{
unsigned int i;
if (FGModel::Run()) return true;
if (FDMExec->Holding()) return false;
- double dt = State->Getdt();
+ RunPreFunctions();
+
+ double dt = FDMExec->GetDeltaT();
vForces.InitMatrix();
vMoments.InitMatrix();
}
if (refuel) DoRefuel( dt * rate );
+ if (dump) DumpFuel( dt * rate );
+
+ RunPostFunctions();
return false;
}
bool FGPropulsion::GetSteadyState(void)
{
- double currentThrust = 0, lastThrust=-1;
- int steady_count,j=0;
- bool steady=false;
+ double currentThrust = 0, lastThrust = -1;
+ int steady_count = 0, j = 0;
+ bool steady = false;
+ bool TrimMode = FDMExec->GetTrimStatus();
vForces.InitMatrix();
vMoments.InitMatrix();
if (!FGModel::Run()) {
+ FDMExec->SetTrimStatus(true);
+
for (unsigned int i=0; i<numEngines; i++) {
- Engines[i]->SetTrimMode(true);
+// cout << " Finding steady state for engine " << i << endl;
steady=false;
steady_count=0;
+ j=0;
while (!steady && j < 6000) {
Engines[i]->Calculate();
lastThrust = currentThrust;
- currentThrust = Engines[i]->GetThrust();
+ currentThrust = Engines[i]->GetThruster()->GetThrust();
if (fabs(lastThrust-currentThrust) < 0.0001) {
steady_count++;
- if (steady_count > 120) { steady=true; }
+ if (steady_count > 120) {
+ steady=true;
+// cout << " Steady state found at thrust: " << currentThrust << " lbs." << endl;
+ }
} else {
steady_count=0;
}
j++;
}
+// if (j >= 6000) {
+// cout << " Could not find a steady state for this engine." << endl;
+// }
vForces += Engines[i]->GetBodyForces(); // sum body frame forces
vMoments += Engines[i]->GetMoments(); // sum body frame moments
- Engines[i]->SetTrimMode(false);
}
+ FDMExec->SetTrimStatus(TrimMode);
+
return false;
} else {
return true;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-bool FGPropulsion::ICEngineStart(void)
+void FGPropulsion::InitRunning(int n)
{
- int j;
+ if (n >= 0) { // A specific engine is supposed to be initialized
- vForces.InitMatrix();
- vMoments.InitMatrix();
+ if (n >= (int)GetNumEngines() ) {
+ throw(string("Tried to initialize a non-existent engine!"));
+ }
+ FDMExec->GetFCS()->SetThrottleCmd(n,1);
+ FDMExec->GetFCS()->SetMixtureCmd(n,1);
+ GetEngine(n)->InitRunning();
+ GetSteadyState();
- for (unsigned int i=0; i<numEngines; i++) {
- Engines[i]->SetTrimMode(true);
- j=0;
- while (!Engines[i]->GetRunning() && j < 2000) {
- Engines[i]->Calculate();
- j++;
+ InitializedEngines = 1 << n;
+ HasInitializedEngines = true;
+
+ } else if (n < 0) { // -1 refers to "All Engines"
+
+ for (unsigned int i=0; i<GetNumEngines(); i++) {
+ FDMExec->GetFCS()->SetThrottleCmd(i,1);
+ FDMExec->GetFCS()->SetMixtureCmd(i,1);
+ GetEngine(i)->InitRunning();
}
- vForces += Engines[i]->GetBodyForces(); // sum body frame forces
- vMoments += Engines[i]->GetMoments(); // sum body frame moments
- Engines[i]->SetTrimMode(false);
+ GetSteadyState();
+ InitializedEngines = -1;
+ HasInitializedEngines = true;
+
}
- return true;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Debug(2);
+ FGModel::Load(el); // Perform base class Load.
+
+ // Process tank definitions first to establish the number of fuel tanks
+
+ Element* tank_element = el->FindElement("tank");
+ while (tank_element) {
+ Tanks.push_back(new FGTank(FDMExec, tank_element, numTanks));
+ if (Tanks.back()->GetType() == FGTank::ttFUEL) numFuelTanks++;
+ else if (Tanks.back()->GetType() == FGTank::ttOXIDIZER) numOxiTanks++;
+ else {cerr << "Unknown tank type specified." << endl; return false;}
+ numTanks++;
+ tank_element = el->FindNextElement("tank");
+ }
+ numSelectedFuelTanks = numFuelTanks;
+ numSelectedOxiTanks = numOxiTanks;
+
Element* engine_element = el->FindElement("engine");
while (engine_element) {
engine_filename = engine_element->GetAttributeValue("file");
document->SetParent(engine_element);
type = document->GetName();
- if (type == "piston_engine") {
- HavePistonEngine = true;
- if (!IsBound) bind();
- Engines.push_back(new FGPiston(FDMExec, document, numEngines));
- } else if (type == "turbine_engine") {
- HaveTurbineEngine = true;
- if (!IsBound) bind();
- Engines.push_back(new FGTurbine(FDMExec, document, numEngines));
- } else if (type == "turboprop_engine") {
- HaveTurboPropEngine = true;
- if (!IsBound) bind();
- Engines.push_back(new FGTurboProp(FDMExec, document, numEngines));
- } else if (type == "rocket_engine") {
- HaveRocketEngine = true;
- if (!IsBound) bind();
- Engines.push_back(new FGRocket(FDMExec, document, numEngines));
- } else if (type == "electric_engine") {
- HaveElectricEngine = true;
- if (!IsBound) bind();
- Engines.push_back(new FGElectric(FDMExec, document, numEngines));
- } else {
- cerr << "Unknown engine type: " << type << endl;
- exit(-5);
+ try {
+ if (type == "piston_engine") {
+ HavePistonEngine = true;
+ if (!IsBound) bind();
+ Engines.push_back(new FGPiston(FDMExec, document, numEngines));
+ } else if (type == "turbine_engine") {
+ HaveTurbineEngine = true;
+ if (!IsBound) bind();
+ Engines.push_back(new FGTurbine(FDMExec, document, numEngines));
+ } else if (type == "turboprop_engine") {
+ HaveTurboPropEngine = true;
+ if (!IsBound) bind();
+ Engines.push_back(new FGTurboProp(FDMExec, document, numEngines));
+ } else if (type == "rocket_engine") {
+ HaveRocketEngine = true;
+ if (!IsBound) bind();
+ Engines.push_back(new FGRocket(FDMExec, document, numEngines));
+ } else if (type == "electric_engine") {
+ HaveElectricEngine = true;
+ if (!IsBound) bind();
+ Engines.push_back(new FGElectric(FDMExec, document, numEngines));
+ } else {
+ cerr << "Unknown engine type: " << type << endl;
+ exit(-5);
+ }
+ } catch (std::string str) {
+ cerr << endl << fgred << str << reset << endl;
+ return false;
}
- FCS->AddThrottle();
+ FDMExec->GetFCS()->AddThrottle();
ThrottleAdded = true;
numEngines++;
ResetParser();
}
- // Process tank definitions
+ CalculateTankInertias();
+ if (!ThrottleAdded) FDMExec->GetFCS()->AddThrottle(); // need to have at least one throttle
- Element* tank_element = el->FindElement("tank");
- while (tank_element) {
- Tanks.push_back(new FGTank(FDMExec, tank_element));
- if (Tanks.back()->GetType() == FGTank::ttFUEL) numFuelTanks++;
- else if (Tanks.back()->GetType() == FGTank::ttOXIDIZER) numOxiTanks++;
- else {cerr << "Unknown tank type specified." << endl; return false;}
- numTanks++;
- tank_element = el->FindNextElement("tank");
- }
- numSelectedFuelTanks = numFuelTanks;
- numSelectedOxiTanks = numOxiTanks;
+ // Process fuel dump rate
+ if (el->FindElement("dump-rate"))
+ DumpRate = el->FindElementValueAsNumberConvertTo("dump-rate", "LBS/MIN");
- CalculateTankInertias();
- if (!ThrottleAdded) FCS->AddThrottle(); // need to have at least one throttle
+ PostLoad(el, PropertyManager);
return true;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-string FGPropulsion::FindEngineFullPathname(string engine_filename)
+string FGPropulsion::FindEngineFullPathname(const string& engine_filename)
{
string fullpath, localpath;
string enginePath = FDMExec->GetEnginePath();
string aircraftPath = FDMExec->GetFullAircraftPath();
- ifstream* engine_file = new ifstream();
+ ifstream engine_file;
string separator = "/";
-# ifdef macintosh
- separator = ";";
-# endif
fullpath = enginePath + separator;
localpath = aircraftPath + separator + "Engines" + separator;
- engine_file->open(string(fullpath + engine_filename + ".xml").c_str());
- if ( !engine_file->is_open()) {
- engine_file->open(string(localpath + engine_filename + ".xml").c_str());
- if ( !engine_file->is_open()) {
+ engine_file.open(string(fullpath + engine_filename + ".xml").c_str());
+ if ( !engine_file.is_open()) {
+ engine_file.open(string(localpath + engine_filename + ".xml").c_str());
+ if ( !engine_file.is_open()) {
cerr << " Could not open engine file: " << engine_filename << " in path "
<< fullpath << " or " << localpath << endl;
return string("");
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-ifstream* FGPropulsion::FindEngineFile(string engine_filename)
+ifstream* FGPropulsion::FindEngineFile(const string& engine_filename)
{
string fullpath, localpath;
string enginePath = FDMExec->GetEnginePath();
ifstream* engine_file = new ifstream();
string separator = "/";
-# ifdef macintosh
- separator = ";";
-# endif
fullpath = enginePath + separator;
localpath = aircraftPath + separator + "Engines" + separator;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-string FGPropulsion::GetPropulsionStrings(string delimeter)
+string FGPropulsion::GetPropulsionStrings(const string& delimiter) const
{
unsigned int i;
for (i=0; i<Engines.size(); i++) {
if (firstime) firstime = false;
- else PropulsionStrings += delimeter;
+ else PropulsionStrings += delimiter;
- PropulsionStrings += Engines[i]->GetEngineLabels(delimeter);
+ PropulsionStrings += Engines[i]->GetEngineLabels(delimiter);
}
for (i=0; i<Tanks.size(); i++) {
- if (Tanks[i]->GetType() == FGTank::ttFUEL) buf << delimeter << "Fuel Tank " << i;
- else if (Tanks[i]->GetType() == FGTank::ttOXIDIZER) buf << delimeter << "Oxidizer Tank " << i;
+ if (Tanks[i]->GetType() == FGTank::ttFUEL) buf << delimiter << "Fuel Tank " << i;
+ else if (Tanks[i]->GetType() == FGTank::ttOXIDIZER) buf << delimiter << "Oxidizer Tank " << i;
}
return PropulsionStrings;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-string FGPropulsion::GetPropulsionValues(string delimeter)
+string FGPropulsion::GetPropulsionValues(const string& delimiter) const
{
unsigned int i;
for (i=0; i<Engines.size(); i++) {
if (firstime) firstime = false;
- else PropulsionValues += delimeter;
+ else PropulsionValues += delimiter;
- PropulsionValues += Engines[i]->GetEngineValues(delimeter);
+ PropulsionValues += Engines[i]->GetEngineValues(delimiter);
}
for (i=0; i<Tanks.size(); i++) {
- buf << delimeter;
+ buf << delimiter;
buf << Tanks[i]->GetContents();
}
FGColumnVector3& FGPropulsion::GetTanksMoment(void)
{
- iTank = Tanks.begin();
vXYZtank_arm.InitMatrix();
- while (iTank < Tanks.end()) {
- vXYZtank_arm(eX) += (*iTank)->GetXYZ(eX)*(*iTank)->GetContents();
- vXYZtank_arm(eY) += (*iTank)->GetXYZ(eY)*(*iTank)->GetContents();
- vXYZtank_arm(eZ) += (*iTank)->GetXYZ(eZ)*(*iTank)->GetContents();
- iTank++;
+ for (unsigned int i=0; i<Tanks.size(); i++) {
+ vXYZtank_arm(eX) += Tanks[i]->GetXYZ(eX) * Tanks[i]->GetContents();
+ vXYZtank_arm(eY) += Tanks[i]->GetXYZ(eY) * Tanks[i]->GetContents();
+ vXYZtank_arm(eZ) += Tanks[i]->GetXYZ(eZ) * Tanks[i]->GetContents();
}
return vXYZtank_arm;
}
{
double Tw = 0.0;
- iTank = Tanks.begin();
- while (iTank < Tanks.end()) {
- Tw += (*iTank)->GetContents();
- iTank++;
- }
+ for (unsigned int i=0; i<Tanks.size(); i++) Tw += Tanks[i]->GetContents();
+
return Tw;
}
tankJ = FGMatrix33();
- for (unsigned int i=0; i<size; i++)
- tankJ += MassBalance->GetPointmassInertia( lbtoslug * Tanks[i]->GetContents(),
+ for (unsigned int i=0; i<size; i++) {
+ tankJ += FDMExec->GetMassBalance()->GetPointmassInertia( lbtoslug * Tanks[i]->GetContents(),
Tanks[i]->GetXYZ() );
+ tankJ(1,1) += Tanks[i]->GetIxx();
+ tankJ(2,2) += Tanks[i]->GetIyy();
+ tankJ(3,3) += Tanks[i]->GetIzz();
+ }
return tankJ;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+void FGPropulsion::DumpFuel(double time_slice)
+{
+ unsigned int i;
+ int TanksDumping = 0;
+
+ for (i=0; i<numTanks; i++) {
+ if (Tanks[i]->GetContents() > Tanks[i]->GetStandpipe()) ++TanksDumping;
+ }
+
+ if (TanksDumping == 0) return;
+
+ double dump_rate_per_tank = DumpRate / 60.0 * time_slice / TanksDumping;
+
+ for (i=0; i<numTanks; i++) {
+ if (Tanks[i]->GetContents() > Tanks[i]->GetStandpipe()) {
+ Transfer(i, -1, dump_rate_per_tank);
+ }
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
void FGPropulsion::SetFuelFreeze(bool f)
{
fuel_freeze = f;
typedef int (FGPropulsion::*iPMF)(void) const;
IsBound = true;
-
+ PropertyManager->Tie("propulsion/set-running", this, (iPMF)0, &FGPropulsion::InitRunning, false);
if (HaveTurbineEngine) {
- PropertyManager->Tie("propulsion/starter_cmd", this, (iPMF)0, &FGPropulsion::SetStarter, true);
- PropertyManager->Tie("propulsion/cutoff_cmd", this, (iPMF)0, &FGPropulsion::SetCutoff, true);
+ PropertyManager->Tie("propulsion/starter_cmd", this, (iPMF)0, &FGPropulsion::SetStarter, false);
+ PropertyManager->Tie("propulsion/cutoff_cmd", this, (iPMF)0, &FGPropulsion::SetCutoff, false);
}
if (HavePistonEngine) {
- PropertyManager->Tie("propulsion/starter_cmd", this, (iPMF)0, &FGPropulsion::SetStarter, true);
- PropertyManager->Tie("propulsion/magneto_cmd", this, (iPMF)0, &FGPropulsion::SetMagnetos, true);
+ PropertyManager->Tie("propulsion/starter_cmd", this, (iPMF)0, &FGPropulsion::SetStarter, false);
+ PropertyManager->Tie("propulsion/magneto_cmd", this, (iPMF)0, &FGPropulsion::SetMagnetos, false);
}
PropertyManager->Tie("propulsion/active_engine", this, (iPMF)&FGPropulsion::GetActiveEngine,
&FGPropulsion::SetActiveEngine, true);
PropertyManager->Tie("propulsion/total-fuel-lbs", this, &FGPropulsion::GetTotalFuelQuantity);
-}
+ PropertyManager->Tie("propulsion/refuel", this, &FGPropulsion::GetRefuel,
+ &FGPropulsion::SetRefuel, true);
+ PropertyManager->Tie("propulsion/fuel_dump", this, &FGPropulsion::GetFuelDump,
+ &FGPropulsion::SetFuelDump, true);
+ PropertyManager->Tie("forces/fbx-prop-lbs", this,1,
+ (PMF)&FGPropulsion::GetForces);
+ PropertyManager->Tie("forces/fby-prop-lbs", this,2,
+ (PMF)&FGPropulsion::GetForces);
+ PropertyManager->Tie("forces/fbz-prop-lbs", this,3,
+ (PMF)&FGPropulsion::GetForces);
+ PropertyManager->Tie("moments/l-prop-lbsft", this,1,
+ (PMF)&FGPropulsion::GetMoments);
+ PropertyManager->Tie("moments/m-prop-lbsft", this,2,
+ (PMF)&FGPropulsion::GetMoments);
+ PropertyManager->Tie("moments/n-prop-lbsft", this,3,
+ (PMF)&FGPropulsion::GetMoments);
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropulsion::unbind(void)
-{
- if (!IsBound) return;
-
- if (HaveTurbineEngine) {
- PropertyManager->Untie("propulsion/starter_cmd");
- PropertyManager->Untie("propulsion/cutoff_cmd");
- }
- if (HavePistonEngine) {
- PropertyManager->Untie("propulsion/starter_cmd");
- PropertyManager->Untie("propulsion/magneto_cmd");
- }
- PropertyManager->Untie("propulsion/active_engine");
- PropertyManager->Untie("propulsion/total-fuel-lbs");
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%