src/FDM/ExternalNet/Makefile \
src/FDM/ExternalPipe/Makefile \
src/FDM/JSBSim/Makefile \
- src/FDM/JSBSim/filtersjb/Makefile \
+ src/FDM/JSBSim/initialization/Makefile \
+ src/FDM/JSBSim/input_output/Makefile \
+ src/FDM/JSBSim/math/Makefile \
+ src/FDM/JSBSim/models/Makefile \
+ src/FDM/JSBSim/models/flight_control/Makefile \
+ src/FDM/JSBSim/models/atmosphere/Makefile \
+ src/FDM/JSBSim/models/propulsion/Makefile \
src/FDM/LaRCsim/Makefile \
src/FDM/SP/Makefile \
src/FDM/UIUCModel/Makefile \
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
#ifdef FGFS
# include <simgear/compiler.h>
# include STL_IOSTREAM
#include "FGFDMExec.h"
#include "FGState.h"
-#include "FGAtmosphere.h"
-#include "FGFCS.h"
-#include "FGGroundCallback.h"
-#include "FGPropulsion.h"
-#include "FGMassBalance.h"
-#include "FGGroundReactions.h"
-#include "FGAerodynamics.h"
-#include "FGInertial.h"
-#include "FGAircraft.h"
-#include "FGPropagate.h"
-#include "FGAuxiliary.h"
-#include "FGOutput.h"
-#include "FGConfigFile.h"
-#include "FGInitialCondition.h"
-#include "FGPropertyManager.h"
+#include <models/FGAtmosphere.h>
+#include <models/atmosphere/FGMSIS.h>
+#include <models/atmosphere/FGMars.h>
+#include <models/FGFCS.h>
+#include <models/FGPropulsion.h>
+#include <models/FGMassBalance.h>
+#include <models/FGGroundReactions.h>
+#include <models/FGAerodynamics.h>
+#include <models/FGInertial.h>
+#include <models/FGAircraft.h>
+#include <models/FGPropagate.h>
+#include <models/FGAuxiliary.h>
+#include <models/FGInput.h>
+#include <models/FGOutput.h>
+#include <initialization/FGInitialCondition.h>
+#include <input_output/FGPropertyManager.h>
namespace JSBSim {
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Constructor
-FGFDMExec::FGFDMExec(FGPropertyManager* root)
+FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root)
{
Frame = 0;
FirstModel = 0;
Error = 0;
+ GroundCallback = 0;
State = 0;
Atmosphere = 0;
FCS = 0;
Inertial = 0;
GroundReactions = 0;
Aircraft = 0;
- GroundCallback = 0;
Propagate = 0;
Auxiliary = 0;
- Output = 0;
+ Input = 0;
IC = 0;
Trim = 0;
terminate = false;
- frozen = false;
modelLoaded = false;
IsSlave = false;
+ holding = false;
+
// Multiple FDM's are stopped for now. We need to ensure that
// the "user" instance always gets the zeroeth instance number,
// because there may be instruments or scripts tied to properties
// in the jsbsim[0] node.
+ // ToDo: it could be that when JSBSim is reset and a new FDM is wanted, that
+ // process might try setting FDMctr = 0. Then the line below would not need
+ // to be commented out.
IdFDM = FDMctr;
//FDMctr++;
debug_lvl = 1;
}
- if (root == 0) master= new FGPropertyManager;
- else master = root;
+ if (Root == 0) master= new FGPropertyManager;
+ else master = Root;
instance = master->GetNode("/fdm/jsbsim",IdFDM,true);
-
-
Debug(0);
-
- // this is here to catch errors in binding member functions
- // to the property tree.
+ // this is to catch errors in binding member functions to the property tree.
try {
Allocate();
} catch ( string msg ) {
cout << "Caught error: " << msg << endl;
exit(1);
}
+
+ Constructing = true;
+ typedef int (FGFDMExec::*iPMF)(void) const;
+ instance->Tie("simulation/do_trim", this, (iPMF)0, &FGFDMExec::DoTrim);
+ Constructing = false;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGFDMExec::~FGFDMExec()
{
+ instance->Untie("simulation/do_trim");
+
try {
DeAllocate();
checkTied( instance );
+ if (Root == 0) delete master;
} catch ( string msg ) {
cout << "Caught error: " << msg << endl;
}
Inertial = new FGInertial(this);
GroundReactions = new FGGroundReactions(this);
Aircraft = new FGAircraft(this);
- GroundCallback = new FGGroundCallback();
Propagate = new FGPropagate(this);
Auxiliary = new FGAuxiliary(this);
- Output = new FGOutput(this);
+ Input = new FGInput(this);
- State = new FGState(this); // This must be done here, as the FGState
- // class needs valid pointers to the above
- // model classes
+ GroundCallback = new FGGroundCallback();
+ State = new FGState(this); // This must be done here, as the FGState
+ // class needs valid pointers to the above
+ // model classes
// Initialize models so they can communicate with each other
Error+=128;}
if (!Propagate->InitModel()) {
cerr << fgred << "Propagate model init failed" << fgdef << endl;
- Error+=512;}
+ Error+=256;}
if (!Auxiliary->InitModel()) {
cerr << fgred << "Auxiliary model init failed" << fgdef << endl;
- Error+=2058;}
- if (!Output->InitModel()) {
- cerr << fgred << "Output model init failed" << fgdef << endl;
- Error+=4096;}
+ Error+=512;}
+ if (!Input->InitModel()) {
+ cerr << fgred << "Input model init failed" << fgdef << endl;
+ Error+=1024;}
if (Error > 0) result = false;
IC = new FGInitialCondition(this);
// Schedule a model. The second arg (the integer) is the pass number. For
- // instance, the atmosphere model gets executed every fifth pass it is called
- // by the executive. Everything else here gets executed each pass.
- // IC and Trim objects are NOT scheduled.
+ // instance, the atmosphere model could get executed every fifth pass it is called
+ // by the executive. IC and Trim objects are NOT scheduled.
+ Schedule(Input, 1);
Schedule(Atmosphere, 1);
Schedule(FCS, 1);
Schedule(Propulsion, 1);
Schedule(Aircraft, 1);
Schedule(Propagate, 1);
Schedule(Auxiliary, 1);
- Schedule(Output, 1);
modelLoaded = false;
bool FGFDMExec::DeAllocate(void)
{
+ delete Input;
delete Atmosphere;
delete FCS;
delete Propulsion;
delete Aircraft;
delete Propagate;
delete Auxiliary;
- delete Output;
delete State;
+ for (int i=0; i<Outputs.size(); i++) {
+ if (Outputs[i]) delete Outputs[i];
+ }
+
+ Outputs.clear();
+
delete IC;
delete Trim;
Error = 0;
State = 0;
+ Input = 0;
Atmosphere = 0;
FCS = 0;
Propulsion = 0;
Aircraft = 0;
Propagate = 0;
Auxiliary = 0;
- Output = 0;
modelLoaded = false;
return modelLoaded;
{
FGModel* model_iterator;
- if (frozen) return true;
-
model_iterator = FirstModel;
if (model_iterator == 0L) return false;
}
frame = Frame++;
- State->IncrTime();
+ if (!Holding()) State->IncrTime();
return true;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// This call will cause the sim time to reset to 0.0
bool FGFDMExec::RunIC(void)
{
- State->Suspend();
+ State->SuspendIntegration();
State->Initialize(IC);
Run();
- State->Resume();
+ State->ResumeIntegration();
return true;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-void FGFDMExec::SetGroundCallback(FGGroundCallback* p) {
- if (GroundCallback)
- delete GroundCallback;
+void FGFDMExec::SetGroundCallback(FGGroundCallback* p)
+{
+ if (GroundCallback) delete GroundCallback;
+
GroundCallback = p;
}
bool FGFDMExec::LoadModel(string AircraftPath, string EnginePath, string model,
bool addModelToPath)
{
-
FGFDMExec::AircraftPath = AircraftPath;
FGFDMExec::EnginePath = EnginePath;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
bool FGFDMExec::LoadModel(string model, bool addModelToPath)
{
-
- bool result = true;
string token;
string aircraftCfgFileName;
+ string separator = "/";
+
+# ifdef macintosh
+ separator = ";";
+# endif
if( AircraftPath.empty() || EnginePath.empty() ) {
cerr << "Error: attempted to load aircraft with undefined ";
}
aircraftCfgFileName = AircraftPath;
-# ifndef macintosh
- if (addModelToPath) aircraftCfgFileName += "/" + model;
- aircraftCfgFileName += "/" + model + ".xml";
-# else
- if (addModelToPath) aircraftCfgFileName += ";" + model;
- aircraftCfgFileName += ";" + model + ".xml";
-# endif
+ if (addModelToPath) aircraftCfgFileName += separator + model;
+ aircraftCfgFileName += separator + model + ".xml";
- FGConfigFile AC_cfg(aircraftCfgFileName);
- if (!AC_cfg.IsOpen()) return false;
+ FGXMLParse *XMLParse = new FGXMLParse();
+ Element* element = 0L;
+ Element* document;
+
+ ifstream input_file(aircraftCfgFileName.c_str());
+ readXML(input_file, *XMLParse);
+ document = XMLParse->GetDocument();
modelName = model;
Allocate();
}
- if (!ReadPrologue(&AC_cfg)) return false;
-
- while ((AC_cfg.GetNextConfigLine() != string("EOF")) &&
- (token = AC_cfg.GetValue()) != string("/FDM_CONFIG")) {
- if (token == "METRICS") {
- if (debug_lvl > 0) cout << fgcyan << "\n Reading Metrics" << fgdef << endl;
- if (!ReadMetrics(&AC_cfg)) result = false;
- } else if (token == "SLAVE") {
- if (debug_lvl > 0) cout << fgcyan << "\n Reading Slave flight vehicle: " << fgdef
- << AC_cfg.GetValue("NAME") << endl;
- if (!ReadSlave(&AC_cfg)) result = false;
- } else if (token == "AERODYNAMICS") {
- if (debug_lvl > 0) cout << fgcyan << "\n Reading Aerodynamics" << fgdef << endl;
- if (!ReadAerodynamics(&AC_cfg)) result = false;
- } else if (token == "UNDERCARRIAGE") {
- if (debug_lvl > 0) cout << fgcyan << "\n Reading Landing Gear" << fgdef << endl;
- if (!ReadUndercarriage(&AC_cfg)) result = false;
- } else if (token == "PROPULSION") {
- if (debug_lvl > 0) cout << fgcyan << "\n Reading Propulsion" << fgdef << endl;
- if (!ReadPropulsion(&AC_cfg)) result = false;
- } else if (token == "FLIGHT_CONTROL") {
- if (debug_lvl > 0) cout << fgcyan << "\n Reading Flight Control" << fgdef << endl;
- if (!ReadFlightControls(&AC_cfg)) result = false;
- } else if (token == "AUTOPILOT") {
- if (debug_lvl > 0) cout << fgcyan << "\n Reading Autopilot" << fgdef << endl;
- if (!ReadFlightControls(&AC_cfg)) result = false;
- } else if (token == "OUTPUT") {
- if (debug_lvl > 0) cout << fgcyan << "\n Reading Output directives" << fgdef << endl;
- if (!ReadOutput(&AC_cfg)) result = false;
+ ReadPrologue(document);
+ element = document->GetElement();
+
+ bool result = true;
+ while (element && result) {
+ string element_name = element->GetName();
+ if (element_name == "fileheader" ) result = ReadFileHeader(element);
+ else if (element_name == "slave") result = ReadSlave(element);
+ else if (element_name == "metrics") result = Aircraft->Load(element);
+ else if (element_name == "mass_balance") result = MassBalance->Load(element);
+ else if (element_name == "ground_reactions") result = GroundReactions->Load(element);
+ else if (element_name == "propulsion") result = Propulsion->Load(element);
+ else if (element_name == "autopilot") result = FCS->Load(element);
+ else if (element_name == "flight_control") result = FCS->Load(element);
+ else if (element_name == "aerodynamics") result = Aerodynamics->Load(element);
+ else if (element_name == "input") result = Input->Load(element);
+ else if (element_name == "output") {
+ FGOutput* Output = new FGOutput(this);
+ Output->InitModel();
+ Schedule(Output, 1);
+ Outputs.push_back(Output);
+ result = Output->Load(element);
+ }
+ else {
+ cerr << "Found unexpected subsystem: " << element_name << ", exiting." << endl;
+ result = false;
+ break;
}
+ element = document->GetNextElement();
}
if (result) {
Debug(3);
} else {
cerr << fgred
- << " FGFDMExec: Failed to load aircraft and/or engine model"
+ << " JSBSim failed to load aircraft and/or engine model"
<< fgdef << endl;
+ return false;
+ }
+
+ struct PropertyCatalogStructure masterPCS;
+ masterPCS.base_string = "";
+ masterPCS.node = (FGPropertyManager*)master;
+
+ BuildPropertyCatalog(&masterPCS);
+
+ return result;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFDMExec::BuildPropertyCatalog(struct PropertyCatalogStructure* pcs)
+{
+ struct PropertyCatalogStructure* pcsNew = new struct PropertyCatalogStructure;
+ int node_idx = 0;
+ char int_buf[10];
+
+ for (int i=0; i<pcs->node->nChildren(); i++) {
+ pcsNew->base_string = pcs->base_string + "/" + pcs->node->getChild(i)->getName();
+ node_idx = pcs->node->getChild(i)->getIndex();
+ sprintf(int_buf, "[%d]", node_idx);
+ if (node_idx != 0) pcsNew->base_string += string(int_buf);
+ if (pcs->node->getChild(i)->nChildren() == 0) {
+ PropertyCatalog.push_back(pcsNew->base_string);
+ } else {
+ pcsNew->node = (FGPropertyManager*)pcs->node->getChild(i);
+ BuildPropertyCatalog(pcsNew);
+ }
}
+ delete pcsNew;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGFDMExec::QueryPropertyCatalog(string in)
+{
+ string results="";
+ for (int i=0; i<PropertyCatalog.size(); i++) {
+ if (PropertyCatalog[i].find(in) != string::npos) results += PropertyCatalog[i] + "\n";
+ }
+ if (results.empty()) return "No matches found\n";
+ return results;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGFDMExec::ReadFileHeader(Element* el)
+{
+ bool result = true; // true for success
+
+ if (debug_lvl & ~1) return result;
+
+ if (el->FindElement("author"))
+ cout << " Model Author: " << el->FindElement("author")->GetDataLine() << endl;
+ if (el->FindElement("filecreationdate"))
+ cout << " Creation Date: " << el->FindElement("filecreationdate")->GetDataLine() << endl;
+ if (el->FindElement("version"))
+ cout << " Version: " << el->FindElement("version")->GetDataLine() << endl;
+ if (el->FindElement("description"))
+ cout << " Description: " << el->FindElement("description")->GetDataLine() << endl;
return result;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-bool FGFDMExec::ReadPrologue(FGConfigFile* AC_cfg)
+bool FGFDMExec::ReadPrologue(Element* el) // el for ReadPrologue is the document element
{
- string token = AC_cfg->GetValue();
- string scratch;
- string AircraftName;
+ bool result = true; // true for success
+
+ if (!el) return false;
- AircraftName = AC_cfg->GetValue("NAME");
+ string AircraftName = el->GetAttributeValue("name");
Aircraft->SetAircraftName(AircraftName);
- if (debug_lvl > 0) cout << underon << "Reading Aircraft Configuration File"
+ if (debug_lvl & 1) cout << underon << "Reading Aircraft Configuration File"
<< underoff << ": " << highint << AircraftName << normint << endl;
- scratch = AC_cfg->GetValue("VERSION").c_str();
- CFGVersion = AC_cfg->GetValue("VERSION");
- Release = AC_cfg->GetValue("RELEASE");
+ CFGVersion = el->GetAttributeValue("version");
+ Release = el->GetAttributeValue("release");
- if (debug_lvl > 0)
+ if (debug_lvl & 1)
cout << " Version: " << highint << CFGVersion
<< normint << endl;
if (CFGVersion != needed_cfg_version) {
return false;
}
- if (Release == "ALPHA" && debug_lvl > 0) {
-#ifndef _MSC_VER
- system("banner ALPHA");
-#endif
+ if (Release == "ALPHA" && (debug_lvl & 1)) {
cout << endl << endl
<< highint << "This aircraft model is an " << fgred << Release
<< reset << highint << " release!!!" << endl << endl << reset
<< " will not fly as expected." << endl << endl
<< fgred << highint << "Use this model for development purposes ONLY!!!"
<< normint << reset << endl << endl;
- } else if (Release == "BETA" && debug_lvl > 0) {
-#ifndef _MSC_VER
- system("banner BETA");
-#endif
+ } else if (Release == "BETA" && (debug_lvl & 1)) {
cout << endl << endl
<< highint << "This aircraft model is a " << fgred << Release
<< reset << highint << " release!!!" << endl << endl << reset
<< "This aircraft model probably will not fly as expected." << endl << endl
<< fgblue << highint << "Use this model for development purposes ONLY!!!"
<< normint << reset << endl << endl;
+ } else if (Release == "PRODUCTION" && (debug_lvl & 1)) {
+ cout << endl << endl
+ << highint << "This aircraft model is a " << fgblue << Release
+ << reset << highint << " release." << endl << endl << reset;
+ } else if (debug_lvl & 1) {
+ cout << endl << endl
+ << highint << "This aircraft model is an " << fgred << Release
+ << reset << highint << " release!!!" << endl << endl << reset
+ << "This aircraft model may not even properly load, and probably"
+ << " will not fly as expected." << endl << endl
+ << fgred << highint << "Use this model for development purposes ONLY!!!"
+ << normint << reset << endl << endl;
}
- return true;
+ return result;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-bool FGFDMExec::ReadSlave(FGConfigFile* AC_cfg)
+bool FGFDMExec::ReadSlave(Element* el)
{
// Add a new slaveData object to the slave FDM list
// Populate that slaveData element with a new FDMExec object
SlaveFDMList.push_back(new slaveData);
SlaveFDMList.back()->exec = new FGFDMExec();
SlaveFDMList.back()->exec->SetSlave();
-
- string AircraftName = AC_cfg->GetValue("FILE");
+/*
+ string AircraftName = AC_cfg->GetValue("file");
debug_lvl = 0; // turn off debug output for slave vehicle
AC_cfg->GetNextConfigLine();
while ((token = AC_cfg->GetValue()) != string("/SLAVE")) {
*AC_cfg >> token;
- if (token == "XLOC") { *AC_cfg >> SlaveFDMList.back()->x; }
- else if (token == "YLOC") { *AC_cfg >> SlaveFDMList.back()->y; }
- else if (token == "ZLOC") { *AC_cfg >> SlaveFDMList.back()->z; }
- else if (token == "PITCH") { *AC_cfg >> SlaveFDMList.back()->pitch;}
- else if (token == "YAW") { *AC_cfg >> SlaveFDMList.back()->yaw; }
- else if (token == "ROLL") { *AC_cfg >> SlaveFDMList.back()->roll; }
+ if (token == "xloc") { *AC_cfg >> SlaveFDMList.back()->x; }
+ else if (token == "yloc") { *AC_cfg >> SlaveFDMList.back()->y; }
+ else if (token == "zloc") { *AC_cfg >> SlaveFDMList.back()->z; }
+ else if (token == "pitch") { *AC_cfg >> SlaveFDMList.back()->pitch;}
+ else if (token == "yaw") { *AC_cfg >> SlaveFDMList.back()->yaw; }
+ else if (token == "roll") { *AC_cfg >> SlaveFDMList.back()->roll; }
else cerr << "Unknown identifier: " << token << " in slave vehicle definition" << endl;
}
-
+*/
if (debug_lvl > 0) {
cout << " X = " << SlaveFDMList.back()->x << endl;
cout << " Y = " << SlaveFDMList.back()->y << endl;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-bool FGFDMExec::ReadPropulsion(FGConfigFile* AC_cfg)
+FGPropertyManager* FGFDMExec::GetPropertyManager(void)
{
- if (!Propulsion->Load(AC_cfg)) {
- cerr << " Propulsion not successfully loaded" << endl;
- return false;
- }
- return true;
+ return instance;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-bool FGFDMExec::ReadFlightControls(FGConfigFile* AC_cfg)
+FGTrim* FGFDMExec::GetTrim(void)
{
- if (!FCS->Load(AC_cfg)) {
- cerr << " Flight Controls not successfully loaded" << endl;
- return false;
- }
- return true;
+ delete Trim;
+ Trim = new FGTrim(this,tNone);
+ return Trim;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-bool FGFDMExec::ReadAerodynamics(FGConfigFile* AC_cfg)
+void FGFDMExec::DisableOutput(void)
{
- if (!Aerodynamics->Load(AC_cfg)) {
- cerr << " Aerodynamics not successfully loaded" << endl;
- return false;
+ for (int i=0; i<Outputs.size(); i++) {
+ Outputs[i]->Disable();
}
- return true;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-bool FGFDMExec::ReadUndercarriage(FGConfigFile* AC_cfg)
+void FGFDMExec::EnableOutput(void)
{
- if (!GroundReactions->Load(AC_cfg)) {
- cerr << " Ground Reactions not successfully loaded" << endl;
- return false;
+ for (int i=0; i<Outputs.size(); i++) {
+ Outputs[i]->Enable();
}
- return true;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-bool FGFDMExec::ReadMetrics(FGConfigFile* AC_cfg)
+void FGFDMExec::DoTrim(int mode)
{
- if (!Aircraft->Load(AC_cfg)) {
- cerr << " Aircraft metrics not successfully loaded" << endl;
- return false;
- }
- return true;
-}
+ double saved_time;
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+cout << "DoTrim called" << endl;
-bool FGFDMExec::ReadOutput(FGConfigFile* AC_cfg)
-{
- if (!Output->Load(AC_cfg)) {
- cerr << " Output not successfully loaded" << endl;
- return false;
+ if (Constructing) return;
+
+ if (mode < 0 || mode > JSBSim::tNone) {
+ cerr << endl << "Illegal trimming mode!" << endl << endl;
+ return;
}
- return true;
+ saved_time = State->Getsim_time();
+ FGTrim trim(this, (JSBSim::TrimMode)mode);
+ if ( !trim.DoTrim() ) cerr << endl << "Trim Failed" << endl << endl;
+ trim.Report();
+ State->Setsim_time(saved_time);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FGPropertyManager* FGFDMExec::GetPropertyManager(void) {
- return instance;
+void FGFDMExec::UseAtmosphereMSIS(void)
+{
+ FGAtmosphere *oldAtmosphere = Atmosphere;
+ Atmosphere = new MSIS(this);
+ if (!Atmosphere->InitModel()) {
+ cerr << fgred << "MSIS Atmosphere model init failed" << fgdef << endl;
+ Error+=1;
+ }
+ delete oldAtmosphere;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FGTrim* FGFDMExec::GetTrim(void) {
- delete Trim;
- Trim = new FGTrim(this,tNone);
- return Trim;
+void FGFDMExec::UseAtmosphereMars(void)
+{
+/*
+ FGAtmosphere *oldAtmosphere = Atmosphere;
+ Atmosphere = new FGMars(this);
+ if (!Atmosphere->InitModel()) {
+ cerr << fgred << "Mars Atmosphere model init failed" << fgdef << endl;
+ Error+=1;
+ }
+ delete oldAtmosphere;
+*/
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
if (from == 2) {
cout << "================== Frame: " << Frame << " Time: "
- << State->Getsim_time() << endl;
+ << State->Getsim_time() << " dt: " << State->Getdt() << endl;
}
}
if (debug_lvl & 8 ) { // Runtime state variables
}
}
+
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include "FGModel.h"
-#include "FGTrim.h"
-#include "FGInitialCondition.h"
-#include "FGJSBBase.h"
-#include "FGGroundCallback.h"
-#include "FGPropertyManager.h"
-#include "FGPropagate.h"
+#include <models/FGModel.h>
+#include <models/FGOutput.h>
+#include <models/FGInput.h>
+#include <initialization/FGTrim.h>
+#include <initialization/FGInitialCondition.h>
+#include <FGJSBBase.h>
+#include <input_output/FGPropertyManager.h>
+#include <input_output/FGXMLParse.h>
+#include <input_output/FGGroundCallback.h>
+#include <models/FGPropagate.h>
#include <vector>
When an aircraft model is loaded the config file is parsed and for each of the
sections of the config file (propulsion, flight control, etc.) the
- corresponding "ReadXXX()" method is called. From within this method the
- "Load()" method of that system is called (e.g. LoadFCS).
+ corresponding Load() method is called (e.g. LoadFCS).
<h4>JSBSim Debugging Directives</h4>
/** Initializes the sim from the initial condition object and executes
each scheduled model without integrating i.e. dt=0.
- @return true if successful
- */
+ @return true if successful */
bool RunIC(void);
- /// Freezes the sim
- void Freeze(void) {frozen = true;}
-
- /// Resumes the sim
- void Resume(void) {frozen = false;}
-
- void SetGroundCallback(FGGroundCallback*);
+ /** Sets the ground callback pointer.
+ @param gc A pointer to a ground callback object. */
+ void SetGroundCallback(FGGroundCallback* gc);
/** Loads an aircraft model.
@param AircraftPath path to the aircraft directory. For instance:
bool LoadModel(string AircraftPath, string EnginePath, string model,
bool addModelToPath = true);
-
/** Loads an aircraft model. The paths to the aircraft and engine
config file directories must be set prior to calling this. See
below.
@return true if successful*/
bool LoadModel(string model, bool addModelToPath = true);
-
/** Sets the path to the engine config file directories.
@param path path to the directory under which engine config
- files are kept, for instance "engine"
- */
+ files are kept, for instance "engine" */
bool SetEnginePath(string path) { EnginePath = path; return true; }
/** Sets the path to the aircraft config file directories.
@param path path to the aircraft directory. For instance:
"aircraft". Under aircraft, then, would be directories for various
- modeled aircraft such as C172/, x15/, etc.
- */
+ modeled aircraft such as C172/, x15/, etc. */
bool SetAircraftPath(string path) { AircraftPath = path; return true; }
- /** Sets the path to the autopilot config file directories.
- @param path path to the control directory. For instance:
- "control".
- */
-// bool SetControlPath(string path) { ControlPath = path; return true; }
-
-
/// @name Top-level executive State and Model retrieval mechanism
//@{
- /// Returns the FGState pointer.
- inline FGState* GetState(void) {return State;}
/// Returns the FGAtmosphere pointer.
inline FGAtmosphere* GetAtmosphere(void) {return Atmosphere;}
/// Returns the FGFCS pointer.
inline FGFCS* GetFCS(void) {return FCS;}
- /// Returns the FGGroundCallback pointer.
- inline FGGroundCallback* GetGroundCallback(void) {return GroundCallback;}
/// Returns the FGPropulsion pointer.
inline FGPropulsion* GetPropulsion(void) {return Propulsion;}
/// Returns the FGAircraft pointer.
inline FGPropagate* GetPropagate(void) {return Propagate;}
/// Returns the FGAuxiliary pointer.
inline FGAuxiliary* GetAuxiliary(void) {return Auxiliary;}
- /// Returns the FGOutput pointer.
- inline FGOutput* GetOutput(void) {return Output;}
+ /// Returns the FGInput pointer.
+ inline FGInput* GetInput(void) {return Input;}
+ /// Returns the FGGroundCallback pointer.
+ inline FGGroundCallback* GetGroundCallback(void) {return GroundCallback;}
+ /// Returns the FGState pointer.
+ inline FGState* GetState(void) {return State;}
// Returns a pointer to the FGInitialCondition object
inline FGInitialCondition* GetIC(void) {return IC;}
// Returns a pointer to the FGTrim object
- FGTrim* GetTrim(void);
+ inline FGTrim* GetTrim(void);
//@}
/// Retrieves the engine path.
inline string GetEnginePath(void) {return EnginePath;}
/// Retrieves the aircraft path.
inline string GetAircraftPath(void) {return AircraftPath;}
-// /// Retrieves the control path.
-// inline string GetControlPath(void) {return ControlPath;}
+ /// Returns the model name.
string GetModelName(void) { return modelName; }
+ /// Returns a pointer to the property manager object.
FGPropertyManager* GetPropertyManager(void);
+ /// Returns a vector of strings representing the names of all loaded models (future)
vector <string> EnumerateFDMs(void);
+ /// Marks this instance of the Exec object as a "slave" object.
void SetSlave(void) {IsSlave = true;}
+ /** Executes trimming in the selected mode.
+ * @param mode Specifies how to trim:
+ * - tLongitudinal=0
+ * - tFull
+ * - tGround
+ * - tPullup
+ * - tCustom
+ * - tTurn
+ * - tNone
+ */
+ void DoTrim(int mode);
+
+ /// Disables data logging to all outputs.
+ void DisableOutput(void);
+ /// Enables data logging to all outputs.
+ void EnableOutput(void);
+ /// Pauses execution by preventing time from incrementing.
+ void Hold(void) {holding = true;}
+ /// Resumes execution from a "Hold".
+ void Resume(void) {holding = false;}
+ /// Returns true if the simulation is Holding (i.e. simulation time is not moving).
+ bool Holding(void) {return holding;}
+
+ struct PropertyCatalogStructure {
+ /// Name of the property.
+ string base_string;
+ /// The node for the property.
+ FGPropertyManager *node;
+ };
+
+ /** Builds a catalog of properties.
+ * This function descends the property tree and creates a list (an STL vector)
+ * containing the name and node for all properties.
+ * @param pcs The "root" property catalog structure pointer. */
+ void BuildPropertyCatalog(struct PropertyCatalogStructure* pcs);
+
+ /** Retrieves property or properties matching the supplied string.
+ * A string is returned that contains a carriage return delimited list of all
+ * strings in the property catalog that matches the supplied chack string.
+ * @param check The string to search for in the property catalog.
+ * @return the carriage-return-delimited string containing all matching strings
+ * in the catalog. */
+ string QueryPropertyCatalog(string check);
+
+ /// Use the MSIS atmosphere model.
+ void UseAtmosphereMSIS(void);
+
+ /// Use the Mars atmosphere model. (Not operative yet.)
+ void UseAtmosphereMars(void);
+
private:
FGModel* FirstModel;
- bool frozen;
bool terminate;
+ bool holding;
+ bool Constructing;
int Error;
unsigned int Frame;
unsigned int IdFDM;
+ FGPropertyManager* Root;
static unsigned int FDMctr;
bool modelLoaded;
string modelName;
bool IsSlave;
static FGPropertyManager *master;
FGPropertyManager *instance;
+ vector <string> PropertyCatalog;
struct slaveData {
FGFDMExec* exec;
string AircraftPath;
string EnginePath;
-// string ControlPath;
string CFGVersion;
string Release;
+ FGGroundCallback* GroundCallback;
FGState* State;
FGAtmosphere* Atmosphere;
FGFCS* FCS;
- FGGroundCallback* GroundCallback;
FGPropulsion* Propulsion;
FGMassBalance* MassBalance;
FGAerodynamics* Aerodynamics;
FGAircraft* Aircraft;
FGPropagate* Propagate;
FGAuxiliary* Auxiliary;
- FGOutput* Output;
+ FGInput* Input;
+ vector <FGOutput*> Outputs;
FGInitialCondition* IC;
FGTrim *Trim;
vector <slaveData*> SlaveFDMList;
- bool ReadMetrics(FGConfigFile*);
- bool ReadSlave(FGConfigFile*);
- bool ReadPropulsion(FGConfigFile*);
- bool ReadFlightControls(FGConfigFile*);
- bool ReadAerodynamics(FGConfigFile*);
- bool ReadUndercarriage(FGConfigFile*);
- bool ReadPrologue(FGConfigFile*);
- bool ReadOutput(FGConfigFile*);
+ bool ReadFileHeader(Element*);
+ bool ReadSlave(Element*);
+ bool ReadPrologue(Element*);
bool Allocate(void);
bool DeAllocate(void);
const double FGJSBBase::degtorad = 1.745329E-2;
const double FGJSBBase::hptoftlbssec = 550.0;
const double FGJSBBase::psftoinhg = 0.014138;
+const double FGJSBBase::psftopa = 47.88;
const double FGJSBBase::fpstokts = 0.592484;
const double FGJSBBase::ktstofps = 1.68781;
const double FGJSBBase::inchtoft = 0.08333333;
const double FGJSBBase::slugtolb = 32.174049;
const double FGJSBBase::lbtoslug = 1.0/slugtolb;
-const string FGJSBBase::needed_cfg_version = "1.65";
-const string FGJSBBase::JSBSim_version = "0.9.5";
+const string FGJSBBase::needed_cfg_version = "2.0";
+const string FGJSBBase::JSBSim_version = "0.9.10.111805";
std::queue <FGJSBBase::Message*> FGJSBBase::Messages;
FGJSBBase::Message FGJSBBase::localMsg;
#ifdef FGFS
# include <simgear/compiler.h>
-# include <simgear/constants.h>
# include <math.h>
# include <queue>
# include STL_STRING
SG_USING_STD(string);
-# ifndef M_PI
-# define M_PI SG_PI
-# endif
+# ifndef M_PI
+# include <simgear/constants.h>
+# define M_PI SG_PI
+# endif
-#else
+#else // JSBSim section
# include <queue>
# include <string>
using std::string;
-# ifndef M_PI
-# define M_PI 3.14159265358979323846
-# endif
+# if defined(_MSC_VER) && _MSC_VER <= 1200
+# ifndef max
+# define max(a,b) (((a) > (b)) ? (a) : (b))
+# endif
+
+# ifndef min
+# define min(a,b) (((a) < (b)) ? (a) : (b))
+# endif
+# else
+
+using std::fabs;
+
+# endif
+
+# ifndef M_PI
+# define M_PI 3.14159265358979323846
+# endif
#endif
-#if !defined(WIN32) || defined(__GNUC__) || ( defined(_MSC_VER) && (_MSC_VER >= 1400))
+#if !defined(WIN32) || defined(__GNUC__)
using std::max;
#endif
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** JSBSim Base class.
+* This class provides universal constants, utility functions, messaging
+* functions, and enumerated constants to JSBSim.
@author Jon S. Berndt
@version $Id$
*/
@return pointer to a Message structure (or NULL if no mesage) */
Message* ProcessMessage(void);
//@}
+
+ /** Returns the version number of JSBSim.
+ * @return The version number of JSBSim. */
string GetVersion(void) {return JSBSim_version;}
+ /// Disables highlighting in the console output.
void disableHighLighting(void);
static short debug_lvl;
+
+ /** Converts from degrees Kelvin to degrees Fahrenheit.
+ * @param kelvin The temperature in degrees Kelvin.
+ * @return The temperature in Fahrenheit. */
static double KelvinToFahrenheit (double kelvin) {
return 1.8*kelvin - 459.4;
}
+ /** Converts from degrees Rankine to degrees Celsius.
+ * @param rankine The temperature in degrees Rankine.
+ * @return The temperature in Celsius. */
static double RankineToCelsius (double rankine) {
return (rankine - 491.67)/1.8;
}
+ /** Converts from degrees Fahrenheit to degrees Celsius.
+ * @param fahrenheit The temperature in degrees Fahrenheit.
+ * @return The temperature in Celsius. */
static double FahrenheitToCelsius (double fahrenheit) {
return (fahrenheit - 32.0)/1.8;
}
+ /** Converts from degrees Celsius to degrees Fahrenheit.
+ * @param celsius The temperature in degrees Celsius.
+ * @return The temperature in Fahrenheit. */
static double CelsiusToFahrenheit (double celsius) {
return celsius * 1.8 + 32.0;
}
static const double degtorad;
static const double hptoftlbssec;
static const double psftoinhg;
+ static const double psftopa;
static const double fpstokts;
static const double ktstofps;
static const double inchtoft;
static const double slugtolb;
static const string needed_cfg_version;
static const string JSBSim_version;
-};
+public:
/// Moments L, M, N
enum {eL = 1, eM, eN };
/// Rates P, Q, R
/// Conversion specifiers
enum {inNone = 0, inDegrees, inRadians, inMeters, inFeet };
+};
+
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGLocation.h
- Author: Jon S. Berndt, Mathias Froehlich
- Date started: 04/04/2004
-
- ------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------------
- ------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
--------------------------------------------------------------------------------
-04/04/2004 MF Created from code previously in the old positions class.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGLOCATION_H
-#define FGLOCATION_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGJSBBase.h"
-#include "FGPropertyManager.h"
-#include "FGColumnVector3.h"
-#include "FGMatrix33.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_LOCATION "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Holds an arbitrary location in the earth centered reference frame.
- This coordinate frame has its center in the middle of the earth.
- Its x-axis points from the center of the earth towards a location
- with zero latitude and longitude on the earths surface. The y-axis
- points from the center of the earth towards a location with zero
- latitude and 90deg longitude on the earths surface. The z-axis
- points from the earths center to the geographic north pole.
-
- This class provides access functions to set and get the location as
- either the simple x, y and z values in ft or longitude/latitude and
- the radial distance of the location from the earth center.
-
- It is common to associate a parent frame with a location. This
- frame is usually called the local horizontal frame or simply the local
- frame. This frame has its x/y plane parallel to the surface of the earth
- (with the assumption of a spherical earth). The x-axis points
- towards north, the y-axis points towards east and the z-axis
- points to the center of the earth.
-
- Since this frame is determined by the location, this class also
- provides the rotation matrices required to transform from the
- earth centered frame to the local horizontal frame and back. There
- are also conversion functions for conversion of position vectors
- given in the one frame to positions in the other frame.
-
- The earth centered reference frame is *NOT* an inertial frame
- since it rotates with the earth.
-
- The coordinates in the earth centered frame are the master values.
- All other values are computed from these master values and are
- cached as long as the location is changed by access through a
- non-const member function. Values are cached to improve performance.
- It is best practice to work with a natural set of master values.
- Other parameters that are derived from these master values are calculated
- only when needed, and IF they are needed and calculated, then they are
- cached (stored and remembered) so they do not need to be re-calculated
- until the master values they are derived from are themselves changed
- (and become stale).
-
- Accuracy and round off:
-
- Given that we model a vehicle near the earth, the earths surface
- radius is about 2*10^7, ft and that we use double values for the
- representation of the location, we have an accuracy of about
- 1e-16*2e7ft/1=2e-9ft left. This should be sufficient for our needs.
- Note that this is the same relative accuracy we would have when we
- compute directly with lon/lat/radius. For the radius value this
- is clear. For the lon/lat pair this is easy to see. Take for
- example KSFO located at about 37.61deg north 122.35deg west, which
- corresponds to 0.65642rad north and 2.13541rad west. Both values
- are of magnitude of about 1. But 1ft corresponds to about
- 1/(2e7*2*pi)=7.9577e-09rad. So the left accuracy with this
- representation is also about 1*1e-16/7.9577e-09=1.2566e-08 which
- is of the same magnitude as the representation chosen here.
-
- The advantage of this representation is that it is a linear space
- without singularities. The singularities are the north and south
- pole and most notably the non-steady jump at -pi to pi. It is
- harder to track this jump correctly especially when we need to
- work with error norms and derivatives of the equations of motion
- within the time-stepping code. Also, the rate of change is of the
- same magnitude for all components in this representation which is
- an advantage for numerical stability in implicit time-stepping too.
-
- Note: The latitude is a GEOCENTRIC value. FlightGear
- converts latitude to a geodetic value and uses that. In order to get best
- matching relative to a map, geocentric latitude must be converted to geodetic.
-
- @see W. C. Durham "Aircraft Dynamics & Control", section 2.2
-
- @author Mathias Froehlich
- @version $Id$
- */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGLocation : virtual FGJSBBase
-{
-public:
- /** Default constructor. */
- FGLocation() { mCacheValid = false; }
-
- /** Constructor to set the longitude, latitude and the distance
- from the center of the earth.
- @param lon longitude
- @param lat GEOCENTRIC latitude
- @param distance from center of earth to vehicle in feet*/
- FGLocation(double lon, double lat, double radius);
-
- /** Copy constructor. */
- FGLocation(const FGColumnVector3& lv)
- : mECLoc(lv), mCacheValid(false) {}
-
- /** Copy constructor. */
- FGLocation(const FGLocation& l)
- : mECLoc(l.mECLoc), mCacheValid(l.mCacheValid) {
- if (!mCacheValid)
- return;
-
- mLon = l.mLon;
- mLat = l.mLat;
- mRadius = l.mRadius;
-
- mTl2ec = l.mTl2ec;
- mTec2l = l.mTec2l;
- }
-
- /** Get the longitude.
- @return the longitude in rad of the location represented with this
- class instance. The returned values are in the range between
- -pi <= lon <= pi. Longitude is positive east and negative west. */
- double GetLongitude() const { ComputeDerived(); return mLon; }
-
- /** Get the longitude.
- @return the longitude in deg of the location represented with this
- class instance. The returned values are in the range between
- -180 <= lon <= 180. Longitude is positive east and negative west. */
- double GetLongitudeDeg() const { ComputeDerived(); return radtodeg*mLon; }
-
- /** Set the longitude.
- @param longitude Longitude in rad to set.
- Sets the longitude of the location represented with this class
- instance to the value of the given argument. The value is meant
- to be in rad. The latitude and the radius value are preserved
- with this call with the exception of radius being equal to
- zero. If the radius is previously set to zero it is changed to be
- equal to 1.0 past this call. Longitude is positive east and negative west. */
- void SetLongitude(double longitude);
-
- /** Get the sine of Longitude. */
- double GetSinLongitude() const { ComputeDerived(); return -mTec2l(2,1); }
-
- /** Get the cosine of Longitude. */
- double GetCosLongitude() const { ComputeDerived(); return mTec2l(2,2); }
-
- /** Get the latitude.
- @return the latitude in rad of the location represented with this
- class instance. The returned values are in the range between
- -pi/2 <= lon <= pi/2. Latitude is positive north and negative south. */
- double GetLatitude() const { ComputeDerived(); return mLat; }
-
- /** Get the latitude.
- @return the latitude in deg of the location represented with this
- class instance. The returned values are in the range between
- -90 <= lon <= 90. Latitude is positive north and negative south. */
- double GetLatitudeDeg() const { ComputeDerived(); return radtodeg*mLat; }
-
- /** Set the latitude.
- @param latitude Latitude in rad to set.
- Sets the latitude of the location represented with this class
- instance to the value of the given argument. The value is meant
- to be in rad. The longitude and the radius value are preserved
- with this call with the exception of radius being equal to
- zero. If the radius is previously set to zero it is changed to be
- equal to 1.0 past this call.
- Latitude is positive north and negative south.
- The arguments should be within the bounds of -pi/2 <= lat <= pi/2.
- The behavior of this function with arguments outside this range is
- left as an exercise to the gentle reader ... */
- void SetLatitude(double latitude);
-
- /** Get the sine of Latitude. */
- double GetSinLatitude() const { ComputeDerived(); return -mTec2l(3,3); }
-
- /** Get the cosine of Latitude. */
- double GetCosLatitude() const { ComputeDerived(); return mTec2l(1,3); }
-
- /** Get the cosine of Latitude. */
- double GetTanLatitude() const {
- ComputeDerived();
- double cLat = mTec2l(1,3);
- if (cLat == 0.0)
- return 0.0;
- else
- return -mTec2l(3,3)/cLat;
- }
-
- /** Get the distance from the center of the earth.
- @return the distance of the location represented with this class
- instance to the center of the earth in ft. The radius value is
- always positive. */
- double GetRadius() const { ComputeDerived(); return mRadius; }
-
- /** Set the distance from the center of the earth.
- @param radius Radius in ft to set.
- Sets the radius of the location represented with this class
- instance to the value of the given argument. The value is meant
- to be in ft. The latitude and longitude values are preserved
- with this call with the exception of radius being equal to
- zero. If the radius is previously set to zero, latitude and
- longitude is set equal to zero past this call.
- The argument should be positive.
- The behavior of this function called with a negative argument is
- left as an exercise to the gentle reader ... */
- void SetRadius(double radius);
-
- /** Transform matrix from local horizontal to earth centered frame.
- Returns a const reference to the rotation matrix of the transform from
- the local horizontal frame to the earth centered frame. */
- const FGMatrix33& GetTl2ec(void) const { ComputeDerived(); return mTl2ec; }
-
- /** Transform matrix from the earth centered to local horizontal frame.
- Returns a const reference to the rotation matrix of the transform from
- the earth centered frame to the local horizontal frame. */
- const FGMatrix33& GetTec2l(void) const { ComputeDerived(); return mTec2l; }
-
- /** Conversion from Local frame coordinates to a location in the
- earth centered and fixed frame.
- @parm lvec Vector in the local horizontal coordinate frame
- @return The location in the earth centered and fixed frame */
- FGLocation LocalToLocation(const FGColumnVector3& lvec) const {
- ComputeDerived(); return mTl2ec*lvec + mECLoc;
- }
-
- /** Conversion from a location in the earth centered and fixed frame
- to local horizontal frame coordinates.
- @parm ecvec Vector in the earth centered and fixed frame
- @return The vector in the local horizontal coordinate frame */
- FGColumnVector3 LocationToLocal(const FGColumnVector3& ecvec) const {
- ComputeDerived(); return mTec2l*(ecvec - mECLoc);
- }
-
- // For time-stepping, locations have vector properties...
-
- /** Read access the entries of the vector.
- @param idx the component index.
- Return the value of the matrix entry at the given index.
- Indices are counted starting with 1.
- Note that the index given in the argument is unchecked. */
- double operator()(unsigned int idx) const { return Entry(idx); }
-
- /** Write access the entries of the vector.
- @param idx the component index.
- @return a reference to the vector entry at the given index.
- Indices are counted starting with 1.
- Note that the index given in the argument is unchecked. */
- double& operator()(unsigned int idx) { return Entry(idx); }
-
- /** Read access the entries of the vector.
- @param idx the component index.
- @return the value of the matrix entry at the given index.
- Indices are counted starting with 1.
- This function is just a shortcut for the @ref double
- operator()(unsigned int idx) const function. It is
- used internally to access the elements in a more convenient way.
- Note that the index given in the argument is unchecked. */
- double Entry(unsigned int idx) const { return mECLoc.Entry(idx); }
-
- /** Write access the entries of the vector.
- @param idx the component index.
- @return a reference to the vector entry at the given index.
- Indices are counted starting with 1.
- This function is just a shortcut for the double&
- operator()(unsigned int idx) function. It is
- used internally to access the elements in a more convenient way.
- Note that the index given in the argument is unchecked. */
- double& Entry(unsigned int idx) {
- mCacheValid = false; return mECLoc.Entry(idx);
- }
-
- const FGLocation& operator=(const FGLocation& l) {
- mECLoc = l.mECLoc;
- mCacheValid = l.mCacheValid;
- if (!mCacheValid)
- return *this;
-
- mLon = l.mLon;
- mLat = l.mLat;
- mRadius = l.mRadius;
-
- mTl2ec = l.mTl2ec;
- mTec2l = l.mTec2l;
-
- return *this;
- }
- bool operator==(const FGLocation& l) const {
- return mECLoc == l.mECLoc;
- }
- bool operator!=(const FGLocation& l) const { return ! operator==(l); }
- const FGLocation& operator+=(const FGLocation &l) {
- mCacheValid = false;
- mECLoc += l.mECLoc;
- return *this;
- }
- const FGLocation& operator-=(const FGLocation &l) {
- mCacheValid = false;
- mECLoc -= l.mECLoc;
- return *this;
- }
- const FGLocation& operator*=(double scalar) {
- mCacheValid = false;
- mECLoc *= scalar;
- return *this;
- }
- const FGLocation& operator/=(double scalar) {
- return operator*=(1.0/scalar);
- }
- FGLocation operator+(const FGLocation& l) const {
- return FGLocation(mECLoc + l.mECLoc);
- }
- FGLocation operator-(const FGLocation& l) const {
- return FGLocation(mECLoc - l.mECLoc);
- }
-
- FGLocation operator*(double scalar) const {
- return FGLocation(scalar*mECLoc);
- }
-
- /** Cast to a simple 3d vector */
- operator const FGColumnVector3&() const {
- return mECLoc;
- }
-
- /** Ties into the property tree.
- Ties the variables represented by this class into the property tree. */
- void bind(FGPropertyManager*, const string&) const;
-
- /** Remove from property tree.
- Unties the variables represented by this class into the property tree. */
- void unbind(FGPropertyManager*, const string&) const;
-
-private:
- /** Computation of derived values.
- This function re-computes the derived values like lat/lon and
- transformation matrices. It does this unconditionally. */
- void ComputeDerivedUnconditional(void) const;
-
- /** Computation of derived values.
- This function checks if the derived values like lat/lon and
- transformation matrices are already computed. If so, it
- returns. If they need to be computed this is done here. */
- void ComputeDerived(void) const {
- if (!mCacheValid)
- ComputeDerivedUnconditional();
- }
-
- /** The coordinates in the earth centered frame. This is the master copy.
- The coordinate frame has its center in the middle of the earth.
- Its x-axis points from the center of the earth towards a
- location with zero latitude and longitude on the earths
- surface. The y-axis points from the center of the earth towards a
- location with zero latitude and 90deg longitude on the earths
- surface. The z-axis points from the earths center to the
- geographic north pole.
- @see W. C. Durham "Aircraft Dynamics & Control", section 2.2 */
- FGColumnVector3 mECLoc;
-
- /** The cached lon/lat/radius values. */
- mutable double mLon;
- mutable double mLat;
- mutable double mRadius;
-
- /** The cached rotation matrices from and to the associated frames. */
- mutable FGMatrix33 mTl2ec;
- mutable FGMatrix33 mTec2l;
-
- /** A data validity flag.
- This class implements caching of the derived values like the
- orthogonal rotation matrices or the lon/lat/radius values. For caching we
- carry a flag which signals if the values are valid or not.
- The C++ keyword "mutable" tells the compiler that the data member is
- allowed to change during a const member function. */
- mutable bool mCacheValid;
-};
-
-/** Scalar multiplication.
-
- @param scalar scalar value to multiply with.
- @param l Vector to multiply.
-
- Multiply the Vector with a scalar value. */
-inline FGLocation operator*(double scalar, const FGLocation& l)
-{
- return l.operator*(scalar);
-}
-
-} // namespace JSBSim
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGMassBalance.cpp
- Author: Jon S. Berndt
- Date started: 09/12/2000
- Purpose: This module models weight and balance
-
- ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) --------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-This class models the change in weight and balance of the aircraft due to fuel
-burnoff, etc.
-
-HISTORY
---------------------------------------------------------------------------------
-09/12/2000 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGMassBalance.h"
-#include "FGPropulsion.h"
-#include "FGPropertyManager.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_MASSBALANCE;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-
-FGMassBalance::FGMassBalance(FGFDMExec* fdmex) : FGModel(fdmex)
-{
- Name = "FGMassBalance";
- Weight = EmptyWeight = Mass = 0.0;
-
- vbaseXYZcg.InitMatrix(0.0);
- baseJ.InitMatrix();
- mJ.InitMatrix();
- mJinv.InitMatrix();
- pmJ.InitMatrix();
-
- bind();
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGMassBalance::~FGMassBalance()
-{
- unbind();
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGMassBalance::Run(void)
-{
- double denom, k1, k2, k3, k4, k5, k6;
- double Ixx, Iyy, Izz, Ixy, Ixz, Iyz;
-
- if (!FGModel::Run()) {
-
- Weight = EmptyWeight + Propulsion->GetTanksWeight() + GetPointMassWeight();
-
- Mass = lbtoslug*Weight;
-
-// Calculate new CG
-
- vXYZcg = (Propulsion->GetTanksMoment() + EmptyWeight*vbaseXYZcg
- + GetPointMassMoment() ) / Weight;
-
-// Calculate new total moments of inertia
-
- // At first it is the base configuration inertia matrix ...
- mJ = baseJ;
- // ... with the additional term originating from the parallel axis theorem.
- mJ += GetPointmassInertia( lbtoslug * EmptyWeight, vbaseXYZcg );
- // Then add the contributions from the additional pointmasses.
- mJ += CalculatePMInertias();
- mJ += Propulsion->CalculateTankInertias();
-
- Ixx = mJ(1,1);
- Iyy = mJ(2,2);
- Izz = mJ(3,3);
- Ixy = -mJ(1,2);
- Ixz = -mJ(1,3);
- Iyz = -mJ(2,3);
-
-// Calculate inertia matrix inverse (ref. Stevens and Lewis, "Flight Control & Simulation")
-
- k1 = (Iyy*Izz - Iyz*Iyz);
- k2 = (Iyz*Ixz + Ixy*Izz);
- k3 = (Ixy*Iyz + Iyy*Ixz);
-
- denom = 1.0/(Ixx*k1 - Ixy*k2 - Ixz*k3 );
- k1 = k1*denom;
- k2 = k2*denom;
- k3 = k3*denom;
- k4 = (Izz*Ixx - Ixz*Ixz)*denom;
- k5 = (Ixy*Ixz + Iyz*Ixx)*denom;
- k6 = (Ixx*Iyy - Ixy*Ixy)*denom;
-
- mJinv.InitMatrix( k1, k2, k3,
- k2, k4, k5,
- k3, k5, k6 );
-
- Debug(2);
-
- return false;
- } else {
- return true;
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGMassBalance::AddPointMass(double weight, double X, double Y, double Z)
-{
- PointMassLoc.push_back(FGColumnVector3(X, Y, Z));
- PointMassWeight.push_back(weight);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGMassBalance::GetPointMassWeight(void)
-{
- double PM_total_weight = 0.0;
-
- for (unsigned int i=0; i<PointMassWeight.size(); i++) {
- PM_total_weight += PointMassWeight[i];
- }
- return PM_total_weight;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGColumnVector3& FGMassBalance::GetPointMassMoment(void)
-{
- PointMassCG.InitMatrix();
-
- for (unsigned int i=0; i<PointMassLoc.size(); i++) {
- PointMassCG += PointMassWeight[i]*PointMassLoc[i];
- }
- return PointMassCG;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGMatrix33& FGMassBalance::CalculatePMInertias(void)
-{
- unsigned int size;
-
- size = PointMassLoc.size();
- if (size == 0) return pmJ;
-
- pmJ = FGMatrix33();
-
- for (unsigned int i=0; i<size; i++)
- pmJ += GetPointmassInertia( lbtoslug * PointMassWeight[i], PointMassLoc[i] );
-
- return pmJ;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGColumnVector3 FGMassBalance::StructuralToBody(const FGColumnVector3& r) const
-{
- // Under the assumption that in the structural frame the:
- //
- // - X-axis is directed afterwards,
- // - Y-axis is directed towards the right,
- // - Z-axis is directed upwards,
- //
- // (as documented in http://jsbsim.sourceforge.net/JSBSimCoordinates.pdf)
- // we have to subtract first the center of gravity of the plane which
- // is also defined in the structural frame:
- //
- // FGColumnVector3 cgOff = r - vXYZcg;
- //
- // Next, we do a change of units:
- //
- // cgOff *= inchtoft;
- //
- // And then a 180 degree rotation is done about the Y axis so that the:
- //
- // - X-axis is directed forward,
- // - Y-axis is directed towards the right,
- // - Z-axis is directed downward.
- //
- // This is needed because the structural and body frames are 180 degrees apart.
-
- return FGColumnVector3(inchtoft*(vXYZcg(1)-r(1)),
- inchtoft*(r(2)-vXYZcg(2)),
- inchtoft*(vXYZcg(3)-r(3)));
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGMassBalance::bind(void)
-{
- typedef double (FGMassBalance::*PMF)(int) const;
- PropertyManager->Tie("inertia/mass-slugs", this,
- &FGMassBalance::GetMass);
- PropertyManager->Tie("inertia/weight-lbs", this,
- &FGMassBalance::GetWeight);
- PropertyManager->Tie("inertia/cg-x-ft", this,1,
- (PMF)&FGMassBalance::GetXYZcg);
- PropertyManager->Tie("inertia/cg-y-ft", this,2,
- (PMF)&FGMassBalance::GetXYZcg);
- PropertyManager->Tie("inertia/cg-z-ft", this,3,
- (PMF)&FGMassBalance::GetXYZcg);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGMassBalance::unbind(void)
-{
- PropertyManager->Untie("inertia/mass-slugs");
- PropertyManager->Untie("inertia/weight-lbs");
- PropertyManager->Untie("inertia/cg-x-ft");
- PropertyManager->Untie("inertia/cg-y-ft");
- PropertyManager->Untie("inertia/cg-z-ft");
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGMassBalance::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
-
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGMassBalance" << endl;
- if (from == 1) cout << "Destroyed: FGMassBalance" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- if (from == 2) {
- if (EmptyWeight <= 0.0 || EmptyWeight > 1e9)
- cout << "MassBalance::EmptyWeight out of bounds: " << EmptyWeight << endl;
- if (Weight <= 0.0 || Weight > 1e9)
- cout << "MassBalance::Weight out of bounds: " << Weight << endl;
- if (Mass <= 0.0 || Mass > 1e9)
- cout << "MassBalance::Mass out of bounds: " << Mass << endl;
- }
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGMassBalance.h
- Author: Jon S. Berndt
- Date started: 09/12/2000
-
- ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) --------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-09/12/2000 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGMASSBALANCE_H
-#define FGMASSBALANCE_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGModel.h"
-#include "FGColumnVector3.h"
-#include "FGMatrix33.h"
-#include <vector>
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_MASSBALANCE "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONSS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Models weight and balance information.
- */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGMassBalance : public FGModel
-{
-
-public:
- FGMassBalance(FGFDMExec*);
- ~FGMassBalance();
-
- bool Run(void);
-
- inline double GetMass(void) const {return Mass;}
- inline double GetWeight(void) const {return Weight;}
- inline double GetEmptyWeight(void) const {return EmptyWeight;}
- inline FGColumnVector3& GetXYZcg(void) {return vXYZcg;}
- inline double GetXYZcg(int axis) const {return vXYZcg(axis);}
- inline double GetbaseXYZcg(int axis) const {return vbaseXYZcg(axis);}
-
- /** Computes the inertia contribution of a pointmass.
- Computes and returns the inertia matrix of a pointmass of mass
- slugs at the given vector r in the structural frame. The units
- should be for the mass in slug and the vector in the structural
- frame as usual in inches.
- @param slugs the mass of this single pointmass given in slugs
- @param r the location of this single pointmass in the structural frame
- */
- FGMatrix33 GetPointmassInertia(double slugs, const FGColumnVector3& r) const
- {
- FGColumnVector3 v = StructuralToBody( r );
- FGColumnVector3 sv = slugs*v;
- double xx = sv(1)*v(1);
- double yy = sv(2)*v(2);
- double zz = sv(3)*v(3);
- double xy = -sv(1)*v(2);
- double xz = -sv(1)*v(3);
- double yz = -sv(2)*v(3);
- return FGMatrix33( yy+zz, xy, xz,
- xy, xx+zz, yz,
- xz, yz, xx+yy );
- }
-
- /** Conversion from the structural frame to the body frame.
- Converts the location given in the structural frame
- coordinate system to the body frame. The units of the structural
- frame are assumed to be in inches. The unit of the result is in
- ft.
- @param r vector coordinate in the structural reference frame (X positive
- aft, measurements in inches).
- @return vector coordinate in the body frame, in feet.
- */
- FGColumnVector3 StructuralToBody(const FGColumnVector3& r) const;
-
- inline void SetEmptyWeight(double EW) { EmptyWeight = EW;}
- inline void SetBaseCG(const FGColumnVector3& CG) {vbaseXYZcg = vXYZcg = CG;}
-
- void AddPointMass(double weight, double X, double Y, double Z);
- double GetPointMassWeight(void);
- FGColumnVector3& GetPointMassMoment(void);
- FGMatrix33& GetJ(void) {return mJ;}
- FGMatrix33& GetJinv(void) {return mJinv;}
- void SetAircraftBaseInertias(FGMatrix33 BaseJ) {baseJ = BaseJ;}
- FGMatrix33& GetAircraftBaseInertias(void) {return baseJ;}
- int GetNumPointMasses(void) {return PointMassLoc.size();}
- FGColumnVector3& GetPointMassLoc(int i) {return PointMassLoc[i];}
- double GetPointMassWeight(int i) {return PointMassWeight[i];}
-
- void bind(void);
- void unbind(void);
-
-private:
- double Weight;
- double EmptyWeight;
- double Mass;
- FGMatrix33 mJ;
- FGMatrix33 mJinv;
- FGMatrix33 pmJ;
- FGMatrix33 baseJ;
- FGColumnVector3 vXYZcg;
- FGColumnVector3 vXYZtank;
- FGColumnVector3 vbaseXYZcg;
- FGColumnVector3 vPMxyz;
- vector <FGColumnVector3> PointMassLoc;
- vector <double> PointMassWeight;
- FGColumnVector3 PointMassCG;
- FGMatrix33& CalculatePMInertias(void);
-
- void Debug(int from);
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-Module: FGMatrix33.cpp
-Author: Tony Peden, Jon Berndt, Mathias Frolich
-Date started: 1998
-Purpose: FGMatrix33 class
-Called by: Various
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-HISTORY
---------------------------------------------------------------------------------
-??/??/?? TP Created
-03/16/2000 JSB Added exception throwing
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "FGMatrix33.h"
-#include "FGColumnVector3.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_MATRIX33;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGMatrix33::FGMatrix33(void)
-{
- data[0] = data[1] = data[2] = data[3] = data[4] = data[5] =
- data[6] = data[7] = data[8] = 0.0;
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-ostream& operator<<(ostream& os, const FGMatrix33& M)
-{
- for (unsigned int i=1; i<=M.Rows(); i++) {
- for (unsigned int j=1; j<=M.Cols(); j++) {
- if (i == M.Rows() && j == M.Cols())
- os << M(i,j);
- else
- os << M(i,j) << ", ";
- }
- }
- return os;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-istream& operator>>(istream& is, FGMatrix33& M)
-{
- for (unsigned int i=1; i<=M.Rows(); i++) {
- for (unsigned int j=1; j<=M.Cols(); j++) {
- is >> M(i,j);
- }
- }
- return is;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGMatrix33::Determinant(void) const {
- return Entry(1,1)*Entry(2,2)*Entry(3,3) + Entry(1,2)*Entry(2,3)*Entry(3,1)
- + Entry(1,3)*Entry(2,1)*Entry(3,2) - Entry(1,3)*Entry(2,2)*Entry(3,1)
- - Entry(1,2)*Entry(2,1)*Entry(3,3) - Entry(2,3)*Entry(3,2)*Entry(1,1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGMatrix33 FGMatrix33::Inverse(void) const {
- // Compute the inverse of a general matrix using Cramers rule.
- // I guess googling for cramers rule gives tons of references
- // for this. :)
- double rdet = 1.0/Determinant();
-
- double i11 = rdet*(Entry(2,2)*Entry(3,3)-Entry(2,3)*Entry(3,2));
- double i21 = rdet*(Entry(2,3)*Entry(3,1)-Entry(2,1)*Entry(3,3));
- double i31 = rdet*(Entry(2,1)*Entry(3,2)-Entry(2,2)*Entry(3,1));
- double i12 = rdet*(Entry(1,3)*Entry(3,2)-Entry(1,2)*Entry(3,3));
- double i22 = rdet*(Entry(1,1)*Entry(3,3)-Entry(1,3)*Entry(3,1));
- double i32 = rdet*(Entry(1,2)*Entry(3,1)-Entry(1,1)*Entry(3,2));
- double i13 = rdet*(Entry(1,2)*Entry(2,3)-Entry(1,3)*Entry(2,2));
- double i23 = rdet*(Entry(1,3)*Entry(2,1)-Entry(1,1)*Entry(2,3));
- double i33 = rdet*(Entry(1,1)*Entry(2,2)-Entry(1,2)*Entry(2,1));
-
- return FGMatrix33( i11, i12, i13,
- i21, i22, i23,
- i31, i32, i33 );
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGMatrix33::InitMatrix(void)
-{
- data[0] = data[1] = data[2] = data[3] = data[4] = data[5] =
- data[6] = data[7] = data[8] = 0.0;
-}
-
-// *****************************************************************************
-// binary operators ************************************************************
-// *****************************************************************************
-
-FGMatrix33 FGMatrix33::operator-(const FGMatrix33& M) const
-{
- return FGMatrix33( Entry(1,1) - M(1,1),
- Entry(1,2) - M(1,2),
- Entry(1,3) - M(1,3),
- Entry(2,1) - M(2,1),
- Entry(2,2) - M(2,2),
- Entry(2,3) - M(2,3),
- Entry(3,1) - M(3,1),
- Entry(3,2) - M(3,2),
- Entry(3,3) - M(3,3) );
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGMatrix33& FGMatrix33::operator-=(const FGMatrix33 &M)
-{
- data[0] -= M.data[0];
- data[1] -= M.data[1];
- data[2] -= M.data[2];
- data[3] -= M.data[3];
- data[4] -= M.data[4];
- data[5] -= M.data[5];
- data[6] -= M.data[6];
- data[7] -= M.data[7];
- data[8] -= M.data[8];
-
- return *this;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGMatrix33 FGMatrix33::operator+(const FGMatrix33& M) const
-{
- return FGMatrix33( Entry(1,1) + M(1,1),
- Entry(1,2) + M(1,2),
- Entry(1,3) + M(1,3),
- Entry(2,1) + M(2,1),
- Entry(2,2) + M(2,2),
- Entry(2,3) + M(2,3),
- Entry(3,1) + M(3,1),
- Entry(3,2) + M(3,2),
- Entry(3,3) + M(3,3) );
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGMatrix33& FGMatrix33::operator+=(const FGMatrix33 &M)
-{
- Entry(1,1) += M(1,1);
- Entry(1,2) += M(1,2);
- Entry(1,3) += M(1,3);
- Entry(2,1) += M(2,1);
- Entry(2,2) += M(2,2);
- Entry(2,3) += M(2,3);
- Entry(3,1) += M(3,1);
- Entry(3,2) += M(3,2);
- Entry(3,3) += M(3,3);
-
- return *this;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGMatrix33 FGMatrix33::operator*(const double scalar) const
-{
- return FGMatrix33( scalar * Entry(1,1),
- scalar * Entry(1,2),
- scalar * Entry(1,3),
- scalar * Entry(2,1),
- scalar * Entry(2,2),
- scalar * Entry(2,3),
- scalar * Entry(3,1),
- scalar * Entry(3,2),
- scalar * Entry(3,3) );
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGMatrix33 operator*(double scalar, FGMatrix33 &M)
-{
- return FGMatrix33( scalar * M(1,1),
- scalar * M(1,2),
- scalar * M(1,3),
- scalar * M(2,1),
- scalar * M(2,2),
- scalar * M(2,3),
- scalar * M(3,1),
- scalar * M(3,2),
- scalar * M(3,3) );
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGMatrix33& FGMatrix33::operator*=(const double scalar)
-{
- Entry(1,1) *= scalar;
- Entry(1,2) *= scalar;
- Entry(1,3) *= scalar;
- Entry(2,1) *= scalar;
- Entry(2,2) *= scalar;
- Entry(2,3) *= scalar;
- Entry(3,1) *= scalar;
- Entry(3,2) *= scalar;
- Entry(3,3) *= scalar;
-
- return *this;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGMatrix33 FGMatrix33::operator*(const FGMatrix33& M) const
-{
- // FIXME: Make compiler friendlier
- FGMatrix33 Product;
-
- Product(1,1) = Entry(1,1)*M(1,1) + Entry(1,2)*M(2,1) + Entry(1,3)*M(3,1);
- Product(1,2) = Entry(1,1)*M(1,2) + Entry(1,2)*M(2,2) + Entry(1,3)*M(3,2);
- Product(1,3) = Entry(1,1)*M(1,3) + Entry(1,2)*M(2,3) + Entry(1,3)*M(3,3);
- Product(2,1) = Entry(2,1)*M(1,1) + Entry(2,2)*M(2,1) + Entry(2,3)*M(3,1);
- Product(2,2) = Entry(2,1)*M(1,2) + Entry(2,2)*M(2,2) + Entry(2,3)*M(3,2);
- Product(2,3) = Entry(2,1)*M(1,3) + Entry(2,2)*M(2,3) + Entry(2,3)*M(3,3);
- Product(3,1) = Entry(3,1)*M(1,1) + Entry(3,2)*M(2,1) + Entry(3,3)*M(3,1);
- Product(3,2) = Entry(3,1)*M(1,2) + Entry(3,2)*M(2,2) + Entry(3,3)*M(3,2);
- Product(3,3) = Entry(3,1)*M(1,3) + Entry(3,2)*M(2,3) + Entry(3,3)*M(3,3);
-
- return Product;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGMatrix33& FGMatrix33::operator*=(const FGMatrix33& M)
-{
- // FIXME: Make compiler friendlier
- double a,b,c;
-
- a = Entry(1,1); b=Entry(1,2); c=Entry(1,3);
- Entry(1,1) = a*M(1,1) + b*M(2,1) + c*M(3,1);
- Entry(1,2) = a*M(1,2) + b*M(2,2) + c*M(3,2);
- Entry(1,3) = a*M(1,3) + b*M(2,3) + c*M(3,3);
-
- a = Entry(2,1); b=Entry(2,2); c=Entry(2,3);
- Entry(2,1) = a*M(1,1) + b*M(2,1) + c*M(3,1);
- Entry(2,2) = a*M(1,2) + b*M(2,2) + c*M(3,2);
- Entry(2,3) = a*M(1,3) + b*M(2,3) + c*M(3,3);
-
- a = Entry(3,1); b=Entry(3,2); c=Entry(3,3);
- Entry(3,1) = a*M(1,1) + b*M(2,1) + c*M(3,1);
- Entry(3,2) = a*M(1,2) + b*M(2,2) + c*M(3,2);
- Entry(3,3) = a*M(1,3) + b*M(2,3) + c*M(3,3);
-
- return *this;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGMatrix33 FGMatrix33::operator/(const double scalar) const
-{
- FGMatrix33 Quot;
-
- if ( scalar != 0 ) {
- double tmp = 1.0/scalar;
- Quot(1,1) = Entry(1,1) * tmp;
- Quot(1,2) = Entry(1,2) * tmp;
- Quot(1,3) = Entry(1,3) * tmp;
- Quot(2,1) = Entry(2,1) * tmp;
- Quot(2,2) = Entry(2,2) * tmp;
- Quot(2,3) = Entry(2,3) * tmp;
- Quot(3,1) = Entry(3,1) * tmp;
- Quot(3,2) = Entry(3,2) * tmp;
- Quot(3,3) = Entry(3,3) * tmp;
- } else {
- MatrixException mE;
- mE.Message = "Attempt to divide by zero in method FGMatrix33::operator/(const double scalar)";
- throw mE;
- }
- return Quot;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGMatrix33& FGMatrix33::operator/=(const double scalar)
-{
- if ( scalar != 0 ) {
- double tmp = 1.0/scalar;
- Entry(1,1) *= tmp;
- Entry(1,2) *= tmp;
- Entry(1,3) *= tmp;
- Entry(2,1) *= tmp;
- Entry(2,2) *= tmp;
- Entry(2,3) *= tmp;
- Entry(3,1) *= tmp;
- Entry(3,2) *= tmp;
- Entry(3,3) *= tmp;
- } else {
- MatrixException mE;
- mE.Message = "Attempt to divide by zero in method FGMatrix33::operator/=(const double scalar)";
- throw mE;
- }
- return *this;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGMatrix33::T(void)
-{
- for (unsigned int i=1; i<=3; i++) {
- for (unsigned int j=i+1; j<=3; j++) {
- double tmp = Entry(i,j);
- Entry(i,j) = Entry(j,i);
- Entry(j,i) = tmp;
- }
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGColumnVector3 FGMatrix33::operator*(const FGColumnVector3& v) const {
- double tmp1 = v(1)*Entry(1,1);
- double tmp2 = v(1)*Entry(2,1);
- double tmp3 = v(1)*Entry(3,1);
-
- tmp1 += v(2)*Entry(1,2);
- tmp2 += v(2)*Entry(2,2);
- tmp3 += v(2)*Entry(3,2);
-
- tmp1 += v(3)*Entry(1,3);
- tmp2 += v(3)*Entry(2,3);
- tmp3 += v(3)*Entry(3,3);
-
- return FGColumnVector3( tmp1, tmp2, tmp3 );
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGMatrix33::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
-
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGMatrix33" << endl;
- if (from == 1) cout << "Destroyed: FGMatrix33" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-Header: FGMatrix33.h
-Author: Tony Peden, Jon Berndt, Mathias Frolich
-Date started: Unknown
-
-HISTORY
---------------------------------------------------------------------------------
-??/??/?? TP Created
-03/16/2000 JSB Added exception throwing
-03/06/2004 MF Rework of the code to make it a bit compiler friendlier
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGMATRIX33_H
-#define FGMATRIX33_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include <stdlib.h>
-#ifdef FGFS
-# include <math.h>
-# include <simgear/compiler.h>
-# include STL_STRING
-# include STL_FSTREAM
-# include STL_IOSTREAM
- SG_USING_STD(string);
- SG_USING_STD(ostream);
- SG_USING_STD(istream);
- SG_USING_STD(cerr);
- SG_USING_STD(cout);
- SG_USING_STD(endl);
-#else
-# include <string>
-# if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
- include <fstream.h>
- include <iostream.h>
-# include <math.h>
-# else
-# include <fstream>
-# include <iostream>
-# if defined(sgi) && !defined(__GNUC__)
-# include <math.h>
-# else
-# include <cmath>
-# endif
- using std::ostream;
- using std::istream;
- using std::cerr;
- using std::cout;
- using std::endl;
-# endif
- using std::string;
-#endif
-
-#include "FGColumnVector3.h"
-#include "FGJSBBase.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_MATRIX33 "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-class FGColumnVector3;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Exception convenience class.
- */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DECLARATION: MatrixException
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class MatrixException : public FGJSBBase
-{
-public:
- string Message;
-};
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
- /** Handles matrix math operations.
- @author Tony Peden, Jon Berndt, Mathias Froelich
- */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DECLARATION: FGMatrix33
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGMatrix33 : public FGJSBBase
-{
-public:
-
- enum {
- eRows = 3,
- eColumns = 3
- };
-
- /** Default initializer.
- Create a zero matrix. */
- FGMatrix33(void);
-
- /** Copy constructor.
- @param M Matrix which is used for initialization.
- Create copy of the matrix given in the argument. */
- FGMatrix33(const FGMatrix33& M) {
- Entry(1,1) = M.Entry(1,1);
- Entry(2,1) = M.Entry(2,1);
- Entry(3,1) = M.Entry(3,1);
- Entry(1,2) = M.Entry(1,2);
- Entry(2,2) = M.Entry(2,2);
- Entry(3,2) = M.Entry(3,2);
- Entry(1,3) = M.Entry(1,3);
- Entry(2,3) = M.Entry(2,3);
- Entry(3,3) = M.Entry(3,3);
-
- Debug(0);
- }
-
- /** Initialization by given values.
- @param m11 value of the 1,1 Matrix element.
- @param m12 value of the 1,2 Matrix element.
- @param m13 value of the 1,3 Matrix element.
- @param m21 value of the 2,1 Matrix element.
- @param m22 value of the 2,2 Matrix element.
- @param m23 value of the 2,3 Matrix element.
- @param m31 value of the 3,1 Matrix element.
- @param m32 value of the 3,2 Matrix element.
- @param m33 value of the 3,3 Matrix element.
- Create a matrix from the doubles given in the arguments. */
- FGMatrix33(double m11, double m12, double m13,
- double m21, double m22, double m23,
- double m31, double m32, double m33) {
- Entry(1,1) = m11;
- Entry(2,1) = m21;
- Entry(3,1) = m31;
- Entry(1,2) = m12;
- Entry(2,2) = m22;
- Entry(3,2) = m32;
- Entry(1,3) = m13;
- Entry(2,3) = m23;
- Entry(3,3) = m33;
-
- Debug(0);
- }
-
- /// Destructor.
- ~FGMatrix33(void) { Debug(1); }
-
- /** Read access the entries of the matrix.
- @param row Row index.
- @param col Column index.
- @return the value of the matrix entry at the given row and
- column indices. Indices are counted starting with 1. */
- double operator()(unsigned int row, unsigned int col) const {
- return Entry(row, col);
- }
-
- /** Write access the entries of the matrix.
- Note that the indices given in the arguments are unchecked.
- @param row Row index.
- @param col Column index.
- @return a reference to the matrix entry at the given row and
- column indices. Indices are counted starting with 1. */
- double& operator()(unsigned int row, unsigned int col) {
- return Entry(row, col);
- }
-
- /** Read access the entries of the matrix.
- This function is just a shortcut for the @ref double&
- operator()(unsigned int row, unsigned int col) function. It is
- used internally to access the elements in a more convenient way.
- Note that the indices given in the arguments are unchecked.
- @param row Row index.
- @param col Column index.
- @return the value of the matrix entry at the given row and
- column indices. Indices are counted starting with 1. */
- double Entry(unsigned int row, unsigned int col) const {
- return data[(col-1)*eRows+row-1];
- }
-
- /** Write access the entries of the matrix.
- This function is just a shortcut for the @ref double&
- operator()(unsigned int row, unsigned int col) function. It is
- used internally to access the elements in a more convenient way.
- Note that the indices given in the arguments are unchecked.
- @param row Row index.
- @param col Column index.
- @return a reference to the matrix entry at the given row and
- column indices. Indices are counted starting with 1. */
- double& Entry(unsigned int row, unsigned int col) {
- return data[(col-1)*eRows+row-1];
- }
-
- /** Number of rows in the matrix.
- @return the number of rows in the matrix. */
- unsigned int Rows(void) const { return eRows; }
-
- /** Number of cloumns in the matrix.
- @return the number of columns in the matrix. */
- unsigned int Cols(void) const { return eColumns; }
-
- /** Transposed matrix.
- This function only returns the transpose of this matrix. This matrix itself
- remains unchanged.
- @return the transposed matrix. */
- FGMatrix33 Transposed(void) const {
- return FGMatrix33( Entry(1,1), Entry(2,1), Entry(3,1),
- Entry(1,2), Entry(2,2), Entry(3,2),
- Entry(1,3), Entry(2,3), Entry(3,3) );
- }
-
- /** Transposes this matrix.
- This function only transposes this matrix. Nothing is returned. */
- void T(void);
-
-/** Initialize the matrix.
- This function initializes a matrix to all 0.0. */
- void InitMatrix(void);
-
-/** Initialize the matrix.
- This function initializes a matrix to user specified values. */
- void InitMatrix(double m11, double m12, double m13,
- double m21, double m22, double m23,
- double m31, double m32, double m33) {
- Entry(1,1) = m11;
- Entry(2,1) = m21;
- Entry(3,1) = m31;
- Entry(1,2) = m12;
- Entry(2,2) = m22;
- Entry(3,2) = m32;
- Entry(1,3) = m13;
- Entry(2,3) = m23;
- Entry(3,3) = m33;
- }
-
- /** Determinant of the matrix.
- @return the determinant of the matrix. */
- double Determinant(void) const;
-
- /** Return if the matrix is invertible.
- Checks and returns if the matrix is nonsingular and thus
- invertible. This is done by simply computing the determinant and
- check if it is zero. Note that this test does not cover any
- instabilities caused by nearly singular matirces using finite
- arithmetics. It only checks exact singularity. */
- bool Invertible(void) const { return 0.0 != Determinant(); }
-
- /** Return the inverse of the matrix.
- Computes and returns if the inverse of the matrix. It is computed
- by Cramers Rule. Also there are no checks performed if the matrix
- is invertible. If you are not sure that it really is check this
- with the @ref Invertible() call before. */
- FGMatrix33 Inverse(void) const;
-
- /** Assignment operator.
- @param A source matrix.
- Copy the content of the matrix given in the argument into *this. */
- FGMatrix33& operator=(const FGMatrix33& A) {
- data[0] = A.data[0];
- data[1] = A.data[1];
- data[2] = A.data[2];
- data[3] = A.data[3];
- data[4] = A.data[4];
- data[5] = A.data[5];
- data[6] = A.data[6];
- data[7] = A.data[7];
- data[8] = A.data[8];
- return *this;
- }
-
- /** Matrix vector multiplication.
- @param v vector to multiply with.
- @return matric vector product.
- Compute and return the product of the current matrix with the
- vector given in the argument. */
- FGColumnVector3 operator*(const FGColumnVector3& v) const;
-
- /** Matrix subtraction.
- @param B matrix to add to.
- @return difference of the matrices.
- Compute and return the sum of the current matrix and the matrix
- B given in the argument. */
- FGMatrix33 operator-(const FGMatrix33& B) const;
-
- /** Matrix addition.
- @param B matrix to add to.
- @return sum of the matrices.
- Compute and return the sum of the current matrix and the matrix
- B given in the argument. */
- FGMatrix33 operator+(const FGMatrix33& B) const;
-
- /** Matrix product.
- @param B matrix to add to.
- @return product of the matrices.
- Compute and return the product of the current matrix and the matrix
- B given in the argument. */
- FGMatrix33 operator*(const FGMatrix33& B) const;
-
- /** Multiply the matrix with a scalar.
- @param scalar scalar factor to multiply with.
- @return scaled matrix.
- Compute and return the product of the current matrix with the
- scalar value scalar given in the argument. */
- FGMatrix33 operator*(const double scalar) const;
-
- /** Multiply the matrix with 1.0/scalar.
- @param scalar scalar factor to divide through.
- @return scaled matrix.
- Compute and return the product of the current matrix with the
- scalar value 1.0/scalar, where scalar is given in the argument. */
- FGMatrix33 operator/(const double scalar) const;
-
- /** In place matrix subtraction.
- @param B matrix to subtract.
- @return reference to the current matrix.
- Compute the diffence from the current matrix and the matrix B
- given in the argument. */
- FGMatrix33& operator-=(const FGMatrix33 &B);
-
- /** In place matrix addition.
- @param B matrix to add.
- @return reference to the current matrix.
- Compute the sum of the current matrix and the matrix B
- given in the argument. */
- FGMatrix33& operator+=(const FGMatrix33 &B);
-
- /** In place matrix multiplication.
- @param B matrix to multiply with.
- @return reference to the current matrix.
- Compute the product of the current matrix and the matrix B
- given in the argument. */
- FGMatrix33& operator*=(const FGMatrix33 &B);
-
- /** In place matrix scale.
- @param scalar scalar value to multiply with.
- @return reference to the current matrix.
- Compute the product of the current matrix and the scalar value scalar
- given in the argument. */
- FGMatrix33& operator*=(const double scalar);
-
- /** In place matrix scale.
- @param scalar scalar value to divide through.
- @return reference to the current matrix.
- Compute the product of the current matrix and the scalar value
- 1.0/scalar, where scalar is given in the argument. */
- FGMatrix33& operator/=(const double scalar);
-
-private:
- double data[eRows*eColumns];
-
- void Debug(int from);
-};
-
-/** Scalar multiplication.
- @param scalar scalar value to multiply with.
- @param A Matrix to multiply.
- Multiply the Matrix with a scalar value.*/
-inline FGMatrix33 operator*(double scalar, const FGMatrix33& A) {
- // use already defined operation.
- return A*scalar;
-}
-
-/** Write matrix to a stream.
- @param os Stream to write to.
- @param M Matrix to write.
- Write the matrix to a stream.*/
-ostream& operator<<(ostream& os, const FGMatrix33& M);
-
-/** Read matrix from a stream.
- @param os Stream to read from.
- @param M Matrix to initialize with the values from the stream.
- Read matrix from a stream.*/
-istream& operator>>(istream& is, FGMatrix33& M);
-
-} // namespace JSBSim
-
-#endif
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGModel.cpp
- Author: Jon Berndt
- Date started: 11/11/98
- Purpose: Base class for all models
- Called by: FGSimExec, et. al.
-
- ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-This base class for the FGAerodynamics, FGPropagate, etc. classes defines methods
-common to all models.
-
-HISTORY
---------------------------------------------------------------------------------
-11/11/98 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGModel.h"
-#include "FGState.h"
-#include "FGFDMExec.h"
-#include "FGAtmosphere.h"
-#include "FGFCS.h"
-#include "FGPropulsion.h"
-#include "FGMassBalance.h"
-#include "FGAerodynamics.h"
-#include "FGInertial.h"
-#include "FGGroundReactions.h"
-#include "FGAircraft.h"
-#include "FGPropagate.h"
-#include "FGAuxiliary.h"
-#include "FGOutput.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_MODEL;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-GLOBAL DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-FGModel::FGModel(FGFDMExec* fdmex)
-{
- FDMExec = fdmex;
- NextModel = 0L;
-
- State = 0;
- Atmosphere = 0;
- FCS = 0;
- Propulsion = 0;
- MassBalance = 0;
- Aerodynamics = 0;
- Inertial = 0;
- GroundReactions = 0;
- Aircraft = 0;
- Propagate = 0;
- Auxiliary = 0;
- Output = 0;
-
- //in order for FGModel derived classes to self-bind (that is, call
- //their bind function in the constructor, the PropertyManager pointer
- //must be brought up now.
- PropertyManager = FDMExec->GetPropertyManager();
-
- exe_ctr = 1;
- rate = 1;
-
- if (debug_lvl & 2) cout << " FGModel Base Class" << endl;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGModel::~FGModel()
-{
- if (debug_lvl & 2) cout << "Destroyed: FGModel" << endl;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGModel::InitModel(void)
-{
- State = FDMExec->GetState();
- Atmosphere = FDMExec->GetAtmosphere();
- FCS = FDMExec->GetFCS();
- Propulsion = FDMExec->GetPropulsion();
- MassBalance = FDMExec->GetMassBalance();
- Aerodynamics = FDMExec->GetAerodynamics();
- Inertial = FDMExec->GetInertial();
- GroundReactions = FDMExec->GetGroundReactions();
- Aircraft = FDMExec->GetAircraft();
- Propagate = FDMExec->GetPropagate();
- Auxiliary = FDMExec->GetAuxiliary();
- Output = FDMExec->GetOutput();
-
- if (!State ||
- !Atmosphere ||
- !FCS ||
- !Propulsion ||
- !MassBalance ||
- !Aerodynamics ||
- !Inertial ||
- !GroundReactions ||
- !Aircraft ||
- !Propagate ||
- !Auxiliary ||
- !Output) return(false);
- else return(true);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGModel::Run()
-{
- if (debug_lvl & 4) cout << "Entering Run() for model " << Name << endl;
-
- if (exe_ctr == 1) {
- if (exe_ctr++ >= rate) exe_ctr = 1;
- return false;
- } else {
- if (exe_ctr++ >= rate) exe_ctr = 1;
- return true;
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGModel::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
-
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGModel" << endl;
- if (from == 1) cout << "Destroyed: FGModel" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGModel.h
- Author: Jon Berndt
- Date started: 11/21/98
-
- ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-11/22/98 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGMODEL_H
-#define FGMODEL_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGJSBBase.h"
-#include "FGPropertyManager.h"
-
-#ifdef FGFS
-# include <simgear/compiler.h>
-# ifdef SG_HAVE_STD_INCLUDES
-# include <iostream>
-# else
-# include <iostream.h>
-# endif
-#else
-# if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
-# include <iostream.h>
-# else
-# include <iostream>
-# endif
-#endif
-
-#include <string>
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_MODEL "$Id$"
-
-using namespace std;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-class FGFDMExec;
-class FGState;
-class FGAtmosphere;
-class FGFCS;
-class FGPropulsion;
-class FGMassBalance;
-class FGAerodynamics;
-class FGInertial;
-class FGGroundReactions;
-class FGAircraft;
-class FGPropagate;
-class FGAuxiliary;
-class FGOutput;
-class FGConfigFile;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Base class for all scheduled JSBSim models
- @author Jon S. Berndt
- */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGModel : public FGJSBBase
-{
-public:
-
- /// Constructor
- FGModel(FGFDMExec*);
- /// Destructor
- virtual ~FGModel();
-
- /** Loads this model.
- @param Config a pointer to the config file instance
- @return true if model is successfully loaded*/
- virtual bool Load(FGConfigFile* Config) {return true;}
-
- FGModel* NextModel;
- string Name;
-
- /** Runs the model; called by the Executive
- @see JSBSim.cpp documentation
- @return false if no error */
- virtual bool Run(void);
- virtual bool InitModel(void);
- virtual void SetRate(int tt) {rate = tt;}
- virtual int GetRate(void) {return rate;}
-
- void SetPropertyManager(FGPropertyManager *fgpm) { PropertyManager=fgpm;}
-
-protected:
- int exe_ctr;
- int rate;
-
- virtual void Debug(int from);
-
- FGFDMExec* FDMExec;
- FGState* State;
- FGAtmosphere* Atmosphere;
- FGFCS* FCS;
- FGPropulsion* Propulsion;
- FGMassBalance* MassBalance;
- FGAerodynamics* Aerodynamics;
- FGInertial* Inertial;
- FGGroundReactions* GroundReactions;
- FGAircraft* Aircraft;
- FGPropagate* Propagate;
- FGAuxiliary* Auxiliary;
- FGOutput* Output;
- FGPropertyManager* PropertyManager;
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
-
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGNozzle.cpp
- Author: Jon S. Berndt
- Date started: 08/24/00
- Purpose: Encapsulates the nozzle object
-
- ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-HISTORY
---------------------------------------------------------------------------------
-08/24/00 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <sstream>
-
-#include "FGNozzle.h"
-#include "FGAtmosphere.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_NOZZLE;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-
-FGNozzle::FGNozzle(FGFDMExec* FDMExec, FGConfigFile* Nzl_cfg, int num) : FGThruster(FDMExec)
-{
- string token;
-
- Name = Nzl_cfg->GetValue("NAME");
- Nzl_cfg->GetNextConfigLine();
- while (Nzl_cfg->GetValue() != string("/FG_NOZZLE")) {
- *Nzl_cfg >> token;
- if (token == "PE") *Nzl_cfg >> PE;
- else if (token == "EXPR") *Nzl_cfg >> ExpR;
- else if (token == "NZL_EFF") *Nzl_cfg >> nzlEff;
- else if (token == "DIAM") *Nzl_cfg >> Diameter;
- else cerr << "Unhandled token in Nozzle config file: " << token << endl;
- }
-
- Thrust = 0;
- Type = ttNozzle;
- Area2 = (Diameter*Diameter/4.0)*M_PI;
- AreaT = Area2/ExpR;
-
- char property_name[80];
- snprintf(property_name, 80, "propulsion/c-thrust[%u]", EngineNum);
- PropertyManager->Tie( property_name, &ThrustCoeff );
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGNozzle::~FGNozzle()
-{
- char property_name[80];
- snprintf(property_name, 80, "propulsion/c-thrust[%u]", EngineNum);
- PropertyManager->Untie( property_name );
-
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGNozzle::Calculate(double CfPc)
-{
- double pAtm = fdmex->GetAtmosphere()->GetPressure();
- Thrust = max((double)0.0, (CfPc * AreaT + (PE - pAtm)*Area2) * nzlEff);
- vFn(1) = Thrust;
-
- ThrustCoeff = max((double)0.0, CfPc / ((pAtm - PE) * Area2));
-
- return Thrust;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGNozzle::GetPowerRequired(void)
-{
- return PE;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGNozzle::GetThrusterLabels(int id, string delimeter)
-{
- std::ostringstream buf;
-
- buf << Name << "_Thrust[" << id << ']';
-
- return buf.str();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGNozzle::GetThrusterValues(int id, string delimeter)
-{
- std::ostringstream buf;
-
- buf << Thrust;
-
- return buf.str();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGNozzle::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
- cout << " Nozzle Name: " << Name << endl;
- cout << " Nozzle Exit Pressure = " << PE << endl;
- cout << " Nozzle Expansion Ratio = " << ExpR << endl;
- cout << " Nozzle Efficiency = " << nzlEff << endl;
- cout << " Nozzle Diameter = " << Diameter << endl;
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGNozzle" << endl;
- if (from == 1) cout << "Destroyed: FGNozzle" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGNozzle.h
- Author: Jon S. Berndt
- Date started: 08/24/00
-
- ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-08/24/00 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGNOZZLE_H
-#define FGNOZZLE_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGThruster.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_NOZZLE "$Id$";
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Models a rocket nozzle.
- @author Jon S. Berndt
- @version $Id$
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGNozzle : public FGThruster {
-
-public:
- /// Constructor
- FGNozzle(FGFDMExec* exec, FGConfigFile* AC_cfg, int num = 0);
- /// Destructor
- ~FGNozzle();
-
- double Calculate(double CfPc);
- double GetPowerRequired(void);
- string GetThrusterLabels(int id, string delimeter);
- string GetThrusterValues(int id, string delimeter);
-
-private:
-
- double PE;
- double ExpR;
- double nzlEff;
- double Diameter;
- double AreaT;
- double Area2;
- void Debug(int from);
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
-
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGOutput.cpp
- Author: Jon Berndt
- Date started: 12/02/98
- Purpose: Manage output of sim parameters to file or stdout
- Called by: FGSimExec
-
- ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-This is the place where you create output routines to dump data for perusal
-later.
-
-HISTORY
---------------------------------------------------------------------------------
-12/02/98 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGOutput.h"
-#include "FGState.h"
-#include "FGFDMExec.h"
-#include "FGAtmosphere.h"
-#include "FGFCS.h"
-#include "FGAerodynamics.h"
-#include "FGGroundReactions.h"
-#include "FGAircraft.h"
-#include "FGMassBalance.h"
-#include "FGPropagate.h"
-#include "FGAuxiliary.h"
-#include "FGInertial.h"
-
-#include <iomanip>
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_OUTPUT;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-FGOutput::FGOutput(FGFDMExec* fdmex) : FGModel(fdmex)
-{
- Name = "FGOutput";
- sFirstPass = dFirstPass = true;
- socket = 0;
- Type = otNone;
- Filename = "";
- SubSystems = 0;
- enabled = true;
- outputInFileName = "";
- delimeter = ", ";
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGOutput::~FGOutput()
-{
- if (socket) delete socket;
- for (unsigned int i=0; i<OutputProperties.size(); i++) delete OutputProperties[i];
-
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGOutput::Run(void)
-{
- if (enabled) {
- if (FGModel::Run()) return true;
- if (Type == otSocket) {
- SocketOutput();
- } else if (Type == otCSV || Type == otTab) {
- DelimitedOutput(Filename);
- } else if (Type == otTerminal) {
- // Not done yet
- } else if (Type == otNone) {
- // Do nothing
- } else {
- // Not a valid type of output
- }
- }
- return false;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGOutput::SetType(string type)
-{
- if (type == "CSV") {
- Type = otCSV;
- delimeter = ", ";
- } else if (type == "TABULAR") {
- Type = otTab;
- delimeter = "\t";
- } else if (type == "SOCKET") {
- Type = otSocket;
- } else if (type == "TERMINAL") {
- Type = otTerminal;
- } else if (type != string("NONE")) {
- Type = otUnknown;
- cerr << "Unknown type of output specified in config file" << endl;
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGOutput::DelimitedOutput(string fname)
-{
- streambuf* buffer;
- string scratch = "";
-
- if (fname == "COUT" || fname == "cout") {
- buffer = cout.rdbuf();
- } else {
- datafile.open(fname.c_str());
- buffer = datafile.rdbuf();
- }
-
- ostream outstream(buffer);
-
- if (dFirstPass) {
- outstream << "Time";
- if (SubSystems & ssSimulation) {
- // Nothing here, yet
- }
- if (SubSystems & ssAerosurfaces) {
- outstream << delimeter;
- outstream << "Aileron Cmd" + delimeter;
- outstream << "Elevator Cmd" + delimeter;
- outstream << "Rudder Cmd" + delimeter;
- outstream << "Flap Cmd" + delimeter;
- outstream << "Left Aileron Pos" + delimeter;
- outstream << "Right Aileron Pos" + delimeter;
- outstream << "Elevator Pos" + delimeter;
- outstream << "Rudder Pos" + delimeter;
- outstream << "Flap Pos";
- }
- if (SubSystems & ssRates) {
- outstream << delimeter;
- outstream << "P" + delimeter + "Q" + delimeter + "R" + delimeter;
- outstream << "Pdot" + delimeter + "Qdot" + delimeter + "Rdot";
- }
- if (SubSystems & ssVelocities) {
- outstream << delimeter;
- outstream << "QBar" + delimeter;
- outstream << "Vtotal" + delimeter;
- outstream << "UBody" + delimeter + "VBody" + delimeter + "WBody" + delimeter;
- outstream << "UAero" + delimeter + "VAero" + delimeter + "WAero" + delimeter;
- outstream << "Vn" + delimeter + "Ve" + delimeter + "Vd";
- }
- if (SubSystems & ssForces) {
- outstream << delimeter;
- outstream << "Drag" + delimeter + "Side" + delimeter + "Lift" + delimeter;
- outstream << "L/D" + delimeter;
- outstream << "Xforce" + delimeter + "Yforce" + delimeter + "Zforce";
- }
- if (SubSystems & ssMoments) {
- outstream << delimeter;
- outstream << "L" + delimeter + "M" + delimeter + "N";
- }
- if (SubSystems & ssAtmosphere) {
- outstream << delimeter;
- outstream << "Rho" + delimeter;
- outstream << "NWind" + delimeter + "EWind" + delimeter + "DWind";
- }
- if (SubSystems & ssMassProps) {
- outstream << delimeter;
- outstream << "Ixx" + delimeter;
- outstream << "Ixy" + delimeter;
- outstream << "Ixz" + delimeter;
- outstream << "Iyx" + delimeter;
- outstream << "Iyy" + delimeter;
- outstream << "Iyz" + delimeter;
- outstream << "Izx" + delimeter;
- outstream << "Izy" + delimeter;
- outstream << "Izz" + delimeter;
- outstream << "Mass" + delimeter;
- outstream << "Xcg" + delimeter + "Ycg" + delimeter + "Zcg";
- }
- if (SubSystems & ssPropagate) {
- outstream << delimeter;
- outstream << "Altitude" + delimeter;
- outstream << "Phi" + delimeter + "Tht" + delimeter + "Psi" + delimeter;
- outstream << "Alpha" + delimeter;
- outstream << "Beta" + delimeter;
- outstream << "Latitude (Deg)" + delimeter;
- outstream << "Longitude (Deg)" + delimeter;
- outstream << "Distance AGL" + delimeter;
- outstream << "Runway Radius";
- }
- if (SubSystems & ssCoefficients) {
- scratch = Aerodynamics->GetCoefficientStrings(delimeter);
- if (scratch.length() != 0) outstream << delimeter << scratch;
- }
- if (SubSystems & ssFCS) {
- scratch = FCS->GetComponentStrings(delimeter);
- if (scratch.length() != 0) outstream << delimeter << scratch;
- }
- if (SubSystems & ssGroundReactions) {
- outstream << delimeter;
- outstream << GroundReactions->GetGroundReactionStrings(delimeter);
- }
- if (SubSystems & ssPropulsion && Propulsion->GetNumEngines() > 0) {
- outstream << delimeter;
- outstream << Propulsion->GetPropulsionStrings(delimeter);
- }
- if (OutputProperties.size() > 0) {
- for (unsigned int i=0;i<OutputProperties.size();i++) {
- outstream << delimeter << OutputProperties[i]->GetName();
- }
- }
-
- outstream << endl;
- dFirstPass = false;
- }
-
- outstream << State->Getsim_time();
- if (SubSystems & ssSimulation) {
- }
- if (SubSystems & ssAerosurfaces) {
- outstream << delimeter;
- outstream << FCS->GetDaCmd() << delimeter;
- outstream << FCS->GetDeCmd() << delimeter;
- outstream << FCS->GetDrCmd() << delimeter;
- outstream << FCS->GetDfCmd() << delimeter;
- outstream << FCS->GetDaLPos() << delimeter;
- outstream << FCS->GetDaRPos() << delimeter;
- outstream << FCS->GetDePos() << delimeter;
- outstream << FCS->GetDrPos() << delimeter;
- outstream << FCS->GetDfPos();
- }
- if (SubSystems & ssRates) {
- outstream << delimeter;
- outstream << Propagate->GetPQR().Dump(delimeter) << delimeter;
- outstream << Propagate->GetPQRdot().Dump(delimeter);
- }
- if (SubSystems & ssVelocities) {
- outstream << delimeter;
- outstream << Auxiliary->Getqbar() << delimeter;
- outstream << setprecision(12) << Auxiliary->GetVt() << delimeter;
- outstream << setprecision(12) << Propagate->GetUVW().Dump(delimeter) << delimeter;
- outstream << Auxiliary->GetAeroUVW().Dump(delimeter) << delimeter;
- outstream << Propagate->GetVel().Dump(delimeter);
- }
- if (SubSystems & ssForces) {
- outstream << delimeter;
- outstream << Aerodynamics->GetvFs() << delimeter;
- outstream << Aerodynamics->GetLoD() << delimeter;
- outstream << Aircraft->GetForces().Dump(delimeter);
- }
- if (SubSystems & ssMoments) {
- outstream << delimeter;
- outstream << Aircraft->GetMoments().Dump(delimeter);
- }
- if (SubSystems & ssAtmosphere) {
- outstream << delimeter;
- outstream << Atmosphere->GetDensity() << delimeter;
- outstream << Atmosphere->GetWindNED().Dump(delimeter);
- }
- if (SubSystems & ssMassProps) {
- outstream << delimeter;
- outstream << MassBalance->GetJ() << delimeter;
- outstream << MassBalance->GetMass() << delimeter;
- outstream << MassBalance->GetXYZcg();
- }
- if (SubSystems & ssPropagate) {
- outstream << delimeter;
- outstream << Propagate->Geth() << delimeter;
- outstream << Propagate->GetEuler().Dump(delimeter) << delimeter;
- outstream << Auxiliary->Getalpha(inDegrees) << delimeter;
- outstream << Auxiliary->Getbeta(inDegrees) << delimeter;
- outstream << Propagate->GetLocation().GetLatitudeDeg() << delimeter;
- outstream << Propagate->GetLocation().GetLongitudeDeg() << delimeter;
- outstream << Propagate->GetDistanceAGL() << delimeter;
- outstream << Propagate->GetRunwayRadius();
- }
- if (SubSystems & ssCoefficients) {
- scratch = Aerodynamics->GetCoefficientValues(delimeter);
- if (scratch.length() != 0) outstream << delimeter << scratch;
- }
- if (SubSystems & ssFCS) {
- scratch = FCS->GetComponentValues(delimeter);
- if (scratch.length() != 0) outstream << delimeter << scratch;
- }
- if (SubSystems & ssGroundReactions) {
- outstream << delimeter;
- outstream << GroundReactions->GetGroundReactionValues(delimeter);
- }
- if (SubSystems & ssPropulsion && Propulsion->GetNumEngines() > 0) {
- outstream << delimeter;
- outstream << Propulsion->GetPropulsionValues(delimeter);
- }
-
- for (unsigned int i=0;i<OutputProperties.size();i++) {
- outstream << delimeter << OutputProperties[i]->getDoubleValue();
- }
-
- outstream << endl;
- outstream.flush();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGOutput::SocketOutput(void)
-{
- string asciiData;
-
- if (socket == NULL) return;
- if (!socket->GetConnectStatus()) return;
-
- socket->Clear();
- if (sFirstPass) {
- socket->Append("<LABELS>");
- socket->Append("Time");
- socket->Append("Altitude");
- socket->Append("Phi");
- socket->Append("Tht");
- socket->Append("Psi");
- socket->Append("Rho");
- socket->Append("Vtotal");
- socket->Append("UBody");
- socket->Append("VBody");
- socket->Append("WBody");
- socket->Append("UAero");
- socket->Append("VAero");
- socket->Append("WAero");
- socket->Append("Vn");
- socket->Append("Ve");
- socket->Append("Vd");
- socket->Append("Udot");
- socket->Append("Vdot");
- socket->Append("Wdot");
- socket->Append("P");
- socket->Append("Q");
- socket->Append("R");
- socket->Append("PDot");
- socket->Append("QDot");
- socket->Append("RDot");
- socket->Append("Fx");
- socket->Append("Fy");
- socket->Append("Fz");
- socket->Append("Latitude (Deg)");
- socket->Append("Longitude (Deg)");
- socket->Append("QBar");
- socket->Append("Alpha");
- socket->Append("L");
- socket->Append("M");
- socket->Append("N");
- socket->Append("Throttle Position");
- socket->Append("Left Aileron Position");
- socket->Append("Right Aileron Position");
- socket->Append("Elevator Position");
- socket->Append("Rudder Position");
- sFirstPass = false;
- socket->Send();
- }
-
- socket->Clear();
- socket->Append(State->Getsim_time());
- socket->Append(Propagate->Geth());
- socket->Append(Propagate->GetEuler(ePhi));
- socket->Append(Propagate->GetEuler(eTht));
- socket->Append(Propagate->GetEuler(ePsi));
- socket->Append(Atmosphere->GetDensity());
- socket->Append(Auxiliary->GetVt());
- socket->Append(Propagate->GetUVW(eU));
- socket->Append(Propagate->GetUVW(eV));
- socket->Append(Propagate->GetUVW(eW));
- socket->Append(Auxiliary->GetAeroUVW(eU));
- socket->Append(Auxiliary->GetAeroUVW(eV));
- socket->Append(Auxiliary->GetAeroUVW(eW));
- socket->Append(Propagate->GetVel(eNorth));
- socket->Append(Propagate->GetVel(eEast));
- socket->Append(Propagate->GetVel(eDown));
- socket->Append(Propagate->GetUVWdot(eU));
- socket->Append(Propagate->GetUVWdot(eV));
- socket->Append(Propagate->GetUVWdot(eW));
- socket->Append(Propagate->GetPQR(eP));
- socket->Append(Propagate->GetPQR(eQ));
- socket->Append(Propagate->GetPQR(eR));
- socket->Append(Propagate->GetPQRdot(eP));
- socket->Append(Propagate->GetPQRdot(eQ));
- socket->Append(Propagate->GetPQRdot(eR));
- socket->Append(Aircraft->GetForces(eX));
- socket->Append(Aircraft->GetForces(eY));
- socket->Append(Aircraft->GetForces(eZ));
- socket->Append(Propagate->GetLocation().GetLatitudeDeg());
- socket->Append(Propagate->GetLocation().GetLongitudeDeg());
- socket->Append(Auxiliary->Getqbar());
- socket->Append(Auxiliary->Getalpha(inDegrees));
- socket->Append(Aircraft->GetMoments(eL));
- socket->Append(Aircraft->GetMoments(eM));
- socket->Append(Aircraft->GetMoments(eN));
- socket->Append(FCS->GetThrottlePos(0));
- socket->Append(FCS->GetDaLPos());
- socket->Append(FCS->GetDaRPos());
- socket->Append(FCS->GetDePos());
- socket->Append(FCS->GetDrPos());
- socket->Send();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGOutput::SocketStatusOutput(string out_str)
-{
- string asciiData;
-
- if (socket == NULL) return;
-
- socket->Clear();
- asciiData = string("<STATUS>") + out_str;
- socket->Append(asciiData.c_str());
- socket->Send();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGOutput::Load(FGConfigFile* AC_cfg)
-{
- string token="", parameter="", separator="";
- string name="", fname="";
- int OutRate = 0;
- FGConfigFile* Output_cfg;
- string property;
- unsigned int port;
-
-# ifndef macintosh
- separator = "/";
-# else
- separator = ";";
-# endif
-
- name = AC_cfg->GetValue("NAME");
- fname = AC_cfg->GetValue("FILE");
- token = AC_cfg->GetValue("TYPE");
- port = atoi(AC_cfg->GetValue("PORT").c_str());
-
- Output->SetType(token);
-
- if (token == "SOCKET") {
- socket = new FGfdmSocket(name,port);
- }
-
- if (!fname.empty()) {
- outputInFileName = FDMExec->GetAircraftPath() + separator
- + FDMExec->GetModelName() + separator + fname + ".xml";
- Output_cfg = new FGConfigFile(outputInFileName);
- if (!Output_cfg->IsOpen()) {
- cerr << "Could not open file: " << outputInFileName << endl;
- return false;
- }
- } else {
- Output_cfg = AC_cfg;
- }
- Output->SetFilename(name);
-
- while ((token = Output_cfg->GetValue()) != string("/OUTPUT")) {
- *Output_cfg >> parameter;
- if (parameter == "RATE_IN_HZ") {
- *Output_cfg >> OutRate;
- }
- if (parameter == "SIMULATION") {
- *Output_cfg >> parameter;
- if (parameter == "ON") SubSystems += ssSimulation;
- }
- if (parameter == "AEROSURFACES") {
- *Output_cfg >> parameter;
- if (parameter == "ON") SubSystems += ssAerosurfaces;
- }
- if (parameter == "RATES") {
- *Output_cfg >> parameter;
- if (parameter == "ON") SubSystems += ssRates;
- }
- if (parameter == "VELOCITIES") {
- *Output_cfg >> parameter;
- if (parameter == "ON") SubSystems += ssVelocities;
- }
- if (parameter == "FORCES") {
- *Output_cfg >> parameter;
- if (parameter == "ON") SubSystems += ssForces;
- }
- if (parameter == "MOMENTS") {
- *Output_cfg >> parameter;
- if (parameter == "ON") SubSystems += ssMoments;
- }
- if (parameter == "ATMOSPHERE") {
- *Output_cfg >> parameter;
- if (parameter == "ON") SubSystems += ssAtmosphere;
- }
- if (parameter == "MASSPROPS") {
- *Output_cfg >> parameter;
- if (parameter == "ON") SubSystems += ssMassProps;
- }
- if (parameter == "POSITION") {
- *Output_cfg >> parameter;
- if (parameter == "ON") SubSystems += ssPropagate;
- }
- if (parameter == "COEFFICIENTS") {
- *Output_cfg >> parameter;
- if (parameter == "ON") SubSystems += ssCoefficients;
- }
- if (parameter == "GROUND_REACTIONS") {
- *Output_cfg >> parameter;
- if (parameter == "ON") SubSystems += ssGroundReactions;
- }
- if (parameter == "FCS") {
- *Output_cfg >> parameter;
- if (parameter == "ON") SubSystems += ssFCS;
- }
- if (parameter == "PROPULSION") {
- *Output_cfg >> parameter;
- if (parameter == "ON") SubSystems += ssPropulsion;
- }
- if (parameter == "PROPERTY") {
- *Output_cfg >> property;
- OutputProperties.push_back(PropertyManager->GetNode(property));
- }
-
- if (parameter == "EOF") break;
- }
-
- OutRate = OutRate>120?120:(OutRate<0?0:OutRate);
- rate = (int)(0.5 + 1.0/(State->Getdt()*OutRate));
-
- Debug(2);
-
- return true;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGOutput::Debug(int from)
-{
- string scratch="";
-
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
-
- }
- if (from == 2) {
- if (outputInFileName.empty())
- cout << " " << "Output parameters read inline" << endl;
- else
- cout << " Output parameters read from file: " << outputInFileName << endl;
-
- if (Filename == "cout" || Filename == "COUT") {
- scratch = " Log output goes to screen console";
- } else if (!Filename.empty()) {
- scratch = " Log output goes to file: " + Filename;
- }
- switch (Type) {
- case otCSV:
- cout << scratch << " in CSV format output at rate " << 120/rate << " Hz" << endl;
- break;
- case otNone:
- cout << " No log output" << endl;
- break;
- }
-
- if (SubSystems & ssSimulation) cout << " Simulation parameters logged" << endl;
- if (SubSystems & ssAerosurfaces) cout << " Aerosurface parameters logged" << endl;
- if (SubSystems & ssRates) cout << " Rate parameters logged" << endl;
- if (SubSystems & ssVelocities) cout << " Velocity parameters logged" << endl;
- if (SubSystems & ssForces) cout << " Force parameters logged" << endl;
- if (SubSystems & ssMoments) cout << " Moments parameters logged" << endl;
- if (SubSystems & ssAtmosphere) cout << " Atmosphere parameters logged" << endl;
- if (SubSystems & ssMassProps) cout << " Mass parameters logged" << endl;
- if (SubSystems & ssCoefficients) cout << " Coefficient parameters logged" << endl;
- if (SubSystems & ssPropagate) cout << " Propagate parameters logged" << endl;
- if (SubSystems & ssGroundReactions) cout << " Ground parameters logged" << endl;
- if (SubSystems & ssFCS) cout << " FCS parameters logged" << endl;
- if (SubSystems & ssPropulsion) cout << " Propulsion parameters logged" << endl;
- if (OutputProperties.size() > 0) cout << " Properties logged:" << endl;
- for (unsigned int i=0;i<OutputProperties.size();i++) {
- cout << " - " << OutputProperties[i]->GetName() << endl;
- }
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGOutput" << endl;
- if (from == 1) cout << "Destroyed: FGOutput" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGOutput.h
- Author: Jon Berndt
- Date started: 12/2/98
-
- ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-12/02/98 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGOUTPUT_H
-#define FGOUTPUT_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGModel.h"
-
-#ifdef FGFS
-# include <simgear/compiler.h>
-# include STL_IOSTREAM
-# include STL_FSTREAM
-#else
-# if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
-# include <iostream.h>
-# include <fstream.h>
-# else
-# include <iostream>
-# include <fstream>
-# endif
-#endif
-
-#include "FGfdmSocket.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_OUTPUT "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Handles simulation output.
- OUTPUT section definition
-
- The following specifies the way that JSBSim writes out data.
-
- NAME is the filename you want the output to go to
-
- TYPE can be:
- CSV Comma separated data. If a filename is supplied then the data
- goes to that file. If COUT or cout is specified, the data goes
- to stdout. If the filename is a null filename the data goes to
- stdout, as well.
- SOCKET Will eventually send data to a socket output, where NAME
- would then be the IP address of the machine the data should be
- sent to. DON'T USE THIS YET!
- TABULAR Columnar data. NOT IMPLEMENTED YET!
- TERMINAL Output to terminal. NOT IMPLEMENTED YET!
- NONE Specifies to do nothing. THis setting makes it easy to turn on and
- off the data output without having to mess with anything else.
-
- The arguments that can be supplied, currently, are
-
- RATE_IN_HZ An integer rate in times-per-second that the data is output. This
- value may not be *exactly* what you want, due to the dependence
- on dt, the cycle rate for the FDM.
-
- The following parameters tell which subsystems of data to output:
-
- SIMULATION ON|OFF
- ATMOSPHERE ON|OFF
- MASSPROPS ON|OFF
- AEROSURFACES ON|OFF
- RATES ON|OFF
- VELOCITIES ON|OFF
- FORCES ON|OFF
- MOMENTS ON|OFF
- POSITION ON|OFF
- COEFFICIENTS ON|OFF
- GROUND_REACTIONS ON|OFF
- FCS ON|OFF
- PROPULSION ON|OFF
-
- NOTE that Time is always output with the data.
- @version $Id$
- */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGOutput : public FGModel
-{
-public:
- FGOutput(FGFDMExec*);
- ~FGOutput();
-
- bool Run(void);
-
- void DelimitedOutput(string);
- void SocketOutput(void);
- void SocketStatusOutput(string);
- void SetFilename(string fn) {Filename = fn;}
- void SetType(string);
- void SetSubsystems(int tt) {SubSystems = tt;}
- inline void Enable(void) { enabled = true; }
- inline void Disable(void) { enabled = false; }
- inline bool Toggle(void) {enabled = !enabled; return enabled;}
- bool Load(FGConfigFile* AC_cfg);
-
- /// Subsystem types for specifying which will be output in the FDM data logging
- enum eSubSystems {
- /** Subsystem: Simulation (= 1) */ ssSimulation = 1,
- /** Subsystem: Aerosurfaces (= 2) */ ssAerosurfaces = 2,
- /** Subsystem: Body rates (= 4) */ ssRates = 4,
- /** Subsystem: Velocities (= 8) */ ssVelocities = 8,
- /** Subsystem: Forces (= 16) */ ssForces = 16,
- /** Subsystem: Moments (= 32) */ ssMoments = 32,
- /** Subsystem: Atmosphere (= 64) */ ssAtmosphere = 64,
- /** Subsystem: Mass Properties (= 128) */ ssMassProps = 128,
- /** Subsystem: Coefficients (= 256) */ ssCoefficients = 256,
- /** Subsystem: Propagate (= 512) */ ssPropagate = 512,
- /** Subsystem: Ground Reactions (= 1024) */ ssGroundReactions = 1024,
- /** Subsystem: FCS (= 2048) */ ssFCS = 2048,
- /** Subsystem: Propulsion (= 4096) */ ssPropulsion = 4096
- } subsystems;
-
-private:
- bool sFirstPass, dFirstPass, enabled;
- int SubSystems;
- string Filename, outputInFileName, delimeter;
- enum {otNone, otCSV, otTab, otSocket, otTerminal, otUnknown} Type;
- ofstream datafile;
- FGfdmSocket* socket;
- vector <FGPropertyManager*> OutputProperties;
- void Debug(int from);
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
-
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGPiston.cpp
- Author: Jon S. Berndt, JSBSim framework
- Dave Luff, Piston engine model
- Date started: 09/12/2000
- Purpose: This module models a Piston engine
-
- ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) --------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-This class descends from the FGEngine class and models a Piston engine based on
-parameters given in the engine config file for this class
-
-HISTORY
---------------------------------------------------------------------------------
-09/12/2000 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <sstream>
-
-#include "FGPiston.h"
-#include "FGPropulsion.h"
-#include "FGPropeller.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_PISTON;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-FGPiston::FGPiston(FGFDMExec* exec, FGConfigFile* Eng_cfg, int engine_number)
- : FGEngine(exec, engine_number),
- R_air(287.3),
- rho_fuel(800), // estimate
- calorific_value_fuel(47.3e6),
- Cp_air(1005),
- Cp_fuel(1700)
-{
- string token;
-
- Type = etPiston;
- crank_counter = 0;
- OilTemp_degK = 298;
- MinManifoldPressure_inHg = 6.5;
- MaxManifoldPressure_inHg = 28.5;
- ManifoldPressure_inHg = Atmosphere->GetPressure() * psftoinhg; // psf to in Hg
- minMAP = 21950;
- maxMAP = 96250;
- MAP = Atmosphere->GetPressure() * 47.88; // psf to Pa
- CylinderHeadTemp_degK = 0.0;
- Displacement = 360;
- MaxHP = 0;
- Cycles = 2;
- IdleRPM = 600;
- Magnetos = 0;
- ExhaustGasTemp_degK = 0.0;
- EGT_degC = 0.0;
-
- dt = State->Getdt();
-
- // Supercharging
- BoostSpeeds = 0; // Default to no supercharging
- BoostSpeed = 0;
- Boosted = false;
- BoostOverride = 0;
- bBoostOverride = false;
- bTakeoffBoost = false;
- TakeoffBoost = 0.0; // Default to no extra takeoff-boost
- int i;
- for (i=0; i<FG_MAX_BOOST_SPEEDS; i++) {
- RatedBoost[i] = 0.0;
- RatedPower[i] = 0.0;
- RatedAltitude[i] = 0.0;
- BoostMul[i] = 1.0;
- RatedMAP[i] = 100000;
- RatedRPM[i] = 2500;
- TakeoffMAP[i] = 100000;
- }
- for (i=0; i<FG_MAX_BOOST_SPEEDS-1; i++) {
- BoostSwitchAltitude[i] = 0.0;
- BoostSwitchPressure[i] = 0.0;
- }
-
- // Initialisation
- volumetric_efficiency = 0.8; // Actually f(speed, load) but this will get us running
-
- // First column is thi, second is neta (combustion efficiency)
- Lookup_Combustion_Efficiency = new FGTable(12);
- *Lookup_Combustion_Efficiency << 0.00 << 0.980;
- *Lookup_Combustion_Efficiency << 0.90 << 0.980;
- *Lookup_Combustion_Efficiency << 1.00 << 0.970;
- *Lookup_Combustion_Efficiency << 1.05 << 0.950;
- *Lookup_Combustion_Efficiency << 1.10 << 0.900;
- *Lookup_Combustion_Efficiency << 1.15 << 0.850;
- *Lookup_Combustion_Efficiency << 1.20 << 0.790;
- *Lookup_Combustion_Efficiency << 1.30 << 0.700;
- *Lookup_Combustion_Efficiency << 1.40 << 0.630;
- *Lookup_Combustion_Efficiency << 1.50 << 0.570;
- *Lookup_Combustion_Efficiency << 1.60 << 0.525;
- *Lookup_Combustion_Efficiency << 2.00 << 0.345;
-
- Power_Mixture_Correlation = new FGTable(13);
- *Power_Mixture_Correlation << (14.7/1.6) << 78.0;
- *Power_Mixture_Correlation << 10 << 86.0;
- *Power_Mixture_Correlation << 11 << 93.5;
- *Power_Mixture_Correlation << 12 << 98.0;
- *Power_Mixture_Correlation << 13 << 100.0;
- *Power_Mixture_Correlation << 14 << 99.0;
- *Power_Mixture_Correlation << 15 << 96.4;
- *Power_Mixture_Correlation << 16 << 92.5;
- *Power_Mixture_Correlation << 17 << 88.0;
- *Power_Mixture_Correlation << 18 << 83.0;
- *Power_Mixture_Correlation << 19 << 78.5;
- *Power_Mixture_Correlation << 20 << 74.0;
- *Power_Mixture_Correlation << (14.7/0.6) << 58;
-
- Name = Eng_cfg->GetValue("NAME");
- Eng_cfg->GetNextConfigLine();
- while (Eng_cfg->GetValue() != string("/FG_PISTON")) {
- *Eng_cfg >> token;
- if (token == "MINMP") *Eng_cfg >> MinManifoldPressure_inHg;
- else if (token == "MAXMP") *Eng_cfg >> MaxManifoldPressure_inHg;
- else if (token == "DISPLACEMENT") *Eng_cfg >> Displacement;
- else if (token == "MAXHP") *Eng_cfg >> MaxHP;
- else if (token == "CYCLES") *Eng_cfg >> Cycles;
- else if (token == "IDLERPM") *Eng_cfg >> IdleRPM;
- else if (token == "MAXTHROTTLE") *Eng_cfg >> MaxThrottle;
- else if (token == "MINTHROTTLE") *Eng_cfg >> MinThrottle;
- else if (token == "NUMBOOSTSPEEDS") *Eng_cfg >> BoostSpeeds;
- else if (token == "BOOSTOVERRIDE") *Eng_cfg >> BoostOverride;
- else if (token == "TAKEOFFBOOST") *Eng_cfg >> TakeoffBoost;
- else if (token == "RATEDBOOST1") *Eng_cfg >> RatedBoost[0];
- else if (token == "RATEDBOOST2") *Eng_cfg >> RatedBoost[1];
- else if (token == "RATEDBOOST3") *Eng_cfg >> RatedBoost[2];
- else if (token == "RATEDPOWER1") *Eng_cfg >> RatedPower[0];
- else if (token == "RATEDPOWER2") *Eng_cfg >> RatedPower[1];
- else if (token == "RATEDPOWER3") *Eng_cfg >> RatedPower[2];
- else if (token == "RATEDRPM1") *Eng_cfg >> RatedRPM[0];
- else if (token == "RATEDRPM2") *Eng_cfg >> RatedRPM[1];
- else if (token == "RATEDRPM3") *Eng_cfg >> RatedRPM[2];
- else if (token == "RATEDALTITUDE1") *Eng_cfg >> RatedAltitude[0];
- else if (token == "RATEDALTITUDE2") *Eng_cfg >> RatedAltitude[1];
- else if (token == "RATEDALTITUDE3") *Eng_cfg >> RatedAltitude[2];
- else cerr << "Unhandled token in Engine config file: " << token << endl;
- }
-
- minMAP = MinManifoldPressure_inHg * 3376.85; // inHg to Pa
- maxMAP = MaxManifoldPressure_inHg * 3376.85;
-
- // Set up and sanity-check the turbo/supercharging configuration based on the input values.
- if(TakeoffBoost > RatedBoost[0]) bTakeoffBoost = true;
- for(i=0; i<BoostSpeeds; ++i) {
- bool bad = false;
- if(RatedBoost[i] <= 0.0) bad = true;
- if(RatedPower[i] <= 0.0) bad = true;
- if(RatedAltitude[i] < 0.0) bad = true; // 0.0 is deliberately allowed - this corresponds to unregulated supercharging.
- if(i > 0 && RatedAltitude[i] < RatedAltitude[i - 1]) bad = true;
- if(bad) {
- // We can't recover from the above - don't use this supercharger speed.
- BoostSpeeds--;
- // TODO - put out a massive error message!
- break;
- }
- // Now sanity-check stuff that is recoverable.
- if(i < BoostSpeeds - 1) {
- if(BoostSwitchAltitude[i] < RatedAltitude[i]) {
- // TODO - put out an error message
- // But we can also make a reasonable estimate, as below.
- BoostSwitchAltitude[i] = RatedAltitude[i] + 1000;
- }
- BoostSwitchPressure[i] = Atmosphere->GetPressure(BoostSwitchAltitude[i]) * 47.88;
- //cout << "BoostSwitchAlt = " << BoostSwitchAltitude[i] << ", pressure = " << BoostSwitchPressure[i] << '\n';
- // Assume there is some hysteresis on the supercharger gear switch, and guess the value for now
- BoostSwitchHysteresis = 1000;
- }
- // Now work out the supercharger pressure multiplier of this speed from the rated boost and altitude.
- RatedMAP[i] = Atmosphere->GetPressureSL() * 47.88 + RatedBoost[i] * 6895; // psf*47.88 = Pa, psi*6895 = Pa.
- // Sometimes a separate BCV setting for takeoff or extra power is fitted.
- if(TakeoffBoost > RatedBoost[0]) {
- // Assume that the effect on the BCV is the same whichever speed is in use.
- TakeoffMAP[i] = RatedMAP[i] + ((TakeoffBoost - RatedBoost[0]) * 6895);
- bTakeoffBoost = true;
- } else {
- TakeoffMAP[i] = RatedMAP[i];
- bTakeoffBoost = false;
- }
- BoostMul[i] = RatedMAP[i] / (Atmosphere->GetPressure(RatedAltitude[i]) * 47.88);
-
- // TODO - get rid of the debugging output before sending it to Jon
- //cout << "Speed " << i+1 << '\n';
- //cout << "BoostMul = " << BoostMul[i] << ", RatedMAP = " << RatedMAP[i] << ", TakeoffMAP = " << TakeoffMAP[i] << '\n';
- }
-
- if(BoostSpeeds > 0) {
- Boosted = true;
- BoostSpeed = 0;
- }
- bBoostOverride = (BoostOverride == 1 ? true : false);
-
- //cout << "Engine is " << (Boosted ? "supercharged" : "naturally aspirated") << '\n';
-
- Debug(0); // Call Debug() routine from constructor if needed
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGPiston::~FGPiston()
-{
- Debug(1); // Call Debug() routine from constructor if needed
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGPiston::Calculate(void)
-{
- if (FuelFlow_gph > 0.0) ConsumeFuel();
-
- Throttle = FCS->GetThrottlePos(EngineNumber);
- Mixture = FCS->GetMixturePos(EngineNumber);
-
- //
- // Input values.
- //
-
- p_amb = Atmosphere->GetPressure() * 47.88; // convert from lbs/ft2 to Pa
- p_amb_sea_level = Atmosphere->GetPressureSL() * 47.88;
- T_amb = Atmosphere->GetTemperature() * (5.0 / 9.0); // convert from Rankine to Kelvin
-
- RPM = Thruster->GetRPM() * Thruster->GetGearRatio();
-
- IAS = Auxiliary->GetVcalibratedKTS();
-
- doEngineStartup();
- if(Boosted) doBoostControl();
- doMAP();
- doAirFlow();
- doFuelFlow();
-
- //Now that the fuel flow is done check if the mixture is too lean to run the engine
- //Assume lean limit at 22 AFR for now - thats a thi of 0.668
- //This might be a bit generous, but since there's currently no audiable warning of impending
- //cutout in the form of misfiring and/or rough running its probably reasonable for now.
- if (equivalence_ratio < 0.668)
- Running = false;
-
- doEnginePower();
- doEGT();
- doCHT();
- doOilTemperature();
- doOilPressure();
-
- if (Thruster->GetType() == FGThruster::ttPropeller) {
- ((FGPropeller*)Thruster)->SetAdvance(FCS->GetPropAdvance(EngineNumber));
- }
-
- PowerAvailable = (HP * hptoftlbssec) - Thruster->GetPowerRequired();
-
- return Thrust = Thruster->Calculate(PowerAvailable);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-/**
- * Start or stop the engine.
- */
-
-void FGPiston::doEngineStartup(void)
-{
- // Check parameters that may alter the operating state of the engine.
- // (spark, fuel, starter motor etc)
- bool spark;
- bool fuel;
-
- // Check for spark
- Magneto_Left = false;
- Magneto_Right = false;
- // Magneto positions:
- // 0 -> off
- // 1 -> left only
- // 2 -> right only
- // 3 -> both
- if (Magnetos != 0) {
- spark = true;
- } else {
- spark = false;
- } // neglects battery voltage, master on switch, etc for now.
-
- if ((Magnetos == 1) || (Magnetos > 2)) Magneto_Left = true;
- if (Magnetos > 1) Magneto_Right = true;
-
- // Assume we have fuel for now
- fuel = !Starved;
-
- // Check if we are turning the starter motor
- if (Cranking != Starter) {
- // This check saves .../cranking from getting updated every loop - they
- // only update when changed.
- Cranking = Starter;
- crank_counter = 0;
- }
-
- if (Cranking) crank_counter++; //Check mode of engine operation
-
- if (!Running && spark && fuel) { // start the engine if revs high enough
- if (Cranking) {
- if ((RPM > 450) && (crank_counter > 175)) // Add a little delay to startup
- Running = true; // on the starter
- } else {
- if (RPM > 450) // This allows us to in-air start
- Running = true; // when windmilling
- }
- }
-
- // Cut the engine *power* - Note: the engine may continue to
- // spin if the prop is in a moving airstream
-
- if ( Running && (!spark || !fuel) ) Running = false;
-
- // Check for stalling (RPM = 0).
- if (Running) {
- if (RPM == 0) {
- Running = false;
- } else if ((RPM <= 480) && (Cranking)) {
- Running = false;
- }
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-/**
- * Calculate the Current Boost Speed
- *
- * This function calculates the current turbo/supercharger boost speed
- * based on altitude and the (automatic) boost-speed control valve configuration.
- *
- * Inputs: p_amb, BoostSwitchPressure, BoostSwitchHysteresis
- *
- * Outputs: BoostSpeed
- */
-
-void FGPiston::doBoostControl(void)
-{
- if(BoostSpeed < BoostSpeeds - 1) {
- // Check if we need to change to a higher boost speed
- if(p_amb < BoostSwitchPressure[BoostSpeed] - BoostSwitchHysteresis) {
- BoostSpeed++;
- }
- } else if(BoostSpeed > 0) {
- // Check if we need to change to a lower boost speed
- if(p_amb > BoostSwitchPressure[BoostSpeed - 1] + BoostSwitchHysteresis) {
- BoostSpeed--;
- }
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-/**
- * Calculate the manifold absolute pressure (MAP) in inches hg
- *
- * This function calculates manifold absolute pressure (MAP)
- * from the throttle position, turbo/supercharger boost control
- * system, engine speed and local ambient air density.
- *
- * TODO: changes in MP should not be instantaneous -- introduce
- * a lag between throttle changes and MP changes, to allow pressure
- * to build up or disperse.
- *
- * Inputs: minMAP, maxMAP, p_amb, Throttle
- *
- * Outputs: MAP, ManifoldPressure_inHg
- */
-
-void FGPiston::doMAP(void)
-{
- if(RPM > 10) {
- // Naturally aspirated
- MAP = minMAP + (Throttle * (maxMAP - minMAP));
- MAP *= p_amb / p_amb_sea_level;
- if(Boosted) {
- // If takeoff boost is fitted, we currently assume the following throttle map:
- // (In throttle % - actual input is 0 -> 1)
- // 99 / 100 - Takeoff boost
- // 96 / 97 / 98 - Rated boost
- // 0 - 95 - Idle to Rated boost (MinManifoldPressure to MaxManifoldPressure)
- // In real life, most planes would be fitted with a mechanical 'gate' between
- // the rated boost and takeoff boost positions.
- double T = Throttle; // processed throttle value.
- bool bTakeoffPos = false;
- if(bTakeoffBoost) {
- if(Throttle > 0.98) {
- //cout << "Takeoff Boost!!!!\n";
- bTakeoffPos = true;
- } else if(Throttle <= 0.95) {
- bTakeoffPos = false;
- T *= 1.0 / 0.95;
- } else {
- bTakeoffPos = false;
- //cout << "Rated Boost!!\n";
- T = 1.0;
- }
- }
- // Boost the manifold pressure.
- MAP *= BoostMul[BoostSpeed];
- // Now clip the manifold pressure to BCV or Wastegate setting.
- if(bTakeoffPos) {
- if(MAP > TakeoffMAP[BoostSpeed]) {
- MAP = TakeoffMAP[BoostSpeed];
- }
- } else {
- if(MAP > RatedMAP[BoostSpeed]) {
- MAP = RatedMAP[BoostSpeed];
- }
- }
- }
- } else {
- // rpm < 10 - effectively stopped.
- // TODO - add a better variation of MAP with engine speed
- MAP = Atmosphere->GetPressure() * 47.88; // psf to Pa
- }
-
- // And set the value in American units as well
- ManifoldPressure_inHg = MAP / 3376.85;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-/**
- * Calculate the air flow through the engine.
- * Also calculates ambient air density
- * (used in CHT calculation for air-cooled engines).
- *
- * Inputs: p_amb, R_air, T_amb, MAP, Displacement,
- * RPM, volumetric_efficiency
- *
- * TODO: Model inlet manifold air temperature.
- *
- * Outputs: rho_air, m_dot_air
- */
-
-void FGPiston::doAirFlow(void)
-{
- rho_air = p_amb / (R_air * T_amb);
- double rho_air_manifold = MAP / (R_air * T_amb);
- double displacement_SI = Displacement * in3tom3;
- double swept_volume = (displacement_SI * (RPM/60)) / 2;
- double v_dot_air = swept_volume * volumetric_efficiency;
- m_dot_air = v_dot_air * rho_air_manifold;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-/**
- * Calculate the fuel flow into the engine.
- *
- * Inputs: Mixture, thi_sea_level, p_amb_sea_level, p_amb, m_dot_air
- *
- * Outputs: equivalence_ratio, m_dot_fuel
- */
-
-void FGPiston::doFuelFlow(void)
-{
- double thi_sea_level = 1.3 * Mixture;
- equivalence_ratio = thi_sea_level * p_amb_sea_level / p_amb;
- m_dot_fuel = m_dot_air / 14.7 * equivalence_ratio;
- FuelFlow_gph = m_dot_fuel
- * 3600 // seconds to hours
- * 2.2046 // kg to lb
- / 6.6; // lb to gal_us of kerosene
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-/**
- * Calculate the power produced by the engine.
- *
- * Currently, the JSBSim propellor model does not allow the
- * engine to produce enough RPMs to get up to a high horsepower.
- * When tested with sufficient RPM, it has no trouble reaching
- * 200HP.
- *
- * Inputs: ManifoldPressure_inHg, p_amb, p_amb_sea_level, RPM, T_amb,
- * equivalence_ratio, Cycles, MaxHP
- *
- * Outputs: Percentage_Power, HP
- */
-
-void FGPiston::doEnginePower(void)
-{
- if (Running) {
- double T_amb_degF = KelvinToFahrenheit(T_amb);
- double T_amb_sea_lev_degF = KelvinToFahrenheit(288);
-
- // FIXME: this needs to be generalized
- double ManXRPM; // Convienience term for use in the calculations
- if(Boosted) {
- // Currently a simple linear fit.
- // The zero crossing is moved up the speed-load range to reduce the idling power.
- // This will change!
- double zeroOffset = (minMAP / 2.0) * (IdleRPM / 2.0);
- ManXRPM = MAP * (RPM > RatedRPM[BoostSpeed] ? RatedRPM[BoostSpeed] : RPM);
- // The speed clip in the line above is deliberate.
- Percentage_Power = ((ManXRPM - zeroOffset) / ((RatedMAP[BoostSpeed] * RatedRPM[BoostSpeed]) - zeroOffset)) * 107.0;
- Percentage_Power -= 7.0; // Another idle power reduction offset - see line above with 107.
- if (Percentage_Power < 0.0) Percentage_Power = 0.0;
- // Note that %power is allowed to go over 100 for boosted powerplants
- // such as for the BCV-override or takeoff power settings.
- // TODO - currently no altitude effect (temperature & exhaust back-pressure) modelled
- // for boosted engines.
- } else {
- ManXRPM = ManifoldPressure_inHg * RPM; // Note that inHg must be used for the following correlation.
- Percentage_Power = (6e-9 * ManXRPM * ManXRPM) + (8e-4 * ManXRPM) - 1.0;
- Percentage_Power += ((T_amb_sea_lev_degF - T_amb_degF) * 7 /120);
- if (Percentage_Power < 0.0) Percentage_Power = 0.0;
- else if (Percentage_Power > 100.0) Percentage_Power = 100.0;
- }
-
- double Percentage_of_best_power_mixture_power =
- Power_Mixture_Correlation->GetValue(14.7 / equivalence_ratio);
-
- Percentage_Power *= Percentage_of_best_power_mixture_power / 100.0;
-
- if(Boosted) {
- HP = Percentage_Power * RatedPower[BoostSpeed] / 100.0;
- } else {
- HP = Percentage_Power * MaxHP / 100.0;
- }
-
- } else {
-
- // Power output when the engine is not running
- if (Cranking) {
- if (RPM < 10) {
- HP = 3.0; // This is a hack to prevent overshooting the idle rpm in
- // the first time step. It may possibly need to be changed
- // if the prop model is changed.
- } else if (RPM < 480) {
- HP = 3.0 + ((480 - RPM) / 10.0);
- // This is a guess - would be nice to find a proper starter moter torque curve
- } else {
- HP = 3.0;
- }
- } else {
- // Quick hack until we port the FMEP stuff
- if (RPM > 0.0)
- HP = -1.5;
- else
- HP = 0.0;
- }
- }
- //cout << "Power = " << HP << '\n';
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-/**
- * Calculate the exhaust gas temperature.
- *
- * Inputs: equivalence_ratio, m_dot_fuel, calorific_value_fuel,
- * Cp_air, m_dot_air, Cp_fuel, m_dot_fuel, T_amb, Percentage_Power
- *
- * Outputs: combustion_efficiency, ExhaustGasTemp_degK
- */
-
-void FGPiston::doEGT(void)
-{
- double delta_T_exhaust;
- double enthalpy_exhaust;
- double heat_capacity_exhaust;
- double dEGTdt;
-
- if ((Running) && (m_dot_air > 0.0)) { // do the energy balance
- combustion_efficiency = Lookup_Combustion_Efficiency->GetValue(equivalence_ratio);
- enthalpy_exhaust = m_dot_fuel * calorific_value_fuel *
- combustion_efficiency * 0.33;
- heat_capacity_exhaust = (Cp_air * m_dot_air) + (Cp_fuel * m_dot_fuel);
- delta_T_exhaust = enthalpy_exhaust / heat_capacity_exhaust;
- ExhaustGasTemp_degK = T_amb + delta_T_exhaust;
- ExhaustGasTemp_degK *= 0.444 + ((0.544 - 0.444) * Percentage_Power / 100.0);
- } else { // Drop towards ambient - guess an appropriate time constant for now
- dEGTdt = (298.0 - ExhaustGasTemp_degK) / 100.0;
- delta_T_exhaust = dEGTdt * dt;
- ExhaustGasTemp_degK += delta_T_exhaust;
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-/**
- * Calculate the cylinder head temperature.
- *
- * Inputs: T_amb, IAS, rho_air, m_dot_fuel, calorific_value_fuel,
- * combustion_efficiency, RPM
- *
- * Outputs: CylinderHeadTemp_degK
- */
-
-void FGPiston::doCHT(void)
-{
- double h1 = -95.0;
- double h2 = -3.95;
- double h3 = -0.05;
-
- double arbitary_area = 1.0;
- double CpCylinderHead = 800.0;
- double MassCylinderHead = 8.0;
-
- double temperature_difference = CylinderHeadTemp_degK - T_amb;
- double v_apparent = IAS * 0.5144444;
- double v_dot_cooling_air = arbitary_area * v_apparent;
- double m_dot_cooling_air = v_dot_cooling_air * rho_air;
- double dqdt_from_combustion =
- m_dot_fuel * calorific_value_fuel * combustion_efficiency * 0.33;
- double dqdt_forced = (h2 * m_dot_cooling_air * temperature_difference) +
- (h3 * RPM * temperature_difference);
- double dqdt_free = h1 * temperature_difference;
- double dqdt_cylinder_head = dqdt_from_combustion + dqdt_forced + dqdt_free;
-
- double HeatCapacityCylinderHead = CpCylinderHead * MassCylinderHead;
-
- CylinderHeadTemp_degK +=
- (dqdt_cylinder_head / HeatCapacityCylinderHead) * dt;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-/**
- * Calculate the oil temperature.
- *
- * Inputs: Percentage_Power, running flag.
- *
- * Outputs: OilTemp_degK
- */
-
-void FGPiston::doOilTemperature(void)
-{
- double idle_percentage_power = 2.3; // approximately
- double target_oil_temp; // Steady state oil temp at the current engine conditions
- double time_constant; // The time constant for the differential equation
-
- if (Running) {
- target_oil_temp = 363;
- time_constant = 500; // Time constant for engine-on idling.
- if (Percentage_Power > idle_percentage_power) {
- time_constant /= ((Percentage_Power / idle_percentage_power) / 10.0); // adjust for power
- }
- } else {
- target_oil_temp = 298;
- time_constant = 1000; // Time constant for engine-off; reflects the fact
- // that oil is no longer getting circulated
- }
-
- double dOilTempdt = (target_oil_temp - OilTemp_degK) / time_constant;
-
- OilTemp_degK += (dOilTempdt * dt);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-/**
- * Calculate the oil pressure.
- *
- * Inputs: RPM
- *
- * Outputs: OilPressure_psi
- */
-
-void FGPiston::doOilPressure(void)
-{
- double Oil_Press_Relief_Valve = 60; // FIXME: may vary by engine
- double Oil_Press_RPM_Max = 1800; // FIXME: may vary by engine
- double Design_Oil_Temp = 358; // degK; FIXME: may vary by engine
- double Oil_Viscosity_Index = 0.25;
-
- OilPressure_psi = (Oil_Press_Relief_Valve / Oil_Press_RPM_Max) * RPM;
-
- if (OilPressure_psi >= Oil_Press_Relief_Valve) {
- OilPressure_psi = Oil_Press_Relief_Valve;
- }
-
- OilPressure_psi += (Design_Oil_Temp - OilTemp_degK) * Oil_Viscosity_Index;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGPiston::GetEngineLabels(string delimeter)
-{
- std::ostringstream buf;
-
- buf << Name << "_PwrAvail[" << EngineNumber << "]" << delimeter
- << Name << "_HP[" << EngineNumber << "]" << delimeter
- << Name << "_equiv_ratio[" << EngineNumber << "]" << delimeter
- << Name << "_MAP[" << EngineNumber << "]" << delimeter
- << Thruster->GetThrusterLabels(EngineNumber, delimeter);
-
- return buf.str();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGPiston::GetEngineValues(string delimeter)
-{
- std::ostringstream buf;
-
- buf << PowerAvailable << delimeter << HP << delimeter
- << equivalence_ratio << delimeter << MAP << delimeter
- << Thruster->GetThrusterValues(EngineNumber, delimeter);
-
- return buf.str();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-//
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGPiston::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
-
- cout << "\n Engine Name: " << Name << endl;
- cout << " MinManifoldPressure: " << MinManifoldPressure_inHg << endl;
- cout << " MaxManifoldPressure: " << MaxManifoldPressure_inHg << endl;
- cout << " Displacement: " << Displacement << endl;
- cout << " MaxHP: " << MaxHP << endl;
- cout << " Cycles: " << Cycles << endl;
- cout << " IdleRPM: " << IdleRPM << endl;
- cout << " MaxThrottle: " << MaxThrottle << endl;
- cout << " MinThrottle: " << MinThrottle << endl;
-
- cout << endl;
- cout << " Combustion Efficiency table:" << endl;
- Lookup_Combustion_Efficiency->Print();
- cout << endl;
-
- cout << endl;
- cout << " Power Mixture Correlation table:" << endl;
- Power_Mixture_Correlation->Print();
- cout << endl;
-
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGPiston" << endl;
- if (from == 1) cout << "Destroyed: FGPiston" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-
-double
-FGPiston::CalcFuelNeed(void)
-{
- return FuelFlow_gph / 3600 * 6 * State->Getdt() * Propulsion->GetRate();
-}
-
-} // namespace JSBSim
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGPiston.h
- Author: Jon S. Berndt
- Date started: 09/12/2000
-
- ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) --------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-09/12/2000 JSB Created
-10/01/2001 DPM Modified to use equations from Dave Luff's piston model.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGPISTON_H
-#define FGPISTON_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGEngine.h"
-#include "FGConfigFile.h"
-#include "FGTable.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_PISTON "$Id$";
-#define FG_MAX_BOOST_SPEEDS 3
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Models Dave Luff's Turbo/Supercharged Piston engine model.
- Additional elements are required for a supercharged engine. These can be
- left off a non-supercharged engine, ie. the changes are all backward
- compatible at present.
-
- - NUMBOOSTSPEEDS - zero (or not present) for a naturally-aspirated engine,
- either 1, 2 or 3 for a boosted engine. This corresponds to the number of
- supercharger speeds. Merlin XII had 1 speed, Merlin 61 had 2, a late
- Griffon engine apparently had 3. No known engine more than 3, although
- some German engines apparently had a continuously variable-speed
- supercharger.
-
- - BOOSTOVERRIDE - whether the boost pressure control system (either a boost
- control valve for superchargers or wastegate for turbochargers) can be
- overriden by the pilot. During wartime this was commonly possible, and
- known as "War Emergency Power" by the Brits. 1 or 0 in the config file.
- This isn't implemented in the model yet though, there would need to be
- some way of getting the boost control cutout lever position (on or off)
- from FlightGear first.
-
- - The next items are all appended with either 1, 2 or 3 depending on which
- boost speed they refer to, eg RATEDBOOST1. The rated values seems to have
- been a common convention at the time to express the maximum continuously
- available power, and the conditions to attain that power.
-
- - RATEDBOOST[123] - the absolute rated boost above sea level ambient for a
- given boost speed, in psi. Eg the Merlin XII had a rated boost of 9psi,
- giving approximately 42inHg manifold pressure up to the rated altitude.
-
- - RATEDALTITUDE[123] - The altitude up to which rated boost can be
- maintained. Up to this altitude the boost is maintained constant for a
- given throttle position by the BCV or wastegate. Beyond this altitude the
- manifold pressure must drop, since the supercharger is now at maximum
- unregulated output. The actual pressure multiplier of the supercharger
- system is calculated at initialisation from this value.
-
- - RATEDPOWER[123] - The power developed at rated boost at rated altitude at
- rated rpm.
-
- - RATEDRPM[123] - The rpm at which rated power is developed.
-
- - TAKEOFFBOOST - Takeoff boost in psi above ambient. Many aircraft had an
- extra boost setting beyond rated boost, but not totally uncontrolled as in
- the already mentioned boost-control-cutout, typically attained by pushing
- the throttle past a mechanical 'gate' preventing its inadvertant use. This
- was typically used for takeoff, and emergency situations, generally for
- not more than five minutes. This is a change in the boost control
- setting, not the actual supercharger speed, and so would only give extra
- power below the rated altitude. When TAKEOFFBOOST is specified in the
- config file (and is above RATEDBOOST1), then the throttle position is
- interpreted as:
-
- - 0 to 0.95 : idle manifold pressure to rated boost (where attainable)
- - 0.96, 0.97, 0.98 : rated boost (where attainable).
- - 0.99, 1.0 : takeoff boost (where attainable).
-
- A typical takeoff boost for an earlyish Merlin was about 12psi, compared
- with a rated boost of 9psi.
-
- It is quite possible that other boost control settings could have been used
- on some aircraft, or that takeoff/extra boost could have activated by other
- means than pushing the throttle full forward through a gate, but this will
- suffice for now.
-
- Note that MAXMP is still the non-boosted max manifold pressure even for
- boosted engines - effectively this is simply a measure of the pressure drop
- through the fully open throttle.
-
- @author Jon S. Berndt (Engine framework code and framework-related mods)
- @author Dave Luff (engine operational code)
- @author David Megginson (initial porting and additional code)
- @version $Id$
- */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGPiston : public FGEngine
-{
-public:
- /// Constructor
- FGPiston(FGFDMExec* exec, FGConfigFile* Eng_cfg, int engine_number);
- /// Destructor
- ~FGPiston();
-
- string GetEngineLabels(string delimeter);
- string GetEngineValues(string delimeter);
-
- double Calculate(void);
- double GetPowerAvailable(void) {return PowerAvailable;}
- double CalcFuelNeed(void);
-
- void SetMagnetos(int magnetos) {Magnetos = magnetos;}
-
- double GetEGT(void) { return EGT_degC; }
- int GetMagnetos(void) {return Magnetos;}
-
- double getExhaustGasTemp_degF(void) {return KelvinToFahrenheit(ExhaustGasTemp_degK);}
- double getManifoldPressure_inHg(void) const {return ManifoldPressure_inHg;}
- double getCylinderHeadTemp_degF(void) {return KelvinToFahrenheit(CylinderHeadTemp_degK);}
- double getOilPressure_psi(void) const {return OilPressure_psi;}
- double getOilTemp_degF (void) {return KelvinToFahrenheit(OilTemp_degK);}
- double getRPM(void) {return RPM;}
-
-private:
- int crank_counter;
-
- double BrakeHorsePower;
- double SpeedSlope;
- double SpeedIntercept;
- double AltitudeSlope;
- double PowerAvailable;
-
- // timestep
- double dt;
-
- void doEngineStartup(void);
- void doBoostControl(void);
- void doMAP(void);
- void doAirFlow(void);
- void doFuelFlow(void);
- void doEnginePower(void);
- void doEGT(void);
- void doCHT(void);
- void doOilPressure(void);
- void doOilTemperature(void);
-
- //
- // constants
- //
-
- const double R_air;
- const double rho_fuel; // kg/m^3
- const double calorific_value_fuel; // W/Kg (approximate)
- const double Cp_air; // J/KgK
- const double Cp_fuel; // J/KgK
-
- FGTable *Lookup_Combustion_Efficiency;
- FGTable *Power_Mixture_Correlation;
-
- //
- // Configuration
- //
- double MinManifoldPressure_inHg; // Inches Hg
- double MaxManifoldPressure_inHg; // Inches Hg
- double Displacement; // cubic inches
- double MaxHP; // horsepower
- double Cycles; // cycles/power stroke
- double IdleRPM; // revolutions per minute
- int BoostSpeeds; // Number of super/turbocharger boost speeds - zero implies no turbo/supercharging.
- int BoostSpeed; // The current boost-speed (zero-based).
- bool Boosted; // Set true for boosted engine.
- int BoostOverride; // The raw value read in from the config file - should be 1 or 0 - see description below.
- bool bBoostOverride; // Set true if pilot override of the boost regulator was fitted.
- // (Typically called 'war emergency power').
- bool bTakeoffBoost; // Set true if extra takeoff / emergency boost above rated boost could be attained.
- // (Typically by extra throttle movement past a mechanical 'gate').
- double TakeoffBoost; // Sea-level takeoff boost in psi. (if fitted).
- double RatedBoost[FG_MAX_BOOST_SPEEDS]; // Sea-level rated boost in psi.
- double RatedAltitude[FG_MAX_BOOST_SPEEDS]; // Altitude at which full boost is reached (boost regulation ends)
- // and at which power starts to fall with altitude [ft].
- double RatedRPM[FG_MAX_BOOST_SPEEDS]; // Engine speed at which the rated power for each boost speed is delivered [rpm].
- double RatedPower[FG_MAX_BOOST_SPEEDS]; // Power at rated throttle position at rated altitude [HP].
- double BoostSwitchAltitude[FG_MAX_BOOST_SPEEDS - 1]; // Altitude at which switchover (currently assumed automatic)
- // from one boost speed to next occurs [ft].
- double BoostSwitchPressure[FG_MAX_BOOST_SPEEDS - 1]; // Pressure at which boost speed switchover occurs [Pa]
- double BoostMul[FG_MAX_BOOST_SPEEDS]; // Pressure multipier of unregulated supercharger
- double RatedMAP[FG_MAX_BOOST_SPEEDS]; // Rated manifold absolute pressure [Pa] (BCV clamp)
- double TakeoffMAP[FG_MAX_BOOST_SPEEDS]; // Takeoff setting manifold absolute pressure [Pa] (BCV clamp)
- double BoostSwitchHysteresis; // Pa.
-
- double minMAP; // Pa
- double maxMAP; // Pa
- double MAP; // Pa
-
- //
- // Inputs (in addition to those in FGEngine).
- //
- double p_amb; // Pascals
- double p_amb_sea_level; // Pascals
- double T_amb; // degrees Kelvin
- double RPM; // revolutions per minute
- double IAS; // knots
- bool Magneto_Left;
- bool Magneto_Right;
- int Magnetos;
-
- //
- // Outputs (in addition to those in FGEngine).
- //
- double rho_air;
- double volumetric_efficiency;
- double m_dot_air;
- double equivalence_ratio;
- double m_dot_fuel;
- double Percentage_Power;
- double HP;
- double combustion_efficiency;
- double ExhaustGasTemp_degK;
- double EGT_degC;
- double ManifoldPressure_inHg;
- double CylinderHeadTemp_degK;
- double OilPressure_psi;
- double OilTemp_degK;
-
- void Debug(int from);
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGPropagate.cpp
- Author: Jon S. Berndt
- Date started: 01/05/99
- Purpose: Integrate the EOM to determine instantaneous position
- Called by: FGFDMExec
-
- ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-This class encapsulates the integration of rates and accelerations to get the
-current position of the aircraft.
-
-HISTORY
---------------------------------------------------------------------------------
-01/05/99 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-COMMENTS, REFERENCES, and NOTES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-[1] Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
- Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
- School, January 1994
-[2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
- JSC 12960, July 1977
-[3] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
- NASA-Ames", NASA CR-2497, January 1975
-[4] Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
- Wiley & Sons, 1979 ISBN 0-471-03032-5
-[5] Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
- 1982 ISBN 0-471-08936-2
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#ifdef FGFS
-# include <simgear/compiler.h>
-# ifdef SG_HAVE_STD_INCLUDES
-# include <cmath>
-# include <iomanip>
-# else
-# include <math.h>
-# include <iomanip.h>
-# endif
-#else
-# if defined(sgi) && !defined(__GNUC__)
-# include <math.h>
-# if (_COMPILER_VERSION < 740)
-# include <iomanip.h>
-# else
-# include <iomanip>
-# endif
-# else
-# include <cmath>
-# include <iomanip>
-# endif
-#endif
-
-#include "FGPropagate.h"
-#include "FGState.h"
-#include "FGFDMExec.h"
-#include "FGAircraft.h"
-#include "FGMassBalance.h"
-#include "FGInertial.h"
-#include "FGPropertyManager.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_PROPAGATE;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-FGPropagate::FGPropagate(FGFDMExec* fdmex) : FGModel(fdmex)
-{
- Name = "FGPropagate";
-
- bind();
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGPropagate::~FGPropagate(void)
-{
- unbind();
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGPropagate::InitModel(void)
-{
- FGModel::InitModel();
-
- SeaLevelRadius = Inertial->RefRadius(); // For initialization ONLY
- RunwayRadius = SeaLevelRadius;
-
- VState.vLocation.SetRadius( SeaLevelRadius + 4.0 );
-
- return true;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
-{
- SeaLevelRadius = FGIC->GetSeaLevelRadiusFtIC();
- RunwayRadius = SeaLevelRadius;
-
- // Set the position lat/lon/radius
- VState.vLocation = FGLocation( FGIC->GetLongitudeRadIC(),
- FGIC->GetLatitudeRadIC(),
- FGIC->GetAltitudeFtIC() + FGIC->GetSeaLevelRadiusFtIC() );
-
- // Set the Orientation from the euler angles
- VState.vQtrn = FGQuaternion( FGIC->GetPhiRadIC(),
- FGIC->GetThetaRadIC(),
- FGIC->GetPsiRadIC() );
-
- // Set the velocities in the instantaneus body frame
- VState.vUVW = FGColumnVector3( FGIC->GetUBodyFpsIC(),
- FGIC->GetVBodyFpsIC(),
- FGIC->GetWBodyFpsIC() );
-
- // Set the angular velocities in the instantaneus body frame.
- VState.vPQR = FGColumnVector3( FGIC->GetPRadpsIC(),
- FGIC->GetQRadpsIC(),
- FGIC->GetRRadpsIC() );
-
- // Compute some derived values.
- vVel = VState.vQtrn.GetTInv()*VState.vUVW;
-
- // Finaly make shure that the quaternion stays normalized.
- VState.vQtrn.Normalize();
-
- // Recompute the RunwayRadius level.
- RecomputeRunwayRadius();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-/*
-Purpose: Called on a schedule to perform EOM integration
-Notes: [JB] Run in standalone mode, SeaLevelRadius will be reference radius.
- In FGFS, SeaLevelRadius is stuffed from FGJSBSim in JSBSim.cxx each pass.
-
-At the top of this Run() function, see several "shortcuts" (or, aliases) being
-set up for use later, rather than using the longer class->function() notation.
-
-Here, propagation of state is done using a simple explicit Euler scheme (see the
-bottom of the function). This propagation is done using the current state values
-and current derivatives. Based on these values we compute an approximation to the
-state values for (now + dt).
-
-*/
-
-bool FGPropagate::Run(void)
-{
- if (FGModel::Run()) return true; // Fast return if we have nothing to do ...
-
- RecomputeRunwayRadius();
-
- double dt = State->Getdt()*rate; // The 'stepsize'
- const FGColumnVector3 omega( 0.0, 0.0, Inertial->omega() ); // earth rotation
- const FGColumnVector3& vForces = Aircraft->GetForces(); // current forces
- const FGColumnVector3& vMoments = Aircraft->GetMoments(); // current moments
-
- double mass = MassBalance->GetMass(); // mass
- const FGMatrix33& J = MassBalance->GetJ(); // inertia matrix
- const FGMatrix33& Jinv = MassBalance->GetJinv(); // inertia matrix inverse
- double r = GetRadius(); // radius
- if (r == 0.0) {cerr << "radius = 0 !" << endl; r = 1e-16;} // radius check
- double rInv = 1.0/r;
- FGColumnVector3 gAccel( 0.0, 0.0, Inertial->GetGAccel(r) );
-
- // The rotation matrices:
- const FGMatrix33& Tl2b = GetTl2b(); // local to body frame
- const FGMatrix33& Tb2l = GetTb2l(); // body to local frame
- const FGMatrix33& Tec2l = VState.vLocation.GetTec2l(); // earth centered to local frame
- const FGMatrix33& Tl2ec = VState.vLocation.GetTl2ec(); // local to earth centered frame
-
- // Inertial angular velocity measured in the body frame.
- const FGColumnVector3 pqri = VState.vPQR + Tl2b*(Tec2l*omega);
-
- // Compute vehicle velocity wrt EC frame, expressed in Local horizontal frame.
- vVel = Tb2l * VState.vUVW;
-
- // First compute the time derivatives of the vehicle state values:
-
- // Compute body frame rotational accelerations based on the current body moments
- vPQRdot = Jinv*(vMoments - pqri*(J*pqri));
-
- // Compute body frame accelerations based on the current body forces
- vUVWdot = VState.vUVW*VState.vPQR + vForces/mass;
-
- // Coriolis acceleration.
- FGColumnVector3 ecVel = Tl2ec*vVel;
- FGColumnVector3 ace = 2.0*omega*ecVel;
- vUVWdot -= Tl2b*(Tec2l*ace);
-
- // Centrifugal acceleration.
- FGColumnVector3 aeec = omega*(omega*VState.vLocation);
- vUVWdot -= Tl2b*(Tec2l*aeec);
-
- // Gravitation accel
- vUVWdot += Tl2b*gAccel;
-
- // Compute vehicle velocity wrt EC frame, expressed in EC frame
- FGColumnVector3 vLocationDot = Tl2ec * vVel;
-
- FGColumnVector3 omegaLocal( rInv*vVel(eEast),
- -rInv*vVel(eNorth),
- -rInv*vVel(eEast)*VState.vLocation.GetTanLatitude() );
-
- // Compute quaternion orientation derivative on current body rates
- FGQuaternion vQtrndot = VState.vQtrn.GetQDot( VState.vPQR - Tl2b*omegaLocal );
-
- // Propagate velocities
- VState.vPQR += dt*vPQRdot;
- VState.vUVW += dt*vUVWdot;
-
- // Propagate positions
- VState.vQtrn += dt*vQtrndot;
- VState.vLocation += dt*vLocationDot;
-
- return false;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropagate::RecomputeRunwayRadius(void)
-{
- // Get the runway radius.
- // Boring: this does not belong here, but since Jon placed the RunwayRadius
- // value here it is better done here than somewhere else.
- FGLocation contactloc;
- FGColumnVector3 dv;
- FGGroundCallback* gcb = FDMExec->GetGroundCallback();
- double t = State->Getsim_time();
- gcb->GetAGLevel(t, VState.vLocation, contactloc, dv, dv);
- RunwayRadius = contactloc.GetRadius();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropagate::Seth(double tt)
-{
- VState.vLocation.SetRadius( tt + SeaLevelRadius );
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGPropagate::GetRunwayRadius(void) const
-{
- return RunwayRadius;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGPropagate::GetDistanceAGL(void) const
-{
- return VState.vLocation.GetRadius() - RunwayRadius;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropagate::SetDistanceAGL(double tt)
-{
- VState.vLocation.SetRadius( tt + RunwayRadius );
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropagate::bind(void)
-{
- typedef double (FGPropagate::*PMF)(int) const;
- PropertyManager->Tie("velocities/h-dot-fps", this, &FGPropagate::Gethdot);
-
- PropertyManager->Tie("velocities/v-north-fps", this, eNorth, (PMF)&FGPropagate::GetVel);
- PropertyManager->Tie("velocities/v-east-fps", this, eEast, (PMF)&FGPropagate::GetVel);
- PropertyManager->Tie("velocities/v-down-fps", this, eDown, (PMF)&FGPropagate::GetVel);
-
- PropertyManager->Tie("velocities/u-fps", this, eU, (PMF)&FGPropagate::GetUVW);
- PropertyManager->Tie("velocities/v-fps", this, eV, (PMF)&FGPropagate::GetUVW);
- PropertyManager->Tie("velocities/w-fps", this, eW, (PMF)&FGPropagate::GetUVW);
-
- PropertyManager->Tie("velocities/p-rad_sec", this, eP, (PMF)&FGPropagate::GetPQR);
- PropertyManager->Tie("velocities/q-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQR);
- PropertyManager->Tie("velocities/r-rad_sec", this, eR, (PMF)&FGPropagate::GetPQR);
-
- PropertyManager->Tie("accelerations/pdot-rad_sec", this, eP, (PMF)&FGPropagate::GetPQRdot);
- PropertyManager->Tie("accelerations/qdot-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQRdot);
- PropertyManager->Tie("accelerations/rdot-rad_sec", this, eR, (PMF)&FGPropagate::GetPQRdot);
-
- PropertyManager->Tie("accelerations/udot-fps", this, eU, (PMF)&FGPropagate::GetUVWdot);
- PropertyManager->Tie("accelerations/vdot-fps", this, eV, (PMF)&FGPropagate::GetUVWdot);
- PropertyManager->Tie("accelerations/wdot-fps", this, eW, (PMF)&FGPropagate::GetUVWdot);
-
- PropertyManager->Tie("position/h-sl-ft", this, &FGPropagate::Geth, &FGPropagate::Seth, true);
- PropertyManager->Tie("position/lat-gc-rad", this, &FGPropagate::GetLatitude, &FGPropagate::SetLatitude);
- PropertyManager->Tie("position/long-gc-rad", this, &FGPropagate::GetLongitude, &FGPropagate::SetLongitude);
- PropertyManager->Tie("position/h-agl-ft", this, &FGPropagate::GetDistanceAGL, &FGPropagate::SetDistanceAGL);
- PropertyManager->Tie("position/radius-to-vehicle-ft", this, &FGPropagate::GetRadius);
-
- PropertyManager->Tie("metrics/runway-radius", this, &FGPropagate::GetRunwayRadius);
-
- PropertyManager->Tie("attitude/phi-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
- PropertyManager->Tie("attitude/theta-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
- PropertyManager->Tie("attitude/psi-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
-
- PropertyManager->Tie("attitude/roll-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
- PropertyManager->Tie("attitude/pitch-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
- PropertyManager->Tie("attitude/heading-true-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropagate::unbind(void)
-{
- PropertyManager->Untie("velocities/v-north-fps");
- PropertyManager->Untie("velocities/v-east-fps");
- PropertyManager->Untie("velocities/v-down-fps");
- PropertyManager->Untie("velocities/h-dot-fps");
- PropertyManager->Untie("velocities/u-fps");
- PropertyManager->Untie("velocities/v-fps");
- PropertyManager->Untie("velocities/w-fps");
- PropertyManager->Untie("velocities/p-rad_sec");
- PropertyManager->Untie("velocities/q-rad_sec");
- PropertyManager->Untie("velocities/r-rad_sec");
- PropertyManager->Untie("accelerations/udot-fps");
- PropertyManager->Untie("accelerations/vdot-fps");
- PropertyManager->Untie("accelerations/wdot-fps");
- PropertyManager->Untie("accelerations/pdot-rad_sec");
- PropertyManager->Untie("accelerations/qdot-rad_sec");
- PropertyManager->Untie("accelerations/rdot-rad_sec");
- PropertyManager->Untie("position/h-sl-ft");
- PropertyManager->Untie("position/lat-gc-rad");
- PropertyManager->Untie("position/long-gc-rad");
- PropertyManager->Untie("position/h-agl-ft");
- PropertyManager->Untie("position/radius-to-vehicle-ft");
- PropertyManager->Untie("metrics/runway-radius");
- PropertyManager->Untie("attitude/phi-rad");
- PropertyManager->Untie("attitude/theta-rad");
- PropertyManager->Untie("attitude/psi-rad");
- PropertyManager->Untie("attitude/roll-rad");
- PropertyManager->Untie("attitude/pitch-rad");
- PropertyManager->Untie("attitude/heading-true-rad");
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGPropagate::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
-
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGPropagate" << endl;
- if (from == 1) cout << "Destroyed: FGPropagate" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGPropagate.h
- Author: Jon S. Berndt
- Date started: 1/5/99
-
- ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-01/05/99 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGPROPAGATE_H
-#define FGPROPAGATE_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGModel.h"
-#include "FGColumnVector3.h"
-#include "FGInitialCondition.h"
-#include "FGLocation.h"
-#include "FGQuaternion.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_PROPAGATE "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Models the EOM and integration/propagation of state
- @author Jon S. Berndt, Mathias Froehlich
- @version $Id$
- */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-// state vector
-
-struct VehicleState {
- FGLocation vLocation;
- FGColumnVector3 vUVW;
- FGColumnVector3 vPQR;
- FGQuaternion vQtrn;
-};
-
-class FGPropagate : public FGModel {
-public:
- /** Constructor
- @param Executive a pointer to the parent executive object */
- FGPropagate(FGFDMExec* Executive);
-
- /// Destructor
- ~FGPropagate();
-
- bool InitModel(void);
-
- /** Runs the Propagate model; called by the Executive
- @return false if no error */
- bool Run(void);
-
- const FGColumnVector3& GetVel(void) const { return vVel; }
- const FGColumnVector3& GetUVW(void) const { return VState.vUVW; }
- const FGColumnVector3& GetUVWdot(void) const { return vUVWdot; }
- const FGColumnVector3& GetPQR(void) const {return VState.vPQR;}
- const FGColumnVector3& GetPQRdot(void) const {return vPQRdot;}
- const FGColumnVector3& GetEuler(void) const { return VState.vQtrn.GetEuler(); }
-
- double GetUVW (int idx) const { return VState.vUVW(idx); }
- double GetUVWdot(int idx) const { return vUVWdot(idx); }
- double GetVel(int idx) const { return vVel(idx); }
- double Geth(void) const { return VState.vLocation.GetRadius() - SeaLevelRadius; }
- double GetPQR(int axis) const {return VState.vPQR(axis);}
- double GetPQRdot(int idx) const {return vPQRdot(idx);}
- double GetEuler(int axis) const { return VState.vQtrn.GetEuler(axis); }
- double GetCosEuler(int idx) const { return VState.vQtrn.GetCosEuler(idx); }
- double GetSinEuler(int idx) const { return VState.vQtrn.GetSinEuler(idx); }
- double Gethdot(void) const { return -vVel(eDown); }
-
- /** Returns the "constant" RunwayRadius.
- The RunwayRadius parameter is set by the calling application or set to
- zero if JSBSim is running in standalone mode.
- @return distance of the runway from the center of the earth.
- @units feet */
- double GetRunwayRadius(void) const;
- double GetSeaLevelRadius(void) const { return SeaLevelRadius; }
- double GetDistanceAGL(void) const;
- double GetRadius(void) const { return VState.vLocation.GetRadius(); }
- double GetLongitude(void) const { return VState.vLocation.GetLongitude(); }
- double GetLatitude(void) const { return VState.vLocation.GetLatitude(); }
- const FGLocation& GetLocation(void) const { return VState.vLocation; }
-
- /** Retrieves the local-to-body transformation matrix.
- @return a reference to the local-to-body transformation matrix. */
- const FGMatrix33& GetTl2b(void) const { return VState.vQtrn.GetT(); }
-
- /** Retrieves the body-to-local transformation matrix.
- @return a reference to the body-to-local matrix. */
- const FGMatrix33& GetTb2l(void) const { return VState.vQtrn.GetTInv(); }
-
-// SET functions
-
- void SetLongitude(double lon) { VState.vLocation.SetLongitude(lon); }
- void SetLatitude(double lat) { VState.vLocation.SetLatitude(lat); }
- void SetRadius(double r) { VState.vLocation.SetRadius(r); }
- void SetLocation(const FGLocation& l) { VState.vLocation = l; }
- void Seth(double tt);
- void SetSeaLevelRadius(double tt) { SeaLevelRadius = tt; }
- void SetDistanceAGL(double tt);
- void SetInitialState(const FGInitialCondition *);
-
- void RecomputeRunwayRadius(void);
-
- void bind(void);
- void unbind(void);
-
-private:
-
-// state vector
-
- struct VehicleState VState;
-
- FGColumnVector3 vVel;
- FGColumnVector3 vPQRdot;
- FGColumnVector3 vUVWdot;
-
- double RunwayRadius, SeaLevelRadius;
-
- void Debug(int from);
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGPropeller.cpp
- Author: Jon S. Berndt
- Date started: 08/24/00
- Purpose: Encapsulates the propeller object
-
- ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-HISTORY
---------------------------------------------------------------------------------
-08/24/00 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <sstream>
-
-#include "FGPropeller.h"
-#include "FGPropagate.h"
-#include "FGAtmosphere.h"
-#include "FGAuxiliary.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_PROPELLER;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-// This class currently makes certain assumptions when calculating torque and
-// p-factor. That is, that the axis of rotation is the X axis of the aircraft -
-// not just the X-axis of the engine/propeller. This may or may not work for a
-// helicopter.
-
-FGPropeller::FGPropeller(FGFDMExec* exec, FGConfigFile* Prop_cfg, int num) : FGThruster(exec)
-{
- string token;
- int rows, cols;
-
- MaxPitch = MinPitch = P_Factor = Sense = Pitch = Advance = 0.0;
- GearRatio = 1.0;
-
- Name = Prop_cfg->GetValue("NAME");
- Prop_cfg->GetNextConfigLine();
- while (Prop_cfg->GetValue() != string("/FG_PROPELLER")) {
- *Prop_cfg >> token;
- if (token == "IXX") {
- *Prop_cfg >> Ixx;
- } else if (token == "DIAMETER") {
- *Prop_cfg >> Diameter;
- Diameter /= 12.0;
- } else if (token == "NUMBLADES") {
- *Prop_cfg >> numBlades;
- } else if (token == "GEARRATIO") {
- *Prop_cfg >> GearRatio;
- } else if (token == "MINPITCH") {
- *Prop_cfg >> MinPitch;
- } else if (token == "MAXPITCH") {
- *Prop_cfg >> MaxPitch;
- } else if (token == "MINRPM") {
- *Prop_cfg >> MinRPM;
- } else if (token == "MAXRPM") {
- *Prop_cfg >> MaxRPM;
- } else if (token == "C_THRUST") {
- *Prop_cfg >> rows >> cols;
- if (cols == 1) cThrust = new FGTable(rows);
- else cThrust = new FGTable(rows, cols);
- *cThrust << *Prop_cfg;
- } else if (token == "C_POWER") {
- *Prop_cfg >> rows >> cols;
- if (cols == 1) cPower = new FGTable(rows);
- else cPower = new FGTable(rows, cols);
- *cPower << *Prop_cfg;
- } else if (token == "EOF") {
- cerr << " End of file reached" << endl;
- break;
- } else {
- cerr << "Unhandled token in Propeller config file: " << token << endl;
- }
- }
-
- Type = ttPropeller;
- RPM = 0;
- vTorque.InitMatrix();
-
- char property_name[80];
- snprintf(property_name, 80, "propulsion/c-thrust[%u]", EngineNum);
- PropertyManager->Tie( property_name, &ThrustCoeff );
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGPropeller::~FGPropeller()
-{
- if (cThrust) delete cThrust;
- if (cPower) delete cPower;
-
- char property_name[80];
- snprintf(property_name, 80, "propulsion/c-thrust[%u]", EngineNum);
- PropertyManager->Untie( property_name );
-
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-//
-// We must be getting the aerodynamic velocity here, NOT the inertial velocity.
-// We need the velocity with respect to the wind.
-//
-// Note that PowerAvailable is the excess power available after the drag of the
-// propeller has been subtracted. At equilibrium, PowerAvailable will be zero -
-// indicating that the propeller will not accelerate or decelerate.
-// Remembering that Torque * omega = Power, we can derive the torque on the
-// propeller and its acceleration to give a new RPM. The current RPM will be
-// used to calculate thrust.
-//
-// Because RPM could be zero, we need to be creative about what RPM is stated as.
-
-double FGPropeller::Calculate(double PowerAvailable)
-{
- double J, omega;
- double Vel = fdmex->GetAuxiliary()->GetAeroUVW(eU);
- double rho = fdmex->GetAtmosphere()->GetDensity();
- double RPS = RPM/60.0;
- double alpha, beta;
-
- if (RPM > 0.10) {
- J = Vel / (Diameter * RPS);
- } else {
- J = 0.0;
- }
-
- if (MaxPitch == MinPitch) { // Fixed pitch prop
- ThrustCoeff = cThrust->GetValue(J);
- } else { // Variable pitch prop
- ThrustCoeff = cThrust->GetValue(J, Pitch);
- }
-
- if (P_Factor > 0.0001) {
- alpha = fdmex->GetAuxiliary()->Getalpha();
- beta = fdmex->GetAuxiliary()->Getbeta();
- SetActingLocationY( GetLocationY() + P_Factor*alpha*Sense);
- SetActingLocationZ( GetLocationZ() + P_Factor*beta*Sense);
- } else if (P_Factor < 0.000) {
- cerr << "P-Factor value in config file must be greater than zero" << endl;
- }
-
- Thrust = ThrustCoeff*RPS*RPS*Diameter*Diameter*Diameter*Diameter*rho;
- omega = RPS*2.0*M_PI;
-
- vFn(1) = Thrust;
-
- // The Ixx value and rotation speed given below are for rotation about the
- // natural axis of the engine. The transform takes place in the base class
- // FGForce::GetBodyForces() function.
-
- vH(eX) = Ixx*omega*Sense;
- vH(eY) = 0.0;
- vH(eZ) = 0.0;
-
- if (omega <= 5) omega = 1.0;
-
- ExcessTorque = PowerAvailable / omega * GearRatio;
- RPM = (RPS + ((ExcessTorque / Ixx) / (2.0 * M_PI)) * deltaT) * 60.0;
-
- // The friction from the engine should
- // stop it somewhere; I chose an
- // arbitrary point.
- if (RPM < 5.0)
- RPM = 0;
-
- vMn = fdmex->GetPropagate()->GetPQR()*vH + vTorque*Sense;
-
- return Thrust; // return thrust in pounds
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGPropeller::GetPowerRequired(void)
-{
- if (RPM <= 0.10) return 0.0; // If the prop ain't turnin', the fuel ain't burnin'.
-
- double cPReq, RPS = RPM / 60.0;
-
- double J = fdmex->GetAuxiliary()->GetAeroUVW(eU) / (Diameter * RPS);
- double rho = fdmex->GetAtmosphere()->GetDensity();
-
- if (MaxPitch == MinPitch) { // Fixed pitch prop
- Pitch = MinPitch;
- cPReq = cPower->GetValue(J);
- } else { // Variable pitch prop
-
- if (MaxRPM != MinRPM) { // fixed-speed prop
- double rpmReq = MinRPM + (MaxRPM - MinRPM) * Advance;
- double dRPM = rpmReq - RPM;
-
- Pitch -= dRPM / 10;
-
- if (Pitch < MinPitch) Pitch = MinPitch;
- else if (Pitch > MaxPitch) Pitch = MaxPitch;
-
- } else {
- Pitch = MinPitch + (MaxPitch - MinPitch) * Advance;
- }
- cPReq = cPower->GetValue(J, Pitch);
- }
-
- PowerRequired = cPReq*RPS*RPS*RPS*Diameter*Diameter*Diameter*Diameter
- *Diameter*rho;
- vTorque(eX) = -Sense*PowerRequired / (RPS*2.0*M_PI);
-
- return PowerRequired;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGColumnVector3 FGPropeller::GetPFactor()
-{
- double px=0.0, py, pz;
-
- py = Thrust * Sense * (GetActingLocationY() - GetLocationY()) / 12.0;
- pz = Thrust * Sense * (GetActingLocationZ() - GetLocationZ()) / 12.0;
-
- return FGColumnVector3(px, py, pz);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGPropeller::GetThrusterLabels(int id, string delimeter)
-{
- std::ostringstream buf;
-
- buf << Name << "_Torque[" << id << "]" << delimeter
- << Name << "_PFactor_Pitch[" << id << "]" << delimeter
- << Name << "_PFactor_Yaw[" << id << "]" << delimeter
- << Name << "_Thrust[" << id << "]" << delimeter;
- if (IsVPitch())
- buf << Name << "_Pitch[" << id << "]" << delimeter;
- buf << Name << "_RPM[" << id << "]";
-
- return buf.str();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGPropeller::GetThrusterValues(int id, string delimeter)
-{
- std::ostringstream buf;
-
- FGColumnVector3 vPFactor = GetPFactor();
- buf << vTorque(eX) << delimeter
- << vPFactor(ePitch) << delimeter
- << vPFactor(eYaw) << delimeter
- << Thrust << delimeter;
- if (IsVPitch())
- buf << Pitch << delimeter;
- buf << RPM;
-
- return buf.str();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGPropeller::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
- cout << "\n Propeller Name: " << Name << endl;
- cout << " IXX = " << Ixx << endl;
- cout << " Diameter = " << Diameter << " ft." << endl;
- cout << " Number of Blades = " << numBlades << endl;
- cout << " Minimum Pitch = " << MinPitch << endl;
- cout << " Maximum Pitch = " << MaxPitch << endl;
- cout << " Thrust Coefficient: " << endl;
- cThrust->Print();
- cout << " Power Coefficient: " << endl;
- cPower->Print();
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGPropeller" << endl;
- if (from == 1) cout << "Destroyed: FGPropeller" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGPropeller.h
- Author: Jon S. Berndt
- Date started: 08/24/00
-
- ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-08/24/00 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGPROPELLER_H
-#define FGPROPELLER_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGThruster.h"
-#include "FGTable.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_PROPELLER "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Propeller modeling class.
- FGPropeller models a propeller given the tabular data for Ct and Cp
- indexed by advance ratio "J". The data for the propeller is
- stored in a config file named "prop_name.xml". The propeller config file
- is referenced from the main aircraft config file in the "Propulsion" section.
- See the constructor for FGPropeller to see what is read in and what should
- be stored in the config file.<br>
- Several references were helpful, here:<ul>
- <li>Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
- Wiley & Sons, 1979 ISBN 0-471-03032-5</li>
- <li>Edwin Hartman, David Biermann, "The Aerodynamic Characteristics of
- Full Scale Propellers Having 2, 3, and 4 Blades of Clark Y and R.A.F. 6
- Airfoil Sections", NACA Report TN-640, 1938 (?)</li>
- <li>Various NACA Technical Notes and Reports</li>
- </ul>
- @author Jon S. Berndt
- @version $Id$
- @see FGEngine
- @see FGThruster
- @see FGTable
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGPropeller : public FGThruster {
-
-public:
- /** Constructor for FGPropeller.
- @param exec a pointer to the main executive object
- @param AC_cfg a pointer to the main aircraft config file object */
- FGPropeller(FGFDMExec* exec, FGConfigFile* AC_cfg, int num = 0);
-
- /// Destructor for FGPropeller - deletes the FGTable objects
- ~FGPropeller();
-
- /** Sets the Revolutions Per Minute for the propeller. Normally the propeller
- instance will calculate its own rotational velocity, given the Torque
- produced by the engine and integrating over time using the standard
- equation for rotational acceleration "a": a = Q/I , where Q is Torque and
- I is moment of inertia for the propeller.
- @param rpm the rotational velocity of the propeller */
- void SetRPM(double rpm) {RPM = rpm;}
-
- /// Returns true of this propeller is variable pitch
- bool IsVPitch(void) {return MaxPitch != MinPitch;}
-
- /** This commands the pitch of the blade to change to the value supplied.
- This call is meant to be issued either from the cockpit or by the flight
- control system (perhaps to maintain constant RPM for a constant-speed
- propeller). This value will be limited to be within whatever is specified
- in the config file for Max and Min pitch. It is also one of the lookup
- indices to the power and thrust tables for variable-pitch propellers.
- @param pitch the pitch of the blade in degrees. */
- void SetPitch(double pitch) {Pitch = pitch;}
-
- void SetAdvance(double advance) {Advance = advance;}
-
- /// Sets the P-Factor constant
- void SetPFactor(double pf) {P_Factor = pf;}
-
- /** Sets the rotation sense of the propeller.
- @param s this value should be +/- 1 ONLY. +1 indicates clockwise rotation as
- viewed by someone standing behind the engine looking forward into
- the direction of flight. */
- void SetSense(double s) { Sense = s;}
-
- double GetSense(void) {return Sense;}
- double GetPFactorValue(void) {return P_Factor;}
-
- /// Retrieves the pitch of the propeller in degrees.
- double GetPitch(void) { return Pitch; }
-
- /// Retrieves the RPMs of the propeller
- double GetRPM(void) { return RPM; }
-
- /// Retrieves the propeller moment of inertia
- double GetIxx(void) { return Ixx; }
-
- /// Retrieves the Torque in foot-pounds (Don't you love the English system?)
- double GetTorque(void) { return vTorque(eX); }
-
- /** Retrieves the power required (or "absorbed") by the propeller -
- i.e. the power required to keep spinning the propeller at the current
- velocity, air density, and rotational rate. */
- double GetPowerRequired(void);
-
- /** Calculates and returns the thrust produced by this propeller.
- Given the excess power available from the engine (in foot-pounds), the thrust is
- calculated, as well as the current RPM. The RPM is calculated by integrating
- the torque provided by the engine over what the propeller "absorbs"
- (essentially the "drag" of the propeller).
- @param PowerAvailable this is the excess power provided by the engine to
- accelerate the prop. It could be negative, dictating that the propeller
- would be slowed.
- @return the thrust in pounds */
- double Calculate(double PowerAvailable);
- FGColumnVector3 GetPFactor(void);
- string GetThrusterLabels(int id, string delimeter);
- string GetThrusterValues(int id, string delimeter);
-
-private:
- int numBlades;
- double RPM;
- double Ixx;
- double Diameter;
- double MaxPitch;
- double MinPitch;
- double MinRPM;
- double MaxRPM;
- double P_Factor;
- double Sense;
- double Pitch;
- double Advance;
- double ExcessTorque;
- FGColumnVector3 vTorque;
- FGTable *cThrust;
- FGTable *cPower;
- void Debug(int from);
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
-
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGPropertyManager.cpp
- Author: Tony Peden
- Based on work originally by David Megginson
- Date: 2/2002
-
- ------------- Copyright (C) 2002 -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGPropertyManager.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-using namespace std;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-COMMENTS, REFERENCES, and NOTES [use "class documentation" below for API docs]
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-*/
-
-namespace JSBSim {
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGPropertyManager::mkPropertyName(string name, bool lowercase) {
-
- /* do this two pass to avoid problems with characters getting skipped
- because the index changed */
- unsigned i;
- for(i=0;i<name.length();i++) {
- if( lowercase && isupper(name[i]) )
- name[i]=tolower(name[i]);
- else if( isspace(name[i]) )
- name[i]='-';
- }
- for(i=0;i<name.length();i++) {
- if( name[i] == '/' )
- name.erase(i,1);
- }
-
- return name;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGPropertyManager*
-FGPropertyManager::GetNode (const string &path, bool create)
-{
- SGPropertyNode* node=this->getNode(path.c_str(), create);
- //if(node == 0)
- // cout << "FGPropertyManager::GetNode() No node found for "
- // << path << endl;
- return (FGPropertyManager*)node;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGPropertyManager*
-FGPropertyManager::GetNode (const string &relpath, int index, bool create)
-{
- return (FGPropertyManager*)getNode(relpath.c_str(),index,create);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-bool FGPropertyManager::HasNode (const string &path)
-{
- return (GetNode(path, false) != 0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGPropertyManager::GetName( void ) {
- return string( getName() );
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGPropertyManager::GetFullyQualifiedName(void) {
- vector<string> stack;
- stack.push_back( getDisplayName(true) );
- SGPropertyNode* tmpn=getParent();
- bool atroot=false;
- while( !atroot ) {
- stack.push_back( tmpn->getDisplayName(true) );
- if( !tmpn->getParent() )
- atroot=true;
- else
- tmpn=tmpn->getParent();
- }
-
- string fqname="";
- for(unsigned i=stack.size()-1;i>0;i--) {
- fqname+= stack[i];
- fqname+= "/";
- }
- fqname+= stack[0];
- return fqname;
-
-}
-
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGPropertyManager::GetBool (const string &name, bool defaultValue)
-{
- return getBoolValue(name.c_str(), defaultValue);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-int FGPropertyManager::GetInt (const string &name, int defaultValue )
-{
- return getIntValue(name.c_str(), defaultValue);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-int FGPropertyManager::GetLong (const string &name, long defaultValue )
-{
- return getLongValue(name.c_str(), defaultValue);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-float FGPropertyManager::GetFloat (const string &name, float defaultValue )
-{
- return getFloatValue(name.c_str(), defaultValue);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGPropertyManager::GetDouble (const string &name, double defaultValue )
-{
- return getDoubleValue(name.c_str(), defaultValue);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGPropertyManager::GetString (const string &name, string defaultValue )
-{
- return string(getStringValue(name.c_str(), defaultValue.c_str()));
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGPropertyManager::SetBool (const string &name, bool val)
-{
- return setBoolValue(name.c_str(), val);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGPropertyManager::SetInt (const string &name, int val)
-{
- return setIntValue(name.c_str(), val);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGPropertyManager::SetLong (const string &name, long val)
-{
- return setLongValue(name.c_str(), val);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGPropertyManager::SetFloat (const string &name, float val)
-{
- return setFloatValue(name.c_str(), val);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGPropertyManager::SetDouble (const string &name, double val)
-{
- return setDoubleValue(name.c_str(), val);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGPropertyManager::SetString (const string &name, const string &val)
-{
- return setStringValue(name.c_str(), val.c_str());
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropertyManager::SetArchivable (const string &name, bool state )
-{
- SGPropertyNode * node = getNode(name.c_str());
- if (node == 0)
- cout <<
- "Attempt to set archive flag for non-existant property "
- << name << endl;
- else
- node->setAttribute(SGPropertyNode::ARCHIVE, state);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropertyManager::SetReadable (const string &name, bool state )
-{
- SGPropertyNode * node = getNode(name.c_str());
- if (node == 0)
- cout <<
- "Attempt to set read flag for non-existant property "
- << name << endl;
- else
- node->setAttribute(SGPropertyNode::READ, state);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropertyManager::SetWritable (const string &name, bool state )
-{
- SGPropertyNode * node = getNode(name.c_str());
- if (node == 0)
- cout <<
- "Attempt to set write flag for non-existant property "
- << name << endl;
- else
- node->setAttribute(SGPropertyNode::WRITE, state);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropertyManager::Untie (const string &name)
-{
- if (!untie(name.c_str()))
- cout << "Failed to untie property " << name << endl;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropertyManager::Tie (const string &name, bool *pointer, bool useDefault)
-{
- if (!tie(name.c_str(), SGRawValuePointer<bool>(pointer),
- useDefault))
- cout <<
- "Failed to tie property " << name << " to a pointer" << endl;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropertyManager::Tie (const string &name, int *pointer,
- bool useDefault )
-{
- if (!tie(name.c_str(), SGRawValuePointer<int>(pointer),
- useDefault))
- cout <<
- "Failed to tie property " << name << " to a pointer" << endl;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropertyManager::Tie (const string &name, long *pointer,
- bool useDefault )
-{
- if (!tie(name.c_str(), SGRawValuePointer<long>(pointer),
- useDefault))
- cout <<
- "Failed to tie property " << name << " to a pointer" << endl;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropertyManager::Tie (const string &name, float *pointer,
- bool useDefault )
-{
- if (!tie(name.c_str(), SGRawValuePointer<float>(pointer),
- useDefault))
- cout <<
- "Failed to tie property " << name << " to a pointer" << endl;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropertyManager::Tie (const string &name, double *pointer,
- bool useDefault)
-{
- if (!tie(name.c_str(), SGRawValuePointer<double>(pointer),
- useDefault))
- cout <<
- "Failed to tie property " << name << " to a pointer" << endl;
-}
-
-} // namespace JSBSim
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGPropertyManager.h
- Author: Tony Peden
- Based on work originally by David Megginson
- Date: 2/2002
-
- ------------- Copyright (C) 2002 -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGPROPERTYMANAGER_H
-#define FGPROPERTYMANAGER_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include <string>
-#ifdef FGFS
-#include <simgear/props/props.hxx>
-#else
-#include "simgear/props/props.hxx"
-#endif
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_PROPERTYMANAGER "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-using namespace std;
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Class wrapper for property handling.
- @author David Megginson, Tony Peden
- */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGPropertyManager : public SGPropertyNode {
- public:
- /// Constructor
- FGPropertyManager(void) {}
- /// Destructor
- ~FGPropertyManager(void) {}
-
- /** Property-ify a name
- * replaces spaces with '-' and, optionally, makes name all lower case
- * @param name string to change
- * @param lowercase true to change all upper case chars to lower
- * NOTE: this function changes its argument and thus relies
- * on pass by value
- */
- string mkPropertyName(string name, bool lowercase);
-
- /**
- * Get a property node.
- *
- * @param path The path of the node, relative to root.
- * @param create true to create the node if it doesn't exist.
- * @return The node, or 0 if none exists and none was created.
- */
- FGPropertyManager*
- GetNode (const string &path, bool create = false);
-
- FGPropertyManager*
- GetNode (const string &relpath, int index, bool create = false);
-
- /**
- * Test whether a given node exists.
- *
- * @param path The path of the node, relative to root.
- * @return true if the node exists, false otherwise.
- */
- bool HasNode (const string &path);
-
- /**
- * Get the name of a node
- */
- string GetName( void );
-
- /**
- * Get the fully qualified name of a node
- * This function is very slow, so is probably useful for debugging only.
- */
- string GetFullyQualifiedName(void);
-
- /**
- * Get a bool value for a property.
- *
- * This method is convenient but inefficient. It should be used
- * infrequently (i.e. for initializing, loading, saving, etc.),
- * not in the main loop. If you need to get a value frequently,
- * it is better to look up the node itself using GetNode and then
- * use the node's getBoolValue() method, to avoid the lookup overhead.
- *
- * @param name The property name.
- * @param defaultValue The default value to return if the property
- * does not exist.
- * @return The property's value as a bool, or the default value provided.
- */
- bool GetBool (const string &name, bool defaultValue = false);
-
-
- /**
- * Get an int value for a property.
- *
- * This method is convenient but inefficient. It should be used
- * infrequently (i.e. for initializing, loading, saving, etc.),
- * not in the main loop. If you need to get a value frequently,
- * it is better to look up the node itself using GetNode and then
- * use the node's getIntValue() method, to avoid the lookup overhead.
- *
- * @param name The property name.
- * @param defaultValue The default value to return if the property
- * does not exist.
- * @return The property's value as an int, or the default value provided.
- */
- int GetInt (const string &name, int defaultValue = 0);
-
-
- /**
- * Get a long value for a property.
- *
- * This method is convenient but inefficient. It should be used
- * infrequently (i.e. for initializing, loading, saving, etc.),
- * not in the main loop. If you need to get a value frequently,
- * it is better to look up the node itself using GetNode and then
- * use the node's getLongValue() method, to avoid the lookup overhead.
- *
- * @param name The property name.
- * @param defaultValue The default value to return if the property
- * does not exist.
- * @return The property's value as a long, or the default value provided.
- */
- int GetLong (const string &name, long defaultValue = 0L);
-
-
- /**
- * Get a float value for a property.
- *
- * This method is convenient but inefficient. It should be used
- * infrequently (i.e. for initializing, loading, saving, etc.),
- * not in the main loop. If you need to get a value frequently,
- * it is better to look up the node itself using GetNode and then
- * use the node's getFloatValue() method, to avoid the lookup overhead.
- *
- * @param name The property name.
- * @param defaultValue The default value to return if the property
- * does not exist.
- * @return The property's value as a float, or the default value provided.
- */
- float GetFloat (const string &name, float defaultValue = 0.0);
-
-
- /**
- * Get a double value for a property.
- *
- * This method is convenient but inefficient. It should be used
- * infrequently (i.e. for initializing, loading, saving, etc.),
- * not in the main loop. If you need to get a value frequently,
- * it is better to look up the node itself using GetNode and then
- * use the node's getDoubleValue() method, to avoid the lookup overhead.
- *
- * @param name The property name.
- * @param defaultValue The default value to return if the property
- * does not exist.
- * @return The property's value as a double, or the default value provided.
- */
- double GetDouble (const string &name, double defaultValue = 0.0);
-
-
- /**
- * Get a string value for a property.
- *
- * This method is convenient but inefficient. It should be used
- * infrequently (i.e. for initializing, loading, saving, etc.),
- * not in the main loop. If you need to get a value frequently,
- * it is better to look up the node itself using GetNode and then
- * use the node's getStringValue() method, to avoid the lookup overhead.
- *
- * @param name The property name.
- * @param defaultValue The default value to return if the property
- * does not exist.
- * @return The property's value as a string, or the default value provided.
- */
- string GetString (const string &name, string defaultValue = "");
-
-
- /**
- * Set a bool value for a property.
- *
- * Assign a bool value to a property. If the property does not
- * yet exist, it will be created and its type will be set to
- * BOOL; if it has a type of UNKNOWN, the type will also be set to
- * BOOL; otherwise, the bool value will be converted to the property's
- * type.
- *
- * @param name The property name.
- * @param val The new value for the property.
- * @return true if the assignment succeeded, false otherwise.
- */
- bool SetBool (const string &name, bool val);
-
-
- /**
- * Set an int value for a property.
- *
- * Assign an int value to a property. If the property does not
- * yet exist, it will be created and its type will be set to
- * INT; if it has a type of UNKNOWN, the type will also be set to
- * INT; otherwise, the bool value will be converted to the property's
- * type.
- *
- * @param name The property name.
- * @param val The new value for the property.
- * @return true if the assignment succeeded, false otherwise.
- */
- bool SetInt (const string &name, int val);
-
-
- /**
- * Set a long value for a property.
- *
- * Assign a long value to a property. If the property does not
- * yet exist, it will be created and its type will be set to
- * LONG; if it has a type of UNKNOWN, the type will also be set to
- * LONG; otherwise, the bool value will be converted to the property's
- * type.
- *
- * @param name The property name.
- * @param val The new value for the property.
- * @return true if the assignment succeeded, false otherwise.
- */
- bool SetLong (const string &name, long val);
-
-
- /**
- * Set a float value for a property.
- *
- * Assign a float value to a property. If the property does not
- * yet exist, it will be created and its type will be set to
- * FLOAT; if it has a type of UNKNOWN, the type will also be set to
- * FLOAT; otherwise, the bool value will be converted to the property's
- * type.
- *
- * @param name The property name.
- * @param val The new value for the property.
- * @return true if the assignment succeeded, false otherwise.
- */
- bool SetFloat (const string &name, float val);
-
-
- /**
- * Set a double value for a property.
- *
- * Assign a double value to a property. If the property does not
- * yet exist, it will be created and its type will be set to
- * DOUBLE; if it has a type of UNKNOWN, the type will also be set to
- * DOUBLE; otherwise, the double value will be converted to the property's
- * type.
- *
- * @param name The property name.
- * @param val The new value for the property.
- * @return true if the assignment succeeded, false otherwise.
- */
- bool SetDouble (const string &name, double val);
-
-
- /**
- * Set a string value for a property.
- *
- * Assign a string value to a property. If the property does not
- * yet exist, it will be created and its type will be set to
- * STRING; if it has a type of UNKNOWN, the type will also be set to
- * STRING; otherwise, the string value will be converted to the property's
- * type.
- *
- * @param name The property name.
- * @param val The new value for the property.
- * @return true if the assignment succeeded, false otherwise.
- */
- bool SetString (const string &name, const string &val);
-
-
- ////////////////////////////////////////////////////////////////////////
- // Convenience functions for setting property attributes.
- ////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Set the state of the archive attribute for a property.
- *
- * If the archive attribute is true, the property will be written
- * when a flight is saved; if it is false, the property will be
- * skipped.
- *
- * A warning message will be printed if the property does not exist.
- *
- * @param name The property name.
- * @param state The state of the archive attribute (defaults to true).
- */
- void SetArchivable (const string &name, bool state = true);
-
-
- /**
- * Set the state of the read attribute for a property.
- *
- * If the read attribute is true, the property value will be readable;
- * if it is false, the property value will always be the default value
- * for its type.
- *
- * A warning message will be printed if the property does not exist.
- *
- * @param name The property name.
- * @param state The state of the read attribute (defaults to true).
- */
- void SetReadable (const string &name, bool state = true);
-
-
- /**
- * Set the state of the write attribute for a property.
- *
- * If the write attribute is true, the property value may be modified
- * (depending on how it is tied); if the write attribute is false, the
- * property value may not be modified.
- *
- * A warning message will be printed if the property does not exist.
- *
- * @param name The property name.
- * @param state The state of the write attribute (defaults to true).
- */
- void SetWritable (const string &name, bool state = true);
-
-
- ////////////////////////////////////////////////////////////////////////
- // Convenience functions for tying properties, with logging.
- ////////////////////////////////////////////////////////////////////////
-
-
- /**
- * Untie a property from an external data source.
- *
- * Classes should use this function to release control of any
- * properties they are managing.
- */
- void Untie (const string &name);
-
-
- // Templates cause ambiguity here
-
- /**
- * Tie a property to an external bool variable.
- *
- * The property's value will automatically mirror the variable's
- * value, and vice-versa, until the property is untied.
- *
- * @param name The property name to tie (full path).
- * @param pointer A pointer to the variable.
- * @param useDefault true if any existing property value should be
- * copied to the variable; false if the variable should not
- * be modified; defaults to true.
- */
- void
- Tie (const string &name, bool *pointer, bool useDefault = true);
-
-
- /**
- * Tie a property to an external int variable.
- *
- * The property's value will automatically mirror the variable's
- * value, and vice-versa, until the property is untied.
- *
- * @param name The property name to tie (full path).
- * @param pointer A pointer to the variable.
- * @param useDefault true if any existing property value should be
- * copied to the variable; false if the variable should not
- * be modified; defaults to true.
- */
- void
- Tie (const string &name, int *pointer, bool useDefault = true);
-
-
- /**
- * Tie a property to an external long variable.
- *
- * The property's value will automatically mirror the variable's
- * value, and vice-versa, until the property is untied.
- *
- * @param name The property name to tie (full path).
- * @param pointer A pointer to the variable.
- * @param useDefault true if any existing property value should be
- * copied to the variable; false if the variable should not
- * be modified; defaults to true.
- */
- void
- Tie (const string &name, long *pointer, bool useDefault = true);
-
-
- /**
- * Tie a property to an external float variable.
- *
- * The property's value will automatically mirror the variable's
- * value, and vice-versa, until the property is untied.
- *
- * @param name The property name to tie (full path).
- * @param pointer A pointer to the variable.
- * @param useDefault true if any existing property value should be
- * copied to the variable; false if the variable should not
- * be modified; defaults to true.
- */
- void
- Tie (const string &name, float *pointer, bool useDefault = true);
-
- /**
- * Tie a property to an external double variable.
- *
- * The property's value will automatically mirror the variable's
- * value, and vice-versa, until the property is untied.
- *
- * @param name The property name to tie (full path).
- * @param pointer A pointer to the variable.
- * @param useDefault true if any existing property value should be
- * copied to the variable; false if the variable should not
- * be modified; defaults to true.
- */
- void
- Tie (const string &name, double *pointer, bool useDefault = true);
-
-//============================================================================
-//
-// All of the following functions *must* be inlined, otherwise linker
-// errors will result
-//
-//============================================================================
-
- /* template <class V> void
- Tie (const string &name, V (*getter)(), void (*setter)(V) = 0,
- bool useDefault = true);
-
- template <class V> void
- Tie (const string &name, int index, V (*getter)(int),
- void (*setter)(int, V) = 0, bool useDefault = true);
-
- template <class T, class V> void
- Tie (const string &name, T * obj, V (T::*getter)() const,
- void (T::*setter)(V) = 0, bool useDefault = true);
-
- template <class T, class V> void
- Tie (const string &name, T * obj, int index,
- V (T::*getter)(int) const, void (T::*setter)(int, V) = 0,
- bool useDefault = true); */
-
- /**
- * Tie a property to a pair of simple functions.
- *
- * Every time the property value is queried, the getter (if any) will
- * be invoked; every time the property value is modified, the setter
- * (if any) will be invoked. The getter can be 0 to make the property
- * unreadable, and the setter can be 0 to make the property
- * unmodifiable.
- *
- * @param name The property name to tie (full path).
- * @param getter The getter function, or 0 if the value is unreadable.
- * @param setter The setter function, or 0 if the value is unmodifiable.
- * @param useDefault true if the setter should be invoked with any existing
- * property value should be; false if the old value should be
- * discarded; defaults to true.
- */
-
- template <class V> inline void
- Tie (const string &name, V (*getter)(), void (*setter)(V) = 0,
- bool useDefault = true)
- {
- if (!tie(name.c_str(), SGRawValueFunctions<V>(getter, setter),
- useDefault))
- {
- cout <<
- "Failed to tie property " << name << " to functions" << endl;
- }
- }
-
-
- /**
- * Tie a property to a pair of indexed functions.
- *
- * Every time the property value is queried, the getter (if any) will
- * be invoked with the index provided; every time the property value
- * is modified, the setter (if any) will be invoked with the index
- * provided. The getter can be 0 to make the property unreadable, and
- * the setter can be 0 to make the property unmodifiable.
- *
- * @param name The property name to tie (full path).
- * @param index The integer argument to pass to the getter and
- * setter functions.
- * @param getter The getter function, or 0 if the value is unreadable.
- * @param setter The setter function, or 0 if the value is unmodifiable.
- * @param useDefault true if the setter should be invoked with any existing
- * property value should be; false if the old value should be
- * discarded; defaults to true.
- */
- template <class V> inline void Tie (const string &name,
- int index, V (*getter)(int),
- void (*setter)(int, V) = 0, bool useDefault = true)
- {
- if (!tie(name.c_str(),
- SGRawValueFunctionsIndexed<V>(index, getter, setter), useDefault))
- {
- cout <<
- "Failed to tie property " << name << " to indexed functions" << endl;
- }
- }
-
-
- /**
- * Tie a property to a pair of object methods.
- *
- * Every time the property value is queried, the getter (if any) will
- * be invoked; every time the property value is modified, the setter
- * (if any) will be invoked. The getter can be 0 to make the property
- * unreadable, and the setter can be 0 to make the property
- * unmodifiable.
- *
- * @param name The property name to tie (full path).
- * @param obj The object whose methods should be invoked.
- * @param getter The object's getter method, or 0 if the value is
- * unreadable.
- * @param setter The object's setter method, or 0 if the value is
- * unmodifiable.
- * @param useDefault true if the setter should be invoked with any existing
- * property value should be; false if the old value should be
- * discarded; defaults to true.
- */
- template <class T, class V> inline void
- Tie (const string &name, T * obj, V (T::*getter)() const,
- void (T::*setter)(V) = 0, bool useDefault = true)
- {
- if (!tie(name.c_str(),
- SGRawValueMethods<T,V>(*obj, getter, setter), useDefault))
- {
- cout <<
- "Failed to tie property " << name << " to object methods" << endl;
- }
- }
-
- /**
- * Tie a property to a pair of indexed object methods.
- *
- * Every time the property value is queried, the getter (if any) will
- * be invoked with the index provided; every time the property value
- * is modified, the setter (if any) will be invoked with the index
- * provided. The getter can be 0 to make the property unreadable, and
- * the setter can be 0 to make the property unmodifiable.
- *
- * @param name The property name to tie (full path).
- * @param obj The object whose methods should be invoked.
- * @param index The integer argument to pass to the getter and
- * setter methods.
- * @param getter The getter method, or 0 if the value is unreadable.
- * @param setter The setter method, or 0 if the value is unmodifiable.
- * @param useDefault true if the setter should be invoked with any existing
- * property value should be; false if the old value should be
- * discarded; defaults to true.
- */
- template <class T, class V> inline void
- Tie (const string &name, T * obj, int index,
- V (T::*getter)(int) const, void (T::*setter)(int, V) = 0,
- bool useDefault = true)
- {
- if (!tie(name.c_str(),
- SGRawValueMethodsIndexed<T,V>(*obj, index, getter, setter), useDefault))
- {
- cout <<
- "Failed to tie property " << name << " to indexed object methods" << endl;
- }
- }
-};
-}
-#endif // FGPROPERTYMANAGER_H
-
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGPropulsion.cpp
- Author: Jon S. Berndt
- Date started: 08/20/00
- Purpose: Encapsulates the set of engines and tanks associated
- with this aircraft
-
- ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-The Propulsion class is the container for the entire propulsion system, which is
-comprised of engines and tanks. Once the Propulsion class gets the config file,
-it reads in information which is specific to a type of engine. Then:
-
-1) The appropriate engine type instance is created
-2) At least one tank object is created, and is linked to an engine.
-
-At Run time each engines Calculate() method is called.
-
-HISTORY
---------------------------------------------------------------------------------
-08/20/00 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "FGPropulsion.h"
-#include "FGRocket.h"
-#include "FGTurbine.h"
-#include "FGPiston.h"
-#include "FGElectric.h"
-#include "FGPropertyManager.h"
-#include <sstream>
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_PROPULSION;
-
-extern short debug_lvl;
-
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)
-{
- Name = "FGPropulsion";
-
- numSelectedFuelTanks = numSelectedOxiTanks = 0;
- numTanks = numEngines = 0;
- numOxiTanks = numFuelTanks = 0;
- ActiveEngine = -1; // -1: ALL, 0: Engine 1, 1: Engine 2 ...
- tankJ.InitMatrix();
- refuel = false;
- fuel_freeze = false;
-
- bind();
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGPropulsion::~FGPropulsion()
-{
- for (unsigned int i=0; i<Engines.size(); i++) delete Engines[i];
- Engines.clear();
- unbind();
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGPropulsion::Run(void)
-{
- unsigned int i;
-
- if (FGModel::Run()) return true;
-
- double dt = State->Getdt();
-
- vForces.InitMatrix();
- vMoments.InitMatrix();
-
- for (i=0; i<numEngines; i++) {
- Engines[i]->Calculate();
- vForces += Engines[i]->GetBodyForces(); // sum body frame forces
- vMoments += Engines[i]->GetMoments(); // sum body frame moments
- }
-
- for (i=0; i<numTanks; i++) {
- Tanks[i]->Calculate( dt * rate );
- }
-
- if (refuel) DoRefuel( dt * rate );
-
- return false;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGPropulsion::GetSteadyState(void)
-{
- double currentThrust = 0, lastThrust=-1;
- int steady_count,j=0;
- bool steady=false;
-
- vForces.InitMatrix();
- vMoments.InitMatrix();
-
- if (!FGModel::Run()) {
- for (unsigned int i=0; i<numEngines; i++) {
- Engines[i]->SetTrimMode(true);
- steady=false;
- steady_count=0;
- while (!steady && j < 6000) {
- Engines[i]->Calculate();
- lastThrust = currentThrust;
- currentThrust = Engines[i]->GetThrust();
- if (fabs(lastThrust-currentThrust) < 0.0001) {
- steady_count++;
- if (steady_count > 120) { steady=true; }
- } else {
- steady_count=0;
- }
- j++;
- }
- vForces += Engines[i]->GetBodyForces(); // sum body frame forces
- vMoments += Engines[i]->GetMoments(); // sum body frame moments
- Engines[i]->SetTrimMode(false);
- }
-
- return false;
- } else {
- return true;
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGPropulsion::ICEngineStart(void)
-{
- int j;
-
- vForces.InitMatrix();
- vMoments.InitMatrix();
-
- for (unsigned int i=0; i<numEngines; i++) {
- Engines[i]->SetTrimMode(true);
- j=0;
- while (!Engines[i]->GetRunning() && j < 2000) {
- Engines[i]->Calculate();
- j++;
- }
- vForces += Engines[i]->GetBodyForces(); // sum body frame forces
- vMoments += Engines[i]->GetMoments(); // sum body frame moments
- Engines[i]->SetTrimMode(false);
- }
- return true;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGPropulsion::Load(FGConfigFile* AC_cfg)
-{
- string token, fullpath, localpath;
- string engineFileName, engType;
- string parameter;
- string enginePath = FDMExec->GetEnginePath();
- string aircraftPath = FDMExec->GetAircraftPath();
- double xLoc, yLoc, zLoc, Pitch, Yaw;
- int Feed;
- bool ThrottleAdded = false;
- FGConfigFile* Cfg_ptr = 0;
-
-# ifndef macintosh
- fullpath = enginePath + "/";
- localpath = aircraftPath + "/Engines/";
-# else
- fullpath = enginePath + ";";
- localpath = aircraftPath + ";Engines;";
-# endif
-
- AC_cfg->GetNextConfigLine();
-
- while ((token = AC_cfg->GetValue()) != string("/PROPULSION")) {
-
- if (token == "AC_ENGINE") { // ============ READING ENGINES
-
- engineFileName = AC_cfg->GetValue("FILE");
-
- // Look in the Aircraft/Engines directory first
- Cfg_ptr = 0;
- FGConfigFile Local_cfg(localpath + engineFileName + ".xml");
- FGConfigFile Eng_cfg(fullpath + engineFileName + ".xml");
- if (Local_cfg.IsOpen()) {
- Cfg_ptr = &Local_cfg;
- if (debug_lvl > 0) cout << "\n Reading engine from file: " << localpath
- + engineFileName + ".xml"<< endl;
- } else {
- if (Eng_cfg.IsOpen()) {
- Cfg_ptr = &Eng_cfg;
- if (debug_lvl > 0) cout << "\n Reading engine from file: " << fullpath
- + engineFileName + ".xml"<< endl;
- }
- }
-
- if (Cfg_ptr) {
- Cfg_ptr->GetNextConfigLine();
- engType = Cfg_ptr->GetValue();
-
- FCS->AddThrottle();
- ThrottleAdded = true;
-
- if (engType == "FG_ROCKET") {
- Engines.push_back(new FGRocket(FDMExec, Cfg_ptr, numEngines));
- } else if (engType == "FG_PISTON") {
- Engines.push_back(new FGPiston(FDMExec, Cfg_ptr, numEngines));
- } else if (engType == "FG_TURBINE") {
- Engines.push_back(new FGTurbine(FDMExec, Cfg_ptr, numEngines));
- } else if (engType == "FG_SIMTURBINE") {
- cerr << endl;
- cerr << "The FG_SIMTURBINE engine type has been renamed to FG_TURBINE." << endl;
- cerr << "To fix this problem, simply replace the FG_SIMTURBINE name " << endl;
- cerr << "in your engine file to FG_TURBINE." << endl;
- cerr << endl;
- Engines.push_back(new FGTurbine(FDMExec, Cfg_ptr, numEngines));
- } else if (engType == "FG_ELECTRIC") {
- Engines.push_back(new FGElectric(FDMExec, Cfg_ptr, numEngines));
- } else {
- cerr << fgred << " Unrecognized engine type: " << underon << engType
- << underoff << " found in config file." << fgdef << endl;
- return false;
- }
-
- Engines.back()->SetEngineFileName(engineFileName);
-
- AC_cfg->GetNextConfigLine();
- while ((token = AC_cfg->GetValue()) != string("/AC_ENGINE")) {
- *AC_cfg >> token;
- if (token == "XLOC") { *AC_cfg >> xLoc; }
- else if (token == "YLOC") { *AC_cfg >> yLoc; }
- else if (token == "ZLOC") { *AC_cfg >> zLoc; }
- else if (token == "PITCH") { *AC_cfg >> Pitch;}
- else if (token == "YAW") { *AC_cfg >> Yaw; }
- else if (token.find("AC_THRUSTER") != string::npos) {
- if (debug_lvl > 0) cout << "\n Reading thruster definition" << endl;
- Engines.back()->LoadThruster(AC_cfg);
- AC_cfg->GetNextConfigLine();
- }
- else if (token == "FEED") {
- *AC_cfg >> Feed;
- Engines[numEngines]->AddFeedTank(Feed);
- if (debug_lvl > 0) cout << " Feed tank: " << Feed << endl;
- } else cerr << "Unknown identifier: " << token << " in engine file: "
- << engineFileName << endl;
- }
-
- if (debug_lvl > 0) {
- cout << " X = " << xLoc << endl;
- cout << " Y = " << yLoc << endl;
- cout << " Z = " << zLoc << endl;
- cout << " Pitch = " << Pitch << endl;
- cout << " Yaw = " << Yaw << endl;
- }
-
- Engines[numEngines]->SetPlacement(xLoc, yLoc, zLoc, Pitch, Yaw);
- numEngines++;
-
- } else {
-
- cerr << fgred << "\n Could not read engine config file: " << underon <<
- engineFileName + ".xml" << underoff << fgdef << endl;
- return false;
- }
-
- } else if (token == "AC_TANK") { // ============== READING TANKS
-
- if (debug_lvl > 0) cout << "\n Reading tank definition" << endl;
- Tanks.push_back(new FGTank(AC_cfg, FDMExec));
- switch(Tanks[numTanks]->GetType()) {
- case FGTank::ttFUEL:
- numSelectedFuelTanks++;
- numFuelTanks++;
- break;
- case FGTank::ttOXIDIZER:
- numSelectedOxiTanks++;
- numOxiTanks++;
- break;
- }
-
- numTanks++;
- }
- AC_cfg->GetNextConfigLine();
- }
-
- CalculateTankInertias();
- if (!ThrottleAdded) FCS->AddThrottle(); // need to have at least one throttle
-
- return true;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGPropulsion::GetPropulsionStrings(string delimeter)
-{
- unsigned int i;
-
- string PropulsionStrings = "";
- bool firstime = true;
- stringstream buf;
-
- for (i=0; i<Engines.size(); i++) {
- if (firstime) firstime = false;
- else PropulsionStrings += delimeter;
-
- PropulsionStrings += Engines[i]->GetEngineLabels(delimeter);
- }
- 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;
- }
-
- return PropulsionStrings;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGPropulsion::GetPropulsionValues(string delimeter)
-{
- unsigned int i;
-
- string PropulsionValues = "";
- bool firstime = true;
- stringstream buf;
-
- for (i=0; i<Engines.size(); i++) {
- if (firstime) firstime = false;
- else PropulsionValues += delimeter;
-
- PropulsionValues += Engines[i]->GetEngineValues(delimeter);
- }
- for (i=0; i<Tanks.size(); i++) {
- buf << delimeter;
- buf << Tanks[i]->GetContents();
- }
-
- return PropulsionValues;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-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++;
- }
- return vXYZtank_arm;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGPropulsion::GetTanksWeight(void)
-{
- double Tw = 0.0;
-
- iTank = Tanks.begin();
- while (iTank < Tanks.end()) {
- Tw += (*iTank)->GetContents();
- iTank++;
- }
- return Tw;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGMatrix33& FGPropulsion::CalculateTankInertias(void)
-{
- unsigned int size;
-
- size = Tanks.size();
- if (size == 0) return tankJ;
-
- tankJ = FGMatrix33();
-
- for (unsigned int i=0; i<size; i++)
- tankJ += MassBalance->GetPointmassInertia( lbtoslug * Tanks[i]->GetContents(),
- Tanks[i]->GetXYZ() );
-
- return tankJ;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropulsion::SetMagnetos(int setting)
-{
- if (ActiveEngine < 0) {
- for (unsigned i=0; i<Engines.size(); i++) {
- ((FGPiston*)Engines[i])->SetMagnetos(setting);
- }
- } else {
- ((FGPiston*)Engines[ActiveEngine])->SetMagnetos(setting);
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropulsion::SetStarter(int setting)
-{
- if (ActiveEngine < 0) {
- for (unsigned i=0; i<Engines.size(); i++) {
- if (setting == 0)
- Engines[i]->SetStarter(false);
- else
- Engines[i]->SetStarter(true);
- }
- } else {
- if (setting == 0)
- Engines[ActiveEngine]->SetStarter(false);
- else
- Engines[ActiveEngine]->SetStarter(true);
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropulsion::SetCutoff(int setting)
-{
- if (ActiveEngine < 0) {
- for (unsigned i=0; i<Engines.size(); i++) {
- if (setting == 0)
- ((FGTurbine*)Engines[i])->SetCutoff(false);
- else
- ((FGTurbine*)Engines[i])->SetCutoff(true);
- }
- } else {
- if (setting == 0)
- ((FGTurbine*)Engines[ActiveEngine])->SetCutoff(false);
- else
- ((FGTurbine*)Engines[ActiveEngine])->SetCutoff(true);
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropulsion::SetActiveEngine(int engine)
-{
- if (engine >= Engines.size() || engine < 0)
- ActiveEngine = -1;
- else
- ActiveEngine = engine;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGPropulsion::Transfer(int source, int target, double amount)
-{
- double shortage, overage;
-
- if (source == -1) {
- shortage = 0.0;
- } else {
- shortage = Tanks[source]->Drain(amount);
- }
- if (target == -1) {
- overage = 0.0;
- } else {
- overage = Tanks[target]->Fill(amount - shortage);
- }
- return overage;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropulsion::DoRefuel(double time_slice)
-{
- double fillrate = 100 * time_slice; // 100 lbs/sec = 6000 lbs/min
- int TanksNotFull = 0;
-
- for (unsigned int i=0; i<numTanks; i++) {
- if (Tanks[i]->GetPctFull() < 99.99) ++TanksNotFull;
- }
-
- if (TanksNotFull) {
- for (unsigned int i=0; i<numTanks; i++) {
- if (Tanks[i]->GetPctFull() < 99.99)
- Transfer(-1, i, fillrate/TanksNotFull);
- }
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropulsion::SetFuelFreeze(bool f)
-{
- fuel_freeze = f;
- for (unsigned int i=0; i<numEngines; i++) {
- Engines[i]->SetFuelFreeze(f);
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropulsion::bind(void)
-{
- typedef double (FGPropulsion::*PMF)(int) const;
- typedef int (FGPropulsion::*iPMF)(void) const;
-
- PropertyManager->Tie("propulsion/magneto_cmd", this,
- (iPMF)0, &FGPropulsion::SetMagnetos, true);
- PropertyManager->Tie("propulsion/starter_cmd", this,
- (iPMF)0, &FGPropulsion::SetStarter, true);
- PropertyManager->Tie("propulsion/cutoff_cmd", this,
- (iPMF)0, &FGPropulsion::SetCutoff, 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);
-
- PropertyManager->Tie("propulsion/active_engine", this,
- (iPMF)&FGPropulsion::GetActiveEngine, &FGPropulsion::SetActiveEngine, true);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropulsion::unbind(void)
-{
- PropertyManager->Untie("propulsion/magneto_cmd");
- PropertyManager->Untie("propulsion/starter_cmd");
- PropertyManager->Untie("propulsion/cutoff_cmd");
- PropertyManager->Untie("propulsion/active_engine");
- PropertyManager->Untie("forces/fbx-prop-lbs");
- PropertyManager->Untie("forces/fby-prop-lbs");
- PropertyManager->Untie("forces/fbz-prop-lbs");
- PropertyManager->Untie("moments/l-prop-lbsft");
- PropertyManager->Untie("moments/m-prop-lbsft");
- PropertyManager->Untie("moments/n-prop-lbsft");
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGPropulsion::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
-
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGPropulsion" << endl;
- if (from == 1) cout << "Destroyed: FGPropulsion" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGPropulsion.h
- Author: Jon S. Berndt
- Date started: 08/20/00
-
- ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-08/20/00 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGPROPULSION_H
-#define FGPROPULSION_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef FGFS
-# include <simgear/compiler.h>
-# ifdef SG_HAVE_STD_INCLUDES
-# include <vector>
-# include <iterator>
-# else
-# include <vector.h>
-# include <iterator.h>
-# endif
-#else
-# include <vector>
-# include <iterator>
-#endif
-
-#include "FGModel.h"
-#include "FGEngine.h"
-#include "FGTank.h"
-#include "FGMatrix33.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_PROPULSION "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Propulsion management class.
- The Propulsion class is the container for the entire propulsion system, which is
- comprised of engines, and tanks. Once the Propulsion class gets the config file,
- it reads in information which is specific to a type of engine. Then:
-
- -# The appropriate engine type instance is created
- -# At least one tank object is created, and is linked to an engine.
-
- At Run time each engines Calculate() method is called.
- @author Jon S. Berndt
- @version $Id$
- @see
- FGEngine
- FGTank
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGPropulsion : public FGModel
-{
-public:
- /// Constructor
- FGPropulsion(FGFDMExec*);
- /// Destructor
- ~FGPropulsion();
-
- /** Executes the propulsion model.
- The initial plan for the FGPropulsion class calls for Run() to be executed,
- calculating the power available from the engine.
-
- [Note: Should we be checking the Starved flag here?] */
- bool Run(void);
-
- /** Loads the propulsion system (engine[s] and tank[s]).
- Characteristics of the propulsion system are read in from the config file.
- @param AC_cfg pointer to the config file instance that describes the
- aircraft being modeled.
- @return true if successfully loaded, otherwise false */
- bool Load(FGConfigFile* AC_cfg);
-
- /// Retrieves the number of engines defined for the aircraft.
- inline unsigned int GetNumEngines(void) const {return Engines.size();}
-
- /** Retrieves an engine object pointer from the list of engines.
- @param index the engine index within the vector container
- @return the address of the specific engine, or zero if no such engine is
- available */
- inline FGEngine* GetEngine(unsigned int index) {
- if (index <= Engines.size()-1) return Engines[index];
- else return 0L; }
-
- /// Retrieves the number of tanks defined for the aircraft.
- inline unsigned int GetNumTanks(void) const {return Tanks.size();}
-
- /** Retrieves a tank object pointer from the list of tanks.
- @param index the tank index within the vector container
- @return the address of the specific tank, or zero if no such tank is
- available */
- inline FGTank* GetTank(unsigned int index) {
- if (index <= Tanks.size()-1) return Tanks[index];
- else return 0L; }
-
- /** Returns the number of fuel tanks currently actively supplying fuel */
- inline int GetnumSelectedFuelTanks(void) const {return numSelectedFuelTanks;}
-
- /** Returns the number of oxidizer tanks currently actively supplying oxidizer */
- inline int GetnumSelectedOxiTanks(void) const {return numSelectedOxiTanks;}
-
- /** Loops the engines until thrust output steady (used for trimming) */
- bool GetSteadyState(void);
-
- /** starts the engines in IC mode (dt=0). All engine-specific setup must
- be done before calling this (i.e. magnetos, starter engage, etc.) */
- bool ICEngineStart(void);
-
- string GetPropulsionStrings(string delimeter);
- string GetPropulsionValues(string delimeter);
-
- inline FGColumnVector3& GetForces(void) {return vForces; }
- inline double GetForces(int n) const { return vForces(n);}
- inline FGColumnVector3& GetMoments(void) {return vMoments;}
- inline double GetMoments(int n) const {return vMoments(n);}
-
- inline bool GetRefuel(void) {return refuel;}
- inline void SetRefuel(bool setting) {refuel = setting;}
- double Transfer(int source, int target, double amount);
- void DoRefuel(double time_slice);
-
- FGColumnVector3& GetTanksMoment(void);
- double GetTanksWeight(void);
-
- inline int GetActiveEngine(void) const
- {
- return ActiveEngine;
- }
-
- inline int GetActiveEngine(void);
- inline bool GetFuelFreeze(void) {return fuel_freeze;}
-
- void SetMagnetos(int setting);
- void SetStarter(int setting);
- void SetCutoff(int setting=0);
- void SetActiveEngine(int engine);
- void SetFuelFreeze(bool f);
- FGMatrix33& CalculateTankInertias(void);
-
- void bind();
- void unbind();
-
-private:
- vector <FGEngine*> Engines;
- vector <FGTank*> Tanks;
- vector <FGTank*>::iterator iTank;
- unsigned int numSelectedFuelTanks;
- unsigned int numSelectedOxiTanks;
- unsigned int numFuelTanks;
- unsigned int numOxiTanks;
- unsigned int numEngines;
- unsigned int numTanks;
- int ActiveEngine;
- FGColumnVector3 vForces;
- FGColumnVector3 vMoments;
- FGColumnVector3 vTankXYZ;
- FGColumnVector3 vXYZtank_arm;
- FGMatrix33 tankJ;
- bool refuel;
- bool fuel_freeze;
-
- void Debug(int from);
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
-
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGQuaternion.cpp
- Author: Jon Berndt, Mathias Froehlich
- Date started: 12/02/98
-
- ------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------------
- ------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
--------------------------------------------------------------------------------
-12/02/98 JSB Created
-15/01/04 Mathias Froehlich implemented a quaternion class from many places
- in JSBSim.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- INCLUDES
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#ifdef FGFS
-# include <math.h>
-# include <simgear/compiler.h>
-# include STL_IOSTREAM
- SG_USING_STD(cerr);
- SG_USING_STD(cout);
- SG_USING_STD(endl);
-#else
-# include <string>
-# if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
-# include <iostream.h>
-# include <math.h>
-# else
-# include <iostream>
-# if defined(sgi) && !defined(__GNUC__)
-# include <math.h>
-# else
-# include <cmath>
-# endif
- using std::cerr;
- using std::cout;
- using std::endl;
-# endif
-#endif
-
-#include "FGMatrix33.h"
-#include "FGColumnVector3.h"
-
-#include "FGQuaternion.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- DEFINITIONS
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_QUATERNION;
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-// Initialize from q
-FGQuaternion::FGQuaternion(const FGQuaternion& q)
- : mCacheValid(q.mCacheValid) {
- Entry(1) = q(1);
- Entry(2) = q(2);
- Entry(3) = q(3);
- Entry(4) = q(4);
- if (mCacheValid) {
- mT = q.mT;
- mTInv = q.mTInv;
- mEulerAngles = q.mEulerAngles;
- mEulerSines = q.mEulerSines;
- mEulerCosines = q.mEulerCosines;
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-// Initialize with the three euler angles
-FGQuaternion::FGQuaternion(double phi, double tht, double psi)
- : mCacheValid(false) {
- double thtd2 = 0.5*tht;
- double psid2 = 0.5*psi;
- double phid2 = 0.5*phi;
-
- double Sthtd2 = sin(thtd2);
- double Spsid2 = sin(psid2);
- double Sphid2 = sin(phid2);
-
- double Cthtd2 = cos(thtd2);
- double Cpsid2 = cos(psid2);
- double Cphid2 = cos(phid2);
-
- double Cphid2Cthtd2 = Cphid2*Cthtd2;
- double Cphid2Sthtd2 = Cphid2*Sthtd2;
- double Sphid2Sthtd2 = Sphid2*Sthtd2;
- double Sphid2Cthtd2 = Sphid2*Cthtd2;
-
- Entry(1) = Cphid2Cthtd2*Cpsid2 + Sphid2Sthtd2*Spsid2;
- Entry(2) = Sphid2Cthtd2*Cpsid2 - Cphid2Sthtd2*Spsid2;
- Entry(3) = Cphid2Sthtd2*Cpsid2 + Sphid2Cthtd2*Spsid2;
- Entry(4) = Cphid2Cthtd2*Spsid2 - Sphid2Sthtd2*Cpsid2;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-/**
- Returns the derivative of the quaternion coresponding to the
- angular velocities PQR.
-*/
-FGQuaternion FGQuaternion::GetQDot(const FGColumnVector3& PQR) const {
- double norm = Magnitude();
- if (norm == 0.0)
- return FGQuaternion::zero();
- double rnorm = 1.0/norm;
-
- FGQuaternion QDot;
- QDot(1) = -0.5*(Entry(2)*PQR(eP) + Entry(3)*PQR(eQ) + Entry(4)*PQR(eR));
- QDot(2) = 0.5*(Entry(1)*PQR(eP) + Entry(3)*PQR(eR) - Entry(4)*PQR(eQ));
- QDot(3) = 0.5*(Entry(1)*PQR(eQ) + Entry(4)*PQR(eP) - Entry(2)*PQR(eR));
- QDot(4) = 0.5*(Entry(1)*PQR(eR) + Entry(2)*PQR(eQ) - Entry(3)*PQR(eP));
- return rnorm*QDot;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGQuaternion::Normalize()
-{
- // Note: this does not touch the cache
- // since it does not change the orientation ...
-
- double norm = Magnitude();
- if (norm == 0.0)
- return;
-
- double rnorm = 1.0/norm;
- Entry(1) *= rnorm;
- Entry(2) *= rnorm;
- Entry(3) *= rnorm;
- Entry(4) *= rnorm;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-// Compute the derived values if required ...
-void FGQuaternion::ComputeDerivedUnconditional(void) const
-{
- mCacheValid = true;
-
- // First normalize the 4-vector
- double norm = Magnitude();
- if (norm == 0.0)
- return;
-
- double rnorm = 1.0/norm;
- double q1 = rnorm*Entry(1);
- double q2 = rnorm*Entry(2);
- double q3 = rnorm*Entry(3);
- double q4 = rnorm*Entry(4);
-
- // Now compute the transformation matrix.
- double q1q1 = q1*q1;
- double q2q2 = q2*q2;
- double q3q3 = q3*q3;
- double q4q4 = q4*q4;
- double q1q2 = q1*q2;
- double q1q3 = q1*q3;
- double q1q4 = q1*q4;
- double q2q3 = q2*q3;
- double q2q4 = q2*q4;
- double q3q4 = q3*q4;
-
- mT(1,1) = q1q1 + q2q2 - q3q3 - q4q4;
- mT(1,2) = 2.0*(q2q3 + q1q4);
- mT(1,3) = 2.0*(q2q4 - q1q3);
- mT(2,1) = 2.0*(q2q3 - q1q4);
- mT(2,2) = q1q1 - q2q2 + q3q3 - q4q4;
- mT(2,3) = 2.0*(q3q4 + q1q2);
- mT(3,1) = 2.0*(q2q4 + q1q3);
- mT(3,2) = 2.0*(q3q4 - q1q2);
- mT(3,3) = q1q1 - q2q2 - q3q3 + q4q4;
- // Since this is an orthogonal matrix, the inverse is simply
- // the transpose.
- mTInv = mT;
- mTInv.T();
-
- // Compute the Euler-angles
- if (mT(3,3) == 0.0)
- mEulerAngles(ePhi) = 0.5*M_PI;
- else
- mEulerAngles(ePhi) = atan2(mT(2,3), mT(3,3));
-
- if (mT(1,3) < -1.0)
- mEulerAngles(eTht) = 0.5*M_PI;
- else if (1.0 < mT(1,3))
- mEulerAngles(eTht) = -0.5*M_PI;
- else
- mEulerAngles(eTht) = asin(-mT(1,3));
-
- if (mT(1,1) == 0.0)
- mEulerAngles(ePsi) = 0.5*M_PI;
- else {
- double psi = atan2(mT(1,2), mT(1,1));
- if (psi < 0.0)
- psi += 2*M_PI;
- mEulerAngles(ePsi) = psi;
- }
-
- // FIXME: may be one can compute those values easier ???
- mEulerSines(ePhi) = sin(mEulerAngles(ePhi));
- // mEulerSines(eTht) = sin(mEulerAngles(eTht));
- mEulerSines(eTht) = -mT(1,3);
- mEulerSines(ePsi) = sin(mEulerAngles(ePsi));
- mEulerCosines(ePhi) = cos(mEulerAngles(ePhi));
- mEulerCosines(eTht) = cos(mEulerAngles(eTht));
- mEulerCosines(ePsi) = cos(mEulerAngles(ePsi));
-}
-
-} // namespace JSBSim
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGQuaternion.h
- Author: Jon Berndt, Mathis Froehlich
- Date started: 12/02/98
-
- ------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------------
- ------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
--------------------------------------------------------------------------------
-12/02/98 JSB Created
-15/01/04 MF Quaternion class from old FGColumnVector4
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGQUATERNION_H
-#define FGQUATERNION_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- INCLUDES
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGJSBBase.h"
-#include "FGMatrix33.h"
-#include "FGColumnVector3.h"
-#include "FGPropertyManager.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- DEFINITIONS
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_QUATERNION "$Id$"
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- CLASS DOCUMENTATION
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Models the Quaternion representation of rotations.
- FGQuaternion is a representation of an arbitrary rotation through a
- quaternion. It has vector properties. This class also contains access
- functions to the euler angle representation of rotations and access to
- transformation matrices for 3D vectors. Transformations and euler angles are
- therefore computed once they are requested for the first time. Then they are
- cached for later usage as long as the class is not accessed trough
- a nonconst member function.
-
- Note: The order of rotations used in this class corresponds to a 3-2-1 sequence,
- or Y-P-R, or Z-Y-X, if you prefer.
-
- @see Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
- Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
- School, January 1994
- @see D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
- JSC 12960, July 1977
- @see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
- NASA-Ames", NASA CR-2497, January 1975
- @see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
- Wiley & Sons, 1979 ISBN 0-471-03032-5
- @see Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
- 1982 ISBN 0-471-08936-2
- @author Mathias Froehlich, extended FGColumnVector4 originally by Tony Peden
- and Jon Berndt
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- CLASS DECLARATION
- %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGQuaternion
- : virtual FGJSBBase {
-public:
- /** Default initializer.
- Default initializer, initializes the class with the identity rotation. */
- FGQuaternion() : mCacheValid(false) {
- Entry(1) = 1.0;
- Entry(2) = Entry(3) = Entry(4) = 0.0;
- }
-
- /** Copy constructor.
- Copy constructor, initializes the quaternion.
- @param q a constant reference to another FGQuaternion instance */
- FGQuaternion(const FGQuaternion& q);
-
- /** Initializer by euler angles.
- Initialize the quaternion with the euler angles.
- @param phi The euler X axis (roll) angle in radians
- @param tht The euler Y axis (attitude) angle in radians
- @param psi The euler Z axis (heading) angle in radians */
- FGQuaternion(double phi, double tht, double psi);
-
- /** Initializer by one euler angle.
- Initialize the quaternion with the single euler angle where its index
- is given in the first argument.
- @param idx Index of the euler angle to initialize
- @param angle The euler angle in radians */
- FGQuaternion(int idx, double angle)
- : mCacheValid(false) {
- double angle2 = 0.5*angle;
-
- double Sangle2 = sin(angle2);
- double Cangle2 = cos(angle2);
-
- if (idx == ePhi) {
- Entry(1) = Cangle2;
- Entry(2) = Sangle2;
- Entry(3) = 0.0;
- Entry(4) = 0.0;
-
- } else if (idx == eTht) {
- Entry(1) = Cangle2;
- Entry(2) = 0.0;
- Entry(3) = Sangle2;
- Entry(4) = 0.0;
-
- } else {
- Entry(1) = Cangle2;
- Entry(2) = 0.0;
- Entry(3) = 0.0;
- Entry(4) = Sangle2;
-
- }
- }
-
- /// Destructor.
- ~FGQuaternion() {}
-
- /** Quaternion 'velocity' for given angular rates.
- Computes the quaternion derivative which results from the given
- angular velocities
- @param PQR a constant reference to the body rate vector
- @return the quaternion derivative */
- FGQuaternion GetQDot(const FGColumnVector3& PQR) const;
-
- /** Transformation matrix.
- @return a reference to the transformation/rotation matrix
- corresponding to this quaternion rotation. */
- const FGMatrix33& GetT(void) const { ComputeDerived(); return mT; }
-
- /** Backward transformation matrix.
- @return a reference to the inverse transformation/rotation matrix
- corresponding to this quaternion rotation. */
- const FGMatrix33& GetTInv(void) const { ComputeDerived(); return mTInv; }
-
- /** Retrieves the Euler angles.
- @return a reference to the triad of euler angles corresponding
- to this quaternion rotation.
- @units radians */
- const FGColumnVector3& GetEuler(void) const {
- ComputeDerived();
- return mEulerAngles;
- }
-
- /** Retrieves the Euler angles.
- @param i the euler angle index.
- @return a reference to the i-th euler angles corresponding
- to this quaternion rotation.
- @units radians */
- double GetEuler(int i) const {
- ComputeDerived();
- return mEulerAngles(i);
- }
-
- /** Retrieves the Euler angles.
- @param i the euler angle index.
- @return a reference to the i-th euler angles corresponding
- to this quaternion rotation.
- @units degrees */
- double GetEulerDeg(int i) const {
- ComputeDerived();
- return radtodeg*mEulerAngles(i);
- }
-
- /** Retrieves sine of the given euler angle.
- @return the sine of the Euler angle theta (pitch attitude) corresponding
- to this quaternion rotation. */
- double GetSinEuler(int i) const {
- ComputeDerived();
- return mEulerSines(i);
- }
-
- /** Retrieves cosine of the given euler angle.
- @return the sine of the Euler angle theta (pitch attitude) corresponding
- to this quaternion rotation. */
- double GetCosEuler(int i) const {
- ComputeDerived();
- return mEulerCosines(i);
- }
-
- /** Read access the entries of the vector.
-
- @param idx the component index.
-
- Return the value of the matrix entry at the given index.
- Indices are counted starting with 1.
-
- Note that the index given in the argument is unchecked.
- */
- double operator()(unsigned int idx) const { return Entry(idx); }
-
- /** Write access the entries of the vector.
-
- @param idx the component index.
-
- Return a reference to the vector entry at the given index.
- Indices are counted starting with 1.
-
- Note that the index given in the argument is unchecked.
- */
- double& operator()(unsigned int idx) { return Entry(idx); }
-
- /** Read access the entries of the vector.
-
- @param idx the component index.
-
- Return the value of the matrix entry at the given index.
- Indices are counted starting with 1.
-
- This function is just a shortcut for the @ref double
- operator()(unsigned int idx) const function. It is
- used internally to access the elements in a more convenient way.
-
- Note that the index given in the argument is unchecked.
- */
- double Entry(unsigned int idx) const { return mData[idx-1]; }
-
- /** Write access the entries of the vector.
-
- @param idx the component index.
-
- Return a reference to the vector entry at the given index.
- Indices are counted starting with 1.
-
- This function is just a shortcut for the @ref double&
- operator()(unsigned int idx) function. It is
- used internally to access the elements in a more convenient way.
-
- Note that the index given in the argument is unchecked.
- */
- double& Entry(unsigned int idx) { mCacheValid = false; return mData[idx-1]; }
-
- /** Assignment operator "=".
- Assign the value of q to the current object. Cached values are
- conserved.
- @param q reference to an FGQuaternion instance
- @return reference to a quaternion object */
- const FGQuaternion& operator=(const FGQuaternion& q) {
- // Copy the master values ...
- Entry(1) = q(1);
- Entry(2) = q(2);
- Entry(3) = q(3);
- Entry(4) = q(4);
- // .. and copy the derived values if they are valid
- mCacheValid = q.mCacheValid;
- if (mCacheValid) {
- mT = q.mT;
- mTInv = q.mTInv;
- mEulerAngles = q.mEulerAngles;
- mEulerSines = q.mEulerSines;
- mEulerCosines = q.mEulerCosines;
- }
- return *this;
- }
-
- /** Comparison operator "==".
- @param q a quaternion reference
- @return true if both quaternions represent the same rotation. */
- bool operator==(const FGQuaternion& q) const {
- return Entry(1) == q(1) && Entry(2) == q(2)
- && Entry(3) == q(3) && Entry(4) == q(4);
- }
-
- /** Comparison operator "!=".
- @param q a quaternion reference
- @return true if both quaternions do not represent the same rotation. */
- bool operator!=(const FGQuaternion& q) const { return ! operator==(q); }
- const FGQuaternion& operator+=(const FGQuaternion& q) {
- // Copy the master values ...
- Entry(1) += q(1);
- Entry(2) += q(2);
- Entry(3) += q(3);
- Entry(4) += q(4);
- mCacheValid = false;
- return *this;
- }
-
- /** Arithmetic operator "-=".
- @param q a quaternion reference.
- @return a quaternion reference representing Q, where Q = Q - q. */
- const FGQuaternion& operator-=(const FGQuaternion& q) {
- // Copy the master values ...
- Entry(1) -= q(1);
- Entry(2) -= q(2);
- Entry(3) -= q(3);
- Entry(4) -= q(4);
- mCacheValid = false;
- return *this;
- }
-
- /** Arithmetic operator "*=".
- @param scalar a multiplicative value.
- @return a quaternion reference representing Q, where Q = Q * scalar. */
- const FGQuaternion& operator*=(double scalar) {
- Entry(1) *= scalar;
- Entry(2) *= scalar;
- Entry(3) *= scalar;
- Entry(4) *= scalar;
- mCacheValid = false;
- return *this;
- }
-
- /** Arithmetic operator "/=".
- @param scalar a divisor value.
- @return a quaternion reference representing Q, where Q = Q / scalar. */
- const FGQuaternion& operator/=(double scalar) {
- return operator*=(1.0/scalar);
- }
-
- /** Arithmetic operator "+".
- @param q a quaternion to be summed.
- @return a quaternion representing Q, where Q = Q + q. */
- FGQuaternion operator+(const FGQuaternion& q) const {
- return FGQuaternion(Entry(1)+q(1), Entry(2)+q(2),
- Entry(3)+q(3), Entry(4)+q(4));
- }
-
- /** Arithmetic operator "-".
- @param q a quaternion to be subtracted.
- @return a quaternion representing Q, where Q = Q - q. */
- FGQuaternion operator-(const FGQuaternion& q) const {
- return FGQuaternion(Entry(1)-q(1), Entry(2)-q(2),
- Entry(3)-q(3), Entry(4)-q(4));
- }
-
- /** Arithmetic operator "*".
- Multiplication of two quaternions is like performing successive rotations.
- @param q a quaternion to be multiplied.
- @return a quaternion representing Q, where Q = Q * q. */
- FGQuaternion operator*(const FGQuaternion& q) const {
- return FGQuaternion(Entry(1)*q(1)-Entry(2)*q(2)-Entry(3)*q(3)-Entry(4)*q(4),
- Entry(1)*q(2)+Entry(2)*q(1)+Entry(3)*q(4)-Entry(4)*q(3),
- Entry(1)*q(3)-Entry(2)*q(4)+Entry(3)*q(1)+Entry(4)*q(2),
- Entry(1)*q(4)+Entry(2)*q(3)-Entry(3)*q(2)+Entry(4)*q(1));
- }
-
- /** Arithmetic operator "*=".
- Multiplication of two quaternions is like performing successive rotations.
- @param q a quaternion to be multiplied.
- @return a quaternion reference representing Q, where Q = Q * q. */
- const FGQuaternion& operator*=(const FGQuaternion& q) {
- double q0 = Entry(1)*q(1)-Entry(2)*q(2)-Entry(3)*q(3)-Entry(4)*q(4);
- double q1 = Entry(1)*q(2)+Entry(2)*q(1)+Entry(3)*q(4)-Entry(4)*q(3);
- double q2 = Entry(1)*q(3)-Entry(2)*q(4)+Entry(3)*q(1)+Entry(4)*q(2);
- double q3 = Entry(1)*q(4)+Entry(2)*q(3)-Entry(3)*q(2)+Entry(4)*q(1);
- Entry(1) = q0;
- Entry(2) = q1;
- Entry(3) = q2;
- Entry(4) = q3;
- mCacheValid = false;
- return *this;
- }
-
- /** Inverse of the quaternion.
-
- Compute and return the inverse of the quaternion so that the orientation
- represented with *this multiplied with the returned value is equal to
- the identity orientation.
- */
- FGQuaternion Inverse(void) const {
- double norm = Magnitude();
- if (norm == 0.0)
- return *this;
- double rNorm = 1.0/norm;
- return FGQuaternion( Entry(1)*rNorm, -Entry(2)*rNorm,
- -Entry(3)*rNorm, -Entry(4)*rNorm );
- }
-
- /** Conjugate of the quaternion.
-
- Compute and return the conjugate of the quaternion. This one is equal
- to the inverse iff the quaternion is normalized.
- */
- FGQuaternion Conjugate(void) const {
- return FGQuaternion( Entry(1), -Entry(2), -Entry(3), -Entry(4) );
- }
-
- friend FGQuaternion operator*(double, const FGQuaternion&);
-
- /** Length of the vector.
-
- Compute and return the euclidean norm of this vector.
- */
- double Magnitude(void) const { return sqrt(SqrMagnitude()); }
-
- /** Square of the length of the vector.
-
- Compute and return the square of the euclidean norm of this vector.
- */
- double SqrMagnitude(void) const {
- return Entry(1)*Entry(1)+Entry(2)*Entry(2)
- +Entry(3)*Entry(3)+Entry(4)*Entry(4);
- }
-
- /** Normialze.
-
- Normalize the vector to have the Magnitude() == 1.0. If the vector
- is equal to zero it is left untouched.
- */
- void Normalize(void);
-
- /** Zero quaternion vector. Does not represent any orientation.
- Useful for initialization of increments */
- static FGQuaternion zero(void) { return FGQuaternion( 0.0, 0.0, 0.0, 0.0 ); }
-
-private:
- /** Copying by assigning the vector valued components. */
- FGQuaternion(double q1, double q2, double q3, double q4) : mCacheValid(false)
- { Entry(1) = q1; Entry(2) = q2; Entry(3) = q3; Entry(4) = q4; }
-
- /** Computation of derived values.
- This function recomputes the derived values like euler angles and
- transformation matrices. It does this unconditionally. */
- void ComputeDerivedUnconditional(void) const;
-
- /** Computation of derived values.
- This function checks if the derived values like euler angles and
- transformation matrices are already computed. If so, it
- returns. If they need to be computed the real worker routine
- \ref FGQuaternion::ComputeDerivedUnconditional(void) const
- is called.
- This function is inlined to avoid function calls in the fast path. */
- void ComputeDerived(void) const {
- if (!mCacheValid)
- ComputeDerivedUnconditional();
- }
-
- /** The quaternion values itself. This is the master copy. */
- double mData[4];
-
- /** A data validity flag.
- This class implements caching of the derived values like the
- orthogonal rotation matrices or the Euler angles. For caching we
- carry a flag which signals if the values are valid or not.
- The C++ keyword "mutable" tells the compiler that the data member is
- allowed to change during a const member function. */
- mutable bool mCacheValid;
-
- /** This stores the transformation matrices. */
- mutable FGMatrix33 mT;
- mutable FGMatrix33 mTInv;
-
- /** The cached euler angles. */
- mutable FGColumnVector3 mEulerAngles;
-
- /** The cached sines and cosines of the euler angles. */
- mutable FGColumnVector3 mEulerSines;
- mutable FGColumnVector3 mEulerCosines;
-};
-
-/** Scalar multiplication.
-
- @param scalar scalar value to multiply with.
- @param p Vector to multiply.
-
- Multiply the Vector with a scalar value.
-*/
-inline FGQuaternion operator*(double scalar, const FGQuaternion& q) {
- return FGQuaternion(scalar*q(1), scalar*q(2), scalar*q(3), scalar*q(4));
-}
-
-} // namespace JSBSim
-
-#endif
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGRocket.cpp
- Author: Jon S. Berndt
- Date started: 09/12/2000
- Purpose: This module models a rocket engine
-
- ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) --------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-This class descends from the FGEngine class and models a rocket engine based on
-parameters given in the engine config file for this class
-
-HISTORY
---------------------------------------------------------------------------------
-09/12/2000 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <sstream>
-
-#include "FGRocket.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_ROCKET;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-FGRocket::FGRocket(FGFDMExec* exec, FGConfigFile* Eng_cfg, int engine_number)
- : FGEngine(exec, engine_number)
-{
- string token;
-
- Name = Eng_cfg->GetValue("NAME");
- Eng_cfg->GetNextConfigLine();
-
- while (Eng_cfg->GetValue() != string("/FG_ROCKET")) {
- *Eng_cfg >> token;
- if (token == "SHR") *Eng_cfg >> SHR;
- else if (token == "MAX_PC") *Eng_cfg >> maxPC;
- else if (token == "PROP_EFF") *Eng_cfg >> propEff;
- else if (token == "MAXTHROTTLE") *Eng_cfg >> MaxThrottle;
- else if (token == "MINTHROTTLE") *Eng_cfg >> MinThrottle;
- else if (token == "SLFUELFLOWMAX") *Eng_cfg >> SLFuelFlowMax;
- else if (token == "SLOXIFLOWMAX") *Eng_cfg >> SLOxiFlowMax;
- else if (token == "VARIANCE") *Eng_cfg >> Variance;
- else cerr << "Unhandled token in Engine config file: " << token << endl;
- }
-
- Debug(0);
-
- Type = etRocket;
- Flameout = false;
-
- PC = 0.0;
- kFactor = (2.0*SHR*SHR/(SHR-1.0))*pow(2.0/(SHR+1), (SHR+1)/(SHR-1));
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGRocket::~FGRocket(void)
-{
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGRocket::Calculate(void)
-{
- double Cf=0;
-
- if (!Flameout && !Starved) ConsumeFuel();
-
- Throttle = FCS->GetThrottlePos(EngineNumber);
-
- if (Throttle < MinThrottle || Starved) {
- PctPower = Thrust = 0.0; // desired thrust
- Flameout = true;
- PC = 0.0;
- } else {
- PctPower = Throttle / MaxThrottle;
- PC = maxPC*PctPower * (1.0 + Variance * ((double)rand()/(double)RAND_MAX - 0.5));
- // The Cf (below) is CF from Eqn. 3-30, "Rocket Propulsion Elements", Fifth Edition,
- // George P. Sutton. Note that the thruster function GetPowerRequired() might
- // be better called GetResistance() or something; this function returns the
- // nozzle exit pressure.
- Cf = sqrt(kFactor*(1 - pow(Thruster->GetPowerRequired()/(PC), (SHR-1)/SHR)));
- Flameout = false;
- }
-
- return Thrust = Thruster->Calculate(Cf*maxPC*PctPower*propEff);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGRocket::GetEngineLabels(string delimeter)
-{
- std::ostringstream buf;
-
- buf << Name << "_ChamberPress[" << EngineNumber << "]" << delimeter
- << Thruster->GetThrusterLabels(EngineNumber, delimeter);
-
- return buf.str();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGRocket::GetEngineValues(string delimeter)
-{
- std::ostringstream buf;
-
- buf << PC << delimeter << Thruster->GetThrusterValues(EngineNumber, delimeter);
-
- return buf.str();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGRocket::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
- cout << " Engine Name: " << Name << endl;
- cout << " Specific Heat Ratio = " << SHR << endl;
- cout << " Maximum Chamber Pressure = " << maxPC << endl;
- cout << " Propulsive Efficiency = " << propEff << endl;
- cout << " MaxThrottle = " << MaxThrottle << endl;
- cout << " MinThrottle = " << MinThrottle << endl;
- cout << " FuelFlowMax = " << SLFuelFlowMax << endl;
- cout << " OxiFlowMax = " << SLOxiFlowMax << endl;
- cout << " Variance = " << Variance << endl;
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGRocket" << endl;
- if (from == 1) cout << "Destroyed: FGRocket" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGRocket.h
- Author: Jon S. Berndt
- Date started: 09/12/2000
-
- ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) --------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-09/12/2000 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGROCKET_H
-#define FGROCKET_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGEngine.h"
-#include "FGConfigFile.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_ROCKET "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Models a generic rocket engine.
- The rocket engine is modeled given the following parameters:
- <ul>
- <li>Chamber pressure (in psf)</li>
- <li>Specific heat ratio (usually about 1.2 for hydrocarbon fuel and LOX)</li>
- <li>Propulsive efficiency (in percent, from 0 to 1.0)</li>
- <li>Variance (in percent, from 0 to 1.0, nominally 0.05)</li>
- </ul>
- Additionally, the following control inputs, operating characteristics, and
- location are required, as with all other engine types:
- <ul>
- <li>Throttle setting (in percent, from 0 to 1.0)</li>
- <li>Maximum allowable throttle setting</li>
- <li>Minimum working throttle setting</li>
- <li>Sea level fuel flow at maximum thrust</li>
- <li>Sea level oxidizer flow at maximum thrust</li>
- <li>X, Y, Z location in structural coordinate frame</li>
- <li>Pitch and Yaw</li>
- </ul>
- The nozzle exit pressure (p2) is returned via a
- call to FGNozzle::GetPowerRequired(). This exit pressure is used,
- along with chamber pressure and specific heat ratio, to get the
- thrust coefficient for the throttle setting. This thrust
- coefficient is multiplied by the chamber pressure and then passed
- to the nozzle Calculate() routine, where the thrust force is
- determined.
-
- @author Jon S. Berndt
- $Id$
- @see FGNozzle,
- FGThruster,
- FGForce,
- FGEngine,
- FGPropulsion,
- FGTank
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGRocket : public FGEngine
-{
-public:
- /** Constructor.
- @param exec pointer to JSBSim parent object, the FDM Executive.
- @param Eng_cfg pointer to the config file object.
- @param engine_number engine number */
- FGRocket(FGFDMExec* exec, FGConfigFile* Eng_cfg, int engine_number);
-
- /** Destructor */
- ~FGRocket(void);
-
- /** Determines the thrust coefficient.
- @return thrust coefficient times chamber pressure */
- double Calculate(void);
-
- /** Gets the chamber pressure.
- @return chamber pressure in psf. */
- double GetChamberPressure(void) {return PC;}
-
- /** Gets the flame-out status.
- The engine will "flame out" if the throttle is set below the minimum
- sustainable setting.
- @return true if engine has flamed out. */
- bool GetFlameout(void) {return Flameout;}
- string GetEngineLabels(string delimeter);
- string GetEngineValues(string delimeter);
-
-private:
- double SHR;
- double maxPC;
- double propEff;
- double kFactor;
- double Variance;
- double PC;
- bool Flameout;
-
- void Debug(int from);
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
-
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGRotor.cpp
- Author: Jon S. Berndt
- Date started: 08/24/00
- Purpose: Encapsulates the rotor object
-
- ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-HISTORY
---------------------------------------------------------------------------------
-08/24/00 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "FGRotor.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_ROTOR;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-
-FGRotor::FGRotor(FGFDMExec *FDMExec) : FGThruster(FDMExec)
-{
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGRotor::~FGRotor()
-{
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGRotor::Calculate(double PowerAvailable)
-{
- return 0.0;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGRotor::GetThrusterLabels(int id, string delimeter)
-{
- return "";
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGRotor::GetThrusterValues(int id, string delimeter)
-{
- return "";
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGRotor::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
-
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGRotor" << endl;
- if (from == 1) cout << "Destroyed: FGRotor" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGRotor.h
- Author: Jon S. Berndt
- Date started: 08/24/00
-
- ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-08/24/00 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGROTOR_H
-#define FGROTOR_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGThruster.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_ROTOR "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Models a rotor (such as for a helicopter); NOT YET IMPLEMENTED.
- */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGRotor : public FGThruster {
-
-public:
- FGRotor(FGFDMExec *FDMExec);
- ~FGRotor();
-
- double Calculate(double);
- string GetThrusterLabels(int id, string delimeter);
- string GetThrusterValues(int id, string delimeter);
-
-private:
- void Debug(int from);
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGScript.cpp
- Author: Jon S. Berndt
- Date started: 12/21/01
- Purpose: Loads and runs JSBSim scripts.
-
- ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-This class wraps up the simulation scripting routines.
-
-HISTORY
---------------------------------------------------------------------------------
-12/21/01 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-COMMENTS, REFERENCES, and NOTES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#ifdef FGFS
-# include <simgear/compiler.h>
-# include STL_IOSTREAM
-# include STL_ITERATOR
-#else
-# if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
-# include <iostream.h>
-# else
-# include <iostream>
-# endif
-# include <iterator>
-#endif
-
-#include "FGScript.h"
-#include "FGConfigFile.h"
-#include "FGTrim.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_FGSCRIPT;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-GLOBAL DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-// Constructor
-
-FGScript::FGScript(FGFDMExec* fgex) : FDMExec(fgex)
-{
- State = FDMExec->GetState();
- PropertyManager=FDMExec->GetPropertyManager();
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGScript::~FGScript()
-{
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGScript::LoadScript( string script )
-{
- FGConfigFile Script(script);
- string token="";
- string aircraft="";
- string initialize="";
- string prop_name;
- bool result = false;
- double dt = 0.0;
- struct condition *newCondition;
-
- if (!Script.IsOpen()) return false;
-
- Script.GetNextConfigLine();
- if (Script.GetValue("runscript").length() <= 0) {
- cerr << "File: " << script << " is not a script file" << endl;
- delete FDMExec;
- return false;
- }
- ScriptName = Script.GetValue("name");
- Scripted = true;
-
- if (debug_lvl > 0) cout << "Reading and running from script file " << ScriptName << endl << endl;
-
- while (Script.GetNextConfigLine() != string("EOF") && Script.GetValue() != string("/runscript")) {
- token = Script.GetValue();
- if (token == "use") {
- if ((token = Script.GetValue("aircraft")) != string("")) {
- aircraft = token;
- result = FDMExec->LoadModel(aircraft);
- if (!result) {
- cerr << "Aircraft file " << aircraft << " was not found" << endl;
- exit(-1);
- }
- if (debug_lvl > 0) cout << " Use aircraft: " << token << endl;
- } else if ((token = Script.GetValue("initialize")) != string("")) {
- initialize = token;
- if (debug_lvl > 0) cout << " Use reset file: " << token << endl;
- } else {
- cerr << "Unknown 'use' keyword: \"" << token << "\"" << endl;
- }
- } else if (token == "run") {
- StartTime = strtod(Script.GetValue("start").c_str(), NULL);
- State->Setsim_time(StartTime);
- EndTime = strtod(Script.GetValue("end").c_str(), NULL);
- dt = strtod(Script.GetValue("dt").c_str(), NULL);
- State->Setdt(dt);
- Script.GetNextConfigLine();
- token = Script.GetValue();
- while (token != string("/run")) {
-
- if (token == "when") {
- Script.GetNextConfigLine();
- token = Script.GetValue();
- newCondition = new struct condition();
- while (token != string("/when")) {
- if (token == "parameter") {
- prop_name = Script.GetValue("name");
- newCondition->TestParam.push_back( PropertyManager->GetNode(prop_name) );
- newCondition->TestValue.push_back(strtod(Script.GetValue("value").c_str(), NULL));
- newCondition->Comparison.push_back(Script.GetValue("comparison"));
- } else if (token == "set") {
- prop_name = Script.GetValue("name");
- newCondition->SetParam.push_back( PropertyManager->GetNode(prop_name) );
- newCondition->SetValue.push_back(strtod(Script.GetValue("value").c_str(), NULL));
- newCondition->Triggered.push_back(false);
- newCondition->OriginalValue.push_back(0.0);
- newCondition->newValue.push_back(0.0);
- newCondition->StartTime.push_back(0.0);
- newCondition->EndTime.push_back(0.0);
- string tempCompare = Script.GetValue("type");
- if (tempCompare == "FG_DELTA") newCondition->Type.push_back(FG_DELTA);
- else if (tempCompare == "FG_BOOL") newCondition->Type.push_back(FG_BOOL);
- else if (tempCompare == "FG_VALUE") newCondition->Type.push_back(FG_VALUE);
- else newCondition->Type.push_back((eType)0);
- tempCompare = Script.GetValue("action");
- if (tempCompare == "FG_RAMP") newCondition->Action.push_back(FG_RAMP);
- else if (tempCompare == "FG_STEP") newCondition->Action.push_back(FG_STEP);
- else if (tempCompare == "FG_EXP") newCondition->Action.push_back(FG_EXP);
- else newCondition->Action.push_back((eAction)0);
-
- if (Script.GetValue("persistent") == "true")
- newCondition->Persistent.push_back(true);
- else
- newCondition->Persistent.push_back(false);
-
- newCondition->TC.push_back(strtod(Script.GetValue("tc").c_str(), NULL));
-
- } else {
- cerr << "Unrecognized keyword in script file: \" [when] " << token << "\"" << endl;
- }
- Script.GetNextConfigLine();
- token = Script.GetValue();
- }
- Conditions.push_back(*newCondition);
- Script.GetNextConfigLine();
- token = Script.GetValue();
-
- } else {
- cerr << "Error reading script file: expected \"when\", got \"" << token << "\"" << endl;
- }
-
- }
- } else if (token.empty()) {
- // do nothing
- } else {
- cerr << "Unrecognized keyword in script file: \"" << token << "\" [runscript] " << endl;
- }
- }
-
- if (aircraft == "") {
- cerr << "Aircraft file not loaded in script" << endl;
- exit(-1);
- }
-
- Debug(4);
-
-
- FGInitialCondition *IC=FDMExec->GetIC();
- if ( ! IC->Load( initialize )) {
- cerr << "Initialization unsuccessful" << endl;
- exit(-1);
- }
-/* comment this out for conversion capability
- FGTrim fgt(FDMExec, tFull);
- if ( !fgt.DoTrim() ) {
- cout << "Trim Failed" << endl;
- }
- fgt.Report();
-*/
- return true;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGScript::RunScript(void)
-{
- vector <struct condition>::iterator iC = Conditions.begin();
- bool truth = false;
- bool WholeTruth = false;
- unsigned i;
-
- double currentTime = State->Getsim_time();
- double newSetValue = 0;
-
- if (currentTime > EndTime) return false;
-
- while (iC < Conditions.end()) {
- // determine whether the set of conditional tests for this condition equate
- // to true
- for (i=0; i<iC->TestValue.size(); i++) {
- if (iC->Comparison[i] == "lt")
- truth = iC->TestParam[i]->getDoubleValue() < iC->TestValue[i];
- else if (iC->Comparison[i] == "le")
- truth = iC->TestParam[i]->getDoubleValue() <= iC->TestValue[i];
- else if (iC->Comparison[i] == "eq")
- truth = iC->TestParam[i]->getDoubleValue() == iC->TestValue[i];
- else if (iC->Comparison[i] == "ge")
- truth = iC->TestParam[i]->getDoubleValue() >= iC->TestValue[i];
- else if (iC->Comparison[i] == "gt")
- truth = iC->TestParam[i]->getDoubleValue() > iC->TestValue[i];
- else if (iC->Comparison[i] == "ne")
- truth = iC->TestParam[i]->getDoubleValue() != iC->TestValue[i];
- else
- cerr << "Bad comparison" << endl;
-
- if (i == 0) WholeTruth = truth;
- else WholeTruth = WholeTruth && truth;
-
- if (!truth && iC->Persistent[i] && iC->Triggered[i]) iC->Triggered[i] = false;
- }
-
- // if the conditions are true, do the setting of the desired parameters
-
- if (WholeTruth) {
- for (i=0; i<iC->SetValue.size(); i++) {
- if ( ! iC->Triggered[i]) {
- iC->OriginalValue[i] = iC->SetParam[i]->getDoubleValue();
- switch (iC->Type[i]) {
- case FG_VALUE:
- iC->newValue[i] = iC->SetValue[i];
- break;
- case FG_DELTA:
- iC->newValue[i] = iC->OriginalValue[i] + iC->SetValue[i];
- break;
- case FG_BOOL:
- iC->newValue[i] = iC->SetValue[i];
- break;
- default:
- cerr << "Invalid Type specified" << endl;
- break;
- }
- iC->Triggered[i] = true;
- iC->StartTime[i] = currentTime;
- }
-
- switch (iC->Action[i]) {
- case FG_RAMP:
- newSetValue = (currentTime - iC->StartTime[i])/(iC->TC[i])
- * (iC->newValue[i] - iC->OriginalValue[i]) + iC->OriginalValue[i];
- if (newSetValue > iC->newValue[i]) newSetValue = iC->newValue[i];
- break;
- case FG_STEP:
- newSetValue = iC->newValue[i];
- break;
- case FG_EXP:
- newSetValue = (1 - exp(-(currentTime - iC->StartTime[i])/(iC->TC[i])))
- * (iC->newValue[i] - iC->OriginalValue[i]) + iC->OriginalValue[i];
- break;
- default:
- cerr << "Invalid Action specified" << endl;
- break;
- }
- iC->SetParam[i]->setDoubleValue(newSetValue);
- }
- }
- iC++;
- }
- return true;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGScript::Debug(int from)
-{
- unsigned int i;
-
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
- } else if (from == 3) {
- } else if (from == 4) { // print out script data
- vector <struct condition>::iterator iterConditions = Conditions.begin();
- int count=0;
-
- cout << "\n Script goes from " << StartTime << " to " << EndTime
- << " with dt = " << State->Getdt() << endl << endl;
-
- while (iterConditions < Conditions.end()) {
- cout << " Condition: " << count++ << endl;
- cout << " if (";
-
- for (i=0; i<iterConditions->TestValue.size(); i++) {
- if (i>0) cout << " and" << endl << " ";
- cout << "(" << iterConditions->TestParam[i]->GetName()
- << " " << iterConditions->Comparison[i] << " "
- << iterConditions->TestValue[i] << ")";
- }
- cout << ") then {";
-
- for (i=0; i<iterConditions->SetValue.size(); i++) {
- cout << endl << " set " << iterConditions->SetParam[i]->GetName()
- << " to " << iterConditions->SetValue[i];
-
- switch (iterConditions->Type[i]) {
- case FG_VALUE:
- cout << " (constant";
- break;
- case FG_DELTA:
- cout << " (delta";
- break;
- case FG_BOOL:
- cout << " (boolean";
- break;
- default:
- cout << " (unspecified type";
- }
-
- switch (iterConditions->Action[i]) {
- case FG_RAMP:
- cout << " via ramp";
- break;
- case FG_STEP:
- cout << " via step";
- break;
- case FG_EXP:
- cout << " via exponential approach";
- break;
- default:
- cout << " via unspecified action";
- }
-
- if (!iterConditions->Persistent[i]) cout << endl
- << " once";
- else cout << endl
- << " repeatedly";
-
- if (iterConditions->Action[i] == FG_RAMP ||
- iterConditions->Action[i] == FG_EXP) cout << endl
- << " with time constant "
- << iterConditions->TC[i];
- }
- cout << ")" << endl << " }" << endl << endl;
-
- iterConditions++;
- }
-
- cout << endl;
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGScript" << endl;
- if (from == 1) cout << "Destroyed: FGScript" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- Header: FGScript.h
- Author: Jon Berndt
- Date started: 12/21/2001
-
- ------------- Copyright (C) 2001 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-12/21/01 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGSCRIPT_HEADER_H
-#define FGSCRIPT_HEADER_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGJSBBase.h"
-#include "FGState.h"
-#include "FGFDMExec.h"
-#include <vector>
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_FGSCRIPT "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Encapsulates the JSBSim scripting capability.
- <h4>Scripting support provided via FGScript.</h4>
-
- <p>There is simple scripting support provided in the FGScript
- class. Commands are specified using the <em>Simple Scripting
- Directives for JSBSim</em> (SSDJ). The script file is in XML
- format. A test condition (or conditions) can be set up in the
- script and when the condition evaluates to true, the specified
- action[s] is/are taken. A test condition can be <em>persistent</em>,
- meaning that if a test condition evaluates to true, then passes
- and evaluates to false, the condition is reset and may again be
- triggered. When the set of tests evaluates to true for a given
- condition, an item may be set to another value. This value might
- be a boolean, a value, or a delta value, and the change from the
- current value to the new value can be either via a step function,
- a ramp, or an exponential approach. The speed of a ramp or
- approach is specified via the time constant. Here is the format
- of the script file:</p>
-
- <pre><strong><?xml version="1.0"?>
- <runscript name="C172-01A">
-
- <!--
- This run is for testing C172 runs
- -->
-
- <use aircraft="c172">
- <use initialize="reset00">
-
- <run start="0.0" end="4.5" dt="0.05">
- <when>
- <parameter name="FG_TIME" comparison="ge" value="0.25">
- <parameter name="FG_TIME" comparison="le" value="0.50">
- <set name="FG_AILERON_CMD" type="FG_VALUE" value="0.25"
- action="FG_STEP" persistent="false" tc ="0.25">
- </when>
- <when>
- <parameter name="FG_TIME" comparison="ge" value="0.5">
- <parameter name="FG_TIME" comparison="le" value="1.5">
- <set name="FG_AILERON_CMD" type="FG_DELTA" value="0.5"
- action="FG_EXP" persistent="false" tc ="0.5">
- </when>
- <when>
- <parameter name="FG_TIME" comparison="ge" value="1.5">
- <parameter name="FG_TIME" comparison="le" value="2.5">
- <set name="FG_RUDDER_CMD" type="FG_DELTA" value="0.5"
- action="FG_RAMP" persistent="false" tc ="0.5">
- </when>
- </run>
-
- </runscript></strong></pre>
-
- <p>The first line must always be present. The second line
- identifies this file as a script file, and gives a descriptive
- name to the script file. Comments are next, delineated by the
- <!-- and --> symbols. The aircraft and initialization files
- to be used are specified in the "use" lines. Next,
- comes the "run" section, where the conditions are
- described in "when" clauses.</p>
- @author Jon S. Berndt
- @version "$Id$"
-
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGScript : public FGJSBBase
-{
-public:
- /// Default constructor
- FGScript(FGFDMExec* exec);
-
- /// Default destructor
- ~FGScript();
-
- /** Loads a script to drive JSBSim (usually in standalone mode).
- The language is the Simple Script Directives for JSBSim (SSDJ).
- @param script the filename (including path name, if any) for the script.
- @return true if successful */
- bool LoadScript( string script );
-
- /** This function is called each pass through the executive Run() method IF
- scripting is enabled.
- @return false if script should exit (i.e. if time limits are violated */
- bool RunScript(void);
-
-private:
- enum eAction {
- FG_RAMP = 1,
- FG_STEP = 2,
- FG_EXP = 3
- };
-
- enum eType {
- FG_VALUE = 1,
- FG_DELTA = 2,
- FG_BOOL = 3
- };
-
- struct condition {
- vector <FGPropertyManager*> TestParam;
- vector <FGPropertyManager*> SetParam;
- vector <double> TestValue;
- vector <double> SetValue;
- vector <string> Comparison;
- vector <double> TC;
- vector <bool> Persistent;
- vector <eAction> Action;
- vector <eType> Type;
- vector <bool> Triggered;
- vector <double> newValue;
- vector <double> OriginalValue;
- vector <double> StartTime;
- vector <double> EndTime;
-
- condition() {
- }
- };
-
- bool Scripted;
-
- string ScriptName;
- double StartTime;
- double EndTime;
- vector <struct condition> Conditions;
-
- FGFDMExec* FDMExec;
- FGState* State;
- FGPropertyManager* PropertyManager;
- void Debug(int from);
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
-
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
#ifdef FGFS
# include <simgear/compiler.h>
# include <math.h>
Propagate = FDMExec->GetPropagate();
Auxiliary = FDMExec->GetAuxiliary();
FCS = FDMExec->GetFCS();
- Output = FDMExec->GetOutput();
Atmosphere = FDMExec->GetAtmosphere();
Aerodynamics = FDMExec->GetAerodynamics();
GroundReactions = FDMExec->GetGroundReactions();
#include <string>
#include <map>
#include "FGJSBBase.h"
-#include "FGInitialCondition.h"
-#include "FGMatrix33.h"
-#include "FGColumnVector3.h"
-#include "FGQuaternion.h"
+#include <initialization/FGInitialCondition.h>
+#include <math/FGMatrix33.h>
+#include <math/FGColumnVector3.h>
+#include <math/FGQuaternion.h>
#include "FGFDMExec.h"
-#include "FGAtmosphere.h"
-#include "FGFCS.h"
-#include "FGPropagate.h"
-#include "FGAuxiliary.h"
-#include "FGAerodynamics.h"
-#include "FGOutput.h"
-#include "FGAircraft.h"
-#include "FGGroundReactions.h"
-#include "FGPropulsion.h"
+#include <models/FGAtmosphere.h>
+#include <models/FGFCS.h>
+#include <models/FGPropagate.h>
+#include <models/FGAuxiliary.h>
+#include <models/FGAerodynamics.h>
+#include <models/FGAircraft.h>
+#include <models/FGGroundReactions.h>
+#include <models/FGPropulsion.h>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
/// Returns the simulation time in seconds.
inline double Getsim_time(void) const { return sim_time; }
/// Returns the simulation delta T.
- inline double Getdt(void) { return dt; }
+ inline double Getdt(void) {
+ return dt;
+ }
/// Suspends the simulation and sets the delta T to zero.
- inline void Suspend(void) {saved_dt = dt; dt = 0.0;}
+ inline void SuspendIntegration(void) {saved_dt = dt; dt = 0.0;}
/// Resumes the simulation by resetting delta T to the correct value.
- inline void Resume(void) {dt = saved_dt;}
+ inline void ResumeIntegration(void) {dt = saved_dt;}
+
+ bool IntegrationSuspended(void) {return dt == 0.0;}
/** Sets the current sim time.
@param cur_time the current time
/** Sets the integration time step for the simulation executive.
@param delta_t the time step in seconds.
*/
- inline void Setdt(double delta_t) { dt = delta_t; }
+ inline void Setdt(double delta_t) {
+ dt = delta_t;
+ }
/** Increments the simulation time.
@return the new simulation time.
FGAircraft* Aircraft;
FGPropagate* Propagate;
- FGOutput* Output;
FGAtmosphere* Atmosphere;
FGFCS* FCS;
FGAerodynamics* Aerodynamics;
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGTable.cpp
- Author: Jon S. Berndt
- Date started: 1/9/2001
- Purpose: Models a lookup table
-
- ------------- Copyright (C) 2001 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-Models a lookup table
-
-HISTORY
---------------------------------------------------------------------------------
-JSB 1/9/00 Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "FGTable.h"
-
-#if defined ( sgi ) && !defined( __GNUC__ ) && (_COMPILER_VERSION < 740)
-#include <iomanip.h>
-#else
-#include <iomanip>
-#endif
-
-using namespace std;
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_TABLE;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-
-FGTable::FGTable(int NRows, int NCols, int NTables)
- : nRows(NTables), nCols(1), nTables(NTables)
-{
- Type = tt3D;
- colCounter = 1;
- rowCounter = 1;
-
- Data = Allocate(); // this data array will contain the keys for the associated tables
- Tables.reserve(nTables);
- for (int i=0; i<nTables; i++) Tables.push_back(FGTable(NRows, NCols));
- lastRowIndex=lastColumnIndex=2;
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGTable::FGTable(int NRows, int NCols) : nRows(NRows), nCols(NCols)
-{
- if (NCols > 1) {
- Type = tt2D;
- colCounter = 1;
- rowCounter = 0;
- } else if (NCols == 1) {
- Type = tt1D;
- colCounter = 0;
- rowCounter = 1;
- } else {
- cerr << "FGTable cannot accept 'Rows=0'" << endl;
- }
-
- Data = Allocate();
- lastRowIndex=lastColumnIndex=2;
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGTable::FGTable(int NRows) : nRows(NRows), nCols(1)
-{
- Type = tt1D;
- colCounter = 0;
- rowCounter = 1;
-
- Data = Allocate();
- Debug(0);
- lastRowIndex=lastColumnIndex=2;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGTable::FGTable(const FGTable& t)
-{
- Type = t.Type;
- colCounter = t.colCounter;
- rowCounter = t.rowCounter;
- tableCounter = t.tableCounter;
-
- nRows = t.nRows;
- nCols = t.nCols;
- nTables = t.nTables;
-
- Tables = t.Tables;
- Data = Allocate();
- for (int r=0; r<=nRows; r++) {
- for (int c=0; c<=nCols; c++) {
- Data[r][c] = t.Data[r][c];
- }
- }
- lastRowIndex = t.lastRowIndex;
- lastColumnIndex = t.lastColumnIndex;
- lastTableIndex = t.lastTableIndex;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double** FGTable::Allocate(void)
-{
- Data = new double*[nRows+1];
- for (int r=0; r<=nRows; r++) {
- Data[r] = new double[nCols+1];
- for (int c=0; c<=nCols; c++) {
- Data[r][c] = 0.0;
- }
- }
- return Data;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGTable::~FGTable()
-{
- if (nTables > 0) Tables.clear();
- for (int r=0; r<=nRows; r++) if (Data[r]) delete[] Data[r];
- if (Data) delete[] Data;
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGTable::GetValue(double key)
-{
- double Factor, Value, Span;
- int r=lastRowIndex;
-
- //if the key is off the end of the table, just return the
- //end-of-table value, do not extrapolate
- if( key <= Data[1][0] ) {
- lastRowIndex=2;
- //cout << "Key underneath table: " << key << endl;
- return Data[1][1];
- } else if ( key >= Data[nRows][0] ) {
- lastRowIndex=nRows;
- //cout << "Key over table: " << key << endl;
- return Data[nRows][1];
- }
-
- // the key is somewhere in the middle, search for the right breakpoint
- // assume the correct breakpoint has not changed since last frame or
- // has only changed very little
-
- if ( r > 2 && Data[r-1][0] > key ) {
- while( Data[r-1][0] > key && r > 2) { r--; }
- } else if ( Data[r][0] < key ) {
- while( Data[r][0] <= key && r <= nRows) { r++; }
- }
-
- lastRowIndex=r;
- // make sure denominator below does not go to zero.
-
- Span = Data[r][0] - Data[r-1][0];
- if (Span != 0.0) {
- Factor = (key - Data[r-1][0]) / Span;
- if (Factor > 1.0) Factor = 1.0;
- } else {
- Factor = 1.0;
- }
-
- Value = Factor*(Data[r][1] - Data[r-1][1]) + Data[r-1][1];
-
- return Value;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-double FGTable::GetValue(double rowKey, double colKey)
-{
- double rFactor, cFactor, col1temp, col2temp, Value;
- int r=lastRowIndex;
- int c=lastColumnIndex;
-
- if ( r > 2 && Data[r-1][0] > rowKey ) {
- while ( Data[r-1][0] > rowKey && r > 2) { r--; }
- } else if ( Data[r][0] < rowKey ) {
-// cout << Data[r][0] << endl;
- while ( r <= nRows && Data[r][0] <= rowKey ) { r++; }
- if ( r > nRows ) r = nRows;
- }
-
- if ( c > 2 && Data[0][c-1] > colKey ) {
- while( Data[0][c-1] > colKey && c > 2) { c--; }
- } else if ( Data[0][c] < colKey ) {
- while( Data[0][c] <= colKey && c <= nCols) { c++; }
- if ( c > nCols ) c = nCols;
- }
-
- lastRowIndex=r;
- lastColumnIndex=c;
-
- rFactor = (rowKey - Data[r-1][0]) / (Data[r][0] - Data[r-1][0]);
- cFactor = (colKey - Data[0][c-1]) / (Data[0][c] - Data[0][c-1]);
-
- if (rFactor > 1.0) rFactor = 1.0;
- else if (rFactor < 0.0) rFactor = 0.0;
-
- if (cFactor > 1.0) cFactor = 1.0;
- else if (cFactor < 0.0) cFactor = 0.0;
-
- col1temp = rFactor*(Data[r][c-1] - Data[r-1][c-1]) + Data[r-1][c-1];
- col2temp = rFactor*(Data[r][c] - Data[r-1][c]) + Data[r-1][c];
-
- Value = col1temp + cFactor*(col2temp - col1temp);
-
- return Value;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGTable::GetValue(double rowKey, double colKey, double tableKey)
-{
- double Factor, Value, Span;
- int r=lastRowIndex;
-
- //if the key is off the end (or before the beginning) of the table,
- // just return the boundary-table value, do not extrapolate
-
- if( tableKey <= Data[1][1] ) {
- lastRowIndex=2;
- return Tables[0].GetValue(rowKey, colKey);
- } else if ( tableKey >= Data[nRows][1] ) {
- lastRowIndex=nRows;
- return Tables[nRows-1].GetValue(rowKey, colKey);
- }
-
- // the key is somewhere in the middle, search for the right breakpoint
- // assume the correct breakpoint has not changed since last frame or
- // has only changed very little
-
- if ( r > 2 && Data[r-1][1] > tableKey ) {
- while( Data[r-1][1] > tableKey && r > 2) { r--; }
- } else if ( Data[r][1] < tableKey ) {
- while( Data[r][1] <= tableKey && r <= nRows) { r++; }
- }
-
- lastRowIndex=r;
- // make sure denominator below does not go to zero.
-
- Span = Data[r][1] - Data[r-1][1];
- if (Span != 0.0) {
- Factor = (tableKey - Data[r-1][1]) / Span;
- if (Factor > 1.0) Factor = 1.0;
- } else {
- Factor = 1.0;
- }
-
- Value = Factor*(Tables[r-1].GetValue(rowKey, colKey) - Tables[r-2].GetValue(rowKey, colKey))
- + Tables[r-2].GetValue(rowKey, colKey);
-
- return Value;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGTable::operator<<(FGConfigFile& infile)
-{
- int startRow=0;
- int startCol=0;
- int tableCtr=0;
-
- if (Type == tt1D || Type == tt3D) startRow = 1;
- if (Type == tt3D) startCol = 1;
-
- for (int r=startRow; r<=nRows; r++) {
- for (int c=startCol; c<=nCols; c++) {
- if (r != 0 || c != 0) {
- infile >> Data[r][c];
- if (Type == tt3D) {
- Tables[tableCtr] << infile;
- tableCtr++;
- }
- }
- }
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGTable& FGTable::operator<<(const double n)
-{
- Data[rowCounter][colCounter] = n;
- if (colCounter == nCols) {
- colCounter = 0;
- rowCounter++;
- } else {
- colCounter++;
- }
- return *this;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGTable& FGTable::operator<<(const int n)
-{
- *this << (double)n;
- return *this;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGTable::Print(int spaces)
-{
- string tabspace;
- int startRow=0;
- int startCol=0;
-
- if (Type == tt1D || Type == tt3D) startRow = 1;
- if (Type == tt3D) startCol = 1;
-
-#if defined (sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
- unsigned long flags = cout.setf(ios::fixed);
-#else
- ios::fmtflags flags = cout.setf(ios::fixed); // set up output stream
-#endif
-
- for (int i=0;i<spaces;i++) tabspace+=" ";
-
- cout.precision(4);
- for (int r=startRow; r<=nRows; r++) {
- cout << tabspace;
- for (int c=startCol; c<=nCols; c++) {
- if (r == 0 && c == 0) {
- cout << " ";
- } else {
- cout << Data[r][c] << " ";
- if (Type == tt3D) {
- cout << endl;
- Tables[r-1].Print(spaces);
- }
- }
- }
- cout << endl;
- }
- cout.setf(flags); // reset
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGTable::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
-
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGTable" << endl;
- if (from == 1) cout << "Destroyed: FGTable" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGTable.h
- Author: Jon S. Berndt
- Date started: 1/9/2001
-
- ------------- Copyright (C) 2001 Jon S. Berndt (jsb@hal-pc.org) --------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-JSB 1/9/00 Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGTABLE_H
-#define FGTABLE_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGConfigFile.h"
-#include "FGJSBBase.h"
-#include <vector>
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_TABLE "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-using std::vector;
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Lookup table class.
- Models a one, two, or three dimensional lookup table for use in FGCoefficient,
- FGPropeller, etc. A one-dimensional table is called a "VECTOR" in a coefficient
- definition. For example:
-<pre>
- \<COEFFICIENT NAME="{short name}" TYPE="VECTOR">
- {name}
- {number of rows}
- {row lookup property}
- {non-dimensionalizing properties}
- {row_1_key} {col_1_data}
- {row_2_key} {... }
- { ... } {... }
- {row_n_key} {... }
- \</COEFFICIENT>
-</pre>
- A "real life" example is as shown here:
-<pre>
- \<COEFFICIENT NAME="CLDf" TYPE="VECTOR">
- Delta_lift_due_to_flap_deflection
- 4
- fcs/flap-pos-deg
- aero/qbar-psf | metrics/Sw-sqft
- 0 0
- 10 0.20
- 20 0.30
- 30 0.35
- \</COEFFICIENT>
-</pre>
- The first column in the data table represents the lookup index (or "key"). In
- this case, the lookup index is fcs/flap-pos-deg (flap extension in degrees).
- If the flap position is 10 degrees, the value returned from the lookup table
- would be 0.20. This value would be multiplied by qbar (aero/qbar-psf) and wing
- area (metrics/Sw-sqft) to get the total lift force that is a result of flap
- deflection (measured in pounds force). If the value of the flap-pos-deg property
- was 15 (degrees), the value output by the table routine would be 0.25 - an
- interpolation. If the flap position in degrees ever went below 0.0, or above
- 30 (degrees), the output from the table routine would be 0 and 0.35, respectively.
- That is, there is no _extrapolation_ to values outside the range of the lookup
- index. This is why it is important to chose the data for the table wisely.
-
- The definition for a 2D table - referred to simply as a TABLE, is as follows:
-<pre>
- \<COEFFICIENT NAME="{short name}" TYPE="TABLE">
- {name}
- {number of rows}
- {number of columns}
- {row lookup property}
- {column lookup property}
- {non-dimensionalizing}
- {col_1_key col_2_key ... col_n_key }
- {row_1_key} {col_1_data col_2_data ... col_n_data}
- {row_2_key} {... ... ... ... }
- { ... } {... ... ... ... }
- {row_n_key} {... ... ... ... }
- \</COEFFICIENT>
-</pre>
- A "real life" example is as shown here:
-<pre>
- \<COEFFICIENT NAME="CYb" TYPE="TABLE">
- Side_force_due_to_beta
- 3
- 2
- aero/beta-rad
- fcs/flap-pos-deg
- aero/qbar-psf | metrics/Sw-sqft
- 0 30
- -0.349 0.137 0.106
- 0 0 0
- 0.349 -0.137 -0.106
- \</COEFFICIENT>
-</pre>
- The definition for a 3D table in a coefficient would be (for example):
-<pre>
- \<COEFFICIENT NAME="{short name}" TYPE="TABLE3D">
- {name}
- {number of rows}
- {number of columns}
- {number of tables}
- {row lookup property}
- {column lookup property}
- {table lookup property}
- {non-dimensionalizing}
- {first table key}
- {col_1_key col_2_key ... col_n_key }
- {row_1_key} {col_1_data col_2_data ... col_n_data}
- {row_2_key} {... ... ... ... }
- { ... } {... ... ... ... }
- {row_n_key} {... ... ... ... }
-
- {second table key}
- {col_1_key col_2_key ... col_n_key }
- {row_1_key} {col_1_data col_2_data ... col_n_data}
- {row_2_key} {... ... ... ... }
- { ... } {... ... ... ... }
- {row_n_key} {... ... ... ... }
-
- ...
-
- \</COEFFICIENT>
-</pre>
- [At the present time, all rows and columns for each table must have the
- same dimension.]
-
- In addition to using a Table for something like a coefficient, where all the
- row and column elements are read in from a file, a Table could be created
- and populated completely within program code:
-<pre>
- // First column is thi, second is neta (combustion efficiency)
- Lookup_Combustion_Efficiency = new FGTable(12);
- *Lookup_Combustion_Efficiency << 0.00 << 0.980;
- *Lookup_Combustion_Efficiency << 0.90 << 0.980;
- *Lookup_Combustion_Efficiency << 1.00 << 0.970;
- *Lookup_Combustion_Efficiency << 1.05 << 0.950;
- *Lookup_Combustion_Efficiency << 1.10 << 0.900;
- *Lookup_Combustion_Efficiency << 1.15 << 0.850;
- *Lookup_Combustion_Efficiency << 1.20 << 0.790;
- *Lookup_Combustion_Efficiency << 1.30 << 0.700;
- *Lookup_Combustion_Efficiency << 1.40 << 0.630;
- *Lookup_Combustion_Efficiency << 1.50 << 0.570;
- *Lookup_Combustion_Efficiency << 1.60 << 0.525;
- *Lookup_Combustion_Efficiency << 2.00 << 0.345;
-</pre>
- The first column in the table, above, is thi (the lookup index, or key). The
- second column is the output data - in this case, "neta" (the Greek letter
- referring to combustion efficiency). Later on, the table is used like this:
-
- combustion_efficiency = Lookup_Combustion_Efficiency->GetValue(equivalence_ratio);
-
- @author Jon S. Berndt
- @version $Id$
- @see FGCoefficient
- @see FGPropeller
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGTable : public FGJSBBase
-{
-public:
- /// Destructor
- ~FGTable();
-
- /** This is the very important copy constructor.
- @param table a const reference to a table.*/
- FGTable(const FGTable& table);
-
- /** The constructor for a VECTOR table
- @param nRows the number of rows in this VECTOR table. */
- FGTable(int nRows);
- FGTable(int nRows, int nCols);
- FGTable(int nRows, int nCols, int numTables);
- double GetValue(double key);
- double GetValue(double rowKey, double colKey);
- double GetValue(double rowKey, double colKey, double TableKey);
- /** Read the table in.
- Data in the config file should be in matrix format with the row
- independents as the first column and the column independents in
- the first row. The implication of this layout is that there should
- be no value in the upper left corner of the matrix e.g:
- <pre>
- 0 10 20 30 ...
- -5 1 2 3 4 ...
- ...
- </pre>
-
- For multiple-table (i.e. 3D) data sets there is an additional number
- key in the table definition. For example:
-
- <pre>
- 0.0
- 0 10 20 30 ...
- -5 1 2 3 4 ...
- ...
- </pre>
- */
-
- void operator<<(FGConfigFile&);
- FGTable& operator<<(const double n);
- FGTable& operator<<(const int n);
- inline double GetElement(int r, int c) {return Data[r][c];}
- inline double GetElement(int r, int c, int t);
- void Print(int spaces=0);
-
-private:
- enum type {tt1D, tt2D, tt3D} Type;
- double** Data;
- vector <FGTable> Tables;
- int nRows, nCols, nTables;
- int colCounter, rowCounter, tableCounter;
- int lastRowIndex, lastColumnIndex, lastTableIndex;
- double** Allocate(void);
- void Debug(int from);
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-#endif
-
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGTank.cpp
- Author: Jon Berndt
- Date started: 01/21/99
- Called by: FGAircraft
-
- ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-See header file.
-
-HISTORY
---------------------------------------------------------------------------------
-01/21/99 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGTank.h"
-
-#if !defined ( sgi ) || defined( __GNUC__ ) && (_COMPILER_VERSION < 740)
-using std::cerr;
-using std::endl;
-using std::cout;
-#endif
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_TANK;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-FGTank::FGTank(FGConfigFile* AC_cfg, FGFDMExec* exec)
-{
- string token;
- double X, Y, Z;
- Area = 1.0;
- Temperature = -9999.0;
- Auxiliary = exec->GetAuxiliary();
-
- type = AC_cfg->GetValue("TYPE");
-
- if (type == "FUEL") Type = ttFUEL;
- else if (type == "OXIDIZER") Type = ttOXIDIZER;
- else Type = ttUNKNOWN;
-
- AC_cfg->GetNextConfigLine();
- while ((token = AC_cfg->GetValue()) != string("/AC_TANK")) {
- if (token == "XLOC") *AC_cfg >> X;
- else if (token == "YLOC") *AC_cfg >> Y;
- else if (token == "ZLOC") *AC_cfg >> Z;
- else if (token == "RADIUS") *AC_cfg >> Radius;
- else if (token == "CAPACITY") *AC_cfg >> Capacity;
- else if (token == "CONTENTS") *AC_cfg >> Contents;
- else if (token == "TEMPERATURE") *AC_cfg >> Temperature;
- else cerr << "Unknown identifier: " << token << " in tank definition." << endl;
- }
-
- vXYZ << X << Y << Z;
-
- Selected = true;
-
- if (Capacity != 0) {
- PctFull = 100.0*Contents/Capacity; // percent full; 0 to 100.0
- } else {
- Contents = 0;
- PctFull = 0;
- }
-
- if (Temperature != -9999.0) Temperature = FahrenheitToCelsius(Temperature);
- Area = 40.0 * pow(Capacity/1975, 0.666666667);
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGTank::~FGTank()
-{
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGTank::Drain(double used)
-{
- double shortage = Contents - used;
-
- if (shortage >= 0) {
- Contents -= used;
- PctFull = 100.0*Contents/Capacity;
- } else {
- Contents = 0.0;
- PctFull = 0.0;
- Selected = false;
- }
- return shortage;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGTank::Fill(double amount)
-{
- double overage = 0.0;
-
- Contents += amount;
-
- if (Contents > Capacity) {
- overage = Contents - Capacity;
- Contents = Capacity;
- PctFull = 100.0;
- } else {
- PctFull = Contents/Capacity*100.0;
- }
- return overage;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGTank::SetContents(double amount)
-{
- Contents = amount;
- if (Contents > Capacity) {
- Contents = Capacity;
- PctFull = 100.0;
- } else {
- PctFull = Contents/Capacity*100.0;
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGTank::Calculate(double dt)
-{
- if (Temperature == -9999.0) return 0.0;
- double HeatCapacity = 900.0; // Joules/lbm/C
- double TempFlowFactor = 1.115; // Watts/sqft/C
- double TAT = Auxiliary->GetTAT_C();
- double Tdiff = TAT - Temperature;
- double dT = 0.0; // Temp change due to one surface
- if (fabs(Tdiff) > 0.1) {
- dT = (TempFlowFactor * Area * Tdiff * dt) / (Contents * HeatCapacity);
- }
- return Temperature += (dT + dT); // For now, assume upper/lower the same
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGTank::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
- cout << " " << type << " tank holds " << Capacity << " lbs. " << type << endl;
- cout << " currently at " << PctFull << "% of maximum capacity" << endl;
- cout << " Tank location (X, Y, Z): " << vXYZ(eX) << ", " << vXYZ(eY) << ", " << vXYZ(eZ) << endl;
- cout << " Effective radius: " << Radius << " inches" << endl;
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGTank" << endl;
- if (from == 1) cout << "Destroyed: FGTank" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGTank.h
- Author: Jon S. Berndt
- Date started: 01/21/99
-
- ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-Based on Flightgear code, which is based on LaRCSim. This class simulates
-a generic Tank.
-
-HISTORY
---------------------------------------------------------------------------------
-01/21/99 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGTank_H
-#define FGTank_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGJSBBase.h"
-#include "FGConfigFile.h"
-#include "FGColumnVector3.h"
-#include "FGAuxiliary.h"
-
-#ifdef FGFS
-# include <simgear/compiler.h>
-# include STL_STRING
- SG_USING_STD(string);
- SG_USING_STD(cerr);
- SG_USING_STD(endl);
- SG_USING_STD(cout);
-#else
-# include <string>
- using std::string;
-# if !defined(sgi) || defined(__GNUC__) || (_COMPILER_VERSION >= 740)
- using std::cerr;
- using std::endl;
- using std::cout;
-# endif
-#endif
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_TANK "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Models a fuel tank.
- @author Jon Berndt
- @see Akbar, Raza et al. "A Simple Analysis of Fuel Addition to the CWT of
- 747", California Institute of Technology, 1998
-<P>
- Fuel temperature is calculated using the following assumptions:
-<P>
- Fuel temperature will only be calculated for tanks which have an initial fuel
- temperature specified in the configuration file.
-<P>
- The surface area of the tank is estimated from the capacity in pounds. It
- is assumed that the tank is a wing tank with dimensions h by 4h by 10h. The
- volume of the tank is then 40(h)(h)(h). The area of the upper or lower
- surface is then 40(h)(h). The volume is also equal to the capacity divided
- by 49.368 lbs/cu-ft, for jet fuel. The surface area of one side can then be
- derived from the tank's capacity.
-<P>
- The heat capacity of jet fuel is assumed to be 900 Joules/lbm/K, and the
- heat transfer factor of the tank is 1.115 Watts/sq-ft/K.
-<P>
-Configuration File Format
-<pre>
-\<AC_TANK TYPE="\<FUEL | OXIDIZER>" NUMBER="\<n>">
- XLOC \<x location>
- YLOC \<y location>
- ZLOC \<z location>
- RADIUS \<radius>
- CAPACITY \<capacity>
- CONTENTS \<contents>
- TEMPERATURE \<fuel temperature>
-\</AC_TANK>
-</pre>
-Definition of the tank configuration file parameters:
-<pre>
-<b>TYPE</b> - One of FUEL or OXIDIZER.
-<b>XLOC</b> - Location of tank on aircraft's x-axis, inches.
-<b>YLOC</b> - Location of tank on aircraft's y-axis, inches.
-<b>ZLOC</b> - Location of tank on aircraft's z-axis, inches.
-<b>RADIUS</b> - Equivalent radius of tank, inches, for modeling slosh.
-<b>CAPACITY</b> - Capacity in pounds.
-<b>CONTENTS</b> - Initial contents in pounds.
-<b>TEMPERATURE</b> - Initial temperature in degrees Fahrenheit.
-</pre>
- */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGTank : public FGJSBBase
-{
-public:
- FGTank(FGConfigFile*, FGFDMExec*);
- ~FGTank();
-
- double Drain(double);
- double Calculate(double dt);
- int GetType(void) {return Type;}
- bool GetSelected(void) {return Selected;}
- double GetPctFull(void) {return PctFull;}
- double GetContents(void) {return Contents;}
- double GetTemperature_degC(void) {return Temperature;}
- double GetTemperature(void) {return CelsiusToFahrenheit(Temperature);}
- const FGColumnVector3& GetXYZ(void) {return vXYZ;}
- double GetXYZ(int idx) {return vXYZ(idx);}
-
- double Fill(double amount);
- void SetContents(double amount);
- void SetTemperature(double temp) { Temperature = temp; }
-
- enum TankType {ttUNKNOWN, ttFUEL, ttOXIDIZER};
-
-private:
- TankType Type;
- string type;
- FGColumnVector3 vXYZ;
- double Capacity;
- double Radius;
- double PctFull;
- double Contents;
- double Area;
- double Temperature;
- bool Selected;
- FGAuxiliary* Auxiliary;
- void Debug(int from);
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
-
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGThruster.cpp
- Author: Jon S. Berndt
- Date started: 08/23/00
- Purpose: Encapsulates the thruster object
-
- ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-HISTORY
---------------------------------------------------------------------------------
-08/23/00 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <sstream>
-
-#include "FGThruster.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_THRUSTER;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-
-FGThruster::FGThruster(FGFDMExec *FDMExec) : FGForce(FDMExec)
-{
- Type = ttDirect;
- SetTransformType(FGForce::tCustom);
-
- EngineNum = 0;
- PropertyManager = FDMExec->GetPropertyManager();
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGThruster::FGThruster(FGFDMExec *FDMExec,
- FGConfigFile *Eng_cfg, int num ): FGForce(FDMExec)
-{
- Type = ttDirect;
- SetTransformType(FGForce::tCustom);
- Name = Eng_cfg->GetValue();
- GearRatio = 1.0;
-
- EngineNum = num;
- ThrustCoeff = 0.0;
- ReverserAngle = 0.0;
- PropertyManager = FDMExec->GetPropertyManager();
-
- char property_name[80];
- snprintf(property_name, 80, "propulsion/c-thrust[%u]", EngineNum);
- PropertyManager->Tie( property_name, &ThrustCoeff );
- snprintf(property_name, 80, "propulsion/engine[%u]/reverser-angle", EngineNum);
- PropertyManager->Tie( property_name, &ReverserAngle );
-
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGThruster::~FGThruster()
-{
- char property_name[80];
- snprintf(property_name, 80, "propulsion/c-thrust[%u]", EngineNum);
- PropertyManager->Untie( property_name );
- snprintf(property_name, 80, "propulsion/engine[%u]/reverser-angle", EngineNum);
- PropertyManager->Untie( property_name );
-
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGThruster::GetThrusterLabels(int id, string delimeter)
-{
- std::ostringstream buf;
-
- buf << Name << "_Thrust[" << id << "]";
-
- return buf.str();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGThruster::GetThrusterValues(int id, string delimeter)
-{
- std::ostringstream buf;
-
- buf << Thrust;
-
- return buf.str();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGThruster::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
-
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGThruster" << endl;
- if (from == 1) cout << "Destroyed: FGThruster" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGThruster.h
- Author: Jon S. Berndt
- Date started: 08/23/00
-
- ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-08/24/00 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGTHRUSTER_H
-#define FGTHRUSTER_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGForce.h"
-#include "FGConfigFile.h"
-#include "FGPropertyManager.h"
-#include <string>
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_THRUSTER "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Base class for specific thrusting devices such as propellers, nozzles, etc.
- @author Jon Berndt
- @version $Id$
- */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGThruster : public FGForce {
-
-public:
- /// Constructor
- FGThruster(FGFDMExec *FDMExec);
- FGThruster(FGFDMExec *FDMExec, FGConfigFile *Eng_cfg, int num );
- /// Destructor
- virtual ~FGThruster();
-
- enum eType {ttNozzle, ttRotor, ttPropeller, ttDirect};
-
- virtual double Calculate(double tt) {
- Thrust = tt;
- vFn(1) = Thrust * cos(ReverserAngle);
- return vFn(1);
- }
- void SetName(string name) {Name = name;}
- virtual void SetRPM(double rpm) {};
- virtual double GetPowerRequired(void) {return 0.0;}
- virtual void SetdeltaT(double dt) {deltaT = dt;}
- double GetThrust(void) {return Thrust;}
- eType GetType(void) {return Type;}
- string GetName(void) {return Name;}
- virtual double GetRPM(void) { return 0.0; };
- double GetGearRatio(void) {return GearRatio; }
- virtual string GetThrusterLabels(int id, string delimeter);
- virtual string GetThrusterValues(int id, string delimeter);
- void SetReverserAngle(double radians) { ReverserAngle = radians; }
- double GetReverserAngle(void) {return ReverserAngle;}
-
-
- inline void SetThrustCoefficient(double ct) { ThrustCoeff = ct; }
-
-protected:
- eType Type;
- string Name;
- double Thrust;
- double PowerRequired;
- double deltaT;
- double GearRatio;
- double ThrustCoeff;
- double ReverserAngle;
- int EngineNum;
- FGPropertyManager* PropertyManager;
- virtual void Debug(int from);
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
-
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGTrim.cpp
- Author: Tony Peden
- Date started: 9/8/99
-
- --------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) ---------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-
- HISTORY
---------------------------------------------------------------------------------
-9/8/99 TP Created
-
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-This class takes the given set of IC's and finds the angle of attack, elevator,
-and throttle setting required to fly steady level. This is currently for in-air
-conditions only. It is implemented using an iterative, one-axis-at-a-time
-scheme. */
-
-// !!!!!!! BEWARE ALL YE WHO ENTER HERE !!!!!!!
-
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include <stdlib.h>
-
-#include "FGFDMExec.h"
-#include "FGAtmosphere.h"
-#include "FGInitialCondition.h"
-#include "FGTrim.h"
-#include "FGAircraft.h"
-#include "FGMassBalance.h"
-#include "FGGroundReactions.h"
-#include "FGInertial.h"
-#include "FGAerodynamics.h"
-#include "FGColumnVector3.h"
-
-#if _MSC_VER
-#pragma warning (disable : 4786 4788)
-#endif
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_TRIM;
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGTrim::FGTrim(FGFDMExec *FDMExec,TrimMode tt) {
-
- N=Nsub=0;
- max_iterations=60;
- max_sub_iterations=100;
- Tolerance=1E-3;
- A_Tolerance = Tolerance / 10;
-
- Debug=0;DebugLevel=0;
- fdmex=FDMExec;
- fgic=fdmex->GetIC();
- total_its=0;
- trimudot=true;
- gamma_fallback=true;
- axis_count=0;
- mode=tt;
- xlo=xhi=alo=ahi=0.0;
- targetNlf=1.0;
- debug_axis=tAll;
- SetMode(tt);
- if (debug_lvl & 2) cout << "Instantiated: FGTrim" << endl;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGTrim::~FGTrim(void) {
- for(current_axis=0; current_axis<TrimAxes.size(); current_axis++) {
- delete TrimAxes[current_axis];
- }
- delete[] sub_iterations;
- delete[] successful;
- delete[] solution;
- if (debug_lvl & 2) cout << "Destroyed: FGTrim" << endl;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGTrim::TrimStats() {
- char out[80];
- int run_sum=0;
- cout << endl << " Trim Statistics: " << endl;
- cout << " Total Iterations: " << total_its << endl;
- if(total_its > 0) {
- cout << " Sub-iterations:" << endl;
- for(current_axis=0; current_axis<TrimAxes.size(); current_axis++) {
- run_sum+=TrimAxes[current_axis]->GetRunCount();
- snprintf(out,80," %5s: %3.0f average: %5.2f successful: %3.0f stability: %5.2f\n",
- TrimAxes[current_axis]->GetStateName().c_str(),
- sub_iterations[current_axis],
- sub_iterations[current_axis]/double(total_its),
- successful[current_axis],
- TrimAxes[current_axis]->GetAvgStability() );
- cout << out;
- }
- cout << " Run Count: " << run_sum << endl;
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGTrim::Report(void) {
- cout << " Trim Results: " << endl;
- for(current_axis=0; current_axis<TrimAxes.size(); current_axis++)
- TrimAxes[current_axis]->AxisReport();
-
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGTrim::ClearStates(void) {
- FGTrimAxis* ta;
-
- mode=tCustom;
- vector<FGTrimAxis*>::iterator iAxes;
- iAxes = TrimAxes.begin();
- while (iAxes != TrimAxes.end()) {
- ta=*iAxes;
- delete ta;
- iAxes++;
- }
- TrimAxes.clear();
- //cout << "TrimAxes.size(): " << TrimAxes.size() << endl;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGTrim::AddState( State state, Control control ) {
- FGTrimAxis* ta;
- bool result=true;
-
- mode = tCustom;
- vector <FGTrimAxis*>::iterator iAxes = TrimAxes.begin();
- while (iAxes != TrimAxes.end()) {
- ta=*iAxes;
- if( ta->GetStateType() == state )
- result=false;
- iAxes++;
- }
- if(result) {
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,state,control));
- delete[] sub_iterations;
- delete[] successful;
- delete[] solution;
- sub_iterations=new double[TrimAxes.size()];
- successful=new double[TrimAxes.size()];
- solution=new bool[TrimAxes.size()];
- }
- return result;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGTrim::RemoveState( State state ) {
- FGTrimAxis* ta;
- bool result=false;
-
- mode = tCustom;
- vector <FGTrimAxis*>::iterator iAxes = TrimAxes.begin();
- while (iAxes != TrimAxes.end()) {
- ta=*iAxes;
- if( ta->GetStateType() == state ) {
- delete ta;
- TrimAxes.erase(iAxes);
- result=true;
- continue;
- }
- iAxes++;
- }
- if(result) {
- delete[] sub_iterations;
- delete[] successful;
- delete[] solution;
- sub_iterations=new double[TrimAxes.size()];
- successful=new double[TrimAxes.size()];
- solution=new bool[TrimAxes.size()];
- }
- return result;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGTrim::EditState( State state, Control new_control ){
- FGTrimAxis* ta;
- bool result=false;
-
- mode = tCustom;
- vector <FGTrimAxis*>::iterator iAxes = TrimAxes.begin();
- while (iAxes != TrimAxes.end()) {
- ta=*iAxes;
- if( ta->GetStateType() == state ) {
- TrimAxes.insert(iAxes,1,new FGTrimAxis(fdmex,fgic,state,new_control));
- delete ta;
- TrimAxes.erase(iAxes+1);
- result=true;
- break;
- }
- iAxes++;
- }
- return result;
-}
-
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGTrim::DoTrim(void) {
-
- trim_failed=false;
- int i;
-
- for(i=0;i < fdmex->GetGroundReactions()->GetNumGearUnits();i++){
- fdmex->GetGroundReactions()->GetGearUnit(i)->SetReport(false);
- }
-
- fdmex->GetOutput()->Disable();
-
- fgic->SetPRadpsIC(0.0);
- fgic->SetQRadpsIC(0.0);
- fgic->SetRRadpsIC(0.0);
-
- //clear the sub iterations counts & zero out the controls
- for(current_axis=0;current_axis<TrimAxes.size();current_axis++) {
- //cout << current_axis << " " << TrimAxes[current_axis]->GetStateName()
- //<< " " << TrimAxes[current_axis]->GetControlName()<< endl;
- if(TrimAxes[current_axis]->GetStateType() == tQdot) {
- if(mode == tGround) {
- TrimAxes[current_axis]->initTheta();
- }
- }
- xlo=TrimAxes[current_axis]->GetControlMin();
- xhi=TrimAxes[current_axis]->GetControlMax();
- TrimAxes[current_axis]->SetControl((xlo+xhi)/2);
- TrimAxes[current_axis]->Run();
- //TrimAxes[current_axis]->AxisReport();
- sub_iterations[current_axis]=0;
- successful[current_axis]=0;
- solution[current_axis]=false;
- }
-
-
- if(mode == tPullup ) {
- cout << "Setting pitch rate and nlf... " << endl;
- setupPullup();
- cout << "pitch rate done ... " << endl;
- TrimAxes[0]->SetStateTarget(targetNlf);
- cout << "nlf done" << endl;
- } else if (mode == tTurn) {
- setupTurn();
- //TrimAxes[0]->SetStateTarget(targetNlf);
- }
-
- do {
- axis_count=0;
- for(current_axis=0;current_axis<TrimAxes.size();current_axis++) {
- setDebug();
- updateRates();
- Nsub=0;
- if(!solution[current_axis]) {
- if(checkLimits()) {
- solution[current_axis]=true;
- solve();
- }
- } else if(findInterval()) {
- solve();
- } else {
- solution[current_axis]=false;
- }
- sub_iterations[current_axis]+=Nsub;
- }
- for(current_axis=0;current_axis<TrimAxes.size();current_axis++) {
- //these checks need to be done after all the axes have run
- if(Debug > 0) TrimAxes[current_axis]->AxisReport();
- if(TrimAxes[current_axis]->InTolerance()) {
- axis_count++;
- successful[current_axis]++;
- }
- }
-
-
- if((axis_count == TrimAxes.size()-1) && (TrimAxes.size() > 1)) {
- //cout << TrimAxes.size()-1 << " out of " << TrimAxes.size() << "!" << endl;
- //At this point we can check the input limits of the failed axis
- //and declare the trim failed if there is no sign change. If there
- //is, keep going until success or max iteration count
-
- //Oh, well: two out of three ain't bad
- for(current_axis=0;current_axis<TrimAxes.size();current_axis++) {
- //these checks need to be done after all the axes have run
- if(!TrimAxes[current_axis]->InTolerance()) {
- if(!checkLimits()) {
- // special case this for now -- if other cases arise proper
- // support can be added to FGTrimAxis
- if( (gamma_fallback) &&
- (TrimAxes[current_axis]->GetStateType() == tUdot) &&
- (TrimAxes[current_axis]->GetControlType() == tThrottle)) {
- cout << " Can't trim udot with throttle, trying flight"
- << " path angle. (" << N << ")" << endl;
- if(TrimAxes[current_axis]->GetState() > 0)
- TrimAxes[current_axis]->SetControlToMin();
- else
- TrimAxes[current_axis]->SetControlToMax();
- TrimAxes[current_axis]->Run();
- delete TrimAxes[current_axis];
- TrimAxes[current_axis]=new FGTrimAxis(fdmex,fgic,tUdot,
- tGamma );
- } else {
- cout << " Sorry, " << TrimAxes[current_axis]->GetStateName()
- << " doesn't appear to be trimmable" << endl;
- //total_its=k;
- trim_failed=true; //force the trim to fail
- } //gamma_fallback
- }
- } //solution check
- } //for loop
- } //all-but-one check
- N++;
- if(N > max_iterations)
- trim_failed=true;
- } while((axis_count < TrimAxes.size()) && (!trim_failed));
- if((!trim_failed) && (axis_count >= TrimAxes.size())) {
- total_its=N;
- if (debug_lvl > 0)
- cout << endl << " Trim successful" << endl;
- } else {
- total_its=N;
- if (debug_lvl > 0)
- cout << endl << " Trim failed" << endl;
- }
- for(i=0;i < fdmex->GetGroundReactions()->GetNumGearUnits();i++){
- fdmex->GetGroundReactions()->GetGearUnit(i)->SetReport(true);
- }
- fdmex->GetOutput()->Enable();
- return !trim_failed;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGTrim::solve(void) {
-
- double x1,x2,x3,f1,f2,f3,d,d0;
- const double relax =0.9;
- double eps=TrimAxes[current_axis]->GetSolverEps();
-
- x1=x2=x3=0;
- d=1;
- bool success=false;
- //initializations
- if( solutionDomain != 0) {
- /* if(ahi > alo) { */
- x1=xlo;f1=alo;
- x3=xhi;f3=ahi;
- /* } else {
- x1=xhi;f1=ahi;
- x3=xlo;f3=alo;
- } */
- d0=fabs(x3-x1);
- //iterations
- //max_sub_iterations=TrimAxes[current_axis]->GetIterationLimit();
- while ( (TrimAxes[current_axis]->InTolerance() == false )
- && (fabs(d) > eps) && (Nsub < max_sub_iterations)) {
- Nsub++;
- d=(x3-x1)/d0;
- x2=x1-d*d0*f1/(f3-f1);
- TrimAxes[current_axis]->SetControl(x2);
- TrimAxes[current_axis]->Run();
- f2=TrimAxes[current_axis]->GetState();
- if(Debug > 1) {
- cout << "FGTrim::solve Nsub,x1,x2,x3: " << Nsub << ", " << x1
- << ", " << x2 << ", " << x3 << endl;
- cout << " " << f1 << ", " << f2 << ", " << f3 << endl;
- }
- if(f1*f2 <= 0.0) {
- x3=x2;
- f3=f2;
- f1=relax*f1;
- //cout << "Solution is between x1 and x2" << endl;
- }
- else if(f2*f3 <= 0.0) {
- x1=x2;
- f1=f2;
- f3=relax*f3;
- //cout << "Solution is between x2 and x3" << endl;
-
- }
- //cout << i << endl;
-
-
- }//end while
- if(Nsub < max_sub_iterations) success=true;
- }
- return success;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-/*
- produces an interval (xlo..xhi) on one side or the other of the current
- control value in which a solution exists. This domain is, hopefully,
- smaller than xmin..0 or 0..xmax and the solver will require fewer iterations
- to find the solution. This is, hopefully, more efficient than having the
- solver start from scratch every time. Maybe it isn't though...
- This tries to take advantage of the idea that the changes from iteration to
- iteration will be small after the first one or two top-level iterations.
-
- assumes that changing the control will a produce significant change in the
- accel i.e. checkLimits() has already been called.
-
- if a solution is found above the current control, the function returns true
- and xlo is set to the current control, xhi to the interval max it found, and
- solutionDomain is set to 1.
- if the solution lies below the current control, then the function returns
- true and xlo is set to the interval min it found and xmax to the current
- control. if no solution is found, then the function returns false.
-
-
- in all cases, alo=accel(xlo) and ahi=accel(xhi) after the function exits.
- no assumptions about the state of the sim after this function has run
- can be made.
-*/
-bool FGTrim::findInterval(void) {
- bool found=false;
- double step;
- double current_control=TrimAxes[current_axis]->GetControl();
- double current_accel=TrimAxes[current_axis]->GetState();;
- double xmin=TrimAxes[current_axis]->GetControlMin();
- double xmax=TrimAxes[current_axis]->GetControlMax();
- double lastxlo,lastxhi,lastalo,lastahi;
-
- step=0.025*fabs(xmax);
- xlo=xhi=current_control;
- alo=ahi=current_accel;
- lastxlo=xlo;lastxhi=xhi;
- lastalo=alo;lastahi=ahi;
- do {
-
- Nsub++;
- step*=2;
- xlo-=step;
- if(xlo < xmin) xlo=xmin;
- xhi+=step;
- if(xhi > xmax) xhi=xmax;
- TrimAxes[current_axis]->SetControl(xlo);
- TrimAxes[current_axis]->Run();
- alo=TrimAxes[current_axis]->GetState();
- TrimAxes[current_axis]->SetControl(xhi);
- TrimAxes[current_axis]->Run();
- ahi=TrimAxes[current_axis]->GetState();
- if(fabs(ahi-alo) <= TrimAxes[current_axis]->GetTolerance()) continue;
- if(alo*ahi <=0) { //found interval with root
- found=true;
- if(alo*current_accel <= 0) { //narrow interval down a bit
- solutionDomain=-1;
- xhi=lastxlo;
- ahi=lastalo;
- //xhi=current_control;
- //ahi=current_accel;
- } else {
- solutionDomain=1;
- xlo=lastxhi;
- alo=lastahi;
- //xlo=current_control;
- //alo=current_accel;
- }
- }
- lastxlo=xlo;lastxhi=xhi;
- lastalo=alo;lastahi=ahi;
- if( !found && xlo==xmin && xhi==xmax ) continue;
- if(Debug > 1)
- cout << "FGTrim::findInterval: Nsub=" << Nsub << " Lo= " << xlo
- << " Hi= " << xhi << " alo*ahi: " << alo*ahi << endl;
- } while(!found && (Nsub <= max_sub_iterations) );
- return found;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-//checks to see which side of the current control value the solution is on
-//and sets solutionDomain accordingly:
-// 1 if solution is between the current and max
-// -1 if solution is between the min and current
-// 0 if there is no solution
-//
-//if changing the control produces no significant change in the accel then
-//solutionDomain is set to zero and the function returns false
-//if a solution is found, then xlo and xhi are set so that they bracket
-//the solution, alo is set to accel(xlo), and ahi is set to accel(xhi)
-//if there is no change or no solution then xlo=xmin, alo=accel(xmin) and
-//xhi=xmax and ahi=accel(xmax)
-//in all cases the sim is left such that the control=xmax and accel=ahi
-
-bool FGTrim::checkLimits(void) {
- bool solutionExists;
- double current_control=TrimAxes[current_axis]->GetControl();
- double current_accel=TrimAxes[current_axis]->GetState();
- xlo=TrimAxes[current_axis]->GetControlMin();
- xhi=TrimAxes[current_axis]->GetControlMax();
-
- TrimAxes[current_axis]->SetControl(xlo);
- TrimAxes[current_axis]->Run();
- alo=TrimAxes[current_axis]->GetState();
- TrimAxes[current_axis]->SetControl(xhi);
- TrimAxes[current_axis]->Run();
- ahi=TrimAxes[current_axis]->GetState();
- if(Debug > 1)
- cout << "checkLimits() xlo,xhi,alo,ahi: " << xlo << ", " << xhi << ", "
- << alo << ", " << ahi << endl;
- solutionDomain=0;
- solutionExists=false;
- if(fabs(ahi-alo) > TrimAxes[current_axis]->GetTolerance()) {
- if(alo*current_accel <= 0) {
- solutionExists=true;
- solutionDomain=-1;
- xhi=current_control;
- ahi=current_accel;
- } else if(current_accel*ahi < 0){
- solutionExists=true;
- solutionDomain=1;
- xlo=current_control;
- alo=current_accel;
- }
- }
- TrimAxes[current_axis]->SetControl(current_control);
- TrimAxes[current_axis]->Run();
- return solutionExists;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGTrim::setupPullup() {
- double g,q,cgamma;
- g=fdmex->GetInertial()->gravity();
- cgamma=cos(fgic->GetFlightPathAngleRadIC());
- cout << "setPitchRateInPullup(): " << g << ", " << cgamma << ", "
- << fgic->GetVtrueFpsIC() << endl;
- q=g*(targetNlf-cgamma)/fgic->GetVtrueFpsIC();
- cout << targetNlf << ", " << q << endl;
- fgic->SetQRadpsIC(q);
- cout << "setPitchRateInPullup() complete" << endl;
-
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGTrim::setupTurn(void){
- double g,phi;
- phi = fgic->GetRollAngleRadIC();
- if( fabs(phi) > 0.001 && fabs(phi) < 1.56 ) {
- targetNlf = 1 / cos(phi);
- g = fdmex->GetInertial()->gravity();
- psidot = g*tan(phi) / fgic->GetUBodyFpsIC();
- cout << targetNlf << ", " << psidot << endl;
- }
-
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGTrim::updateRates(void){
- if( mode == tTurn ) {
- double phi = fgic->GetRollAngleRadIC();
- double g = fdmex->GetInertial()->gravity();
- double p,q,r,theta;
- if(fabs(phi) > 0.001 && fabs(phi) < 1.56 ) {
- theta=fgic->GetPitchAngleRadIC();
- phi=fgic->GetRollAngleRadIC();
- psidot = g*tan(phi) / fgic->GetUBodyFpsIC();
- p=-psidot*sin(theta);
- q=psidot*cos(theta)*sin(phi);
- r=psidot*cos(theta)*cos(phi);
- } else {
- p=q=r=0;
- }
- fgic->SetPRadpsIC(p);
- fgic->SetQRadpsIC(q);
- fgic->SetRRadpsIC(r);
- } else if( mode == tPullup && fabs(targetNlf-1) > 0.01) {
- double g,q,cgamma;
- g=fdmex->GetInertial()->gravity();
- cgamma=cos(fgic->GetFlightPathAngleRadIC());
- q=g*(targetNlf-cgamma)/fgic->GetVtrueFpsIC();
- fgic->SetQRadpsIC(q);
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGTrim::setDebug(void) {
- if(debug_axis == tAll ||
- TrimAxes[current_axis]->GetStateType() == debug_axis ) {
- Debug=DebugLevel;
- return;
- } else {
- Debug=0;
- return;
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGTrim::SetMode(TrimMode tt) {
- ClearStates();
- mode=tt;
- switch(tt) {
- case tFull:
- if (debug_lvl > 0)
- cout << " Full Trim" << endl;
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tWdot,tAlpha ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tUdot,tThrottle ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tQdot,tPitchTrim ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tHmgt,tBeta ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tVdot,tPhi ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tPdot,tAileron ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tRdot,tRudder ));
- break;
- case tLongitudinal:
- if (debug_lvl > 0)
- cout << " Longitudinal Trim" << endl;
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tWdot,tAlpha ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tUdot,tThrottle ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tQdot,tPitchTrim ));
- break;
- case tGround:
- if (debug_lvl > 0)
- cout << " Ground Trim" << endl;
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tWdot,tAltAGL ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tQdot,tTheta ));
- //TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tPdot,tPhi ));
- break;
- case tPullup:
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tNlf,tAlpha ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tUdot,tThrottle ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tQdot,tPitchTrim ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tHmgt,tBeta ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tVdot,tPhi ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tPdot,tAileron ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tRdot,tRudder ));
- break;
- case tTurn:
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tWdot,tAlpha ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tUdot,tThrottle ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tQdot,tPitchTrim ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tVdot,tBeta ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tPdot,tAileron ));
- TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tRdot,tRudder ));
- break;
- case tCustom:
- case tNone:
- break;
- }
- //cout << "TrimAxes.size(): " << TrimAxes.size() << endl;
- sub_iterations=new double[TrimAxes.size()];
- successful=new double[TrimAxes.size()];
- solution=new bool[TrimAxes.size()];
- current_axis=0;
-}
-//YOU WERE WARNED, BUT YOU DID IT ANYWAY.
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGTrim.h
- Author: Tony Peden
- Date started: 7/1/99
-
- ------------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-
- HISTORY
---------------------------------------------------------------------------------
-9/8/99 TP Created
-
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-This class takes the given set of IC's and finds the aircraft state required to
-maintain a specified flight condition. This flight condition can be
-steady-level with non-zero sideslip, a steady turn, a pull-up or pushover.
-On-ground conditions can be trimmed as well, but this is currently limited to
-adjusting altitude and pitch angle only. It is implemented using an iterative,
-one-axis-at-a-time scheme.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGTRIM_H
-#define FGTRIM_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGFDMExec.h"
-#include "FGJSBBase.h"
-#include "FGTrimAxis.h"
-
-#include <vector>
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_TRIM "$Id$"
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
- #define snprintf _snprintf
-#endif
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-typedef enum { tLongitudinal, tFull, tGround, tPullup,
- tCustom, tNone, tTurn
- } TrimMode;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** FGTrim -- the trimming routine for JSBSim.
- FGTrim finds the aircraft attitude and control settings needed to maintain
- the steady state described by the FGInitialCondition object . It does this
- iteratively by assigning a control to each state and adjusting that control
- until the state is within a specified tolerance of zero. States include the
- recti-linear accelerations udot, vdot, and wdot, the angular accelerations
- qdot, pdot, and rdot, and the difference between heading and ground track.
- Controls include the usual flight deck controls available to the pilot plus
- angle of attack (alpha), sideslip angle(beta), flight path angle (gamma),
- pitch attitude(theta), roll attitude(phi), and altitude above ground. The
- last three are used for on-ground trimming. The state-control pairs used in
- a given trim are completely user configurable and several pre-defined modes
- are provided as well. They are:
- - tLongitudinal: Trim wdot with alpha, udot with thrust, qdot with elevator
- - tFull: tLongitudinal + vdot with phi, pdot with aileron, rdot with rudder
- and heading minus ground track (hmgt) with beta
- - tPullup: tLongitudinal but adjust alpha to achieve load factor input
- with SetTargetNlf()
- - tGround: wdot with altitude, qdot with theta, and pdot with phi
-
- The remaining modes include <b>tCustom</b>, which is completely user defined and
- <b>tNone</b>.
-
- Note that trims can (and do) fail for reasons that are completely outside
- the control of the trimming routine itself. The most common problem is the
- initial conditions: is the model capable of steady state flight
- at those conditions? Check the speed, altitude, configuration (flaps,
- gear, etc.), weight, cg, and anything else that may be relevant.
-
- Example usage:<pre>
- FGFDMExec* FDMExec = new FGFDMExec();
-
- FGInitialCondition* fgic = new FGInitialCondition(FDMExec);
- FGTrim fgt(FDMExec, fgic, tFull);
- fgic->SetVcaibratedKtsIC(100);
- fgic->SetAltitudeFtIC(1000);
- fgic->SetClimbRate(500);
- if( !fgt.DoTrim() ) {
- cout << "Trim Failed" << endl;
- }
- fgt.Report(); </pre>
- @author Tony Peden
- @version "$Id$"
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGTrim : public FGJSBBase
-{
-private:
-
- vector<FGTrimAxis*> TrimAxes;
- unsigned int current_axis;
- int N, Nsub;
- TrimMode mode;
- int DebugLevel, Debug;
- double Tolerance, A_Tolerance;
- double wdot,udot,qdot;
- double dth;
- double *sub_iterations;
- double *successful;
- bool *solution;
- int max_sub_iterations;
- int max_iterations;
- int total_its;
- bool trimudot;
- bool gamma_fallback;
- bool trim_failed;
- unsigned int axis_count;
- int solutionDomain;
- double xlo,xhi,alo,ahi;
- double targetNlf;
- int debug_axis;
-
- double psidot,thetadot;
-
- FGFDMExec* fdmex;
- FGInitialCondition* fgic;
-
- bool solve(void);
-
- /** @return false if there is no change in the current axis accel
- between accel(control_min) and accel(control_max). If there is a
- change, sets solutionDomain to:
- 0 for no sign change,
- -1 if sign change between accel(control_min) and accel(0)
- 1 if sign between accel(0) and accel(control_max)
- */
- bool findInterval(void);
-
- bool checkLimits(void);
-
- void setupPullup(void);
- void setupTurn(void);
-
- void updateRates(void);
-
- void setDebug(void);
-
-public:
- /** Initializes the trimming class
- @param FDMExec pointer to a JSBSim executive object.
- @param tm trim mode
- */
- FGTrim(FGFDMExec *FDMExec, TrimMode tm=tGround );
-
- ~FGTrim(void);
-
- /** Execute the trim
- */
- bool DoTrim(void);
-
- /** Print the results of the trim. For each axis trimmed, this
- includes the final state value, control value, and tolerance
- used.
- @return true if trim succeeds
- */
- void Report(void);
-
- /** Iteration statistics
- */
- void TrimStats();
-
- /** Clear all state-control pairs and set a predefined trim mode
- @param tm the set of axes to trim. Can be:
- tLongitudinal, tFull, tGround, tCustom, or tNone
- */
- void SetMode(TrimMode tm);
-
- /** Clear all state-control pairs from the current configuration.
- The trimming routine must have at least one state-control pair
- configured to be useful
- */
- void ClearStates(void);
-
- /** Add a state-control pair to the current configuration. See the enums
- State and Control in FGTrimAxis.h for the available options.
- Will fail if the given state is already configured.
- @param state the accel or other condition to zero
- @param control the control used to zero the state
- @return true if add is successful
- */
- bool AddState( State state, Control control );
-
- /** Remove a specific state-control pair from the current configuration
- @param state the state to remove
- @return true if removal is successful
- */
- bool RemoveState( State state );
-
- /** Change the control used to zero a state previously configured
- @param state the accel or other condition to zero
- @param new_control the control used to zero the state
- */
- bool EditState( State state, Control new_control );
-
- /** automatically switch to trimming longitudinal acceleration with
- flight path angle (gamma) once it becomes apparent that there
- is not enough/too much thrust.
- @param bb true to enable fallback
- */
- inline void SetGammaFallback(bool bb) { gamma_fallback=bb; }
-
- /** query the fallback state
- @return true if fallback is enabled.
- */
- inline bool GetGammaFallback(void) { return gamma_fallback; }
-
- /** Set the iteration limit. DoTrim() will return false if limit
- iterations are reached before trim is achieved. The default
- is 60. This does not ordinarily need to be changed.
- @param ii integer iteration limit
- */
- inline void SetMaxCycles(int ii) { max_iterations = ii; }
-
- /** Set the per-axis iteration limit. Attempt to zero each state
- by iterating limit times before moving on to the next. The
- default limit is 100 and also does not ordinarily need to
- be changed.
- @param ii integer iteration limit
- */
- inline void SetMaxCyclesPerAxis(int ii) { max_sub_iterations = ii; }
-
- /** Set the tolerance for declaring a state trimmed. Angular accels are
- held to a tolerance of 1/10th of the given. The default is
- 0.001 for the recti-linear accelerations and 0.0001 for the angular.
- */
- inline void SetTolerance(double tt) {
- Tolerance = tt;
- A_Tolerance = tt / 10;
- }
-
- /**
- Debug level 1 shows results of each top-level iteration
- Debug level 2 shows level 1 & results of each per-axis iteration
- */
- inline void SetDebug(int level) { DebugLevel = level; }
- inline void ClearDebug(void) { DebugLevel = 0; }
-
- /**
- Output debug data for one of the axes
- The State enum is defined in FGTrimAxis.h
- */
- inline void DebugState(State state) { debug_axis=state; }
-
- inline void SetTargetNlf(double nlf) { targetNlf=nlf; }
- inline double GetTargetNlf(void) { return targetNlf; }
-
-};
-}
-
-#endif
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGTrimAxis.cpp
- Author: Tony Peden
- Date started: 7/3/00
-
- --------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) ---------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-
- HISTORY
---------------------------------------------------------------------------------
-7/3/00 TP Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef _MSC_VER
-# pragma warning (disable : 4786)
-#endif
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <string>
-#include <stdlib.h>
-
-#include "FGFDMExec.h"
-#include "FGAtmosphere.h"
-#include "FGInitialCondition.h"
-#include "FGTrimAxis.h"
-#include "FGAircraft.h"
-#include "FGPropulsion.h"
-#include "FGAerodynamics.h"
-
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_TRIMAXIS;
-
-/*****************************************************************************/
-
-FGTrimAxis::FGTrimAxis(FGFDMExec* fdex, FGInitialCondition* ic, State st,
- Control ctrl) {
-
- fdmex=fdex;
- fgic=ic;
- state=st;
- control=ctrl;
- max_iterations=10;
- control_value=0;
- its_to_stable_value=0;
- total_iterations=0;
- total_stability_iterations=0;
- state_convert=1.0;
- control_convert=1.0;
- state_value=0;
- state_target=0;
- switch(state) {
- case tUdot: tolerance = DEFAULT_TOLERANCE; break;
- case tVdot: tolerance = DEFAULT_TOLERANCE; break;
- case tWdot: tolerance = DEFAULT_TOLERANCE; break;
- case tQdot: tolerance = DEFAULT_TOLERANCE / 10; break;
- case tPdot: tolerance = DEFAULT_TOLERANCE / 10; break;
- case tRdot: tolerance = DEFAULT_TOLERANCE / 10; break;
- case tHmgt: tolerance = 0.01; break;
- case tNlf: state_target=1.0; tolerance = 1E-5; break;
- case tAll: break;
- }
-
- solver_eps=tolerance;
- switch(control) {
- case tThrottle:
- control_min=0;
- control_max=1;
- control_value=0.5;
- break;
- case tBeta:
- control_min=-30*degtorad;
- control_max=30*degtorad;
- control_convert=radtodeg;
- break;
- case tAlpha:
- control_min=fdmex->GetAerodynamics()->GetAlphaCLMin();
- control_max=fdmex->GetAerodynamics()->GetAlphaCLMax();
- if(control_max <= control_min) {
- control_max=20*degtorad;
- control_min=-5*degtorad;
- }
- control_value= (control_min+control_max)/2;
- control_convert=radtodeg;
- solver_eps=tolerance/100;
- break;
- case tPitchTrim:
- case tElevator:
- case tRollTrim:
- case tAileron:
- case tYawTrim:
- case tRudder:
- control_min=-1;
- control_max=1;
- state_convert=radtodeg;
- solver_eps=tolerance/100;
- break;
- case tAltAGL:
- control_min=0;
- control_max=30;
- control_value=fdmex->GetPropagate()->GetDistanceAGL();
- solver_eps=tolerance/100;
- break;
- case tTheta:
- control_min=fdmex->GetPropagate()->GetEuler(eTht) - 5*degtorad;
- control_max=fdmex->GetPropagate()->GetEuler(eTht) + 5*degtorad;
- state_convert=radtodeg;
- break;
- case tPhi:
- control_min=fdmex->GetPropagate()->GetEuler(ePhi) - 30*degtorad;
- control_max=fdmex->GetPropagate()->GetEuler(ePhi) + 30*degtorad;
- state_convert=radtodeg;
- control_convert=radtodeg;
- break;
- case tGamma:
- solver_eps=tolerance/100;
- control_min=-80*degtorad;
- control_max=80*degtorad;
- control_convert=radtodeg;
- break;
- case tHeading:
- control_min=fdmex->GetPropagate()->GetEuler(ePsi) - 30*degtorad;
- control_max=fdmex->GetPropagate()->GetEuler(ePsi) + 30*degtorad;
- state_convert=radtodeg;
- break;
- }
-
-
- Debug(0);
-}
-
-/*****************************************************************************/
-
-FGTrimAxis::~FGTrimAxis(void)
-{
- Debug(1);
-}
-
-/*****************************************************************************/
-
-void FGTrimAxis::getState(void) {
- switch(state) {
- case tUdot: state_value=fdmex->GetPropagate()->GetUVWdot(1)-state_target; break;
- case tVdot: state_value=fdmex->GetPropagate()->GetUVWdot(2)-state_target; break;
- case tWdot: state_value=fdmex->GetPropagate()->GetUVWdot(3)-state_target; break;
- case tQdot: state_value=fdmex->GetPropagate()->GetPQRdot(2)-state_target;break;
- case tPdot: state_value=fdmex->GetPropagate()->GetPQRdot(1)-state_target; break;
- case tRdot: state_value=fdmex->GetPropagate()->GetPQRdot(3)-state_target; break;
- case tHmgt: state_value=computeHmgt()-state_target; break;
- case tNlf: state_value=fdmex->GetAircraft()->GetNlf()-state_target; break;
- case tAll: break;
- }
-}
-
-/*****************************************************************************/
-
-//States are not settable
-
-void FGTrimAxis::getControl(void) {
- switch(control) {
- case tThrottle: control_value=fdmex->GetFCS()->GetThrottleCmd(0); break;
- case tBeta: control_value=fdmex->GetAuxiliary()->Getalpha(); break;
- case tAlpha: control_value=fdmex->GetAuxiliary()->Getbeta(); break;
- case tPitchTrim: control_value=fdmex->GetFCS() -> GetPitchTrimCmd(); break;
- case tElevator: control_value=fdmex->GetFCS() -> GetDeCmd(); break;
- case tRollTrim:
- case tAileron: control_value=fdmex->GetFCS() -> GetDaCmd(); break;
- case tYawTrim:
- case tRudder: control_value=fdmex->GetFCS() -> GetDrCmd(); break;
- case tAltAGL: control_value=fdmex->GetPropagate()->GetDistanceAGL();break;
- case tTheta: control_value=fdmex->GetPropagate()->GetEuler(eTht); break;
- case tPhi: control_value=fdmex->GetPropagate()->GetEuler(ePhi); break;
- case tGamma: control_value=fdmex->GetAuxiliary()->GetGamma();break;
- case tHeading: control_value=fdmex->GetPropagate()->GetEuler(ePsi); break;
- }
-}
-
-/*****************************************************************************/
-
-double FGTrimAxis::computeHmgt(void) {
- double diff;
-
- diff = fdmex->GetPropagate()->GetEuler(ePsi) -
- fdmex->GetAuxiliary()->GetGroundTrack();
-
- if( diff < -M_PI ) {
- return (diff + 2*M_PI);
- } else if( diff > M_PI ) {
- return (diff - 2*M_PI);
- } else {
- return diff;
- }
-
-}
-
-/*****************************************************************************/
-
-
-void FGTrimAxis::setControl(void) {
- switch(control) {
- case tThrottle: setThrottlesPct(); break;
- case tBeta: fgic->SetBetaRadIC(control_value); break;
- case tAlpha: fgic->SetAlphaRadIC(control_value); break;
- case tPitchTrim: fdmex->GetFCS()->SetPitchTrimCmd(control_value); break;
- case tElevator: fdmex->GetFCS()->SetDeCmd(control_value); break;
- case tRollTrim:
- case tAileron: fdmex->GetFCS()->SetDaCmd(control_value); break;
- case tYawTrim:
- case tRudder: fdmex->GetFCS()->SetDrCmd(control_value); break;
- case tAltAGL: fgic->SetAltitudeAGLFtIC(control_value); break;
- case tTheta: fgic->SetPitchAngleRadIC(control_value); break;
- case tPhi: fgic->SetRollAngleRadIC(control_value); break;
- case tGamma: fgic->SetFlightPathAngleRadIC(control_value); break;
- case tHeading: fgic->SetTrueHeadingRadIC(control_value); break;
- }
-}
-
-
-
-
-
-/*****************************************************************************/
-
-// the aircraft center of rotation is no longer the cg once the gear
-// contact the ground so the altitude needs to be changed when pitch
-// and roll angle are adjusted. Instead of attempting to calculate the
-// new center of rotation, pick a gear unit as a reference and use its
-// location vector to calculate the new height change. i.e. new altitude =
-// earth z component of that vector (which is in body axes )
-void FGTrimAxis::SetThetaOnGround(double ff) {
- int center,i,ref;
-
- // favor an off-center unit so that the same one can be used for both
- // pitch and roll. An on-center unit is used (for pitch)if that's all
- // that's in contact with the ground.
- i=0; ref=-1; center=-1;
- while( (ref < 0) && (i < fdmex->GetGroundReactions()->GetNumGearUnits()) ) {
- if(fdmex->GetGroundReactions()->GetGearUnit(i)->GetWOW()) {
- if(fabs(fdmex->GetGroundReactions()->GetGearUnit(i)->GetBodyLocation(2)) > 0.01)
- ref=i;
- else
- center=i;
- }
- i++;
- }
- if((ref < 0) && (center >= 0)) {
- ref=center;
- }
- cout << "SetThetaOnGround ref gear: " << ref << endl;
- if(ref >= 0) {
- double sp = fdmex->GetPropagate()->GetSinEuler(ePhi);
- double cp = fdmex->GetPropagate()->GetCosEuler(ePhi);
- double lx = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(1);
- double ly = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(2);
- double lz = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(3);
- double hagl = -1*lx*sin(ff) +
- ly*sp*cos(ff) +
- lz*cp*cos(ff);
-
- fgic->SetAltitudeAGLFtIC(hagl);
- cout << "SetThetaOnGround new alt: " << hagl << endl;
- }
- fgic->SetPitchAngleRadIC(ff);
- cout << "SetThetaOnGround new theta: " << ff << endl;
-}
-
-/*****************************************************************************/
-
-bool FGTrimAxis::initTheta(void) {
- int i,N;
- int iForward = 0;
- int iAft = 1;
- double zAft,zForward,zDiff,theta;
- double xAft,xForward,xDiff;
- bool level;
- double saveAlt;
-
- saveAlt=fgic->GetAltitudeAGLFtIC();
- fgic->SetAltitudeAGLFtIC(100);
-
-
- N=fdmex->GetGroundReactions()->GetNumGearUnits();
-
- //find the first wheel unit forward of the cg
- //the list is short so a simple linear search is fine
- for( i=0; i<N; i++ ) {
- if(fdmex->GetGroundReactions()->GetGearUnit(i)->GetBodyLocation(1) > 0 ) {
- iForward=i;
- break;
- }
- }
- //now find the first wheel unit aft of the cg
- for( i=0; i<N; i++ ) {
- if(fdmex->GetGroundReactions()->GetGearUnit(i)->GetBodyLocation(1) < 0 ) {
- iAft=i;
- break;
- }
- }
-
- // now adjust theta till the wheels are the same distance from the ground
- xAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetBodyLocation(1);
- xForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetBodyLocation(1);
- xDiff = xForward - xAft;
- zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
- zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
- zDiff = zForward - zAft;
- level=false;
- theta=fgic->GetPitchAngleDegIC();
- while(!level && (i < 100)) {
- theta+=radtodeg*atan(zDiff/xDiff);
- fgic->SetPitchAngleDegIC(theta);
- fdmex->RunIC();
- zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
- zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
- zDiff = zForward - zAft;
- //cout << endl << theta << " " << zDiff << endl;
- //cout << "0: " << fdmex->GetGroundReactions()->GetGearUnit(0)->GetLocalGear() << endl;
- //cout << "1: " << fdmex->GetGroundReactions()->GetGearUnit(1)->GetLocalGear() << endl;
- if(fabs(zDiff ) < 0.1)
- level=true;
- i++;
- }
- //cout << i << endl;
- if (debug_lvl > 0) {
- cout << " Initial Theta: " << fdmex->GetPropagate()->GetEuler(eTht)*radtodeg << endl;
- cout << " Used gear unit " << iAft << " as aft and " << iForward << " as forward" << endl;
- }
- control_min=(theta+5)*degtorad;
- control_max=(theta-5)*degtorad;
- fgic->SetAltitudeAGLFtIC(saveAlt);
- if(i < 100)
- return true;
- else
- return false;
-}
-
-/*****************************************************************************/
-
-void FGTrimAxis::SetPhiOnGround(double ff) {
- int i,ref;
-
- i=0; ref=-1;
- //must have an off-center unit here
- while ( (ref < 0) && (i < fdmex->GetGroundReactions()->GetNumGearUnits()) ) {
- if ( (fdmex->GetGroundReactions()->GetGearUnit(i)->GetWOW()) &&
- (fabs(fdmex->GetGroundReactions()->GetGearUnit(i)->GetBodyLocation(2)) > 0.01))
- ref=i;
- i++;
- }
- if (ref >= 0) {
- double st = fdmex->GetPropagate()->GetSinEuler(eTht);
- double ct = fdmex->GetPropagate()->GetCosEuler(eTht);
- double lx = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(1);
- double ly = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(2);
- double lz = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(3);
- double hagl = -1*lx*st +
- ly*sin(ff)*ct +
- lz*cos(ff)*ct;
-
- fgic->SetAltitudeAGLFtIC(hagl);
- }
- fgic->SetRollAngleRadIC(ff);
-
-}
-
-/*****************************************************************************/
-
-void FGTrimAxis::Run(void) {
-
- double last_state_value;
- int i;
- setControl();
- //cout << "FGTrimAxis::Run: " << control_value << endl;
- i=0;
- bool stable=false;
- while(!stable) {
- i++;
- last_state_value=state_value;
- fdmex->RunIC();
- getState();
- if(i > 1) {
- if((fabs(last_state_value - state_value) < tolerance) || (i >= 100) )
- stable=true;
- }
- }
-
- its_to_stable_value=i;
- total_stability_iterations+=its_to_stable_value;
- total_iterations++;
-}
-
-/*****************************************************************************/
-
-void FGTrimAxis::setThrottlesPct(void) {
- double tMin,tMax;
- for(unsigned i=0;i<fdmex->GetPropulsion()->GetNumEngines();i++) {
- tMin=fdmex->GetPropulsion()->GetEngine(i)->GetThrottleMin();
- tMax=fdmex->GetPropulsion()->GetEngine(i)->GetThrottleMax();
- //cout << "setThrottlespct: " << i << ", " << control_min << ", " << control_max << ", " << control_value;
- fdmex->GetFCS()->SetThrottleCmd(i,tMin+control_value*(tMax-tMin));
- //cout << "setThrottlespct: " << fdmex->GetFCS()->GetThrottleCmd(i) << endl;
- fdmex->RunIC(); //apply throttle change
- fdmex->GetPropulsion()->GetSteadyState();
- }
-}
-
-/*****************************************************************************/
-
-void FGTrimAxis::AxisReport(void) {
-
- char out[80];
-
- sprintf(out," %20s: %6.2f %5s: %9.2e Tolerance: %3.0e",
- GetControlName().c_str(), GetControl()*control_convert,
- GetStateName().c_str(), GetState()+state_target, GetTolerance());
- cout << out;
-
- if( fabs(GetState()+state_target) < fabs(GetTolerance()) )
- cout << " Passed" << endl;
- else
- cout << " Failed" << endl;
-}
-
-/*****************************************************************************/
-
-double FGTrimAxis::GetAvgStability( void ) {
- if(total_iterations > 0) {
- return double(total_stability_iterations)/double(total_iterations);
- }
- return 0;
-}
-
-/*****************************************************************************/
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGTrimAxis::Debug(int from)
-{
-
- if (debug_lvl <= 0) return;
- if (debug_lvl & 1 ) { // Standard console startup message output
- if (from == 0) { // Constructor
-
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGTrimAxis" << endl;
- if (from == 1) cout << "Destroyed: FGTrimAxis" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGTrimAxis.h
- Author: Tony Peden
- Date started: 7/3/00
-
- ------------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
- HISTORY
---------------------------------------------------------------------------------
-7/3/00 TP Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGTRIMAXIS_H
-#define FGTRIMAXIS_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include <string>
-
-#include "FGFDMExec.h"
-#include "FGJSBBase.h"
-#include "FGInitialCondition.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_TRIMAXIS "$Id$"
-
-#define DEFAULT_TOLERANCE 0.001
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-const string StateNames[10]= { "all","udot","vdot","wdot","qdot","pdot","rdot",
- "hmgt","nlf"
- };
-const string ControlNames[14]= { "Throttle","Sideslip","Angle of Attack",
- "Elevator","Ailerons","Rudder",
- "Altitude AGL", "Pitch Angle",
- "Roll Angle", "Flight Path Angle",
- "Pitch Trim", "Roll Trim", "Yaw Trim",
- "Heading"
- };
-
-class FGInitialCondition;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Models an aircraft axis for purposes of trimming.
- */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-enum State { tAll,tUdot,tVdot,tWdot,tQdot,tPdot,tRdot,tHmgt,tNlf };
-enum Control { tThrottle, tBeta, tAlpha, tElevator, tAileron, tRudder, tAltAGL,
- tTheta, tPhi, tGamma, tPitchTrim, tRollTrim, tYawTrim, tHeading };
-
-class FGTrimAxis : public FGJSBBase
-{
-public:
- FGTrimAxis(FGFDMExec* fdmex,
- FGInitialCondition *ic,
- State st,
- Control ctrl );
- ~FGTrimAxis();
-
- void Run(void);
-
- double GetState(void) { getState(); return state_value; }
- //Accels are not settable
- inline void SetControl(double value ) { control_value=value; }
- inline double GetControl(void) { return control_value; }
-
- inline State GetStateType(void) { return state; }
- inline Control GetControlType(void) { return control; }
-
- inline string GetStateName(void) { return StateNames[state]; }
- inline string GetControlName(void) { return ControlNames[control]; }
-
- inline double GetControlMin(void) { return control_min; }
- inline double GetControlMax(void) { return control_max; }
-
- inline void SetControlToMin(void) { control_value=control_min; }
- inline void SetControlToMax(void) { control_value=control_max; }
-
- inline void SetControlLimits(double min, double max) {
- control_min=min;
- control_max=max;
- }
-
- inline void SetTolerance(double ff) { tolerance=ff;}
- inline double GetTolerance(void) { return tolerance; }
-
- inline double GetSolverEps(void) { return solver_eps; }
- inline void SetSolverEps(double ff) { solver_eps=ff; }
-
- inline int GetIterationLimit(void) { return max_iterations; }
- inline void SetIterationLimit(int ii) { max_iterations=ii; }
-
- inline int GetStability(void) { return its_to_stable_value; }
- inline int GetRunCount(void) { return total_stability_iterations; }
- double GetAvgStability( void );
-
- void SetThetaOnGround(double ff);
- void SetPhiOnGround(double ff);
-
- inline void SetStateTarget(double target) { state_target=target; }
- inline double GetStateTarget(void) { return state_target; }
-
- bool initTheta(void);
-
- void AxisReport(void);
-
- bool InTolerance(void) { getState(); return (fabs(state_value) <= tolerance); }
-
-private:
- FGFDMExec *fdmex;
- FGInitialCondition *fgic;
-
- State state;
- Control control;
-
- double state_target;
-
- double state_value;
- double control_value;
-
- double control_min;
- double control_max;
-
- double tolerance;
-
- double solver_eps;
-
- double state_convert;
- double control_convert;
-
- int max_iterations;
-
- int its_to_stable_value;
- int total_stability_iterations;
- int total_iterations;
-
- void setThrottlesPct(void);
-
- void getState(void);
- void getControl(void);
- void setControl(void);
-
- double computeHmgt(void);
-
- void Debug(int from);
-};
-}
-#endif
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGTurbine.cpp
- Author: David Culp
- Date started: 03/11/2003
- Purpose: This module models a turbine engine.
-
- ------------- Copyright (C) 2003 David Culp (davidculp2@comcast.net) ---------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-This class descends from the FGEngine class and models a turbine engine based
-on parameters given in the engine config file for this class
-
-HISTORY
---------------------------------------------------------------------------------
-03/11/2003 DPC Created
-09/08/2003 DPC Changed Calculate() and added engine phases
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <vector>
-#include <sstream>
-
-#include "FGTurbine.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_TURBINE;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-
-FGTurbine::FGTurbine(FGFDMExec* exec, FGConfigFile* cfg, int engine_number)
- : FGEngine(exec, engine_number)
-{
- SetDefaults();
-
- Load(cfg);
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGTurbine::~FGTurbine()
-{
- unbind();
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The main purpose of Calculate() is to determine what phase the engine should
-// be in, then call the corresponding function.
-
-double FGTurbine::Calculate(void)
-{
- TAT = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556;
- dt = State->Getdt() * Propulsion->GetRate();
- ThrottlePos = FCS->GetThrottlePos(EngineNumber);
- if (ThrottlePos > 1.0) {
- AugmentCmd = ThrottlePos - 1.0;
- ThrottlePos -= AugmentCmd;
- } else {
- AugmentCmd = 0.0;
- }
-
- // When trimming is finished check if user wants engine OFF or RUNNING
- if ((phase == tpTrim) && (dt > 0)) {
- if (Running && !Starved) {
- phase = tpRun;
- N2 = IdleN2 + ThrottlePos * N2_factor;
- N1 = IdleN1 + ThrottlePos * N1_factor;
- OilTemp_degK = 366.0;
- Cutoff = false;
- }
- else {
- phase = tpOff;
- Cutoff = true;
- EGT_degC = TAT;
- }
- }
-
- if (!Running && Cutoff && Starter) {
- if (phase == tpOff) phase = tpSpinUp;
- }
- if (!Running && !Cutoff && (N2 > 15.0)) phase = tpStart;
- if (Cutoff && (phase != tpSpinUp)) phase = tpOff;
- if (dt == 0) phase = tpTrim;
- if (Starved) phase = tpOff;
- if (Stalled) phase = tpStall;
- if (Seized) phase = tpSeize;
-
- switch (phase) {
- case tpOff: Thrust = Off(); break;
- case tpRun: Thrust = Run(); break;
- case tpSpinUp: Thrust = SpinUp(); break;
- case tpStart: Thrust = Start(); break;
- case tpStall: Thrust = Stall(); break;
- case tpSeize: Thrust = Seize(); break;
- case tpTrim: Thrust = Trim(); break;
- default: Thrust = Off();
- }
-
- // The thruster can modify the thrust, eg. thrust reverser
- return Thrust = Thruster->Calculate(Thrust);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGTurbine::Off(void)
-{
- double qbar = Auxiliary->Getqbar();
- Running = false;
- FuelFlow_pph = Seek(&FuelFlow_pph, 0, 1000.0, 10000.0);
- N1 = Seek(&N1, qbar/10.0, N1/2.0, N1/2.0);
- N2 = Seek(&N2, qbar/15.0, N2/2.0, N2/2.0);
- EGT_degC = Seek(&EGT_degC, TAT, 11.7, 7.3);
- OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0.2, 0.2);
- OilPressure_psi = N2 * 0.62;
- NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
- EPR = Seek(&EPR, 1.0, 0.2, 0.2);
- Augmentation = false;
- return 0.0;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGTurbine::Run(void)
-{
- double idlethrust, milthrust, thrust;
- double N2norm; // 0.0 = idle N2, 1.0 = maximum N2
- idlethrust = MilThrust * ThrustTables[0]->TotalValue();
- milthrust = (MilThrust - idlethrust) * ThrustTables[1]->TotalValue();
-
- Running = true;
- Starter = false;
-
- N2 = Seek(&N2, IdleN2 + ThrottlePos * N2_factor, delay, delay * 3.0);
- N1 = Seek(&N1, IdleN1 + ThrottlePos * N1_factor, delay, delay * 2.4);
- N2norm = (N2 - IdleN2) / N2_factor;
- thrust = idlethrust + (milthrust * N2norm * N2norm);
- EGT_degC = TAT + 363.1 + ThrottlePos * 357.1;
- OilPressure_psi = N2 * 0.62;
- OilTemp_degK = Seek(&OilTemp_degK, 366.0, 1.2, 0.1);
-
- if (!Augmentation) {
- double correctedTSFC = TSFC * (0.84 + (1-N2norm)*(1-N2norm));
- FuelFlow_pph = Seek(&FuelFlow_pph, thrust * correctedTSFC, 1000.0, 100000);
- if (FuelFlow_pph < IdleFF) FuelFlow_pph = IdleFF;
- NozzlePosition = Seek(&NozzlePosition, 1.0 - N2norm, 0.8, 0.8);
- thrust = thrust * (1.0 - BleedDemand);
- EPR = 1.0 + thrust/MilThrust;
- }
-
- if (AugMethod == 1) {
- if ((ThrottlePos > 0.99) && (N2 > 97.0)) {Augmentation = true;}
- else {Augmentation = false;}
- }
-
- if ((Augmented == 1) && Augmentation && (AugMethod < 2)) {
- thrust = MaxThrust * ThrustTables[2]->TotalValue();
- FuelFlow_pph = Seek(&FuelFlow_pph, thrust * ATSFC, 5000.0, 10000.0);
- NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
- }
-
- if (AugMethod == 2) {
- if (AugmentCmd > 0.0) {
- Augmentation = true;
- double tdiff = (MaxThrust * ThrustTables[2]->TotalValue()) - thrust;
- thrust += (tdiff * AugmentCmd);
- FuelFlow_pph = Seek(&FuelFlow_pph, thrust * ATSFC, 5000.0, 10000.0);
- NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
- } else {
- Augmentation = false;
- }
- }
-
- if ((Injected == 1) && Injection) {
- thrust = thrust * ThrustTables[3]->TotalValue();
- }
-
- ConsumeFuel();
- if (Cutoff) phase = tpOff;
- if (Starved) phase = tpOff;
-
- return thrust;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGTurbine::SpinUp(void)
-{
- Running = false;
- FuelFlow_pph = 0.0;
- N2 = Seek(&N2, 25.18, 3.0, N2/2.0);
- N1 = Seek(&N1, 5.21, 1.0, N1/2.0);
- EGT_degC = Seek(&EGT_degC, TAT, 11.7, 7.3);
- OilPressure_psi = N2 * 0.62;
- OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0.2, 0.2);
- EPR = 1.0;
- NozzlePosition = 1.0;
- return 0.0;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGTurbine::Start(void)
-{
- if ((N2 > 15.0) && !Starved) { // minimum 15% N2 needed for start
- Cranking = true; // provided for sound effects signal
- if (N2 < IdleN2) {
- N2 = Seek(&N2, IdleN2, 2.0, N2/2.0);
- N1 = Seek(&N1, IdleN1, 1.4, N1/2.0);
- EGT_degC = Seek(&EGT_degC, TAT + 363.1, 21.3, 7.3);
- FuelFlow_pph = Seek(&FuelFlow_pph, IdleFF, 103.7, 103.7);
- OilPressure_psi = N2 * 0.62;
- ConsumeFuel();
- }
- else {
- phase = tpRun;
- Running = true;
- Starter = false;
- Cranking = false;
- }
- }
- else { // no start if N2 < 15%
- phase = tpOff;
- Starter = false;
- }
-
- return 0.0;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGTurbine::Stall(void)
-{
- double qbar = Auxiliary->Getqbar();
- EGT_degC = TAT + 903.14;
- FuelFlow_pph = IdleFF;
- N1 = Seek(&N1, qbar/10.0, 0, N1/10.0);
- N2 = Seek(&N2, qbar/15.0, 0, N2/10.0);
- ConsumeFuel();
- if (ThrottlePos < 0.01) phase = tpRun; // clear the stall with throttle
-
- return 0.0;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGTurbine::Seize(void)
-{
- double qbar = Auxiliary->Getqbar();
- N2 = 0.0;
- N1 = Seek(&N1, qbar/20.0, 0, N1/15.0);
- FuelFlow_pph = IdleFF;
- ConsumeFuel();
- OilPressure_psi = 0.0;
- OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0, 0.2);
- Running = false;
- return 0.0;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGTurbine::Trim(void)
-{
- double idlethrust, milthrust, thrust, tdiff;
- idlethrust = MilThrust * ThrustTables[0]->TotalValue();;
- milthrust = (MilThrust - idlethrust) * ThrustTables[1]->TotalValue();
- thrust = (idlethrust + (milthrust * ThrottlePos * ThrottlePos))
- * (1.0 - BleedDemand);
- if (AugmentCmd > 0.0) {
- tdiff = (MaxThrust * ThrustTables[2]->TotalValue()) - thrust;
- thrust += (tdiff * AugmentCmd);
- }
-
- return thrust;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGTurbine::CalcFuelNeed(void)
-{
- return FuelFlow_pph /3600 * State->Getdt() * Propulsion->GetRate();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGTurbine::GetPowerAvailable(void) {
- if( ThrottlePos <= 0.77 )
- return 64.94*ThrottlePos;
- else
- return 217.38*ThrottlePos - 117.38;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGTurbine::Seek(double *var, double target, double accel, double decel) {
- double v = *var;
- if (v > target) {
- v -= dt * decel;
- if (v < target) v = target;
- } else if (v < target) {
- v += dt * accel;
- if (v > target) v = target;
- }
- return v;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGTurbine::SetDefaults(void)
-{
- Name = "Not defined";
- N1 = N2 = 0.0;
- Type = etTurbine;
- MilThrust = 10000.0;
- MaxThrust = 10000.0;
- BypassRatio = 0.0;
- TSFC = 0.8;
- ATSFC = 1.7;
- IdleN1 = 30.0;
- IdleN2 = 60.0;
- MaxN1 = 100.0;
- MaxN2 = 100.0;
- Augmented = 0;
- AugMethod = 0;
- Injected = 0;
- BleedDemand = 0.0;
- ThrottlePos = 0.0;
- AugmentCmd = 0.0;
- InletPosition = 1.0;
- NozzlePosition = 1.0;
- Augmentation = false;
- Injection = false;
- Reversed = false;
- Cutoff = true;
- phase = tpOff;
- Stalled = false;
- Seized = false;
- Overtemp = false;
- Fire = false;
- EGT_degC = 0.0;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGTurbine::Load(FGConfigFile *Eng_cfg)
-{
- string token;
-
- Name = Eng_cfg->GetValue("NAME");
- Eng_cfg->GetNextConfigLine();
- int counter=0;
-
- while ( ((token = Eng_cfg->GetValue()) != string("/FG_TURBINE")) &&
- (token != string("/FG_SIMTURBINE")) ) {
- *Eng_cfg >> token;
-
- if (token[0] == '<') token.erase(0,1); // Tables are read "<TABLE"
-
- if (token == "MILTHRUST") *Eng_cfg >> MilThrust;
- else if (token == "MAXTHRUST") *Eng_cfg >> MaxThrust;
- else if (token == "BYPASSRATIO") *Eng_cfg >> BypassRatio;
- else if (token == "BLEED") *Eng_cfg >> BleedDemand;
- else if (token == "TSFC") *Eng_cfg >> TSFC;
- else if (token == "ATSFC") *Eng_cfg >> ATSFC;
- else if (token == "IDLEN1") *Eng_cfg >> IdleN1;
- else if (token == "IDLEN2") *Eng_cfg >> IdleN2;
- else if (token == "MAXN1") *Eng_cfg >> MaxN1;
- else if (token == "MAXN2") *Eng_cfg >> MaxN2;
- else if (token == "AUGMENTED") *Eng_cfg >> Augmented;
- else if (token == "AUGMETHOD") *Eng_cfg >> AugMethod;
- else if (token == "INJECTED") *Eng_cfg >> Injected;
- else if (token == "MINTHROTTLE") *Eng_cfg >> MinThrottle;
- else if (token == "TABLE") {
- if (counter++ == 0) Debug(2); // print engine specs prior to table read
- ThrustTables.push_back( new FGCoefficient(FDMExec) );
- ThrustTables.back()->Load(Eng_cfg);
- }
- else cerr << "Unhandled token in Engine config file: " << token << endl;
- if (token == "EOF") return false;
- }
-
- // Pre-calculations and initializations
-
- delay = 60.0 / (BypassRatio + 3.0);
- N1_factor = MaxN1 - IdleN1;
- N2_factor = MaxN2 - IdleN2;
- OilTemp_degK = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556 + 273.0;
- IdleFF = pow(MilThrust, 0.2) * 107.0; // just an estimate
-
- bindmodel();
- return true;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGTurbine::GetEngineLabels(string delimeter)
-{
- std::ostringstream buf;
-
- buf << Name << "_N1[" << EngineNumber << "]" << delimeter
- << Name << "_N2[" << EngineNumber << "]" << delimeter
- << Thruster->GetThrusterLabels(EngineNumber, delimeter);
-
- return buf.str();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGTurbine::GetEngineValues(string delimeter)
-{
- std::ostringstream buf;
-
- buf << N1 << delimeter
- << N2 << delimeter
- << Thruster->GetThrusterValues(EngineNumber, delimeter);
-
- return buf.str();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGTurbine::bindmodel()
-{
- char property_name[80];
-
- snprintf(property_name, 80, "propulsion/engine[%u]/n1", EngineNumber);
- PropertyManager->Tie( property_name, &N1);
- snprintf(property_name, 80, "propulsion/engine[%u]/n2", EngineNumber);
- PropertyManager->Tie( property_name, &N2);
- snprintf(property_name, 80, "propulsion/engine[%u]/fuel-flow", EngineNumber);
- PropertyManager->Tie( property_name, &FuelFlow_pph);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGTurbine::unbind()
-{
- char property_name[80];
-
- snprintf(property_name, 80, "propulsion/engine[%u]/n1", EngineNumber);
- PropertyManager->Untie(property_name);
- snprintf(property_name, 80, "propulsion/engine[%u]/n2", EngineNumber);
- PropertyManager->Untie(property_name);
- snprintf(property_name, 80, "propulsion/engine[%u]/fuel-flow", EngineNumber);
- PropertyManager->Untie( property_name);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGTurbine::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
-
- }
- if (from == 2) { // called from Load()
- cout << "\n Engine Name: " << Name << endl;
- cout << " MilThrust: " << MilThrust << endl;
- cout << " MaxThrust: " << MaxThrust << endl;
- cout << " BypassRatio: " << BypassRatio << endl;
- cout << " TSFC: " << TSFC << endl;
- cout << " ATSFC: " << ATSFC << endl;
- cout << " IdleN1: " << IdleN1 << endl;
- cout << " IdleN2: " << IdleN2 << endl;
- cout << " MaxN1: " << MaxN1 << endl;
- cout << " MaxN2: " << MaxN2 << endl;
- cout << " Augmented: " << Augmented << endl;
- cout << " AugMethod: " << AugMethod << endl;
- cout << " Injected: " << Injected << endl;
- cout << " MinThrottle: " << MinThrottle << endl;
-
- cout << endl;
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGTurbine" << endl;
- if (from == 1) cout << "Destroyed: FGTurbine" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGTurbine.h
- Author: David Culp
- Date started: 03/11/2003
-
- ------------- Copyright (C) 2003 David Culp (davidculp2@comcast.net)----------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-03/11/2003 DPC Created, based on FGTurbine
-09/22/2003 DPC Added starting, stopping, new framework
-04/29/2004 DPC Renamed from FGSimTurbine to FGTurbine
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGTURBINE_H
-#define FGTURBINE_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include <vector>
-#include "FGEngine.h"
-#include "FGConfigFile.h"
-#include "FGCoefficient.h"
-
-#define ID_TURBINE "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** This class models a turbine engine. Based on Jon Berndt's FGTurbine module.
- Here the term "phase" signifies the engine's mode of operation. At any given
- time the engine is in only one phase. At simulator startup the engine will be
- placed in the Trim phase in order to provide a simplified thrust value without
- throttle lag. When trimming is complete the engine will go to the Off phase,
- unless the value FGEngine::Running has been previously set to true, in which
- case the engine will go to the Run phase. Once an engine is in the Off phase
- the full starting procedure (or airstart) must be used to get it running.
-<P>
- - STARTING (on ground):
- -# Set the control FGEngine::Starter to true. The engine will spin up to
- a maximum of about %25 N2 (%5.2 N1). This simulates the action of a
- pneumatic starter.
- -# After reaching %15 N2 set the control FGEngine::Cutoff to false. If fuel
- is available the engine will now accelerate to idle. The starter will
- automatically be set to false after the start cycle.
-<P>
- - STARTING (in air):
- -# Increase speed to obtain a minimum of %15 N2. If this is not possible,
- the starter may be used to assist.
- -# Place the control FGEngine::Cutoff to false.
-<P>
- Ignition is assumed to be on anytime the Cutoff control is set to false,
- therefore a seperate ignition system is not modeled.
-
-Configuration File Format
-<pre>
-\<FG_TURBINE NAME="<name>">
- MILTHRUST \<thrust>
- MAXTHRUST \<thrust>
- BYPASSRATIO \<bypass ratio>
- TSFC \<thrust specific fuel consumption>
- ATSFC \<afterburning thrust specific fuel consumption>
- IDLEN1 \<idle N1>
- IDLEN2 \<idle N2>
- MAXN1 \<max N1>
- MAXN2 \<max N2>
- AUGMENTED \<0|1>
- AUGMETHOD \<0|1>
- INJECTED \<0|1>
- ...
-\</FG_TURBINE>
-</pre>
-Definition of the turbine engine configuration file parameters:
-<pre>
-<b>MILTHRUST</b> - Maximum thrust, static, at sea level, lbf.
-<b>MAXTHRUST</b> - Afterburning thrust, static, at sea level, lbf
-[this value will be ignored when AUGMENTED is zero (false)].
-<b>BYPASSRATIO</b> - Ratio of bypass air flow to core air flow.
-<b>TSFC</b> - Thrust-specific fuel consumption, lbm/hr/lbf
-[i.e. fuel flow divided by thrust].
-<b>ATSFC</b> - Afterburning TSFC, lbm/hr/lbf
-[this value will be ignored when AUGMENTED is zero (false)]
-<b>IDLEN1</b> - Fan rotor rpm (% of max) at idle
-<b>IDLEN2</b> - Core rotor rpm (% of max) at idle
-<b>MAXN1</b> - Fan rotor rpm (% of max) at full throttle [not always 100!]
-<b>MAXN2</b> - Core rotor rpm (% of max) at full throttle [not always 100!]
-<b>AUGMENTED</b>
- 0 == afterburner not installed
- 1 == afterburner installed
-<b>AUGMETHOD</b>
- 0 == afterburner activated by property /engines/engine[n]/augmentation
- 1 == afterburner activated by pushing throttle above 99% position
- 2 == throttle range is expanded in the FCS, and values above 1.0 are afterburner range
- [this item will be ignored when AUGMENTED == 0]
-<b>INJECTED</b>
- 0 == Water injection not installed
- 1 == Water injection installed
-</pre>
- @author David P. Culp
- @version "$Id$"
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGTurbine : public FGEngine
-{
-public:
- /** Constructor
- @param Executive pointer to executive structure
- @param Eng_cfg pointer to engine config file instance
- @param engine_number engine number*/
- FGTurbine(FGFDMExec* Executive, FGConfigFile* Eng_cfg, int engine_number);
- /// Destructor
- ~FGTurbine();
-
- enum phaseType { tpOff, tpRun, tpSpinUp, tpStart, tpStall, tpSeize, tpTrim };
-
- double Calculate(void);
- double CalcFuelNeed(void);
- double GetPowerAvailable(void);
- double Seek(double* var, double target, double accel, double decel);
-
- phaseType GetPhase(void) { return phase; }
-
- bool GetOvertemp(void) {return Overtemp; }
- bool GetInjection(void) {return Injection;}
- bool GetFire(void) { return Fire; }
- bool GetAugmentation(void) {return Augmentation;}
- bool GetReversed(void) { return Reversed; }
- bool GetCutoff(void) { return Cutoff; }
- int GetIgnition(void) {return Ignition;}
-
- double GetInlet(void) { return InletPosition; }
- double GetNozzle(void) { return NozzlePosition; }
- double GetBleedDemand(void) {return BleedDemand;}
- double GetN1(void) {return N1;}
- double GetN2(void) {return N2;}
- double GetEPR(void) {return EPR;}
- double GetEGT(void) {return EGT_degC;}
-
- double getOilPressure_psi () const {return OilPressure_psi;}
- double getOilTemp_degF (void) {return KelvinToFahrenheit(OilTemp_degK);}
-
- void SetInjection(bool injection) {Injection = injection;}
- void SetIgnition(int ignition) {Ignition = ignition;}
- void SetAugmentation(bool augmentation) {Augmentation = augmentation;}
- void SetPhase( phaseType p ) { phase = p; }
- void SetEPR(double epr) {EPR = epr;}
- void SetBleedDemand(double bleedDemand) {BleedDemand = bleedDemand;}
- void SetReverse(bool reversed) { Reversed = reversed; }
- void SetCutoff(bool cutoff) { Cutoff = cutoff; }
-
- string GetEngineLabels(string delimeter);
- string GetEngineValues(string delimeter);
-
-private:
-
- typedef vector<FGCoefficient*> CoeffArray;
- CoeffArray ThrustTables;
-
- phaseType phase; ///< Operating mode, or "phase"
- double MilThrust; ///< Maximum Unaugmented Thrust, static @ S.L. (lbf)
- double MaxThrust; ///< Maximum Augmented Thrust, static @ S.L. (lbf)
- double BypassRatio; ///< Bypass Ratio
- double TSFC; ///< Thrust Specific Fuel Consumption (lbm/hr/lbf)
- double ATSFC; ///< Augmented TSFC (lbm/hr/lbf)
- double IdleN1; ///< Idle N1
- double IdleN2; ///< Idle N2
- double N1; ///< N1
- double N2; ///< N2
- double MaxN1; ///< N1 at 100% throttle
- double MaxN2; ///< N2 at 100% throttle
- double IdleFF; ///< Idle Fuel Flow (lbm/hr)
- double delay; ///< Inverse spool-up time from idle to 100% (seconds)
- double dt; ///< Simulator time slice
- double N1_factor; ///< factor to tie N1 and throttle
- double N2_factor; ///< factor to tie N2 and throttle
- double ThrottlePos; ///< FCS-supplied throttle position
- double AugmentCmd; ///< modulated afterburner command (0.0 to 1.0)
- double TAT; ///< total air temperature (deg C)
- bool Stalled; ///< true if engine is compressor-stalled
- bool Seized; ///< true if inner spool is seized
- bool Overtemp; ///< true if EGT exceeds limits
- bool Fire; ///< true if engine fire detected
- bool Injection;
- bool Augmentation;
- bool Reversed;
- bool Cutoff;
- int Injected; ///< = 1 if water injection installed
- int Ignition;
- int Augmented; ///< = 1 if augmentation installed
- int AugMethod; ///< = 0 if using property /engine[n]/augmentation
- ///< = 1 if using last 1% of throttle movement
- ///< = 2 if using FCS-defined throttle
- double EGT_degC;
- double EPR;
- double OilPressure_psi;
- double OilTemp_degK;
- double BleedDemand;
- double InletPosition;
- double NozzlePosition;
-
- double Off(void);
- double Run();
- double SpinUp(void);
- double Start(void);
- double Stall(void);
- double Seize(void);
- double Trim();
-
- void SetDefaults(void);
- bool Load(FGConfigFile *ENG_cfg);
- void bindmodel(void);
- void unbind(void);
- void Debug(int from);
-
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
-
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGfdmSocket.cpp
- Author: Jon S. Berndt
- Date started: 11/08/99
- Purpose: Encapsulates a socket
- Called by: FGOutput, et. al.
-
- ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-This class excapsulates a socket for simple data writing
-
-HISTORY
---------------------------------------------------------------------------------
-11/08/99 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "FGfdmSocket.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_FDMSOCKET;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-FGfdmSocket::FGfdmSocket(string address, int port)
-{
- size = 0;
- connected = false;
-
- #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
- WSADATA wsaData;
- int wsaReturnCode;
- wsaReturnCode = WSAStartup(MAKEWORD(1,1), &wsaData);
- if (wsaReturnCode == 0) cout << "Winsock DLL loaded ..." << endl;
- else cout << "Winsock DLL not initialized ..." << endl;
- #endif
-
- if (address.find_first_not_of("0123456789.",0) != address.npos) {
- if ((host = gethostbyname(address.c_str())) == NULL) {
- cout << "Could not get host net address by name..." << endl;
- }
- } else {
- if ((host = gethostbyaddr(address.c_str(), address.size(), PF_INET)) == NULL) {
- cout << "Could not get host net address by number..." << endl;
- }
- }
-
- if (host != NULL) {
- cout << "Got host net address..." << endl;
- sckt = socket(AF_INET, SOCK_STREAM, 0);
-
- if (sckt >= 0) { // successful
- memset(&scktName, 0, sizeof(struct sockaddr_in));
- scktName.sin_family = AF_INET;
- scktName.sin_port = htons(port);
- memcpy(&scktName.sin_addr, host->h_addr_list[0], host->h_length);
- int len = sizeof(struct sockaddr_in);
- if (connect(sckt, (struct sockaddr*)&scktName, len) == 0) { // successful
- cout << "Successfully connected to socket ..." << endl;
- connected = true;
- } else { // unsuccessful
- cout << "Could not connect to socket ..." << endl;
- }
- } else { // unsuccessful
- cout << "Could not create socket for FDM, error = " << errno << endl;
- }
- }
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGfdmSocket::~FGfdmSocket()
-{
- #ifndef macintosh
- if (sckt) shutdown(sckt,2);
- #endif
-
- #ifdef __BORLANDC__
- WSACleanup();
- #endif
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGfdmSocket::Clear(void)
-{
- buffer = "";
- size = 0;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGfdmSocket::Append(const char* item)
-{
- if (size == 0) buffer += string(item);
- else buffer += string(",") + string(item);
- size++;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGfdmSocket::Append(double item)
-{
- char s[25];
-
- sprintf(s,"%12.7f",item);
-
- if (size == 0) buffer += string(s);
- else buffer += string(",") + string(s);
- size++;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGfdmSocket::Append(long item)
-{
- char s[25];
-
- sprintf(s,"%12ld",item);
-
- if (size == 0) buffer += string(s);
- else buffer += string(",") + string(s);
- size++;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGfdmSocket::Send(void)
-{
- buffer += string("\n");
- if ((send(sckt,buffer.c_str(),buffer.size(),0)) <= 0) {
- perror("send");
- } else {
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGfdmSocket::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGfdmSocket" << endl;
- if (from == 1) cout << "Destroyed: FGfdmSocket" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGfdmSocket.h
- Author: Jon S. Berndt
- Date started: 11/08/99
-
- ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-11/08/99 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGfdmSocket_H
-#define FGfdmSocket_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include <stdio.h>
-
-#ifdef FGFS
-# include <simgear/compiler.h>
-# include STL_STRING
-# include STL_IOSTREAM
-# include STL_FSTREAM
- SG_USING_STD(cout);
- SG_USING_STD(endl);
-#else
-# include <string>
-# if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
-# include <iostream.h>
-# include <fstream.h>
-# else
-# include <iostream>
-# include <fstream>
- using std::cout;
- using std::endl;
-# endif
-#endif
-
-#include <sys/types.h>
-#include "FGJSBBase.h"
-
-#if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
- #include <winsock.h>
-#else
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #include <errno.h>
-#endif
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_FDMSOCKET "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Encapsulates a socket object.
- */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-using std::string;
-
-class FGfdmSocket : public FGJSBBase
-{
-public:
- FGfdmSocket(string, int);
- ~FGfdmSocket();
- void Send(void);
- void Append(const char*);
- void Append(double);
- void Append(long);
- void Clear(void);
- bool GetConnectStatus(void) {return connected;}
-
-private:
- int sckt;
- int size;
- struct sockaddr_in scktName;
- struct hostent *host;
- string buffer;
- bool connected;
- void Debug(int from);
-};
-}
-#endif
#include <Main/globals.hxx>
#include <Main/fg_props.hxx>
+#include "JSBSim.hxx"
#include <FDM/JSBSim/FGFDMExec.h>
-#include <FDM/JSBSim/FGAircraft.h>
-#include <FDM/JSBSim/FGFCS.h>
-#include <FDM/JSBSim/FGPropagate.h>
+#include <FDM/JSBSim/FGJSBBase.h>
#include <FDM/JSBSim/FGState.h>
-#include <FDM/JSBSim/FGAuxiliary.h>
-#include <FDM/JSBSim/FGInitialCondition.h>
-#include <FDM/JSBSim/FGTrim.h>
-#include <FDM/JSBSim/FGAtmosphere.h>
-#include <FDM/JSBSim/FGMassBalance.h>
-#include <FDM/JSBSim/FGAerodynamics.h>
-#include <FDM/JSBSim/FGLGear.h>
-#include <FDM/JSBSim/FGPropertyManager.h>
-#include <FDM/JSBSim/FGEngine.h>
-#include <FDM/JSBSim/FGPiston.h>
-#include <FDM/JSBSim/FGGroundCallback.h>
-#include <FDM/JSBSim/FGTurbine.h>
-#include <FDM/JSBSim/FGRocket.h>
-#include <FDM/JSBSim/FGElectric.h>
-#include <FDM/JSBSim/FGNozzle.h>
-#include <FDM/JSBSim/FGPropeller.h>
-#include <FDM/JSBSim/FGRotor.h>
-#include <FDM/JSBSim/FGTank.h>
-#include "JSBSim.hxx"
+#include <FDM/JSBSim/initialization/FGInitialCondition.h>
+#include <FDM/JSBSim/initialization/FGTrim.h>
+#include <FDM/JSBSim/models/FGModel.h>
+#include <FDM/JSBSim/models/FGAircraft.h>
+#include <FDM/JSBSim/models/FGFCS.h>
+#include <FDM/JSBSim/models/FGPropagate.h>
+#include <FDM/JSBSim/models/FGAuxiliary.h>
+#include <FDM/JSBSim/models/FGAtmosphere.h>
+#include <FDM/JSBSim/models/FGMassBalance.h>
+#include <FDM/JSBSim/models/FGAerodynamics.h>
+#include <FDM/JSBSim/models/FGLGear.h>
+#include <FDM/JSBSim/models/propulsion/FGEngine.h>
+#include <FDM/JSBSim/models/propulsion/FGPiston.h>
+#include <FDM/JSBSim/models/propulsion/FGTurbine.h>
+#include <FDM/JSBSim/models/propulsion/FGTurboProp.h>
+#include <FDM/JSBSim/models/propulsion/FGRocket.h>
+#include <FDM/JSBSim/models/propulsion/FGElectric.h>
+#include <FDM/JSBSim/models/propulsion/FGNozzle.h>
+#include <FDM/JSBSim/models/propulsion/FGPropeller.h>
+#include <FDM/JSBSim/models/propulsion/FGRotor.h>
+#include <FDM/JSBSim/models/propulsion/FGTank.h>
+#include <FDM/JSBSim/input_output/FGPropertyManager.h>
+#include <FDM/JSBSim/input_output/FGGroundCallback.h>
+
+using namespace JSBSim;
static inline double
FMAX (double a, double b)
}
}
- reset_on_crash = fgGetBool("/sim/reset-on-crash", false);
- crashed = false;
- fgSetBool("/sim/crashed", false);
-
fdmex = new FGFDMExec( (FGPropertyManager*)globals->get_props() );
// Register ground callback.
// Explicitly call the superclass's
// init method first.
-#ifdef FG_WEATHERCM
- Atmosphere->UseInternal();
-#else
if (fgGetBool("/environment/params/control-fdm-atmosphere")) {
Atmosphere->UseExternal();
Atmosphere->SetExTemperature(
} else {
Atmosphere->UseInternal();
}
-#endif
fgic->SetVnorthFpsIC( wind_from_north->getDoubleValue() );
fgic->SetVeastFpsIC( wind_from_east->getDoubleValue() );
switch(fgic->GetSpeedSet()) {
case setned:
SG_LOG(SG_FLIGHT,SG_INFO, " Vn,Ve,Vd= "
- << Propagate->GetVel(eNorth) << ", "
- << Propagate->GetVel(eEast) << ", "
- << Propagate->GetVel(eDown) << " ft/s");
+ << Propagate->GetVel(FGJSBBase::eNorth) << ", "
+ << Propagate->GetVel(FGJSBBase::eEast) << ", "
+ << Propagate->GetVel(FGJSBBase::eDown) << " ft/s");
break;
case setuvw:
SG_LOG(SG_FLIGHT,SG_INFO, " U,V,W= "
stall_warning->setDoubleValue(0);
SG_LOG( SG_FLIGHT, SG_INFO, " Bank Angle: "
- << Propagate->GetEuler(ePhi)*RADTODEG << " deg" );
+ << Propagate->GetEuler(FGJSBBase::ePhi)*RADTODEG << " deg" );
SG_LOG( SG_FLIGHT, SG_INFO, " Pitch Angle: "
- << Propagate->GetEuler(eTht)*RADTODEG << " deg" );
+ << Propagate->GetEuler(FGJSBBase::eTht)*RADTODEG << " deg" );
SG_LOG( SG_FLIGHT, SG_INFO, " True Heading: "
- << Propagate->GetEuler(ePsi)*RADTODEG << " deg" );
+ << Propagate->GetEuler(FGJSBBase::ePsi)*RADTODEG << " deg" );
SG_LOG( SG_FLIGHT, SG_INFO, " Latitude: "
<< Propagate->GetLocation().GetLatitudeDeg() << " deg" );
SG_LOG( SG_FLIGHT, SG_INFO, " Longitude: "
// translate JSBsim back to FG structure so that the
// autopilot (and the rest of the sim can use the updated values
copy_from_JSBsim();
-
- // crashed (altitude AGL < 0)
- if (get_Altitude_AGL() < 0.0) {
- crash_message = "Attempted to fly under ground.";
- crash_handler();
- }
}
/******************************************************************************/
FCS->SetThrottleCmd(i, globals->get_controls()->get_throttle(i));
FCS->SetMixtureCmd(i, globals->get_controls()->get_mixture(i));
FCS->SetPropAdvanceCmd(i, globals->get_controls()->get_prop_advance(i));
+ FCS->SetFeatherCmd(i, globals->get_controls()->get_feather(i));
switch (Propulsion->GetEngine(i)->GetType()) {
case FGEngine::etPiston:
FGRocket* eng = (FGRocket*)Propulsion->GetEngine(i);
break;
} // end FGRocket code block
+ case FGEngine::etTurboprop:
+ { // FGTurboProp code block
+ FGTurboProp* eng = (FGTurboProp*)Propulsion->GetEngine(i);
+ eng->SetReverse( globals->get_controls()->get_reverser(i) );
+ eng->SetCutoff( globals->get_controls()->get_cutoff(i) );
+ eng->SetIgnition( globals->get_controls()->get_ignition(i) );
+
+ eng->SetGeneratorPower( globals->get_controls()->get_generator_breaker(i) );
+ eng->SetCondition( globals->get_controls()->get_condition(i) );
+ break;
+ } // end FGTurboProp code block
}
{ // FGEngine code block
// Velocities
- _set_Velocities_Local( Propagate->GetVel(eNorth),
- Propagate->GetVel(eEast),
- Propagate->GetVel(eDown) );
+ _set_Velocities_Local( Propagate->GetVel(FGJSBBase::eNorth),
+ Propagate->GetVel(FGJSBBase::eEast),
+ Propagate->GetVel(FGJSBBase::eDown) );
_set_Velocities_Wind_Body( Propagate->GetUVW(1),
Propagate->GetUVW(2),
Propagate->GetUVW(3) );
// Make the HUD work ...
- _set_Velocities_Ground( Propagate->GetVel(eNorth),
- Propagate->GetVel(eEast),
- -Propagate->GetVel(eDown) );
+ _set_Velocities_Ground( Propagate->GetVel(FGJSBBase::eNorth),
+ Propagate->GetVel(FGJSBBase::eEast),
+ -Propagate->GetVel(FGJSBBase::eDown) );
_set_V_rel_wind( Auxiliary->GetVt() );
_set_V_ground_speed( Auxiliary->GetVground() );
- _set_Omega_Body( Propagate->GetPQR(eP),
- Propagate->GetPQR(eQ),
- Propagate->GetPQR(eR) );
+ _set_Omega_Body( Propagate->GetPQR(FGJSBBase::eP),
+ Propagate->GetPQR(FGJSBBase::eQ),
+ Propagate->GetPQR(FGJSBBase::eR) );
- _set_Euler_Rates( Auxiliary->GetEulerRates(ePhi),
- Auxiliary->GetEulerRates(eTht),
- Auxiliary->GetEulerRates(ePsi) );
+ _set_Euler_Rates( Auxiliary->GetEulerRates(FGJSBBase::ePhi),
+ Auxiliary->GetEulerRates(FGJSBBase::eTht),
+ Auxiliary->GetEulerRates(FGJSBBase::ePsi) );
_set_Mach_number( Auxiliary->GetMach() );
_set_Altitude_AGL( Propagate->GetDistanceAGL() );
{
- double loc_cart[3] = { l(eX), l(eY), l(eZ) };
+ double loc_cart[3] = { l(FGJSBBase::eX), l(FGJSBBase::eY), l(FGJSBBase::eZ) };
double contact[3], d[3], sd, t;
int id;
is_valid_m(&t, d, &sd);
_set_Runway_altitude( rwrad - get_Sea_level_radius() );
}
- _set_Euler_Angles( Propagate->GetEuler(ePhi),
- Propagate->GetEuler(eTht),
- Propagate->GetEuler(ePsi) );
+ _set_Euler_Angles( Propagate->GetEuler(FGJSBBase::ePhi),
+ Propagate->GetEuler(FGJSBBase::eTht),
+ Propagate->GetEuler(FGJSBBase::ePsi) );
_set_Alpha( Auxiliary->Getalpha() );
_set_Beta( Auxiliary->Getbeta() );
globals->get_controls()->set_augmentation(i, eng->GetAugmentation() );
} // end FGTurbine code block
break;
+ case FGEngine::etTurboprop:
+ { // FGTurboProp code block
+ FGTurboProp* eng = (FGTurboProp*)Propulsion->GetEngine(i);
+ node->setDoubleValue("n1", eng->GetN1());
+ //node->setDoubleValue("n2", eng->GetN2());
+ node->setDoubleValue("itt_degf", 32 + eng->GetITT()*9/5);
+ node->setBoolValue("ignition", eng->GetIgnition());
+ node->setDoubleValue("nozzle-pos-norm", eng->GetNozzle());
+ node->setDoubleValue("inlet-pos-norm", eng->GetInlet());
+ node->setDoubleValue("oil-pressure-psi", eng->getOilPressure_psi());
+ node->setBoolValue("reversed", eng->GetReversed());
+ node->setBoolValue("cutoff", eng->GetCutoff());
+ node->setBoolValue("starting", eng->GetEngStarting());
+ node->setBoolValue("generator-power", eng->GetGeneratorPower());
+ node->setBoolValue("damaged", eng->GetCondition());
+ node->setBoolValue("ielu-intervent", eng->GetIeluIntervent());
+ node->setDoubleValue("oil-temperature-degf", eng->getOilTemp_degF());
+// node->setBoolValue("onfire", eng->GetFire());
+ globals->get_controls()->set_reverser(i, eng->GetReversed() );
+ globals->get_controls()->set_cutoff(i, eng->GetCutoff() );
+ } // end FGTurboProp code block
+ break;
case FGEngine::etElectric:
{ // FGElectric code block
FGElectric* eng = (FGElectric*)Propulsion->GetEngine(i);
tnode->setDoubleValue("rpm", thruster->GetRPM());
tnode->setDoubleValue("pitch", prop->GetPitch());
tnode->setDoubleValue("torque", prop->GetTorque());
+ tnode->setBoolValue("feathered", prop->GetFeather());
} // end FGPropeller code block
break;
case FGThruster::ttRotor:
speedbrake_pos_pct->setDoubleValue( FCS->GetDsbPos(ofNorm) );
spoilers_pos_pct->setDoubleValue( FCS->GetDspPos(ofNorm) );
+ // force a sim reset if crashed (altitude AGL < 0)
+ if (get_Altitude_AGL() < 0.0) {
+ fgSetBool("/sim/crashed", true);
+ SGPropertyNode* node = fgGetNode("/sim/presets", true);
+ globals->get_commands()->execute("old-reinit-dialog", node);
+ }
+
return true;
}
bool FGJSBsim::ToggleDataLogging(void)
{
- return fdmex->GetOutput()->Toggle();
+ // ToDo: handle this properly
+ fdmex->DisableOutput();
+ return false;
}
bool FGJSBsim::ToggleDataLogging(bool state)
{
if (state) {
- fdmex->GetOutput()->Enable();
+ fdmex->EnableOutput();
return true;
} else {
- fdmex->GetOutput()->Disable();
+ fdmex->DisableOutput();
return false;
}
}
}
}
-void FGJSBsim::crash_handler(void)
-{
- if (crashed) return; // we already crashed
- crashed = true;
- fgSetBool("/sim/crashed", true);
- SG_LOG( SG_FLIGHT, SG_WARN, " Crash: " << crash_message );
- if (reset_on_crash) {
- SGPropertyNode* node = fgGetNode("/sim/presets", true);
- globals->get_commands()->execute("old-reinit-dialog", node);
- } else {
- fgSetBool("/sim/freeze/master", true);
- fgSetBool("/sim/freeze/clock", true);
- }
-}
class FGInitialCondition;
}
-using namespace JSBSim;
+// Adding it here will cause a namespace clash in FlightGear -EMH-
+// using namespace JSBSim;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DOCUMENTATION
void do_trim(void);
void update_ic(void);
- //** Handle a crash of the user aircraft. */
- void crash_handler();
-
private:
- FGFDMExec *fdmex;
- FGInitialCondition *fgic;
+ JSBSim::FGFDMExec *fdmex;
+ JSBSim::FGInitialCondition *fgic;
bool needTrim;
- FGState* State;
- FGAtmosphere* Atmosphere;
- FGFCS* FCS;
- FGPropulsion* Propulsion;
- FGMassBalance* MassBalance;
- FGAircraft* Aircraft;
- FGPropagate* Propagate;
- FGAuxiliary* Auxiliary;
- FGAerodynamics* Aerodynamics;
- FGGroundReactions *GroundReactions;
+ JSBSim::FGState* State;
+ JSBSim::FGAtmosphere* Atmosphere;
+ JSBSim::FGFCS* FCS;
+ JSBSim::FGPropulsion* Propulsion;
+ JSBSim::FGMassBalance* MassBalance;
+ JSBSim::FGAircraft* Aircraft;
+ JSBSim::FGPropagate* Propagate;
+ JSBSim::FGAuxiliary* Auxiliary;
+ JSBSim::FGAerodynamics* Aerodynamics;
+ JSBSim::FGGroundReactions *GroundReactions;
int runcount;
double trim_elev;
void init_gear(void);
void update_gear(void);
- bool reset_on_crash;
- bool crashed;
- string crash_message;
-
};
-SUBDIRS = filtersjb
-
-EXTRA_DIST = Makefile.solo
+SUBDIRS = initialization models input_output math
noinst_LIBRARIES = libJSBSim.a
-libJSBSim_a_SOURCES = \
- FGAerodynamics.cpp FGAerodynamics.h \
- FGAircraft.cpp FGAircraft.h \
- FGAtmosphere.cpp FGAtmosphere.h \
- FGAuxiliary.cpp FGAuxiliary.h \
- FGCoefficient.cpp FGCoefficient.h \
- FGColumnVector3.cpp FGColumnVector3.h \
- FGConfigFile.cpp FGConfigFile.h \
- FGFCS.cpp FGFCS.h \
- FGFDMExec.cpp FGFDMExec.h \
- FGFactorGroup.cpp FGFactorGroup.h \
- FGForce.cpp FGForce.h \
- FGGroundReactions.cpp FGGroundReactions.h \
- FGInertial.cpp FGInertial.h \
- FGInitialCondition.cpp FGInitialCondition.h \
- FGJSBBase.cpp FGJSBBase.h \
- FGLGear.cpp FGLGear.h \
- FGMassBalance.cpp FGMassBalance.h \
- FGMatrix33.cpp FGMatrix33.h \
- FGModel.cpp FGModel.h \
- FGNozzle.cpp FGNozzle.h \
- FGOutput.cpp FGOutput.h \
- FGPiston.cpp FGPiston.h \
- FGPropeller.cpp FGPropeller.h \
- FGPropulsion.cpp FGPropulsion.h \
- FGRotor.cpp FGRotor.h \
- FGRocket.cpp FGRocket.h \
- FGScript.cpp FGScript.h \
- FGState.cpp FGState.h \
- FGTable.cpp FGTable.h \
- FGThruster.cpp FGThruster.h \
- FGTrim.cpp FGTrim.h \
- FGTrimAxis.cpp FGTrimAxis.h \
- FGTurbine.cpp FGTurbine.h \
- FGEngine.cpp FGEngine.h \
- FGTank.cpp FGTank.h \
- FGfdmSocket.cpp FGfdmSocket.h \
- FGTurbine.cpp FGTurbine.h \
- FGPropertyManager.cpp FGPropertyManager.h \
- FGPropagate.cpp FGPropagate.h \
- FGLocation.cpp FGLocation.h \
- FGQuaternion.cpp FGQuaternion.h \
- FGElectric.cpp FGElectric.h \
- FGGroundCallback.cpp FGGroundCallback.h \
- JSBSim.cxx JSBSim.hxx
-
-
-# noinst_PROGRAMS = testJSBsim
+libJSBSim_a_SOURCES = FGFDMExec.cpp FGJSBBase.cpp FGState.cpp JSBSim.cxx
-AM_CXXFLAGS = -DFGFS
+noinst_HEADERS = FGFDMExec.h FGJSBBase.h FGState.h JSBSim.hxx
-INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
+INCLUDES = -I$(top_srcdir)/src -I$(top_srcdir)/src/FDM/JSBSim
+++ /dev/null
-CC = g++
-INCLUDES = -I.
-LINKDIR= -Lfiltersjb/
-JSBSim_objects = FGAircraft.o FGAtmosphere.o FGCoefficient.o FGFCS.o FGFDMExec.o\
-FGModel.o FGOutput.o FGPosition.o FGRotation.o FGState.o FGTranslation.o\
-FGUtility.o FGTank.o FGAuxiliary.o FGfdmSocket.o FGTrim.o FGTrimAxis.o\
-FGConfigFile.o FGInitialCondition.o FGLGear.o FGMatrix.o FGPropulsion.o FGRocket.o\
-FGTurboShaft.o FGTurboJet.o FGTurboProp.o FGPiston.o FGForce.o FGThruster.o FGEngine.o\
-FGTable.o FGPropeller.o FGNozzle.o FGAerodynamics.o FGMassBalance.o FGInertial.o\
-FGFactorGroup.o
-
-JSBSim : $(JSBSim_objects) JSBSim.o libFCSComponents.a
- $(CC) $(INCLUDES) $(CCOPTS) $(LINKDIR) $(JSBSim_objects) JSBSim.o -oJSBSim -lm -lFCSComponents
-
-libFCSComponents.a:
- cd filtersjb; make -fMakefile.solo; cd ..
-
-FGAerodynamics.o: FGAerodynamics.cpp FGAerodynamics.h FGModel.h \
- FGDefs.h FGConfigFile.h FGState.h FGInitialCondition.h FGFDMExec.h \
- FGAtmosphere.h FGMatrix.h FGFCS.h filtersjb/FGFCSComponent.h \
- filtersjb/../FGDefs.h filtersjb/../FGFCS.h FGLGear.h FGAircraft.h \
- FGPropulsion.h FGRocket.h FGEngine.h FGTranslation.h FGRotation.h \
- FGPosition.h FGAuxiliary.h FGOutput.h FGfdmSocket.h FGPiston.h \
- FGTurboShaft.h FGTurboJet.h FGTurboProp.h FGTank.h FGPropeller.h \
- FGThruster.h FGForce.h FGTable.h FGNozzle.h FGMassBalance.h \
- FGCoefficient.h FGFactorGroup.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGAerodynamics.cpp
-
-FGAircraft.o: FGAircraft.cpp FGAircraft.h FGModel.h FGDefs.h \
- FGPropulsion.h FGRocket.h FGEngine.h FGState.h FGInitialCondition.h \
- FGFDMExec.h FGAtmosphere.h FGMatrix.h FGFCS.h \
- filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h filtersjb/../FGFCS.h \
- FGLGear.h FGConfigFile.h FGPosition.h FGRotation.h FGMassBalance.h \
- FGTranslation.h FGAerodynamics.h FGCoefficient.h FGTable.h \
- FGFactorGroup.h FGOutput.h FGfdmSocket.h FGAuxiliary.h FGPiston.h \
- FGTurboShaft.h FGTurboJet.h FGTurboProp.h FGTank.h FGPropeller.h \
- FGThruster.h FGForce.h FGNozzle.h FGInertial.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGAircraft.cpp
-
-FGAtmosphere.o: FGAtmosphere.cpp FGAtmosphere.h FGModel.h FGDefs.h \
- FGMatrix.h FGState.h FGInitialCondition.h FGFDMExec.h FGFCS.h \
- filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h filtersjb/../FGFCS.h \
- FGLGear.h FGConfigFile.h FGAircraft.h FGPropulsion.h FGRocket.h \
- FGEngine.h FGTranslation.h FGRotation.h FGPosition.h FGAuxiliary.h \
- FGOutput.h FGfdmSocket.h FGPiston.h FGTurboShaft.h FGTurboJet.h \
- FGTurboProp.h FGTank.h FGPropeller.h FGThruster.h FGForce.h FGTable.h \
- FGNozzle.h FGMassBalance.h FGAerodynamics.h FGCoefficient.h \
- FGFactorGroup.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGAtmosphere.cpp
-
-FGAuxiliary.o: FGAuxiliary.cpp FGAuxiliary.h FGModel.h FGDefs.h \
- FGMatrix.h FGTranslation.h FGRotation.h FGAtmosphere.h FGState.h \
- FGInitialCondition.h FGFDMExec.h FGFCS.h filtersjb/FGFCSComponent.h \
- filtersjb/../FGDefs.h filtersjb/../FGFCS.h FGLGear.h FGConfigFile.h \
- FGAircraft.h FGPropulsion.h FGRocket.h FGEngine.h FGPosition.h \
- FGOutput.h FGfdmSocket.h FGPiston.h FGTurboShaft.h FGTurboJet.h \
- FGTurboProp.h FGTank.h FGPropeller.h FGThruster.h FGForce.h FGTable.h \
- FGNozzle.h FGMassBalance.h FGAerodynamics.h FGCoefficient.h \
- FGFactorGroup.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGAuxiliary.cpp
-
-FGCoefficient.o: FGCoefficient.cpp FGCoefficient.h FGConfigFile.h \
- FGDefs.h FGTable.h FGState.h FGInitialCondition.h FGFDMExec.h \
- FGModel.h FGAtmosphere.h FGMatrix.h FGFCS.h \
- filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h filtersjb/../FGFCS.h \
- FGLGear.h FGAircraft.h FGPropulsion.h FGRocket.h FGEngine.h \
- FGTranslation.h FGRotation.h FGPosition.h FGAuxiliary.h FGOutput.h \
- FGfdmSocket.h FGPiston.h FGTurboShaft.h FGTurboJet.h FGTurboProp.h \
- FGTank.h FGPropeller.h FGThruster.h FGForce.h FGNozzle.h \
- FGMassBalance.h FGAerodynamics.h FGFactorGroup.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGCoefficient.cpp
-
-FGColumnVector3.o: FGColumnVector3.cpp FGColumnVector3.h FGMatrix.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGColumnVector3.cpp
-
-FGConfigFile.o: FGConfigFile.cpp FGConfigFile.h FGDefs.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGConfigFile.cpp
-
-FGEngine.o: FGEngine.cpp FGEngine.h FGState.h FGDefs.h \
- FGInitialCondition.h FGFDMExec.h FGModel.h FGAtmosphere.h FGMatrix.h \
- FGFCS.h filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h \
- filtersjb/../FGFCS.h FGLGear.h FGConfigFile.h FGAircraft.h \
- FGPropulsion.h FGRocket.h FGPiston.h FGTurboShaft.h FGTurboJet.h \
- FGTurboProp.h FGTank.h FGPropeller.h FGThruster.h FGForce.h FGTable.h \
- FGTranslation.h FGNozzle.h FGPosition.h FGRotation.h FGMassBalance.h \
- FGAerodynamics.h FGCoefficient.h FGFactorGroup.h FGOutput.h \
- FGfdmSocket.h FGAuxiliary.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGEngine.cpp
-
-FGFCS.o: FGFCS.cpp FGDefs.h FGFCS.h filtersjb/FGFCSComponent.h \
- filtersjb/../FGDefs.h filtersjb/../FGFCS.h FGModel.h FGLGear.h \
- FGConfigFile.h FGMatrix.h FGFDMExec.h FGInitialCondition.h \
- FGAtmosphere.h FGAircraft.h FGPropulsion.h FGRocket.h FGEngine.h \
- FGState.h FGTranslation.h FGRotation.h FGPosition.h FGAerodynamics.h \
- FGMassBalance.h FGCoefficient.h FGTable.h FGFactorGroup.h FGOutput.h \
- FGfdmSocket.h FGAuxiliary.h FGPiston.h FGTurboShaft.h FGTurboJet.h \
- FGTurboProp.h FGTank.h FGPropeller.h FGThruster.h FGForce.h \
- FGNozzle.h filtersjb/FGFilter.h filtersjb/../FGConfigFile.h \
- filtersjb/FGDeadBand.h filtersjb/FGGain.h filtersjb/../FGTable.h \
- filtersjb/FGGradient.h filtersjb/FGSwitch.h filtersjb/FGSummer.h \
- filtersjb/FGFlaps.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGFCS.cpp
-
-FGFDMExec.o: FGFDMExec.cpp FGFDMExec.h FGModel.h FGDefs.h \
- FGInitialCondition.h FGAtmosphere.h FGMatrix.h FGState.h FGFCS.h \
- filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h filtersjb/../FGFCS.h \
- FGLGear.h FGConfigFile.h FGAircraft.h FGPropulsion.h FGRocket.h \
- FGEngine.h FGTranslation.h FGRotation.h FGPosition.h FGAuxiliary.h \
- FGOutput.h FGfdmSocket.h FGPiston.h FGTurboShaft.h FGTurboJet.h \
- FGTurboProp.h FGTank.h FGPropeller.h FGThruster.h FGForce.h FGTable.h \
- FGNozzle.h FGMassBalance.h FGAerodynamics.h FGCoefficient.h \
- FGFactorGroup.h FGInertial.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGFDMExec.cpp
-
-FGFactorGroup.o: FGFactorGroup.cpp FGCoefficient.h FGConfigFile.h \
- FGDefs.h FGTable.h FGFactorGroup.h FGAerodynamics.h FGModel.h \
- FGState.h FGInitialCondition.h FGFDMExec.h FGAtmosphere.h FGMatrix.h \
- FGFCS.h filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h \
- filtersjb/../FGFCS.h FGLGear.h FGAircraft.h FGPropulsion.h FGRocket.h \
- FGEngine.h FGTranslation.h FGRotation.h FGPosition.h FGAuxiliary.h \
- FGOutput.h FGfdmSocket.h FGPiston.h FGTurboShaft.h FGTurboJet.h \
- FGTurboProp.h FGTank.h FGPropeller.h FGThruster.h FGForce.h \
- FGNozzle.h FGMassBalance.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGFactorGroup.cpp
-
-FGForce.o: FGForce.cpp FGFDMExec.h FGModel.h FGDefs.h \
- FGInitialCondition.h FGAtmosphere.h FGMatrix.h FGAircraft.h \
- FGPropulsion.h FGRocket.h FGEngine.h FGState.h FGFCS.h \
- filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h filtersjb/../FGFCS.h \
- FGLGear.h FGConfigFile.h FGPosition.h FGRotation.h FGMassBalance.h \
- FGTranslation.h FGAerodynamics.h FGCoefficient.h FGTable.h \
- FGFactorGroup.h FGOutput.h FGfdmSocket.h FGAuxiliary.h FGPiston.h \
- FGTurboShaft.h FGTurboJet.h FGTurboProp.h FGTank.h FGPropeller.h \
- FGThruster.h FGForce.h FGNozzle.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGForce.cpp
-
-FGGroundReactions.o: FGGroundReactions.cpp FGGroundReactions.h \
- FGModel.h FGDefs.h FGConfigFile.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGGroundReactions.cpp
-
-FGInertial.o: FGInertial.cpp FGInertial.h FGModel.h FGDefs.h \
- FGConfigFile.h FGMatrix.h FGPosition.h FGMassBalance.h FGPropulsion.h \
- FGRocket.h FGEngine.h FGState.h FGInitialCondition.h FGFDMExec.h \
- FGAtmosphere.h FGFCS.h filtersjb/FGFCSComponent.h \
- filtersjb/../FGDefs.h filtersjb/../FGFCS.h FGLGear.h FGAircraft.h \
- FGRotation.h FGTranslation.h FGAerodynamics.h FGCoefficient.h \
- FGTable.h FGFactorGroup.h FGOutput.h FGfdmSocket.h FGAuxiliary.h \
- FGPiston.h FGTurboShaft.h FGTurboJet.h FGTurboProp.h FGTank.h \
- FGPropeller.h FGThruster.h FGForce.h FGNozzle.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGInertial.cpp
-
-FGInitialCondition.o: FGInitialCondition.cpp FGInitialCondition.h \
- FGFDMExec.h FGModel.h FGDefs.h FGAtmosphere.h FGMatrix.h FGState.h \
- FGFCS.h filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h \
- filtersjb/../FGFCS.h FGLGear.h FGConfigFile.h FGAircraft.h \
- FGPropulsion.h FGRocket.h FGEngine.h FGTranslation.h FGRotation.h \
- FGPosition.h FGAuxiliary.h FGOutput.h FGfdmSocket.h FGPiston.h \
- FGTurboShaft.h FGTurboJet.h FGTurboProp.h FGTank.h FGPropeller.h \
- FGThruster.h FGForce.h FGTable.h FGNozzle.h FGMassBalance.h \
- FGAerodynamics.h FGCoefficient.h FGFactorGroup.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGInitialCondition.cpp
-
-FGLGear.o: FGLGear.cpp FGLGear.h FGConfigFile.h FGDefs.h FGMatrix.h \
- FGFDMExec.h FGModel.h FGInitialCondition.h FGAtmosphere.h \
- FGAircraft.h FGPropulsion.h FGRocket.h FGEngine.h FGState.h FGFCS.h \
- filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h filtersjb/../FGFCS.h \
- FGTranslation.h FGRotation.h FGPosition.h FGAerodynamics.h \
- FGMassBalance.h FGCoefficient.h FGTable.h FGFactorGroup.h FGOutput.h \
- FGfdmSocket.h FGAuxiliary.h FGPiston.h FGTurboShaft.h FGTurboJet.h \
- FGTurboProp.h FGTank.h FGPropeller.h FGThruster.h FGForce.h \
- FGNozzle.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGLGear.cpp
-
-FGMassBalance.o: FGMassBalance.cpp FGMassBalance.h FGModel.h FGDefs.h \
- FGPropulsion.h FGRocket.h FGEngine.h FGState.h FGInitialCondition.h \
- FGFDMExec.h FGAtmosphere.h FGMatrix.h FGFCS.h \
- filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h filtersjb/../FGFCS.h \
- FGLGear.h FGConfigFile.h FGAircraft.h FGPosition.h FGRotation.h \
- FGTranslation.h FGAerodynamics.h FGCoefficient.h FGTable.h \
- FGFactorGroup.h FGOutput.h FGfdmSocket.h FGAuxiliary.h FGPiston.h \
- FGTurboShaft.h FGTurboJet.h FGTurboProp.h FGTank.h FGPropeller.h \
- FGThruster.h FGForce.h FGNozzle.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGMassBalance.cpp
-
-FGMatrix.o: FGMatrix.cpp FGMatrix.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGMatrix.cpp
-
-FGModel.o: FGModel.cpp FGModel.h FGDefs.h FGState.h \
- FGInitialCondition.h FGFDMExec.h FGAtmosphere.h FGMatrix.h FGFCS.h \
- filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h filtersjb/../FGFCS.h \
- FGLGear.h FGConfigFile.h FGAircraft.h FGPropulsion.h FGRocket.h \
- FGEngine.h FGTranslation.h FGRotation.h FGPosition.h FGAuxiliary.h \
- FGOutput.h FGfdmSocket.h FGPiston.h FGTurboShaft.h FGTurboJet.h \
- FGTurboProp.h FGTank.h FGPropeller.h FGThruster.h FGForce.h FGTable.h \
- FGNozzle.h FGMassBalance.h FGAerodynamics.h FGCoefficient.h \
- FGFactorGroup.h FGInertial.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGModel.cpp
-
-FGNozzle.o: FGNozzle.cpp FGNozzle.h FGThruster.h FGForce.h FGFDMExec.h \
- FGModel.h FGDefs.h FGInitialCondition.h FGAtmosphere.h FGMatrix.h \
- FGConfigFile.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGNozzle.cpp
-
-FGOutput.o: FGOutput.cpp FGOutput.h FGModel.h FGDefs.h FGfdmSocket.h \
- FGState.h FGInitialCondition.h FGFDMExec.h FGAtmosphere.h FGMatrix.h \
- FGFCS.h filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h \
- filtersjb/../FGFCS.h FGLGear.h FGConfigFile.h FGAircraft.h \
- FGPropulsion.h FGRocket.h FGEngine.h FGTranslation.h FGRotation.h \
- FGPosition.h FGAuxiliary.h FGPiston.h FGTurboShaft.h FGTurboJet.h \
- FGTurboProp.h FGTank.h FGPropeller.h FGThruster.h FGForce.h FGTable.h \
- FGNozzle.h FGMassBalance.h FGAerodynamics.h FGCoefficient.h \
- FGFactorGroup.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGOutput.cpp
-
-FGPiston.o: FGPiston.cpp FGDefs.h FGPiston.h FGEngine.h FGState.h \
- FGInitialCondition.h FGFDMExec.h FGModel.h FGAtmosphere.h FGMatrix.h \
- FGFCS.h filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h \
- filtersjb/../FGFCS.h FGLGear.h FGConfigFile.h FGAircraft.h \
- FGPropulsion.h FGRocket.h FGTurboShaft.h FGTurboJet.h FGTurboProp.h \
- FGTank.h FGPropeller.h FGThruster.h FGForce.h FGTable.h \
- FGTranslation.h FGNozzle.h FGPosition.h FGRotation.h FGMassBalance.h \
- FGAerodynamics.h FGCoefficient.h FGFactorGroup.h FGOutput.h \
- FGfdmSocket.h FGAuxiliary.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGPiston.cpp
-
-FGPosition.o: FGPosition.cpp FGPosition.h FGModel.h FGDefs.h \
- FGMatrix.h FGAtmosphere.h FGState.h FGInitialCondition.h FGFDMExec.h \
- FGFCS.h filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h \
- filtersjb/../FGFCS.h FGLGear.h FGConfigFile.h FGAircraft.h \
- FGPropulsion.h FGRocket.h FGEngine.h FGTranslation.h FGRotation.h \
- FGAuxiliary.h FGOutput.h FGfdmSocket.h FGPiston.h FGTurboShaft.h \
- FGTurboJet.h FGTurboProp.h FGTank.h FGPropeller.h FGThruster.h \
- FGForce.h FGTable.h FGNozzle.h FGMassBalance.h FGAerodynamics.h \
- FGCoefficient.h FGFactorGroup.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGPosition.cpp
-
-FGPropeller.o: FGPropeller.cpp FGPropeller.h FGThruster.h FGForce.h \
- FGFDMExec.h FGModel.h FGDefs.h FGInitialCondition.h FGAtmosphere.h \
- FGMatrix.h FGConfigFile.h FGTable.h FGTranslation.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGPropeller.cpp
-
-FGPropulsion.o: FGPropulsion.cpp FGPropulsion.h FGModel.h FGDefs.h \
- FGRocket.h FGEngine.h FGState.h FGInitialCondition.h FGFDMExec.h \
- FGAtmosphere.h FGMatrix.h FGFCS.h filtersjb/FGFCSComponent.h \
- filtersjb/../FGDefs.h filtersjb/../FGFCS.h FGLGear.h FGConfigFile.h \
- FGAircraft.h FGPosition.h FGRotation.h FGMassBalance.h \
- FGTranslation.h FGAerodynamics.h FGCoefficient.h FGTable.h \
- FGFactorGroup.h FGOutput.h FGfdmSocket.h FGAuxiliary.h FGPiston.h \
- FGTurboShaft.h FGTurboJet.h FGTurboProp.h FGTank.h FGPropeller.h \
- FGThruster.h FGForce.h FGNozzle.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGPropulsion.cpp
-
-FGRocket.o: FGRocket.cpp FGDefs.h FGRocket.h FGEngine.h FGState.h \
- FGInitialCondition.h FGFDMExec.h FGModel.h FGAtmosphere.h FGMatrix.h \
- FGFCS.h filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h \
- filtersjb/../FGFCS.h FGLGear.h FGConfigFile.h FGAircraft.h \
- FGPropulsion.h FGPiston.h FGTurboShaft.h FGTurboJet.h FGTurboProp.h \
- FGTank.h FGPropeller.h FGThruster.h FGForce.h FGTable.h \
- FGTranslation.h FGNozzle.h FGPosition.h FGRotation.h FGMassBalance.h \
- FGAerodynamics.h FGCoefficient.h FGFactorGroup.h FGOutput.h \
- FGfdmSocket.h FGAuxiliary.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGRocket.cpp
-
-FGRotation.o: FGRotation.cpp FGRotation.h FGModel.h FGDefs.h \
- FGMatrix.h FGAtmosphere.h FGState.h FGInitialCondition.h FGFDMExec.h \
- FGFCS.h filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h \
- filtersjb/../FGFCS.h FGLGear.h FGConfigFile.h FGAircraft.h \
- FGPropulsion.h FGRocket.h FGEngine.h FGTranslation.h FGPosition.h \
- FGAuxiliary.h FGOutput.h FGfdmSocket.h FGPiston.h FGTurboShaft.h \
- FGTurboJet.h FGTurboProp.h FGTank.h FGPropeller.h FGThruster.h \
- FGForce.h FGTable.h FGNozzle.h FGMassBalance.h FGAerodynamics.h \
- FGCoefficient.h FGFactorGroup.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGRotation.cpp
-
-FGRotor.o: FGRotor.cpp FGRotor.h FGThruster.h FGForce.h FGFDMExec.h \
- FGModel.h FGDefs.h FGInitialCondition.h FGAtmosphere.h FGMatrix.h \
- FGConfigFile.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGRotor.cpp
-
-FGState.o: FGState.cpp FGState.h FGDefs.h FGInitialCondition.h \
- FGFDMExec.h FGModel.h FGAtmosphere.h FGMatrix.h FGFCS.h \
- filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h filtersjb/../FGFCS.h \
- FGLGear.h FGConfigFile.h FGAircraft.h FGPropulsion.h FGRocket.h \
- FGEngine.h FGTranslation.h FGRotation.h FGPosition.h FGAuxiliary.h \
- FGOutput.h FGfdmSocket.h FGPiston.h FGTurboShaft.h FGTurboJet.h \
- FGTurboProp.h FGTank.h FGPropeller.h FGThruster.h FGForce.h FGTable.h \
- FGNozzle.h FGMassBalance.h FGAerodynamics.h FGCoefficient.h \
- FGFactorGroup.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGState.cpp
-
-FGTable.o: FGTable.cpp FGTable.h FGConfigFile.h FGDefs.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGTable.cpp
-
-FGTank.o: FGTank.cpp FGDefs.h FGTank.h FGConfigFile.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGTank.cpp
-
-FGThruster.o: FGThruster.cpp FGThruster.h FGForce.h FGFDMExec.h \
- FGModel.h FGDefs.h FGInitialCondition.h FGAtmosphere.h FGMatrix.h \
- FGConfigFile.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGThruster.cpp
-
-FGTranslation.o: FGTranslation.cpp FGTranslation.h FGModel.h FGDefs.h \
- FGMatrix.h FGRotation.h FGAtmosphere.h FGState.h FGInitialCondition.h \
- FGFDMExec.h FGFCS.h filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h \
- filtersjb/../FGFCS.h FGLGear.h FGConfigFile.h FGAircraft.h \
- FGPropulsion.h FGRocket.h FGEngine.h FGPosition.h FGAuxiliary.h \
- FGOutput.h FGfdmSocket.h FGPiston.h FGTurboShaft.h FGTurboJet.h \
- FGTurboProp.h FGTank.h FGPropeller.h FGThruster.h FGForce.h FGTable.h \
- FGNozzle.h FGMassBalance.h FGAerodynamics.h FGCoefficient.h \
- FGFactorGroup.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGTranslation.cpp
-
-FGTrim.o: FGTrim.cpp FGFDMExec.h FGModel.h FGDefs.h \
- FGInitialCondition.h FGAtmosphere.h FGMatrix.h FGTrim.h FGRotation.h \
- FGState.h FGFCS.h filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h \
- filtersjb/../FGFCS.h FGLGear.h FGConfigFile.h FGAircraft.h \
- FGPropulsion.h FGRocket.h FGEngine.h FGTranslation.h FGPosition.h \
- FGAuxiliary.h FGOutput.h FGfdmSocket.h FGPiston.h FGTurboShaft.h \
- FGTurboJet.h FGTurboProp.h FGTank.h FGPropeller.h FGThruster.h \
- FGForce.h FGTable.h FGNozzle.h FGMassBalance.h FGAerodynamics.h \
- FGCoefficient.h FGFactorGroup.h FGTrimAxis.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGTrim.cpp
-
-FGTrimAxis.o: FGTrimAxis.cpp FGFDMExec.h FGModel.h FGDefs.h \
- FGInitialCondition.h FGAtmosphere.h FGMatrix.h FGTrimAxis.h \
- FGRotation.h FGState.h FGFCS.h filtersjb/FGFCSComponent.h \
- filtersjb/../FGDefs.h filtersjb/../FGFCS.h FGLGear.h FGConfigFile.h \
- FGAircraft.h FGPropulsion.h FGRocket.h FGEngine.h FGTranslation.h \
- FGPosition.h FGAuxiliary.h FGOutput.h FGfdmSocket.h FGPiston.h \
- FGTurboShaft.h FGTurboJet.h FGTurboProp.h FGTank.h FGPropeller.h \
- FGThruster.h FGForce.h FGTable.h FGNozzle.h FGMassBalance.h \
- FGAerodynamics.h FGCoefficient.h FGFactorGroup.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGTrimAxis.cpp
-
-FGTurboJet.o: FGTurboJet.cpp FGTurboJet.h FGEngine.h FGState.h \
- FGDefs.h FGInitialCondition.h FGFDMExec.h FGModel.h FGAtmosphere.h \
- FGMatrix.h FGFCS.h filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h \
- filtersjb/../FGFCS.h FGLGear.h FGConfigFile.h FGAircraft.h \
- FGPropulsion.h FGRocket.h FGPiston.h FGTurboShaft.h FGTurboProp.h \
- FGTank.h FGPropeller.h FGThruster.h FGForce.h FGTable.h \
- FGTranslation.h FGNozzle.h FGPosition.h FGRotation.h FGMassBalance.h \
- FGAerodynamics.h FGCoefficient.h FGFactorGroup.h FGOutput.h \
- FGfdmSocket.h FGAuxiliary.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGTurboJet.cpp
-
-FGTurboProp.o: FGTurboProp.cpp FGTurboProp.h FGEngine.h FGState.h \
- FGDefs.h FGInitialCondition.h FGFDMExec.h FGModel.h FGAtmosphere.h \
- FGMatrix.h FGFCS.h filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h \
- filtersjb/../FGFCS.h FGLGear.h FGConfigFile.h FGAircraft.h \
- FGPropulsion.h FGRocket.h FGPiston.h FGTurboShaft.h FGTurboJet.h \
- FGTank.h FGPropeller.h FGThruster.h FGForce.h FGTable.h \
- FGTranslation.h FGNozzle.h FGPosition.h FGRotation.h FGMassBalance.h \
- FGAerodynamics.h FGCoefficient.h FGFactorGroup.h FGOutput.h \
- FGfdmSocket.h FGAuxiliary.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGTurboProp.cpp
-
-FGTurboShaft.o: FGTurboShaft.cpp FGTurboShaft.h FGEngine.h FGState.h \
- FGDefs.h FGInitialCondition.h FGFDMExec.h FGModel.h FGAtmosphere.h \
- FGMatrix.h FGFCS.h filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h \
- filtersjb/../FGFCS.h FGLGear.h FGConfigFile.h FGAircraft.h \
- FGPropulsion.h FGRocket.h FGPiston.h FGTurboJet.h FGTurboProp.h \
- FGTank.h FGPropeller.h FGThruster.h FGForce.h FGTable.h \
- FGTranslation.h FGNozzle.h FGPosition.h FGRotation.h FGMassBalance.h \
- FGAerodynamics.h FGCoefficient.h FGFactorGroup.h FGOutput.h \
- FGfdmSocket.h FGAuxiliary.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGTurboShaft.cpp
-
-FGUtility.o: FGUtility.cpp FGUtility.h FGState.h FGDefs.h \
- FGInitialCondition.h FGFDMExec.h FGModel.h FGAtmosphere.h FGMatrix.h \
- FGFCS.h filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h \
- filtersjb/../FGFCS.h FGLGear.h FGConfigFile.h FGAircraft.h \
- FGPropulsion.h FGRocket.h FGEngine.h FGTranslation.h FGRotation.h \
- FGPosition.h FGAuxiliary.h FGOutput.h FGfdmSocket.h FGPiston.h \
- FGTurboShaft.h FGTurboJet.h FGTurboProp.h FGTank.h FGPropeller.h \
- FGThruster.h FGForce.h FGTable.h FGNozzle.h FGMassBalance.h \
- FGAerodynamics.h FGCoefficient.h FGFactorGroup.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGUtility.cpp
-
-FGfdmSocket.o: FGfdmSocket.cpp FGfdmSocket.h
- $(CC) $(INCLUDES) $(CCOPTS) -c FGfdmSocket.cpp
-
-JSBSim.o: JSBSim.cpp FGFDMExec.h FGModel.h FGDefs.h \
- FGInitialCondition.h FGAtmosphere.h FGMatrix.h FGRotation.h FGState.h \
- FGFCS.h filtersjb/FGFCSComponent.h filtersjb/../FGDefs.h \
- filtersjb/../FGFCS.h FGLGear.h FGConfigFile.h FGAircraft.h \
- FGPropulsion.h FGRocket.h FGEngine.h FGTranslation.h FGPosition.h \
- FGAuxiliary.h FGOutput.h FGfdmSocket.h FGPiston.h FGTurboShaft.h \
- FGTurboJet.h FGTurboProp.h FGTank.h FGPropeller.h FGThruster.h \
- FGForce.h FGTable.h FGNozzle.h FGMassBalance.h FGAerodynamics.h \
- FGCoefficient.h FGFactorGroup.h
- $(CC) $(INCLUDES) $(CCOPTS) -c JSBSim.cpp
-
-
-x15trim.o:x15trim.cpp
- $(CC) $(INCLUDES) $(CCOPTS) -c x15trim.cpp
-
-x15trim:$(JSBSim_objects) x15trim.o libFCSComponents.a
- $(CC) $(INCLUDES) $(CCOPTS) $(LINKDIR) $(JSBSim_objects) x15trim.o -ox15trim -lm -lFCSComponents
-
-clean:
- -mv *.*~ backup
- -rm *.o
-
-all:
- touch *.cpp
- cd filtersjb; make all -fMakefile.solo; cd ..
- make JSBSim -fMakefile.solo
-
-debug:
- touch *.cpp
- touch filtersjb/*.cpp
- cd filtersjb; make debug CCOPTS=-g -fMakefile.solo; cd ..
- make JSBSim CCOPTS=-g -fMakefile.solo
+++ /dev/null
-Contents\r
---------\r
-\r
-1) Introduction\r
-2) Building with autoconf/automake\r
-3) Contact\r
-\r
-\r
-1) Introduction\r
----------------\r
-\r
-JSBSim is a multi-platform, general purpose object-oriented Flight\r
-Dynamics Model (FDM) written in C++. Jon Berndt and Tony Peden began\r
-about mid-1998 writing JSBSim. As of this writing it is the default\r
-FDM for FlightGear. JSBSim can also be run in a standalone batch mode\r
-for testing and study. More information on JSBSim can be found at the\r
-JSBSim home page here:\r
-\r
-http://jsbsim.sourceforge.net\r
-\r
-The standalone version of JSBSim can be easily built from the command\r
-line of a unix or unix-like (CygWin/Linux/Unix/IRIX, etc.) system like\r
-this:\r
-\r
-make -fMakefile.solo\r
-\r
-If you are on an IRIX machine you can use the Makefile.irix makefile.\r
-Directions are also provided below for using traditional auto* utilities\r
-also provided with JSBSim.\r
-\r
-\r
-2) Building with autoconf/automake\r
-----------------------------------\r
-\r
-Unpack the distribution tarball (if needed - CVS users will have\r
-downloaded the code directly) using your preferred method, and change\r
-to the working directory. For example :\r
-\r
-$ tar xvfz JSBSim-0.1.2.tar.gz\r
-$ cd JSBSim-0.1.2\r
-\r
-NOTE for CVS users: If you are using JSBSim from a CVS checkout, or\r
-snapshot, you will need to create the initial configure script. The\r
-commands to do this have been included in the 'autogen.sh' script, so\r
-just :\r
-\r
-$ ./autogen.sh\r
-\r
-If you wish to customise your version of JSBSim, use the following to\r
-determine any build-time options you may be interested in.\r
-\r
-$ ./configure --help\r
-\r
-Then :\r
-\r
-$ ./configure\r
-\r
-This will check your system platform, compiler and other local\r
-configuration variables needed to build JSBSim, and generates the\r
-necessary Makefiles. Next :\r
-\r
-$ make\r
-\r
-Will compile the various classes, and link the library. Finally :\r
-\r
-$ make install\r
-\r
-Unless specified otherwise (with --prefix configure option), this will\r
-install 'JSBSim.a' into '/usr/local/lib'.\r
-\r
-\r
-3) Contact\r
-----------\r
-\r
-For more information on JSBSim contact Jon Berndt at jsbsim@hal-pc.org.\r
-\r
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGCondition.cpp
- Author: Jon S. Berndt
- Date started: 1/2/2003
-
- -------------- Copyright (C) 2003 Jon S. Berndt (jsb@hal-pc.org) --------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-COMMENTS, REFERENCES, and NOTES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "FGCondition.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_CONDITION;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-string FGCondition::indent = " ";
-
-
-FGCondition::FGCondition(FGConfigFile* AC_cfg, FGPropertyManager* PropertyManager) :
- PropertyManager(PropertyManager)
-{
- mComparison["EQ"] = eEQ;
- mComparison["NE"] = eNE;
- mComparison["GT"] = eGT;
- mComparison["GE"] = eGE;
- mComparison["LT"] = eLT;
- mComparison["LE"] = eLE;
- mComparison["=="] = eEQ;
- mComparison["!="] = eNE;
- mComparison[">"] = eGT;
- mComparison[">="] = eGE;
- mComparison["<"] = eLT;
- mComparison["<="] = eLE;
-
- TestParam1 = TestParam2 = 0L;
- TestValue = 0.0;
- Comparison = ecUndef;
- Logic = elUndef;
- conditions.clear();
-
- if (AC_cfg->GetValue("CONDITION_GROUP").empty()) { // define a condition
-
- *AC_cfg >> property1 >> conditional >> property2;
- TestParam1 = PropertyManager->GetNode(property1, true);
- Comparison = mComparison[conditional];
-
- if (property2.find_first_not_of("-.0123456789eE") == string::npos) {
- TestValue = atof(property2.c_str());
- } else {
- TestParam2 = PropertyManager->GetNode(property2, true);
- }
-
- isGroup = false;
-
- } else { // define a condition group
-
- if (AC_cfg->GetValue("LOGIC") == "OR") Logic = eOR;
- else if (AC_cfg->GetValue("LOGIC") == "AND") Logic = eAND;
-
- AC_cfg->GetNextConfigLine();
- while (AC_cfg->GetValue() != string("/CONDITION_GROUP")) {
- conditions.push_back(FGCondition(AC_cfg, PropertyManager));
- }
- isGroup = true;
- AC_cfg->GetNextConfigLine();
- }
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGCondition::~FGCondition(void)
-{
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGCondition::Evaluate(void )
-{
- vector <FGCondition>::iterator iConditions;
- bool pass = false;
- double compareValue;
-
- if (Logic == eAND) {
-
- iConditions = conditions.begin();
- pass = true;
- while (iConditions < conditions.end()) {
- if (!iConditions->Evaluate()) pass = false;
- *iConditions++;
- }
-
- } else if (Logic == eOR) {
-
- pass = false;
- while (iConditions < conditions.end()) {
- if (iConditions->Evaluate()) pass = true;
- *iConditions++;
- }
-
- } else {
-
- if (TestParam2 != 0L) compareValue = TestParam2->getDoubleValue();
- else compareValue = TestValue;
-
- switch (Comparison) {
- case ecUndef:
- cerr << "Undefined comparison operator." << endl;
- break;
- case eEQ:
- pass = TestParam1->getDoubleValue() == compareValue;
- break;
- case eNE:
- pass = TestParam1->getDoubleValue() != compareValue;
- break;
- case eGT:
- pass = TestParam1->getDoubleValue() > compareValue;
- break;
- case eGE:
- pass = TestParam1->getDoubleValue() >= compareValue;
- break;
- case eLT:
- pass = TestParam1->getDoubleValue() < compareValue;
- break;
- case eLE:
- pass = TestParam1->getDoubleValue() <= compareValue;
- break;
- default:
- cerr << "Unknown comparison operator." << endl;
- }
- }
-
- return pass;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGCondition::PrintCondition(void )
-{
- vector <FGCondition>::iterator iConditions;
- string scratch;
-
- if (isGroup) {
- switch(Logic) {
- case (elUndef):
- scratch = " UNSET";
- cerr << "unset logic for test condition" << endl;
- break;
- case (eAND):
- scratch = " if all of the following are true";
- break;
- case (eOR):
- scratch = " if any of the following are true:";
- break;
- default:
- scratch = " UNKNOWN";
- cerr << "Unknown logic for test condition" << endl;
- }
-
- iConditions = conditions.begin();
- cout << scratch << endl;
- while (iConditions < conditions.end()) {
- iConditions->PrintCondition();
- *iConditions++;
- }
- } else {
- if (TestParam2 != 0L)
- cout << TestParam1->GetName() << " " << conditional << " " << TestParam2->GetName();
- else
- cout << TestParam1->GetName() << " " << conditional << " " << TestValue;
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGCondition::convert(void)
-{
- if (conditions.empty())
- cout << " " << property1 << " " << conditional << " " << property2 << endl;
- else
- for (int i; i<conditions.size(); i++) conditions[i].convert();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGCondition::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
-
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGCondition" << endl;
- if (from == 1) cout << "Destroyed: FGCondition" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-
-} //namespace JSBSim
-
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGCondition.h
- Author: Jon S. Berndt
- Date started: 1/02/2003
-
- ------------- Copyright (C) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGCONDITION_H
-#define FGCONDITION_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "../FGConfigFile.h"
-#include <map>
-#include "../FGPropertyManager.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_CONDITION "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Encapsulates a condition, which is used in parts of JSBSim including switches
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGCondition : public FGJSBBase
-{
-public:
- FGCondition(FGConfigFile* AC_cfg, FGPropertyManager* PropertyManager);
- ~FGCondition(void);
-
- bool Evaluate(void);
- void PrintCondition(void);
- void convert(void);
-
-private:
- FGConfigFile* AC_cfg;
-
- enum eComparison {ecUndef=0, eEQ, eNE, eGT, eGE, eLT, eLE};
- enum eLogic {elUndef=0, eAND, eOR};
- map <string, eComparison> mComparison;
- eLogic Logic;
-
- FGPropertyManager *TestParam1, *TestParam2, *PropertyManager;
- double TestValue;
- eComparison Comparison;
- bool isGroup;
- string conditional;
- string property1, property2;
-
- static string indent;
-
- vector <FGCondition> conditions;
-
- void Debug(int from);
-};
-}
-#endif
-
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGDeadBand.cpp
- Author: Jon S. Berndt
- Date started: 11/1999
-
- ------------- Copyright (C) 2000 -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-HISTORY
---------------------------------------------------------------------------------
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-COMMENTS, REFERENCES, and NOTES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "FGDeadBand.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_DEADBAND;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGDeadBand::FGDeadBand(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
- AC_cfg(AC_cfg)
-{
- Type = AC_cfg->GetValue("TYPE");
- Name = AC_cfg->GetValue("NAME");
- AC_cfg->GetNextConfigLine();
- string token;
-
- clipmax = clipmin = 0.0;
- clip = false;
- gain = 1.0;
- width = 0.0;
-
- while ((token = AC_cfg->GetValue()) != string("/COMPONENT")) {
- *AC_cfg >> token;
- if (token == "INPUT") {
- if (InputNodes.size() > 0) {
- cerr << "Deadband can only accept one input" << endl;
- } else {
- *AC_cfg >> token;
- InputNodes.push_back(resolveSymbol(token));
- }
- } else if (token == "WIDTH") {
- *AC_cfg >> width;
- } else if (token == "CLIPTO") {
- *AC_cfg >> clipmin >> clipmax;
- if (clipmax > clipmin) clip = true;
- } else if (token == "GAIN") {
- *AC_cfg >> gain;
- } else if (token == "OUTPUT") {
- *AC_cfg >> token;
- OutputNode = PropertyManager->GetNode(token);
- }
- }
- FGFCSComponent::bind();
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGDeadBand::~FGDeadBand()
-{
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGDeadBand::Run(void )
-{
- FGFCSComponent::Run(); // call the base class for initialization of Input
-
- Input = InputNodes[0]->getDoubleValue();
-
- if (Input < -width/2.0) {
- Output = (Input + width/2.0)*gain;
- } else if (Input > width/2.0) {
- Output = (Input - width/2.0)*gain;
- } else {
- Output = 0.0;
- }
-
- if (clip) {
- if (Output > clipmax) Output = clipmax;
- else if (Output < clipmin) Output = clipmin;
- }
-
- if (IsOutput) SetOutput();
-
- return true;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGDeadBand::convert(void)
-{
- cout << endl;
- cout << " <component name=\"" << Name << "\" type=\"" << Type << "\">" << endl;
-
- cout << " <input>" << (InputNodes[0]->GetFullyQualifiedName()).substr(12) << "</input>" << endl;
-
- if (gain != 1.0)
- cout << " <gain>" << gain << "</gain>" << endl;
-
- cout << " <width>" << width << "</width>" << endl;
-
- if (clip) {
- cout << " <clip>" << endl;
- cout << " <min>" << clipmin << "</min>" << endl;
- cout << " <max>" << clipmax << "</max>" << endl;
- cout << " </clip>" << endl;
- }
-
- if (IsOutput)
- cout << " <output>" << (OutputNode->GetFullyQualifiedName()).substr(12) << "</output>" << endl;
-
- cout << " </component>" << endl;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGDeadBand::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
- cout << " INPUT: " << InputNodes[0]->getName() << endl;
- cout << " DEADBAND WIDTH: " << width << endl;
- cout << " GAIN: " << gain << endl;
- if (clip) cout << " CLIPTO: " << clipmin
- << ", " << clipmax << endl;
- if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGDeadBand" << endl;
- if (from == 1) cout << "Destroyed: FGDeadBand" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGDeadBand.h
- Author:
- Date started:
-
- ------------- Copyright (C) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGDEADBAND_H
-#define FGDEADBAND_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGFCSComponent.h"
-#include "../FGConfigFile.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_DEADBAND "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-class FGFCS;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Models a deadband object.
- Here is the format of the deadband control specification:
- <pre>
- \<COMPONENT NAME="Deadbeat1" TYPE="DEADBAND">
- INPUT {input}
- WIDTH {deadband width}
- MIN {minimum value}
- MAX {maximum value}
- [GAIN {optional deadband gain}]
- [OUTPUT {optional output parameter to set}]
- \</COMPONENT>
- </pre>
- The WIDTH value is the total deadband region within which an input will
- produce no output. For example, say that the WIDTH value is 2.0. If the
- input is between -1.0 and +1.0, the output will be zero.
- @author Jon S. Berndt
- @version $Id$
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGDeadBand : public FGFCSComponent
-{
-public:
- FGDeadBand(FGFCS* fcs, FGConfigFile* AC_cfg);
- ~FGDeadBand();
-
- bool Run(void);
- void convert(void);
-
-private:
- FGConfigFile* AC_cfg;
- double width;
- double clipmax, clipmin;
- bool clip;
- double gain;
-
- void Debug(int from);
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-#endif
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGFCSComponent.cpp
- Author: Jon S. Berndt
- Date started: 11/1999
-
- ------------- Copyright (C) 2000 -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-HISTORY
---------------------------------------------------------------------------------
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-COMMENTS, REFERENCES, and NOTES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "FGFCSComponent.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_FCSCOMPONENT;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-FGFCSComponent::FGFCSComponent(FGFCS* _fcs) : fcs(_fcs)
-{
- Type = "";
- Input = 0.0;
- Output = 0.0;
- OutputNode = 0;
- IsOutput = false;
- PropertyManager=fcs->GetPropertyManager();
- treenode = 0;
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGFCSComponent::~FGFCSComponent()
-{
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGFCSComponent::SetOutput(void)
-{
- OutputNode->setDoubleValue(Output);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGFCSComponent::Run(void)
-{
- return true;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGPropertyManager* FGFCSComponent::resolveSymbol(string token)
-{
- string prop;
- FGPropertyManager* tmp = PropertyManager->GetNode(token,false);
- if (!tmp) {
- if (token.find("/") == token.npos) prop = "model/" + token;
- //cerr << "Creating new property " << prop << endl;
- tmp = PropertyManager->GetNode(token,true);
- }
- return tmp;
-}
-
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGFCSComponent::bind(void)
-{
- string tmp = "fcs/" + PropertyManager->mkPropertyName(Name, true);
- FGPropertyManager *tmpn;
- PropertyManager->Tie( tmp,this, &FGFCSComponent::GetOutput);
- tmp = "fcs/components/" + PropertyManager->mkPropertyName(Name, true);
- treenode = PropertyManager->GetNode( tmp, true );
- for(unsigned i=0;i<InputNodes.size();i++) {
- tmpn=treenode->GetNode( "input-property",(int)i,true );
- tmpn->setStringValue( InputNodes[i]->GetName().c_str() );
- }
- if(OutputNode) treenode->SetString("output-property",OutputNode->GetName());
- treenode->Tie("output-value",this,&FGFCSComponent::GetOutput);
- treenode->SetString("type",Type);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGFCSComponent::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGFCSComponent" << endl;
- if (from == 1) cout << "Destroyed: FGFCSComponent" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGFCSComponent.h
- Author: Jon S. Berndt
- Date started: 05/01/2000
-
- ------------- Copyright (C) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGFCSCOMPONENT_H
-#define FGFCSCOMPONENT_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef FGFS
-# include <simgear/compiler.h>
-#endif
-
-#include <string>
-#include <vector>
-#include "../FGJSBBase.h"
-#include "../FGPropertyManager.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_FCSCOMPONENT "$Id$"
-
-using std::string;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-class FGFCS;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Base class for JSBSim Flight Control System Components.
- The Flight Control System (FCS) for JSBSim consists of the FCS container
- class (see \URL[FGFCS]{FGFCS.html}), the FGFCSComponent base class, and the
- component classes from which can be constructed a string, or channel. See:
-
- - FGSwitch
- - FGGain
- - FGKinemat
- - FGFilter
- - FGDeadBand
- - FGSummer
- - FGGradient
-
- @author Jon S. Berndt
- @version $Id$
- @see Documentation for the FGFCS class, and for the configuration file class
- FGConfigFile.
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGFCSComponent : public FGJSBBase
-{
-public:
- /// Constructor
- FGFCSComponent(FGFCS*);
- /// Destructor
- virtual ~FGFCSComponent();
-
- virtual bool Run(void);
- virtual void SetOutput(void);
- inline double GetOutput (void) const {return Output;}
- inline FGPropertyManager* GetOutputNode(void) { return OutputNode; }
- inline string GetName(void) const {return Name;}
- inline string GetType(void) const { return Type; }
- virtual double GetOutputPct(void) const { return 0; }
- virtual void convert(void) {};
- virtual void bind();
- FGPropertyManager* resolveSymbol(string token);
-
-protected:
- FGFCS* fcs;
- FGPropertyManager* PropertyManager;
- FGPropertyManager* treenode;
- string Type;
- string Name;
- vector <FGPropertyManager*> InputNodes;
- vector <float> InputSigns;
- double Input;
- FGPropertyManager* OutputNode;
- double Output;
- bool IsOutput;
- virtual void Debug(int from);
-};
-
-} //namespace JSBSim
-
-#include "../FGFCS.h"
-
-#endif
-
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGFilter.cpp
- Author: Jon S. Berndt
- Date started: 11/2000
-
- ------------- Copyright (C) 2000 -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-HISTORY
---------------------------------------------------------------------------------
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-COMMENTS, REFERENCES, and NOTES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "FGFilter.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_FILTER;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-FGFilter::FGFilter(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
- AC_cfg(AC_cfg)
-{
- string token;
- double denom;
- string sOutputIdx;
-
- Type = AC_cfg->GetValue("TYPE");
- Name = AC_cfg->GetValue("NAME");
- AC_cfg->GetNextConfigLine();
- dt = fcs->GetState()->Getdt();
- Trigger = 0;
-
- C1 = C2 = C3 = C4 = C5 = C6 = 0.0;
-
- if (Type == "LAG_FILTER") FilterType = eLag ;
- else if (Type == "LEAD_LAG_FILTER") FilterType = eLeadLag ;
- else if (Type == "SECOND_ORDER_FILTER") FilterType = eOrder2 ;
- else if (Type == "WASHOUT_FILTER") FilterType = eWashout ;
- else if (Type == "INTEGRATOR") FilterType = eIntegrator ;
- else FilterType = eUnknown ;
-
- while ((token = AC_cfg->GetValue()) != string("/COMPONENT")) {
- *AC_cfg >> token;
- if (token == "C1") *AC_cfg >> C1;
- else if (token == "C2") *AC_cfg >> C2;
- else if (token == "C3") *AC_cfg >> C3;
- else if (token == "C4") *AC_cfg >> C4;
- else if (token == "C5") *AC_cfg >> C5;
- else if (token == "C6") *AC_cfg >> C6;
- else if (token == "TRIGGER")
- {
- token = AC_cfg->GetValue("TRIGGER");
- *AC_cfg >> token;
- Trigger = resolveSymbol(token);
- }
- else if (token == "INPUT")
- {
- token = AC_cfg->GetValue("INPUT");
- if( InputNodes.size() > 0 ) {
- cerr << "Filters can only accept one input" << endl;
- } else {
- *AC_cfg >> token;
- InputNodes.push_back( resolveSymbol(token) );
- }
- }
- else if (token == "OUTPUT")
- {
- IsOutput = true;
- *AC_cfg >> sOutputIdx;
- OutputNode = PropertyManager->GetNode( sOutputIdx );
- }
- else cerr << "Unknown filter type: " << token << endl;
- }
-
- Initialize = true;
-
- switch (FilterType) {
- case eLag:
- denom = 2.00 + dt*C1;
- ca = dt*C1 / denom;
- cb = (2.00 - dt*C1) / denom;
- break;
- case eLeadLag:
- denom = 2.00*C3 + dt*C4;
- ca = (2.00*C1 + dt*C2) / denom;
- cb = (dt*C2 - 2.00*C1) / denom;
- cc = (2.00*C3 - dt*C4) / denom;
- break;
- case eOrder2:
- denom = 4.0*C4 + 2.0*C5*dt + C6*dt*dt;
- ca = (4.0*C1 + 2.0*C2*dt + C3*dt*dt) / denom;
- cb = (2.0*C3*dt*dt - 8.0*C1) / denom;
- cc = (4.0*C1 - 2.0*C2*dt + C3*dt*dt) / denom;
- cd = (2.0*C6*dt*dt - 8.0*C4) / denom;
- ce = (4.0*C4 - 2.0*C5*dt + C6*dt*dt) / denom;
- break;
- case eWashout:
- denom = 2.00 + dt*C1;
- ca = 2.00 / denom;
- cb = (2.00 - dt*C1) / denom;
- break;
- case eIntegrator:
- ca = dt*C1 / 2.00;
- break;
- case eUnknown:
- cerr << "Unknown filter type" << endl;
- break;
- }
- FGFCSComponent::bind();
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGFilter::~FGFilter()
-{
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGFilter::Run(void)
-{
- int test = 0;
-
- FGFCSComponent::Run(); // call the base class for initialization of Input
-
- if (Initialize) {
-
- PreviousOutput1 = PreviousInput1 = Output = Input;
- Initialize = false;
-
- } else if (Trigger != 0) {
- test = Trigger->getIntValue();
- if (test < 0) {
- Input = PreviousInput1 = PreviousInput2 = 0.0;
- } else {
- Output = PreviousOutput1 = PreviousOutput2 = 0.0;
- }
-
- } else {
- Input = InputNodes[0]->getDoubleValue();
- switch (FilterType) {
- case eLag:
- Output = Input * ca + PreviousInput1 * ca + PreviousOutput1 * cb;
- break;
- case eLeadLag:
- Output = Input * ca + PreviousInput1 * cb + PreviousOutput1 * cc;
- break;
- case eOrder2:
- Output = Input * ca + PreviousInput1 * cb + PreviousInput2 * cc
- - PreviousOutput1 * cd - PreviousOutput2 * ce;
- break;
- case eWashout:
- Output = Input * ca - PreviousInput1 * ca + PreviousOutput1 * cb;
- break;
- case eIntegrator:
- Output = Input * ca + PreviousInput1 * ca + PreviousOutput1;
- break;
- case eUnknown:
- break;
- }
-
- }
-
- PreviousOutput2 = PreviousOutput1;
- PreviousOutput1 = Output;
- PreviousInput2 = PreviousInput1;
- PreviousInput1 = Input;
-
- if (IsOutput) SetOutput();
-
- return true;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGFilter::convert(void)
-{
- cout << endl;
- cout << " <component name=\"" << Name << "\" type=\"" << Type << "\">" << endl;
-
- cout << " <input>" << (InputNodes[0]->GetFullyQualifiedName()).substr(12) << "</input>" << endl;
-
- if (C1 != 0) cout << " <c1>" << C1 << "</c1>" << endl;
- if (C2 != 0) cout << " <c2>" << C2 << "</c2>" << endl;
- if (C3 != 0) cout << " <c3>" << C3 << "</c3>" << endl;
- if (C4 != 0) cout << " <c4>" << C4 << "</c4>" << endl;
- if (C5 != 0) cout << " <c5>" << C5 << "</c5>" << endl;
- if (C6 != 0) cout << " <c6>" << C6 << "</c6>" << endl;
-
- if (Trigger != 0) cout << " <trigger>" << Trigger << "</trigger>" << endl;
-
- if (IsOutput)
- cout << " <output>" << (OutputNode->GetFullyQualifiedName()).substr(12) << "</output>" << endl;
-
- cout << " </component>" << endl;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGFilter::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
- cout << " INPUT: " << InputNodes[0]->getName() << endl;
- cout << " C1: " << C1 << endl;
- cout << " C2: " << C2 << endl;
- cout << " C3: " << C3 << endl;
- cout << " C4: " << C4 << endl;
- cout << " C5: " << C5 << endl;
- cout << " C6: " << C6 << endl;
- if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGFilter" << endl;
- if (from == 1) cout << "Destroyed: FGFilter" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGFilter.h
- Author: Jon S. Berndt
- Date started: 4/2000
-
- ------------- Copyright (C) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGFILTER_H
-#define FGFILTER_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGFCSComponent.h"
-#include "../FGConfigFile.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_FILTER "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Encapsulates a filter for the flight control system.
-The filter component can simulate any filter up to second order. The
-Tustin substitution is used to take filter definitions from LaPlace space to the
-time domain. The general format for a filter specification is:
-
-<pre>
-\<COMPONENT NAME="name" TYPE="type">
- INPUT \<property>
- C1 \<value>
- [C2 \<value>]
- [C3 \<value>]
- [C4 \<value>]
- [C5 \<value>]
- [C6 \<value>]
- [OUTPUT \<property>]
-\</COMPONENT>
-</pre>
-
-For a lag filter of the form,
-<pre>
- C1
-------
-s + C1
-</pre>
-the corresponding filter definition is:
-<pre>
-\<COMPONENT NAME="name" TYPE="LAG_FILTER">
- INPUT \<property>
- C1 \<value>
- [OUTPUT \<property>]
-\</COMPONENT>
-</pre>
-As an example, for the specific filter:
-<pre>
- 600
-------
-s + 600
-</pre>
-the corresponding filter definition could be:
-<pre>
-\<COMPONENT NAME="LAG_1" TYPE="LAG_FILTER">
- INPUT aileron_cmd
- C1 600
-\</COMPONENT>
-</pre>
-For a lead-lag filter of the form:
-<pre>
-C1*s + C2
----------
-C3*s + C4
-</pre>
-The corresponding filter definition is:
-<pre>
-\<COMPONENT NAME="name" TYPE="LEAD_LAG_FILTER">
- INPUT \<property>
- C1 \<value>
- C2 \<value>
- C3 \<value>
- C4 \<value>
- [OUTPUT \<property>]
-\</COMPONENT>
-</pre>
-For a washout filter of the form:
-<pre>
- s
-------
-s + C1
-</pre>
-The corresponding filter definition is:
-<pre>
-\<COMPONENT NAME="name" TYPE="WASHOUT_FILTER">
- INPUT \<property>
- C1 \<value>
- [OUTPUT \<property>]
-\</COMPONENT>
-</pre>
-For a second order filter of the form:
-<pre>
-C1*s^2 + C2*s + C3
-------------------
-C4*s^2 + C5*s + C6
-</pre>
-The corresponding filter definition is:
-<pre>
-\<COMPONENT NAME="name" TYPE="SECOND_ORDER_FILTER">
- INPUT \<property>
- C1 \<value>
- C2 \<value>
- C3 \<value>
- C4 \<value>
- C5 \<value>
- C6 \<value>
- [OUTPUT \<property>]
-\</COMPONENT>
-</pre>
-For an integrator of the form:
-<pre>
- C1
- ---
- s
-</pre>
-The corresponding filter definition is:
-<pre>
-\<COMPONENT NAME="name" TYPE="INTEGRATOR">
- INPUT \<property>
- C1 \<value>
- [OUTPUT \<property>]
- [TRIGGER \<property>]
-\</COMPONENT>
-</pre>
-For the integrator, the TRIGGER features the following behavior, if the TRIGGER
-property value is:
- - -1 (or simply less than zero), all previous inputs and outputs are set to 0.0
- - 0, no action is taken - the output is calculated normally
- - +1 (or simply greater than zero), all previous outputs (only) will be set to 0.0
-
-In all the filter specifications above, an [OUTPUT] keyword is also seen. This
-is so that the last component in a "string" can copy its value to the appropriate
-output, such as the elevator, or speedbrake, etc.
-
-@author Jon S. Berndt
-@version $Id$
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGFilter : public FGFCSComponent
-{
-public:
- FGFilter(FGFCS* fcs, FGConfigFile* AC_cfg);
- ~FGFilter();
-
- bool Run (void);
-
- /** When true, causes previous values to be set to current values. This
- is particularly useful for first pass. */
- bool Initialize;
- void convert(void);
-
- enum {eLag, eLeadLag, eOrder2, eWashout, eIntegrator, eUnknown} FilterType;
-
-private:
- double dt;
- double ca;
- double cb;
- double cc;
- double cd;
- double ce;
- double C1;
- double C2;
- double C3;
- double C4;
- double C5;
- double C6;
- double PreviousInput1;
- double PreviousInput2;
- double PreviousOutput1;
- double PreviousOutput2;
- FGConfigFile* AC_cfg;
- FGPropertyManager* Trigger;
- void Debug(int from);
-};
-}
-#endif
-
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGGain.cpp
- Author: Jon S. Berndt
- Date started: 4/2000
-
- ------------- Copyright (C) 2000 -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-HISTORY
---------------------------------------------------------------------------------
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-COMMENTS, REFERENCES, and NOTES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "FGGain.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_GAIN;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-
-FGGain::FGGain(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
- AC_cfg(AC_cfg)
-{
- string token;
- string strScheduledBy;
- string sOutputIdx;
-
- State = fcs->GetState();
-
- Gain = 1.000;
- Rows = 0;
- Min = Max = 0.0;
- OutputPct = 0;
- invert = false;
- ScheduledBy = 0;
- clip = false;
- clipmin = clipmax = 0.0;
-
- Type = AC_cfg->GetValue("TYPE");
- Name = AC_cfg->GetValue("NAME");
- AC_cfg->GetNextConfigLine();
-
- while ((token = AC_cfg->GetValue()) != string("/COMPONENT")) {
- *AC_cfg >> token;
- if (token == "INPUT") {
- *AC_cfg >> token;
-
- if (token[0] == '-') {
- invert = true;
- token.erase(0,1);
- }
-
- if (InputNodes.size() > 0) {
- cerr << "Gains can only accept one input" << endl;
- } else {
- InputNodes.push_back( resolveSymbol(token) );
- }
-
- } else if (token == "GAIN") {
- *AC_cfg >> Gain;
- } else if (token == "MIN") {
- *AC_cfg >> Min;
- } else if (token == "MAX") {
- *AC_cfg >> Max;
- } else if (token == "CLIPTO") {
- *AC_cfg >> clipmin >> clipmax;
- if (clipmax > clipmin) {
- clip = true;
- }
- } else if (token == "INVERT") {
- invert = true;
- cerr << endl << "The INVERT keyword is being deprecated and will not be "
- "supported in the future. Please use a minus sign in front "
- "of an input property in the future." << endl << endl;
- } else if (token == "ROWS") {
- *AC_cfg >> Rows;
- Table = new FGTable(Rows);
- } else if (token == "SCHEDULED_BY") {
- token = AC_cfg->GetValue("SCHEDULED_BY");
- *AC_cfg >> strScheduledBy;
- ScheduledBy = PropertyManager->GetNode( strScheduledBy );
- } else if (token == "OUTPUT") {
- IsOutput = true;
- *AC_cfg >> sOutputIdx;
- OutputNode = PropertyManager->GetNode( sOutputIdx, true );
- } else {
- AC_cfg->ResetLineIndexToZero();
- *Table << *AC_cfg;
- }
- }
-
- FGFCSComponent::bind();
- if (Type == "AEROSURFACE_SCALE")
- treenode->Tie( "output-norm", this, &FGGain::GetOutputPct );
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGGain::~FGGain()
-{
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGGain::Run(void )
-{
- double SchedGain = 1.0;
- double LookupVal = 0;
-
- FGFCSComponent::Run(); // call the base class for initialization of Input
- Input = InputNodes[0]->getDoubleValue();
-
- if (invert) Input = -Input;
-
- if (Type == "PURE_GAIN") { // PURE_GAIN
-
- Output = Gain * Input;
-
- } else if (Type == "SCHEDULED_GAIN") { // SCHEDULED_GAIN
-
- LookupVal = ScheduledBy->getDoubleValue();
- SchedGain = Table->GetValue(LookupVal);
- Output = Gain * SchedGain * Input;
-
- } else if (Type == "AEROSURFACE_SCALE") { // AEROSURFACE_SCALE
-
- OutputPct = Input;
- if (Input >= 0.0) Output = Input * Max;
- else Output = Input * -Min;
- Output *= Gain;
-
- }
-
- if (clip) {
- if (Output > clipmax) Output = clipmax;
- else if (Output < clipmin) Output = clipmin;
- }
-
- if (IsOutput) SetOutput();
-
- return true;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGGain::convert(void)
-{
- cout << endl;
- cout << " <component name=\"" << Name << "\" type=\"" << Type << "\">" << endl;
-
- if (invert)
- cout << " <input>-" << (InputNodes[0]->GetFullyQualifiedName()).substr(12) << "</input>" << endl;
- else
- cout << " <input>" << (InputNodes[0]->GetFullyQualifiedName()).substr(12) << "</input>" << endl;
-
- if (Gain != 1.0)
- cout << " <gain>" << Gain << "</gain>" << endl;
-
- if (Type == "PURE_GAIN") { // PURE_GAIN
- } else if (Type == "SCHEDULED_GAIN") { // SCHEDULED_GAIN
- cout << " <table>" << endl;
- cout << " <independentVar>" << ScheduledBy->GetFullyQualifiedName().substr(12) << "</independentVar>" << endl;
- cout << " <tableData>" << endl;
- Table->Print(20);
- cout << " </tableData>" << endl;
- cout << " </table>" << endl;
- } else if (Type == "AEROSURFACE_SCALE") { // AEROSURFACE_SCALE
- cout << " <limit>" << endl;
- cout << " <min>" << Min << "</min>" << endl;
- cout << " <max>" << Max << "</max>" << endl;
- cout << " </limit>" << endl;
- }
-
- if (clip) {
- cout << " <clip>" << endl;
- cout << " <min>" << clipmin << "</min>" << endl;
- cout << " <max>" << clipmax << "</max>" << endl;
- cout << " </clip>" << endl;
- }
-
- if (IsOutput)
- cout << " <output>" << (OutputNode->GetFullyQualifiedName()).substr(12) << "</output>" << endl;
-
- cout << " </component>" << endl;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGGain::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
- if (invert)
- cout << " INPUT: -" << InputNodes[0]->getName() << endl;
- else
- cout << " INPUT: " << InputNodes[0]->getName() << endl;
-
- cout << " GAIN: " << Gain << endl;
- if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
- cout << " MIN: " << Min << endl;
- cout << " MAX: " << Max << endl;
- if (ScheduledBy != 0) {
- cout << " Scheduled by parameter: " << ScheduledBy->getName() << endl;
- Table->Print();
- }
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGGain" << endl;
- if (from == 1) cout << "Destroyed: FGGain" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGGain.h
- Author:
- Date started:
-
- ------------- Copyright (C) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGGAIN_H
-#define FGGAIN_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef FGFS
-# include <simgear/compiler.h>
-# include STL_STRING
- SG_USING_STD(string);
-#else
-# include <string>
-#endif
-
-#include "FGFCSComponent.h"
-#include "../FGConfigFile.h"
-#include "../FGTable.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_GAIN "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-class FGFCS;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Encapsulates a gain component for the flight control system.
- The gain component merely multiplies the input by a gain. The form of the
- gain component specification is:
- <pre>
- \<COMPONENT NAME="name" TYPE="PURE_GAIN">
- INPUT \<property>
- GAIN \<value>
- [OUTPUT \<property>]
- \</COMPONENT>
- </pre>
- Note: as is the case with the Summer component, the input property name may be
- immediately preceded by a minus sign to invert that signal.
-
- The scheduled gain component multiplies the input by a variable gain that is
- dependent on another property (such as qbar, altitude, etc.). The lookup
- mapping is in the form of a table. This kind of component might be used, for
- example, in a case where aerosurface deflection must only be commanded to
- acceptable settings - i.e at higher qbar the commanded elevator setting might
- be attenuated. The form of the scheduled gain component specification is:
- <pre>
- \<COMPONENT NAME="name" TYPE="SCHEDULED_GAIN">
- INPUT \<property>
- [GAIN \<value>]
- SCHEDULED_BY \<property>
- ROWS \<number_of_rows>
- \<lookup_value gain_value>
- ?
- [CLIPTO \<min> \<max> 1]
- [OUTPUT \<property>]
- \</COMPONENT>
- </pre>
- An overall GAIN may be supplied that is multiplicative with the scheduled gain.
-
- Note: as is the case with the Summer component, the input property name may
- be immediately preceded by a minus sign to invert that signal.
-
- Here is an example of a scheduled gain component specification:
- <pre>
- \<COMPONENT NAME="Pitch Scheduled Gain 1" TYPE="SCHEDULED_GAIN">
- INPUT fcs/pitch-gain-1
- GAIN 0.017
- SCHEDULED_BY fcs/elevator-pos-rad
- ROWS 22
- -0.68 -26.548
- -0.595 -20.513
- -0.51 -15.328
- -0.425 -10.993
- -0.34 -7.508
- -0.255 -4.873
- -0.17 -3.088
- -0.085 -2.153
- 0 -2.068
- 0.085 -2.833
- 0.102 -3.088
- 0.119 -3.377
- 0.136 -3.7
- 0.153 -4.057
- 0.17 -4.448
- 0.187 -4.873
- 0.272 -7.508
- 0.357 -10.993
- 0.442 -15.328
- 0.527 -20.513
- 0.612 -26.548
- 0.697 -33.433
- \</COMPONENT>
- </pre>
- In the example above, we see the utility of the overall GAIN value in
- effecting a degrees-to-radians conversion.
-
- The aerosurface scale component is a modified version of the simple gain
- component. The normal purpose
- for this component is to take control inputs that range from -1 to +1 or
- from 0 to +1 and scale them to match the expected inputs to a flight control
- system. For instance, the normal and expected ability of a pilot to push or
- pull on a control stick is about 50 pounds. The input to the pitch channelb
- lock diagram of a flight control system is in units of pounds. Yet, the
- joystick control input is usually in a range from -1 to +1. The form of the
- aerosurface scaling component specification is:
-<pre>
- \<COMPONENT NAME="name" TYPE="AEROSURFACE_SCALE">
- INPUT \<property>
- MIN \<value>
- MAX \<value>
- [GAIN \<value>]
- [OUTPUT \<property>]
- \</COMPONENT>
-</pre>
- Note: as is the case with the Summer component, the input property name may be
- immediately preceded by a minus sign to invert that signal.
-
- @author Jon S. Berndt
- @version $Id$
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGGain : public FGFCSComponent
-{
-public:
- FGGain(FGFCS* fcs, FGConfigFile* AC_cfg);
- ~FGGain();
-
- double GetOutputPct() const { return OutputPct; }
- void convert(void);
- bool Run (void);
-
-private:
- FGConfigFile* AC_cfg;
- FGTable* Table;
- FGState* State;
- double Gain;
- double Min, Max;
- double clipmin, clipmax;
- double OutputPct;
- bool invert, clip;
- int Rows;
- FGPropertyManager* ScheduledBy;
-
- void Debug(int from);
-};
-}
-#endif
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGGradient.cpp
- Author:
- Date started:
-
- ------------- Copyright (C) 2000 -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-HISTORY
---------------------------------------------------------------------------------
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-COMMENTS, REFERENCES, and NOTES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "FGGradient.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_GRADIENT;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-
-FGGradient::FGGradient(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
- AC_cfg(AC_cfg)
-{
- Type = AC_cfg->GetValue("TYPE");
- Name = AC_cfg->GetValue("NAME");
-
- FGFCSComponent::bind();
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGGradient::~FGGradient()
-{
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGGradient::Run(void )
-{
- FGFCSComponent::Run(); // call the base class for initialization of Input
-
- return true;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGGradient::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
-
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGGradient" << endl;
- if (from == 1) cout << "Destroyed: FGGradient" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGGradient.h
- Author:
- Date started:
-
- ------------- Copyright (C) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGGRADIENT_H
-#define FGGRADIENT_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGFCSComponent.h"
-#include "../FGConfigFile.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_GRADIENT "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-class FGFCS;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Encapsulates a gradient component for the flight control system.
- */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGGradient : public FGFCSComponent
-{
-public:
- FGGradient(FGFCS* fcs, FGConfigFile* AC_cfg);
- ~FGGradient();
-
- bool Run (void);
-
-private:
- FGConfigFile* AC_cfg;
- void Debug(int from);
-};
-}
-#endif
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGKinemat.cpp
- Author: Tony Peden, for flight control system authored by Jon S. Berndt
- Date started: 12/02/01
-
- ------------- Copyright (C) 2000 Anthony K. Peden -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-HISTORY
---------------------------------------------------------------------------------
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-COMMENTS, REFERENCES, and NOTES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include <math.h>
-#include <float.h>
-
-#include "FGKinemat.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_FLAPS;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-FGKinemat::FGKinemat(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
- AC_cfg(AC_cfg)
-{
- string token,sOutputIdx;
- double tmpDetent;
- double tmpTime;
-
- Detents.clear();
- TransitionTimes.clear();
-
- OutputPct=0;
- DoScale = true;
-
- Type = AC_cfg->GetValue("TYPE");
- Name = AC_cfg->GetValue("NAME");
- AC_cfg->GetNextConfigLine();
-
- while ((token = AC_cfg->GetValue()) != string("/COMPONENT")) {
- *AC_cfg >> token;
- if (token == "INPUT") {
- token = AC_cfg->GetValue("INPUT");
- if( InputNodes.size() > 0 ) {
- cerr << "Kinemat can only accept one input" << endl;
- } else {
- *AC_cfg >> token;
- InputNodes.push_back( resolveSymbol(token) );
- }
-
- } else if ( token == "DETENTS" ) {
- *AC_cfg >> NumDetents;
- if (NumDetents < 2) {
- cerr << "Kinemat must have at least 2 DETENTS" << endl;
- }
- for (int i=0;i<NumDetents;i++) {
- *AC_cfg >> tmpDetent;
- *AC_cfg >> tmpTime;
- Detents.push_back(tmpDetent);
- TransitionTimes.push_back(tmpTime);
- }
- } else if (token == "OUTPUT") {
-
- IsOutput = true;
- *AC_cfg >> sOutputIdx;
- OutputNode = PropertyManager->GetNode(sOutputIdx, true);
- } else if (token == "NOSCALE") {
-
- DoScale = false;
- }
- }
- FGFCSComponent::bind();
- treenode->Tie("output-norm", this, &FGKinemat::GetOutputPct );
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGKinemat::~FGKinemat()
-{
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGKinemat::Run(void )
-{
- double dt = fcs->GetState()->Getdt();
-
- Input = InputNodes[0]->getDoubleValue();
-
- if (DoScale) Input *= Detents[NumDetents-1];
-
- Output = OutputNode->getDoubleValue();
-
- if (Input < Detents[0])
- Input = Detents[0];
- else if (Detents[NumDetents-1] < Input)
- Input = Detents[NumDetents-1];
-
- // Process all detent intervals the movement traverses until either the
- // final value is reached or the time interval has finished.
- while ( 0.0 < dt && !EqualToRoundoff(Input, Output) ) {
-
- // Find the area where Output is in
- int ind;
- for (ind = 1; (Input < Output) ? Detents[ind] < Output : Detents[ind] <= Output ; ++ind)
- if (NumDetents <= ind)
- break;
-
- // A transition time of 0.0 means an infinite rate.
- // The output is reached in one step
- if (TransitionTimes[ind] <= 0.0) {
- Output = Input;
- break;
- } else {
- // Compute the rate in this area
- double Rate = (Detents[ind] - Detents[ind-1])/TransitionTimes[ind];
- // Compute the maximum input value inside this area
- double ThisInput = Input;
- if (ThisInput < Detents[ind-1]) ThisInput = Detents[ind-1];
- if (Detents[ind] < ThisInput) ThisInput = Detents[ind];
- // Compute the time to reach the value in ThisInput
- double ThisDt = fabs((ThisInput-Output)/Rate);
-
- // and clip to the timestep size
- if (dt < ThisDt) {
- ThisDt = dt;
- if (Output < Input)
- Output += ThisDt*Rate;
- else
- Output -= ThisDt*Rate;
- } else
- // Handle this case separate to make shure the termination condition
- // is met even in inexact arithmetics ...
- Output = ThisInput;
-
- dt -= ThisDt;
- }
- }
-
- OutputPct = (Output-Detents[0])/(Detents[NumDetents-1]-Detents[0]);
-
- if (IsOutput) SetOutput();
-
- return true;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGKinemat::convert(void)
-{
- cout << endl;
- cout << " <component name=\"" << Name << "\" type=\"" << Type << "\">" << endl;
-
- cout << " <input>" << (InputNodes[0]->GetFullyQualifiedName()).substr(12) << "</input>" << endl;
-
- cout << " <traverse>" << endl;
- for (int i=0; i<Detents.size(); i++) {
- cout << " <setting>" << endl;
- cout << " <position>" << Detents[i] << "</position>" << endl;
- cout << " <time>" << TransitionTimes[i] << "</time>" << endl;
- cout << " </setting>" << endl;
- }
- cout << " </traverse>" << endl;
-
- if (IsOutput)
- cout << " <output>" << (OutputNode->GetFullyQualifiedName()).substr(12) << "</output>" << endl;
-
- cout << " </component>" << endl;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGKinemat::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
- cout << " INPUT: " << InputNodes[0]->getName() << endl;
- cout << " DETENTS: " << NumDetents << endl;
- for (int i=0;i<NumDetents;i++) {
- cout << " " << Detents[i] << " " << TransitionTimes[i] << endl;
- }
- if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
- if (!DoScale) cout << " NOSCALE" << endl;
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGKinemat" << endl;
- if (from == 1) cout << "Destroyed: FGKinemat" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGKinemat.h
- Author: Tony Peden, for flight control system authored by Jon S. Berndt
- Date started: 12/02/01
-
- ------------- Copyright (C) Anthony K. Peden -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGKinemat_H
-#define FGKinemat_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef FGFS
-# include <simgear/compiler.h>
-# ifdef SG_HAVE_STD_INCLUDES
-# include <vector>
-# else
-# include <vector.h>
-# endif
-#else
-# include <vector>
-#endif
-
-#include <string>
-#include "FGFCSComponent.h"
-#include "../FGConfigFile.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_FLAPS "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Encapsulates a kinematic component for the flight control system.
- */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGKinemat : public FGFCSComponent {
-public:
- /** Initializer.
- @param fcs A reference to the ccurrent flightcontrolsystem.
- @param AC_cfg reference to the current aircraft configuration file.
- Initializes the FGKinemat object from the given configuration
- file. The Configuration file is expected to be at the stream
- position where the KINEMAT object starts. Also it is expected to
- be past the end of the current KINEMAT configuration on exit.
- */
- FGKinemat(FGFCS* fcs, FGConfigFile* AC_cfg);
-
- /** Destructor.
- */
- ~FGKinemat();
-
- /** Kinemat output value.
- @return the current output of the kinemat object on the range of [0,1].
- */
- double GetOutputPct() const { return OutputPct; }
-
- /** Run method, overwrites FGModel::Run().
- @return false on success, true on failure.
- The routine doing the work.
- */
- bool Run (void);
- void convert(void);
-
-private:
- FGConfigFile* AC_cfg;
- vector<double> Detents;
- vector<double> TransitionTimes;
- int NumDetents;
- double OutputPct;
- bool DoScale;
-
- void Debug(int from);
-};
-}
-#endif
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGSummer.cpp
- Author: Jon S. Berndt
- Date started: 4/2000
-
- ------------- Copyright (C) 2000 -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-HISTORY
---------------------------------------------------------------------------------
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-COMMENTS, REFERENCES, and NOTES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "FGSummer.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_SUMMER;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-
-FGSummer::FGSummer(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
- AC_cfg(AC_cfg)
-{
- string token,sOutputIdx;
-
- clip = false;
- clipmin = clipmax = 0.0;
- Bias = 0.0;
-
- Type = AC_cfg->GetValue("TYPE");
- Name = AC_cfg->GetValue("NAME");
- AC_cfg->GetNextConfigLine();
-
- while ((token = AC_cfg->GetValue()) != string("/COMPONENT")) {
- *AC_cfg >> token;
-
- if (token == "INPUT") {
- token = AC_cfg->GetValue("INPUT");
- *AC_cfg >> token;
-
- if (token[0] == '-') {
- InputSigns.push_back(-1.0);
- token.erase(0,1);
- } else {
- InputSigns.push_back( 1.0);
- }
-
- InputNodes.push_back( resolveSymbol(token) );
- } else if (token == "BIAS") {
- *AC_cfg >> Bias;
- } else if (token == "CLIPTO") {
- *AC_cfg >> clipmin >> clipmax;
- if (clipmax > clipmin) {
- clip = true;
- }
- } else if (token == "OUTPUT") {
- IsOutput = true;
- *AC_cfg >> sOutputIdx;
- OutputNode = PropertyManager->GetNode(sOutputIdx, true);
- }
- }
-
- FGFCSComponent::bind();
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGSummer::~FGSummer()
-{
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGSummer::Run(void )
-{
- unsigned int idx;
-
- // The Summer takes several inputs, so do not call the base class Run()
- // FGFCSComponent::Run();
-
- Output = 0.0;
-
- for (idx=0; idx<InputNodes.size(); idx++) {
- Output += InputNodes[idx]->getDoubleValue()*InputSigns[idx];
- }
-
- Output += Bias;
-
- if (clip) {
- if (Output > clipmax) Output = clipmax;
- else if (Output < clipmin) Output = clipmin;
- }
-
- if (IsOutput) SetOutput();
-
- return true;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGSummer::convert(void)
-{
- string sSign;
-
- cout << endl;
- cout << " <component name=\"" << Name << "\" type=\"" << Type << "\">" << endl;
-
- for (int i=0; i<InputNodes.size(); i++) {
- if (InputSigns[i] < 0.0) sSign = "-";
- else sSign = "";
- cout << " <input>" << sSign << (InputNodes[i]->GetFullyQualifiedName()).substr(12) << "</input>" << endl;
- }
-
- if (Bias != 0.0)
- cout << " <bias>" << Bias << "</bias>" << endl;
-
- if (clip) {
- cout << " <clip>" << endl;
- cout << " <min>" << clipmin << "</min>" << endl;
- cout << " <max>" << clipmax << "</max>" << endl;
- cout << " </clip>" << endl;
- }
-
- if (IsOutput)
- cout << " <output>" << (OutputNode->GetFullyQualifiedName()).substr(12) << "</output>" << endl;
-
- cout << " </component>" << endl;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGSummer::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
- cout << " INPUTS: " << endl;
- for (unsigned i=0;i<InputNodes.size();i++) {
- if (InputSigns[i] < 0)
- cout << " -" << InputNodes[i]->getName() << endl;
- else
- cout << " " << InputNodes[i]->getName() << endl;
- }
- if (Bias != 0.0) cout << " Bias: " << Bias << endl;
- if (clip) cout << " CLIPTO: " << clipmin
- << ", " << clipmax << endl;
- if (IsOutput) cout << " OUTPUT: " <<OutputNode->getName() << endl;
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGSummer" << endl;
- if (from == 1) cout << "Destroyed: FGSummer" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-
-} //namespace JSBSim
-
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGSummer.h
- Author:
- Date started:
-
- ------------- Copyright (C) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGSUMMER_H
-#define FGSUMMER_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef FGFS
-# include <simgear/compiler.h>
-# ifdef SG_HAVE_STD_INCLUDES
-# include <vector>
-# else
-# include <vector.h>
-# endif
-#else
-# include <vector>
-#endif
-
-#include <string>
-#include "FGFCSComponent.h"
-#include "../FGConfigFile.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_SUMMER "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Models a flight control system summing component.
- The Summer component sums two or more inputs. These can be pilot control
- inputs or state variables, and a bias can also be added in using the BIAS
- keyword. The form of the summer component specification is:
-<pre>
- \<COMPONENT NAME="name" TYPE="SUMMER">
- INPUT \<property>
- INPUT \<property>
- [BIAS \<value>]
- [?]
- [CLIPTO \<min> \<max> 1]
- [OUTPUT \<property>]
- \</COMPONENT>
-</pre>
- Note that in the case of an input property the property name may be
- immediately preceded by a minus sign. Here's an example of a summer
- component specification:
-<pre>
- \<COMPONENT NAME="Roll A/P Error summer" TYPE="SUMMER">
- INPUT velocities/p-rad_sec
- INPUT -fcs/roll-ap-wing-leveler
- INPUT fcs/roll-ap-error-integrator
- CLIPTO -1 1
- \</COMPONENT>
-</pre>
- Note that there can be only one BIAS statement per component.
-
- @author Jon S. Berndt
- @version $Id$
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGSummer : public FGFCSComponent
-{
-public:
- /** Constructor.
- @param fcs a pointer to the parent FGFCS object.
- @param AC_cfg a pointer to the configuration file object. */
- FGSummer(FGFCS* fcs, FGConfigFile* AC_cfg);
- /// Destructor
- ~FGSummer();
-
- /// The execution method for this FCS component.
- bool Run(void);
- void convert(void);
-
-private:
- FGConfigFile* AC_cfg;
- bool clip;
- double clipmin,clipmax;
- double Bias;
- void Debug(int from);
-};
-}
-#endif
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGSwitch.cpp
- Author: Jon S. Berndt
- Date started: 4/2000
-
- ------------- Copyright (C) 2000 -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-HISTORY
---------------------------------------------------------------------------------
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-COMMENTS, REFERENCES, and NOTES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-The SWITCH component is defined as follows (see the API documentation for more
-information):
-
-<COMPONENT NAME="switch1" TYPE="SWITCH">
- <TEST LOGIC="{AND|OR|DEFAULT}" OUTPUT="{property|value}">
- {property} {conditional} {property|value}
- <CONDITION_GROUP LOGIC="{AND|OR}">
- {property} {conditional} {property|value}
- ...
- </CONDITION_GROUP>
- ...
- </TEST>
- <TEST LOGIC="{AND|OR}" OUTPUT="{property|value}">
- {property} {conditional} {property|value}
- ...
- </TEST>
- ...
-</COMPONENT>
-
-Also, see the header file (FGSwitch.h) for further details.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef HAVE_CONFIG_H
-# include <config.h>
-#endif
-
-#include "FGSwitch.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_SWITCH;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-
-FGSwitch::FGSwitch(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
- AC_cfg(AC_cfg)
-{
- string token, value;
- struct test *current_test;
- string sOutputIdx;
-
- Type = AC_cfg->GetValue("TYPE");
- Name = AC_cfg->GetValue("NAME");
-
- AC_cfg->GetNextConfigLine();
- while ((token = AC_cfg->GetValue()) != string("/COMPONENT")) {
-
- // See the above documentation, or the API docs, for information on what
- // the SWITCH component is supposed to look like in the configuration file.
- // Below, the switch component is read in.
-
- if (token == "TEST") {
- tests.push_back(test());
- current_test = &tests.back();
-
- if (AC_cfg->GetValue("LOGIC") == "OR") {
- current_test->Logic = eOR;
- } else if (AC_cfg->GetValue("LOGIC") == "AND") {
- current_test->Logic = eAND;
- } else if (AC_cfg->GetValue("LOGIC") == "DEFAULT") {
- current_test->Logic = eDefault;
- } else { // error
- cerr << "Unrecognized LOGIC token in switch component: " << Name << endl;
- }
-
- value = AC_cfg->GetValue("VALUE");
- if (value.empty()) {
- cerr << "No VALUE supplied for switch component: " << Name << endl;
- } else {
- if (value.find_first_not_of("-.0123456789eE") == string::npos) {
- // if true (and execution falls into this block), "value" is a number.
- current_test->OutputVal = atof(value.c_str());
- } else {
- // "value" must be a property if execution passes to here.
- if (value[0] == '-') {
- current_test->sign = -1.0;
- value.erase(0,1);
- } else {
- current_test->sign = 1.0;
- }
- current_test->OutputProp = PropertyManager->GetNode(value);
- }
- }
-
- AC_cfg->GetNextConfigLine();
- while (AC_cfg->GetValue() != string("/TEST")) {
- current_test->conditions.push_back(FGCondition(AC_cfg, PropertyManager));
- }
- AC_cfg->GetNextConfigLine();
- } else if (token == "OUTPUT") {
- IsOutput = true;
- *AC_cfg >> sOutputIdx;
- *AC_cfg >> sOutputIdx;
- OutputNode = PropertyManager->GetNode( sOutputIdx, true );
- }
- }
-
- FGFCSComponent::bind();
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGSwitch::~FGSwitch()
-{
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGSwitch::Run(void )
-{
- vector <test>::iterator iTests = tests.begin();
- vector <FGCondition>::iterator iConditions;
- bool pass = false;
-
- FGFCSComponent::Run(); // call the base class for initialization of Input
-
- while (iTests < tests.end()) {
- iConditions = iTests->conditions.begin();
-
- if (iTests->Logic == eDefault) {
- Output = iTests->GetValue();
- } else if (iTests->Logic == eAND) {
- pass = true;
- while (iConditions < iTests->conditions.end()) {
- if (!iConditions->Evaluate()) pass = false;
- *iConditions++;
- }
- } else if (iTests->Logic == eOR) {
- pass = false;
- while (iConditions < iTests->conditions.end()) {
- if (iConditions->Evaluate()) pass = true;
- *iConditions++;
- }
- } else {
- cerr << "Invalid logic test" << endl;
- }
-
- if (pass) {
- Output = iTests->GetValue();
- break;
- }
- *iTests++;
- }
-
- if (IsOutput) SetOutput();
-
- return true;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGSwitch::convert(void)
-{
- cout << endl;
- cout << " <component name=\"" << Name << "\" type=\"" << Type << "\">" << endl;
-
-// cout << " <input>" << InputNodes[0]->GetName() << "</input>" << endl;
-
- for (int i=0; i<tests.size(); i++) {
- if (tests[i].Logic == eDefault) {
- if (tests[i].OutputProp == 0L)
- cout << " <default value=\"" << tests[i].OutputVal << "\"/>" << endl;
- else
- cout << " <default value=\"" << (tests[i].OutputProp->GetFullyQualifiedName()).substr(12) << "\"/>" << endl;
- } else if (tests[i].Logic == eAND) {
- if (tests[i].OutputProp == 0L)
- cout << " <test logic=\"AND\" value=\"" << tests[i].OutputVal << "\">" << endl;
- else
- cout << " <test logic=\"AND\" value=\"" << (tests[i].OutputProp->GetFullyQualifiedName()).substr(12) << "\">" << endl;
- } else if (tests[i].Logic == eOR) {
- if (tests[i].OutputProp == 0L)
- cout << " <test logic=\"OR\" value=\"" << tests[i].OutputVal << "\">" << endl;
- else
- cout << " <test logic=\"OR\" value=\"" << (tests[i].OutputProp->GetFullyQualifiedName()).substr(12) << "\">" << endl;
- }
- for (int j=0; j<tests[i].conditions.size(); j++) {
- tests[i].conditions[j].convert();
- }
- if (tests[i].Logic != eDefault) cout << " </test>" << endl;
- }
-
- if (IsOutput)
- cout << " <output>" << (OutputNode->GetFullyQualifiedName()).substr(12) << "</output>" << endl;
-
- cout << " </component>" << endl;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The bitmasked value choices are as follows:
-// unset: In this case (the default) JSBSim would only print
-// out the normally expected messages, essentially echoing
-// the config files as they are read. If the environment
-// variable is not set, debug_lvl is set to 1 internally
-// 0: This requests JSBSim not to output any messages
-// whatsoever.
-// 1: This value explicity requests the normal JSBSim
-// startup messages
-// 2: This value asks for a message to be printed out when
-// a class is instantiated
-// 4: When this value is set, a message is displayed when a
-// FGModel object executes its Run() method
-// 8: When this value is set, various runtime state variables
-// are printed out periodically
-// 16: When set various parameters are sanity checked and
-// a message is printed out when they go out of bounds
-
-void FGSwitch::Debug(int from)
-{
- vector <test>::iterator iTests = tests.begin();
- vector <FGCondition>::iterator iConditions;
- string comp, scratch;
- string indent = " ";
- bool first = false;
-
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
- while (iTests < tests.end()) {
-
- scratch = " if ";
-
- switch(iTests->Logic) {
- case (elUndef):
- comp = " UNSET ";
- cerr << "Unset logic for test condition" << endl;
- break;
- case (eAND):
- comp = " AND ";
- break;
- case (eOR):
- comp=" OR ";
- break;
- case (eDefault):
- scratch = " by default.";
- break;
- default:
- comp = " UNKNOWN ";
- cerr << "Unknown logic for test condition" << endl;
- }
-
- if (iTests->OutputProp != 0L)
- if (iTests->sign < 0)
- cout << indent << "Switch VALUE is - " << iTests->OutputProp->GetName() << scratch << endl;
- else
- cout << indent << "Switch VALUE is " << iTests->OutputProp->GetName() << scratch << endl;
- else
- cout << indent << "Switch VALUE is " << iTests->OutputVal << scratch << endl;
-
- iConditions = iTests->conditions.begin();
- first = true;
- while (iConditions < iTests->conditions.end()) {
- if (!first) cout << indent << comp << " ";
- else cout << indent << " ";
- first = false;
- iConditions->PrintCondition();
- cout << endl;
- *iConditions++;
- }
- cout << endl;
- *iTests++;
- }
- if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGSwitch" << endl;
- if (from == 1) cout << "Destroyed: FGSwitch" << endl;
- }
- if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
- }
- if (debug_lvl & 8 ) { // Runtime state variables
- }
- if (debug_lvl & 16) { // Sanity checking
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-
-} //namespace JSBSim
-
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGSwitch.h
- Author: Jon S. Berndt
- Date started: 12/23/2002
-
- ------------- Copyright (C) -------------
-
- This program is free software; you can redistribute it and/or modify it under
- the terms of the GNU General Public License as published by the Free Software
- Foundation; either version 2 of the License, or (at your option) any later
- version.
-
- This program is distributed in the hope that it will be useful, but WITHOUT
- ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public License along with
- this program; if not, write to the Free Software Foundation, Inc., 59 Temple
- Place - Suite 330, Boston, MA 02111-1307, USA.
-
- Further information about the GNU General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-HISTORY
---------------------------------------------------------------------------------
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGSWITCH_H
-#define FGSWITCH_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGFCSComponent.h"
-#include "../FGConfigFile.h"
-#include "FGCondition.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_SWITCH "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Encapsulates a switch for the flight control system.
-
-The SWITCH component models a switch - either on/off or a multi-choice rotary
-switch. The switch can represent a physical cockpit switch, or can represent a
-logical switch, where several conditions might need to be satisfied before a
-particular state is reached. The VALUE of the switch - the output value for the
-component - is chosen depending on the state of the switch. Each switch is
-comprised of two or more TESTs. Each TEST has a VALUE associated with it. The
-first TEST that evaluates to TRUE will set the output value of the switch
-according to the VALUE parameter belonging to that TEST. Each TEST contains one
-or more CONDITIONS, which each must be logically related (if there are more than
-one) given the value of the LOGIC parameter, and which takes the form:
-
- property conditional property|value
-
-e.g.
-
- qbar GE 21.0
-
-or,
-
- roll_rate < pitch_rate
-
-Within a TEST, a CONDITION_GROUP can be specified. A CONDITION_GROUP allows for
-complex groupings of logical comparisons. Each CONDITION_GROUP contains
-additional conditions, as well as possibly additional CONDITION_GROUPs.
-
-<pre>
-\<COMPONENT NAME="switch1" TYPE="SWITCH"\>
- \<TEST LOGIC="{AND|OR|DEFAULT}" VALUE="{property|value}"\>
- {property} {conditional} {property|value}
- \<CONDITION_GROUP LOGIC="{AND|OR}"\>
- {property} {conditional} {property|value}
- ...
- \</CONDITION_GROUP\>
- ...
- \</TEST>
- \<TEST LOGIC="{AND|OR}" VALUE="{property|value}"\>
- {property} {conditional} {property|value}
- ...
- \</TEST\>
- ...
- [OUTPUT \<property>]
-\</COMPONENT\>
-</pre>
-
-Here's an example:
-<pre>
-\<COMPONENT NAME="Roll A/P Autoswitch" TYPE="SWITCH">
- \<TEST LOGIC="DEFAULT" VALUE="0.0">
- \</TEST>
- \<TEST LOGIC="AND" VALUE="fcs/roll-ap-error-summer">
- ap/attitude_hold == 1
- \</TEST>
-\</COMPONENT>
-</pre>
-The above example specifies that the default value of the component (i.e. the
-output property of the component, addressed by the property, ap/roll-ap-autoswitch)
-is 0.0. If or when the attitude hold switch is selected (property
-ap/attitude_hold takes the value 1), the value of the switch component will be
-whatever value fcs/roll-ap-error-summer is.
-@author Jon S. Berndt
-@version $Id$
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGSwitch : public FGFCSComponent
-{
-public:
- FGSwitch(FGFCS* fcs, FGConfigFile* AC_cfg);
- ~FGSwitch();
-
- bool Run(void);
- void convert(void);
-
- enum eLogic {elUndef=0, eAND, eOR, eDefault};
- enum eComparison {ecUndef=0, eEQ, eNE, eGT, eGE, eLT, eLE};
-
-private:
- FGFCS* fcs;
- FGConfigFile* AC_cfg;
-
- struct test {
- vector <FGCondition> conditions;
- eLogic Logic;
- double OutputVal;
- FGPropertyManager *OutputProp;
- float sign;
-
- double GetValue(void) {
- if (OutputProp == 0L) return OutputVal;
- else return OutputProp->getDoubleValue()*sign;
- }
-
- test(void) { // constructor for the test structure
- Logic = elUndef;
- OutputVal = 0.0;
- OutputProp = 0L;
- sign = 1.0;
- }
-
- };
-
- vector <test> tests;
-
- void Debug(int from);
-};
-}
-#endif
--- /dev/null
+/*******************************************************************************
+
+ Header: FGInitialCondition.cpp
+ Author: Tony Peden
+ Date started: 7/1/99
+
+ ------------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+
+ HISTORY
+--------------------------------------------------------------------------------
+7/1/99 TP Created
+
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+The purpose of this class is to take a set of initial conditions and provide
+a kinematically consistent set of body axis velocity components, euler
+angles, and altitude. This class does not attempt to trim the model i.e.
+the sim will most likely start in a very dynamic state (unless, of course,
+you have chosen your IC's wisely) even after setting it up with this class.
+
+********************************************************************************
+INCLUDES
+*******************************************************************************/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# ifdef SG_HAVE_STD_INCLUDES
+# include <fstream>
+# else
+# include <fstream.h>
+# endif
+#else
+# if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
+# include <fstream.h>
+# else
+# include <fstream>
+# endif
+#endif
+
+#include "FGInitialCondition.h"
+#include <FGFDMExec.h>
+#include <models/FGInertial.h>
+#include <models/FGAtmosphere.h>
+#include <models/FGAerodynamics.h>
+#include <models/FGPropagate.h>
+#include <input_output/FGPropertyManager.h>
+#include <models/FGPropulsion.h>
+#include <input_output/FGXMLParse.h>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_INITIALCONDITION;
+
+//******************************************************************************
+
+FGInitialCondition::FGInitialCondition(FGFDMExec *FDMExec)
+{
+ vt=vc=ve=vg=0;
+ mach=0;
+ alpha=beta=gamma=0;
+ theta=phi=psi=0;
+ altitude=hdot=0;
+ latitude=longitude=0;
+ u=v=w=0;
+ p=q=r=0;
+ uw=vw=ww=0;
+ vnorth=veast=vdown=0;
+ wnorth=weast=wdown=0;
+ whead=wcross=0;
+ wdir=wmag=0;
+ lastSpeedSet=setvt;
+ lastWindSet=setwned;
+ sea_level_radius = FDMExec->GetInertial()->RefRadius();
+ radius_to_vehicle = FDMExec->GetInertial()->RefRadius();
+ terrain_altitude = 0;
+
+ salpha=sbeta=stheta=sphi=spsi=sgamma=0;
+ calpha=cbeta=ctheta=cphi=cpsi=cgamma=1;
+
+ if(FDMExec != NULL ) {
+ fdmex=FDMExec;
+ fdmex->GetPropagate()->Seth(altitude);
+ fdmex->GetAtmosphere()->Run();
+ PropertyManager=fdmex->GetPropertyManager();
+ bind();
+ } else {
+ cout << "FGInitialCondition: This class requires a pointer to a valid FGFDMExec object" << endl;
+ }
+
+ Debug(0);
+}
+
+//******************************************************************************
+
+FGInitialCondition::~FGInitialCondition()
+{
+ unbind();
+ Debug(1);
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetVcalibratedKtsIC(double tt) {
+
+ if(getMachFromVcas(&mach,tt*ktstofps)) {
+ //cout << "Mach: " << mach << endl;
+ lastSpeedSet=setvc;
+ vc=tt*ktstofps;
+ vt=mach*fdmex->GetAtmosphere()->GetSoundSpeed();
+ ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
+ //cout << "Vt: " << vt*fpstokts << " Vc: " << vc*fpstokts << endl;
+ }
+ else {
+ cout << "Failed to get Mach number for given Vc and altitude, Vc unchanged." << endl;
+ cout << "Please mail the set of initial conditions used to apeden@earthlink.net" << endl;
+ }
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetVequivalentKtsIC(double tt) {
+ ve=tt*ktstofps;
+ lastSpeedSet=setve;
+ vt=ve*1/sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
+ mach=vt/fdmex->GetAtmosphere()->GetSoundSpeed();
+ vc=calcVcas(mach);
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetVgroundFpsIC(double tt) {
+ double ua,va,wa;
+ double vxz;
+
+ vg=tt;
+ lastSpeedSet=setvg;
+ vnorth = vg*cos(psi); veast = vg*sin(psi); vdown = 0;
+ calcUVWfromNED();
+ ua = u + uw; va = v + vw; wa = w + ww;
+ vt = sqrt( ua*ua + va*va + wa*wa );
+ alpha = beta = 0;
+ vxz = sqrt( u*u + w*w );
+ if( w != 0 ) alpha = atan2( w, u );
+ if( vxz != 0 ) beta = atan2( v, vxz );
+ mach=vt/fdmex->GetAtmosphere()->GetSoundSpeed();
+ vc=calcVcas(mach);
+ ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetVtrueFpsIC(double tt) {
+ vt=tt;
+ lastSpeedSet=setvt;
+ mach=vt/fdmex->GetAtmosphere()->GetSoundSpeed();
+ vc=calcVcas(mach);
+ ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetMachIC(double tt) {
+ mach=tt;
+ lastSpeedSet=setmach;
+ vt=mach*fdmex->GetAtmosphere()->GetSoundSpeed();
+ vc=calcVcas(mach);
+ ve=vt*sqrt(fdmex->GetAtmosphere()->GetDensityRatio());
+ //cout << "Vt: " << vt*fpstokts << " Vc: " << vc*fpstokts << endl;
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetClimbRateFpmIC(double tt) {
+ SetClimbRateFpsIC(tt/60.0);
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetClimbRateFpsIC(double tt) {
+
+ if(vt > 0.1) {
+ hdot=tt;
+ gamma=asin(hdot/vt);
+ sgamma=sin(gamma); cgamma=cos(gamma);
+ }
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetFlightPathAngleRadIC(double tt) {
+ gamma=tt;
+ sgamma=sin(gamma); cgamma=cos(gamma);
+ getTheta();
+ hdot=vt*sgamma;
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetAlphaRadIC(double tt) {
+ alpha=tt;
+ salpha=sin(alpha); calpha=cos(alpha);
+ getTheta();
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetPitchAngleRadIC(double tt) {
+ theta=tt;
+ stheta=sin(theta); ctheta=cos(theta);
+ getAlpha();
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetBetaRadIC(double tt) {
+ beta=tt;
+ sbeta=sin(beta); cbeta=cos(beta);
+ getTheta();
+
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetRollAngleRadIC(double tt) {
+ phi=tt;
+ sphi=sin(phi); cphi=cos(phi);
+ getTheta();
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetTrueHeadingRadIC(double tt) {
+ psi=tt;
+ spsi=sin(psi); cpsi=cos(psi);
+ calcWindUVW();
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetUBodyFpsIC(double tt) {
+ u=tt;
+ vt=sqrt(u*u + v*v + w*w);
+ lastSpeedSet=setuvw;
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetVBodyFpsIC(double tt) {
+ v=tt;
+ vt=sqrt(u*u + v*v + w*w);
+ lastSpeedSet=setuvw;
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetWBodyFpsIC(double tt) {
+ w=tt;
+ vt=sqrt( u*u + v*v + w*w );
+ lastSpeedSet=setuvw;
+}
+
+//******************************************************************************
+
+double FGInitialCondition::GetUBodyFpsIC(void) const {
+ if(lastSpeedSet == setvg )
+ return u;
+ else
+ return vt*calpha*cbeta - uw;
+}
+
+//******************************************************************************
+
+double FGInitialCondition::GetVBodyFpsIC(void) const {
+ if( lastSpeedSet == setvg )
+ return v;
+ else {
+ return vt*sbeta - vw;
+ }
+}
+
+//******************************************************************************
+
+double FGInitialCondition::GetWBodyFpsIC(void) const {
+ if( lastSpeedSet == setvg )
+ return w;
+ else
+ return vt*salpha*cbeta -ww;
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetWindNEDFpsIC(double wN, double wE, double wD ) {
+ wnorth = wN; weast = wE; wdown = wD;
+ lastWindSet = setwned;
+ calcWindUVW();
+ if(lastSpeedSet == setvg)
+ SetVgroundFpsIC(vg);
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetCrossWindKtsIC(double cross){
+ wcross=cross*ktstofps;
+ lastWindSet=setwhc;
+ calcWindUVW();
+ if(lastSpeedSet == setvg)
+ SetVgroundFpsIC(vg);
+
+}
+
+//******************************************************************************
+
+// positive from left
+void FGInitialCondition::SetHeadWindKtsIC(double head){
+ whead=head*ktstofps;
+ lastWindSet=setwhc;
+ calcWindUVW();
+ if(lastSpeedSet == setvg)
+ SetVgroundFpsIC(vg);
+
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetWindDownKtsIC(double wD) {
+ wdown=wD;
+ calcWindUVW();
+ if(lastSpeedSet == setvg)
+ SetVgroundFpsIC(vg);
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetWindMagKtsIC(double mag) {
+ wmag=mag*ktstofps;
+ lastWindSet=setwmd;
+ calcWindUVW();
+ if(lastSpeedSet == setvg)
+ SetVgroundFpsIC(vg);
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetWindDirDegIC(double dir) {
+ wdir=dir*degtorad;
+ lastWindSet=setwmd;
+ calcWindUVW();
+ if(lastSpeedSet == setvg)
+ SetVgroundFpsIC(vg);
+}
+
+
+//******************************************************************************
+
+void FGInitialCondition::calcWindUVW(void) {
+
+ switch(lastWindSet) {
+ case setwmd:
+ wnorth=wmag*cos(wdir);
+ weast=wmag*sin(wdir);
+ break;
+ case setwhc:
+ wnorth=whead*cos(psi) + wcross*cos(psi+M_PI/2);
+ weast=whead*sin(psi) + wcross*sin(psi+M_PI/2);
+ break;
+ case setwned:
+ break;
+ }
+ uw=wnorth*ctheta*cpsi +
+ weast*ctheta*spsi -
+ wdown*stheta;
+ vw=wnorth*( sphi*stheta*cpsi - cphi*spsi ) +
+ weast*( sphi*stheta*spsi + cphi*cpsi ) +
+ wdown*sphi*ctheta;
+ ww=wnorth*(cphi*stheta*cpsi + sphi*spsi) +
+ weast*(cphi*stheta*spsi - sphi*cpsi) +
+ wdown*cphi*ctheta;
+
+
+ /* cout << "FGInitialCondition::calcWindUVW: wnorth, weast, wdown "
+ << wnorth << ", " << weast << ", " << wdown << endl;
+ cout << "FGInitialCondition::calcWindUVW: theta, phi, psi "
+ << theta << ", " << phi << ", " << psi << endl;
+ cout << "FGInitialCondition::calcWindUVW: uw, vw, ww "
+ << uw << ", " << vw << ", " << ww << endl; */
+
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetAltitudeFtIC(double tt) {
+ altitude=tt;
+ fdmex->GetPropagate()->Seth(altitude);
+ fdmex->GetAtmosphere()->Run();
+ //lets try to make sure the user gets what they intended
+
+ switch(lastSpeedSet) {
+ case setned:
+ case setuvw:
+ case setvt:
+ SetVtrueKtsIC(vt*fpstokts);
+ break;
+ case setvc:
+ SetVcalibratedKtsIC(vc*fpstokts);
+ break;
+ case setve:
+ SetVequivalentKtsIC(ve*fpstokts);
+ break;
+ case setmach:
+ SetMachIC(mach);
+ break;
+ case setvg:
+ SetVgroundFpsIC(vg);
+ break;
+ }
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetAltitudeAGLFtIC(double tt) {
+ SetAltitudeFtIC(terrain_altitude + tt);
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetSeaLevelRadiusFtIC(double tt) {
+ sea_level_radius = tt;
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetTerrainAltitudeFtIC(double tt) {
+ terrain_altitude=tt;
+}
+
+//******************************************************************************
+
+void FGInitialCondition::calcUVWfromNED(void) {
+ u=vnorth*ctheta*cpsi +
+ veast*ctheta*spsi -
+ vdown*stheta;
+ v=vnorth*( sphi*stheta*cpsi - cphi*spsi ) +
+ veast*( sphi*stheta*spsi + cphi*cpsi ) +
+ vdown*sphi*ctheta;
+ w=vnorth*( cphi*stheta*cpsi + sphi*spsi ) +
+ veast*( cphi*stheta*spsi - sphi*cpsi ) +
+ vdown*cphi*ctheta;
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetVnorthFpsIC(double tt) {
+ vnorth=tt;
+ calcUVWfromNED();
+ vt=sqrt(u*u + v*v + w*w);
+ lastSpeedSet=setned;
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetVeastFpsIC(double tt) {
+ veast=tt;
+ calcUVWfromNED();
+ vt=sqrt(u*u + v*v + w*w);
+ lastSpeedSet=setned;
+}
+
+//******************************************************************************
+
+void FGInitialCondition::SetVdownFpsIC(double tt) {
+ vdown=tt;
+ calcUVWfromNED();
+ vt=sqrt(u*u + v*v + w*w);
+ SetClimbRateFpsIC(-1*vdown);
+ lastSpeedSet=setned;
+}
+
+//******************************************************************************
+
+bool FGInitialCondition::getMachFromVcas(double *Mach,double vcas) {
+
+ bool result=false;
+ double guess=1.5;
+ xlo=xhi=0;
+ xmin=0;xmax=50;
+ sfunc=&FGInitialCondition::calcVcas;
+ if(findInterval(vcas,guess)) {
+ if(solve(&mach,vcas))
+ result=true;
+ }
+ return result;
+}
+
+//******************************************************************************
+
+bool FGInitialCondition::getAlpha(void) {
+ bool result=false;
+ double guess=theta-gamma;
+
+ if(vt < 0.01) return 0;
+
+ xlo=xhi=0;
+ xmin=fdmex->GetAerodynamics()->GetAlphaCLMin();
+ xmax=fdmex->GetAerodynamics()->GetAlphaCLMax();
+ sfunc=&FGInitialCondition::GammaEqOfAlpha;
+ if(findInterval(0,guess)){
+ if(solve(&alpha,0)){
+ result=true;
+ salpha=sin(alpha);
+ calpha=cos(alpha);
+ }
+ }
+ calcWindUVW();
+ return result;
+}
+
+//******************************************************************************
+
+bool FGInitialCondition::getTheta(void) {
+ bool result=false;
+ double guess=alpha+gamma;
+
+ if(vt < 0.01) return 0;
+
+ xlo=xhi=0;
+ xmin=-89;xmax=89;
+ sfunc=&FGInitialCondition::GammaEqOfTheta;
+ if(findInterval(0,guess)){
+ if(solve(&theta,0)){
+ result=true;
+ stheta=sin(theta);
+ ctheta=cos(theta);
+ }
+ }
+ calcWindUVW();
+ return result;
+}
+
+//******************************************************************************
+
+double FGInitialCondition::GammaEqOfTheta(double Theta) {
+ double a,b,c;
+ double sTheta,cTheta;
+
+ //theta=Theta; stheta=sin(theta); ctheta=cos(theta);
+ sTheta=sin(Theta); cTheta=cos(Theta);
+ calcWindUVW();
+ a=wdown + vt*calpha*cbeta + uw;
+ b=vt*sphi*sbeta + vw*sphi;
+ c=vt*cphi*salpha*cbeta + ww*cphi;
+ return vt*sgamma - ( a*sTheta - (b+c)*cTheta);
+}
+
+//******************************************************************************
+
+double FGInitialCondition::GammaEqOfAlpha(double Alpha) {
+ double a,b,c;
+ double sAlpha,cAlpha;
+ sAlpha=sin(Alpha); cAlpha=cos(Alpha);
+ a=wdown + vt*cAlpha*cbeta + uw;
+ b=vt*sphi*sbeta + vw*sphi;
+ c=vt*cphi*sAlpha*cbeta + ww*cphi;
+
+ return vt*sgamma - ( a*stheta - (b+c)*ctheta );
+}
+
+//******************************************************************************
+
+double FGInitialCondition::calcVcas(double Mach) {
+
+ double p=fdmex->GetAtmosphere()->GetPressure();
+ double psl=fdmex->GetAtmosphere()->GetPressureSL();
+ double rhosl=fdmex->GetAtmosphere()->GetDensitySL();
+ double pt,A,B,D,vcas;
+ if(Mach < 0) Mach=0;
+ if(Mach < 1) //calculate total pressure assuming isentropic flow
+ pt=p*pow((1 + 0.2*Mach*Mach),3.5);
+ else {
+ // shock in front of pitot tube, we'll assume its normal and use
+ // the Rayleigh Pitot Tube Formula, i.e. the ratio of total
+ // pressure behind the shock to the static pressure in front
+
+
+ //the normal shock assumption should not be a bad one -- most supersonic
+ //aircraft place the pitot probe out front so that it is the forward
+ //most point on the aircraft. The real shock would, of course, take
+ //on something like the shape of a rounded-off cone but, here again,
+ //the assumption should be good since the opening of the pitot probe
+ //is very small and, therefore, the effects of the shock curvature
+ //should be small as well. AFAIK, this approach is fairly well accepted
+ //within the aerospace community
+
+ B = 5.76*Mach*Mach/(5.6*Mach*Mach - 0.8);
+
+ // The denominator above is zero for Mach ~ 0.38, for which
+ // we'll never be here, so we're safe
+
+ D = (2.8*Mach*Mach-0.4)*0.4167;
+ pt = p*pow(B,3.5)*D;
+ }
+
+ A = pow(((pt-p)/psl+1),0.28571);
+ vcas = sqrt(7*psl/rhosl*(A-1));
+ //cout << "calcVcas: vcas= " << vcas*fpstokts << " mach= " << Mach << " pressure: " << pt << endl;
+ return vcas;
+}
+
+//******************************************************************************
+
+bool FGInitialCondition::findInterval(double x,double guess) {
+ //void find_interval(inter_params &ip,eqfunc f,double y,double constant, int &flag){
+
+ int i=0;
+ bool found=false;
+ double flo,fhi,fguess;
+ double lo,hi,step;
+ step=0.1;
+ fguess=(this->*sfunc)(guess)-x;
+ lo=hi=guess;
+ do {
+ step=2*step;
+ lo-=step;
+ hi+=step;
+ if(lo < xmin) lo=xmin;
+ if(hi > xmax) hi=xmax;
+ i++;
+ flo=(this->*sfunc)(lo)-x;
+ fhi=(this->*sfunc)(hi)-x;
+ if(flo*fhi <=0) { //found interval with root
+ found=true;
+ if(flo*fguess <= 0) { //narrow interval down a bit
+ hi=lo+step; //to pass solver interval that is as
+ //small as possible
+ }
+ else if(fhi*fguess <= 0) {
+ lo=hi-step;
+ }
+ }
+ //cout << "findInterval: i=" << i << " Lo= " << lo << " Hi= " << hi << endl;
+ }
+ while((found == 0) && (i <= 100));
+ xlo=lo;
+ xhi=hi;
+ return found;
+}
+
+//******************************************************************************
+
+bool FGInitialCondition::solve(double *y,double x)
+{
+ double x1,x2,x3,f1,f2,f3,d,d0;
+ double eps=1E-5;
+ double const relax =0.9;
+ int i;
+ bool success=false;
+
+ //initializations
+ d=1;
+ x2 = 0;
+ x1=xlo;x3=xhi;
+ f1=(this->*sfunc)(x1)-x;
+ f3=(this->*sfunc)(x3)-x;
+ d0=fabs(x3-x1);
+
+ //iterations
+ i=0;
+ while ((fabs(d) > eps) && (i < 100)) {
+ d=(x3-x1)/d0;
+ x2 = x1-d*d0*f1/(f3-f1);
+
+ f2=(this->*sfunc)(x2)-x;
+ //cout << "solve x1,x2,x3: " << x1 << "," << x2 << "," << x3 << endl;
+ //cout << " " << f1 << "," << f2 << "," << f3 << endl;
+
+ if(fabs(f2) <= 0.001) {
+ x1=x3=x2;
+ } else if(f1*f2 <= 0.0) {
+ x3=x2;
+ f3=f2;
+ f1=relax*f1;
+ } else if(f2*f3 <= 0) {
+ x1=x2;
+ f1=f2;
+ f3=relax*f3;
+ }
+ //cout << i << endl;
+ i++;
+ }//end while
+ if(i < 100) {
+ success=true;
+ *y=x2;
+ }
+
+ //cout << "Success= " << success << " Vcas: " << vcas*fpstokts << " Mach: " << x2 << endl;
+ return success;
+}
+
+//******************************************************************************
+
+double FGInitialCondition::GetWindDirDegIC(void) {
+ if(weast != 0.0)
+ return atan2(weast,wnorth)*radtodeg;
+ else if(wnorth > 0)
+ return 0.0;
+ else
+ return 180.0;
+}
+
+//******************************************************************************
+
+bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
+{
+ string resetDef, acpath;
+ ifstream initialization_file;
+ FGXMLParse initialization_file_parser;
+ Element *document, *el;
+ int n;
+
+ string sep = "/";
+# ifdef macintosh
+ string sep = ";";
+# endif
+
+ if( useStoredPath ) {
+ acpath = fdmex->GetAircraftPath() + sep + fdmex->GetModelName();
+ resetDef = acpath + sep + rstfile + ".xml";
+ } else {
+ resetDef = rstfile;
+ }
+
+ initialization_file.open(resetDef.c_str());
+ if ( !initialization_file.is_open()) {
+ cerr << "Could not open initialization file: " << resetDef << endl;
+ return false;
+ }
+
+ readXML(initialization_file, initialization_file_parser);
+ document = initialization_file_parser.GetDocument(); // document holds the
+ // initialization description
+ if (document->GetName() != string("initialize")) {
+ cerr << "File: " << resetDef << " is not a reset file" << endl;
+ exit(-1);
+ }
+
+ if (document->FindElement("ubody"))
+ SetUBodyFpsIC(document->FindElementValueAsNumberConvertTo("ubody", "FT/SEC"));
+ if (document->FindElement("vbody"))
+ SetVBodyFpsIC(document->FindElementValueAsNumberConvertTo("vbody", "FT/SEC"));
+ if (document->FindElement("wbody"))
+ SetWBodyFpsIC(document->FindElementValueAsNumberConvertTo("wbody", "FT/SEC"));
+ if (document->FindElement("latitude"))
+ SetLatitudeDegIC(document->FindElementValueAsNumberConvertTo("latitude", "DEG"));
+ if (document->FindElement("longitude"))
+ SetLongitudeDegIC(document->FindElementValueAsNumberConvertTo("longitude", "DEG"));
+ if (document->FindElement("phi"))
+ SetRollAngleDegIC(document->FindElementValueAsNumberConvertTo("phi", "DEG"));
+ if (document->FindElement("theta"))
+ SetPitchAngleDegIC(document->FindElementValueAsNumberConvertTo("theta", "DEG"));
+ if (document->FindElement("psi"))
+ SetTrueHeadingDegIC(document->FindElementValueAsNumberConvertTo("psi", "DEG"));
+ if (document->FindElement("alpha"))
+ SetAlphaDegIC(document->FindElementValueAsNumberConvertTo("alpha", "DEG"));
+ if (document->FindElement("beta"))
+ SetBetaDegIC(document->FindElementValueAsNumberConvertTo("beta", "DEG"));
+ if (document->FindElement("gamma"))
+ SetFlightPathAngleDegIC(document->FindElementValueAsNumberConvertTo("gamma", "DEG"));
+ if (document->FindElement("roc"))
+ SetClimbRateFpmIC(document->FindElementValueAsNumberConvertTo("roc", "FT/SEC"));
+ if (document->FindElement("altitude"))
+ SetAltitudeFtIC(document->FindElementValueAsNumberConvertTo("altitude", "FT"));
+ if (document->FindElement("winddir"))
+ SetWindDirDegIC(document->FindElementValueAsNumberConvertTo("winddir", "DEG"));
+ if (document->FindElement("vwind"))
+ SetWindMagKtsIC(document->FindElementValueAsNumberConvertTo("vwind", "FT/SEC"));
+ if (document->FindElement("hwind"))
+ SetHeadWindKtsIC(document->FindElementValueAsNumberConvertTo("hwind", "KTS"));
+ if (document->FindElement("xwind"))
+ SetCrossWindKtsIC(document->FindElementValueAsNumberConvertTo("xwind", "KTS"));
+ if (document->FindElement("vc"))
+ SetVcalibratedKtsIC(document->FindElementValueAsNumberConvertTo("vc", "FT/SEC"));
+ if (document->FindElement("mach"))
+ SetMachIC(document->FindElementValueAsNumber("mach"));
+ if (document->FindElement("vground"))
+ SetVgroundKtsIC(document->FindElementValueAsNumberConvertTo("vground", "FT/SEC"));
+ if (document->FindElement("running")) {
+ n = document->FindElementValueAsNumber("running");
+ if (n != 0) {
+ FGPropulsion* propulsion = fdmex->GetPropulsion();
+ for(int i=0; i<propulsion->GetNumEngines(); i++) {
+ propulsion->GetEngine(i)->SetRunning(true);
+ }
+ }
+ }
+
+ fdmex->RunIC();
+
+ return true;
+}
+
+//******************************************************************************
+
+void FGInitialCondition::bind(void){
+ PropertyManager->Tie("ic/vc-kts", this,
+ &FGInitialCondition::GetVcalibratedKtsIC,
+ &FGInitialCondition::SetVcalibratedKtsIC,
+ true);
+ PropertyManager->Tie("ic/ve-kts", this,
+ &FGInitialCondition::GetVequivalentKtsIC,
+ &FGInitialCondition::SetVequivalentKtsIC,
+ true);
+ PropertyManager->Tie("ic/vg-kts", this,
+ &FGInitialCondition::GetVgroundKtsIC,
+ &FGInitialCondition::SetVgroundKtsIC,
+ true);
+ PropertyManager->Tie("ic/vt-kts", this,
+ &FGInitialCondition::GetVtrueKtsIC,
+ &FGInitialCondition::SetVtrueKtsIC,
+ true);
+ PropertyManager->Tie("ic/mach-norm", this,
+ &FGInitialCondition::GetMachIC,
+ &FGInitialCondition::SetMachIC,
+ true);
+ PropertyManager->Tie("ic/roc-fpm", this,
+ &FGInitialCondition::GetClimbRateFpmIC,
+ &FGInitialCondition::SetClimbRateFpmIC,
+ true);
+ PropertyManager->Tie("ic/gamma-deg", this,
+ &FGInitialCondition::GetFlightPathAngleDegIC,
+ &FGInitialCondition::SetFlightPathAngleDegIC,
+ true);
+ PropertyManager->Tie("ic/alpha-deg", this,
+ &FGInitialCondition::GetAlphaDegIC,
+ &FGInitialCondition::SetAlphaDegIC,
+ true);
+ PropertyManager->Tie("ic/beta-deg", this,
+ &FGInitialCondition::GetBetaDegIC,
+ &FGInitialCondition::SetBetaDegIC,
+ true);
+ PropertyManager->Tie("ic/theta-deg", this,
+ &FGInitialCondition::GetPitchAngleDegIC,
+ &FGInitialCondition::SetPitchAngleDegIC,
+ true);
+ PropertyManager->Tie("ic/phi-deg", this,
+ &FGInitialCondition::GetRollAngleDegIC,
+ &FGInitialCondition::SetRollAngleDegIC,
+ true);
+ PropertyManager->Tie("ic/psi-true-deg", this,
+ &FGInitialCondition::GetHeadingDegIC );
+ PropertyManager->Tie("ic/lat-gc-deg", this,
+ &FGInitialCondition::GetLatitudeDegIC,
+ &FGInitialCondition::SetLatitudeDegIC,
+ true);
+ PropertyManager->Tie("ic/long-gc-deg", this,
+ &FGInitialCondition::GetLongitudeDegIC,
+ &FGInitialCondition::SetLongitudeDegIC,
+ true);
+ PropertyManager->Tie("ic/h-sl-ft", this,
+ &FGInitialCondition::GetAltitudeFtIC,
+ &FGInitialCondition::SetAltitudeFtIC,
+ true);
+ PropertyManager->Tie("ic/h-agl-ft", this,
+ &FGInitialCondition::GetAltitudeAGLFtIC,
+ &FGInitialCondition::SetAltitudeAGLFtIC,
+ true);
+ PropertyManager->Tie("ic/sea-level-radius-ft", this,
+ &FGInitialCondition::GetSeaLevelRadiusFtIC,
+ &FGInitialCondition::SetSeaLevelRadiusFtIC,
+ true);
+ PropertyManager->Tie("ic/terrain-altitude-ft", this,
+ &FGInitialCondition::GetTerrainAltitudeFtIC,
+ &FGInitialCondition::SetTerrainAltitudeFtIC,
+ true);
+ PropertyManager->Tie("ic/vg-fps", this,
+ &FGInitialCondition::GetVgroundFpsIC,
+ &FGInitialCondition::SetVgroundFpsIC,
+ true);
+ PropertyManager->Tie("ic/vt-fps", this,
+ &FGInitialCondition::GetVtrueFpsIC,
+ &FGInitialCondition::SetVtrueFpsIC,
+ true);
+ PropertyManager->Tie("ic/vw-bx-fps", this,
+ &FGInitialCondition::GetWindUFpsIC);
+ PropertyManager->Tie("ic/vw-by-fps", this,
+ &FGInitialCondition::GetWindVFpsIC);
+ PropertyManager->Tie("ic/vw-bz-fps", this,
+ &FGInitialCondition::GetWindWFpsIC);
+ PropertyManager->Tie("ic/vw-north-fps", this,
+ &FGInitialCondition::GetWindNFpsIC);
+ PropertyManager->Tie("ic/vw-east-fps", this,
+ &FGInitialCondition::GetWindEFpsIC);
+ PropertyManager->Tie("ic/vw-down-fps", this,
+ &FGInitialCondition::GetWindDFpsIC);
+ PropertyManager->Tie("ic/vw-mag-fps", this,
+ &FGInitialCondition::GetWindFpsIC);
+ /* PropertyManager->Tie("ic/vw-dir-deg", this,
+ &FGInitialCondition::GetWindDirDegIC,
+ &FGInitialCondition::SetWindDirDegIC,
+ true); */
+
+ PropertyManager->Tie("ic/roc-fps", this,
+ &FGInitialCondition::GetClimbRateFpsIC,
+ &FGInitialCondition::SetClimbRateFpsIC,
+ true);
+ /* PropertyManager->Tie("ic/u-fps", this,
+ &FGInitialCondition::GetUBodyFpsIC,
+ &FGInitialCondition::SetUBodyFpsIC,
+ true);
+ PropertyManager->Tie("ic/v-fps", this,
+ &FGInitialCondition::GetVBodyFpsIC,
+ &FGInitialCondition::SetVBodyFpsIC,
+ true);
+ PropertyManager->Tie("ic/w-fps", this,
+ &FGInitialCondition::GetWBodyFpsIC,
+ &FGInitialCondition::SetWBodyFpsIC,
+ true); */
+
+ PropertyManager->Tie("ic/gamma-rad", this,
+ &FGInitialCondition::GetFlightPathAngleRadIC,
+ &FGInitialCondition::SetFlightPathAngleRadIC,
+ true);
+ PropertyManager->Tie("ic/alpha-rad", this,
+ &FGInitialCondition::GetAlphaRadIC,
+ &FGInitialCondition::SetAlphaRadIC,
+ true);
+ PropertyManager->Tie("ic/theta-rad", this,
+ &FGInitialCondition::GetPitchAngleRadIC,
+ &FGInitialCondition::SetPitchAngleRadIC,
+ true);
+ PropertyManager->Tie("ic/beta-rad", this,
+ &FGInitialCondition::GetBetaRadIC,
+ &FGInitialCondition::SetBetaRadIC,
+ true);
+ PropertyManager->Tie("ic/phi-rad", this,
+ &FGInitialCondition::GetRollAngleRadIC,
+ &FGInitialCondition::SetRollAngleRadIC,
+ true);
+ PropertyManager->Tie("ic/psi-true-rad", this,
+ &FGInitialCondition::GetHeadingRadIC);
+ PropertyManager->Tie("ic/lat-gc-rad", this,
+ &FGInitialCondition::GetLatitudeRadIC,
+ &FGInitialCondition::SetLatitudeRadIC,
+ true);
+ PropertyManager->Tie("ic/long-gc-rad", this,
+ &FGInitialCondition::GetLongitudeRadIC,
+ &FGInitialCondition::SetLongitudeRadIC,
+ true);
+ PropertyManager->Tie("ic/p-rad_sec", this,
+ &FGInitialCondition::GetPRadpsIC,
+ &FGInitialCondition::SetPRadpsIC,
+ true);
+ PropertyManager->Tie("ic/q-rad_sec", this,
+ &FGInitialCondition::GetQRadpsIC,
+ &FGInitialCondition::SetQRadpsIC,
+ true);
+ PropertyManager->Tie("ic/r-rad_sec", this,
+ &FGInitialCondition::GetRRadpsIC,
+ &FGInitialCondition::SetRRadpsIC,
+ true);
+
+}
+
+//******************************************************************************
+
+void FGInitialCondition::unbind(void){
+ PropertyManager->Untie("ic/vc-kts");
+ PropertyManager->Untie("ic/ve-kts");
+ PropertyManager->Untie("ic/vg-kts");
+ PropertyManager->Untie("ic/vt-kts");
+ PropertyManager->Untie("ic/mach-norm");
+ PropertyManager->Untie("ic/roc-fpm");
+ PropertyManager->Untie("ic/gamma-deg");
+ PropertyManager->Untie("ic/alpha-deg");
+ PropertyManager->Untie("ic/beta-deg");
+ PropertyManager->Untie("ic/theta-deg");
+ PropertyManager->Untie("ic/phi-deg");
+ PropertyManager->Untie("ic/psi-true-deg");
+ PropertyManager->Untie("ic/lat-gc-deg");
+ PropertyManager->Untie("ic/long-gc-deg");
+ PropertyManager->Untie("ic/h-sl-ft");
+ PropertyManager->Untie("ic/h-agl-ft");
+ PropertyManager->Untie("ic/sea-level-radius-ft");
+ PropertyManager->Untie("ic/terrain-altitude-ft");
+ PropertyManager->Untie("ic/vg-fps");
+ PropertyManager->Untie("ic/vt-fps");
+ PropertyManager->Untie("ic/vw-bx-fps");
+ PropertyManager->Untie("ic/vw-by-fps");
+ PropertyManager->Untie("ic/vw-bz-fps");
+ PropertyManager->Untie("ic/vw-north-fps");
+ PropertyManager->Untie("ic/vw-east-fps");
+ PropertyManager->Untie("ic/vw-down-fps");
+ PropertyManager->Untie("ic/vw-mag-fps");
+ /* PropertyManager->Untie("ic/vw-dir-deg"); */
+
+ PropertyManager->Untie("ic/roc-fps");
+
+ /* PropertyManager->Untie("ic/u-fps");
+ PropertyManager->Untie("ic/v-fps");
+ PropertyManager->Untie("ic/w-fps"); */
+
+ PropertyManager->Untie("ic/gamma-rad");
+ PropertyManager->Untie("ic/alpha-rad");
+ PropertyManager->Untie("ic/theta-rad");
+ PropertyManager->Untie("ic/beta-rad");
+ PropertyManager->Untie("ic/phi-rad");
+ PropertyManager->Untie("ic/psi-true-rad");
+ PropertyManager->Untie("ic/lat-gc-rad");
+ PropertyManager->Untie("ic/long-gc-rad");
+ PropertyManager->Untie("ic/p-rad_sec");
+ PropertyManager->Untie("ic/q-rad_sec");
+ PropertyManager->Untie("ic/r-rad_sec");
+
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGInitialCondition::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGInitialCondition" << endl;
+ if (from == 1) cout << "Destroyed: FGInitialCondition" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGInitialCondition.h
+ Author: Tony Peden
+ Date started: 7/1/99
+
+ ------------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+ HISTORY
+--------------------------------------------------------------------------------
+7/1/99 TP Created
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+The purpose of this class is to take a set of initial conditions and provide
+a kinematically consistent set of body axis velocity components, euler
+angles, and altitude. This class does not attempt to trim the model i.e.
+the sim will most likely start in a very dynamic state (unless, of course,
+you have chosen your IC's wisely) even after setting it up with this class.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGINITIALCONDITION_H
+#define FGINITIALCONDITION_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <FGFDMExec.h>
+#include <FGJSBBase.h>
+#include <math/FGColumnVector3.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_INITIALCONDITION "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+typedef enum { setvt, setvc, setve, setmach, setuvw, setned, setvg } speedset;
+typedef enum { setwned, setwmd, setwhc } windset;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Takes a set of initial conditions and provide a kinematically consistent set
+ of body axis velocity components, euler angles, and altitude. This class
+ does not attempt to trim the model i.e. the sim will most likely start in a
+ very dynamic state (unless, of course, you have chosen your IC's wisely)
+ even after setting it up with this class.
+
+ USAGE NOTES
+
+ With a valid object of FGFDMExec and an aircraft model loaded
+ FGInitialCondition fgic=new FGInitialCondition(FDMExec);
+ fgic->SetVcalibratedKtsIC()
+ fgic->SetAltitudeFtIC();
+
+ //to directly into Run
+ FDMExec->GetState()->Initialize(fgic)
+ delete fgic;
+ FDMExec->Run()
+
+ //or to loop the sim w/o integrating
+ FDMExec->RunIC(fgic)
+
+ Speed:
+
+ Since vc, ve, vt, and mach all represent speed, the remaining
+ three are recalculated each time one of them is set (using the
+ current altitude). The most recent speed set is remembered so
+ that if and when altitude is reset, the last set speed is used
+ to recalculate the remaining three. Setting any of the body
+ components forces a recalculation of vt and vt then becomes the
+ most recent speed set.
+
+ Alpha,Gamma, and Theta:
+
+ This class assumes that it will be used to set up the sim for a
+ steady, zero pitch rate condition. Since any two of those angles
+ specifies the third gamma (flight path angle) is favored when setting
+ alpha and theta and alpha is favored when setting gamma. i.e.
+
+ - set alpha : recalculate theta using gamma as currently set
+ - set theta : recalculate alpha using gamma as currently set
+ - set gamma : recalculate theta using alpha as currently set
+
+ The idea being that gamma is most interesting to pilots (since it
+ is indicative of climb rate).
+
+ Setting climb rate is, for the purpose of this discussion,
+ considered equivalent to setting gamma.
+
+ These are the items that can be set in an initialization file:
+
+ UBODY <velocity, ft/sec>
+ VBODY <velocity, ft/sec>
+ WBODY <velocity, ft/sec>
+ LATITUDE <position, degrees>
+ LONGITUDE <position, degrees>
+ PHI <orientation, degrees>
+ THETA <orientation, degrees>
+ PSI <orientation, degrees>
+ ALPHA <angle, degrees>
+ BETA <angle, degrees>
+ GAMMA <angle, degrees>
+ ROC <vertical velocity, ft/sec>
+ ALTITUDE <altitude, ft>
+ WINDDIR <wind from-angle, degrees>
+ VWIND <magnitude wind speed, ft/sec>
+ HWIND <headwind speed, knots>
+ XWIND <crosswind speed, knots>
+ VC <calibrated airspeed, ft/sec>
+ MACH <mach>
+ VGROUND <ground speed, ft/sec>
+ RUNNING <0 or 1>
+
+
+ @author Tony Peden
+ @version "$Id$"
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGInitialCondition : public FGJSBBase
+{
+public:
+ /// Constructor
+ FGInitialCondition(FGFDMExec *fdmex);
+ /// Destructor
+ ~FGInitialCondition();
+
+ void SetVcalibratedKtsIC(double tt);
+ void SetVequivalentKtsIC(double tt);
+ inline void SetVtrueKtsIC(double tt) { SetVtrueFpsIC(tt*ktstofps); }
+ inline void SetVgroundKtsIC(double tt) { SetVgroundFpsIC(tt*ktstofps); }
+ void SetMachIC(double tt);
+
+ inline void SetAlphaDegIC(double tt) { SetAlphaRadIC(tt*degtorad); }
+ inline void SetBetaDegIC(double tt) { SetBetaRadIC(tt*degtorad);}
+
+ inline void SetPitchAngleDegIC(double tt) { SetPitchAngleRadIC(tt*degtorad); }
+ inline void SetRollAngleDegIC(double tt) { SetRollAngleRadIC(tt*degtorad);}
+ inline void SetTrueHeadingDegIC(double tt){ SetTrueHeadingRadIC(tt*degtorad); }
+
+ void SetClimbRateFpmIC(double tt);
+ inline void SetFlightPathAngleDegIC(double tt) { SetFlightPathAngleRadIC(tt*degtorad); }
+
+ void SetAltitudeFtIC(double tt);
+ void SetAltitudeAGLFtIC(double tt);
+
+ void SetSeaLevelRadiusFtIC(double tt);
+ void SetTerrainAltitudeFtIC(double tt);
+
+ inline void SetLatitudeDegIC(double tt) { latitude=tt*degtorad; }
+ inline void SetLongitudeDegIC(double tt) { longitude=tt*degtorad; }
+
+
+ inline double GetVcalibratedKtsIC(void) const { return vc*fpstokts; }
+ inline double GetVequivalentKtsIC(void) const { return ve*fpstokts; }
+ inline double GetVgroundKtsIC(void) const { return vg*fpstokts; }
+ inline double GetVtrueKtsIC(void) const { return vt*fpstokts; }
+ inline double GetMachIC(void) const { return mach; }
+
+ inline double GetClimbRateFpmIC(void) const { return hdot*60; }
+ inline double GetFlightPathAngleDegIC(void)const { return gamma*radtodeg; }
+
+ inline double GetAlphaDegIC(void) const { return alpha*radtodeg; }
+ inline double GetBetaDegIC(void) const { return beta*radtodeg; }
+
+ inline double GetPitchAngleDegIC(void) const { return theta*radtodeg; }
+ inline double GetRollAngleDegIC(void) const { return phi*radtodeg; }
+ inline double GetHeadingDegIC(void) const { return psi*radtodeg; }
+
+ inline double GetLatitudeDegIC(void) const { return latitude*radtodeg; }
+ inline double GetLongitudeDegIC(void) const { return longitude*radtodeg; }
+
+ inline double GetAltitudeFtIC(void) const { return altitude; }
+ inline double GetAltitudeAGLFtIC(void) const { return altitude - terrain_altitude; }
+
+ inline double GetSeaLevelRadiusFtIC(void) const { return sea_level_radius; }
+ inline double GetTerrainAltitudeFtIC(void) const { return terrain_altitude; }
+
+ void SetVgroundFpsIC(double tt);
+ void SetVtrueFpsIC(double tt);
+ void SetUBodyFpsIC(double tt);
+ void SetVBodyFpsIC(double tt);
+ void SetWBodyFpsIC(double tt);
+ void SetVnorthFpsIC(double tt);
+ void SetVeastFpsIC(double tt);
+ void SetVdownFpsIC(double tt);
+ void SetPRadpsIC(double tt) { p = tt; }
+ void SetQRadpsIC(double tt) { q = tt; }
+ void SetRRadpsIC(double tt) { r = tt; }
+
+ void SetWindNEDFpsIC(double wN, double wE, double wD);
+
+ void SetWindMagKtsIC(double mag);
+ void SetWindDirDegIC(double dir);
+
+ void SetHeadWindKtsIC(double head);
+ void SetCrossWindKtsIC(double cross);// positive from left
+
+ void SetWindDownKtsIC(double wD);
+
+ void SetClimbRateFpsIC(double tt);
+ inline double GetVgroundFpsIC(void) const { return vg; }
+ inline double GetVtrueFpsIC(void) const { return vt; }
+ inline double GetWindUFpsIC(void) const { return uw; }
+ inline double GetWindVFpsIC(void) const { return vw; }
+ inline double GetWindWFpsIC(void) const { return ww; }
+ inline double GetWindNFpsIC(void) const { return wnorth; }
+ inline double GetWindEFpsIC(void) const { return weast; }
+ inline double GetWindDFpsIC(void) const { return wdown; }
+ inline double GetWindFpsIC(void) const { return sqrt(wnorth*wnorth + weast*weast); }
+ double GetWindDirDegIC(void);
+ inline double GetClimbRateFpsIC(void) const { return hdot; }
+ double GetUBodyFpsIC(void) const;
+ double GetVBodyFpsIC(void) const;
+ double GetWBodyFpsIC(void) const;
+ double GetPRadpsIC() const { return p; }
+ double GetQRadpsIC() const { return q; }
+ double GetRRadpsIC() const { return r; }
+ void SetFlightPathAngleRadIC(double tt);
+ void SetAlphaRadIC(double tt);
+ void SetPitchAngleRadIC(double tt);
+ void SetBetaRadIC(double tt);
+ void SetRollAngleRadIC(double tt);
+ void SetTrueHeadingRadIC(double tt);
+ inline void SetLatitudeRadIC(double tt) { latitude=tt; }
+ inline void SetLongitudeRadIC(double tt) { longitude=tt; }
+ inline double GetFlightPathAngleRadIC(void) const { return gamma; }
+ inline double GetAlphaRadIC(void) const { return alpha; }
+ inline double GetPitchAngleRadIC(void) const { return theta; }
+ inline double GetBetaRadIC(void) const { return beta; }
+ inline double GetRollAngleRadIC(void) const { return phi; }
+ inline double GetHeadingRadIC(void) const { return psi; }
+ inline double GetLatitudeRadIC(void) const { return latitude; }
+ inline double GetLongitudeRadIC(void) const { return longitude; }
+ inline double GetThetaRadIC(void) const { return theta; }
+ inline double GetPhiRadIC(void) const { return phi; }
+ inline double GetPsiRadIC(void) const { return psi; }
+
+ inline speedset GetSpeedSet(void) { return lastSpeedSet; }
+ inline windset GetWindSet(void) { return lastWindSet; }
+
+ bool Load(string rstname, bool useStoredPath = true );
+
+ void bind(void);
+ void unbind(void);
+
+
+private:
+ double vt,vc,ve,vg;
+ double mach;
+ double altitude,hdot;
+ double latitude,longitude;
+ double u,v,w;
+ double p,q,r;
+ double uw,vw,ww;
+ double vnorth,veast,vdown;
+ double wnorth,weast,wdown;
+ double whead, wcross, wdir, wmag;
+ double sea_level_radius;
+ double terrain_altitude;
+ double radius_to_vehicle;
+
+ double alpha, beta, theta, phi, psi, gamma;
+ double salpha,sbeta,stheta,sphi,spsi,sgamma;
+ double calpha,cbeta,ctheta,cphi,cpsi,cgamma;
+
+ double xlo, xhi,xmin,xmax;
+
+ typedef double (FGInitialCondition::*fp)(double x);
+ fp sfunc;
+
+ speedset lastSpeedSet;
+ windset lastWindSet;
+
+ FGFDMExec *fdmex;
+ FGPropertyManager *PropertyManager;
+
+ bool getAlpha(void);
+ bool getTheta(void);
+ bool getMachFromVcas(double *Mach,double vcas);
+
+ double GammaEqOfTheta(double Theta);
+ double GammaEqOfAlpha(double Alpha);
+ double calcVcas(double Mach);
+ void calcUVWfromNED(void);
+ void calcWindUVW(void);
+
+ bool findInterval(double x,double guess);
+ bool solve(double *y, double x);
+ void Debug(int from);
+};
+}
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGTrim.cpp
+ Author: Tony Peden
+ Date started: 9/8/99
+
+ --------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) ---------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+
+ HISTORY
+--------------------------------------------------------------------------------
+9/8/99 TP Created
+
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+This class takes the given set of IC's and finds the angle of attack, elevator,
+and throttle setting required to fly steady level. This is currently for in-air
+conditions only. It is implemented using an iterative, one-axis-at-a-time
+scheme. */
+
+// !!!!!!! BEWARE ALL YE WHO ENTER HERE !!!!!!!
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <stdlib.h>
+
+#include <FGFDMExec.h>
+#include <models/FGAtmosphere.h>
+#include "FGInitialCondition.h"
+#include "FGTrim.h"
+#include <models/FGAircraft.h>
+#include <models/FGMassBalance.h>
+#include <models/FGGroundReactions.h>
+#include <models/FGInertial.h>
+#include <models/FGAerodynamics.h>
+#include <math/FGColumnVector3.h>
+
+#if _MSC_VER
+#pragma warning (disable : 4786 4788)
+#endif
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_TRIM;
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGTrim::FGTrim(FGFDMExec *FDMExec,TrimMode tt) {
+
+ N=Nsub=0;
+ max_iterations=60;
+ max_sub_iterations=100;
+ Tolerance=1E-3;
+ A_Tolerance = Tolerance / 10;
+
+ Debug=0;DebugLevel=0;
+ fdmex=FDMExec;
+ fgic=fdmex->GetIC();
+ total_its=0;
+ trimudot=true;
+ gamma_fallback=true;
+ axis_count=0;
+ mode=tt;
+ xlo=xhi=alo=ahi=0.0;
+ targetNlf=1.0;
+ debug_axis=tAll;
+ SetMode(tt);
+ if (debug_lvl & 2) cout << "Instantiated: FGTrim" << endl;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGTrim::~FGTrim(void) {
+ for(current_axis=0; current_axis<TrimAxes.size(); current_axis++) {
+ delete TrimAxes[current_axis];
+ }
+ delete[] sub_iterations;
+ delete[] successful;
+ delete[] solution;
+ if (debug_lvl & 2) cout << "Destroyed: FGTrim" << endl;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGTrim::TrimStats() {
+ char out[80];
+ int run_sum=0;
+ cout << endl << " Trim Statistics: " << endl;
+ cout << " Total Iterations: " << total_its << endl;
+ if(total_its > 0) {
+ cout << " Sub-iterations:" << endl;
+ for(current_axis=0; current_axis<TrimAxes.size(); current_axis++) {
+ run_sum+=TrimAxes[current_axis]->GetRunCount();
+ snprintf(out,80," %5s: %3.0f average: %5.2f successful: %3.0f stability: %5.2f\n",
+ TrimAxes[current_axis]->GetStateName().c_str(),
+ sub_iterations[current_axis],
+ sub_iterations[current_axis]/double(total_its),
+ successful[current_axis],
+ TrimAxes[current_axis]->GetAvgStability() );
+ cout << out;
+ }
+ cout << " Run Count: " << run_sum << endl;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGTrim::Report(void) {
+ cout << " Trim Results: " << endl;
+ for(current_axis=0; current_axis<TrimAxes.size(); current_axis++)
+ TrimAxes[current_axis]->AxisReport();
+
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGTrim::ClearStates(void) {
+ FGTrimAxis* ta;
+
+ mode=tCustom;
+ vector<FGTrimAxis*>::iterator iAxes;
+ iAxes = TrimAxes.begin();
+ while (iAxes != TrimAxes.end()) {
+ ta=*iAxes;
+ delete ta;
+ iAxes++;
+ }
+ TrimAxes.clear();
+ //cout << "TrimAxes.size(): " << TrimAxes.size() << endl;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGTrim::AddState( State state, Control control ) {
+ FGTrimAxis* ta;
+ bool result=true;
+
+ mode = tCustom;
+ vector <FGTrimAxis*>::iterator iAxes = TrimAxes.begin();
+ while (iAxes != TrimAxes.end()) {
+ ta=*iAxes;
+ if( ta->GetStateType() == state )
+ result=false;
+ iAxes++;
+ }
+ if(result) {
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,state,control));
+ delete[] sub_iterations;
+ delete[] successful;
+ delete[] solution;
+ sub_iterations=new double[TrimAxes.size()];
+ successful=new double[TrimAxes.size()];
+ solution=new bool[TrimAxes.size()];
+ }
+ return result;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGTrim::RemoveState( State state ) {
+ FGTrimAxis* ta;
+ bool result=false;
+
+ mode = tCustom;
+ vector <FGTrimAxis*>::iterator iAxes = TrimAxes.begin();
+ while (iAxes != TrimAxes.end()) {
+ ta=*iAxes;
+ if( ta->GetStateType() == state ) {
+ delete ta;
+ TrimAxes.erase(iAxes);
+ result=true;
+ continue;
+ }
+ iAxes++;
+ }
+ if(result) {
+ delete[] sub_iterations;
+ delete[] successful;
+ delete[] solution;
+ sub_iterations=new double[TrimAxes.size()];
+ successful=new double[TrimAxes.size()];
+ solution=new bool[TrimAxes.size()];
+ }
+ return result;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGTrim::EditState( State state, Control new_control ){
+ FGTrimAxis* ta;
+ bool result=false;
+
+ mode = tCustom;
+ vector <FGTrimAxis*>::iterator iAxes = TrimAxes.begin();
+ while (iAxes != TrimAxes.end()) {
+ ta=*iAxes;
+ if( ta->GetStateType() == state ) {
+ TrimAxes.insert(iAxes,1,new FGTrimAxis(fdmex,fgic,state,new_control));
+ delete ta;
+ TrimAxes.erase(iAxes+1);
+ result=true;
+ break;
+ }
+ iAxes++;
+ }
+ return result;
+}
+
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGTrim::DoTrim(void) {
+
+ trim_failed=false;
+ int i;
+
+ for(i=0;i < fdmex->GetGroundReactions()->GetNumGearUnits();i++){
+ fdmex->GetGroundReactions()->GetGearUnit(i)->SetReport(false);
+ }
+
+ fdmex->DisableOutput();
+
+ fgic->SetPRadpsIC(0.0);
+ fgic->SetQRadpsIC(0.0);
+ fgic->SetRRadpsIC(0.0);
+
+ //clear the sub iterations counts & zero out the controls
+ for(current_axis=0;current_axis<TrimAxes.size();current_axis++) {
+ //cout << current_axis << " " << TrimAxes[current_axis]->GetStateName()
+ //<< " " << TrimAxes[current_axis]->GetControlName()<< endl;
+ if(TrimAxes[current_axis]->GetStateType() == tQdot) {
+ if(mode == tGround) {
+ TrimAxes[current_axis]->initTheta();
+ }
+ }
+ xlo=TrimAxes[current_axis]->GetControlMin();
+ xhi=TrimAxes[current_axis]->GetControlMax();
+ TrimAxes[current_axis]->SetControl((xlo+xhi)/2);
+ TrimAxes[current_axis]->Run();
+ //TrimAxes[current_axis]->AxisReport();
+ sub_iterations[current_axis]=0;
+ successful[current_axis]=0;
+ solution[current_axis]=false;
+ }
+
+
+ if(mode == tPullup ) {
+ cout << "Setting pitch rate and nlf... " << endl;
+ setupPullup();
+ cout << "pitch rate done ... " << endl;
+ TrimAxes[0]->SetStateTarget(targetNlf);
+ cout << "nlf done" << endl;
+ } else if (mode == tTurn) {
+ setupTurn();
+ //TrimAxes[0]->SetStateTarget(targetNlf);
+ }
+
+ do {
+ axis_count=0;
+ for(current_axis=0;current_axis<TrimAxes.size();current_axis++) {
+ setDebug();
+ updateRates();
+ Nsub=0;
+ if(!solution[current_axis]) {
+ if(checkLimits()) {
+ solution[current_axis]=true;
+ solve();
+ }
+ } else if(findInterval()) {
+ solve();
+ } else {
+ solution[current_axis]=false;
+ }
+ sub_iterations[current_axis]+=Nsub;
+ }
+ for(current_axis=0;current_axis<TrimAxes.size();current_axis++) {
+ //these checks need to be done after all the axes have run
+ if(Debug > 0) TrimAxes[current_axis]->AxisReport();
+ if(TrimAxes[current_axis]->InTolerance()) {
+ axis_count++;
+ successful[current_axis]++;
+ }
+ }
+
+
+ if((axis_count == TrimAxes.size()-1) && (TrimAxes.size() > 1)) {
+ //cout << TrimAxes.size()-1 << " out of " << TrimAxes.size() << "!" << endl;
+ //At this point we can check the input limits of the failed axis
+ //and declare the trim failed if there is no sign change. If there
+ //is, keep going until success or max iteration count
+
+ //Oh, well: two out of three ain't bad
+ for(current_axis=0;current_axis<TrimAxes.size();current_axis++) {
+ //these checks need to be done after all the axes have run
+ if(!TrimAxes[current_axis]->InTolerance()) {
+ if(!checkLimits()) {
+ // special case this for now -- if other cases arise proper
+ // support can be added to FGTrimAxis
+ if( (gamma_fallback) &&
+ (TrimAxes[current_axis]->GetStateType() == tUdot) &&
+ (TrimAxes[current_axis]->GetControlType() == tThrottle)) {
+ cout << " Can't trim udot with throttle, trying flight"
+ << " path angle. (" << N << ")" << endl;
+ if(TrimAxes[current_axis]->GetState() > 0)
+ TrimAxes[current_axis]->SetControlToMin();
+ else
+ TrimAxes[current_axis]->SetControlToMax();
+ TrimAxes[current_axis]->Run();
+ delete TrimAxes[current_axis];
+ TrimAxes[current_axis]=new FGTrimAxis(fdmex,fgic,tUdot,
+ tGamma );
+ } else {
+ cout << " Sorry, " << TrimAxes[current_axis]->GetStateName()
+ << " doesn't appear to be trimmable" << endl;
+ //total_its=k;
+ trim_failed=true; //force the trim to fail
+ } //gamma_fallback
+ }
+ } //solution check
+ } //for loop
+ } //all-but-one check
+ N++;
+ if(N > max_iterations)
+ trim_failed=true;
+ } while((axis_count < TrimAxes.size()) && (!trim_failed));
+ if((!trim_failed) && (axis_count >= TrimAxes.size())) {
+ total_its=N;
+ if (debug_lvl > 0)
+ cout << endl << " Trim successful" << endl;
+ } else {
+ total_its=N;
+ if (debug_lvl > 0)
+ cout << endl << " Trim failed" << endl;
+ }
+ for(i=0;i < fdmex->GetGroundReactions()->GetNumGearUnits();i++){
+ fdmex->GetGroundReactions()->GetGearUnit(i)->SetReport(true);
+ }
+ fdmex->EnableOutput();
+ return !trim_failed;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGTrim::solve(void) {
+
+ double x1,x2,x3,f1,f2,f3,d,d0;
+ const double relax =0.9;
+ double eps=TrimAxes[current_axis]->GetSolverEps();
+
+ x1=x2=x3=0;
+ d=1;
+ bool success=false;
+ //initializations
+ if( solutionDomain != 0) {
+ /* if(ahi > alo) { */
+ x1=xlo;f1=alo;
+ x3=xhi;f3=ahi;
+ /* } else {
+ x1=xhi;f1=ahi;
+ x3=xlo;f3=alo;
+ } */
+ d0=fabs(x3-x1);
+ //iterations
+ //max_sub_iterations=TrimAxes[current_axis]->GetIterationLimit();
+ while ( (TrimAxes[current_axis]->InTolerance() == false )
+ && (fabs(d) > eps) && (Nsub < max_sub_iterations)) {
+ Nsub++;
+ d=(x3-x1)/d0;
+ x2=x1-d*d0*f1/(f3-f1);
+ TrimAxes[current_axis]->SetControl(x2);
+ TrimAxes[current_axis]->Run();
+ f2=TrimAxes[current_axis]->GetState();
+ if(Debug > 1) {
+ cout << "FGTrim::solve Nsub,x1,x2,x3: " << Nsub << ", " << x1
+ << ", " << x2 << ", " << x3 << endl;
+ cout << " " << f1 << ", " << f2 << ", " << f3 << endl;
+ }
+ if(f1*f2 <= 0.0) {
+ x3=x2;
+ f3=f2;
+ f1=relax*f1;
+ //cout << "Solution is between x1 and x2" << endl;
+ }
+ else if(f2*f3 <= 0.0) {
+ x1=x2;
+ f1=f2;
+ f3=relax*f3;
+ //cout << "Solution is between x2 and x3" << endl;
+
+ }
+ //cout << i << endl;
+
+
+ }//end while
+ if(Nsub < max_sub_iterations) success=true;
+ }
+ return success;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+/*
+ produces an interval (xlo..xhi) on one side or the other of the current
+ control value in which a solution exists. This domain is, hopefully,
+ smaller than xmin..0 or 0..xmax and the solver will require fewer iterations
+ to find the solution. This is, hopefully, more efficient than having the
+ solver start from scratch every time. Maybe it isn't though...
+ This tries to take advantage of the idea that the changes from iteration to
+ iteration will be small after the first one or two top-level iterations.
+
+ assumes that changing the control will a produce significant change in the
+ accel i.e. checkLimits() has already been called.
+
+ if a solution is found above the current control, the function returns true
+ and xlo is set to the current control, xhi to the interval max it found, and
+ solutionDomain is set to 1.
+ if the solution lies below the current control, then the function returns
+ true and xlo is set to the interval min it found and xmax to the current
+ control. if no solution is found, then the function returns false.
+
+
+ in all cases, alo=accel(xlo) and ahi=accel(xhi) after the function exits.
+ no assumptions about the state of the sim after this function has run
+ can be made.
+*/
+bool FGTrim::findInterval(void) {
+ bool found=false;
+ double step;
+ double current_control=TrimAxes[current_axis]->GetControl();
+ double current_accel=TrimAxes[current_axis]->GetState();;
+ double xmin=TrimAxes[current_axis]->GetControlMin();
+ double xmax=TrimAxes[current_axis]->GetControlMax();
+ double lastxlo,lastxhi,lastalo,lastahi;
+
+ step=0.025*fabs(xmax);
+ xlo=xhi=current_control;
+ alo=ahi=current_accel;
+ lastxlo=xlo;lastxhi=xhi;
+ lastalo=alo;lastahi=ahi;
+ do {
+
+ Nsub++;
+ step*=2;
+ xlo-=step;
+ if(xlo < xmin) xlo=xmin;
+ xhi+=step;
+ if(xhi > xmax) xhi=xmax;
+ TrimAxes[current_axis]->SetControl(xlo);
+ TrimAxes[current_axis]->Run();
+ alo=TrimAxes[current_axis]->GetState();
+ TrimAxes[current_axis]->SetControl(xhi);
+ TrimAxes[current_axis]->Run();
+ ahi=TrimAxes[current_axis]->GetState();
+ if(fabs(ahi-alo) <= TrimAxes[current_axis]->GetTolerance()) continue;
+ if(alo*ahi <=0) { //found interval with root
+ found=true;
+ if(alo*current_accel <= 0) { //narrow interval down a bit
+ solutionDomain=-1;
+ xhi=lastxlo;
+ ahi=lastalo;
+ //xhi=current_control;
+ //ahi=current_accel;
+ } else {
+ solutionDomain=1;
+ xlo=lastxhi;
+ alo=lastahi;
+ //xlo=current_control;
+ //alo=current_accel;
+ }
+ }
+ lastxlo=xlo;lastxhi=xhi;
+ lastalo=alo;lastahi=ahi;
+ if( !found && xlo==xmin && xhi==xmax ) continue;
+ if(Debug > 1)
+ cout << "FGTrim::findInterval: Nsub=" << Nsub << " Lo= " << xlo
+ << " Hi= " << xhi << " alo*ahi: " << alo*ahi << endl;
+ } while(!found && (Nsub <= max_sub_iterations) );
+ return found;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+//checks to see which side of the current control value the solution is on
+//and sets solutionDomain accordingly:
+// 1 if solution is between the current and max
+// -1 if solution is between the min and current
+// 0 if there is no solution
+//
+//if changing the control produces no significant change in the accel then
+//solutionDomain is set to zero and the function returns false
+//if a solution is found, then xlo and xhi are set so that they bracket
+//the solution, alo is set to accel(xlo), and ahi is set to accel(xhi)
+//if there is no change or no solution then xlo=xmin, alo=accel(xmin) and
+//xhi=xmax and ahi=accel(xmax)
+//in all cases the sim is left such that the control=xmax and accel=ahi
+
+bool FGTrim::checkLimits(void) {
+ bool solutionExists;
+ double current_control=TrimAxes[current_axis]->GetControl();
+ double current_accel=TrimAxes[current_axis]->GetState();
+ xlo=TrimAxes[current_axis]->GetControlMin();
+ xhi=TrimAxes[current_axis]->GetControlMax();
+
+ TrimAxes[current_axis]->SetControl(xlo);
+ TrimAxes[current_axis]->Run();
+ alo=TrimAxes[current_axis]->GetState();
+ TrimAxes[current_axis]->SetControl(xhi);
+ TrimAxes[current_axis]->Run();
+ ahi=TrimAxes[current_axis]->GetState();
+ if(Debug > 1)
+ cout << "checkLimits() xlo,xhi,alo,ahi: " << xlo << ", " << xhi << ", "
+ << alo << ", " << ahi << endl;
+ solutionDomain=0;
+ solutionExists=false;
+ if(fabs(ahi-alo) > TrimAxes[current_axis]->GetTolerance()) {
+ if(alo*current_accel <= 0) {
+ solutionExists=true;
+ solutionDomain=-1;
+ xhi=current_control;
+ ahi=current_accel;
+ } else if(current_accel*ahi < 0){
+ solutionExists=true;
+ solutionDomain=1;
+ xlo=current_control;
+ alo=current_accel;
+ }
+ }
+ TrimAxes[current_axis]->SetControl(current_control);
+ TrimAxes[current_axis]->Run();
+ return solutionExists;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGTrim::setupPullup() {
+ double g,q,cgamma;
+ g=fdmex->GetInertial()->gravity();
+ cgamma=cos(fgic->GetFlightPathAngleRadIC());
+ cout << "setPitchRateInPullup(): " << g << ", " << cgamma << ", "
+ << fgic->GetVtrueFpsIC() << endl;
+ q=g*(targetNlf-cgamma)/fgic->GetVtrueFpsIC();
+ cout << targetNlf << ", " << q << endl;
+ fgic->SetQRadpsIC(q);
+ cout << "setPitchRateInPullup() complete" << endl;
+
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGTrim::setupTurn(void){
+ double g,phi;
+ phi = fgic->GetRollAngleRadIC();
+ if( fabs(phi) > 0.001 && fabs(phi) < 1.56 ) {
+ targetNlf = 1 / cos(phi);
+ g = fdmex->GetInertial()->gravity();
+ psidot = g*tan(phi) / fgic->GetUBodyFpsIC();
+ cout << targetNlf << ", " << psidot << endl;
+ }
+
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGTrim::updateRates(void){
+ if( mode == tTurn ) {
+ double phi = fgic->GetRollAngleRadIC();
+ double g = fdmex->GetInertial()->gravity();
+ double p,q,r,theta;
+ if(fabs(phi) > 0.001 && fabs(phi) < 1.56 ) {
+ theta=fgic->GetPitchAngleRadIC();
+ phi=fgic->GetRollAngleRadIC();
+ psidot = g*tan(phi) / fgic->GetUBodyFpsIC();
+ p=-psidot*sin(theta);
+ q=psidot*cos(theta)*sin(phi);
+ r=psidot*cos(theta)*cos(phi);
+ } else {
+ p=q=r=0;
+ }
+ fgic->SetPRadpsIC(p);
+ fgic->SetQRadpsIC(q);
+ fgic->SetRRadpsIC(r);
+ } else if( mode == tPullup && fabs(targetNlf-1) > 0.01) {
+ double g,q,cgamma;
+ g=fdmex->GetInertial()->gravity();
+ cgamma=cos(fgic->GetFlightPathAngleRadIC());
+ q=g*(targetNlf-cgamma)/fgic->GetVtrueFpsIC();
+ fgic->SetQRadpsIC(q);
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGTrim::setDebug(void) {
+ if(debug_axis == tAll ||
+ TrimAxes[current_axis]->GetStateType() == debug_axis ) {
+ Debug=DebugLevel;
+ return;
+ } else {
+ Debug=0;
+ return;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGTrim::SetMode(TrimMode tt) {
+ ClearStates();
+ mode=tt;
+ switch(tt) {
+ case tFull:
+ if (debug_lvl > 0)
+ cout << " Full Trim" << endl;
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tWdot,tAlpha ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tUdot,tThrottle ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tQdot,tPitchTrim ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tHmgt,tBeta ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tVdot,tPhi ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tPdot,tAileron ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tRdot,tRudder ));
+ break;
+ case tLongitudinal:
+ if (debug_lvl > 0)
+ cout << " Longitudinal Trim" << endl;
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tWdot,tAlpha ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tUdot,tThrottle ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tQdot,tPitchTrim ));
+ break;
+ case tGround:
+ if (debug_lvl > 0)
+ cout << " Ground Trim" << endl;
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tWdot,tAltAGL ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tQdot,tTheta ));
+ //TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tPdot,tPhi ));
+ break;
+ case tPullup:
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tNlf,tAlpha ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tUdot,tThrottle ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tQdot,tPitchTrim ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tHmgt,tBeta ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tVdot,tPhi ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tPdot,tAileron ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tRdot,tRudder ));
+ break;
+ case tTurn:
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tWdot,tAlpha ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tUdot,tThrottle ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tQdot,tPitchTrim ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tVdot,tBeta ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tPdot,tAileron ));
+ TrimAxes.push_back(new FGTrimAxis(fdmex,fgic,tRdot,tRudder ));
+ break;
+ case tCustom:
+ case tNone:
+ break;
+ }
+ //cout << "TrimAxes.size(): " << TrimAxes.size() << endl;
+ sub_iterations=new double[TrimAxes.size()];
+ successful=new double[TrimAxes.size()];
+ solution=new bool[TrimAxes.size()];
+ current_axis=0;
+}
+//YOU WERE WARNED, BUT YOU DID IT ANYWAY.
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGTrim.h
+ Author: Tony Peden
+ Date started: 7/1/99
+
+ ------------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+
+ HISTORY
+--------------------------------------------------------------------------------
+9/8/99 TP Created
+
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+This class takes the given set of IC's and finds the aircraft state required to
+maintain a specified flight condition. This flight condition can be
+steady-level with non-zero sideslip, a steady turn, a pull-up or pushover.
+On-ground conditions can be trimmed as well, but this is currently limited to
+adjusting altitude and pitch angle only. It is implemented using an iterative,
+one-axis-at-a-time scheme.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGTRIM_H
+#define FGTRIM_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGFDMExec.h"
+#include "FGJSBBase.h"
+#include "FGTrimAxis.h"
+
+#include <vector>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_TRIM "$Id$"
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+ #define snprintf _snprintf
+#endif
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+typedef enum { tLongitudinal=0, tFull, tGround, tPullup,
+ tCustom, tTurn, tNone } TrimMode;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** FGTrim -- the trimming routine for JSBSim.
+ FGTrim finds the aircraft attitude and control settings needed to maintain
+ the steady state described by the FGInitialCondition object . It does this
+ iteratively by assigning a control to each state and adjusting that control
+ until the state is within a specified tolerance of zero. States include the
+ recti-linear accelerations udot, vdot, and wdot, the angular accelerations
+ qdot, pdot, and rdot, and the difference between heading and ground track.
+ Controls include the usual flight deck controls available to the pilot plus
+ angle of attack (alpha), sideslip angle(beta), flight path angle (gamma),
+ pitch attitude(theta), roll attitude(phi), and altitude above ground. The
+ last three are used for on-ground trimming. The state-control pairs used in
+ a given trim are completely user configurable and several pre-defined modes
+ are provided as well. They are:
+ - tLongitudinal: Trim wdot with alpha, udot with thrust, qdot with elevator
+ - tFull: tLongitudinal + vdot with phi, pdot with aileron, rdot with rudder
+ and heading minus ground track (hmgt) with beta
+ - tPullup: tLongitudinal but adjust alpha to achieve load factor input
+ with SetTargetNlf()
+ - tGround: wdot with altitude, qdot with theta, and pdot with phi
+
+ The remaining modes include <b>tCustom</b>, which is completely user defined and
+ <b>tNone</b>.
+
+ Note that trims can (and do) fail for reasons that are completely outside
+ the control of the trimming routine itself. The most common problem is the
+ initial conditions: is the model capable of steady state flight
+ at those conditions? Check the speed, altitude, configuration (flaps,
+ gear, etc.), weight, cg, and anything else that may be relevant.
+
+ Example usage:<pre>
+ FGFDMExec* FDMExec = new FGFDMExec();
+
+ FGInitialCondition* fgic = new FGInitialCondition(FDMExec);
+ FGTrim fgt(FDMExec, fgic, tFull);
+ fgic->SetVcaibratedKtsIC(100);
+ fgic->SetAltitudeFtIC(1000);
+ fgic->SetClimbRate(500);
+ if( !fgt.DoTrim() ) {
+ cout << "Trim Failed" << endl;
+ }
+ fgt.Report(); </pre>
+ @author Tony Peden
+ @version "$Id$"
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGTrim : public FGJSBBase
+{
+private:
+
+ vector<FGTrimAxis*> TrimAxes;
+ unsigned int current_axis;
+ int N, Nsub;
+ TrimMode mode;
+ int DebugLevel, Debug;
+ double Tolerance, A_Tolerance;
+ double wdot,udot,qdot;
+ double dth;
+ double *sub_iterations;
+ double *successful;
+ bool *solution;
+ int max_sub_iterations;
+ int max_iterations;
+ int total_its;
+ bool trimudot;
+ bool gamma_fallback;
+ bool trim_failed;
+ unsigned int axis_count;
+ int solutionDomain;
+ double xlo,xhi,alo,ahi;
+ double targetNlf;
+ int debug_axis;
+
+ double psidot,thetadot;
+
+ FGFDMExec* fdmex;
+ FGInitialCondition* fgic;
+
+ bool solve(void);
+
+ /** @return false if there is no change in the current axis accel
+ between accel(control_min) and accel(control_max). If there is a
+ change, sets solutionDomain to:
+ 0 for no sign change,
+ -1 if sign change between accel(control_min) and accel(0)
+ 1 if sign between accel(0) and accel(control_max)
+ */
+ bool findInterval(void);
+
+ bool checkLimits(void);
+
+ void setupPullup(void);
+ void setupTurn(void);
+
+ void updateRates(void);
+
+ void setDebug(void);
+
+public:
+ /** Initializes the trimming class
+ @param FDMExec pointer to a JSBSim executive object.
+ @param tm trim mode
+ */
+ FGTrim(FGFDMExec *FDMExec, TrimMode tm=tGround );
+
+ ~FGTrim(void);
+
+ /** Execute the trim
+ */
+ bool DoTrim(void);
+
+ /** Print the results of the trim. For each axis trimmed, this
+ includes the final state value, control value, and tolerance
+ used.
+ @return true if trim succeeds
+ */
+ void Report(void);
+
+ /** Iteration statistics
+ */
+ void TrimStats();
+
+ /** Clear all state-control pairs and set a predefined trim mode
+ @param tm the set of axes to trim. Can be:
+ tLongitudinal, tFull, tGround, tCustom, or tNone
+ */
+ void SetMode(TrimMode tm);
+
+ /** Clear all state-control pairs from the current configuration.
+ The trimming routine must have at least one state-control pair
+ configured to be useful
+ */
+ void ClearStates(void);
+
+ /** Add a state-control pair to the current configuration. See the enums
+ State and Control in FGTrimAxis.h for the available options.
+ Will fail if the given state is already configured.
+ @param state the accel or other condition to zero
+ @param control the control used to zero the state
+ @return true if add is successful
+ */
+ bool AddState( State state, Control control );
+
+ /** Remove a specific state-control pair from the current configuration
+ @param state the state to remove
+ @return true if removal is successful
+ */
+ bool RemoveState( State state );
+
+ /** Change the control used to zero a state previously configured
+ @param state the accel or other condition to zero
+ @param new_control the control used to zero the state
+ */
+ bool EditState( State state, Control new_control );
+
+ /** automatically switch to trimming longitudinal acceleration with
+ flight path angle (gamma) once it becomes apparent that there
+ is not enough/too much thrust.
+ @param bb true to enable fallback
+ */
+ inline void SetGammaFallback(bool bb) { gamma_fallback=bb; }
+
+ /** query the fallback state
+ @return true if fallback is enabled.
+ */
+ inline bool GetGammaFallback(void) { return gamma_fallback; }
+
+ /** Set the iteration limit. DoTrim() will return false if limit
+ iterations are reached before trim is achieved. The default
+ is 60. This does not ordinarily need to be changed.
+ @param ii integer iteration limit
+ */
+ inline void SetMaxCycles(int ii) { max_iterations = ii; }
+
+ /** Set the per-axis iteration limit. Attempt to zero each state
+ by iterating limit times before moving on to the next. The
+ default limit is 100 and also does not ordinarily need to
+ be changed.
+ @param ii integer iteration limit
+ */
+ inline void SetMaxCyclesPerAxis(int ii) { max_sub_iterations = ii; }
+
+ /** Set the tolerance for declaring a state trimmed. Angular accels are
+ held to a tolerance of 1/10th of the given. The default is
+ 0.001 for the recti-linear accelerations and 0.0001 for the angular.
+ */
+ inline void SetTolerance(double tt) {
+ Tolerance = tt;
+ A_Tolerance = tt / 10;
+ }
+
+ /**
+ Debug level 1 shows results of each top-level iteration
+ Debug level 2 shows level 1 & results of each per-axis iteration
+ */
+ inline void SetDebug(int level) { DebugLevel = level; }
+ inline void ClearDebug(void) { DebugLevel = 0; }
+
+ /**
+ Output debug data for one of the axes
+ The State enum is defined in FGTrimAxis.h
+ */
+ inline void DebugState(State state) { debug_axis=state; }
+
+ inline void SetTargetNlf(double nlf) { targetNlf=nlf; }
+ inline double GetTargetNlf(void) { return targetNlf; }
+
+};
+}
+
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGTrimAxis.cpp
+ Author: Tony Peden
+ Date started: 7/3/00
+
+ --------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) ---------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+
+ HISTORY
+--------------------------------------------------------------------------------
+7/3/00 TP Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef _MSC_VER
+# pragma warning (disable : 4786)
+#endif
+
+#include <string>
+#include <stdlib.h>
+
+#include <FGFDMExec.h>
+#include <models/FGAtmosphere.h>
+#include "FGInitialCondition.h"
+#include "FGTrimAxis.h"
+#include <models/FGAircraft.h>
+#include <models/FGPropulsion.h>
+#include <models/FGAerodynamics.h>
+
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_TRIMAXIS;
+
+/*****************************************************************************/
+
+FGTrimAxis::FGTrimAxis(FGFDMExec* fdex, FGInitialCondition* ic, State st,
+ Control ctrl) {
+
+ fdmex=fdex;
+ fgic=ic;
+ state=st;
+ control=ctrl;
+ max_iterations=10;
+ control_value=0;
+ its_to_stable_value=0;
+ total_iterations=0;
+ total_stability_iterations=0;
+ state_convert=1.0;
+ control_convert=1.0;
+ state_value=0;
+ state_target=0;
+ switch(state) {
+ case tUdot: tolerance = DEFAULT_TOLERANCE; break;
+ case tVdot: tolerance = DEFAULT_TOLERANCE; break;
+ case tWdot: tolerance = DEFAULT_TOLERANCE; break;
+ case tQdot: tolerance = DEFAULT_TOLERANCE / 10; break;
+ case tPdot: tolerance = DEFAULT_TOLERANCE / 10; break;
+ case tRdot: tolerance = DEFAULT_TOLERANCE / 10; break;
+ case tHmgt: tolerance = 0.01; break;
+ case tNlf: state_target=1.0; tolerance = 1E-5; break;
+ case tAll: break;
+ }
+
+ solver_eps=tolerance;
+ switch(control) {
+ case tThrottle:
+ control_min=0;
+ control_max=1;
+ control_value=0.5;
+ break;
+ case tBeta:
+ control_min=-30*degtorad;
+ control_max=30*degtorad;
+ control_convert=radtodeg;
+ break;
+ case tAlpha:
+ control_min=fdmex->GetAerodynamics()->GetAlphaCLMin();
+ control_max=fdmex->GetAerodynamics()->GetAlphaCLMax();
+ if(control_max <= control_min) {
+ control_max=20*degtorad;
+ control_min=-5*degtorad;
+ }
+ control_value= (control_min+control_max)/2;
+ control_convert=radtodeg;
+ solver_eps=tolerance/100;
+ break;
+ case tPitchTrim:
+ case tElevator:
+ case tRollTrim:
+ case tAileron:
+ case tYawTrim:
+ case tRudder:
+ control_min=-1;
+ control_max=1;
+ state_convert=radtodeg;
+ solver_eps=tolerance/100;
+ break;
+ case tAltAGL:
+ control_min=0;
+ control_max=30;
+ control_value=fdmex->GetPropagate()->GetDistanceAGL();
+ solver_eps=tolerance/100;
+ break;
+ case tTheta:
+ control_min=fdmex->GetPropagate()->GetEuler(eTht) - 5*degtorad;
+ control_max=fdmex->GetPropagate()->GetEuler(eTht) + 5*degtorad;
+ state_convert=radtodeg;
+ break;
+ case tPhi:
+ control_min=fdmex->GetPropagate()->GetEuler(ePhi) - 30*degtorad;
+ control_max=fdmex->GetPropagate()->GetEuler(ePhi) + 30*degtorad;
+ state_convert=radtodeg;
+ control_convert=radtodeg;
+ break;
+ case tGamma:
+ solver_eps=tolerance/100;
+ control_min=-80*degtorad;
+ control_max=80*degtorad;
+ control_convert=radtodeg;
+ break;
+ case tHeading:
+ control_min=fdmex->GetPropagate()->GetEuler(ePsi) - 30*degtorad;
+ control_max=fdmex->GetPropagate()->GetEuler(ePsi) + 30*degtorad;
+ state_convert=radtodeg;
+ break;
+ }
+
+
+ Debug(0);
+}
+
+/*****************************************************************************/
+
+FGTrimAxis::~FGTrimAxis(void)
+{
+ Debug(1);
+}
+
+/*****************************************************************************/
+
+void FGTrimAxis::getState(void) {
+ switch(state) {
+ case tUdot: state_value=fdmex->GetPropagate()->GetUVWdot(1)-state_target; break;
+ case tVdot: state_value=fdmex->GetPropagate()->GetUVWdot(2)-state_target; break;
+ case tWdot: state_value=fdmex->GetPropagate()->GetUVWdot(3)-state_target; break;
+ case tQdot: state_value=fdmex->GetPropagate()->GetPQRdot(2)-state_target;break;
+ case tPdot: state_value=fdmex->GetPropagate()->GetPQRdot(1)-state_target; break;
+ case tRdot: state_value=fdmex->GetPropagate()->GetPQRdot(3)-state_target; break;
+ case tHmgt: state_value=computeHmgt()-state_target; break;
+ case tNlf: state_value=fdmex->GetAircraft()->GetNlf()-state_target; break;
+ case tAll: break;
+ }
+}
+
+/*****************************************************************************/
+
+//States are not settable
+
+void FGTrimAxis::getControl(void) {
+ switch(control) {
+ case tThrottle: control_value=fdmex->GetFCS()->GetThrottleCmd(0); break;
+ case tBeta: control_value=fdmex->GetAuxiliary()->Getalpha(); break;
+ case tAlpha: control_value=fdmex->GetAuxiliary()->Getbeta(); break;
+ case tPitchTrim: control_value=fdmex->GetFCS() -> GetPitchTrimCmd(); break;
+ case tElevator: control_value=fdmex->GetFCS() -> GetDeCmd(); break;
+ case tRollTrim:
+ case tAileron: control_value=fdmex->GetFCS() -> GetDaCmd(); break;
+ case tYawTrim:
+ case tRudder: control_value=fdmex->GetFCS() -> GetDrCmd(); break;
+ case tAltAGL: control_value=fdmex->GetPropagate()->GetDistanceAGL();break;
+ case tTheta: control_value=fdmex->GetPropagate()->GetEuler(eTht); break;
+ case tPhi: control_value=fdmex->GetPropagate()->GetEuler(ePhi); break;
+ case tGamma: control_value=fdmex->GetAuxiliary()->GetGamma();break;
+ case tHeading: control_value=fdmex->GetPropagate()->GetEuler(ePsi); break;
+ }
+}
+
+/*****************************************************************************/
+
+double FGTrimAxis::computeHmgt(void) {
+ double diff;
+
+ diff = fdmex->GetPropagate()->GetEuler(ePsi) -
+ fdmex->GetAuxiliary()->GetGroundTrack();
+
+ if( diff < -M_PI ) {
+ return (diff + 2*M_PI);
+ } else if( diff > M_PI ) {
+ return (diff - 2*M_PI);
+ } else {
+ return diff;
+ }
+
+}
+
+/*****************************************************************************/
+
+
+void FGTrimAxis::setControl(void) {
+ switch(control) {
+ case tThrottle: setThrottlesPct(); break;
+ case tBeta: fgic->SetBetaRadIC(control_value); break;
+ case tAlpha: fgic->SetAlphaRadIC(control_value); break;
+ case tPitchTrim: fdmex->GetFCS()->SetPitchTrimCmd(control_value); break;
+ case tElevator: fdmex->GetFCS()->SetDeCmd(control_value); break;
+ case tRollTrim:
+ case tAileron: fdmex->GetFCS()->SetDaCmd(control_value); break;
+ case tYawTrim:
+ case tRudder: fdmex->GetFCS()->SetDrCmd(control_value); break;
+ case tAltAGL: fgic->SetAltitudeAGLFtIC(control_value); break;
+ case tTheta: fgic->SetPitchAngleRadIC(control_value); break;
+ case tPhi: fgic->SetRollAngleRadIC(control_value); break;
+ case tGamma: fgic->SetFlightPathAngleRadIC(control_value); break;
+ case tHeading: fgic->SetTrueHeadingRadIC(control_value); break;
+ }
+}
+
+
+
+
+
+/*****************************************************************************/
+
+// the aircraft center of rotation is no longer the cg once the gear
+// contact the ground so the altitude needs to be changed when pitch
+// and roll angle are adjusted. Instead of attempting to calculate the
+// new center of rotation, pick a gear unit as a reference and use its
+// location vector to calculate the new height change. i.e. new altitude =
+// earth z component of that vector (which is in body axes )
+void FGTrimAxis::SetThetaOnGround(double ff) {
+ int center,i,ref;
+
+ // favor an off-center unit so that the same one can be used for both
+ // pitch and roll. An on-center unit is used (for pitch)if that's all
+ // that's in contact with the ground.
+ i=0; ref=-1; center=-1;
+ while( (ref < 0) && (i < fdmex->GetGroundReactions()->GetNumGearUnits()) ) {
+ if(fdmex->GetGroundReactions()->GetGearUnit(i)->GetWOW()) {
+ if(fabs(fdmex->GetGroundReactions()->GetGearUnit(i)->GetBodyLocation(2)) > 0.01)
+ ref=i;
+ else
+ center=i;
+ }
+ i++;
+ }
+ if((ref < 0) && (center >= 0)) {
+ ref=center;
+ }
+ cout << "SetThetaOnGround ref gear: " << ref << endl;
+ if(ref >= 0) {
+ double sp = fdmex->GetPropagate()->GetSinEuler(ePhi);
+ double cp = fdmex->GetPropagate()->GetCosEuler(ePhi);
+ double lx = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(1);
+ double ly = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(2);
+ double lz = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(3);
+ double hagl = -1*lx*sin(ff) +
+ ly*sp*cos(ff) +
+ lz*cp*cos(ff);
+
+ fgic->SetAltitudeAGLFtIC(hagl);
+ cout << "SetThetaOnGround new alt: " << hagl << endl;
+ }
+ fgic->SetPitchAngleRadIC(ff);
+ cout << "SetThetaOnGround new theta: " << ff << endl;
+}
+
+/*****************************************************************************/
+
+bool FGTrimAxis::initTheta(void) {
+ int i,N;
+ int iForward = 0;
+ int iAft = 1;
+ double zAft,zForward,zDiff,theta;
+ double xAft,xForward,xDiff;
+ bool level;
+ double saveAlt;
+
+ saveAlt=fgic->GetAltitudeAGLFtIC();
+ fgic->SetAltitudeAGLFtIC(100);
+
+
+ N=fdmex->GetGroundReactions()->GetNumGearUnits();
+
+ //find the first wheel unit forward of the cg
+ //the list is short so a simple linear search is fine
+ for( i=0; i<N; i++ ) {
+ if(fdmex->GetGroundReactions()->GetGearUnit(i)->GetBodyLocation(1) > 0 ) {
+ iForward=i;
+ break;
+ }
+ }
+ //now find the first wheel unit aft of the cg
+ for( i=0; i<N; i++ ) {
+ if(fdmex->GetGroundReactions()->GetGearUnit(i)->GetBodyLocation(1) < 0 ) {
+ iAft=i;
+ break;
+ }
+ }
+
+ // now adjust theta till the wheels are the same distance from the ground
+ xAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetBodyLocation(1);
+ xForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetBodyLocation(1);
+ xDiff = xForward - xAft;
+ zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
+ zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
+ zDiff = zForward - zAft;
+ level=false;
+ theta=fgic->GetPitchAngleDegIC();
+ while(!level && (i < 100)) {
+ theta+=radtodeg*atan(zDiff/xDiff);
+ fgic->SetPitchAngleDegIC(theta);
+ fdmex->RunIC();
+ zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
+ zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
+ zDiff = zForward - zAft;
+ //cout << endl << theta << " " << zDiff << endl;
+ //cout << "0: " << fdmex->GetGroundReactions()->GetGearUnit(0)->GetLocalGear() << endl;
+ //cout << "1: " << fdmex->GetGroundReactions()->GetGearUnit(1)->GetLocalGear() << endl;
+ if(fabs(zDiff ) < 0.1)
+ level=true;
+ i++;
+ }
+ //cout << i << endl;
+ if (debug_lvl > 0) {
+ cout << " Initial Theta: " << fdmex->GetPropagate()->GetEuler(eTht)*radtodeg << endl;
+ cout << " Used gear unit " << iAft << " as aft and " << iForward << " as forward" << endl;
+ }
+ control_min=(theta+5)*degtorad;
+ control_max=(theta-5)*degtorad;
+ fgic->SetAltitudeAGLFtIC(saveAlt);
+ if(i < 100)
+ return true;
+ else
+ return false;
+}
+
+/*****************************************************************************/
+
+void FGTrimAxis::SetPhiOnGround(double ff) {
+ int i,ref;
+
+ i=0; ref=-1;
+ //must have an off-center unit here
+ while ( (ref < 0) && (i < fdmex->GetGroundReactions()->GetNumGearUnits()) ) {
+ if ( (fdmex->GetGroundReactions()->GetGearUnit(i)->GetWOW()) &&
+ (fabs(fdmex->GetGroundReactions()->GetGearUnit(i)->GetBodyLocation(2)) > 0.01))
+ ref=i;
+ i++;
+ }
+ if (ref >= 0) {
+ double st = fdmex->GetPropagate()->GetSinEuler(eTht);
+ double ct = fdmex->GetPropagate()->GetCosEuler(eTht);
+ double lx = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(1);
+ double ly = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(2);
+ double lz = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(3);
+ double hagl = -1*lx*st +
+ ly*sin(ff)*ct +
+ lz*cos(ff)*ct;
+
+ fgic->SetAltitudeAGLFtIC(hagl);
+ }
+ fgic->SetRollAngleRadIC(ff);
+
+}
+
+/*****************************************************************************/
+
+void FGTrimAxis::Run(void) {
+
+ double last_state_value;
+ int i;
+ setControl();
+ //cout << "FGTrimAxis::Run: " << control_value << endl;
+ i=0;
+ bool stable=false;
+ while(!stable) {
+ i++;
+ last_state_value=state_value;
+ fdmex->RunIC();
+ getState();
+ if(i > 1) {
+ if((fabs(last_state_value - state_value) < tolerance) || (i >= 100) )
+ stable=true;
+ }
+ }
+
+ its_to_stable_value=i;
+ total_stability_iterations+=its_to_stable_value;
+ total_iterations++;
+}
+
+/*****************************************************************************/
+
+void FGTrimAxis::setThrottlesPct(void) {
+ double tMin,tMax;
+ for(unsigned i=0;i<fdmex->GetPropulsion()->GetNumEngines();i++) {
+ tMin=fdmex->GetPropulsion()->GetEngine(i)->GetThrottleMin();
+ tMax=fdmex->GetPropulsion()->GetEngine(i)->GetThrottleMax();
+ //cout << "setThrottlespct: " << i << ", " << control_min << ", " << control_max << ", " << control_value;
+ fdmex->GetFCS()->SetThrottleCmd(i,tMin+control_value*(tMax-tMin));
+ //cout << "setThrottlespct: " << fdmex->GetFCS()->GetThrottleCmd(i) << endl;
+ fdmex->RunIC(); //apply throttle change
+ fdmex->GetPropulsion()->GetSteadyState();
+ }
+}
+
+/*****************************************************************************/
+
+void FGTrimAxis::AxisReport(void) {
+
+ char out[80];
+
+ sprintf(out," %20s: %6.2f %5s: %9.2e Tolerance: %3.0e",
+ GetControlName().c_str(), GetControl()*control_convert,
+ GetStateName().c_str(), GetState()+state_target, GetTolerance());
+ cout << out;
+
+ if( fabs(GetState()+state_target) < fabs(GetTolerance()) )
+ cout << " Passed" << endl;
+ else
+ cout << " Failed" << endl;
+}
+
+/*****************************************************************************/
+
+double FGTrimAxis::GetAvgStability( void ) {
+ if(total_iterations > 0) {
+ return double(total_stability_iterations)/double(total_iterations);
+ }
+ return 0;
+}
+
+/*****************************************************************************/
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGTrimAxis::Debug(int from)
+{
+
+ if (debug_lvl <= 0) return;
+ if (debug_lvl & 1 ) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGTrimAxis" << endl;
+ if (from == 1) cout << "Destroyed: FGTrimAxis" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGTrimAxis.h
+ Author: Tony Peden
+ Date started: 7/3/00
+
+ ------------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+ HISTORY
+--------------------------------------------------------------------------------
+7/3/00 TP Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGTRIMAXIS_H
+#define FGTRIMAXIS_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <string>
+
+#include "FGFDMExec.h"
+#include "FGJSBBase.h"
+#include "FGInitialCondition.h"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_TRIMAXIS "$Id$"
+
+#define DEFAULT_TOLERANCE 0.001
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+const string StateNames[10]= { "all","udot","vdot","wdot","qdot","pdot","rdot",
+ "hmgt","nlf"
+ };
+const string ControlNames[14]= { "Throttle","Sideslip","Angle of Attack",
+ "Elevator","Ailerons","Rudder",
+ "Altitude AGL", "Pitch Angle",
+ "Roll Angle", "Flight Path Angle",
+ "Pitch Trim", "Roll Trim", "Yaw Trim",
+ "Heading"
+ };
+
+class FGInitialCondition;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models an aircraft axis for purposes of trimming.
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+enum State { tAll,tUdot,tVdot,tWdot,tQdot,tPdot,tRdot,tHmgt,tNlf };
+enum Control { tThrottle, tBeta, tAlpha, tElevator, tAileron, tRudder, tAltAGL,
+ tTheta, tPhi, tGamma, tPitchTrim, tRollTrim, tYawTrim, tHeading };
+
+class FGTrimAxis : public FGJSBBase
+{
+public:
+ FGTrimAxis(FGFDMExec* fdmex,
+ FGInitialCondition *ic,
+ State st,
+ Control ctrl );
+ ~FGTrimAxis();
+
+ void Run(void);
+
+ double GetState(void) { getState(); return state_value; }
+ //Accels are not settable
+ inline void SetControl(double value ) { control_value=value; }
+ inline double GetControl(void) { return control_value; }
+
+ inline State GetStateType(void) { return state; }
+ inline Control GetControlType(void) { return control; }
+
+ inline string GetStateName(void) { return StateNames[state]; }
+ inline string GetControlName(void) { return ControlNames[control]; }
+
+ inline double GetControlMin(void) { return control_min; }
+ inline double GetControlMax(void) { return control_max; }
+
+ inline void SetControlToMin(void) { control_value=control_min; }
+ inline void SetControlToMax(void) { control_value=control_max; }
+
+ inline void SetControlLimits(double min, double max) {
+ control_min=min;
+ control_max=max;
+ }
+
+ inline void SetTolerance(double ff) { tolerance=ff;}
+ inline double GetTolerance(void) { return tolerance; }
+
+ inline double GetSolverEps(void) { return solver_eps; }
+ inline void SetSolverEps(double ff) { solver_eps=ff; }
+
+ inline int GetIterationLimit(void) { return max_iterations; }
+ inline void SetIterationLimit(int ii) { max_iterations=ii; }
+
+ inline int GetStability(void) { return its_to_stable_value; }
+ inline int GetRunCount(void) { return total_stability_iterations; }
+ double GetAvgStability( void );
+
+ void SetThetaOnGround(double ff);
+ void SetPhiOnGround(double ff);
+
+ inline void SetStateTarget(double target) { state_target=target; }
+ inline double GetStateTarget(void) { return state_target; }
+
+ bool initTheta(void);
+
+ void AxisReport(void);
+
+ bool InTolerance(void) { getState(); return (fabs(state_value) <= tolerance); }
+
+private:
+ FGFDMExec *fdmex;
+ FGInitialCondition *fgic;
+
+ State state;
+ Control control;
+
+ double state_target;
+
+ double state_value;
+ double control_value;
+
+ double control_min;
+ double control_max;
+
+ double tolerance;
+
+ double solver_eps;
+
+ double state_convert;
+ double control_convert;
+
+ int max_iterations;
+
+ int its_to_stable_value;
+ int total_stability_iterations;
+ int total_iterations;
+
+ void setThrottlesPct(void);
+
+ void getState(void);
+ void getControl(void);
+ void setControl(void);
+
+ double computeHmgt(void);
+
+ void Debug(int from);
+};
+}
+#endif
--- /dev/null
+noinst_LIBRARIES = libInit.a
+
+libInit_a_SOURCES = FGInitialCondition.cpp FGTrim.cpp FGTrimAxis.cpp
+
+noinst_HEADERS = FGInitialCondition.h FGTrim.h FGTrimAxis.h
+
+INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGGroundCallback.cpp
+ Author: Mathias Froehlich
+ Date started: 05/21/04
+
+ ------ Copyright (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) -------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+-------------------------------------------------------------------------------
+05/21/00 MF Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <math/FGColumnVector3.h>
+#include <math/FGLocation.h>
+#include "FGGroundCallback.h"
+
+namespace JSBSim {
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGGroundCallback::FGGroundCallback()
+{
+ mReferenceRadius = 20925650.0;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGGroundCallback::~FGGroundCallback()
+{
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGGroundCallback::GetAltitude(const FGLocation& loc) const
+{
+ return loc.GetRadius() - mReferenceRadius;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGGroundCallback::GetAGLevel(double t, const FGLocation& loc,
+ FGLocation& contact, FGColumnVector3& normal,
+ FGColumnVector3& vel) const
+{
+ vel = FGColumnVector3(0.0, 0.0, 0.0);
+ normal = (-1/FGColumnVector3(loc).Magnitude())*FGColumnVector3(loc);
+ double radius = loc.GetRadius();
+ double agl = GetAltitude(loc);
+ contact = ((radius-agl)/radius)*FGColumnVector3(loc);
+ return agl;
+}
+
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGGroundCallback.h
+ Author: Mathias Froehlich
+ Date started: 05/21/04
+
+ ------ Copyright (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) -------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+-------------------------------------------------------------------------------
+05/21/00 MF Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGGROUNDCALLBACK_H
+#define FGGROUNDCALLBACK_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <math/FGColumnVector3.h>
+#include <math/FGLocation.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_GROUNDCALLBACK "$Id$"
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** This class provides callback slots to get ground specific data like
+ ground elevation and such.
+ There is a default implementation, which returns values for a
+ ball formed earth.
+
+ @author Mathias Froehlich
+ @version $Id$
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGGroundCallback : public FGJSBBase
+{
+public:
+ FGGroundCallback();
+ virtual ~FGGroundCallback();
+
+ /** Compute the altitude above sealevel. */
+ virtual double GetAltitude(const FGLocation& l) const;
+ /** Compute the altitude above ground. Defaults to sealevel altitude. */
+ virtual double GetAGLevel(double t, const FGLocation& l, FGLocation& cont,
+ FGColumnVector3& n, FGColumnVector3& v) const;
+private:
+ /// Reference radius.
+ double mReferenceRadius;
+};
+
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGPropertyManager.cpp
+ Author: Tony Peden
+ Based on work originally by David Megginson
+ Date: 2/2002
+
+ ------------- Copyright (C) 2002 -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGPropertyManager.h"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+using namespace std;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+COMMENTS, REFERENCES, and NOTES [use "class documentation" below for API docs]
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+*/
+
+namespace JSBSim {
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGPropertyManager::mkPropertyName(string name, bool lowercase) {
+
+ /* do this two pass to avoid problems with characters getting skipped
+ because the index changed */
+ unsigned i;
+ for(i=0;i<name.length();i++) {
+ if( lowercase && isupper(name[i]) )
+ name[i]=tolower(name[i]);
+ else if( isspace(name[i]) )
+ name[i]='-';
+ }
+ /*
+ for(i=0;i<name.length();i++) {
+ if( name[i] == '/' )
+ name.erase(i,1);
+ }
+ */
+ return name;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGPropertyManager*
+FGPropertyManager::GetNode (const string &path, bool create)
+{
+ SGPropertyNode* node=this->getNode(path.c_str(), create);
+ if (node == 0 && !suppress_warning)
+ cout << "FGPropertyManager::GetNode() No node found for "
+ << path << endl;
+ return (FGPropertyManager*)node;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGPropertyManager*
+FGPropertyManager::GetNode (const string &relpath, int index, bool create)
+{
+ return (FGPropertyManager*)getNode(relpath.c_str(),index,create);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+bool FGPropertyManager::HasNode (const string &path)
+{
+ // Checking if a node exists shouldn't write a warning if it doesn't exist
+ suppress_warning = true;
+ bool has_node = (GetNode(path, false) != 0);
+ suppress_warning = false;
+ return has_node;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGPropertyManager::GetName( void ) {
+ return string( getName() );
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGPropertyManager::GetFullyQualifiedName(void) {
+ vector<string> stack;
+ stack.push_back( getDisplayName(true) );
+ SGPropertyNode* tmpn=getParent();
+ bool atroot=false;
+ while( !atroot ) {
+ stack.push_back( tmpn->getDisplayName(true) );
+ if( !tmpn->getParent() )
+ atroot=true;
+ else
+ tmpn=tmpn->getParent();
+ }
+
+ string fqname="";
+ for(unsigned i=stack.size()-1;i>0;i--) {
+ fqname+= stack[i];
+ fqname+= "/";
+ }
+ fqname+= stack[0];
+ return fqname;
+
+}
+
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGPropertyManager::GetBool (const string &name, bool defaultValue)
+{
+ return getBoolValue(name.c_str(), defaultValue);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+int FGPropertyManager::GetInt (const string &name, int defaultValue )
+{
+ return getIntValue(name.c_str(), defaultValue);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+int FGPropertyManager::GetLong (const string &name, long defaultValue )
+{
+ return getLongValue(name.c_str(), defaultValue);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+float FGPropertyManager::GetFloat (const string &name, float defaultValue )
+{
+ return getFloatValue(name.c_str(), defaultValue);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGPropertyManager::GetDouble (const string &name, double defaultValue )
+{
+ return getDoubleValue(name.c_str(), defaultValue);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGPropertyManager::GetString (const string &name, string defaultValue )
+{
+ return string(getStringValue(name.c_str(), defaultValue.c_str()));
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGPropertyManager::SetBool (const string &name, bool val)
+{
+ return setBoolValue(name.c_str(), val);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGPropertyManager::SetInt (const string &name, int val)
+{
+ return setIntValue(name.c_str(), val);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGPropertyManager::SetLong (const string &name, long val)
+{
+ return setLongValue(name.c_str(), val);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGPropertyManager::SetFloat (const string &name, float val)
+{
+ return setFloatValue(name.c_str(), val);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGPropertyManager::SetDouble (const string &name, double val)
+{
+ return setDoubleValue(name.c_str(), val);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGPropertyManager::SetString (const string &name, const string &val)
+{
+ return setStringValue(name.c_str(), val.c_str());
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropertyManager::SetArchivable (const string &name, bool state )
+{
+ SGPropertyNode * node = getNode(name.c_str());
+ if (node == 0)
+ cout <<
+ "Attempt to set archive flag for non-existant property "
+ << name << endl;
+ else
+ node->setAttribute(SGPropertyNode::ARCHIVE, state);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropertyManager::SetReadable (const string &name, bool state )
+{
+ SGPropertyNode * node = getNode(name.c_str());
+ if (node == 0)
+ cout <<
+ "Attempt to set read flag for non-existant property "
+ << name << endl;
+ else
+ node->setAttribute(SGPropertyNode::READ, state);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropertyManager::SetWritable (const string &name, bool state )
+{
+ SGPropertyNode * node = getNode(name.c_str());
+ if (node == 0)
+ cout <<
+ "Attempt to set write flag for non-existant property "
+ << name << endl;
+ else
+ node->setAttribute(SGPropertyNode::WRITE, state);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropertyManager::Untie (const string &name)
+{
+ if (!untie(name.c_str()))
+ cout << "Failed to untie property " << name << endl;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropertyManager::Tie (const string &name, bool *pointer, bool useDefault)
+{
+ if (!tie(name.c_str(), SGRawValuePointer<bool>(pointer), useDefault))
+ cout << "Failed to tie property " << name << " to a pointer" << endl;
+ else if (debug_lvl & 0x20)
+ cout << name << endl;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropertyManager::Tie (const string &name, int *pointer,
+ bool useDefault )
+{
+ if (!tie(name.c_str(), SGRawValuePointer<int>(pointer), useDefault))
+ cout << "Failed to tie property " << name << " to a pointer" << endl;
+ else if (debug_lvl & 0x20)
+ cout << name << endl;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropertyManager::Tie (const string &name, long *pointer,
+ bool useDefault )
+{
+ if (!tie(name.c_str(), SGRawValuePointer<long>(pointer), useDefault))
+ cout << "Failed to tie property " << name << " to a pointer" << endl;
+ else if (debug_lvl & 0x20)
+ cout << name << endl;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropertyManager::Tie (const string &name, float *pointer,
+ bool useDefault )
+{
+ if (!tie(name.c_str(), SGRawValuePointer<float>(pointer), useDefault))
+ cout << "Failed to tie property " << name << " to a pointer" << endl;
+ else if (debug_lvl & 0x20)
+ cout << name << endl;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropertyManager::Tie (const string &name, double *pointer, bool useDefault)
+{
+ if (!tie(name.c_str(), SGRawValuePointer<double>(pointer), useDefault))
+ cout << "Failed to tie property " << name << " to a pointer" << endl;
+ else if (debug_lvl & 0x20)
+ cout << name << endl;
+}
+
+} // namespace JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGPropertyManager.h
+ Author: Tony Peden
+ Based on work originally by David Megginson
+ Date: 2/2002
+
+ ------------- Copyright (C) 2002 -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGPROPERTYMANAGER_H
+#define FGPROPERTYMANAGER_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <string>
+#ifdef FGFS
+# include <simgear/props/props.hxx>
+#else
+# include "simgear/props/props.hxx"
+#endif
+
+#include "FGJSBBase.h"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_PROPERTYMANAGER "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+using namespace std;
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Class wrapper for property handling.
+ @author David Megginson, Tony Peden
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGPropertyManager : public SGPropertyNode, public FGJSBBase
+{
+ private:
+ bool suppress_warning;
+ public:
+ /// Constructor
+ FGPropertyManager(void) {suppress_warning = false;}
+ /// Destructor
+ ~FGPropertyManager(void) {}
+
+ /** Property-ify a name
+ * replaces spaces with '-' and, optionally, makes name all lower case
+ * @param name string to change
+ * @param lowercase true to change all upper case chars to lower
+ * NOTE: this function changes its argument and thus relies
+ * on pass by value
+ */
+ string mkPropertyName(string name, bool lowercase);
+
+ /**
+ * Get a property node.
+ *
+ * @param path The path of the node, relative to root.
+ * @param create true to create the node if it doesn't exist.
+ * @return The node, or 0 if none exists and none was created.
+ */
+ FGPropertyManager*
+ GetNode (const string &path, bool create = false);
+
+ FGPropertyManager*
+ GetNode (const string &relpath, int index, bool create = false);
+
+ /**
+ * Test whether a given node exists.
+ *
+ * @param path The path of the node, relative to root.
+ * @return true if the node exists, false otherwise.
+ */
+ bool HasNode (const string &path);
+
+ /**
+ * Get the name of a node
+ */
+ string GetName( void );
+
+ /**
+ * Get the fully qualified name of a node
+ * This function is very slow, so is probably useful for debugging only.
+ */
+ string GetFullyQualifiedName(void);
+
+ /**
+ * Get a bool value for a property.
+ *
+ * This method is convenient but inefficient. It should be used
+ * infrequently (i.e. for initializing, loading, saving, etc.),
+ * not in the main loop. If you need to get a value frequently,
+ * it is better to look up the node itself using GetNode and then
+ * use the node's getBoolValue() method, to avoid the lookup overhead.
+ *
+ * @param name The property name.
+ * @param defaultValue The default value to return if the property
+ * does not exist.
+ * @return The property's value as a bool, or the default value provided.
+ */
+ bool GetBool (const string &name, bool defaultValue = false);
+
+
+ /**
+ * Get an int value for a property.
+ *
+ * This method is convenient but inefficient. It should be used
+ * infrequently (i.e. for initializing, loading, saving, etc.),
+ * not in the main loop. If you need to get a value frequently,
+ * it is better to look up the node itself using GetNode and then
+ * use the node's getIntValue() method, to avoid the lookup overhead.
+ *
+ * @param name The property name.
+ * @param defaultValue The default value to return if the property
+ * does not exist.
+ * @return The property's value as an int, or the default value provided.
+ */
+ int GetInt (const string &name, int defaultValue = 0);
+
+
+ /**
+ * Get a long value for a property.
+ *
+ * This method is convenient but inefficient. It should be used
+ * infrequently (i.e. for initializing, loading, saving, etc.),
+ * not in the main loop. If you need to get a value frequently,
+ * it is better to look up the node itself using GetNode and then
+ * use the node's getLongValue() method, to avoid the lookup overhead.
+ *
+ * @param name The property name.
+ * @param defaultValue The default value to return if the property
+ * does not exist.
+ * @return The property's value as a long, or the default value provided.
+ */
+ int GetLong (const string &name, long defaultValue = 0L);
+
+
+ /**
+ * Get a float value for a property.
+ *
+ * This method is convenient but inefficient. It should be used
+ * infrequently (i.e. for initializing, loading, saving, etc.),
+ * not in the main loop. If you need to get a value frequently,
+ * it is better to look up the node itself using GetNode and then
+ * use the node's getFloatValue() method, to avoid the lookup overhead.
+ *
+ * @param name The property name.
+ * @param defaultValue The default value to return if the property
+ * does not exist.
+ * @return The property's value as a float, or the default value provided.
+ */
+ float GetFloat (const string &name, float defaultValue = 0.0);
+
+
+ /**
+ * Get a double value for a property.
+ *
+ * This method is convenient but inefficient. It should be used
+ * infrequently (i.e. for initializing, loading, saving, etc.),
+ * not in the main loop. If you need to get a value frequently,
+ * it is better to look up the node itself using GetNode and then
+ * use the node's getDoubleValue() method, to avoid the lookup overhead.
+ *
+ * @param name The property name.
+ * @param defaultValue The default value to return if the property
+ * does not exist.
+ * @return The property's value as a double, or the default value provided.
+ */
+ double GetDouble (const string &name, double defaultValue = 0.0);
+
+
+ /**
+ * Get a string value for a property.
+ *
+ * This method is convenient but inefficient. It should be used
+ * infrequently (i.e. for initializing, loading, saving, etc.),
+ * not in the main loop. If you need to get a value frequently,
+ * it is better to look up the node itself using GetNode and then
+ * use the node's getStringValue() method, to avoid the lookup overhead.
+ *
+ * @param name The property name.
+ * @param defaultValue The default value to return if the property
+ * does not exist.
+ * @return The property's value as a string, or the default value provided.
+ */
+ string GetString (const string &name, string defaultValue = "");
+
+
+ /**
+ * Set a bool value for a property.
+ *
+ * Assign a bool value to a property. If the property does not
+ * yet exist, it will be created and its type will be set to
+ * BOOL; if it has a type of UNKNOWN, the type will also be set to
+ * BOOL; otherwise, the bool value will be converted to the property's
+ * type.
+ *
+ * @param name The property name.
+ * @param val The new value for the property.
+ * @return true if the assignment succeeded, false otherwise.
+ */
+ bool SetBool (const string &name, bool val);
+
+
+ /**
+ * Set an int value for a property.
+ *
+ * Assign an int value to a property. If the property does not
+ * yet exist, it will be created and its type will be set to
+ * INT; if it has a type of UNKNOWN, the type will also be set to
+ * INT; otherwise, the bool value will be converted to the property's
+ * type.
+ *
+ * @param name The property name.
+ * @param val The new value for the property.
+ * @return true if the assignment succeeded, false otherwise.
+ */
+ bool SetInt (const string &name, int val);
+
+
+ /**
+ * Set a long value for a property.
+ *
+ * Assign a long value to a property. If the property does not
+ * yet exist, it will be created and its type will be set to
+ * LONG; if it has a type of UNKNOWN, the type will also be set to
+ * LONG; otherwise, the bool value will be converted to the property's
+ * type.
+ *
+ * @param name The property name.
+ * @param val The new value for the property.
+ * @return true if the assignment succeeded, false otherwise.
+ */
+ bool SetLong (const string &name, long val);
+
+
+ /**
+ * Set a float value for a property.
+ *
+ * Assign a float value to a property. If the property does not
+ * yet exist, it will be created and its type will be set to
+ * FLOAT; if it has a type of UNKNOWN, the type will also be set to
+ * FLOAT; otherwise, the bool value will be converted to the property's
+ * type.
+ *
+ * @param name The property name.
+ * @param val The new value for the property.
+ * @return true if the assignment succeeded, false otherwise.
+ */
+ bool SetFloat (const string &name, float val);
+
+
+ /**
+ * Set a double value for a property.
+ *
+ * Assign a double value to a property. If the property does not
+ * yet exist, it will be created and its type will be set to
+ * DOUBLE; if it has a type of UNKNOWN, the type will also be set to
+ * DOUBLE; otherwise, the double value will be converted to the property's
+ * type.
+ *
+ * @param name The property name.
+ * @param val The new value for the property.
+ * @return true if the assignment succeeded, false otherwise.
+ */
+ bool SetDouble (const string &name, double val);
+
+
+ /**
+ * Set a string value for a property.
+ *
+ * Assign a string value to a property. If the property does not
+ * yet exist, it will be created and its type will be set to
+ * STRING; if it has a type of UNKNOWN, the type will also be set to
+ * STRING; otherwise, the string value will be converted to the property's
+ * type.
+ *
+ * @param name The property name.
+ * @param val The new value for the property.
+ * @return true if the assignment succeeded, false otherwise.
+ */
+ bool SetString (const string &name, const string &val);
+
+
+ ////////////////////////////////////////////////////////////////////////
+ // Convenience functions for setting property attributes.
+ ////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Set the state of the archive attribute for a property.
+ *
+ * If the archive attribute is true, the property will be written
+ * when a flight is saved; if it is false, the property will be
+ * skipped.
+ *
+ * A warning message will be printed if the property does not exist.
+ *
+ * @param name The property name.
+ * @param state The state of the archive attribute (defaults to true).
+ */
+ void SetArchivable (const string &name, bool state = true);
+
+
+ /**
+ * Set the state of the read attribute for a property.
+ *
+ * If the read attribute is true, the property value will be readable;
+ * if it is false, the property value will always be the default value
+ * for its type.
+ *
+ * A warning message will be printed if the property does not exist.
+ *
+ * @param name The property name.
+ * @param state The state of the read attribute (defaults to true).
+ */
+ void SetReadable (const string &name, bool state = true);
+
+
+ /**
+ * Set the state of the write attribute for a property.
+ *
+ * If the write attribute is true, the property value may be modified
+ * (depending on how it is tied); if the write attribute is false, the
+ * property value may not be modified.
+ *
+ * A warning message will be printed if the property does not exist.
+ *
+ * @param name The property name.
+ * @param state The state of the write attribute (defaults to true).
+ */
+ void SetWritable (const string &name, bool state = true);
+
+
+ ////////////////////////////////////////////////////////////////////////
+ // Convenience functions for tying properties, with logging.
+ ////////////////////////////////////////////////////////////////////////
+
+
+ /**
+ * Untie a property from an external data source.
+ *
+ * Classes should use this function to release control of any
+ * properties they are managing.
+ */
+ void Untie (const string &name);
+
+
+ // Templates cause ambiguity here
+
+ /**
+ * Tie a property to an external bool variable.
+ *
+ * The property's value will automatically mirror the variable's
+ * value, and vice-versa, until the property is untied.
+ *
+ * @param name The property name to tie (full path).
+ * @param pointer A pointer to the variable.
+ * @param useDefault true if any existing property value should be
+ * copied to the variable; false if the variable should not
+ * be modified; defaults to true.
+ */
+ void
+ Tie (const string &name, bool *pointer, bool useDefault = true);
+
+
+ /**
+ * Tie a property to an external int variable.
+ *
+ * The property's value will automatically mirror the variable's
+ * value, and vice-versa, until the property is untied.
+ *
+ * @param name The property name to tie (full path).
+ * @param pointer A pointer to the variable.
+ * @param useDefault true if any existing property value should be
+ * copied to the variable; false if the variable should not
+ * be modified; defaults to true.
+ */
+ void
+ Tie (const string &name, int *pointer, bool useDefault = true);
+
+
+ /**
+ * Tie a property to an external long variable.
+ *
+ * The property's value will automatically mirror the variable's
+ * value, and vice-versa, until the property is untied.
+ *
+ * @param name The property name to tie (full path).
+ * @param pointer A pointer to the variable.
+ * @param useDefault true if any existing property value should be
+ * copied to the variable; false if the variable should not
+ * be modified; defaults to true.
+ */
+ void
+ Tie (const string &name, long *pointer, bool useDefault = true);
+
+
+ /**
+ * Tie a property to an external float variable.
+ *
+ * The property's value will automatically mirror the variable's
+ * value, and vice-versa, until the property is untied.
+ *
+ * @param name The property name to tie (full path).
+ * @param pointer A pointer to the variable.
+ * @param useDefault true if any existing property value should be
+ * copied to the variable; false if the variable should not
+ * be modified; defaults to true.
+ */
+ void
+ Tie (const string &name, float *pointer, bool useDefault = true);
+
+ /**
+ * Tie a property to an external double variable.
+ *
+ * The property's value will automatically mirror the variable's
+ * value, and vice-versa, until the property is untied.
+ *
+ * @param name The property name to tie (full path).
+ * @param pointer A pointer to the variable.
+ * @param useDefault true if any existing property value should be
+ * copied to the variable; false if the variable should not
+ * be modified; defaults to true.
+ */
+ void
+ Tie (const string &name, double *pointer, bool useDefault = true);
+
+//============================================================================
+//
+// All of the following functions *must* be inlined, otherwise linker
+// errors will result
+//
+//============================================================================
+
+ /* template <class V> void
+ Tie (const string &name, V (*getter)(), void (*setter)(V) = 0,
+ bool useDefault = true);
+
+ template <class V> void
+ Tie (const string &name, int index, V (*getter)(int),
+ void (*setter)(int, V) = 0, bool useDefault = true);
+
+ template <class T, class V> void
+ Tie (const string &name, T * obj, V (T::*getter)() const,
+ void (T::*setter)(V) = 0, bool useDefault = true);
+
+ template <class T, class V> void
+ Tie (const string &name, T * obj, int index,
+ V (T::*getter)(int) const, void (T::*setter)(int, V) = 0,
+ bool useDefault = true); */
+
+ /**
+ * Tie a property to a pair of simple functions.
+ *
+ * Every time the property value is queried, the getter (if any) will
+ * be invoked; every time the property value is modified, the setter
+ * (if any) will be invoked. The getter can be 0 to make the property
+ * unreadable, and the setter can be 0 to make the property
+ * unmodifiable.
+ *
+ * @param name The property name to tie (full path).
+ * @param getter The getter function, or 0 if the value is unreadable.
+ * @param setter The setter function, or 0 if the value is unmodifiable.
+ * @param useDefault true if the setter should be invoked with any existing
+ * property value should be; false if the old value should be
+ * discarded; defaults to true.
+ */
+
+ template <class V> inline void
+ Tie (const string &name, V (*getter)(), void (*setter)(V) = 0, bool useDefault = true)
+ {
+ if (!tie(name.c_str(), SGRawValueFunctions<V>(getter, setter), useDefault))
+ cout << "Failed to tie property " << name << " to functions" << endl;
+ else if (debug_lvl & 0x20)
+ cout << name << endl;
+ }
+
+
+ /**
+ * Tie a property to a pair of indexed functions.
+ *
+ * Every time the property value is queried, the getter (if any) will
+ * be invoked with the index provided; every time the property value
+ * is modified, the setter (if any) will be invoked with the index
+ * provided. The getter can be 0 to make the property unreadable, and
+ * the setter can be 0 to make the property unmodifiable.
+ *
+ * @param name The property name to tie (full path).
+ * @param index The integer argument to pass to the getter and
+ * setter functions.
+ * @param getter The getter function, or 0 if the value is unreadable.
+ * @param setter The setter function, or 0 if the value is unmodifiable.
+ * @param useDefault true if the setter should be invoked with any existing
+ * property value should there be one; false if the old value should be
+ * discarded; defaults to true.
+ */
+ template <class V> inline void Tie (const string &name, int index, V (*getter)(int),
+ void (*setter)(int, V) = 0, bool useDefault = true)
+ {
+ if (!tie(name.c_str(), SGRawValueFunctionsIndexed<V>(index, getter, setter), useDefault))
+ cout << "Failed to tie property " << name << " to indexed functions" << endl;
+ else if (debug_lvl & 0x20)
+ cout << name << endl;
+ }
+
+
+ /**
+ * Tie a property to a pair of object methods.
+ *
+ * Every time the property value is queried, the getter (if any) will
+ * be invoked; every time the property value is modified, the setter
+ * (if any) will be invoked. The getter can be 0 to make the property
+ * unreadable, and the setter can be 0 to make the property
+ * unmodifiable.
+ *
+ * @param name The property name to tie (full path).
+ * @param obj The object whose methods should be invoked.
+ * @param getter The object's getter method, or 0 if the value is
+ * unreadable.
+ * @param setter The object's setter method, or 0 if the value is
+ * unmodifiable.
+ * @param useDefault true if the setter should be invoked with any existing
+ * property value should be; false if the old value should be
+ * discarded; defaults to true.
+ */
+ template <class T, class V> inline void
+ Tie (const string &name, T * obj, V (T::*getter)() const,
+ void (T::*setter)(V) = 0, bool useDefault = true)
+ {
+ if (!tie(name.c_str(), SGRawValueMethods<T,V>(*obj, getter, setter), useDefault))
+ cout << "Failed to tie property " << name << " to object methods" << endl;
+ else if (debug_lvl & 0x20)
+ cout << name << endl;
+ }
+
+ /**
+ * Tie a property to a pair of indexed object methods.
+ *
+ * Every time the property value is queried, the getter (if any) will
+ * be invoked with the index provided; every time the property value
+ * is modified, the setter (if any) will be invoked with the index
+ * provided. The getter can be 0 to make the property unreadable, and
+ * the setter can be 0 to make the property unmodifiable.
+ *
+ * @param name The property name to tie (full path).
+ * @param obj The object whose methods should be invoked.
+ * @param index The integer argument to pass to the getter and
+ * setter methods.
+ * @param getter The getter method, or 0 if the value is unreadable.
+ * @param setter The setter method, or 0 if the value is unmodifiable.
+ * @param useDefault true if the setter should be invoked with any existing
+ * property value should be; false if the old value should be
+ * discarded; defaults to true.
+ */
+ template <class T, class V> inline void
+ Tie (const string &name, T * obj, int index, V (T::*getter)(int) const,
+ void (T::*setter)(int, V) = 0, bool useDefault = true)
+ {
+ if (!tie(name.c_str(), SGRawValueMethodsIndexed<T,V>(*obj, index, getter, setter), useDefault))
+ cout << "Failed to tie property " << name << " to indexed object methods" << endl;
+ else if (debug_lvl & 0x20)
+ cout << name << endl;
+ }
+};
+}
+#endif // FGPROPERTYMANAGER_H
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGScript.cpp
+ Author: Jon S. Berndt
+ Date started: 12/21/01
+ Purpose: Loads and runs JSBSim scripts.
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+This class wraps up the simulation scripting routines.
+
+HISTORY
+--------------------------------------------------------------------------------
+12/21/01 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+COMMENTS, REFERENCES, and NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# include STL_IOSTREAM
+# include STL_ITERATOR
+#else
+# if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
+# include <iostream.h>
+# else
+# include <iostream>
+# endif
+# include <iterator>
+#endif
+
+#include "FGScript.h"
+#include "FGXMLParse.h"
+#include <initialization/FGTrim.h>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_FGSCRIPT;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+GLOBAL DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+// Constructor
+
+FGScript::FGScript(FGFDMExec* fgex) : FDMExec(fgex)
+{
+ State = FDMExec->GetState();
+ PropertyManager=FDMExec->GetPropertyManager();
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGScript::~FGScript()
+{
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGScript::LoadScript( string script )
+{
+ string aircraft="", initialize="", comparison = "", prop_name="";
+ Element *document=0, *element=0, *run_element=0, *when_element=0;
+ Element *parameter_element=0, *set_element=0;
+ bool result = false;
+ double dt = 0.0, value = 0.0;
+ FGXMLParse script_file_parser;
+ struct condition *newCondition;
+ ifstream script_file(script.c_str());
+
+ if ( !script_file ) return false;
+
+ readXML(script_file, script_file_parser);
+ document = script_file_parser.GetDocument();
+
+ if (document->GetName() != string("runscript")) {
+ cerr << "File: " << script << " is not a script file" << endl;
+ return false;
+ }
+
+ // read aircraft and initialization files
+
+ element = document->FindElement("use");
+ if (element) {
+ aircraft = element->GetAttributeValue("aircraft");
+ if (!aircraft.empty()) {
+ result = FDMExec->LoadModel(aircraft);
+ if (!result) return false;
+ } else {
+ cerr << "Aircraft must be specified first in script file." << endl;
+ return false;
+ }
+
+ element = document->FindNextElement("use");
+ initialize = element->GetAttributeValue("initialize");
+
+ } else {
+ cerr << "No \"use\" directives in the script file." << endl;
+ return false;
+ }
+
+ run_element = document->FindElement("run");
+
+ if (!run_element) {
+ cerr << "No \"run\" element found in script." << endl;
+ return false;
+ }
+
+ // Set sim timing
+
+ StartTime = run_element->GetAttributeValueAsNumber("start");
+ State->Setsim_time(StartTime);
+ EndTime = run_element->GetAttributeValueAsNumber("end");
+ dt = run_element->GetAttributeValueAsNumber("dt");
+ State->Setdt(dt);
+
+ // read "when" tests from script
+
+ when_element = run_element->FindElement("when");
+ while (when_element) { // "when" processing
+ newCondition = new struct condition();
+
+ // read parameters
+ parameter_element = when_element->FindElement("parameter");
+ while (parameter_element) {
+ prop_name = parameter_element->GetAttributeValue("name");
+ newCondition->TestParam.push_back( PropertyManager->GetNode(prop_name) );
+ value = parameter_element->GetAttributeValueAsNumber("value");
+ newCondition->TestValue.push_back(value);
+ comparison = parameter_element->GetAttributeValue("comparison");
+ newCondition->Comparison.push_back(comparison);
+ parameter_element = when_element->FindNextElement("parameter");
+ }
+
+ // read set definitions
+ set_element = when_element->FindElement("set");
+ while (set_element) {
+ prop_name = set_element->GetAttributeValue("name");
+ newCondition->SetParam.push_back( PropertyManager->GetNode(prop_name) );
+ value = set_element->GetAttributeValueAsNumber("value");
+ newCondition->SetValue.push_back(value);
+ newCondition->Triggered.push_back(false);
+ newCondition->OriginalValue.push_back(0.0);
+ newCondition->newValue.push_back(0.0);
+ newCondition->StartTime.push_back(0.0);
+ newCondition->EndTime.push_back(0.0);
+ string tempCompare = set_element->GetAttributeValue("type");
+ if (tempCompare == "FG_DELTA") newCondition->Type.push_back(FG_DELTA);
+ else if (tempCompare == "FG_BOOL") newCondition->Type.push_back(FG_BOOL);
+ else if (tempCompare == "FG_VALUE") newCondition->Type.push_back(FG_VALUE);
+ else newCondition->Type.push_back(FG_VALUE); // DEFAULT
+ tempCompare = set_element->GetAttributeValue("action");
+ if (tempCompare == "FG_RAMP") newCondition->Action.push_back(FG_RAMP);
+ else if (tempCompare == "FG_STEP") newCondition->Action.push_back(FG_STEP);
+ else if (tempCompare == "FG_EXP") newCondition->Action.push_back(FG_EXP);
+ else newCondition->Action.push_back(FG_STEP); // DEFAULT
+
+ if (set_element->GetAttributeValue("persistent") == "true")
+ newCondition->Persistent.push_back(true);
+ else
+ newCondition->Persistent.push_back(false); // DEFAULT
+
+ if (!set_element->GetAttributeValue("tc").empty())
+ newCondition->TC.push_back(set_element->GetAttributeValueAsNumber("tc"));
+ else
+ newCondition->TC.push_back(1.0); // DEFAULT
+
+ set_element = when_element->FindNextElement("set");
+ }
+ Conditions.push_back(*newCondition);
+ when_element = run_element->FindNextElement("when");
+ }
+
+ Debug(4);
+
+ FGInitialCondition *IC=FDMExec->GetIC();
+ if ( ! IC->Load( initialize )) {
+ cerr << "Initialization unsuccessful" << endl;
+ exit(-1);
+ }
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGScript::RunScript(void)
+{
+ vector <struct condition>::iterator iC = Conditions.begin();
+ bool truth = false;
+ bool WholeTruth = false;
+ unsigned i;
+
+ double currentTime = State->Getsim_time();
+ double newSetValue = 0;
+
+ if (currentTime > EndTime) return false;
+
+ while (iC < Conditions.end()) {
+ // determine whether the set of conditional tests for this condition equate
+ // to true
+ for (i=0; i<iC->TestValue.size(); i++) {
+ if (iC->Comparison[i] == "lt")
+ truth = iC->TestParam[i]->getDoubleValue() < iC->TestValue[i];
+ else if (iC->Comparison[i] == "le")
+ truth = iC->TestParam[i]->getDoubleValue() <= iC->TestValue[i];
+ else if (iC->Comparison[i] == "eq")
+ truth = iC->TestParam[i]->getDoubleValue() == iC->TestValue[i];
+ else if (iC->Comparison[i] == "ge")
+ truth = iC->TestParam[i]->getDoubleValue() >= iC->TestValue[i];
+ else if (iC->Comparison[i] == "gt")
+ truth = iC->TestParam[i]->getDoubleValue() > iC->TestValue[i];
+ else if (iC->Comparison[i] == "ne")
+ truth = iC->TestParam[i]->getDoubleValue() != iC->TestValue[i];
+ else
+ cerr << "Bad comparison" << endl;
+
+ if (i == 0) WholeTruth = truth;
+ else WholeTruth = WholeTruth && truth;
+
+ if (!truth && iC->Persistent[i] && iC->Triggered[i]) iC->Triggered[i] = false;
+ }
+
+ // if the conditions are true, do the setting of the desired parameters
+
+ if (WholeTruth) {
+ for (i=0; i<iC->SetValue.size(); i++) {
+ if ( ! iC->Triggered[i]) {
+ iC->OriginalValue[i] = iC->SetParam[i]->getDoubleValue();
+ switch (iC->Type[i]) {
+ case FG_VALUE:
+ iC->newValue[i] = iC->SetValue[i];
+ break;
+ case FG_DELTA:
+ iC->newValue[i] = iC->OriginalValue[i] + iC->SetValue[i];
+ break;
+ case FG_BOOL:
+ iC->newValue[i] = iC->SetValue[i];
+ break;
+ default:
+ cerr << "Invalid Type specified" << endl;
+ break;
+ }
+ iC->Triggered[i] = true;
+ iC->StartTime[i] = currentTime;
+ }
+
+ double time_span = currentTime - iC->StartTime[i];
+ double value_span = iC->newValue[i] - iC->OriginalValue[i];
+
+ switch (iC->Action[i]) {
+ case FG_RAMP:
+ if (time_span <= iC->TC[i])
+ newSetValue = time_span/iC->TC[i] * value_span + iC->OriginalValue[i];
+ else
+ newSetValue = iC->newValue[i];
+ break;
+ case FG_STEP:
+ newSetValue = iC->newValue[i];
+ break;
+ case FG_EXP:
+ newSetValue = (1 - exp( -time_span/iC->TC[i] )) * value_span + iC->OriginalValue[i];
+ break;
+ default:
+ cerr << "Invalid Action specified" << endl;
+ break;
+ }
+ iC->SetParam[i]->setDoubleValue(newSetValue);
+ }
+ }
+ iC++;
+ }
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGScript::Debug(int from)
+{
+ unsigned int i;
+
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+ } else if (from == 3) {
+ } else if (from == 4) { // print out script data
+ vector <struct condition>::iterator iterConditions = Conditions.begin();
+ int count=0;
+
+ cout << "\n Script goes from " << StartTime << " to " << EndTime
+ << " with dt = " << State->Getdt() << endl << endl;
+
+ while (iterConditions < Conditions.end()) {
+ cout << " Condition: " << count++ << endl;
+ cout << " if (";
+
+ for (i=0; i<iterConditions->TestValue.size(); i++) {
+ if (i>0) cout << " and" << endl << " ";
+ cout << "(" << iterConditions->TestParam[i]->GetName()
+ << " " << iterConditions->Comparison[i] << " "
+ << iterConditions->TestValue[i] << ")";
+ }
+ cout << ") then {";
+
+ for (i=0; i<iterConditions->SetValue.size(); i++) {
+ cout << endl << " set " << iterConditions->SetParam[i]->GetName()
+ << " to " << iterConditions->SetValue[i];
+
+ switch (iterConditions->Type[i]) {
+ case FG_VALUE:
+ cout << " (constant";
+ break;
+ case FG_DELTA:
+ cout << " (delta";
+ break;
+ case FG_BOOL:
+ cout << " (boolean";
+ break;
+ default:
+ cout << " (unspecified type";
+ }
+
+ switch (iterConditions->Action[i]) {
+ case FG_RAMP:
+ cout << " via ramp";
+ break;
+ case FG_STEP:
+ cout << " via step";
+ break;
+ case FG_EXP:
+ cout << " via exponential approach";
+ break;
+ default:
+ cout << " via unspecified action";
+ }
+
+ if (!iterConditions->Persistent[i]) cout << endl
+ << " once";
+ else cout << endl
+ << " repeatedly";
+
+ if (iterConditions->Action[i] == FG_RAMP ||
+ iterConditions->Action[i] == FG_EXP) cout << endl
+ << " with time constant "
+ << iterConditions->TC[i];
+ }
+ cout << ")" << endl << " }" << endl << endl;
+
+ iterConditions++;
+ }
+
+ cout << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGScript" << endl;
+ if (from == 1) cout << "Destroyed: FGScript" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ Header: FGScript.h
+ Author: Jon Berndt
+ Date started: 12/21/2001
+
+ ------------- Copyright (C) 2001 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+12/21/01 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGSCRIPT_HEADER_H
+#define FGSCRIPT_HEADER_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGJSBBase.h"
+#include "FGState.h"
+#include "FGFDMExec.h"
+#include <vector>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_FGSCRIPT "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Encapsulates the JSBSim scripting capability.
+ <h4>Scripting support provided via FGScript.</h4>
+
+ <p>There is simple scripting support provided in the FGScript
+ class. Commands are specified using the <em>Simple Scripting
+ Directives for JSBSim</em> (SSDJ). The script file is in XML
+ format. A test condition (or conditions) can be set up in the
+ script and when the condition evaluates to true, the specified
+ action[s] is/are taken. A test condition can be <em>persistent</em>,
+ meaning that if a test condition evaluates to true, then passes
+ and evaluates to false, the condition is reset and may again be
+ triggered. When the set of tests evaluates to true for a given
+ condition, an item may be set to another value. This value might
+ be a boolean, a value, or a delta value, and the change from the
+ current value to the new value can be either via a step function,
+ a ramp, or an exponential approach. The speed of a ramp or
+ approach is specified via the time constant. Here is the format
+ of the script file:</p>
+
+ <pre><strong><?xml version="1.0"?>
+ <runscript name="C172-01A">
+
+ <!--
+ This run is for testing C172 runs
+ -->
+
+ <use aircraft="c172">
+ <use initialize="reset00">
+
+ <run start="0.0" end="4.5" dt="0.05">
+ <when>
+ <parameter name="FG_TIME" comparison="ge" value="0.25">
+ <parameter name="FG_TIME" comparison="le" value="0.50">
+ <set name="FG_AILERON_CMD" type="FG_VALUE" value="0.25"
+ action="FG_STEP" persistent="false" tc ="0.25">
+ </when>
+ <when>
+ <parameter name="FG_TIME" comparison="ge" value="0.5">
+ <parameter name="FG_TIME" comparison="le" value="1.5">
+ <set name="FG_AILERON_CMD" type="FG_DELTA" value="0.5"
+ action="FG_EXP" persistent="false" tc ="0.5">
+ </when>
+ <when>
+ <parameter name="FG_TIME" comparison="ge" value="1.5">
+ <parameter name="FG_TIME" comparison="le" value="2.5">
+ <set name="FG_RUDDER_CMD" type="FG_DELTA" value="0.5"
+ action="FG_RAMP" persistent="false" tc ="0.5">
+ </when>
+ </run>
+
+ </runscript></strong></pre>
+
+ <p>The first line must always be present. The second line
+ identifies this file as a script file, and gives a descriptive
+ name to the script file. Comments are next, delineated by the
+ <!-- and --> symbols. The aircraft and initialization files
+ to be used are specified in the "use" lines. Next,
+ comes the "run" section, where the conditions are
+ described in "when" clauses.</p>
+ @author Jon S. Berndt
+ @version "$Id$"
+
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGScript : public FGJSBBase
+{
+public:
+ /// Default constructor
+ FGScript(FGFDMExec* exec);
+
+ /// Default destructor
+ ~FGScript();
+
+ /** Loads a script to drive JSBSim (usually in standalone mode).
+ The language is the Simple Script Directives for JSBSim (SSDJ).
+ @param script the filename (including path name, if any) for the script.
+ @return true if successful */
+ bool LoadScript( string script );
+
+ /** This function is called each pass through the executive Run() method IF
+ scripting is enabled.
+ @return false if script should exit (i.e. if time limits are violated */
+ bool RunScript(void);
+
+private:
+ enum eAction {
+ FG_RAMP = 1,
+ FG_STEP = 2,
+ FG_EXP = 3
+ };
+
+ enum eType {
+ FG_VALUE = 1,
+ FG_DELTA = 2,
+ FG_BOOL = 3
+ };
+
+ struct condition {
+ vector <FGPropertyManager*> TestParam;
+ vector <FGPropertyManager*> SetParam;
+ vector <double> TestValue;
+ vector <double> SetValue;
+ vector <string> Comparison;
+ vector <double> TC;
+ vector <bool> Persistent;
+ vector <eAction> Action;
+ vector <eType> Type;
+ vector <bool> Triggered;
+ vector <double> newValue;
+ vector <double> OriginalValue;
+ vector <double> StartTime;
+ vector <double> EndTime;
+
+ condition() {
+ }
+ };
+
+ bool Scripted;
+
+ string ScriptName;
+ double StartTime;
+ double EndTime;
+ vector <struct condition> Conditions;
+
+ FGFDMExec* FDMExec;
+ FGState* State;
+ FGPropertyManager* PropertyManager;
+ void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Author: Jon Berndt
+ Date started: 09/28/2004
+ Purpose: XML element class
+ Called by: FGXMLParse
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGXMLElement.h"
+#ifdef FGFS
+# ifndef __BORLANDC__
+# include <simgear/compiler.h>
+# endif
+# ifdef SG_HAVE_STD_INCLUDES
+# include <cmath>
+# include <cstdlib>
+# else
+# include <math.h>
+# include <stdlib.h>
+# endif
+#else
+# if defined (sgi) && !defined(__GNUC__)
+# include <math.h>
+# include <stdlib.h>
+# else
+# include <cmath>
+# include <cstdlib>
+# endif
+#endif
+
+#include <stdlib.h>
+#include <math.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_XMLELEMENT;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+Element::Element(string nm)
+{
+ name = nm;
+ parent = 0L;
+ element_index = 0;
+
+ // convert ["from"]["to"] = factor, so: from * factor = to
+ convert["M"]["FT"] = 3.2808399;
+ convert["FT"]["M"] = 1.0/convert["M"]["FT"];
+ convert["M2"]["FT2"] = convert["M"]["FT"]*convert["M"]["FT"];
+ convert["FT2"]["M2"] = 1.0/convert["M2"]["FT2"];
+ convert["FT"]["IN"] = 12.0;
+ convert["IN"]["FT"] = 1.0/convert["FT"]["IN"];
+ convert["LBS"]["KG"] = 0.45359237;
+ convert["KG"]["LBS"] = 1.0/convert["LBS"]["KG"];
+ convert["SLUG*FT2"]["KG*M2"] = 1.35594;
+ convert["KG*M2"]["SLUG*FT2"] = 1.0/convert["SLUG*FT2"]["KG*M2"];
+ convert["RAD"]["DEG"] = 360.0/(2.0*3.1415926);
+ convert["DEG"]["RAD"] = 1.0/convert["RAD"]["DEG"];
+ convert["LBS/FT"]["N/M"] = 14.5939;
+ convert["LBS/FT/SEC"]["N/M/SEC"] = 14.5939;
+ convert["N/M"]["LBS/FT"] = 1.0/convert["LBS/FT"]["N/M"];
+ convert["N/M/SEC"]["LBS/FT/SEC"] = 1.0/convert["LBS/FT/SEC"]["N/M/SEC"];
+ convert["WATTS"]["HP"] = 0.001341022;
+ convert["HP"]["WATTS"] = 1.0/convert["WATTS"]["HP"];
+ convert["N"]["LBS"] = 0.22482;
+ convert["LBS"]["N"] = 1.0/convert["N"]["LBS"];
+ convert["KTS"]["FT/SEC"] = 1.68781;
+ convert["FT/SEC"]["KTS"] = 1.0/convert["KTS"]["FT/SEC"];
+ convert["FT*LBS"]["N*M"] = 1.35581795;
+ convert["N*M"]["FT*LBS"] = 1/convert["FT*LBS"]["N*M"];
+
+ convert["M"]["M"] = 1.00;
+ convert["FT"]["FT"] = 1.00;
+ convert["IN"]["IN"] = 1.00;
+ convert["IN3"]["IN3"] = 1.00;
+ convert["DEG"]["DEG"] = 1.00;
+ convert["RAD"]["RAD"] = 1.00;
+ convert["M2"]["M2"] = 1.00;
+ convert["FT2"]["FT2"] = 1.00;
+ convert["KG*M2"]["KG*M2"] = 1.00;
+ convert["SLUG*FT2"]["SLUG*FT2"] = 1.00;
+ convert["KG"]["KG"] = 1.00;
+ convert["LBS"]["LBS"] = 1.00;
+ convert["LBS/FT"]["LBS/FT"] = 1.00;
+ convert["LBS/SEC"]["LBS/SEC"] = 1.00;
+ convert["LBS/FT/SEC"]["LBS/FT/SEC"] = 1.00;
+ convert["N/M"]["N/M"] = 1.00;
+ convert["N/M/SEC"]["N/M/SEC"] = 1.00;
+ convert["PSI"]["PSI"] = 1.00;
+ convert["PSF"]["PSF"] = 1.00;
+ convert["INHG"]["INHG"] = 1.00;
+ convert["HP"]["HP"] = 1.00;
+ convert["N"]["N"] = 1.00;
+ convert["WATTS"]["WATTS"] = 1.00;
+ convert["LBS/SEC"]["LBS/SEC"] = 1.00;
+ convert["FT/SEC"]["FT/SEC"] = 1.00;
+ convert["KTS"]["KTS"] = 1.00;
+ convert["FT*LBS"]["FT*LBS"] = 1.00;
+ convert["N*M"]["N*M"] = 1.00;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Element::~Element(void)
+{
+ for (int i=0; i<children.size(); i++) delete children[i];
+ data_lines.clear();
+ attributes.clear();
+ attribute_key.clear();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string Element::GetAttributeValue(string attr)
+{
+ int select=-1;
+ for (int i=0; i<attribute_key.size(); i++) {
+ if (attribute_key[i] == attr) select = i;
+ }
+ if (select < 0) return string("");
+ else return attributes[attr];
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double Element::GetAttributeValueAsNumber(string attr)
+{
+ string attribute = GetAttributeValue(attr);
+
+ if (attribute.empty()) return 99e99;
+ else return (atof(attribute.c_str()));
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Element* Element::GetElement(int el)
+{
+ if (children.size() > el) {
+ element_index = el;
+ return children[el];
+ }
+ else {
+ element_index = 0;
+ return 0L;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Element* Element::GetNextElement(void)
+{
+ if (children.size() > element_index+1) {
+ element_index++;
+ return children[element_index];
+ } else {
+ element_index = 0;
+ return 0L;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string Element::GetDataLine(int i)
+{
+ if (data_lines.size() > 0) return data_lines[i];
+ else return string("");
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double Element::GetDataAsNumber(void)
+{
+ if (data_lines.size() == 1) {
+ return atof(data_lines[0].c_str());
+ } else {
+ return 99e99;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+int Element::GetNumElements(string element_name)
+{
+ int number_of_elements=0;
+ Element* el=FindElement(element_name);
+ while (el) {
+ number_of_elements++;
+ el=FindNextElement(element_name);
+ }
+ return number_of_elements;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Element* Element::FindElement(string el)
+{
+ if (el.empty() && children.size() >= 1) {
+ element_index = 1;
+ return children[0];
+ }
+ for (int i=0; i<children.size(); i++) {
+ if (el == children[i]->GetName()) {
+ element_index = i+1;
+ return children[i];
+ }
+ }
+ element_index = 0;
+ return 0L;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Element* Element::FindNextElement(string el)
+{
+ if (el.empty()) {
+ if (element_index < children.size()) {
+ return children[element_index++];
+ } else {
+ element_index = 0;
+ return 0L;
+ }
+ }
+ for (int i=element_index; i<children.size(); i++) {
+ if (el == children[i]->GetName()) {
+ element_index = i+1;
+ return children[i];
+ }
+ }
+ element_index = 0;
+ return 0L;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double Element::FindElementValueAsNumber(string el)
+{
+ Element* element = FindElement(el);
+ if (element) {
+ return element->GetDataAsNumber();
+ } else {
+ return 99e99;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string Element::FindElementValue(string el)
+{
+ Element* element = FindElement(el);
+ if (element) {
+ return element->GetDataLine();
+ } else {
+ return "";
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double Element::FindElementValueAsNumberConvertTo(string el, string target_units)
+{
+ Element* element = FindElement(el);
+ double value;
+ string supplied_units="";
+
+ if (element) {
+ value = element->GetDataAsNumber();
+ supplied_units = element->GetAttributeValue("unit");
+ if (!supplied_units.empty()) {
+ if (convert.find(supplied_units) != convert.end()) {
+ if (convert[supplied_units].find(target_units) != convert[supplied_units].end()) {
+ value *= convert[supplied_units][target_units];
+ } else {
+ cerr << endl << "Target unit: \"" << target_units << "\" does not exist (typo?). Add new unit"
+ << " conversion in FGXMLElement.cpp." << endl;
+ exit(-1);
+ }
+ } else {
+ cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit"
+ << " conversion in FGXMLElement.cpp." << endl;
+ exit(-1);
+ }
+ }
+ } else {
+ return 99e99;
+ }
+ return value;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double Element::FindElementValueAsNumberConvertFromTo( string el,
+ string supplied_units,
+ string target_units)
+{
+ Element* element = FindElement(el);
+ double value;
+
+ if (element) {
+ value = element->GetDataAsNumber();
+ if (!supplied_units.empty()) {
+ if (convert.find(supplied_units) != convert.end()) {
+ if (convert[supplied_units].find(target_units) != convert[supplied_units].end()) {
+ value *= convert[supplied_units][target_units];
+ } else {
+ cerr << endl << "Target unit: \"" << target_units << "\" does not exist (typo?). Add new unit"
+ << " conversion in FGXMLElement.cpp." << endl;
+ exit(-1);
+ }
+ } else {
+ cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit"
+ << " conversion in FGXMLElement.cpp." << endl;
+ exit(-1);
+ }
+ }
+ } else {
+ return 99e99;
+ }
+ return value;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGColumnVector3 Element::FindElementTripletConvertTo( string target_units)
+{
+ FGColumnVector3 triplet;
+ Element* item;
+ double value=0.0;
+ string supplied_units = GetAttributeValue("unit");
+
+ item = FindElement("x");
+ if (!item) item = FindElement("roll");
+ if (item) {
+ value = item->GetDataAsNumber();
+ if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
+ } else {
+ value = 0.0;
+ cerr << "Could not find an X triplet item for this column vector." << endl;
+ }
+ triplet(1) = value;
+
+ item = FindElement("y");
+ if (!item) item = FindElement("pitch");
+ if (item) {
+ value = item->GetDataAsNumber();
+ if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
+ } else {
+ value = 0.0;
+ cerr << "Could not find a Y triplet item for this column vector." << endl;
+ }
+ triplet(2) = value;
+
+ item = FindElement("z");
+ if (!item) item = FindElement("yaw");
+ if (item) {
+ value = item->GetDataAsNumber();
+ if (!supplied_units.empty()) value *= convert[supplied_units][target_units];
+ } else {
+ value = 0.0;
+ cerr << "Could not find a Z triplet item for this column vector." << endl;
+ }
+ triplet(3) = value;
+
+ return triplet;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void Element::Print(int level)
+{
+ int i, spaces;
+
+ level+=2;
+ for (int spaces=0; spaces<=level; spaces++) cout << " "; // format output
+ cout << "Element Name: " << name;
+ for (int i=0; i<attributes.size(); i++) {
+ cout << " " << attribute_key[i] << " = " << attributes[attribute_key[i]];
+ }
+ cout << endl;
+ for (i=0; i<data_lines.size(); i++) {
+ for (spaces=0; spaces<=level; spaces++) cout << " "; // format output
+ cout << data_lines[i] << endl;
+ }
+ for (i=0; i<children.size(); i++) {
+ children[i]->Print(level);
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void Element::AddAttribute(string name, string value)
+{
+ attribute_key.push_back(name);
+ attributes[name] = value;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void Element::AddData(string d)
+{
+ int string_start = d.find_first_not_of(" ");
+ if (string_start > 0) d.erase(0,string_start-1);
+ data_lines.push_back(d);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+} // end namespace JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ File: FGXMLElement.h
+ Author: Jon S. Berndt
+ Date started: 9/28/04
+
+ ------------- Copyright (C) 2004 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef XMLELEMENT_H
+#define XMLELEMENT_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# ifdef SG_HAVE_STD_INCLUDES
+# include <string>
+# include <vector>
+# include <iostream>
+# include <map>
+# else
+# include <vector.h>
+# include <string>
+# include <iostream.h>
+# include <map.h>
+# endif
+#else
+# include <string>
+# include <map>
+# include <iostream>
+# include <vector>
+ using std::string;
+ using std::map;
+ using std::vector;
+ using std::cout;
+ using std::endl;
+#endif
+ using std::string;
+ using std::map;
+ using std::vector;
+ using std::cout;
+ using std::endl;
+
+#include <math/FGColumnVector3.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_XMLELEMENT "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Encapsulates an XML element.
+ This class handles the creation, storage, and manipulation of XML elements.
+ This class also can convert supplied values as follows:
+
+ convert ["from"]["to"] = factor, so: from * factor = to
+ - convert["M"]["FT"] = 3.2808399;
+ - convert["FT"]["M"] = 1.0/convert["M"]["FT"];
+ - convert["M2"]["FT2"] = convert["M"]["FT"]*convert["M"]["FT"];
+ - convert["FT2"]["M2"] = 1.0/convert["M2"]["FT2"];
+ - convert["FT"]["IN"] = 12.0;
+ - convert["IN"]["FT"] = 1.0/convert["FT"]["IN"];
+ - convert["LBS"]["KG"] = 0.45359237;
+ - convert["KG"]["LBS"] = 1.0/convert["LBS"]["KG"];
+ - convert["SLUG*FT2"]["KG*M2"] = 1.35594;
+ - convert["KG*M2"]["SLUG*FT2"] = 1.0/convert["SLUG*FT2"]["KG*M2"];
+ - convert["RAD"]["DEG"] = 360.0/(2.0*3.1415926);
+ - convert["DEG"]["RAD"] = 1.0/convert["RAD"]["DEG"];
+ - convert["LBS/FT"]["N/M"] = 14.5939;
+ - convert["LBS/FT/SEC"]["N/M/SEC"] = 14.5939;
+ - convert["N/M"]["LBS/FT"] = 1.0/convert["LBS/FT"]["N/M"];
+ - convert["N/M/SEC"]["LBS/FT/SEC"] = 1.0/convert["LBS/FT/SEC"]["N/M/SEC"];
+ - convert["WATTS"]["HP"] = 0.001341022;
+ - convert["HP"]["WATTS"] = 1.0/convert["WATTS"]["HP"];
+ - convert["N"]["LBS"] = 0.22482;
+ - convert["LBS"]["N"] = 1.0/convert["N"]["LBS"];
+ - convert["KTS"]["FT/SEC"] = ktstofps;
+
+ - convert["M"]["M"] = 1.00;
+ - convert["FT"]["FT"] = 1.00;
+ - convert["IN"]["IN"] = 1.00;
+ - convert["DEG"]["DEG"] = 1.00;
+ - convert["RAD"]["RAD"] = 1.00;
+ - convert["M2"]["M2"] = 1.00;
+ - convert["FT2"]["FT2"] = 1.00;
+ - convert["KG*M2"]["KG*M2"] = 1.00;
+ - convert["SLUG*FT2"]["SLUG*FT2"] = 1.00;
+ - convert["KG"]["KG"] = 1.00;
+ - convert["LBS"]["LBS"] = 1.00;
+ - convert["LBS/FT"]["LBS/FT"] = 1.00;
+ - convert["N/M"]["N/M"] = 1.00;
+ - convert["LBS/FT/SEC"]["LBS/FT/SEC"] = 1.00;
+ - convert["N/M/SEC"]["N/M/SEC"] = 1.00;
+ - convert["PSI"]["PSI"] = 1.00;
+ - convert["INHG"]["INHG"] = 1.00;
+ - convert["HP"]["HP"] = 1.00;
+ - convert["N"]["N"] = 1.00;
+ - convert["WATTS"]["WATTS"] = 1.00;
+ - convert["KTS"]["KTS"] = 1.0;
+ - convert["FT/SEC"]["FT/SEC"] = 1.0;
+
+ Where:
+ - N = newtons
+ - M = meters
+ - M2 = meters squared
+ - KG = kilograms
+ - LBS = pounds force
+ - FT = feet
+ - FT2 = feet squared
+ - SEC = seconds
+ - SLUG = slug
+ - DEG = degrees
+ - RAD = radians
+ - WATTS = watts
+
+ @author Jon S. Berndt
+ @version $Id$
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class Element {
+public:
+ /** Constructor
+ @param nm the name of this element (if given)
+ */
+ Element(string nm);
+ /// Destructor
+ ~Element(void);
+
+ /** Retrieves an attribute.
+ @param key specifies the attribute key to retrieve the value of.
+ @return the key value (as a string), or the empty string if no such
+ attribute exists. */
+ string GetAttributeValue(string key);
+
+ /** Retrieves an attribute value as a double precision real number.
+ @param key specifies the attribute key to retrieve the value of.
+ @return the key value (as a number), or the HUGE_VAL if no such
+ attribute exists. */
+ double GetAttributeValueAsNumber(string key);
+
+ /** Retrieves the element name.
+ @return the element name, or the empty string if no name has been set.*/
+ string GetName(void) {return name;}
+
+ /** Gets a line of data belonging to an element.
+ @param i the index of the data line to return (0 by default).
+ @return a string representing the data line requested, or the empty string
+ if none exists.*/
+ string GetDataLine(int i=0);
+
+ /// Returns the number of lines of data stored
+ int GetNumDataLines(void) {return data_lines.size();}
+
+ /// Returns the number of child elements for this element.
+ int GetNumElements(void) {return children.size();}
+
+ /// Returns the number of named child elements for this element.
+ int GetNumElements(string);
+
+ /** Converts the element data to a number.
+ This function attempts to convert the first (and presumably only) line of
+ data "owned" by the element into a real number. If there is not exactly one
+ line of data owned by the element, then HUGE_VAL is returned.
+ @return the numeric value of the data owned by the element.*/
+ double GetDataAsNumber(void);
+
+ /** Returns a pointer to the element requested by index.
+ This function also resets an internal counter to the index, so that
+ subsequent calls to GetNextElement() will return the following
+ elements sequentially, until the last element is reached. At that point,
+ GetNextElement() will return NULL.
+ @param el the index of the requested element (0 by default)
+ @return a pointer to the Element, or 0 if no valid element exists. */
+ Element* GetElement(int el=0);
+
+ /** Returns a pointer to the next element in the list.
+ The function GetElement() must be called first to be sure that this
+ function will return the correct element. The call to GetElement() resets
+ the internal counter to zero. Subsequent calls to GetNextElement() return
+ a pointer to subsequent elements in the list. When the final element is
+ reached, 0 is returned.
+ @return a pointer to the next Element in the sequence, or 0 if no valid
+ Element is present. */
+ Element* GetNextElement(void);
+
+ /** Returns a pointer to the parent of an element.
+ @return a pointer to the parent Element, or 0 if this is the top level Element. */
+ Element* GetParent(void) {return parent;}
+
+ /** Searches for a specified element.
+ Finds the first element that matches the supplied string, or simply the first
+ element if no search string is supplied. This function call resets the internal
+ element counter to the first element.
+ @param el the search string (empty string by default).
+ @return a pointer to the first element that matches the supplied search string. */
+ Element* FindElement(string el="");
+
+ /** Searches for the next element as specified.
+ This function would be called after FindElement() is first called (in order to
+ reset the internal counter). If no argument is supplied (or the empty string)
+ a pointer to the very next element is returned. Otherwise, the next occurence
+ of the named element is returned. If the end of the list is reached, 0 is
+ returned.
+ @param el the name of the next element to find.
+ @return the pointer to the found element, or 0 if no appropriate element us
+ found.*/
+ Element* FindNextElement(string el="");
+
+ /** Searches for the named element and returns the string data belonging to it.
+ This function allows the data belonging to a named element to be returned
+ as a string. If no element is found, the empty string is returned. If no
+ argument is supplied, the data string for the first element is returned.
+ @param el the name of the element being searched for (the empty string by
+ default)
+ @return the data value for the named element as a string, or the empty
+ string if the element cannot be found. */
+ string FindElementValue(string el="");
+
+ /** Searches for the named element and returns the data belonging to it as a number.
+ This function allows the data belonging to a named element to be returned
+ as a double. If no element is found, HUGE_VAL is returned. If no
+ argument is supplied, the data for the first element is returned.
+ @param el the name of the element being searched for (the empty string by
+ default)
+ @return the data value for the named element as a double, or HUGE_VAL if the
+ data is missing. */
+ double FindElementValueAsNumber(string el="");
+
+ /** Searches for the named element and converts and returns the data belonging to it.
+ This function allows the data belonging to a named element to be returned
+ as a double. If no element is found, HUGE_VAL is returned. If no
+ argument is supplied, the data for the first element is returned. Additionally,
+ this function converts the value from the units specified in the config file (via
+ the UNITS="" attribute in the element definition) to the native units used by
+ JSBSim itself, as specified by the target_units parameter. The currently
+ allowable unit conversions are seen in the source file FGXMLElement.cpp.
+ Also, see above in the main documentation for this class.
+ @param el the name of the element being searched for (the empty string by
+ default)
+ @param target_units the string representing the native units used by JSBSim
+ to which the value returned will be converted.
+ @return the unit-converted data value for the named element as a double,
+ or HUGE_VAL if the data is missing. */
+ double FindElementValueAsNumberConvertTo(string el, string target_units);
+
+ /** Searches for the named element and converts and returns the data belonging to it.
+ This function allows the data belonging to a named element to be returned
+ as a double. If no element is found, HUGE_VAL is returned. If no
+ argument is supplied, the data for the first element is returned. Additionally,
+ this function converts the value from the units specified in the supplied_units
+ parameter to the units specified in the target_units parameter. JSBSim itself,
+ as specified by the target_units parameter. The currently allowable unit
+ conversions are seen in the source file FGXMLElement.cpp. Also, see above
+ in the main documentation for this class.
+ @param el the name of the element being searched for (the empty string by
+ default)
+ @param supplied_units the string representing the units of the value as
+ supplied by the config file.
+ @param target_units the string representing the native units used by JSBSim
+ to which the value returned will be converted.
+ @return the unit-converted data value for the named element as a double,
+ or HUGE_VAL if the data is missing. */
+ double FindElementValueAsNumberConvertFromTo( string el,
+ string supplied_units,
+ string target_units);
+
+ /** Composes a 3-element column vector for the supplied location or orientation.
+ This function processes a LOCATION or ORIENTATION construct, returning a
+ filled-out 3-element column vector containing the X, Y, Z or ROLL, PITCH,
+ YAW elements found in the supplied element. If one of the mentioned components
+ is not found, that component is set to zero and a warning message is printed.
+ All three elements should be supplied.
+ @param target_units the string representing the native units used by JSBSim
+ to which the value returned will be converted.
+ @return a column vector object built from the LOCATION or ORIENT components. */
+ FGColumnVector3 FindElementTripletConvertTo( string target_units);
+
+ /** This function sets the value of the parent class attribute to the supplied
+ Element pointer.
+ @param p pointer to the parent Element. */
+ void SetParent(Element* p) {parent = p;}
+
+ /** Adds a child element to the list of children stored for this element.
+ * @param el Child element to add. */
+ void AddChildElement(Element* el) {children.push_back(el);}
+
+ /** Stores an attribute belonging to this element.
+ * @param name The string name of the attribute.
+ * @param value The string value of the attribute. */
+ void AddAttribute(string name, string value);
+
+ /** Stores data belonging to this element.
+ * @param d the data to store. */
+ void AddData(string d);
+
+ /** Prints the element.
+ * Prints this element and calls the Print routine for child elements.
+ * @param d The tab level. A level corresponds to a single space. */
+ void Print(int level=0);
+
+private:
+ string name;
+ map <string, string> attributes;
+ vector <string> data_lines;
+ vector <Element*> children;
+ vector <string> attribute_key;
+ Element *parent;
+ int element_index;
+ typedef map <string, map <string, double> > tMapConvert;
+ tMapConvert convert;
+};
+
+} // namespace JSBSim
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGXMLParse.h
+ Author: Jon Berndt
+ Date started: 08/20/2004
+ Purpose: Config file read-in class and XML parser
+ Called by: Various
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGXMLParse.h"
+#include <stdlib.h>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_XMLPARSE;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGXMLParse.h"
+
+using namespace std;
+
+FGXMLParse::FGXMLParse(void)
+{
+ first_element_read = false;
+ current_element = document = 0L;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGXMLParse::~FGXMLParse(void)
+{
+ if (document) delete document;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGXMLParse::startXML(void)
+{
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGXMLParse::reset(void)
+{
+ if (document) delete document;
+ first_element_read = false;
+ current_element = document = 0L;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGXMLParse::endXML(void)
+{
+ // At this point, document should equal current_element ?
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGXMLParse::startElement (const char * name, const XMLAttributes &atts)
+{
+ string Name(name);
+ Element *temp_element;
+
+ working_string.erase();
+
+ if (!first_element_read) {
+ document = new Element(Name);
+ current_element = document;
+ first_element_read = true;
+ } else {
+ temp_element = new Element(Name);
+ temp_element->SetParent(current_element);
+ current_element->AddChildElement(temp_element);
+ current_element = temp_element;
+ }
+
+ if (current_element == 0L) {
+ cerr << "No current element read (no top-level element in XML file?)" << endl;
+ exit (-1);
+ }
+
+ for (int i=0; i<atts.size();i++) {
+ current_element->AddAttribute(atts.getName(i), atts.getValue(i));
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGXMLParse::endElement (const char * name)
+{
+ int size, pos;
+ string local_work_string;
+
+ while (!working_string.empty()) {
+ // clear leading newlines and spaces
+ while (working_string[0] == '\n' || working_string[0] == ' ')
+ working_string.erase(0,1);
+
+ // remove spaces (only) from end of string
+ size = working_string.size();
+ while (working_string[size-1] == ' ')
+ {
+ working_string.erase(size-1,1);
+ size = working_string.size();
+ }
+
+ if (!working_string.empty()) {
+ pos = working_string.find("\n");
+ if (pos != string::npos) local_work_string = working_string.substr(0,pos);
+ else local_work_string = working_string;
+ current_element->AddData(local_work_string);
+ working_string.erase(0, pos);
+ }
+ }
+
+ current_element = current_element->GetParent();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGXMLParse::data (const char * s, int length)
+{
+ working_string += string(s, length);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGXMLParse::pi (const char * target, const char * data)
+{
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGXMLParse::warning (const char * message, int line, int column)
+{
+ cerr << "Warning: " << message << " line: " << line << " column: " << column << endl;
+}
+
+} // end namespace JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGXMLParse.h
+ Author: Jon S. Berndt
+ Date started: 8/20/04
+
+ ------------- Copyright (C) 2004 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGXMLPARSE_H
+#define FGXMLPARSE_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# include STL_STRING
+#else
+# include <string>
+# include <iostream>
+ using std::string;
+ using std::cout;
+ using std::cerr;
+ using std::endl;
+#endif
+
+#include "FGXMLElement.h"
+#include "simgear/xml/easyxml.hxx"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_XMLPARSE "$Id$"
+#define VALID_CHARS """`!@#$%^&*()_+`1234567890-={}[];':,.<>/?abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Encapsulates an XML parser based on the EasyXML parser from the SimGear library.
+ @author Jon S. Berndt
+ @version $Id$
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGXMLParse : public XMLVisitor
+{
+public:
+ FGXMLParse(void);
+ virtual ~FGXMLParse(void);
+
+ Element* GetDocument(void) {return document;}
+
+ void startXML();
+ void endXML();
+ void startElement (const char * name, const XMLAttributes &atts);
+ void endElement (const char * name);
+ void data (const char * s, int length);
+ void pi (const char * target, const char * data);
+ void warning (const char * message, int line, int column);
+ void reset(void);
+
+private:
+ bool first_element_read;
+ mutable string working_string;
+ Element *document;
+ Element *current_element;
+};
+
+} // namespace JSBSim
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGfdmSocket.cpp
+ Author: Jon S. Berndt
+ Date started: 11/08/99
+ Purpose: Encapsulates a socket
+ Called by: FGOutput, et. al.
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+This class excapsulates a socket for simple data writing
+
+HISTORY
+--------------------------------------------------------------------------------
+11/08/99 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGfdmSocket.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_FDMSOCKET;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGfdmSocket::FGfdmSocket(string address, int port)
+{
+ sckt = sckt_in = size = 0;
+ connected = false;
+
+ #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
+ WSADATA wsaData;
+ int wsaReturnCode;
+ wsaReturnCode = WSAStartup(MAKEWORD(1,1), &wsaData);
+ if (wsaReturnCode == 0) cout << "Winsock DLL loaded ..." << endl;
+ else cout << "Winsock DLL not initialized ..." << endl;
+ #endif
+
+ if (address.find_first_not_of("0123456789.",0) != address.npos) {
+ if ((host = gethostbyname(address.c_str())) == NULL) {
+ cout << "Could not get host net address by name..." << endl;
+ }
+ } else {
+ if ((host = gethostbyaddr(address.c_str(), address.size(), PF_INET)) == NULL) {
+ cout << "Could not get host net address by number..." << endl;
+ }
+ }
+
+ if (host != NULL) {
+ cout << "Got host net address..." << endl;
+ sckt = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (sckt >= 0) { // successful
+ memset(&scktName, 0, sizeof(struct sockaddr_in));
+ scktName.sin_family = AF_INET;
+ scktName.sin_port = htons(port);
+ memcpy(&scktName.sin_addr, host->h_addr_list[0], host->h_length);
+ int len = sizeof(struct sockaddr_in);
+ if (connect(sckt, (struct sockaddr*)&scktName, len) == 0) { // successful
+ cout << "Successfully connected to socket ..." << endl;
+ connected = true;
+ } else { // unsuccessful
+ cout << "Could not connect to socket ..." << endl;
+ }
+ } else { // unsuccessful
+ cout << "Could not create socket for FDM, error = " << errno << endl;
+ }
+ }
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGfdmSocket::FGfdmSocket(int port)
+{
+ size = 0;
+ connected = false;
+ unsigned long NoBlock = true;
+
+ #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
+ WSADATA wsaData;
+ int wsaReturnCode;
+ wsaReturnCode = WSAStartup(MAKEWORD(1,1), &wsaData);
+ if (wsaReturnCode == 0) cout << "Winsock DLL loaded ..." << endl;
+ else cerr << "Winsock DLL not initialized ..." << endl;
+ #endif
+
+ sckt = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (sckt >= 0) { // successful
+ memset(&scktName, 0, sizeof(struct sockaddr_in));
+ scktName.sin_family = AF_INET;
+ scktName.sin_port = htons(port);
+// memcpy(&scktName.sin_addr, host->h_addr_list[0], host->h_length);
+ int len = sizeof(struct sockaddr_in);
+ if (bind(sckt, (struct sockaddr*)&scktName, len) == 0) { // successful
+ cout << "Successfully bound to socket ..." << endl;
+ if (listen(sckt, 5) >= 0) { // successful listen()
+ #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
+ ioctlsocket(sckt, FIONBIO, &NoBlock);
+ sckt_in = accept(sckt, (struct sockaddr*)&scktName, &len);
+ #else
+ ioctl(sckt, FIONBIO, &NoBlock);
+ sckt_in = accept(sckt, (struct sockaddr*)&scktName, (socklen_t*)&len);
+ #endif
+ } else {
+ cerr << "Could not listen ..." << endl;
+ }
+ connected = true;
+ } else { // unsuccessful
+ cerr << "Could not bind to socket ..." << endl;
+ }
+ } else { // unsuccessful
+ cerr << "Could not create socket for FDM, error = " << errno << endl;
+ }
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGfdmSocket::~FGfdmSocket()
+{
+ #ifndef macintosh
+ if (sckt) shutdown(sckt,2);
+ if (sckt_in) shutdown(sckt_in,2);
+ #endif
+
+ #ifdef __BORLANDC__
+ WSACleanup();
+ #endif
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGfdmSocket::Receive(void)
+{
+ char buf[1024];
+ int len = sizeof(struct sockaddr_in);
+ int num_chars=0;
+ int total_chars = 0;
+ unsigned long NoBlock = true;
+ string data = ""; // todo: should allocate this with a standard size as a
+ // class attribute and pass as a reference?
+
+ if (sckt_in <= 0) {
+ #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
+ sckt_in = accept(sckt, (struct sockaddr*)&scktName, &len);
+ #else
+ sckt_in = accept(sckt, (struct sockaddr*)&scktName, (socklen_t*)&len);
+ #endif
+ if (sckt_in > 0) {
+ #if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
+ ioctlsocket(sckt_in, FIONBIO,&NoBlock);
+ #else
+ ioctl(sckt_in, FIONBIO, &NoBlock);
+ #endif
+ send(sckt_in, "Connected to JSBSim server\nJSBSim> ", 35, 0);
+ }
+ }
+
+ if (sckt_in > 0) {
+ while ((num_chars = recv(sckt_in, buf, 1024, 0)) > 0) {
+ data += string(buf).substr(0,num_chars);
+ total_chars += num_chars;
+ }
+
+#if defined(_MSC_VER)
+ // when nothing received and the error isn't "would block"
+ // then assume that the client has closed the socket.
+ if (num_chars == 0) {
+ DWORD err = WSAGetLastError ();
+ if (err != WSAEWOULDBLOCK) {
+ printf ("Socket Closed. back to listening\n");
+ closesocket (sckt_in);
+ sckt_in = -1;
+ }
+ }
+#endif
+ }
+
+ return data.substr(0, total_chars);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+int FGfdmSocket::Reply(string text)
+{
+ int num_chars_sent=0;
+
+ if (sckt_in >= 0) {
+ num_chars_sent = send(sckt_in, text.c_str(), text.size(), 0);
+ send(sckt_in, "JSBSim> ", 8, 0);
+ } else {
+ cerr << "Socket reply must be to a valid socket" << endl;
+ return -1;
+ }
+ return num_chars_sent;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGfdmSocket::Close(void)
+{
+ close(sckt_in);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGfdmSocket::Clear(void)
+{
+ buffer = "";
+ size = 0;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGfdmSocket::Clear(string s)
+{
+ buffer = s + " ";
+ size = buffer.size();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGfdmSocket::Append(const char* item)
+{
+ if (size == 0) buffer += string(item);
+ else buffer += string(",") + string(item);
+ size++;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGfdmSocket::Append(double item)
+{
+ char s[25];
+
+ sprintf(s,"%12.7f",item);
+
+ if (size == 0) buffer += string(s);
+ else buffer += string(",") + string(s);
+ size++;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGfdmSocket::Append(long item)
+{
+ char s[25];
+
+ sprintf(s,"%12ld",item);
+
+ if (size == 0) buffer += string(s);
+ else buffer += string(",") + string(s);
+ size++;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGfdmSocket::Send(void)
+{
+ buffer += string("\n");
+ if ((send(sckt,buffer.c_str(),buffer.size(),0)) <= 0) {
+ perror("send");
+ } else {
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGfdmSocket::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGfdmSocket" << endl;
+ if (from == 1) cout << "Destroyed: FGfdmSocket" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGfdmSocket.h
+ Author: Jon S. Berndt
+ Date started: 11/08/99
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+11/08/99 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGfdmSocket_H
+#define FGfdmSocket_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <stdio.h>
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# include STL_STRING
+# include STL_IOSTREAM
+# include STL_FSTREAM
+ SG_USING_STD(cout);
+ SG_USING_STD(endl);
+#else
+# include <string>
+# if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
+# include <iostream.h>
+# include <fstream.h>
+# else
+# include <iostream>
+# include <fstream>
+ using std::cout;
+ using std::endl;
+# endif
+#endif
+
+#include <sys/types.h>
+#include "FGJSBBase.h"
+
+#if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
+ #include <winsock.h>
+ #include <io.h>
+#else
+ #include <unistd.h>
+ #include <sys/socket.h>
+ #include <netinet/in.h>
+ #include <netdb.h>
+ #include <errno.h>
+ #include <sys/ioctl.h>
+#endif
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_FDMSOCKET "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Encapsulates a socket object.
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+using std::string;
+using std::cerr;
+
+class FGfdmSocket : public FGJSBBase
+{
+public:
+ FGfdmSocket(string, int);
+ FGfdmSocket(int);
+ ~FGfdmSocket();
+ void Send(void);
+ string Receive(void);
+ int Reply(string text);
+ void Append(const string s) {Append(s.c_str());}
+ void Append(const char*);
+ void Append(double);
+ void Append(long);
+ void Clear(void);
+ void Clear(string s);
+ void Close(void);
+ bool GetConnectStatus(void) {return connected;}
+
+private:
+ int sckt;
+ int sckt_in;
+ int size;
+ struct sockaddr_in scktName;
+ struct hostent *host;
+ string buffer;
+ bool connected;
+ void Debug(int from);
+};
+}
+#endif
--- /dev/null
+noinst_LIBRARIES = libInputOutput.a
+
+libInputOutput_a_SOURCES = FGGroundCallback.cpp FGPropertyManager.cpp FGScript.cpp FGXMLElement.cpp FGXMLParse.cpp FGfdmSocket.cpp
+
+noinst_HEADERS = FGGroundCallback.h FGPropertyManager.h FGScript.h FGXMLElement.h FGXMLParse.h FGfdmSocket.h
+
+INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Module: FGColumnVector3.cpp
+Author: Originally by Tony Peden [formatted here (and broken??) by JSB]
+Date started: 1998
+Purpose: FGColumnVector3 class
+Called by: Various
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+??/??/?? TP Created
+03/16/2000 JSB Added exception throwing
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGColumnVector3.h"
+#include <stdio.h>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_COLUMNVECTOR3;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGColumnVector3::FGColumnVector3(void)
+{
+ data[0] = data[1] = data[2] = 0.0;
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGColumnVector3::Dump(string delimeter) const
+{
+ char buffer[256];
+ sprintf(buffer, "%f%s%f%s%f", Entry(1), delimeter.c_str(), Entry(2), delimeter.c_str(), Entry(3));
+ return string(buffer);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ostream& operator<<(ostream& os, const FGColumnVector3& col)
+{
+ os << col(1) << " , " << col(2) << " , " << col(3);
+ return os;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGColumnVector3 FGColumnVector3::operator/(const double scalar) const
+{
+ if (scalar != 0.0)
+ return operator*( 1.0/scalar );
+
+ cerr << "Attempt to divide by zero in method \
+ FGColumnVector3::operator/(const double scalar), \
+ object " << data[0] << " , " << data[1] << " , " << data[2] << endl;
+ return FGColumnVector3();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGColumnVector3& FGColumnVector3::operator/=(const double scalar)
+{
+ if (scalar != 0.0)
+ operator*=( 1.0/scalar );
+ else
+ cerr << "Attempt to divide by zero in method \
+ FGColumnVector3::operator/=(const double scalar), \
+ object " << data[0] << " , " << data[1] << " , " << data[2] << endl;
+
+ return *this;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGColumnVector3::Magnitude(void) const
+{
+ if (Entry(1) == 0.0 && Entry(2) == 0.0 && Entry(3) == 0.0)
+ return 0.0;
+ else
+ return sqrt( Entry(1)*Entry(1) + Entry(2)*Entry(2) + Entry(3)*Entry(3) );
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGColumnVector3& FGColumnVector3::Normalize(void)
+{
+ double Mag = Magnitude();
+
+ if (Mag != 0.0)
+ operator*=( 1.0/Mag );
+
+ return *this;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGColumnVector3 FGColumnVector3::multElementWise(const FGColumnVector3& V) const
+{
+ return FGColumnVector3(Entry(1) * V(1), Entry(2) * V(2), Entry(3) * V(3));
+}
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGColumnVector3::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGColumnVector3" << endl;
+ if (from == 1) cout << "Destroyed: FGColumnVector3" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+
+} // namespace JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Header: FGColumnVector3.h
+Author: Originally by Tony Peden [formatted and adapted here by Jon Berndt]
+Date started: Unknown
+
+HISTORY
+--------------------------------------------------------------------------------
+??/??/???? ?? Initial version and more.
+03/06/2004 MF Rework, document and do much inlineing.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGCOLUMNVECTOR3_H
+#define FGCOLUMNVECTOR3_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <stdlib.h>
+#ifdef FGFS
+# include <math.h>
+# include <simgear/compiler.h>
+# include STL_STRING
+# include STL_FSTREAM
+# include STL_IOSTREAM
+ SG_USING_STD(string);
+ SG_USING_STD(ostream);
+ SG_USING_STD(istream);
+ SG_USING_STD(cerr);
+ SG_USING_STD(cout);
+ SG_USING_STD(endl);
+#else
+# include <string>
+# if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
+# include <fstream.h>
+# include <iostream.h>
+# include <math.h>
+# else
+# include <fstream>
+# include <iostream>
+# if defined(sgi) && !defined(__GNUC__)
+# include <math.h>
+# else
+# include <cmath>
+# endif
+ using std::ostream;
+ using std::istream;
+ using std::cerr;
+ using std::cout;
+ using std::endl;
+# if !(defined(_MSC_VER) && _MSC_VER <= 1200)
+ using std::sqrt;
+# endif
+# endif
+ using std::string;
+#endif
+
+#include "FGJSBBase.h"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_COLUMNVECTOR3 "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** This class implements a 3 dimensional vector.
+ @author Jon S. Berndt, Tony Peden, et. al.
+ @version $Id$
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGColumnVector3 : public FGJSBBase
+{
+public:
+ /** Default initializer.
+ Create a zero vector. */
+ FGColumnVector3(void);
+
+ /** Initialization by given values.
+ @param X value of the x-conponent.
+ @param Y value of the y-conponent.
+ @param Z value of the z-conponent.
+ Create a vector from the doubles given in the arguments. */
+ FGColumnVector3(double X, double Y, double Z) {
+ data[0] = X;
+ data[1] = Y;
+ data[2] = Z;
+ Debug(0);
+ }
+
+ /** Copy constructor.
+ @param v Vector which is used for initialization.
+ Create copy of the vector given in the argument. */
+ FGColumnVector3(const FGColumnVector3& v) {
+ data[0] = v.data[0];
+ data[1] = v.data[1];
+ data[2] = v.data[2];
+ Debug(0);
+ }
+
+ /// Destructor.
+ ~FGColumnVector3(void) { Debug(1); }
+
+ /** Read access the entries of the vector.
+ @param idx the component index.
+ Return the value of the matrix entry at the given index.
+ Indices are counted starting with 1.
+ Note that the index given in the argument is unchecked. */
+ double operator()(unsigned int idx) const { return Entry(idx); }
+
+ /** Write access the entries of the vector.
+ @param idx the component index.
+ Return a reference to the vector entry at the given index.
+ Indices are counted starting with 1.
+ Note that the index given in the argument is unchecked. */
+ double& operator()(unsigned int idx) { return Entry(idx); }
+
+ /** Read access the entries of the vector.
+ @param idx the component index.
+ Return the value of the matrix entry at the given index.
+ Indices are counted starting with 1.
+ This function is just a shortcut for the @ref double
+ operator()(unsigned int idx) const function. It is
+ used internally to access the elements in a more convenient way.
+ Note that the index given in the argument is unchecked. */
+ double Entry(unsigned int idx) const { return data[idx-1]; }
+
+ /** Write access the entries of the vector.
+ @param idx the component index.
+ Return a reference to the vector entry at the given index.
+ Indices are counted starting with 1.
+ This function is just a shortcut for the @ref double&
+ operator()(unsigned int idx) function. It is
+ used internally to access the elements in a more convenient way.
+ Note that the index given in the argument is unchecked. */
+ double& Entry(unsigned int idx) { return data[idx-1]; }
+
+ /** Prints the contents of the vector
+ @param delimeter the item separator (tab or comma)
+ @return a string with the delimeter-separated contents of the vector */
+ string Dump(string delimeter) const;
+
+ /** Assignment operator.
+ @param b source vector.
+ Copy the content of the vector given in the argument into *this. */
+ FGColumnVector3& operator=(const FGColumnVector3& b) {
+ data[0] = b.data[0];
+ data[1] = b.data[1];
+ data[2] = b.data[2];
+ return *this;
+ }
+
+ /** Comparison operator.
+ @param b other vector.
+ Returns true if both vectors are exactly the same. */
+ bool operator==(const FGColumnVector3& b) const {
+ return data[0] == b.data[0] && data[1] == b.data[1] && data[2] == b.data[2];
+ }
+
+ /** Comparison operator.
+ @param b other vector.
+ Returns false if both vectors are exactly the same. */
+ bool operator!=(const FGColumnVector3& b) const { return ! operator==(b); }
+
+ /** Multiplication by a scalar.
+ @param scalar scalar value to multiply the vector with.
+ @return The resulting vector from the multiplication with that scalar.
+ Multiply the vector with the scalar given in the argument. */
+ FGColumnVector3 operator*(const double scalar) const {
+ return FGColumnVector3(scalar*Entry(1), scalar*Entry(2), scalar*Entry(3));
+ }
+
+ /** Multiply by 1/scalar.
+ @param scalar scalar value to devide the vector through.
+ @return The resulting vector from the division through that scalar.
+ Multiply the vector with the 1/scalar given in the argument. */
+ FGColumnVector3 operator/(const double scalar) const;
+
+ /** Cross product multiplication.
+ @param v vector to multiply with.
+ @return The resulting vector from the cross product multiplication.
+ Compute and return the cross product of the current vector with
+ the given argument. */
+ FGColumnVector3 operator*(const FGColumnVector3& V) const {
+ return FGColumnVector3( Entry(2) * V(3) - Entry(3) * V(2),
+ Entry(3) * V(1) - Entry(1) * V(3),
+ Entry(1) * V(2) - Entry(2) * V(1) );
+ }
+
+ /// Addition operator.
+ FGColumnVector3 operator+(const FGColumnVector3& B) const {
+ return FGColumnVector3( Entry(1) + B(1), Entry(2) + B(2), Entry(3) + B(3) );
+ }
+
+ /// Subtraction operator.
+ FGColumnVector3 operator-(const FGColumnVector3& B) const {
+ return FGColumnVector3( Entry(1) - B(1), Entry(2) - B(2), Entry(3) - B(3) );
+ }
+
+ /// Subtract an other vector.
+ FGColumnVector3& operator-=(const FGColumnVector3 &B) {
+ Entry(1) -= B(1);
+ Entry(2) -= B(2);
+ Entry(3) -= B(3);
+ return *this;
+ }
+
+ /// Add an other vector.
+ FGColumnVector3& operator+=(const FGColumnVector3 &B) {
+ Entry(1) += B(1);
+ Entry(2) += B(2);
+ Entry(3) += B(3);
+ return *this;
+ }
+
+ /// Scale by a scalar.
+ FGColumnVector3& operator*=(const double scalar) {
+ Entry(1) *= scalar;
+ Entry(2) *= scalar;
+ Entry(3) *= scalar;
+ return *this;
+ }
+
+ /// Scale by a 1/scalar.
+ FGColumnVector3& operator/=(const double scalar);
+
+ void InitMatrix(void) { data[0] = data[1] = data[2] = 0.0; }
+ void InitMatrix(double a) { data[0] = data[1] = data[2] = a; }
+ void InitMatrix(double a, double b, double c) {
+ data[0]=a; data[1]=b; data[2]=c;
+ }
+
+ /** Length of the vector.
+ Compute and return the euclidean norm of this vector. */
+ double Magnitude(void) const;
+
+ /** Length of the vector in a coordinate axis plane.
+ Compute and return the euclidean norm of this vector projected into
+ the coordinate axis plane idx1-idx2. */
+ double Magnitude(int idx1, int idx2) const {
+ return sqrt( Entry(idx1)*Entry(idx1) + Entry(idx2)*Entry(idx2) );
+ }
+
+ /** Normalize.
+ Normalize the vector to have the Magnitude() == 1.0. If the vector
+ is equal to zero it is left untouched. */
+ FGColumnVector3& Normalize(void);
+
+ // ??? Is this something sensible ??
+ FGColumnVector3 multElementWise(const FGColumnVector3& V) const;
+
+ // little trick here.
+ struct AssignRef {
+ AssignRef(FGColumnVector3& r, int i) : Ref(r), idx(i) {}
+ AssignRef operator<<(const double ff) {
+ Ref.Entry(idx) = ff;
+ return AssignRef(Ref, idx+1);
+ }
+ FGColumnVector3& Ref;
+ int idx;
+ };
+ AssignRef operator<<(const double ff) {
+ Entry(1) = ff;
+ return AssignRef(*this, 2);
+ }
+
+private:
+ double data[3];
+
+ void Debug(int from);
+};
+
+/** Scalar multiplication.
+ @param scalar scalar value to multiply with.
+ @param A Vector to multiply.
+ Multiply the Vector with a scalar value.*/
+inline FGColumnVector3 operator*(double scalar, const FGColumnVector3& A) {
+ // use already defined operation.
+ return A*scalar;
+}
+
+/** Write vector to a stream.
+ @param os Stream to write to.
+ @param M Matrix to write.
+ Write the matrix to a stream.*/
+ostream& operator<<(ostream& os, const FGColumnVector3& col);
+
+} // namespace JSBSim
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Module: FGFunction.cpp
+Author: Jon Berndt
+Date started: 8/25/2004
+Purpose: Stores various parameter types for functions
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <stdio.h>
+
+#include "FGFunction.h"
+#include "FGTable.h"
+#include "FGPropertyValue.h"
+#include "FGRealValue.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_FUNCTION;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, string prefix)
+ : PropertyManager(propMan), Prefix(prefix)
+{
+ int i;
+ Element* element;
+ string operation, property_name;
+ int size = el->GetNumElements();
+ cached = false;
+ cachedValue = -HUGE_VAL;
+
+ Name = el->GetAttributeValue("name");
+ operation = el->GetName();
+ if (operation == string("function")) {
+ Type = eTopLevel;
+ bind();
+ } else if (operation == string("product")) {
+ Type = eProduct;
+ } else if (operation == string("difference")) {
+ Type = eDifference;
+ } else if (operation == string("sum")) {
+ Type = eSum;
+ } else if (operation == string("quotient")) {
+ Type = eQuotient;
+ } else if (operation == string("pow")) {
+ Type = ePow;
+ } else if (operation == string("abs")) {
+ Type = eAbs;
+ } else if (operation == string("sin")) {
+ Type = eSin;
+ } else if (operation == string("cos")) {
+ Type = eCos;
+ } else if (operation == string("tan")) {
+ Type = eTan;
+ } else if (operation == string("asin")) {
+ Type = eASin;
+ } else if (operation == string("acos")) {
+ Type = eACos;
+ } else if (operation == string("atan")) {
+ Type = eATan;
+ } else if (operation == string("atan2")) {
+ Type = eATan2;
+ } else if (operation != string("description")) {
+ cerr << "Bad operation " << operation << " detected in configuration file" << endl;
+ }
+
+ element = el->GetElement();
+ while (element) {
+ operation = element->GetName();
+
+ // data types
+ if (operation == string("property")) {
+ property_name = element->GetDataLine();
+ Parameters.push_back(new FGPropertyValue(PropertyManager->GetNode(property_name)));
+ } else if (operation == string("value")) {
+ Parameters.push_back(new FGRealValue(element->GetDataAsNumber()));
+ } else if (operation == string("table")) {
+ Parameters.push_back(new FGTable(PropertyManager, element));
+ // operations
+ } else if (operation == string("product") ||
+ operation == string("difference") ||
+ operation == string("sum") ||
+ operation == string("quotient") ||
+ operation == string("pow") ||
+ operation == string("abs") ||
+ operation == string("sin") ||
+ operation == string("cos") ||
+ operation == string("tan") ||
+ operation == string("asin") ||
+ operation == string("acos") ||
+ operation == string("atan") ||
+ operation == string("atan2"))
+ {
+ Parameters.push_back(new FGFunction(PropertyManager, element));
+ } else if (operation != string("description")) {
+ cerr << "Bad operation " << operation << " detected in configuration file" << endl;
+ }
+ element = el->GetNextElement();
+ }
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGFunction::~FGFunction(void)
+{
+ string tmp = PropertyManager->mkPropertyName(Prefix + Name, false); // Allow upper case
+ PropertyManager->Untie(tmp);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFunction::cacheValue(bool cache)
+{
+ cached = false; // Must set cached to false prior to calling GetValue(), else
+ // it will _never_ calculate the value;
+ if (cache) {
+ cachedValue = GetValue();
+ cached = true;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGFunction::GetValue(void) const
+{
+ int i;
+
+ if (cached) return cachedValue;
+
+ double temp = Parameters[0]->GetValue();
+
+ switch (Type) {
+ case eTopLevel:
+ break;
+ case eProduct:
+ for (i=1;i<Parameters.size();i++) temp *= Parameters[i]->GetValue();
+ break;
+ case eDifference:
+ for (i=1;i<Parameters.size();i++) temp -= Parameters[i]->GetValue();
+ break;
+ case eSum:
+ for (i=1;i<Parameters.size();i++) temp += Parameters[i]->GetValue();
+ break;
+ case eQuotient:
+ temp /= Parameters[1]->GetValue();
+ break;
+ case ePow:
+ temp = pow(temp,Parameters[1]->GetValue());
+ break;
+ case eAbs:
+ temp = abs(temp);
+ break;
+ case eSin:
+ temp = sin(temp);
+ break;
+ case eCos:
+ temp = cos(temp);
+ break;
+ case eTan:
+ temp = tan(temp);
+ break;
+ case eACos:
+ temp = acos(temp);
+ break;
+ case eASin:
+ temp = asin(temp);
+ break;
+ case eATan:
+ temp = atan(temp);
+ break;
+ case eATan2:
+ temp = atan2(temp, Parameters[1]->GetValue());
+ break;
+ default:
+ cerr << "Unknown function operation type" << endl;
+ break;
+ }
+
+ return temp;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGFunction::GetValueAsString(void) const
+{
+ char buffer[20];
+ string value;
+
+ sprintf(buffer,"%9.6f",GetValue());
+ value = string(buffer);
+ return value;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFunction::bind(void)
+{
+ string tmp = PropertyManager->mkPropertyName(Prefix + Name, false); // Allow upper case
+ PropertyManager->Tie( tmp, this, &FGFunction::GetValue);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGFunction::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+ if (Type == eTopLevel)
+ cout << " Function: " << Name << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGGroundReactions" << endl;
+ if (from == 1) cout << "Destroyed: FGGroundReactions" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Header: FGFunction.h
+Author: Jon Berndt
+Date started: August 25 2004
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGFUNCTION_H
+#define FGFUNCTION_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <vector>
+#include <string>
+#include "FGParameter.h"
+#include <input_output/FGXMLElement.h>
+#include <input_output/FGPropertyManager.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_FUNCTION "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+ /** Represents various types of parameters.
+ @author Jon Berndt
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DECLARATION: FGFunction
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGFunction : public FGParameter
+{
+public:
+
+ FGFunction(FGPropertyManager* propMan, Element* el, string prefix="");
+ ~FGFunction();
+
+ double GetValue(void) const;
+ string GetValueAsString(void) const;
+ string GetName(void) const {return Name;}
+ void cacheValue(bool);
+
+private:
+ vector <FGParameter*> Parameters;
+ FGPropertyManager* const PropertyManager;
+ bool cached;
+ string Prefix;
+ double cachedValue;
+ enum functionType {eTopLevel=0, eProduct, eDifference, eSum, eQuotient, ePow,
+ eAbs, eSin, eCos, eTan, eASin, eACos, eATan, eATan2} Type;
+ string Name;
+ void bind(void);
+ void Debug(int from);
+};
+
+} // namespace JSBSim
+
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGLocation.cpp
+ Author: Jon S. Berndt
+ Date started: 04/04/2004
+ Purpose: Store an arbitrary location on the globe
+
+ ------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------------
+ ------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+------------------------------------------------------------------------------
+This class encapsulates an arbitrary position in the globe with its accessors.
+It has vector properties, so you can add multiply ....
+
+HISTORY
+------------------------------------------------------------------------------
+04/04/2004 MF Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# ifdef SG_HAVE_STD_INCLUDES
+# include <cmath>
+# else
+# include <math.h>
+# endif
+#else
+# if defined(sgi) && !defined(__GNUC__)
+# include <math.h>
+# else
+# include <cmath>
+# endif
+#endif
+
+#include "FGLocation.h"
+#include <input_output/FGPropertyManager.h>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_LOCATION;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGLocation::FGLocation(double lon, double lat, double radius)
+{
+ mCacheValid = false;
+
+ double sinLat = sin(lat);
+ double cosLat = cos(lat);
+ double sinLon = sin(lon);
+ double cosLon = cos(lon);
+ mECLoc = FGColumnVector3( radius*cosLat*cosLon,
+ radius*cosLat*sinLon,
+ radius*sinLat );
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGLocation::SetLongitude(double longitude)
+{
+ double rtmp = mECLoc.Magnitude(eX, eY);
+ // Check if we have zero radius.
+ // If so set it to 1, so that we can set a position
+ if (0.0 == mECLoc.Magnitude())
+ rtmp = 1.0;
+
+ // Fast return if we are on the north or south pole ...
+ if (rtmp == 0.0)
+ return;
+
+ mCacheValid = false;
+
+ mECLoc(eX) = rtmp*cos(longitude);
+ mECLoc(eY) = rtmp*sin(longitude);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGLocation::SetLatitude(double latitude)
+{
+ mCacheValid = false;
+
+ double r = mECLoc.Magnitude();
+ if (r == 0.0) {
+ mECLoc(eX) = 1.0;
+ r = 1.0;
+ }
+
+ double rtmp = mECLoc.Magnitude(eX, eY);
+ if (rtmp != 0.0) {
+ double fac = r/rtmp*cos(latitude);
+ mECLoc(eX) *= fac;
+ mECLoc(eY) *= fac;
+ } else {
+ mECLoc(eX) = r*cos(latitude);
+ mECLoc(eY) = 0.0;
+ }
+ mECLoc(eZ) = r*sin(latitude);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGLocation::SetRadius(double radius)
+{
+ mCacheValid = false;
+
+ double rold = mECLoc.Magnitude();
+ if (rold == 0.0)
+ mECLoc(eX) = radius;
+ else
+ mECLoc *= radius/rold;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGLocation::ComputeDerivedUnconditional(void) const
+{
+ // The radius is just the Euclidean norm of the vector.
+ mRadius = mECLoc.Magnitude();
+
+ // The distance of the location to the y-axis, which is the axis
+ // through the poles.
+ double rxy = sqrt(mECLoc(eX)*mECLoc(eX) + mECLoc(eY)*mECLoc(eY));
+
+ // Compute the sin/cos values of the longitude
+ double sinLon, cosLon;
+ if (rxy == 0.0) {
+ sinLon = 0.0;
+ cosLon = 1.0;
+ } else {
+ sinLon = mECLoc(eY)/rxy;
+ cosLon = mECLoc(eX)/rxy;
+ }
+
+ // Compute the sin/cos values of the latitude
+ double sinLat, cosLat;
+ if (mRadius == 0.0) {
+ sinLat = 0.0;
+ cosLat = 1.0;
+ } else {
+ sinLat = mECLoc(eZ)/mRadius;
+ cosLat = rxy/mRadius;
+ }
+
+ // Compute the longitude and latitude itself
+ if ( mECLoc( eX ) == 0.0 && mECLoc( eY ) == 0.0 )
+ mLon = 0.0;
+ else
+ mLon = atan2( mECLoc( eY ), mECLoc( eX ) );
+
+ if ( rxy == 0.0 && mECLoc( eZ ) == 0.0 )
+ mLat = 0.0;
+ else
+ mLat = atan2( mECLoc(eZ), rxy );
+
+ // Compute the transform matrices from and to the earth centered frame.
+ // see Durham Chapter 4, problem 1, page 52
+ mTec2l = FGMatrix33( -cosLon*sinLat, -sinLon*sinLat, cosLat,
+ -sinLon , cosLon , 0.0 ,
+ -cosLon*cosLat, -sinLon*cosLat, -sinLat );
+
+ mTl2ec = mTec2l.Transposed();
+
+ // Mark the cached values as valid
+ mCacheValid = true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGLocation::bind(FGPropertyManager* PropertyManager, const string& prefix) const
+{
+ PropertyManager->Tie(prefix + "lat-gc-rad", (FGLocation*)this,
+ &FGLocation::GetLatitude);
+ PropertyManager->Tie(prefix + "lat-gc-deg", (FGLocation*)this,
+ &FGLocation::GetLatitudeDeg);
+ PropertyManager->Tie(prefix + "long-gc-rad", (FGLocation*)this,
+ &FGLocation::GetLongitude);
+ PropertyManager->Tie(prefix + "long-gc-deg", (FGLocation*)this,
+ &FGLocation::GetLongitudeDeg);
+ PropertyManager->Tie(prefix + "radius-ft", (FGLocation*)this,
+ &FGLocation::GetRadius);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGLocation::unbind(FGPropertyManager* PropertyManager, const string& prefix) const
+{
+ PropertyManager->Untie(prefix + "lat-gc-rad");
+ PropertyManager->Untie(prefix + "lat-gc-deg");
+ PropertyManager->Untie(prefix + "long-gc-rad");
+ PropertyManager->Untie(prefix + "long-gc-deg");
+ PropertyManager->Untie(prefix + "radius-ft");
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+} // namespace JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGLocation.h
+ Author: Jon S. Berndt, Mathias Froehlich
+ Date started: 04/04/2004
+
+ ------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------------
+ ------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+-------------------------------------------------------------------------------
+04/04/2004 MF Created from code previously in the old positions class.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGLOCATION_H
+#define FGLOCATION_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <FGJSBBase.h>
+#include <input_output/FGPropertyManager.h>
+#include "FGColumnVector3.h"
+#include "FGMatrix33.h"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_LOCATION "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Holds an arbitrary location in the earth centered reference frame.
+ This coordinate frame has its center in the middle of the earth.
+ Its x-axis points from the center of the earth towards a location
+ with zero latitude and longitude on the earths surface. The y-axis
+ points from the center of the earth towards a location with zero
+ latitude and 90deg longitude on the earths surface. The z-axis
+ points from the earths center to the geographic north pole.
+
+ This class provides access functions to set and get the location as
+ either the simple x, y and z values in ft or longitude/latitude and
+ the radial distance of the location from the earth center.
+
+ It is common to associate a parent frame with a location. This
+ frame is usually called the local horizontal frame or simply the local
+ frame. This frame has its x/y plane parallel to the surface of the earth
+ (with the assumption of a spherical earth). The x-axis points
+ towards north, the y-axis points towards east and the z-axis
+ points to the center of the earth.
+
+ Since this frame is determined by the location, this class also
+ provides the rotation matrices required to transform from the
+ earth centered frame to the local horizontal frame and back. There
+ are also conversion functions for conversion of position vectors
+ given in the one frame to positions in the other frame.
+
+ The earth centered reference frame is *NOT* an inertial frame
+ since it rotates with the earth.
+
+ The coordinates in the earth centered frame are the master values.
+ All other values are computed from these master values and are
+ cached as long as the location is changed by access through a
+ non-const member function. Values are cached to improve performance.
+ It is best practice to work with a natural set of master values.
+ Other parameters that are derived from these master values are calculated
+ only when needed, and IF they are needed and calculated, then they are
+ cached (stored and remembered) so they do not need to be re-calculated
+ until the master values they are derived from are themselves changed
+ (and become stale).
+
+ Accuracy and round off:
+
+ Given that we model a vehicle near the earth, the earths surface
+ radius is about 2*10^7, ft and that we use double values for the
+ representation of the location, we have an accuracy of about
+ 1e-16*2e7ft/1=2e-9ft left. This should be sufficient for our needs.
+ Note that this is the same relative accuracy we would have when we
+ compute directly with lon/lat/radius. For the radius value this
+ is clear. For the lon/lat pair this is easy to see. Take for
+ example KSFO located at about 37.61deg north 122.35deg west, which
+ corresponds to 0.65642rad north and 2.13541rad west. Both values
+ are of magnitude of about 1. But 1ft corresponds to about
+ 1/(2e7*2*pi)=7.9577e-09rad. So the left accuracy with this
+ representation is also about 1*1e-16/7.9577e-09=1.2566e-08 which
+ is of the same magnitude as the representation chosen here.
+
+ The advantage of this representation is that it is a linear space
+ without singularities. The singularities are the north and south
+ pole and most notably the non-steady jump at -pi to pi. It is
+ harder to track this jump correctly especially when we need to
+ work with error norms and derivatives of the equations of motion
+ within the time-stepping code. Also, the rate of change is of the
+ same magnitude for all components in this representation which is
+ an advantage for numerical stability in implicit time-stepping too.
+
+ Note: The latitude is a GEOCENTRIC value. FlightGear
+ converts latitude to a geodetic value and uses that. In order to get best
+ matching relative to a map, geocentric latitude must be converted to geodetic.
+
+ @see W. C. Durham "Aircraft Dynamics & Control", section 2.2
+
+ @author Mathias Froehlich
+ @version $Id$
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGLocation : virtual FGJSBBase
+{
+public:
+ /** Default constructor. */
+ FGLocation() { mCacheValid = false; }
+
+ /** Constructor to set the longitude, latitude and the distance
+ from the center of the earth.
+ @param lon longitude
+ @param lat GEOCENTRIC latitude
+ @param distance from center of earth to vehicle in feet*/
+ FGLocation(double lon, double lat, double radius);
+
+ /** Copy constructor. */
+ FGLocation(const FGColumnVector3& lv)
+ : mECLoc(lv), mCacheValid(false) {}
+
+ /** Copy constructor. */
+ FGLocation(const FGLocation& l)
+ : mECLoc(l.mECLoc), mCacheValid(l.mCacheValid) {
+ if (!mCacheValid)
+ return;
+
+ mLon = l.mLon;
+ mLat = l.mLat;
+ mRadius = l.mRadius;
+
+ mTl2ec = l.mTl2ec;
+ mTec2l = l.mTec2l;
+ }
+
+ /** Get the longitude.
+ @return the longitude in rad of the location represented with this
+ class instance. The returned values are in the range between
+ -pi <= lon <= pi. Longitude is positive east and negative west. */
+ double GetLongitude() const { ComputeDerived(); return mLon; }
+
+ /** Get the longitude.
+ @return the longitude in deg of the location represented with this
+ class instance. The returned values are in the range between
+ -180 <= lon <= 180. Longitude is positive east and negative west. */
+ double GetLongitudeDeg() const { ComputeDerived(); return radtodeg*mLon; }
+
+ /** Set the longitude.
+ @param longitude Longitude in rad to set.
+ Sets the longitude of the location represented with this class
+ instance to the value of the given argument. The value is meant
+ to be in rad. The latitude and the radius value are preserved
+ with this call with the exception of radius being equal to
+ zero. If the radius is previously set to zero it is changed to be
+ equal to 1.0 past this call. Longitude is positive east and negative west. */
+ void SetLongitude(double longitude);
+
+ /** Get the sine of Longitude. */
+ double GetSinLongitude() const { ComputeDerived(); return -mTec2l(2,1); }
+
+ /** Get the cosine of Longitude. */
+ double GetCosLongitude() const { ComputeDerived(); return mTec2l(2,2); }
+
+ /** Get the latitude.
+ @return the latitude in rad of the location represented with this
+ class instance. The returned values are in the range between
+ -pi/2 <= lon <= pi/2. Latitude is positive north and negative south. */
+ double GetLatitude() const { ComputeDerived(); return mLat; }
+
+ /** Get the latitude.
+ @return the latitude in deg of the location represented with this
+ class instance. The returned values are in the range between
+ -90 <= lon <= 90. Latitude is positive north and negative south. */
+ double GetLatitudeDeg() const { ComputeDerived(); return radtodeg*mLat; }
+
+ /** Set the latitude.
+ @param latitude Latitude in rad to set.
+ Sets the latitude of the location represented with this class
+ instance to the value of the given argument. The value is meant
+ to be in rad. The longitude and the radius value are preserved
+ with this call with the exception of radius being equal to
+ zero. If the radius is previously set to zero it is changed to be
+ equal to 1.0 past this call.
+ Latitude is positive north and negative south.
+ The arguments should be within the bounds of -pi/2 <= lat <= pi/2.
+ The behavior of this function with arguments outside this range is
+ left as an exercise to the gentle reader ... */
+ void SetLatitude(double latitude);
+
+ /** Get the sine of Latitude. */
+ double GetSinLatitude() const { ComputeDerived(); return -mTec2l(3,3); }
+
+ /** Get the cosine of Latitude. */
+ double GetCosLatitude() const { ComputeDerived(); return mTec2l(1,3); }
+
+ /** Get the cosine of Latitude. */
+ double GetTanLatitude() const {
+ ComputeDerived();
+ double cLat = mTec2l(1,3);
+ if (cLat == 0.0)
+ return 0.0;
+ else
+ return -mTec2l(3,3)/cLat;
+ }
+
+ /** Get the distance from the center of the earth.
+ @return the distance of the location represented with this class
+ instance to the center of the earth in ft. The radius value is
+ always positive. */
+ double GetRadius() const { ComputeDerived(); return mRadius; }
+
+ /** Set the distance from the center of the earth.
+ @param radius Radius in ft to set.
+ Sets the radius of the location represented with this class
+ instance to the value of the given argument. The value is meant
+ to be in ft. The latitude and longitude values are preserved
+ with this call with the exception of radius being equal to
+ zero. If the radius is previously set to zero, latitude and
+ longitude is set equal to zero past this call.
+ The argument should be positive.
+ The behavior of this function called with a negative argument is
+ left as an exercise to the gentle reader ... */
+ void SetRadius(double radius);
+
+ /** Transform matrix from local horizontal to earth centered frame.
+ Returns a const reference to the rotation matrix of the transform from
+ the local horizontal frame to the earth centered frame. */
+ const FGMatrix33& GetTl2ec(void) const { ComputeDerived(); return mTl2ec; }
+
+ /** Transform matrix from the earth centered to local horizontal frame.
+ Returns a const reference to the rotation matrix of the transform from
+ the earth centered frame to the local horizontal frame. */
+ const FGMatrix33& GetTec2l(void) const { ComputeDerived(); return mTec2l; }
+
+ /** Conversion from Local frame coordinates to a location in the
+ earth centered and fixed frame.
+ @parm lvec Vector in the local horizontal coordinate frame
+ @return The location in the earth centered and fixed frame */
+ FGLocation LocalToLocation(const FGColumnVector3& lvec) const {
+ ComputeDerived(); return mTl2ec*lvec + mECLoc;
+ }
+
+ /** Conversion from a location in the earth centered and fixed frame
+ to local horizontal frame coordinates.
+ @parm ecvec Vector in the earth centered and fixed frame
+ @return The vector in the local horizontal coordinate frame */
+ FGColumnVector3 LocationToLocal(const FGColumnVector3& ecvec) const {
+ ComputeDerived(); return mTec2l*(ecvec - mECLoc);
+ }
+
+ // For time-stepping, locations have vector properties...
+
+ /** Read access the entries of the vector.
+ @param idx the component index.
+ Return the value of the matrix entry at the given index.
+ Indices are counted starting with 1.
+ Note that the index given in the argument is unchecked. */
+ double operator()(unsigned int idx) const { return Entry(idx); }
+
+ /** Write access the entries of the vector.
+ @param idx the component index.
+ @return a reference to the vector entry at the given index.
+ Indices are counted starting with 1.
+ Note that the index given in the argument is unchecked. */
+ double& operator()(unsigned int idx) { return Entry(idx); }
+
+ /** Read access the entries of the vector.
+ @param idx the component index.
+ @return the value of the matrix entry at the given index.
+ Indices are counted starting with 1.
+ This function is just a shortcut for the @ref double
+ operator()(unsigned int idx) const function. It is
+ used internally to access the elements in a more convenient way.
+ Note that the index given in the argument is unchecked. */
+ double Entry(unsigned int idx) const { return mECLoc.Entry(idx); }
+
+ /** Write access the entries of the vector.
+ @param idx the component index.
+ @return a reference to the vector entry at the given index.
+ Indices are counted starting with 1.
+ This function is just a shortcut for the double&
+ operator()(unsigned int idx) function. It is
+ used internally to access the elements in a more convenient way.
+ Note that the index given in the argument is unchecked. */
+ double& Entry(unsigned int idx) {
+ mCacheValid = false; return mECLoc.Entry(idx);
+ }
+
+ const FGLocation& operator=(const FGLocation& l) {
+ mECLoc = l.mECLoc;
+ mCacheValid = l.mCacheValid;
+ if (!mCacheValid)
+ return *this;
+
+ mLon = l.mLon;
+ mLat = l.mLat;
+ mRadius = l.mRadius;
+
+ mTl2ec = l.mTl2ec;
+ mTec2l = l.mTec2l;
+
+ return *this;
+ }
+ bool operator==(const FGLocation& l) const {
+ return mECLoc == l.mECLoc;
+ }
+ bool operator!=(const FGLocation& l) const { return ! operator==(l); }
+ const FGLocation& operator+=(const FGLocation &l) {
+ mCacheValid = false;
+ mECLoc += l.mECLoc;
+ return *this;
+ }
+ const FGLocation& operator-=(const FGLocation &l) {
+ mCacheValid = false;
+ mECLoc -= l.mECLoc;
+ return *this;
+ }
+ const FGLocation& operator*=(double scalar) {
+ mCacheValid = false;
+ mECLoc *= scalar;
+ return *this;
+ }
+ const FGLocation& operator/=(double scalar) {
+ return operator*=(1.0/scalar);
+ }
+ FGLocation operator+(const FGLocation& l) const {
+ return FGLocation(mECLoc + l.mECLoc);
+ }
+ FGLocation operator-(const FGLocation& l) const {
+ return FGLocation(mECLoc - l.mECLoc);
+ }
+
+ FGLocation operator*(double scalar) const {
+ return FGLocation(scalar*mECLoc);
+ }
+
+ /** Cast to a simple 3d vector */
+ operator const FGColumnVector3&() const {
+ return mECLoc;
+ }
+
+ /** Ties into the property tree.
+ Ties the variables represented by this class into the property tree. */
+ void bind(FGPropertyManager*, const string&) const;
+
+ /** Remove from property tree.
+ Unties the variables represented by this class into the property tree. */
+ void unbind(FGPropertyManager*, const string&) const;
+
+private:
+ /** Computation of derived values.
+ This function re-computes the derived values like lat/lon and
+ transformation matrices. It does this unconditionally. */
+ void ComputeDerivedUnconditional(void) const;
+
+ /** Computation of derived values.
+ This function checks if the derived values like lat/lon and
+ transformation matrices are already computed. If so, it
+ returns. If they need to be computed this is done here. */
+ void ComputeDerived(void) const {
+ if (!mCacheValid)
+ ComputeDerivedUnconditional();
+ }
+
+ /** The coordinates in the earth centered frame. This is the master copy.
+ The coordinate frame has its center in the middle of the earth.
+ Its x-axis points from the center of the earth towards a
+ location with zero latitude and longitude on the earths
+ surface. The y-axis points from the center of the earth towards a
+ location with zero latitude and 90deg longitude on the earths
+ surface. The z-axis points from the earths center to the
+ geographic north pole.
+ @see W. C. Durham "Aircraft Dynamics & Control", section 2.2 */
+ FGColumnVector3 mECLoc;
+
+ /** The cached lon/lat/radius values. */
+ mutable double mLon;
+ mutable double mLat;
+ mutable double mRadius;
+
+ /** The cached rotation matrices from and to the associated frames. */
+ mutable FGMatrix33 mTl2ec;
+ mutable FGMatrix33 mTec2l;
+
+ /** A data validity flag.
+ This class implements caching of the derived values like the
+ orthogonal rotation matrices or the lon/lat/radius values. For caching we
+ carry a flag which signals if the values are valid or not.
+ The C++ keyword "mutable" tells the compiler that the data member is
+ allowed to change during a const member function. */
+ mutable bool mCacheValid;
+};
+
+/** Scalar multiplication.
+
+ @param scalar scalar value to multiply with.
+ @param l Vector to multiply.
+
+ Multiply the Vector with a scalar value. */
+inline FGLocation operator*(double scalar, const FGLocation& l)
+{
+ return l.operator*(scalar);
+}
+
+} // namespace JSBSim
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Module: FGMatrix33.cpp
+Author: Tony Peden, Jon Berndt, Mathias Frolich
+Date started: 1998
+Purpose: FGMatrix33 class
+Called by: Various
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+??/??/?? TP Created
+03/16/2000 JSB Added exception throwing
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGMatrix33.h"
+#include "FGColumnVector3.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_MATRIX33;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGMatrix33::FGMatrix33(void)
+{
+ data[0] = data[1] = data[2] = data[3] = data[4] = data[5] =
+ data[6] = data[7] = data[8] = 0.0;
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ostream& operator<<(ostream& os, const FGMatrix33& M)
+{
+ for (unsigned int i=1; i<=M.Rows(); i++) {
+ for (unsigned int j=1; j<=M.Cols(); j++) {
+ if (i == M.Rows() && j == M.Cols())
+ os << M(i,j);
+ else
+ os << M(i,j) << ", ";
+ }
+ }
+ return os;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+istream& operator>>(istream& is, FGMatrix33& M)
+{
+ for (unsigned int i=1; i<=M.Rows(); i++) {
+ for (unsigned int j=1; j<=M.Cols(); j++) {
+ is >> M(i,j);
+ }
+ }
+ return is;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGMatrix33::Determinant(void) const {
+ return Entry(1,1)*Entry(2,2)*Entry(3,3) + Entry(1,2)*Entry(2,3)*Entry(3,1)
+ + Entry(1,3)*Entry(2,1)*Entry(3,2) - Entry(1,3)*Entry(2,2)*Entry(3,1)
+ - Entry(1,2)*Entry(2,1)*Entry(3,3) - Entry(2,3)*Entry(3,2)*Entry(1,1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGMatrix33 FGMatrix33::Inverse(void) const {
+ // Compute the inverse of a general matrix using Cramers rule.
+ // I guess googling for cramers rule gives tons of references
+ // for this. :)
+ double rdet = 1.0/Determinant();
+
+ double i11 = rdet*(Entry(2,2)*Entry(3,3)-Entry(2,3)*Entry(3,2));
+ double i21 = rdet*(Entry(2,3)*Entry(3,1)-Entry(2,1)*Entry(3,3));
+ double i31 = rdet*(Entry(2,1)*Entry(3,2)-Entry(2,2)*Entry(3,1));
+ double i12 = rdet*(Entry(1,3)*Entry(3,2)-Entry(1,2)*Entry(3,3));
+ double i22 = rdet*(Entry(1,1)*Entry(3,3)-Entry(1,3)*Entry(3,1));
+ double i32 = rdet*(Entry(1,2)*Entry(3,1)-Entry(1,1)*Entry(3,2));
+ double i13 = rdet*(Entry(1,2)*Entry(2,3)-Entry(1,3)*Entry(2,2));
+ double i23 = rdet*(Entry(1,3)*Entry(2,1)-Entry(1,1)*Entry(2,3));
+ double i33 = rdet*(Entry(1,1)*Entry(2,2)-Entry(1,2)*Entry(2,1));
+
+ return FGMatrix33( i11, i12, i13,
+ i21, i22, i23,
+ i31, i32, i33 );
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGMatrix33::InitMatrix(void)
+{
+ data[0] = data[1] = data[2] = data[3] = data[4] = data[5] =
+ data[6] = data[7] = data[8] = 0.0;
+}
+
+// *****************************************************************************
+// binary operators ************************************************************
+// *****************************************************************************
+
+FGMatrix33 FGMatrix33::operator-(const FGMatrix33& M) const
+{
+ return FGMatrix33( Entry(1,1) - M(1,1),
+ Entry(1,2) - M(1,2),
+ Entry(1,3) - M(1,3),
+ Entry(2,1) - M(2,1),
+ Entry(2,2) - M(2,2),
+ Entry(2,3) - M(2,3),
+ Entry(3,1) - M(3,1),
+ Entry(3,2) - M(3,2),
+ Entry(3,3) - M(3,3) );
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGMatrix33& FGMatrix33::operator-=(const FGMatrix33 &M)
+{
+ data[0] -= M.data[0];
+ data[1] -= M.data[1];
+ data[2] -= M.data[2];
+ data[3] -= M.data[3];
+ data[4] -= M.data[4];
+ data[5] -= M.data[5];
+ data[6] -= M.data[6];
+ data[7] -= M.data[7];
+ data[8] -= M.data[8];
+
+ return *this;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGMatrix33 FGMatrix33::operator+(const FGMatrix33& M) const
+{
+ return FGMatrix33( Entry(1,1) + M(1,1),
+ Entry(1,2) + M(1,2),
+ Entry(1,3) + M(1,3),
+ Entry(2,1) + M(2,1),
+ Entry(2,2) + M(2,2),
+ Entry(2,3) + M(2,3),
+ Entry(3,1) + M(3,1),
+ Entry(3,2) + M(3,2),
+ Entry(3,3) + M(3,3) );
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGMatrix33& FGMatrix33::operator+=(const FGMatrix33 &M)
+{
+ Entry(1,1) += M(1,1);
+ Entry(1,2) += M(1,2);
+ Entry(1,3) += M(1,3);
+ Entry(2,1) += M(2,1);
+ Entry(2,2) += M(2,2);
+ Entry(2,3) += M(2,3);
+ Entry(3,1) += M(3,1);
+ Entry(3,2) += M(3,2);
+ Entry(3,3) += M(3,3);
+
+ return *this;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGMatrix33 FGMatrix33::operator*(const double scalar) const
+{
+ return FGMatrix33( scalar * Entry(1,1),
+ scalar * Entry(1,2),
+ scalar * Entry(1,3),
+ scalar * Entry(2,1),
+ scalar * Entry(2,2),
+ scalar * Entry(2,3),
+ scalar * Entry(3,1),
+ scalar * Entry(3,2),
+ scalar * Entry(3,3) );
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGMatrix33 operator*(double scalar, FGMatrix33 &M)
+{
+ return FGMatrix33( scalar * M(1,1),
+ scalar * M(1,2),
+ scalar * M(1,3),
+ scalar * M(2,1),
+ scalar * M(2,2),
+ scalar * M(2,3),
+ scalar * M(3,1),
+ scalar * M(3,2),
+ scalar * M(3,3) );
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGMatrix33& FGMatrix33::operator*=(const double scalar)
+{
+ Entry(1,1) *= scalar;
+ Entry(1,2) *= scalar;
+ Entry(1,3) *= scalar;
+ Entry(2,1) *= scalar;
+ Entry(2,2) *= scalar;
+ Entry(2,3) *= scalar;
+ Entry(3,1) *= scalar;
+ Entry(3,2) *= scalar;
+ Entry(3,3) *= scalar;
+
+ return *this;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGMatrix33 FGMatrix33::operator*(const FGMatrix33& M) const
+{
+ // FIXME: Make compiler friendlier
+ FGMatrix33 Product;
+
+ Product(1,1) = Entry(1,1)*M(1,1) + Entry(1,2)*M(2,1) + Entry(1,3)*M(3,1);
+ Product(1,2) = Entry(1,1)*M(1,2) + Entry(1,2)*M(2,2) + Entry(1,3)*M(3,2);
+ Product(1,3) = Entry(1,1)*M(1,3) + Entry(1,2)*M(2,3) + Entry(1,3)*M(3,3);
+ Product(2,1) = Entry(2,1)*M(1,1) + Entry(2,2)*M(2,1) + Entry(2,3)*M(3,1);
+ Product(2,2) = Entry(2,1)*M(1,2) + Entry(2,2)*M(2,2) + Entry(2,3)*M(3,2);
+ Product(2,3) = Entry(2,1)*M(1,3) + Entry(2,2)*M(2,3) + Entry(2,3)*M(3,3);
+ Product(3,1) = Entry(3,1)*M(1,1) + Entry(3,2)*M(2,1) + Entry(3,3)*M(3,1);
+ Product(3,2) = Entry(3,1)*M(1,2) + Entry(3,2)*M(2,2) + Entry(3,3)*M(3,2);
+ Product(3,3) = Entry(3,1)*M(1,3) + Entry(3,2)*M(2,3) + Entry(3,3)*M(3,3);
+
+ return Product;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGMatrix33& FGMatrix33::operator*=(const FGMatrix33& M)
+{
+ // FIXME: Make compiler friendlier
+ double a,b,c;
+
+ a = Entry(1,1); b=Entry(1,2); c=Entry(1,3);
+ Entry(1,1) = a*M(1,1) + b*M(2,1) + c*M(3,1);
+ Entry(1,2) = a*M(1,2) + b*M(2,2) + c*M(3,2);
+ Entry(1,3) = a*M(1,3) + b*M(2,3) + c*M(3,3);
+
+ a = Entry(2,1); b=Entry(2,2); c=Entry(2,3);
+ Entry(2,1) = a*M(1,1) + b*M(2,1) + c*M(3,1);
+ Entry(2,2) = a*M(1,2) + b*M(2,2) + c*M(3,2);
+ Entry(2,3) = a*M(1,3) + b*M(2,3) + c*M(3,3);
+
+ a = Entry(3,1); b=Entry(3,2); c=Entry(3,3);
+ Entry(3,1) = a*M(1,1) + b*M(2,1) + c*M(3,1);
+ Entry(3,2) = a*M(1,2) + b*M(2,2) + c*M(3,2);
+ Entry(3,3) = a*M(1,3) + b*M(2,3) + c*M(3,3);
+
+ return *this;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGMatrix33 FGMatrix33::operator/(const double scalar) const
+{
+ FGMatrix33 Quot;
+
+ if ( scalar != 0 ) {
+ double tmp = 1.0/scalar;
+ Quot(1,1) = Entry(1,1) * tmp;
+ Quot(1,2) = Entry(1,2) * tmp;
+ Quot(1,3) = Entry(1,3) * tmp;
+ Quot(2,1) = Entry(2,1) * tmp;
+ Quot(2,2) = Entry(2,2) * tmp;
+ Quot(2,3) = Entry(2,3) * tmp;
+ Quot(3,1) = Entry(3,1) * tmp;
+ Quot(3,2) = Entry(3,2) * tmp;
+ Quot(3,3) = Entry(3,3) * tmp;
+ } else {
+ MatrixException mE;
+ mE.Message = "Attempt to divide by zero in method FGMatrix33::operator/(const double scalar)";
+ throw mE;
+ }
+ return Quot;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGMatrix33& FGMatrix33::operator/=(const double scalar)
+{
+ if ( scalar != 0 ) {
+ double tmp = 1.0/scalar;
+ Entry(1,1) *= tmp;
+ Entry(1,2) *= tmp;
+ Entry(1,3) *= tmp;
+ Entry(2,1) *= tmp;
+ Entry(2,2) *= tmp;
+ Entry(2,3) *= tmp;
+ Entry(3,1) *= tmp;
+ Entry(3,2) *= tmp;
+ Entry(3,3) *= tmp;
+ } else {
+ MatrixException mE;
+ mE.Message = "Attempt to divide by zero in method FGMatrix33::operator/=(const double scalar)";
+ throw mE;
+ }
+ return *this;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGMatrix33::T(void)
+{
+ for (unsigned int i=1; i<=3; i++) {
+ for (unsigned int j=i+1; j<=3; j++) {
+ double tmp = Entry(i,j);
+ Entry(i,j) = Entry(j,i);
+ Entry(j,i) = tmp;
+ }
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGColumnVector3 FGMatrix33::operator*(const FGColumnVector3& v) const {
+ double tmp1 = v(1)*Entry(1,1);
+ double tmp2 = v(1)*Entry(2,1);
+ double tmp3 = v(1)*Entry(3,1);
+
+ tmp1 += v(2)*Entry(1,2);
+ tmp2 += v(2)*Entry(2,2);
+ tmp3 += v(2)*Entry(3,2);
+
+ tmp1 += v(3)*Entry(1,3);
+ tmp2 += v(3)*Entry(2,3);
+ tmp3 += v(3)*Entry(3,3);
+
+ return FGColumnVector3( tmp1, tmp2, tmp3 );
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGMatrix33::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGMatrix33" << endl;
+ if (from == 1) cout << "Destroyed: FGMatrix33" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Header: FGMatrix33.h
+Author: Tony Peden, Jon Berndt, Mathias Frolich
+Date started: Unknown
+
+HISTORY
+--------------------------------------------------------------------------------
+??/??/?? TP Created
+03/16/2000 JSB Added exception throwing
+03/06/2004 MF Rework of the code to make it a bit compiler friendlier
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGMATRIX33_H
+#define FGMATRIX33_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <stdlib.h>
+#ifdef FGFS
+# include <math.h>
+# include <simgear/compiler.h>
+# include STL_STRING
+# include STL_FSTREAM
+# include STL_IOSTREAM
+ SG_USING_STD(string);
+ SG_USING_STD(ostream);
+ SG_USING_STD(istream);
+ SG_USING_STD(cerr);
+ SG_USING_STD(cout);
+ SG_USING_STD(endl);
+#else
+# include <string>
+# if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
+ include <fstream.h>
+ include <iostream.h>
+# include <math.h>
+# else
+# include <fstream>
+# include <iostream>
+# if defined(sgi) && !defined(__GNUC__)
+# include <math.h>
+# else
+# include <cmath>
+# endif
+ using std::ostream;
+ using std::istream;
+ using std::cerr;
+ using std::cout;
+ using std::endl;
+# endif
+ using std::string;
+#endif
+
+#include "FGColumnVector3.h"
+#include "FGJSBBase.h"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_MATRIX33 "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+class FGColumnVector3;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Exception convenience class.
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DECLARATION: MatrixException
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class MatrixException : public FGJSBBase
+{
+public:
+ string Message;
+};
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+ /** Handles matrix math operations.
+ @author Tony Peden, Jon Berndt, Mathias Froelich
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DECLARATION: FGMatrix33
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGMatrix33 : public FGJSBBase
+{
+public:
+
+ enum {
+ eRows = 3,
+ eColumns = 3
+ };
+
+ /** Default initializer.
+
+ Create a zero matrix.
+ */
+ FGMatrix33(void);
+
+ /** Copy constructor.
+
+ @param M Matrix which is used for initialization.
+
+ Create copy of the matrix given in the argument.
+ */
+ FGMatrix33(const FGMatrix33& M) {
+ Entry(1,1) = M.Entry(1,1);
+ Entry(2,1) = M.Entry(2,1);
+ Entry(3,1) = M.Entry(3,1);
+ Entry(1,2) = M.Entry(1,2);
+ Entry(2,2) = M.Entry(2,2);
+ Entry(3,2) = M.Entry(3,2);
+ Entry(1,3) = M.Entry(1,3);
+ Entry(2,3) = M.Entry(2,3);
+ Entry(3,3) = M.Entry(3,3);
+
+ Debug(0);
+ }
+
+ /** Initialization by given values.
+
+ @param m11 value of the 1,1 Matrix element.
+ @param m12 value of the 1,2 Matrix element.
+ @param m13 value of the 1,3 Matrix element.
+ @param m21 value of the 2,1 Matrix element.
+ @param m22 value of the 2,2 Matrix element.
+ @param m23 value of the 2,3 Matrix element.
+ @param m31 value of the 3,1 Matrix element.
+ @param m32 value of the 3,2 Matrix element.
+ @param m33 value of the 3,3 Matrix element.
+
+ Create a matrix from the doubles given in the arguments.
+ */
+ FGMatrix33(double m11, double m12, double m13,
+ double m21, double m22, double m23,
+ double m31, double m32, double m33) {
+ Entry(1,1) = m11;
+ Entry(2,1) = m21;
+ Entry(3,1) = m31;
+ Entry(1,2) = m12;
+ Entry(2,2) = m22;
+ Entry(3,2) = m32;
+ Entry(1,3) = m13;
+ Entry(2,3) = m23;
+ Entry(3,3) = m33;
+
+ Debug(0);
+ }
+
+ /** Destructor.
+ */
+ ~FGMatrix33(void) { Debug(1); }
+
+ /** Read access the entries of the matrix.
+ @param row Row index.
+ @param col Column index.
+
+ @return the value of the matrix entry at the given row and
+ column indices. Indices are counted starting with 1.
+ */
+ double operator()(unsigned int row, unsigned int col) const {
+ return Entry(row, col);
+ }
+
+ /** Write access the entries of the matrix.
+ Note that the indices given in the arguments are unchecked.
+
+ @param row Row index.
+ @param col Column index.
+
+ @return a reference to the matrix entry at the given row and
+ column indices. Indices are counted starting with 1.
+ */
+ double& operator()(unsigned int row, unsigned int col) {
+ return Entry(row, col);
+ }
+
+ /** Read access the entries of the matrix.
+ This function is just a shortcut for the @ref double&
+ operator()(unsigned int row, unsigned int col) function. It is
+ used internally to access the elements in a more convenient way.
+
+ Note that the indices given in the arguments are unchecked.
+
+ @param row Row index.
+ @param col Column index.
+
+ @return the value of the matrix entry at the given row and
+ column indices. Indices are counted starting with 1.
+ */
+ double Entry(unsigned int row, unsigned int col) const {
+ return data[(col-1)*eRows+row-1];
+ }
+
+ /** Write access the entries of the matrix.
+ This function is just a shortcut for the @ref double&
+ operator()(unsigned int row, unsigned int col) function. It is
+ used internally to access the elements in a more convenient way.
+
+ Note that the indices given in the arguments are unchecked.
+
+ @param row Row index.
+ @param col Column index.
+
+ @return a reference to the matrix entry at the given row and
+ column indices. Indices are counted starting with 1.
+ */
+ double& Entry(unsigned int row, unsigned int col) {
+ return data[(col-1)*eRows+row-1];
+ }
+
+ /** Number of rows in the matrix.
+ @return the number of rows in the matrix.
+ */
+ unsigned int Rows(void) const { return eRows; }
+
+ /** Number of cloumns in the matrix.
+ @return the number of columns in the matrix.
+ */
+ unsigned int Cols(void) const { return eColumns; }
+
+ /** Transposed matrix.
+ This function only returns the transpose of this matrix. This matrix itself
+ remains unchanged.
+ @return the transposed matrix.
+ */
+ FGMatrix33 Transposed(void) const {
+ return FGMatrix33( Entry(1,1), Entry(2,1), Entry(3,1),
+ Entry(1,2), Entry(2,2), Entry(3,2),
+ Entry(1,3), Entry(2,3), Entry(3,3) );
+ }
+
+ /** Transposes this matrix.
+ This function only transposes this matrix. Nothing is returned.
+ */
+ void T(void);
+
+/** Initialize the matrix.
+ This function initializes a matrix to all 0.0.
+ */
+ void InitMatrix(void);
+
+/** Initialize the matrix.
+ This function initializes a matrix to user specified values.
+ */
+ void InitMatrix(double m11, double m12, double m13,
+ double m21, double m22, double m23,
+ double m31, double m32, double m33) {
+ Entry(1,1) = m11;
+ Entry(2,1) = m21;
+ Entry(3,1) = m31;
+ Entry(1,2) = m12;
+ Entry(2,2) = m22;
+ Entry(3,2) = m32;
+ Entry(1,3) = m13;
+ Entry(2,3) = m23;
+ Entry(3,3) = m33;
+ }
+
+ /** Determinant of the matrix.
+ @return the determinant of the matrix.
+ */
+ double Determinant(void) const;
+
+ /** Return if the matrix is invertible.
+ Checks and returns if the matrix is nonsingular and thus
+ invertible. This is done by simply computing the determinant and
+ check if it is zero. Note that this test does not cover any
+ instabilities caused by nearly singular matirces using finite
+ arithmetics. It only checks exact singularity.
+ */
+ bool Invertible(void) const { return 0.0 != Determinant(); }
+
+ /** Return the inverse of the matrix.
+ Computes and returns if the inverse of the matrix. It is computed
+ by Cramers Rule. Also there are no checks performed if the matrix
+ is invertible. If you are not sure that it really is check this
+ with the @ref Invertible() call before.
+ */
+ FGMatrix33 Inverse(void) const;
+
+ /** Assignment operator.
+
+ @param A source matrix.
+
+ Copy the content of the matrix given in the argument into *this.
+ */
+ FGMatrix33& operator=(const FGMatrix33& A) {
+ data[0] = A.data[0];
+ data[1] = A.data[1];
+ data[2] = A.data[2];
+ data[3] = A.data[3];
+ data[4] = A.data[4];
+ data[5] = A.data[5];
+ data[6] = A.data[6];
+ data[7] = A.data[7];
+ data[8] = A.data[8];
+ return *this;
+ }
+
+ /** Matrix vector multiplication.
+
+ @param v vector to multiply with.
+ @return matric vector product.
+
+ Compute and return the product of the current matrix with the
+ vector given in the argument.
+ */
+ FGColumnVector3 operator*(const FGColumnVector3& v) const;
+
+ /** Matrix subtraction.
+
+ @param B matrix to add to.
+ @return difference of the matrices.
+
+ Compute and return the sum of the current matrix and the matrix
+ B given in the argument.
+ */
+ FGMatrix33 operator-(const FGMatrix33& B) const;
+
+ /** Matrix addition.
+
+ @param B matrix to add to.
+ @return sum of the matrices.
+
+ Compute and return the sum of the current matrix and the matrix
+ B given in the argument.
+ */
+ FGMatrix33 operator+(const FGMatrix33& B) const;
+
+ /** Matrix product.
+
+ @param B matrix to add to.
+ @return product of the matrices.
+
+ Compute and return the product of the current matrix and the matrix
+ B given in the argument.
+ */
+ FGMatrix33 operator*(const FGMatrix33& B) const;
+
+ /** Multiply the matrix with a scalar.
+
+ @param scalar scalar factor to multiply with.
+ @return scaled matrix.
+
+ Compute and return the product of the current matrix with the
+ scalar value scalar given in the argument.
+ */
+ FGMatrix33 operator*(const double scalar) const;
+
+ /** Multiply the matrix with 1.0/scalar.
+
+ @param scalar scalar factor to divide through.
+ @return scaled matrix.
+
+ Compute and return the product of the current matrix with the
+ scalar value 1.0/scalar, where scalar is given in the argument.
+ */
+ FGMatrix33 operator/(const double scalar) const;
+
+ /** In place matrix subtraction.
+
+ @param B matrix to subtract.
+ @return reference to the current matrix.
+
+ Compute the diffence from the current matrix and the matrix B
+ given in the argument.
+ */
+ FGMatrix33& operator-=(const FGMatrix33 &B);
+
+ /** In place matrix addition.
+
+ @param B matrix to add.
+ @return reference to the current matrix.
+
+ Compute the sum of the current matrix and the matrix B
+ given in the argument.
+ */
+ FGMatrix33& operator+=(const FGMatrix33 &B);
+
+ /** In place matrix multiplication.
+
+ @param B matrix to multiply with.
+ @return reference to the current matrix.
+
+ Compute the product of the current matrix and the matrix B
+ given in the argument.
+ */
+ FGMatrix33& operator*=(const FGMatrix33 &B);
+
+ /** In place matrix scale.
+
+ @param scalar scalar value to multiply with.
+ @return reference to the current matrix.
+
+ Compute the product of the current matrix and the scalar value scalar
+ given in the argument.
+ */
+ FGMatrix33& operator*=(const double scalar);
+
+ /** In place matrix scale.
+
+ @param scalar scalar value to divide through.
+ @return reference to the current matrix.
+
+ Compute the product of the current matrix and the scalar value
+ 1.0/scalar, where scalar is given in the argument.
+ */
+ FGMatrix33& operator/=(const double scalar);
+
+private:
+ double data[eRows*eColumns];
+
+ void Debug(int from);
+};
+
+/** Scalar multiplication.
+
+ @param scalar scalar value to multiply with.
+ @param A Matrix to multiply.
+
+ Multiply the Matrix with a scalar value.
+*/
+inline FGMatrix33 operator*(double scalar, const FGMatrix33& A) {
+ // use already defined operation.
+ return A*scalar;
+}
+
+/** Write matrix to a stream.
+
+ @param os Stream to write to.
+ @param M Matrix to write.
+
+ Write the matrix to a stream.
+*/
+ostream& operator<<(ostream& os, const FGMatrix33& M);
+
+/** Read matrix from a stream.
+
+ @param os Stream to read from.
+ @param M Matrix to initialize with the values from the stream.
+
+ Read matrix from a stream.
+*/
+istream& operator>>(istream& is, FGMatrix33& M);
+
+} // namespace JSBSim
+
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Header: FGParameter.h
+Author: Jon Berndt
+Date started: August 25 2004
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGPARAMETER_H
+#define FGPARAMETER_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGJSBBase.h"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_PARAMETER "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+ /** Represents various types of parameters.
+ @author Jon Berndt
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DECLARATION: FGParameter
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGParameter : public FGJSBBase
+{
+public:
+
+ virtual double GetValue(void) const = 0;
+
+protected:
+};
+
+} // namespace JSBSim
+
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Module: FGPropertyValue.cpp
+Author: Jon Berndt
+Date started: 12/10/2004
+Purpose: Stores property values
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGPropertyValue.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_PROPERTYVALUE;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGPropertyValue::FGPropertyValue(FGPropertyManager* propNode) : PropertyManager(propNode)
+{
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGPropertyValue::GetValue(void) const
+{
+ return PropertyManager->getDoubleValue();
+}
+
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Header: FGPropertyValue.h
+Author: Jon Berndt
+Date started: December 10 2004
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGPROPERTYVALUE_H
+#define FGPROPERTYVALUE_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGParameter.h"
+#include <input_output/FGPropertyManager.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_PROPERTYVALUE "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+ /** Represents a property value
+ @author Jon Berndt
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DECLARATION: FGPropertyValue
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGPropertyValue : public FGParameter
+{
+public:
+
+ FGPropertyValue(FGPropertyManager* propNode);
+ ~FGPropertyValue() {};
+
+ double GetValue(void) const;
+
+private:
+ FGPropertyManager* PropertyManager;
+};
+
+} // namespace JSBSim
+
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGQuaternion.cpp
+ Author: Jon Berndt, Mathias Froehlich
+ Date started: 12/02/98
+
+ ------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------------
+ ------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+-------------------------------------------------------------------------------
+12/02/98 JSB Created
+15/01/04 Mathias Froehlich implemented a quaternion class from many places
+ in JSBSim.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ INCLUDES
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <math.h>
+# include <simgear/compiler.h>
+# include STL_IOSTREAM
+ SG_USING_STD(cerr);
+ SG_USING_STD(cout);
+ SG_USING_STD(endl);
+#else
+# include <string>
+# if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
+# include <iostream.h>
+# include <math.h>
+# else
+# include <iostream>
+# if defined(sgi) && !defined(__GNUC__)
+# include <math.h>
+# else
+# include <cmath>
+# endif
+ using std::cerr;
+ using std::cout;
+ using std::endl;
+# endif
+#endif
+
+#include "FGMatrix33.h"
+#include "FGColumnVector3.h"
+
+#include "FGQuaternion.h"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ DEFINITIONS
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_QUATERNION;
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+// Initialize from q
+FGQuaternion::FGQuaternion(const FGQuaternion& q)
+ : mCacheValid(q.mCacheValid) {
+ Entry(1) = q(1);
+ Entry(2) = q(2);
+ Entry(3) = q(3);
+ Entry(4) = q(4);
+ if (mCacheValid) {
+ mT = q.mT;
+ mTInv = q.mTInv;
+ mEulerAngles = q.mEulerAngles;
+ mEulerSines = q.mEulerSines;
+ mEulerCosines = q.mEulerCosines;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+// Initialize with the three euler angles
+FGQuaternion::FGQuaternion(double phi, double tht, double psi)
+ : mCacheValid(false) {
+ double thtd2 = 0.5*tht;
+ double psid2 = 0.5*psi;
+ double phid2 = 0.5*phi;
+
+ double Sthtd2 = sin(thtd2);
+ double Spsid2 = sin(psid2);
+ double Sphid2 = sin(phid2);
+
+ double Cthtd2 = cos(thtd2);
+ double Cpsid2 = cos(psid2);
+ double Cphid2 = cos(phid2);
+
+ double Cphid2Cthtd2 = Cphid2*Cthtd2;
+ double Cphid2Sthtd2 = Cphid2*Sthtd2;
+ double Sphid2Sthtd2 = Sphid2*Sthtd2;
+ double Sphid2Cthtd2 = Sphid2*Cthtd2;
+
+ Entry(1) = Cphid2Cthtd2*Cpsid2 + Sphid2Sthtd2*Spsid2;
+ Entry(2) = Sphid2Cthtd2*Cpsid2 - Cphid2Sthtd2*Spsid2;
+ Entry(3) = Cphid2Sthtd2*Cpsid2 + Sphid2Cthtd2*Spsid2;
+ Entry(4) = Cphid2Cthtd2*Spsid2 - Sphid2Sthtd2*Cpsid2;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/**
+ Returns the derivative of the quaternion coresponding to the
+ angular velocities PQR.
+*/
+FGQuaternion FGQuaternion::GetQDot(const FGColumnVector3& PQR) const {
+ double norm = Magnitude();
+ if (norm == 0.0)
+ return FGQuaternion::zero();
+ double rnorm = 1.0/norm;
+
+ FGQuaternion QDot;
+ QDot(1) = -0.5*(Entry(2)*PQR(eP) + Entry(3)*PQR(eQ) + Entry(4)*PQR(eR));
+ QDot(2) = 0.5*(Entry(1)*PQR(eP) + Entry(3)*PQR(eR) - Entry(4)*PQR(eQ));
+ QDot(3) = 0.5*(Entry(1)*PQR(eQ) + Entry(4)*PQR(eP) - Entry(2)*PQR(eR));
+ QDot(4) = 0.5*(Entry(1)*PQR(eR) + Entry(2)*PQR(eQ) - Entry(3)*PQR(eP));
+ return rnorm*QDot;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGQuaternion::Normalize()
+{
+ // Note: this does not touch the cache
+ // since it does not change the orientation ...
+
+ double norm = Magnitude();
+ if (norm == 0.0)
+ return;
+
+ double rnorm = 1.0/norm;
+ Entry(1) *= rnorm;
+ Entry(2) *= rnorm;
+ Entry(3) *= rnorm;
+ Entry(4) *= rnorm;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+// Compute the derived values if required ...
+void FGQuaternion::ComputeDerivedUnconditional(void) const
+{
+ mCacheValid = true;
+
+ // First normalize the 4-vector
+ double norm = Magnitude();
+ if (norm == 0.0)
+ return;
+
+ double rnorm = 1.0/norm;
+ double q1 = rnorm*Entry(1);
+ double q2 = rnorm*Entry(2);
+ double q3 = rnorm*Entry(3);
+ double q4 = rnorm*Entry(4);
+
+ // Now compute the transformation matrix.
+ double q1q1 = q1*q1;
+ double q2q2 = q2*q2;
+ double q3q3 = q3*q3;
+ double q4q4 = q4*q4;
+ double q1q2 = q1*q2;
+ double q1q3 = q1*q3;
+ double q1q4 = q1*q4;
+ double q2q3 = q2*q3;
+ double q2q4 = q2*q4;
+ double q3q4 = q3*q4;
+
+ mT(1,1) = q1q1 + q2q2 - q3q3 - q4q4;
+ mT(1,2) = 2.0*(q2q3 + q1q4);
+ mT(1,3) = 2.0*(q2q4 - q1q3);
+ mT(2,1) = 2.0*(q2q3 - q1q4);
+ mT(2,2) = q1q1 - q2q2 + q3q3 - q4q4;
+ mT(2,3) = 2.0*(q3q4 + q1q2);
+ mT(3,1) = 2.0*(q2q4 + q1q3);
+ mT(3,2) = 2.0*(q3q4 - q1q2);
+ mT(3,3) = q1q1 - q2q2 - q3q3 + q4q4;
+ // Since this is an orthogonal matrix, the inverse is simply
+ // the transpose.
+ mTInv = mT;
+ mTInv.T();
+
+ // Compute the Euler-angles
+ if (mT(3,3) == 0.0)
+ mEulerAngles(ePhi) = 0.5*M_PI;
+ else
+ mEulerAngles(ePhi) = atan2(mT(2,3), mT(3,3));
+
+ if (mT(1,3) < -1.0)
+ mEulerAngles(eTht) = 0.5*M_PI;
+ else if (1.0 < mT(1,3))
+ mEulerAngles(eTht) = -0.5*M_PI;
+ else
+ mEulerAngles(eTht) = asin(-mT(1,3));
+
+ if (mT(1,1) == 0.0)
+ mEulerAngles(ePsi) = 0.5*M_PI;
+ else {
+ double psi = atan2(mT(1,2), mT(1,1));
+ if (psi < 0.0)
+ psi += 2*M_PI;
+ mEulerAngles(ePsi) = psi;
+ }
+
+ // FIXME: may be one can compute those values easier ???
+ mEulerSines(ePhi) = sin(mEulerAngles(ePhi));
+ // mEulerSines(eTht) = sin(mEulerAngles(eTht));
+ mEulerSines(eTht) = -mT(1,3);
+ mEulerSines(ePsi) = sin(mEulerAngles(ePsi));
+ mEulerCosines(ePhi) = cos(mEulerAngles(ePhi));
+ mEulerCosines(eTht) = cos(mEulerAngles(eTht));
+ mEulerCosines(ePsi) = cos(mEulerAngles(ePsi));
+}
+
+} // namespace JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGQuaternion.h
+ Author: Jon Berndt, Mathis Froehlich
+ Date started: 12/02/98
+
+ ------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------------
+ ------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+-------------------------------------------------------------------------------
+12/02/98 JSB Created
+15/01/04 MF Quaternion class from old FGColumnVector4
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGQUATERNION_H
+#define FGQUATERNION_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ INCLUDES
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <FGJSBBase.h>
+#include "FGMatrix33.h"
+#include "FGColumnVector3.h"
+#include <input_output/FGPropertyManager.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ DEFINITIONS
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_QUATERNION "$Id$"
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ CLASS DOCUMENTATION
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models the Quaternion representation of rotations.
+ FGQuaternion is a representation of an arbitrary rotation through a
+ quaternion. It has vector properties. This class also contains access
+ functions to the euler angle representation of rotations and access to
+ transformation matrices for 3D vectors. Transformations and euler angles are
+ therefore computed once they are requested for the first time. Then they are
+ cached for later usage as long as the class is not accessed trough
+ a nonconst member function.
+
+ Note: The order of rotations used in this class corresponds to a 3-2-1 sequence,
+ or Y-P-R, or Z-Y-X, if you prefer.
+
+ @see Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
+ Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
+ School, January 1994
+ @see D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
+ JSC 12960, July 1977
+ @see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
+ NASA-Ames", NASA CR-2497, January 1975
+ @see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
+ Wiley & Sons, 1979 ISBN 0-471-03032-5
+ @see Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
+ 1982 ISBN 0-471-08936-2
+ @author Mathias Froehlich, extended FGColumnVector4 originally by Tony Peden
+ and Jon Berndt
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ CLASS DECLARATION
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGQuaternion
+ : virtual FGJSBBase {
+public:
+ /** Default initializer.
+ Default initializer, initializes the class with the identity rotation. */
+ FGQuaternion() : mCacheValid(false) {
+ Entry(1) = 1.0;
+ Entry(2) = Entry(3) = Entry(4) = 0.0;
+ }
+
+ /** Copy constructor.
+ Copy constructor, initializes the quaternion.
+ @param q a constant reference to another FGQuaternion instance */
+ FGQuaternion(const FGQuaternion& q);
+
+ /** Initializer by euler angles.
+ Initialize the quaternion with the euler angles.
+ @param phi The euler X axis (roll) angle in radians
+ @param tht The euler Y axis (attitude) angle in radians
+ @param psi The euler Z axis (heading) angle in radians */
+ FGQuaternion(double phi, double tht, double psi);
+
+ /** Initializer by one euler angle.
+ Initialize the quaternion with the single euler angle where its index
+ is given in the first argument.
+ @param idx Index of the euler angle to initialize
+ @param angle The euler angle in radians */
+ FGQuaternion(int idx, double angle)
+ : mCacheValid(false) {
+ double angle2 = 0.5*angle;
+
+ double Sangle2 = sin(angle2);
+ double Cangle2 = cos(angle2);
+
+ if (idx == ePhi) {
+ Entry(1) = Cangle2;
+ Entry(2) = Sangle2;
+ Entry(3) = 0.0;
+ Entry(4) = 0.0;
+
+ } else if (idx == eTht) {
+ Entry(1) = Cangle2;
+ Entry(2) = 0.0;
+ Entry(3) = Sangle2;
+ Entry(4) = 0.0;
+
+ } else {
+ Entry(1) = Cangle2;
+ Entry(2) = 0.0;
+ Entry(3) = 0.0;
+ Entry(4) = Sangle2;
+
+ }
+ }
+
+ /// Destructor.
+ ~FGQuaternion() {}
+
+ /** Quaternion 'velocity' for given angular rates.
+ Computes the quaternion derivative which results from the given
+ angular velocities
+ @param PQR a constant reference to the body rate vector
+ @return the quaternion derivative */
+ FGQuaternion GetQDot(const FGColumnVector3& PQR) const;
+
+ /** Transformation matrix.
+ @return a reference to the transformation/rotation matrix
+ corresponding to this quaternion rotation. */
+ const FGMatrix33& GetT(void) const { ComputeDerived(); return mT; }
+
+ /** Backward transformation matrix.
+ @return a reference to the inverse transformation/rotation matrix
+ corresponding to this quaternion rotation. */
+ const FGMatrix33& GetTInv(void) const { ComputeDerived(); return mTInv; }
+
+ /** Retrieves the Euler angles.
+ @return a reference to the triad of euler angles corresponding
+ to this quaternion rotation.
+ @units radians */
+ const FGColumnVector3& GetEuler(void) const {
+ ComputeDerived();
+ return mEulerAngles;
+ }
+
+ /** Retrieves the Euler angles.
+ @param i the euler angle index.
+ @return a reference to the i-th euler angles corresponding
+ to this quaternion rotation.
+ @units radians */
+ double GetEuler(int i) const {
+ ComputeDerived();
+ return mEulerAngles(i);
+ }
+
+ /** Retrieves the Euler angles.
+ @param i the euler angle index.
+ @return a reference to the i-th euler angles corresponding
+ to this quaternion rotation.
+ @units degrees */
+ double GetEulerDeg(int i) const {
+ ComputeDerived();
+ return radtodeg*mEulerAngles(i);
+ }
+
+ /** Retrieves sine of the given euler angle.
+ @return the sine of the Euler angle theta (pitch attitude) corresponding
+ to this quaternion rotation. */
+ double GetSinEuler(int i) const {
+ ComputeDerived();
+ return mEulerSines(i);
+ }
+
+ /** Retrieves cosine of the given euler angle.
+ @return the sine of the Euler angle theta (pitch attitude) corresponding
+ to this quaternion rotation. */
+ double GetCosEuler(int i) const {
+ ComputeDerived();
+ return mEulerCosines(i);
+ }
+
+ /** Read access the entries of the vector.
+
+ @param idx the component index.
+
+ Return the value of the matrix entry at the given index.
+ Indices are counted starting with 1.
+
+ Note that the index given in the argument is unchecked.
+ */
+ double operator()(unsigned int idx) const { return Entry(idx); }
+
+ /** Write access the entries of the vector.
+
+ @param idx the component index.
+
+ Return a reference to the vector entry at the given index.
+ Indices are counted starting with 1.
+
+ Note that the index given in the argument is unchecked.
+ */
+ double& operator()(unsigned int idx) { return Entry(idx); }
+
+ /** Read access the entries of the vector.
+
+ @param idx the component index.
+
+ Return the value of the matrix entry at the given index.
+ Indices are counted starting with 1.
+
+ This function is just a shortcut for the @ref double
+ operator()(unsigned int idx) const function. It is
+ used internally to access the elements in a more convenient way.
+
+ Note that the index given in the argument is unchecked.
+ */
+ double Entry(unsigned int idx) const { return mData[idx-1]; }
+
+ /** Write access the entries of the vector.
+
+ @param idx the component index.
+
+ Return a reference to the vector entry at the given index.
+ Indices are counted starting with 1.
+
+ This function is just a shortcut for the @ref double&
+ operator()(unsigned int idx) function. It is
+ used internally to access the elements in a more convenient way.
+
+ Note that the index given in the argument is unchecked.
+ */
+ double& Entry(unsigned int idx) { mCacheValid = false; return mData[idx-1]; }
+
+ /** Assignment operator "=".
+ Assign the value of q to the current object. Cached values are
+ conserved.
+ @param q reference to an FGQuaternion instance
+ @return reference to a quaternion object */
+ const FGQuaternion& operator=(const FGQuaternion& q) {
+ // Copy the master values ...
+ Entry(1) = q(1);
+ Entry(2) = q(2);
+ Entry(3) = q(3);
+ Entry(4) = q(4);
+ // .. and copy the derived values if they are valid
+ mCacheValid = q.mCacheValid;
+ if (mCacheValid) {
+ mT = q.mT;
+ mTInv = q.mTInv;
+ mEulerAngles = q.mEulerAngles;
+ mEulerSines = q.mEulerSines;
+ mEulerCosines = q.mEulerCosines;
+ }
+ return *this;
+ }
+
+ /** Comparison operator "==".
+ @param q a quaternion reference
+ @return true if both quaternions represent the same rotation. */
+ bool operator==(const FGQuaternion& q) const {
+ return Entry(1) == q(1) && Entry(2) == q(2)
+ && Entry(3) == q(3) && Entry(4) == q(4);
+ }
+
+ /** Comparison operator "!=".
+ @param q a quaternion reference
+ @return true if both quaternions do not represent the same rotation. */
+ bool operator!=(const FGQuaternion& q) const { return ! operator==(q); }
+ const FGQuaternion& operator+=(const FGQuaternion& q) {
+ // Copy the master values ...
+ Entry(1) += q(1);
+ Entry(2) += q(2);
+ Entry(3) += q(3);
+ Entry(4) += q(4);
+ mCacheValid = false;
+ return *this;
+ }
+
+ /** Arithmetic operator "-=".
+ @param q a quaternion reference.
+ @return a quaternion reference representing Q, where Q = Q - q. */
+ const FGQuaternion& operator-=(const FGQuaternion& q) {
+ // Copy the master values ...
+ Entry(1) -= q(1);
+ Entry(2) -= q(2);
+ Entry(3) -= q(3);
+ Entry(4) -= q(4);
+ mCacheValid = false;
+ return *this;
+ }
+
+ /** Arithmetic operator "*=".
+ @param scalar a multiplicative value.
+ @return a quaternion reference representing Q, where Q = Q * scalar. */
+ const FGQuaternion& operator*=(double scalar) {
+ Entry(1) *= scalar;
+ Entry(2) *= scalar;
+ Entry(3) *= scalar;
+ Entry(4) *= scalar;
+ mCacheValid = false;
+ return *this;
+ }
+
+ /** Arithmetic operator "/=".
+ @param scalar a divisor value.
+ @return a quaternion reference representing Q, where Q = Q / scalar. */
+ const FGQuaternion& operator/=(double scalar) {
+ return operator*=(1.0/scalar);
+ }
+
+ /** Arithmetic operator "+".
+ @param q a quaternion to be summed.
+ @return a quaternion representing Q, where Q = Q + q. */
+ FGQuaternion operator+(const FGQuaternion& q) const {
+ return FGQuaternion(Entry(1)+q(1), Entry(2)+q(2),
+ Entry(3)+q(3), Entry(4)+q(4));
+ }
+
+ /** Arithmetic operator "-".
+ @param q a quaternion to be subtracted.
+ @return a quaternion representing Q, where Q = Q - q. */
+ FGQuaternion operator-(const FGQuaternion& q) const {
+ return FGQuaternion(Entry(1)-q(1), Entry(2)-q(2),
+ Entry(3)-q(3), Entry(4)-q(4));
+ }
+
+ /** Arithmetic operator "*".
+ Multiplication of two quaternions is like performing successive rotations.
+ @param q a quaternion to be multiplied.
+ @return a quaternion representing Q, where Q = Q * q. */
+ FGQuaternion operator*(const FGQuaternion& q) const {
+ return FGQuaternion(Entry(1)*q(1)-Entry(2)*q(2)-Entry(3)*q(3)-Entry(4)*q(4),
+ Entry(1)*q(2)+Entry(2)*q(1)+Entry(3)*q(4)-Entry(4)*q(3),
+ Entry(1)*q(3)-Entry(2)*q(4)+Entry(3)*q(1)+Entry(4)*q(2),
+ Entry(1)*q(4)+Entry(2)*q(3)-Entry(3)*q(2)+Entry(4)*q(1));
+ }
+
+ /** Arithmetic operator "*=".
+ Multiplication of two quaternions is like performing successive rotations.
+ @param q a quaternion to be multiplied.
+ @return a quaternion reference representing Q, where Q = Q * q. */
+ const FGQuaternion& operator*=(const FGQuaternion& q) {
+ double q0 = Entry(1)*q(1)-Entry(2)*q(2)-Entry(3)*q(3)-Entry(4)*q(4);
+ double q1 = Entry(1)*q(2)+Entry(2)*q(1)+Entry(3)*q(4)-Entry(4)*q(3);
+ double q2 = Entry(1)*q(3)-Entry(2)*q(4)+Entry(3)*q(1)+Entry(4)*q(2);
+ double q3 = Entry(1)*q(4)+Entry(2)*q(3)-Entry(3)*q(2)+Entry(4)*q(1);
+ Entry(1) = q0;
+ Entry(2) = q1;
+ Entry(3) = q2;
+ Entry(4) = q3;
+ mCacheValid = false;
+ return *this;
+ }
+
+ /** Inverse of the quaternion.
+
+ Compute and return the inverse of the quaternion so that the orientation
+ represented with *this multiplied with the returned value is equal to
+ the identity orientation.
+ */
+ FGQuaternion Inverse(void) const {
+ double norm = Magnitude();
+ if (norm == 0.0)
+ return *this;
+ double rNorm = 1.0/norm;
+ return FGQuaternion( Entry(1)*rNorm, -Entry(2)*rNorm,
+ -Entry(3)*rNorm, -Entry(4)*rNorm );
+ }
+
+ /** Conjugate of the quaternion.
+
+ Compute and return the conjugate of the quaternion. This one is equal
+ to the inverse iff the quaternion is normalized.
+ */
+ FGQuaternion Conjugate(void) const {
+ return FGQuaternion( Entry(1), -Entry(2), -Entry(3), -Entry(4) );
+ }
+
+ friend FGQuaternion operator*(double, const FGQuaternion&);
+
+ /** Length of the vector.
+
+ Compute and return the euclidean norm of this vector.
+ */
+ double Magnitude(void) const { return sqrt(SqrMagnitude()); }
+
+ /** Square of the length of the vector.
+
+ Compute and return the square of the euclidean norm of this vector.
+ */
+ double SqrMagnitude(void) const {
+ return Entry(1)*Entry(1)+Entry(2)*Entry(2)
+ +Entry(3)*Entry(3)+Entry(4)*Entry(4);
+ }
+
+ /** Normialze.
+
+ Normalize the vector to have the Magnitude() == 1.0. If the vector
+ is equal to zero it is left untouched.
+ */
+ void Normalize(void);
+
+ /** Zero quaternion vector. Does not represent any orientation.
+ Useful for initialization of increments */
+ static FGQuaternion zero(void) { return FGQuaternion( 0.0, 0.0, 0.0, 0.0 ); }
+
+private:
+ /** Copying by assigning the vector valued components. */
+ FGQuaternion(double q1, double q2, double q3, double q4) : mCacheValid(false)
+ { Entry(1) = q1; Entry(2) = q2; Entry(3) = q3; Entry(4) = q4; }
+
+ /** Computation of derived values.
+ This function recomputes the derived values like euler angles and
+ transformation matrices. It does this unconditionally. */
+ void ComputeDerivedUnconditional(void) const;
+
+ /** Computation of derived values.
+ This function checks if the derived values like euler angles and
+ transformation matrices are already computed. If so, it
+ returns. If they need to be computed the real worker routine
+ \ref FGQuaternion::ComputeDerivedUnconditional(void) const
+ is called.
+ This function is inlined to avoid function calls in the fast path. */
+ void ComputeDerived(void) const {
+ if (!mCacheValid)
+ ComputeDerivedUnconditional();
+ }
+
+ /** The quaternion values itself. This is the master copy. */
+ double mData[4];
+
+ /** A data validity flag.
+ This class implements caching of the derived values like the
+ orthogonal rotation matrices or the Euler angles. For caching we
+ carry a flag which signals if the values are valid or not.
+ The C++ keyword "mutable" tells the compiler that the data member is
+ allowed to change during a const member function. */
+ mutable bool mCacheValid;
+
+ /** This stores the transformation matrices. */
+ mutable FGMatrix33 mT;
+ mutable FGMatrix33 mTInv;
+
+ /** The cached euler angles. */
+ mutable FGColumnVector3 mEulerAngles;
+
+ /** The cached sines and cosines of the euler angles. */
+ mutable FGColumnVector3 mEulerSines;
+ mutable FGColumnVector3 mEulerCosines;
+};
+
+/** Scalar multiplication.
+
+ @param scalar scalar value to multiply with.
+ @param p Vector to multiply.
+
+ Multiply the Vector with a scalar value.
+*/
+inline FGQuaternion operator*(double scalar, const FGQuaternion& q) {
+ return FGQuaternion(scalar*q(1), scalar*q(2), scalar*q(3), scalar*q(4));
+}
+
+} // namespace JSBSim
+
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Module: FGRealValue.cpp
+Author: Jon Berndt
+Date started: 12/10/2004
+Purpose: Stores real values
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGRealValue.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_REALVALUE;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGRealValue::FGRealValue(double value) : Value(value)
+{
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGRealValue::GetValue(void) const
+{
+ return Value;
+}
+
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Header: FGRealValue.h
+Author: Jon Berndt
+Date started: December 10 2004
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGREALVALUE_H
+#define FGREALVALUE_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGParameter.h"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_REALVALUE "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+ /** Represents a real value
+ @author Jon Berndt
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DECLARATION: FGRealValue
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGRealValue : public FGParameter
+{
+public:
+
+ FGRealValue(double val);
+ ~FGRealValue() {};
+
+ double GetValue(void) const;
+
+private:
+ double Value;
+};
+
+} // namespace JSBSim
+
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGTable.cpp
+ Author: Jon S. Berndt
+ Date started: 1/9/2001
+ Purpose: Models a lookup table
+
+ ------------- Copyright (C) 2001 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+Models a lookup table
+
+HISTORY
+--------------------------------------------------------------------------------
+JSB 1/9/00 Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGTable.h"
+
+#if defined ( sgi ) && !defined( __GNUC__ ) && (_COMPILER_VERSION < 740)
+# include <iomanip.h>
+#else
+# include <iomanip>
+#endif
+
+using namespace std;
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_TABLE;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGTable::FGTable(int NRows) : nRows(NRows), nCols(1), PropertyManager(0)
+{
+ Type = tt1D;
+ colCounter = 0;
+ rowCounter = 1;
+ nTables = 0;
+
+ Data = Allocate();
+ Debug(0);
+ lastRowIndex=lastColumnIndex=2;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGTable::FGTable(const FGTable& t) : PropertyManager(t.PropertyManager)
+{
+ Type = t.Type;
+ colCounter = t.colCounter;
+ rowCounter = t.rowCounter;
+ tableCounter = t.tableCounter;
+ nRows = t.nRows;
+ nCols = t.nCols;
+ nTables = t.nTables;
+ dimension = t.dimension;
+ internal = t.internal;
+
+ Tables = t.Tables;
+ Data = Allocate();
+ for (int r=0; r<=nRows; r++) {
+ for (int c=0; c<=nCols; c++) {
+ Data[r][c] = t.Data[r][c];
+ }
+ }
+ lastRowIndex = t.lastRowIndex;
+ lastColumnIndex = t.lastColumnIndex;
+ lastTableIndex = t.lastTableIndex;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGTable::FGTable(FGPropertyManager* propMan, Element* el) : PropertyManager(propMan)
+{
+ int i;
+
+ stringstream buf;
+ string property_string;
+ string lookup_axis;
+ string call_type;
+ string parent_type;
+ FGPropertyManager* node;
+ Element *tableData;
+ Element *parent_element;
+ Element *axisElement;
+ string operation_types = "function, product, sum, difference, quotient,"
+ "pow, abs, sin, cos, asin, acos, tan, atan, table";
+
+ nTables = 0;
+
+ // Is this an internal lookup table?
+
+ internal = false;
+ call_type = el->GetAttributeValue("type");
+ if (call_type == string("internal")) {
+ parent_element = el->GetParent();
+ parent_type = parent_element->GetName();
+ if (operation_types.find(parent_type) == string::npos) {
+ internal = true;
+ } else {
+ // internal table is a child element of a restricted type
+ cerr << endl << fgred << " An internal table cannot be nested within another type," << endl;
+ cerr << " such as a function. The 'internal' keyword is ignored." << fgdef << endl << endl;
+ }
+ } else if (!call_type.empty()) {
+ cerr << endl << fgred << " An unknown table type attribute is listed: " << call_type
+ << ". Execution cannot continue." << fgdef << endl << endl;
+ abort();
+ }
+
+ // Determine and store the lookup properties for this table unless this table
+ // is part of a 3D table, in which case its independentVar property indexes will
+ // be set by a call from the owning table during creation
+
+ dimension = 0;
+
+ axisElement = el->FindElement("independentVar");
+ if (axisElement) {
+
+ // The 'internal' attribute of the table element cannot be specified
+ // at the same time that independentVars are specified.
+ if (internal) {
+ cerr << endl << fgred << " This table specifies both 'internal' call type" << endl;
+ cerr << " and specific lookup properties via the 'independentVar' element." << endl;
+ cerr << " These are mutually exclusive specifications. The 'internal'" << endl;
+ cerr << " attribute will be ignored." << fgdef << endl << endl;
+ internal = false;
+ }
+
+ for (i=0; i<3; i++) lookupProperty[i] = 0;
+
+ while (axisElement) {
+ property_string = axisElement->GetDataLine();
+ node = PropertyManager->GetNode(property_string);
+
+ lookup_axis = axisElement->GetAttributeValue("lookup");
+ if (lookup_axis == string("row")) {
+ lookupProperty[eRow] = node;
+ } else if (lookup_axis == string("column")) {
+ lookupProperty[eColumn] = node;
+ } else if (lookup_axis == string("table")) {
+ lookupProperty[eTable] = node;
+ } else { // assumed single dimension table; row lookup
+ lookupProperty[eRow] = node;
+ }
+ dimension++;
+ axisElement = el->FindNextElement("independentVar");
+ }
+
+ } else if (internal) { // This table is an internal table
+
+ // determine how many rows, columns, and tables in this table (dimension).
+
+ if (el->GetNumElements("tableData") > 1) {
+ dimension = 3; // this is a 3D table
+ } else {
+ tableData = el->FindElement("tableData");
+ string test_line = tableData->GetDataLine(1); // examine second line in table for dimension
+ if (FindNumColumns(test_line) == 2) dimension = 1; // 1D table
+ else if (FindNumColumns(test_line) > 2) dimension = 2; // 2D table
+ else {
+ cerr << "Invalid number of columns in table" << endl;
+ }
+ }
+
+ } else { // no independentVars found, and table is not marked as internal
+ cerr << endl << fgred << "No independent variable found for table." << fgdef << endl << endl;
+ abort();
+ }
+ // end lookup property code
+
+ tableData = el->FindElement("tableData");
+ for (int i=0; i<tableData->GetNumDataLines(); i++) {
+ buf << tableData->GetDataLine(i) << string(" ");
+ }
+ switch (dimension) {
+ case 1:
+ nRows = tableData->GetNumDataLines();
+ nCols = 1;
+ Type = tt1D;
+ colCounter = 0;
+ rowCounter = 1;
+ Data = Allocate();
+ Debug(0);
+ lastRowIndex = lastColumnIndex = 2;
+ *this << buf;
+ break;
+ case 2:
+ nRows = tableData->GetNumDataLines()-1;
+
+ if (nRows >= 2) nCols = FindNumColumns(tableData->GetDataLine(0));
+ else {
+ cerr << endl << fgred << "Not enough rows in this table." << fgdef << endl;
+ abort();
+ }
+
+ Type = tt2D;
+ colCounter = 1;
+ rowCounter = 0;
+
+ Data = Allocate();
+ lastRowIndex = lastColumnIndex = 2;
+ *this << buf;
+ break;
+ case 3:
+ nTables = el->GetNumElements("tableData");
+ nRows = nTables;
+ nCols = 1;
+ Type = tt3D;
+ colCounter = 1;
+ rowCounter = 1;
+
+ Data = Allocate(); // this data array will contain the keys for the associated tables
+ Tables.reserve(nTables); // necessary?
+ tableData = el->FindElement("tableData");
+ for (i=0; i<nTables; i++) {
+ Tables.push_back(new FGTable(PropertyManager, tableData));
+ Data[i+1][1] = tableData->GetAttributeValueAsNumber("breakPoint");
+ Tables[i]->SetRowIndexProperty(lookupProperty[eRow]);
+ Tables[i]->SetColumnIndexProperty(lookupProperty[eColumn]);
+ tableData = el->FindNextElement("tableData");
+ }
+
+ Debug(0);
+ break;
+ default:
+ cout << "No dimension given" << endl;
+ break;
+ }
+ if (debug_lvl & 1) Print();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double** FGTable::Allocate(void)
+{
+ Data = new double*[nRows+1];
+ for (int r=0; r<=nRows; r++) {
+ Data[r] = new double[nCols+1];
+ for (int c=0; c<=nCols; c++) {
+ Data[r][c] = 0.0;
+ }
+ }
+ return Data;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGTable::~FGTable()
+{
+ if (nTables > 0) {
+cout << "nTables = " << nTables << endl;
+ for (int i=0; i<nTables; i++) delete Tables[i];
+ Tables.clear();
+ }
+ for (int r=0; r<=nRows; r++) if (Data[r]) delete[] Data[r];
+ if (Data) delete[] Data;
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+int FGTable::FindNumColumns(string test_line)
+{
+ // determine number of data columns in table (first column is row lookup - don't count)
+ int position=0;
+ int nCols=0;
+ while ((position = test_line.find_first_not_of(" \t", position)) != string::npos) {
+ nCols++;
+ position = test_line.find_first_of(" \t", position);
+ }
+ return nCols;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTable::GetValue(void) const
+{
+ double temp = 0;
+ double temp2 = 0;
+
+ switch (Type) {
+ case tt1D:
+ temp = lookupProperty[eRow]->getDoubleValue();
+ temp2 = GetValue(temp);
+ return temp2;
+ case tt2D:
+ return GetValue(lookupProperty[eRow]->getDoubleValue(),
+ lookupProperty[eColumn]->getDoubleValue());
+ case tt3D:
+ return GetValue(lookupProperty[eRow]->getDoubleValue(),
+ lookupProperty[eColumn]->getDoubleValue(),
+ lookupProperty[eTable]->getDoubleValue());
+ default:
+ cerr << "Attempted to GetValue() for invalid/unknown table type" << endl;
+ throw(string("Attempted to GetValue() for invalid/unknown table type"));
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTable::GetValue(double key) const
+{
+ double Factor, Value, Span;
+ int r=lastRowIndex;
+
+ //if the key is off the end of the table, just return the
+ //end-of-table value, do not extrapolate
+ if( key <= Data[1][0] ) {
+ lastRowIndex=2;
+ //cout << "Key underneath table: " << key << endl;
+ return Data[1][1];
+ } else if ( key >= Data[nRows][0] ) {
+ lastRowIndex=nRows;
+ //cout << "Key over table: " << key << endl;
+ return Data[nRows][1];
+ }
+
+ // the key is somewhere in the middle, search for the right breakpoint
+ // assume the correct breakpoint has not changed since last frame or
+ // has only changed very little
+
+ if ( r > 2 && Data[r-1][0] > key ) {
+ while( Data[r-1][0] > key && r > 2) { r--; }
+ } else if ( Data[r][0] < key ) {
+ while( Data[r][0] <= key && r <= nRows) { r++; }
+ }
+
+ lastRowIndex=r;
+ // make sure denominator below does not go to zero.
+
+ Span = Data[r][0] - Data[r-1][0];
+ if (Span != 0.0) {
+ Factor = (key - Data[r-1][0]) / Span;
+ if (Factor > 1.0) Factor = 1.0;
+ } else {
+ Factor = 1.0;
+ }
+
+ Value = Factor*(Data[r][1] - Data[r-1][1]) + Data[r-1][1];
+
+ return Value;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTable::GetValue(double rowKey, double colKey) const
+{
+ double rFactor, cFactor, col1temp, col2temp, Value;
+ int r=lastRowIndex;
+ int c=lastColumnIndex;
+
+ if ( r > 2 && Data[r-1][0] > rowKey ) {
+ while ( Data[r-1][0] > rowKey && r > 2) { r--; }
+ } else if ( Data[r][0] < rowKey ) {
+ while ( r <= nRows && Data[r][0] <= rowKey ) { r++; }
+ if ( r > nRows ) r = nRows;
+ }
+
+ if ( c > 2 && Data[0][c-1] > colKey ) {
+ while( Data[0][c-1] > colKey && c > 2) { c--; }
+ } else if ( Data[0][c] < colKey ) {
+ while( Data[0][c] <= colKey && c <= nCols) { c++; }
+ if ( c > nCols ) c = nCols;
+ }
+
+ lastRowIndex=r;
+ lastColumnIndex=c;
+
+ rFactor = (rowKey - Data[r-1][0]) / (Data[r][0] - Data[r-1][0]);
+ cFactor = (colKey - Data[0][c-1]) / (Data[0][c] - Data[0][c-1]);
+
+ if (rFactor > 1.0) rFactor = 1.0;
+ else if (rFactor < 0.0) rFactor = 0.0;
+
+ if (cFactor > 1.0) cFactor = 1.0;
+ else if (cFactor < 0.0) cFactor = 0.0;
+
+ col1temp = rFactor*(Data[r][c-1] - Data[r-1][c-1]) + Data[r-1][c-1];
+ col2temp = rFactor*(Data[r][c] - Data[r-1][c]) + Data[r-1][c];
+
+ Value = col1temp + cFactor*(col2temp - col1temp);
+
+ return Value;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTable::GetValue(double rowKey, double colKey, double tableKey) const
+{
+ double Factor, Value, Span;
+ int r=lastRowIndex;
+
+ //if the key is off the end (or before the beginning) of the table,
+ // just return the boundary-table value, do not extrapolate
+
+ if( tableKey <= Data[1][1] ) {
+ lastRowIndex=2;
+ return Tables[0]->GetValue(rowKey, colKey);
+ } else if ( tableKey >= Data[nRows][1] ) {
+ lastRowIndex=nRows;
+ return Tables[nRows-1]->GetValue(rowKey, colKey);
+ }
+
+ // the key is somewhere in the middle, search for the right breakpoint
+ // assume the correct breakpoint has not changed since last frame or
+ // has only changed very little
+
+ if ( r > 2 && Data[r-1][1] > tableKey ) {
+ while( Data[r-1][1] > tableKey && r > 2) { r--; }
+ } else if ( Data[r][1] < tableKey ) {
+ while( Data[r][1] <= tableKey && r <= nRows) { r++; }
+ }
+
+ lastRowIndex=r;
+ // make sure denominator below does not go to zero.
+
+ Span = Data[r][1] - Data[r-1][1];
+ if (Span != 0.0) {
+ Factor = (tableKey - Data[r-1][1]) / Span;
+ if (Factor > 1.0) Factor = 1.0;
+ } else {
+ Factor = 1.0;
+ }
+
+ Value = Factor*(Tables[r-1]->GetValue(rowKey, colKey) - Tables[r-2]->GetValue(rowKey, colKey))
+ + Tables[r-2]->GetValue(rowKey, colKey);
+
+ return Value;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGTable::operator<<(stringstream& in_stream)
+{
+ int startRow=0;
+ int startCol=0;
+
+ if (Type == tt1D || Type == tt3D) startRow = 1;
+ if (Type == tt3D) startCol = 1;
+
+ for (int r=startRow; r<=nRows; r++) {
+ for (int c=startCol; c<=nCols; c++) {
+ if (r != 0 || c != 0) {
+ in_stream >> Data[r][c];
+ }
+ }
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGTable& FGTable::operator<<(const double n)
+{
+ Data[rowCounter][colCounter] = n;
+ if (colCounter == nCols) {
+ colCounter = 0;
+ rowCounter++;
+ } else {
+ colCounter++;
+ }
+ return *this;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGTable& FGTable::operator<<(const int n)
+{
+ *this << (double)n;
+ return *this;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGTable::Print(void)
+{
+ int startRow=0;
+ int startCol=0;
+
+ if (Type == tt1D || Type == tt3D) startRow = 1;
+ if (Type == tt3D) startCol = 1;
+
+#if defined (sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
+ unsigned long flags = cout.setf(ios::fixed);
+#else
+ ios::fmtflags flags = cout.setf(ios::fixed); // set up output stream
+#endif
+
+ switch(Type) {
+ case tt1D:
+ cout << " 1 dimensional table with " << nRows << " rows." << endl;
+ break;
+ case tt2D:
+ cout << " 2 dimensional table with " << nRows << " rows, " << nCols << " columns." << endl;
+ break;
+ case tt3D:
+ cout << " 3 dimensional table with " << nRows << " rows, "
+ << nCols << " columns "
+ << nTables << " tables." << endl;
+ break;
+ }
+ cout.precision(4);
+ for (int r=startRow; r<=nRows; r++) {
+ cout << " ";
+ for (int c=startCol; c<=nCols; c++) {
+ if (r == 0 && c == 0) {
+ cout << " ";
+ } else {
+ cout << Data[r][c] << " ";
+ if (Type == tt3D) {
+ cout << endl;
+ Tables[r-1]->Print();
+ }
+ }
+ }
+ cout << endl;
+ }
+ cout.setf(flags); // reset
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGTable::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGTable" << endl;
+ if (from == 1) cout << "Destroyed: FGTable" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGTable.h
+ Author: Jon S. Berndt
+ Date started: 1/9/2001
+
+ ------------- Copyright (C) 2001 Jon S. Berndt (jsb@hal-pc.org) --------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+JSB 1/9/00 Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGTABLE_H
+#define FGTABLE_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <input_output/FGXMLElement.h>
+#include "FGParameter.h"
+#include <input_output/FGPropertyManager.h>
+#include <sstream>
+#include <vector>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_TABLE "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+using std::vector;
+using std::stringstream;
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Lookup table class.
+ Models a one, two, or three dimensional lookup table for use in FGCoefficient,
+ FGPropeller, etc. A one-dimensional table is called a "VECTOR" in a coefficient
+ definition. For example:
+<pre>
+ \<COEFFICIENT NAME="{short name}" TYPE="VECTOR">
+ {name}
+ {number of rows}
+ {row lookup property}
+ {non-dimensionalizing properties}
+ {row_1_key} {col_1_data}
+ {row_2_key} {... }
+ { ... } {... }
+ {row_n_key} {... }
+ \</COEFFICIENT>
+</pre>
+ A "real life" example is as shown here:
+<pre>
+ \<COEFFICIENT NAME="CLDf" TYPE="VECTOR">
+ Delta_lift_due_to_flap_deflection
+ 4
+ fcs/flap-pos-deg
+ aero/qbar-psf | metrics/Sw-sqft
+ 0 0
+ 10 0.20
+ 20 0.30
+ 30 0.35
+ \</COEFFICIENT>
+</pre>
+ The first column in the data table represents the lookup index (or "key"). In
+ this case, the lookup index is fcs/flap-pos-deg (flap extension in degrees).
+ If the flap position is 10 degrees, the value returned from the lookup table
+ would be 0.20. This value would be multiplied by qbar (aero/qbar-psf) and wing
+ area (metrics/Sw-sqft) to get the total lift force that is a result of flap
+ deflection (measured in pounds force). If the value of the flap-pos-deg property
+ was 15 (degrees), the value output by the table routine would be 0.25 - an
+ interpolation. If the flap position in degrees ever went below 0.0, or above
+ 30 (degrees), the output from the table routine would be 0 and 0.35, respectively.
+ That is, there is no _extrapolation_ to values outside the range of the lookup
+ index. This is why it is important to chose the data for the table wisely.
+
+ The definition for a 2D table - referred to simply as a TABLE, is as follows:
+<pre>
+ \<COEFFICIENT NAME="{short name}" TYPE="TABLE">
+ {name}
+ {number of rows}
+ {number of columns}
+ {row lookup property}
+ {column lookup property}
+ {non-dimensionalizing}
+ {col_1_key col_2_key ... col_n_key }
+ {row_1_key} {col_1_data col_2_data ... col_n_data}
+ {row_2_key} {... ... ... ... }
+ { ... } {... ... ... ... }
+ {row_n_key} {... ... ... ... }
+ \</COEFFICIENT>
+</pre>
+ A "real life" example is as shown here:
+<pre>
+ \<COEFFICIENT NAME="CYb" TYPE="TABLE">
+ Side_force_due_to_beta
+ 3
+ 2
+ aero/beta-rad
+ fcs/flap-pos-deg
+ aero/qbar-psf | metrics/Sw-sqft
+ 0 30
+ -0.349 0.137 0.106
+ 0 0 0
+ 0.349 -0.137 -0.106
+ \</COEFFICIENT>
+</pre>
+ The definition for a 3D table in a coefficient would be (for example):
+<pre>
+ \<COEFFICIENT NAME="{short name}" TYPE="TABLE3D">
+ {name}
+ {number of rows}
+ {number of columns}
+ {number of tables}
+ {row lookup property}
+ {column lookup property}
+ {table lookup property}
+ {non-dimensionalizing}
+ {first table key}
+ {col_1_key col_2_key ... col_n_key }
+ {row_1_key} {col_1_data col_2_data ... col_n_data}
+ {row_2_key} {... ... ... ... }
+ { ... } {... ... ... ... }
+ {row_n_key} {... ... ... ... }
+
+ {second table key}
+ {col_1_key col_2_key ... col_n_key }
+ {row_1_key} {col_1_data col_2_data ... col_n_data}
+ {row_2_key} {... ... ... ... }
+ { ... } {... ... ... ... }
+ {row_n_key} {... ... ... ... }
+
+ ...
+
+ \</COEFFICIENT>
+</pre>
+ [At the present time, all rows and columns for each table must have the
+ same dimension.]
+
+ In addition to using a Table for something like a coefficient, where all the
+ row and column elements are read in from a file, a Table could be created
+ and populated completely within program code:
+<pre>
+ // First column is thi, second is neta (combustion efficiency)
+ Lookup_Combustion_Efficiency = new FGTable(12);
+ *Lookup_Combustion_Efficiency << 0.00 << 0.980;
+ *Lookup_Combustion_Efficiency << 0.90 << 0.980;
+ *Lookup_Combustion_Efficiency << 1.00 << 0.970;
+ *Lookup_Combustion_Efficiency << 1.05 << 0.950;
+ *Lookup_Combustion_Efficiency << 1.10 << 0.900;
+ *Lookup_Combustion_Efficiency << 1.15 << 0.850;
+ *Lookup_Combustion_Efficiency << 1.20 << 0.790;
+ *Lookup_Combustion_Efficiency << 1.30 << 0.700;
+ *Lookup_Combustion_Efficiency << 1.40 << 0.630;
+ *Lookup_Combustion_Efficiency << 1.50 << 0.570;
+ *Lookup_Combustion_Efficiency << 1.60 << 0.525;
+ *Lookup_Combustion_Efficiency << 2.00 << 0.345;
+</pre>
+ The first column in the table, above, is thi (the lookup index, or key). The
+ second column is the output data - in this case, "neta" (the Greek letter
+ referring to combustion efficiency). Later on, the table is used like this:
+
+ combustion_efficiency = Lookup_Combustion_Efficiency->GetValue(equivalence_ratio);
+
+ @author Jon S. Berndt
+ @version $Id$
+ @see FGCoefficient
+ @see FGPropeller
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGTable : public FGParameter
+{
+public:
+ /// Destructor
+ ~FGTable();
+
+ /** This is the very important copy constructor.
+ @param table a const reference to a table.*/
+ FGTable(const FGTable& table);
+
+ /// The constructor for a table
+ FGTable (FGPropertyManager* propMan, Element* el);
+ FGTable (int );
+ double GetValue(void) const;
+ double GetValue(double key) const;
+ double GetValue(double rowKey, double colKey) const;
+ double GetValue(double rowKey, double colKey, double TableKey) const;
+ /** Read the table in.
+ Data in the config file should be in matrix format with the row
+ independents as the first column and the column independents in
+ the first row. The implication of this layout is that there should
+ be no value in the upper left corner of the matrix e.g:
+ <pre>
+ 0 10 20 30 ...
+ -5 1 2 3 4 ...
+ ...
+ </pre>
+
+ For multiple-table (i.e. 3D) data sets there is an additional number
+ key in the table definition. For example:
+
+ <pre>
+ 0.0
+ 0 10 20 30 ...
+ -5 1 2 3 4 ...
+ ...
+ </pre>
+ */
+
+ void operator<<(stringstream&);
+ FGTable& operator<<(const double n);
+ FGTable& operator<<(const int n);
+
+ inline double GetElement(int r, int c) {return Data[r][c];}
+ inline double GetElement(int r, int c, int t);
+
+ void SetRowIndexProperty(FGPropertyManager *node) {lookupProperty[eRow] = node;}
+ void SetColumnIndexProperty(FGPropertyManager *node) {lookupProperty[eColumn] = node;}
+
+ void Print(void);
+
+private:
+ enum type {tt1D, tt2D, tt3D} Type;
+ enum axis {eRow=0, eColumn, eTable};
+ bool internal;
+ FGPropertyManager *lookupProperty[3];
+ double** Data;
+ vector <FGTable*> Tables;
+ int FindNumColumns(string);
+ int nRows, nCols, nTables, dimension;
+ int colCounter, rowCounter, tableCounter;
+ mutable int lastRowIndex, lastColumnIndex, lastTableIndex;
+ double** Allocate(void);
+ FGPropertyManager* const PropertyManager;
+
+ void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+#endif
+
--- /dev/null
+noinst_LIBRARIES = libMath.a
+
+libMath_a_SOURCES = FGColumnVector3.cpp FGFunction.cpp FGLocation.cpp FGMatrix33.cpp \
+ FGPropertyValue.cpp FGQuaternion.cpp FGRealValue.cpp FGTable.cpp
+
+noinst_HEADERS = FGColumnVector3.h FGFunction.h FGLocation.h FGMatrix33.h \
+ FGParameter.h FGPropertyValue.h FGQuaternion.h FGRealValue.h FGTable.h
+
+INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGAerodynamics.cpp
+ Author: Jon S. Berndt
+ Date started: 09/13/00
+ Purpose: Encapsulates the aerodynamic forces
+
+ ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+09/13/00 JSB Created
+04/22/01 JSB Moved code into here from FGAircraft
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGAerodynamics.h"
+#include "FGPropagate.h"
+#include "FGAircraft.h"
+#include "FGState.h"
+#include "FGMassBalance.h"
+#include <input_output/FGPropertyManager.h>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_AERODYNAMICS;
+
+const unsigned NAxes=6;
+const char* AxisNames[] = { "drag", "side-force", "lift", "rolling-moment",
+ "pitching-moment","yawing-moment" };
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+FGAerodynamics::FGAerodynamics(FGFDMExec* FDMExec) : FGModel(FDMExec)
+{
+ Name = "FGAerodynamics";
+
+ AxisIdx["DRAG"] = 0;
+ AxisIdx["SIDE"] = 1;
+ AxisIdx["LIFT"] = 2;
+ AxisIdx["ROLL"] = 3;
+ AxisIdx["PITCH"] = 4;
+ AxisIdx["YAW"] = 5;
+
+ Coeff = new CoeffArray[6];
+
+ impending_stall = stall_hyst = 0.0;
+ alphaclmin = alphaclmax = 0.0;
+ alphahystmin = alphahystmax = 0.0;
+ clsq = lod = 0.0;
+ alphaw = 0.0;
+ bi2vel = ci2vel = 0.0;
+ bind();
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGAerodynamics::~FGAerodynamics()
+{
+ unsigned int i,j;
+
+ unbind();
+
+ for (i=0; i<6; i++)
+ for (j=0; j<Coeff[i].size(); j++)
+ delete Coeff[i][j];
+
+ delete[] Coeff;
+
+ for (i=0; i<variables.size(); i++)
+ delete variables[i];
+
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGAerodynamics::Run(void)
+{
+ unsigned int axis_ctr, ctr, i;
+ double alpha, twovel;
+
+ if (FGModel::Run()) return true;
+ if (FDMExec->Holding()) return false; // if paused don't execute
+
+ // calculate some oft-used quantities for speed
+
+ twovel = 2*Auxiliary->GetVt();
+ if (twovel != 0) {
+ bi2vel = Aircraft->GetWingSpan() / twovel;
+ ci2vel = Aircraft->Getcbar() / twovel;
+ }
+ alphaw = Auxiliary->Getalpha() + Aircraft->GetWingIncidence();
+ alpha = Auxiliary->Getalpha();
+ qbar_area = Aircraft->GetWingArea() * Auxiliary->Getqbar();
+
+ if (alphaclmax != 0) {
+ if (alpha > 0.85*alphaclmax) {
+ impending_stall = 10*(alpha/alphaclmax - 0.85);
+ } else {
+ impending_stall = 0;
+ }
+ }
+
+ if (alphahystmax != 0.0 && alphahystmin != 0.0) {
+ if (alpha > alphahystmax) {
+ stall_hyst = 1;
+ } else if (alpha < alphahystmin) {
+ stall_hyst = 0;
+ }
+ }
+
+ vLastFs = vFs;
+ vFs.InitMatrix();
+
+ // Tell the variable functions to cache their values, so while the aerodynamic
+ // functions are being calculated for each axis, these functions do not get
+ // calculated each time, but instead use the values that have already
+ // been calculated for this frame.
+ for (i=0; i<variables.size(); i++) variables[i]->cacheValue(true);
+
+ for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) {
+ for (ctr=0; ctr < Coeff[axis_ctr].size(); ctr++) {
+ vFs(axis_ctr+1) += Coeff[axis_ctr][ctr]->GetValue();
+ }
+ }
+
+ // calculate lift coefficient squared
+ if ( Auxiliary->Getqbar() > 0) {
+ clsq = vFs(eLift) / (Aircraft->GetWingArea()*Auxiliary->Getqbar());
+ clsq *= clsq;
+ }
+
+ if ( vFs(eDrag) > 0) {
+ lod = vFs(eLift) / vFs(eDrag);
+ }
+
+ //correct signs of drag and lift to wind axes convention
+ //positive forward, right, down
+ vFs(eDrag)*=-1; vFs(eLift)*=-1;
+
+ // transform stability axis forces into body axes
+ vForces = State->GetTs2b()*vFs;
+
+ vDXYZcg = MassBalance->StructuralToBody(Aircraft->GetXYZrp());
+
+ vMoments = vDXYZcg*vForces; // M = r X F
+
+ for (axis_ctr = 0; axis_ctr < 3; axis_ctr++) {
+ for (ctr = 0; ctr < Coeff[axis_ctr+3].size(); ctr++) {
+ vMoments(axis_ctr+1) += Coeff[axis_ctr+3][ctr]->GetValue();
+ }
+ }
+
+ return false;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGAerodynamics::Load(Element *element)
+{
+ string parameter, axis, scratch;
+ Element *temp_element, *axis_element, *function_element;
+
+ Debug(2);
+
+ if (temp_element = element->FindElement("alphalimits")) {
+ alphaclmin = temp_element->FindElementValueAsNumberConvertTo("min", "DEG");
+ alphaclmax = temp_element->FindElementValueAsNumberConvertTo("max", "DEG");
+ }
+
+ if (temp_element = element->FindElement("hysteresis_limits")) {
+ alphahystmin = temp_element->FindElementValueAsNumberConvertTo("min", "DEG");
+ alphahystmax = temp_element->FindElementValueAsNumberConvertTo("max", "DEG");
+ }
+
+ function_element = element->FindElement("function");
+ while (function_element) {
+ variables.push_back( new FGFunction(PropertyManager, function_element) );
+ function_element = element->FindNextElement("function");
+ }
+
+ axis_element = element->FindElement("axis");
+ while (axis_element) {
+ CoeffArray ca;
+ axis = axis_element->GetAttributeValue("name");
+ function_element = axis_element->FindElement("function");
+ while (function_element) {
+ ca.push_back( new FGFunction(PropertyManager, function_element) );
+ function_element = axis_element->FindNextElement("function");
+ }
+ Coeff[AxisIdx[axis]] = ca;
+ axis_element = element->FindNextElement("axis");
+ }
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGAerodynamics::GetCoefficientStrings(string delimeter)
+{
+ string CoeffStrings = "";
+ bool firstime = true;
+ unsigned int axis, sd;
+
+ for (sd = 0; sd < variables.size(); sd++) {
+ if (firstime) {
+ firstime = false;
+ } else {
+ CoeffStrings += delimeter;
+ }
+ CoeffStrings += variables[sd]->GetName();
+ }
+
+ for (axis = 0; axis < 6; axis++) {
+ for (sd = 0; sd < Coeff[axis].size(); sd++) {
+ CoeffStrings += delimeter;
+ CoeffStrings += Coeff[axis][sd]->GetName();
+ }
+ }
+ return CoeffStrings;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGAerodynamics::GetCoefficientValues(string delimeter)
+{
+ string SDValues = "";
+ bool firstime = true;
+ unsigned int sd;
+
+ for (sd = 0; sd < variables.size(); sd++) {
+ if (firstime) {
+ firstime = false;
+ } else {
+ SDValues += delimeter;
+ }
+ SDValues += variables[sd]->GetValueAsString();
+ }
+
+ for (unsigned int axis = 0; axis < 6; axis++) {
+ for (unsigned int sd = 0; sd < Coeff[axis].size(); sd++) {
+ SDValues += delimeter;
+ SDValues += Coeff[axis][sd]->GetValueAsString();
+ }
+ }
+
+ return SDValues;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGAerodynamics::bind(void)
+{
+ typedef double (FGAerodynamics::*PMF)(int) const;
+
+ PropertyManager->Tie("forces/fbx-aero-lbs", this,1,
+ (PMF)&FGAerodynamics::GetForces);
+ PropertyManager->Tie("forces/fby-aero-lbs", this,2,
+ (PMF)&FGAerodynamics::GetForces);
+ PropertyManager->Tie("forces/fbz-aero-lbs", this,3,
+ (PMF)&FGAerodynamics::GetForces);
+ PropertyManager->Tie("moments/l-aero-lbsft", this,1,
+ (PMF)&FGAerodynamics::GetMoments);
+ PropertyManager->Tie("moments/m-aero-lbsft", this,2,
+ (PMF)&FGAerodynamics::GetMoments);
+ PropertyManager->Tie("moments/n-aero-lbsft", this,3,
+ (PMF)&FGAerodynamics::GetMoments);
+ PropertyManager->Tie("forces/fwx-aero-lbs", this,1,
+ (PMF)&FGAerodynamics::GetvFs);
+ PropertyManager->Tie("forces/fwy-aero-lbs", this,2,
+ (PMF)&FGAerodynamics::GetvFs);
+ PropertyManager->Tie("forces/fwz-aero-lbs", this,3,
+ (PMF)&FGAerodynamics::GetvFs);
+ PropertyManager->Tie("forces/lod-norm", this,
+ &FGAerodynamics::GetLoD);
+ PropertyManager->Tie("aero/cl-squared", this,
+ &FGAerodynamics::GetClSquared);
+ PropertyManager->Tie("aero/qbar-area", &qbar_area);
+ PropertyManager->Tie("aero/alpha-max-deg", this,
+ &FGAerodynamics::GetAlphaCLMax,
+ &FGAerodynamics::SetAlphaCLMax,
+ true);
+ PropertyManager->Tie("aero/alpha-min-deg", this,
+ &FGAerodynamics::GetAlphaCLMin,
+ &FGAerodynamics::SetAlphaCLMin,
+ true);
+ PropertyManager->Tie("aero/bi2vel", this,
+ &FGAerodynamics::GetBI2Vel);
+ PropertyManager->Tie("aero/ci2vel", this,
+ &FGAerodynamics::GetCI2Vel);
+ PropertyManager->Tie("aero/alpha-wing-rad", this,
+ &FGAerodynamics::GetAlphaW);
+ PropertyManager->Tie("systems/stall-warn-norm", this,
+ &FGAerodynamics::GetStallWarn);
+ PropertyManager->Tie("aero/stall-hyst-norm", this,
+ &FGAerodynamics::GetHysteresisParm);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGAerodynamics::unbind(void)
+{
+ unsigned i,j;
+
+ PropertyManager->Untie("forces/fbx-aero-lbs");
+ PropertyManager->Untie("forces/fby-aero-lbs");
+ PropertyManager->Untie("forces/fbz-aero-lbs");
+ PropertyManager->Untie("moments/l-aero-lbsft");
+ PropertyManager->Untie("moments/m-aero-lbsft");
+ PropertyManager->Untie("moments/n-aero-lbsft");
+ PropertyManager->Untie("forces/fwx-aero-lbs");
+ PropertyManager->Untie("forces/fwy-aero-lbs");
+ PropertyManager->Untie("forces/fwz-aero-lbs");
+ PropertyManager->Untie("forces/lod-norm");
+ PropertyManager->Untie("aero/cl-squared");
+ PropertyManager->Untie("aero/qbar-area");
+ PropertyManager->Untie("aero/alpha-max-deg");
+ PropertyManager->Untie("aero/alpha-min-deg");
+ PropertyManager->Untie("aero/bi2vel");
+ PropertyManager->Untie("aero/ci2vel");
+ PropertyManager->Untie("aero/alpha-wing-rad");
+ PropertyManager->Untie("aero/stall-hyst-norm");
+ PropertyManager->Untie("systems/stall-warn-norm");
+
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGAerodynamics::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 2) { // Loader
+ cout << endl << " Aerodynamics: " << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGAerodynamics" << endl;
+ if (from == 1) cout << "Destroyed: FGAerodynamics" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+
+} // namespace JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGAerodynamics.h
+ Author: Jon S. Berndt
+ Date started: 09/13/00
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+09/13/00 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGAERODYNAMICS_H
+#define FGAERODYNAMICS_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# ifdef SG_HAVE_STD_INCLUDES
+# include <vector>
+# include <map>
+# else
+# include <vector.h>
+# include <map.h>
+# endif
+#else
+# include <vector>
+# include <map>
+#endif
+
+#include "FGModel.h"
+#include <math/FGFunction.h>
+#include <math/FGColumnVector3.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_AERODYNAMICS "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Encapsulates the aerodynamic calculations.
+ This class owns and contains the list of coefficients that define the
+ aerodynamic properties of this aircraft. Here also, such unique phenomena
+ as ground effect and maximum lift curve tailoff are handled.
+ @config
+ <pre>
+ \<AERODYNAMICS>
+ \<AXIS NAME="{LIFT|DRAG|SIDE|ROLL|PITCH|YAW}">
+ {Coefficient definitions}
+ \</AXIS>
+ {Additional axis definitions}
+ \</AERODYNAMICS> </pre>
+
+ @author Jon S. Berndt, Tony Peden
+ $Id$
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGAerodynamics : public FGModel {
+
+public:
+ /** Constructor
+ @param Executive a pointer to the parent executive object */
+ FGAerodynamics(FGFDMExec* Executive);
+ /// Destructor
+ ~FGAerodynamics();
+
+ /** Runs the Aerodynamics model; called by the Executive
+ @return false if no error */
+ bool Run(void);
+
+ /** Loads the Aerodynamics model.
+ The Load function for this class expects the XML parser to
+ have found the AERODYNAMICS keyword in the configuration file.
+ @param element pointer to the current XML element for aerodynamics parameters.
+ @return true if successful */
+ bool Load(Element* element);
+
+ /** Gets the total aerodynamic force vector.
+ @return a force vector reference. */
+ FGColumnVector3& GetForces(void) {return vForces;}
+
+ /** Gets the aerodynamic force for an axis.
+ @param n Axis index. This could be 0, 1, or 2, or one of the
+ axis enums: eX, eY, eZ.
+ @return the force acting on an axis */
+ double GetForces(int n) const {return vForces(n);}
+
+ /** Gets the total aerodynamic moment vector.
+ @return a moment vector reference. */
+ FGColumnVector3& GetMoments(void) {return vMoments;}
+
+ /** Gets the aerodynamic moment for an axis.
+ @return the moment about a single axis (as described also in the
+ similar call to GetForces(int n).*/
+ double GetMoments(int n) const {return vMoments(n);}
+
+ FGColumnVector3& GetvLastFs(void) { return vLastFs; }
+ double GetvLastFs(int axis) const { return vLastFs(axis); }
+ FGColumnVector3& GetvFs(void) { return vFs; }
+ double GetvFs(int axis) const { return vFs(axis); }
+ inline double GetLoD(void) const { return lod; }
+ inline double GetClSquared(void) const { return clsq; }
+ inline double GetAlphaCLMax(void) const { return alphaclmax; }
+ inline double GetAlphaCLMin(void) const { return alphaclmin; }
+
+ inline double GetAlphaHystMax(void) const { return alphahystmax; }
+ inline double GetAlphaHystMin(void) const { return alphahystmin; }
+ inline double GetHysteresisParm(void) const { return stall_hyst; }
+ inline double GetStallWarn(void) const { return impending_stall; }
+ double GetAlphaW(void) const { return alphaw; }
+
+ double GetBI2Vel(void) const { return bi2vel; }
+ double GetCI2Vel(void) const { return ci2vel; }
+
+ inline void SetAlphaCLMax(double tt) { alphaclmax=tt; }
+ inline void SetAlphaCLMin(double tt) { alphaclmin=tt; }
+
+ /** Gets the strings for the current set of coefficients.
+ @param delimeter either a tab or comma string depending on output type
+ @return a string containing the descriptive names for all coefficients */
+ string GetCoefficientStrings(string delimeter);
+
+ /** Gets the coefficient values.
+ @param delimeter either a tab or comma string depending on output type
+ @return a string containing the numeric values for the current set of
+ coefficients */
+ string GetCoefficientValues(string delimeter);
+
+ void bind(void);
+ void unbind(void);
+
+private:
+ typedef map<string,int> AxisIndex;
+ AxisIndex AxisIdx;
+ vector <FGFunction*> variables;
+ typedef vector <FGFunction*> CoeffArray;
+ CoeffArray* Coeff;
+ FGColumnVector3 vFs;
+ FGColumnVector3 vForces;
+ FGColumnVector3 vMoments;
+ FGColumnVector3 vLastFs;
+ FGColumnVector3 vDXYZcg;
+ double alphaclmax, alphaclmin;
+ double alphahystmax, alphahystmin;
+ double impending_stall, stall_hyst;
+ double bi2vel, ci2vel,alphaw;
+ double clsq, lod, qbar_area;
+
+ typedef double (FGAerodynamics::*PMF)(int) const;
+
+ void Debug(int from);
+};
+
+} // namespace JSBSim
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGAircraft.cpp
+ Author: Jon S. Berndt
+ Date started: 12/12/98
+ Purpose: Encapsulates an aircraft
+ Called by: FGFDMExec
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+Models the aircraft reactions and forces. This class is instantiated by the
+FGFDMExec class and scheduled as an FDM entry.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+COMMENTS, REFERENCES, and NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#ifdef FGFS
+# ifndef __BORLANDC__
+# include <simgear/compiler.h>
+# endif
+# ifdef SG_HAVE_STD_INCLUDES
+# include <cmath>
+# else
+# include <math.h>
+# endif
+#else
+# if defined (sgi) && !defined(__GNUC__)
+# include <math.h>
+# else
+# include <cmath>
+# endif
+#endif
+
+#include "FGAircraft.h"
+#include "FGMassBalance.h"
+#include "FGInertial.h"
+#include "FGGroundReactions.h"
+#include "FGAerodynamics.h"
+#include <FGState.h>
+#include <FGFDMExec.h>
+#include "FGPropagate.h"
+#include <input_output/FGPropertyManager.h>
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+GLOBAL DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_AIRCRAFT;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGAircraft::FGAircraft(FGFDMExec* fdmex) : FGModel(fdmex)
+{
+ Name = "FGAircraft";
+ WingSpan = 0.0;
+ HTailArea = VTailArea = 0.0;
+ HTailArm = VTailArm = 0.0;
+ lbarh = lbarv = 0.0;
+ vbarh = vbarv = 0.0;
+ WingIncidence = 0.0;
+
+ bind();
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGAircraft::~FGAircraft()
+{
+ unbind();
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGAircraft::Run(void)
+{
+ if (FGModel::Run()) return true;
+ if (FDMExec->Holding()) return false;
+
+ vForces.InitMatrix();
+ vForces += Aerodynamics->GetForces();
+ vForces += Propulsion->GetForces();
+ vForces += GroundReactions->GetForces();
+
+ vMoments.InitMatrix();
+ vMoments += Aerodynamics->GetMoments();
+ vMoments += Propulsion->GetMoments();
+ vMoments += GroundReactions->GetMoments();
+
+// printf("%s:%i\n", __FILE__, __LINE__);
+ vBodyAccel = vForces/MassBalance->GetMass();
+
+// printf("%s:%i\n", __FILE__, __LINE__);
+ vNcg = vBodyAccel/Inertial->gravity();
+
+ vNwcg = State->GetTb2s() * vNcg;
+ vNwcg(3) = -1*vNwcg(3) + 1;
+
+ return false;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGAircraft::GetNlf(void)
+{
+ return -1*Aerodynamics->GetvFs(3)/MassBalance->GetWeight();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGAircraft::Load(Element* el)
+{
+ string element_name;
+ Element* element;
+
+ if (el->FindElement("wingarea"))
+ WingArea = el->FindElementValueAsNumberConvertTo("wingarea", "FT2");
+ if (el->FindElement("wingspan"))
+ WingSpan = el->FindElementValueAsNumberConvertTo("wingspan", "FT");
+ if (el->FindElement("chord"))
+ cbar = el->FindElementValueAsNumberConvertTo("chord", "FT");
+ if (el->FindElement("wing_incidence"))
+ WingIncidence = el->FindElementValueAsNumberConvertTo("wing_incidence", "DEG");
+ if (el->FindElement("htailarea"))
+ HTailArea = el->FindElementValueAsNumberConvertTo("htailarea", "FT2");
+ if (el->FindElement("htailarm"))
+ HTailArm = el->FindElementValueAsNumberConvertTo("htailarm", "FT");
+ if (el->FindElement("vtailarea"))
+ VTailArea = el->FindElementValueAsNumberConvertTo("vtailarea", "FT2");
+ if (el->FindElement("vtailarm"))
+ VTailArm = el->FindElementValueAsNumberConvertTo("vtailarm", "FT");
+
+ // Find all LOCATION elements that descend from this METRICS branch of the
+ // config file. This would be CG location, eyepoint, etc.
+
+ element = el->FindElement("location");
+ while (element) {
+ element_name = element->GetAttributeValue("name");
+
+ if (element_name == "AERORP") vXYZrp = element->FindElementTripletConvertTo("IN");
+ else if (element_name == "EYEPOINT") vXYZep = element->FindElementTripletConvertTo("IN");
+ else if (element_name == "VRP") vXYZvrp = element->FindElementTripletConvertTo("IN");
+
+ element = el->FindNextElement("location");
+ }
+
+ // calculate some derived parameters
+ if (cbar != 0.0) {
+ lbarh = HTailArm/cbar;
+ lbarv = VTailArm/cbar;
+ if (WingArea != 0.0) {
+ vbarh = HTailArm*HTailArea / (cbar*WingArea);
+ vbarv = VTailArm*VTailArea / (cbar*WingArea);
+ }
+ }
+
+ Debug(2);
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGAircraft::bind(void)
+{
+ typedef double (FGAircraft::*PMF)(int) const;
+ PropertyManager->Tie("metrics/Sw-sqft", this, &FGAircraft::GetWingArea);
+ PropertyManager->Tie("metrics/bw-ft", this, &FGAircraft::GetWingSpan);
+ PropertyManager->Tie("metrics/cbarw-ft", this, &FGAircraft::Getcbar);
+ PropertyManager->Tie("metrics/iw-deg", this, &FGAircraft::GetWingIncidence);
+ PropertyManager->Tie("metrics/Sh-sqft", this, &FGAircraft::GetHTailArea);
+ PropertyManager->Tie("metrics/lh-ft", this, &FGAircraft::GetHTailArm);
+ PropertyManager->Tie("metrics/Sv-sqft", this, &FGAircraft::GetVTailArea);
+ PropertyManager->Tie("metrics/lv-ft", this, &FGAircraft::GetVTailArm);
+ PropertyManager->Tie("metrics/lh-norm", this, &FGAircraft::Getlbarh);
+ PropertyManager->Tie("metrics/lv-norm", this, &FGAircraft::Getlbarv);
+ PropertyManager->Tie("metrics/vbarh-norm", this, &FGAircraft::Getvbarh);
+ PropertyManager->Tie("metrics/vbarv-norm", this, &FGAircraft::Getvbarv);
+ PropertyManager->Tie("moments/l-total-lbsft", this, eL, (PMF)&FGAircraft::GetMoments);
+ PropertyManager->Tie("moments/m-total-lbsft", this, eM, (PMF)&FGAircraft::GetMoments);
+ PropertyManager->Tie("moments/n-total-lbsft", this, eN, (PMF)&FGAircraft::GetMoments);
+ PropertyManager->Tie("forces/fbx-total-lbs", this, eX, (PMF)&FGAircraft::GetForces);
+ PropertyManager->Tie("forces/fby-total-lbs", this, eY, (PMF)&FGAircraft::GetForces);
+ PropertyManager->Tie("forces/fbz-total-lbs", this, eZ, (PMF)&FGAircraft::GetForces);
+ PropertyManager->Tie("metrics/aero-rp-x-in", this, eX, (PMF)&FGAircraft::GetXYZrp);
+ PropertyManager->Tie("metrics/aero-rp-y-in", this, eY, (PMF)&FGAircraft::GetXYZrp);
+ PropertyManager->Tie("metrics/aero-rp-z-in", this, eZ, (PMF)&FGAircraft::GetXYZrp);
+ PropertyManager->Tie("metrics/eyepoint-x-in", this, eX, (PMF)&FGAircraft::GetXYZep);
+ PropertyManager->Tie("metrics/eyepoint-y-in", this, eY,(PMF)&FGAircraft::GetXYZep);
+ PropertyManager->Tie("metrics/eyepoint-z-in", this, eZ, (PMF)&FGAircraft::GetXYZep);
+ PropertyManager->Tie("metrics/visualrefpoint-x-in", this, eX, (PMF)&FGAircraft::GetXYZvrp);
+ PropertyManager->Tie("metrics/visualrefpoint-y-in", this, eY, (PMF)&FGAircraft::GetXYZvrp);
+ PropertyManager->Tie("metrics/visualrefpoint-z-in", this, eZ, (PMF)&FGAircraft::GetXYZvrp);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGAircraft::unbind(void)
+{
+ PropertyManager->Untie("metrics/Sw-sqft");
+ PropertyManager->Untie("metrics/bw-ft");
+ PropertyManager->Untie("metrics/cbarw-ft");
+ PropertyManager->Untie("metrics/iw-deg");
+ PropertyManager->Untie("metrics/Sh-sqft");
+ PropertyManager->Untie("metrics/lh-ft");
+ PropertyManager->Untie("metrics/Sv-sqft");
+ PropertyManager->Untie("metrics/lv-ft");
+ PropertyManager->Untie("metrics/lh-norm");
+ PropertyManager->Untie("metrics/lv-norm");
+ PropertyManager->Untie("metrics/vbarh-norm");
+ PropertyManager->Untie("metrics/vbarv-norm");
+ PropertyManager->Untie("moments/l-total-lbsft");
+ PropertyManager->Untie("moments/m-total-lbsft");
+ PropertyManager->Untie("moments/n-total-lbsft");
+ PropertyManager->Untie("forces/fbx-total-lbs");
+ PropertyManager->Untie("forces/fby-total-lbs");
+ PropertyManager->Untie("forces/fbz-total-lbs");
+ PropertyManager->Untie("metrics/aero-rp-x-in");
+ PropertyManager->Untie("metrics/aero-rp-y-in");
+ PropertyManager->Untie("metrics/aero-rp-z-in");
+ PropertyManager->Untie("metrics/eyepoint-x-in");
+ PropertyManager->Untie("metrics/eyepoint-y-in");
+ PropertyManager->Untie("metrics/eyepoint-z-in");
+ PropertyManager->Untie("metrics/visualrefpoint-x-in");
+ PropertyManager->Untie("metrics/visualrefpoint-y-in");
+ PropertyManager->Untie("metrics/visualrefpoint-z-in");
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGAircraft::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 2) { // Loading
+ cout << endl << " Aircraft Metrics:" << endl;
+ cout << " WingArea: " << WingArea << endl;
+ cout << " WingSpan: " << WingSpan << endl;
+ cout << " Incidence: " << WingIncidence << endl;
+ cout << " Chord: " << cbar << endl;
+ cout << " H. Tail Area: " << HTailArea << endl;
+ cout << " H. Tail Arm: " << HTailArm << endl;
+ cout << " V. Tail Area: " << VTailArea << endl;
+ cout << " V. Tail Arm: " << VTailArm << endl;
+ cout << " Eyepoint (x, y, z): " << vXYZep << endl;
+ cout << " Ref Pt (x, y, z): " << vXYZrp << endl;
+ cout << " Visual Ref Pt (x, y, z): " << vXYZvrp << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGAircraft" << endl;
+ if (from == 1) cout << "Destroyed: FGAircraft" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+
+} // namespace JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGAircraft.h
+ Author: Jon S. Berndt
+ Date started: 12/12/98
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+12/12/98 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGAIRCRAFT_H
+#define FGAIRCRAFT_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# ifdef SG_HAVE_STD_INCLUDES
+# include <vector>
+# include <iterator>
+# else
+# include <vector.h>
+# include <iterator.h>
+# endif
+#else
+# include <vector>
+# include <iterator>
+#endif
+
+#include "FGModel.h"
+#include <input_output/FGXMLElement.h>
+#include <math/FGColumnVector3.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_AIRCRAFT "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Encapsulates an Aircraft and its systems.
+ Owns all the parts (other classes) which make up this aircraft. This includes
+ the Engines, Tanks, Propellers, Nozzles, Aerodynamic and Mass properties,
+ landing gear, etc. These constituent parts may actually run as separate
+ JSBSim models themselves, but the responsibility for initializing them and
+ for retrieving their force and moment contributions falls to FGAircraft.
+ @author Jon S. Berndt
+ @version $Id$
+ @see Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
+ Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
+ School, January 1994
+ @see D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
+ JSC 12960, July 1977
+ @see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
+ NASA-Ames", NASA CR-2497, January 1975
+ @see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
+ Wiley & Sons, 1979 ISBN 0-471-03032-5
+ @see Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
+ 1982 ISBN 0-471-08936-2
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGAircraft : public FGModel {
+public:
+ /** Constructor
+ @param Executive a pointer to the parent executive object */
+ FGAircraft(FGFDMExec *Executive);
+
+ /// Destructor
+ ~FGAircraft();
+
+ /** Runs the Aircraft model; called by the Executive
+ @see JSBSim.cpp documentation
+ @return false if no error */
+ bool Run(void);
+
+ /** Loads the aircraft.
+ The executive calls this method to load the aircraft into JSBSim.
+ @param el a pointer to the element tree
+ @return true if successful */
+ bool Load(Element* el);
+
+ /** Gets the aircraft name
+ @return the name of the aircraft as a string type */
+ inline string GetAircraftName(void) { return AircraftName; }
+
+ /// Gets the wing area
+ double GetWingArea(void) const { return WingArea; }
+ /// Gets the wing span
+ double GetWingSpan(void) const { return WingSpan; }
+ /// Gets the average wing chord
+ double Getcbar(void) const { return cbar; }
+ inline double GetWingIncidence(void) const { return WingIncidence; }
+ inline double GetHTailArea(void) const { return HTailArea; }
+ inline double GetHTailArm(void) const { return HTailArm; }
+ inline double GetVTailArea(void) const { return VTailArea; }
+ inline double GetVTailArm(void) const { return VTailArm; }
+ inline double Getlbarh(void) const { return lbarh; } // HTailArm / cbar
+ inline double Getlbarv(void) const { return lbarv; } // VTailArm / cbar
+ inline double Getvbarh(void) const { return vbarh; } // H. Tail Volume
+ inline double Getvbarv(void) const { return vbarv; } // V. Tail Volume
+ inline FGColumnVector3& GetMoments(void) { return vMoments; }
+ inline double GetMoments(int idx) const { return vMoments(idx); }
+ inline FGColumnVector3& GetForces(void) { return vForces; }
+ inline double GetForces(int idx) const { return vForces(idx); }
+ inline FGColumnVector3& GetBodyAccel(void) { return vBodyAccel; }
+ inline double GetBodyAccel(int idx) { return vBodyAccel(idx); }
+ inline FGColumnVector3& GetNcg (void) { return vNcg; }
+ inline double GetNcg(int idx) { return vNcg(idx); }
+ inline FGColumnVector3& GetXYZrp(void) { return vXYZrp; }
+ inline FGColumnVector3& GetXYZvrp(void) { return vXYZvrp; }
+ inline FGColumnVector3& GetXYZep(void) { return vXYZep; }
+ inline double GetXYZrp(int idx) const { return vXYZrp(idx); }
+ inline double GetXYZvrp(int idx) const { return vXYZvrp(idx); }
+ inline double GetXYZep(int idx) const { return vXYZep(idx); }
+ inline void SetAircraftName(string name) {AircraftName = name;}
+
+ double GetNlf(void);
+
+ inline FGColumnVector3& GetNwcg(void) { return vNwcg; }
+
+ void bind(void);
+ void unbind(void);
+
+private:
+ FGColumnVector3 vMoments;
+ FGColumnVector3 vForces;
+ FGColumnVector3 vXYZrp;
+ FGColumnVector3 vXYZvrp;
+ FGColumnVector3 vXYZep;
+ FGColumnVector3 vDXYZcg;
+ FGColumnVector3 vBodyAccel;
+ FGColumnVector3 vNcg;
+ FGColumnVector3 vNwcg;
+
+ double WingArea, WingSpan, cbar, WingIncidence;
+ double HTailArea, VTailArea, HTailArm, VTailArm;
+ double lbarh,lbarv,vbarh,vbarv;
+ string AircraftName;
+
+ void Debug(int from);
+};
+
+} // namespace JSBSim
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGAtmosphere.cpp
+ Author: Jon Berndt
+ Implementation of 1959 Standard Atmosphere added by Tony Peden
+ Date started: 11/24/98
+ Purpose: Models the atmosphere
+ Called by: FGSimExec
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+Models the atmosphere. The equation used below was determined by a third order
+curve fit using Excel. The data is from the ICAO atmosphere model.
+
+HISTORY
+--------------------------------------------------------------------------------
+11/24/98 JSB Created
+07/23/99 TP Added implementation of 1959 Standard Atmosphere
+ Moved calculation of Mach number to FGPropagate
+ Later updated to '76 model
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+COMMENTS, REFERENCES, and NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[1] Anderson, John D. "Introduction to Flight, Third Edition", McGraw-Hill,
+ 1989, ISBN 0-07-001641-0
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGAtmosphere.h"
+#include <FGState.h>
+#include <FGFDMExec.h>
+#include "FGAircraft.h"
+#include "FGPropagate.h"
+#include "FGInertial.h"
+#include <input_output/FGPropertyManager.h>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_ATMOSPHERE;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+FGAtmosphere::FGAtmosphere(FGFDMExec* fdmex) : FGModel(fdmex)
+{
+ Name = "FGAtmosphere";
+ lastIndex = 0;
+ h = 0.0;
+ psiw = 0.0;
+ htab[0]=0;
+ htab[1]=36089.239;
+ htab[2]=65616.798;
+ htab[3]=104986.878;
+ htab[4]=154199.475;
+ htab[5]=170603.675;
+ htab[6]=200131.234;
+ htab[7]=259186.352; //ft.
+
+ MagnitudedAccelDt = MagnitudeAccel = Magnitude = 0.0;
+// turbType = ttNone;
+ turbType = ttStandard;
+// turbType = ttBerndt;
+ TurbGain = 0.0;
+ TurbRate = 1.0;
+
+ T_dev_sl = T_dev = delta_T = 0.0;
+ StandardTempOnly = false;
+
+ bind();
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGAtmosphere::~FGAtmosphere()
+{
+ unbind();
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGAtmosphere::InitModel(void)
+{
+ FGModel::InitModel();
+
+ UseInternal(); // this is the default
+
+ Calculate(h);
+ StdSLtemperature = SLtemperature = 518.67;
+ StdSLpressure = SLpressure = 2116.22;
+ StdSLdensity = SLdensity = 0.00237767;
+ StdSLsoundspeed = SLsoundspeed = sqrt(SHRatio*Reng*StdSLtemperature);
+ rSLtemperature = 1.0/StdSLtemperature;
+ rSLpressure = 1.0/StdSLpressure;
+ rSLdensity = 1.0/StdSLdensity;
+ rSLsoundspeed = 1.0/StdSLsoundspeed;
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGAtmosphere::Run(void)
+{
+ if (FGModel::Run()) return true;
+ if (FDMExec->Holding()) return false;
+
+ T_dev = 0.0;
+ h = Propagate->Geth();
+
+ if (!useExternal) {
+ Calculate(h);
+ CalculateDerived();
+ } else {
+ CalculateDerived();
+ }
+
+ Debug(2);
+ return false;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+//
+// See reference 1
+
+void FGAtmosphere::Calculate(double altitude)
+{
+ double slope, reftemp, refpress;
+ int i = 0;
+
+ i = lastIndex;
+ if (altitude < htab[lastIndex]) {
+ if (altitude <= 0) {
+ i = 0;
+ altitude=0;
+ } else {
+ i = lastIndex-1;
+ while (htab[i] > altitude) i--;
+ }
+ } else if (altitude > htab[lastIndex+1]) {
+ if (altitude >= htab[7]) {
+ i = 7;
+ altitude = htab[7];
+ } else {
+ i = lastIndex+1;
+ while (htab[i+1] < altitude) i++;
+ }
+ }
+
+ switch(i) {
+ case 1: // 36089 ft.
+ slope = 0;
+ reftemp = 389.97;
+ refpress = 472.452;
+ //refdens = 0.000706032;
+ break;
+ case 2: // 65616 ft.
+ slope = 0.00054864;
+ reftemp = 389.97;
+ refpress = 114.636;
+ //refdens = 0.000171306;
+ break;
+ case 3: // 104986 ft.
+ slope = 0.00153619;
+ reftemp = 411.57;
+ refpress = 8.36364;
+ //refdens = 1.18422e-05;
+ break;
+ case 4: // 154199 ft.
+ slope = 0;
+ reftemp = 487.17;
+ refpress = 0.334882;
+ //refdens = 4.00585e-7;
+ break;
+ case 5: // 170603 ft.
+ slope = -0.00109728;
+ reftemp = 487.17;
+ refpress = 0.683084;
+ //refdens = 8.17102e-7;
+ break;
+ case 6: // 200131 ft.
+ slope = -0.00219456;
+ reftemp = 454.17;
+ refpress = 0.00684986;
+ //refdens = 8.77702e-9;
+ break;
+ case 7: // 259186 ft.
+ slope = 0;
+ reftemp = 325.17;
+ refpress = 0.000122276;
+ //refdens = 2.19541e-10;
+ break;
+ case 0:
+ default: // sea level
+ slope = -0.00356616; // R/ft.
+ reftemp = 518.67; // R
+ refpress = 2116.22; // psf
+ //refdens = 0.00237767; // slugs/cubic ft.
+ break;
+
+ }
+
+ // If delta_T is set, then that is our temperature deviation at any altitude.
+ // If not, then we'll estimate a deviation based on the sea level deviation (if set).
+
+ if(!StandardTempOnly) {
+ T_dev = 0.0;
+ if (delta_T != 0.0) {
+ T_dev = delta_T;
+ } else {
+ if ((altitude < 36089.239) && (T_dev_sl != 0.0)) {
+ T_dev = T_dev_sl * ( 1.0 - (altitude/36089.239));
+ }
+ }
+ reftemp+=T_dev;
+ }
+
+ if (slope == 0) {
+ intTemperature = reftemp;
+ intPressure = refpress*exp(-Inertial->SLgravity()/(reftemp*Reng)*(altitude-htab[i]));
+ intDensity = intPressure/(Reng*intTemperature);
+ } else {
+ intTemperature = reftemp+slope*(altitude-htab[i]);
+ intPressure = refpress*pow(intTemperature/reftemp,-Inertial->SLgravity()/(slope*Reng));
+ intDensity = intPressure/(Reng*intTemperature);
+ }
+
+ lastIndex=i;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// Calculate parameters derived from T, P and rho
+
+void FGAtmosphere::CalculateDerived(void)
+{
+ T_dev = (*temperature) - GetTemperature(h);
+ density_altitude = h + T_dev * 66.7;
+
+ if (turbType != ttStandard) {
+ Turbulence();
+ vWindNED += vTurbulence;
+ }
+ if (vWindNED(1) != 0.0) psiw = atan2( vWindNED(2), vWindNED(1) );
+ if (psiw < 0) psiw += 2*M_PI;
+
+ soundspeed = sqrt(SHRatio*Reng*(*temperature));
+}
+
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// Get the standard atmospheric properties at a specified altitude
+
+void FGAtmosphere::GetStdAtmosphere(double altitude) {
+ StandardTempOnly = true;
+ Calculate(altitude);
+ StandardTempOnly = false;
+ atmosphere.Temperature = intTemperature;
+ atmosphere.Pressure = intPressure;
+ atmosphere.Density = intDensity;
+
+ // Reset the internal atmospheric state
+ Calculate(h);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// Get the standard pressure at a specified altitude
+
+double FGAtmosphere::GetPressure(double altitude) {
+ GetStdAtmosphere(altitude);
+ return atmosphere.Pressure;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// Get the standard temperature at a specified altitude
+
+double FGAtmosphere::GetTemperature(double altitude) {
+ GetStdAtmosphere(altitude);
+ return atmosphere.Temperature;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// Get the standard density at a specified altitude
+
+double FGAtmosphere::GetDensity(double altitude) {
+ GetStdAtmosphere(altitude);
+ return atmosphere.Density;
+}
+
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// square a value, but preserve the original sign
+
+static inline double square_signed (double value)
+{
+ if (value < 0)
+ return value * value * -1;
+ else
+ return value * value;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGAtmosphere::Turbulence(void)
+{
+ switch (turbType) {
+ case ttStandard: {
+ vDirectiondAccelDt(eX) = 1 - 2.0*(double(rand())/double(RAND_MAX));
+ vDirectiondAccelDt(eY) = 1 - 2.0*(double(rand())/double(RAND_MAX));
+ vDirectiondAccelDt(eZ) = 1 - 2.0*(double(rand())/double(RAND_MAX));
+
+ MagnitudedAccelDt = 1 - 2.0*(double(rand())/double(RAND_MAX)) - Magnitude;
+ // Scale the magnitude so that it moves
+ // away from the peaks
+ MagnitudedAccelDt = ((MagnitudedAccelDt - Magnitude) /
+ (1 + fabs(Magnitude)));
+ MagnitudeAccel += MagnitudedAccelDt*rate*TurbRate*State->Getdt();
+ Magnitude += MagnitudeAccel*rate*State->Getdt();
+
+ vDirectiondAccelDt.Normalize();
+
+ // deemphasise non-vertical forces
+ vDirectiondAccelDt(eX) = square_signed(vDirectiondAccelDt(eX));
+ vDirectiondAccelDt(eY) = square_signed(vDirectiondAccelDt(eY));
+
+ vDirectionAccel += vDirectiondAccelDt*rate*TurbRate*State->Getdt();
+ vDirectionAccel.Normalize();
+ vDirection += vDirectionAccel*rate*State->Getdt();
+
+ vDirection.Normalize();
+
+ // Diminish turbulence within three wingspans
+ // of the ground
+ vTurbulence = TurbGain * Magnitude * vDirection;
+ double HOverBMAC = Auxiliary->GetHOverBMAC();
+ if (HOverBMAC < 3.0)
+ vTurbulence *= (HOverBMAC / 3.0) * (HOverBMAC / 3.0);
+
+ vTurbulenceGrad = TurbGain*MagnitudeAccel * vDirection;
+
+ vBodyTurbGrad = Propagate->GetTl2b()*vTurbulenceGrad;
+
+ if (Aircraft->GetWingSpan() > 0) {
+ vTurbPQR(eP) = vBodyTurbGrad(eY)/Aircraft->GetWingSpan();
+ } else {
+ vTurbPQR(eP) = vBodyTurbGrad(eY)/30.0;
+ }
+// if (Aircraft->GetHTailArm() != 0.0)
+// vTurbPQR(eQ) = vBodyTurbGrad(eZ)/Aircraft->GetHTailArm();
+// else
+// vTurbPQR(eQ) = vBodyTurbGrad(eZ)/10.0;
+
+ if (Aircraft->GetVTailArm() > 0)
+ vTurbPQR(eR) = vBodyTurbGrad(eX)/Aircraft->GetVTailArm();
+ else
+ vTurbPQR(eR) = vBodyTurbGrad(eX)/10.0;
+
+ // Clear the horizontal forces
+ // actually felt by the plane, now
+ // that we've used them to calculate
+ // moments.
+ vTurbulence(eX) = 0.0;
+ vTurbulence(eY) = 0.0;
+
+ break;
+ }
+ case ttBerndt: {
+ vDirectiondAccelDt(eX) = 1 - 2.0*(double(rand())/double(RAND_MAX));
+ vDirectiondAccelDt(eY) = 1 - 2.0*(double(rand())/double(RAND_MAX));
+ vDirectiondAccelDt(eZ) = 1 - 2.0*(double(rand())/double(RAND_MAX));
+
+
+ MagnitudedAccelDt = 1 - 2.0*(double(rand())/double(RAND_MAX)) - Magnitude;
+ MagnitudeAccel += MagnitudedAccelDt*rate*State->Getdt();
+ Magnitude += MagnitudeAccel*rate*State->Getdt();
+
+ vDirectiondAccelDt.Normalize();
+ vDirectionAccel += vDirectiondAccelDt*rate*State->Getdt();
+ vDirectionAccel.Normalize();
+ vDirection += vDirectionAccel*rate*State->Getdt();
+
+ // Diminish z-vector within two wingspans
+ // of the ground
+ double HOverBMAC = Auxiliary->GetHOverBMAC();
+ if (HOverBMAC < 2.0)
+ vDirection(eZ) *= HOverBMAC / 2.0;
+
+ vDirection.Normalize();
+
+ vTurbulence = TurbGain*Magnitude * vDirection;
+ vTurbulenceGrad = TurbGain*MagnitudeAccel * vDirection;
+
+ vBodyTurbGrad = Propagate->GetTl2b()*vTurbulenceGrad;
+ vTurbPQR(eP) = vBodyTurbGrad(eY)/Aircraft->GetWingSpan();
+ if (Aircraft->GetHTailArm() > 0)
+ vTurbPQR(eQ) = vBodyTurbGrad(eZ)/Aircraft->GetHTailArm();
+ else
+ vTurbPQR(eQ) = vBodyTurbGrad(eZ)/10.0;
+
+ if (Aircraft->GetVTailArm() > 0)
+ vTurbPQR(eR) = vBodyTurbGrad(eX)/Aircraft->GetVTailArm();
+ else
+ vTurbPQR(eR) = vBodyTurbGrad(eX)/10.0;
+
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGAtmosphere::UseExternal(void)
+{
+ temperature=&exTemperature;
+ pressure=&exPressure;
+ density=&exDensity;
+ useExternal=true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGAtmosphere::UseInternal(void)
+{
+ temperature=&intTemperature;
+ pressure=&intPressure;
+ density=&intDensity;
+ useExternal=false;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGAtmosphere::bind(void)
+{
+ typedef double (FGAtmosphere::*PMF)(int) const;
+ PropertyManager->Tie("atmosphere/T-R", this,
+ &FGAtmosphere::GetTemperature);
+ PropertyManager->Tie("atmosphere/rho-slugs_ft3", this,
+ &FGAtmosphere::GetDensity);
+// PropertyManager->Tie("atmosphere/P-psf", this,
+// &FGAtmosphere::GetPressure);
+ PropertyManager->Tie("atmosphere/a-fps", this,
+ &FGAtmosphere::GetSoundSpeed);
+ PropertyManager->Tie("atmosphere/T-sl-R", this,
+ &FGAtmosphere::GetTemperatureSL);
+ PropertyManager->Tie("atmosphere/rho-sl-slugs_ft3", this,
+ &FGAtmosphere::GetDensitySL);
+ PropertyManager->Tie("atmosphere/P-sl-psf", this,
+ &FGAtmosphere::GetPressureSL);
+ PropertyManager->Tie("atmosphere/a-sl-fps", this,
+ &FGAtmosphere::GetSoundSpeedSL);
+ PropertyManager->Tie("atmosphere/theta", this,
+ &FGAtmosphere::GetTemperatureRatio);
+ PropertyManager->Tie("atmosphere/sigma", this,
+ &FGAtmosphere::GetDensityRatio);
+ PropertyManager->Tie("atmosphere/delta", this,
+ &FGAtmosphere::GetPressureRatio);
+ PropertyManager->Tie("atmosphere/a-ratio", this,
+ &FGAtmosphere::GetSoundSpeedRatio);
+ PropertyManager->Tie("atmosphere/psiw-rad", this,
+ &FGAtmosphere::GetWindPsi);
+ PropertyManager->Tie("atmosphere/delta-T", this,
+ &FGAtmosphere::GetDeltaT, &FGAtmosphere::SetDeltaT);
+ PropertyManager->Tie("atmosphere/T-sl-dev-F", this,
+ &FGAtmosphere::GetSLTempDev, &FGAtmosphere::SetSLTempDev);
+ PropertyManager->Tie("atmosphere/density-altitude", this,
+ &FGAtmosphere::GetDensityAltitude);
+ PropertyManager->Tie("atmosphere/p-turb-rad_sec", this,1,
+ (PMF)&FGAtmosphere::GetTurbPQR);
+ PropertyManager->Tie("atmosphere/q-turb-rad_sec", this,2,
+ (PMF)&FGAtmosphere::GetTurbPQR);
+ PropertyManager->Tie("atmosphere/r-turb-rad_sec", this,3,
+ (PMF)&FGAtmosphere::GetTurbPQR);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGAtmosphere::unbind(void)
+{
+ PropertyManager->Untie("atmosphere/T-R");
+ PropertyManager->Untie("atmosphere/rho-slugs_ft3");
+// PropertyManager->Untie("atmosphere/P-psf");
+ PropertyManager->Untie("atmosphere/a-fps");
+ PropertyManager->Untie("atmosphere/T-sl-R");
+ PropertyManager->Untie("atmosphere/rho-sl-slugs_ft3");
+ PropertyManager->Untie("atmosphere/P-sl-psf");
+ PropertyManager->Untie("atmosphere/a-sl-fps");
+ PropertyManager->Untie("atmosphere/delta-T");
+ PropertyManager->Untie("atmosphere/T-sl-dev-F");
+ PropertyManager->Untie("atmosphere/density-altitude");
+ PropertyManager->Untie("atmosphere/theta");
+ PropertyManager->Untie("atmosphere/sigma");
+ PropertyManager->Untie("atmosphere/delta");
+ PropertyManager->Untie("atmosphere/a-ratio");
+ PropertyManager->Untie("atmosphere/psiw-rad");
+ PropertyManager->Untie("atmosphere/p-turb-rad_sec");
+ PropertyManager->Untie("atmosphere/q-turb-rad_sec");
+ PropertyManager->Untie("atmosphere/r-turb-rad_sec");
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGAtmosphere::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGAtmosphere" << endl;
+ if (from == 1) cout << "Destroyed: FGAtmosphere" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 128) { // Turbulence
+ if (frame == 0 && from == 2) {
+ cout << "vTurbulence(X), vTurbulence(Y), vTurbulence(Z), "
+ << "vTurbulenceGrad(X), vTurbulenceGrad(Y), vTurbulenceGrad(Z), "
+ << "vDirection(X), vDirection(Y), vDirection(Z), "
+ << "Magnitude, "
+ << "vTurbPQR(P), vTurbPQR(Q), vTurbPQR(R), " << endl;
+ } else if (from == 2) {
+ cout << vTurbulence << ", " << vTurbulenceGrad << ", " << vDirection << ", " << Magnitude << ", " << vTurbPQR << endl;
+ }
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+
+} // namespace JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGAtmosphere.h
+ Author: Jon Berndt
+ Implementation of 1959 Standard Atmosphere added by Tony Peden
+ Date started: 11/24/98
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+11/24/98 JSB Created
+07/23/99 TP Added implementation of 1959 Standard Atmosphere
+ Moved calculation of Mach number to FGPropagate
+ Updated to '76 model
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGAtmosphere_H
+#define FGAtmosphere_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGModel.h"
+#include <math/FGColumnVector3.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_ATMOSPHERE "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models the standard atmosphere.
+ @author Tony Peden, Jon Berndt
+ @version $Id$
+ @see Anderson, John D. "Introduction to Flight, Third Edition", McGraw-Hill,
+ 1989, ISBN 0-07-001641-0
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGAtmosphere : public FGModel {
+public:
+
+ /// Constructor
+ FGAtmosphere(FGFDMExec*);
+ /// Destructor
+ ~FGAtmosphere();
+ /** Runs the Atmosphere model; called by the Executive
+ @return false if no error */
+ bool Run(void);
+ bool InitModel(void);
+
+ /// Returns the temperature in degrees Rankine.
+ inline double GetTemperature(void) const {return *temperature;}
+ /** Returns the density in slugs/ft^3.
+ <i>This function may <b>only</b> be used if Run() is called first.</i> */
+ inline double GetDensity(void) const {return *density;}
+ /// Returns the pressure in psf.
+ inline double GetPressure(void) const {return *pressure;}
+ /// Returns the standard pressure at a specified altitude
+ double GetPressure(double altitude);
+ /// Returns the standard temperature at a specified altitude
+ double GetTemperature(double altitude);
+ /// Returns the standard density at a specified altitude
+ double GetDensity(double altitude);
+ /// Returns the speed of sound in ft/sec.
+ inline double GetSoundSpeed(void) const {return soundspeed;}
+
+ /// Returns the sea level temperature in degrees Rankine.
+ inline double GetTemperatureSL(void) const { return SLtemperature; }
+ /// Returns the sea level density in slugs/ft^3
+ inline double GetDensitySL(void) const { return SLdensity; }
+ /// Returns the sea level pressure in psf.
+ inline double GetPressureSL(void) const { return SLpressure; }
+ /// Returns the sea level speed of sound in ft/sec.
+ inline double GetSoundSpeedSL(void) const { return SLsoundspeed; }
+
+ /// Returns the ratio of at-altitude temperature over the sea level value.
+ inline double GetTemperatureRatio(void) const { return (*temperature)*rSLtemperature; }
+ /// Returns the ratio of at-altitude density over the sea level value.
+ inline double GetDensityRatio(void) const { return (*density)*rSLdensity; }
+ /// Returns the ratio of at-altitude pressure over the sea level value.
+ inline double GetPressureRatio(void) const { return (*pressure)*rSLpressure; }
+ /// Returns the ratio of at-altitude sound speed over the sea level value.
+ inline double GetSoundSpeedRatio(void) const { return soundspeed*rSLsoundspeed; }
+
+ /// Tells the simulator to use an externally calculated atmosphere model.
+ void UseExternal(void);
+ /// Tells the simulator to use the internal atmosphere model.
+ void UseInternal(void); //this is the default
+ /// Gets the boolean that tells if the external atmosphere model is being used.
+ bool External(void) { return useExternal; }
+
+ /// Provides the external atmosphere model with an interface to set the temperature.
+ inline void SetExTemperature(double t) { exTemperature=t; }
+ /// Provides the external atmosphere model with an interface to set the density.
+ inline void SetExDensity(double d) { exDensity=d; }
+ /// Provides the external atmosphere model with an interface to set the pressure.
+ inline void SetExPressure(double p) { exPressure=p; }
+
+ /// Sets the temperature deviation at sea-level in degrees Fahrenheit
+ inline void SetSLTempDev(double d) { T_dev_sl = d; }
+ /// Gets the temperature deviation at sea-level in degrees Fahrenheit
+ inline double GetSLTempDev(void) const { return T_dev_sl; }
+ /// Sets the current delta-T in degrees Fahrenheit
+ inline void SetDeltaT(double d) { delta_T = d; }
+ /// Gets the current delta-T in degrees Fahrenheit
+ inline double GetDeltaT(void) const { return delta_T; }
+ /// Gets the at-altitude temperature deviation in degrees Fahrenheit
+ inline double GetTempDev(void) const { return T_dev; }
+ /// Gets the density altitude in feet
+ inline double GetDensityAltitude(void) const { return density_altitude; }
+
+ /// Sets the wind components in NED frame.
+ inline void SetWindNED(double wN, double wE, double wD) { vWindNED(1)=wN; vWindNED(2)=wE; vWindNED(3)=wD;}
+
+ /// Retrieves the wind components in NED frame.
+ inline FGColumnVector3& GetWindNED(void) { return vWindNED; }
+
+ /** Retrieves the wind direction. The direction is defined as north=0 and
+ increases counterclockwise. The wind heading is returned in radians.*/
+ inline double GetWindPsi(void) const { return psiw; }
+
+ inline void SetTurbGain(double tt) {TurbGain = tt;}
+ inline void SetTurbRate(double tt) {TurbRate = tt;}
+
+ inline double GetTurbPQR(int idx) const {return vTurbPQR(idx);}
+ inline FGColumnVector3& GetTurbPQR(void) {return vTurbPQR;}
+
+ void bind(void);
+ void unbind(void);
+
+
+protected:
+ double rho;
+
+ enum tType {ttStandard, ttBerndt, ttNone} turbType;
+ struct atmType {double Temperature; double Pressure; double Density;};
+
+ int lastIndex;
+ double h;
+ double htab[8];
+ double StdSLtemperature,StdSLdensity,StdSLpressure,StdSLsoundspeed;
+ double rSLtemperature,rSLdensity,rSLpressure,rSLsoundspeed; //reciprocals
+ double SLtemperature,SLdensity,SLpressure,SLsoundspeed;
+ double *temperature,*density,*pressure;
+ double soundspeed;
+ bool useExternal;
+ double exTemperature,exDensity,exPressure;
+ double intTemperature, intDensity, intPressure;
+ double T_dev_sl, T_dev, delta_T, density_altitude;
+ atmType atmosphere;
+ bool StandardTempOnly;
+
+ double MagnitudedAccelDt, MagnitudeAccel, Magnitude;
+ double TurbGain;
+ double TurbRate;
+ FGColumnVector3 vDirectiondAccelDt;
+ FGColumnVector3 vDirectionAccel;
+ FGColumnVector3 vDirection;
+ FGColumnVector3 vTurbulence;
+ FGColumnVector3 vTurbulenceGrad;
+ FGColumnVector3 vBodyTurbGrad;
+ FGColumnVector3 vTurbPQR;
+
+ FGColumnVector3 vWindNED;
+ double psiw;
+
+ /// Calculate the atmosphere for the given altitude, including effects of temperature deviation.
+ void Calculate(double altitude);
+ /// Calculate atmospheric properties other than the basic T, P and rho.
+ void CalculateDerived(void);
+ /// Get T, P and rho for a standard atmosphere at the given altitude.
+ void GetStdAtmosphere(double altitude);
+ void Turbulence(void);
+ void Debug(int from);
+};
+
+} // namespace JSBSim
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGAuxiliary.cpp
+ Author: Tony Peden, Jon Berndt
+ Date started: 01/26/99
+ Purpose: Calculates additional parameters needed by the visual system, etc.
+ Called by: FGSimExec
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+This class calculates various auxiliary parameters.
+
+REFERENCES
+ Anderson, John D. "Introduction to Flight", 3rd Edition, McGraw-Hill, 1989
+ pgs. 112-126
+HISTORY
+--------------------------------------------------------------------------------
+01/26/99 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGAuxiliary.h"
+#include "FGAerodynamics.h"
+#include "FGPropagate.h"
+#include "FGAtmosphere.h"
+#include <FGState.h>
+#include <FGFDMExec.h>
+#include "FGAircraft.h"
+#include "FGInertial.h"
+#include <input_output/FGPropertyManager.h>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_AUXILIARY;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+FGAuxiliary::FGAuxiliary(FGFDMExec* fdmex) : FGModel(fdmex)
+{
+ Name = "FGAuxiliary";
+ vcas = veas = pt = tat = 0;
+ psl = rhosl = 1;
+ earthPosAngle = 0.0;
+ qbar = 0;
+ qbarUW = 0.0;
+ qbarUV = 0.0;
+ Mach = 0.0;
+ alpha = beta = 0.0;
+ adot = bdot = 0.0;
+ gamma = Vt = Vground = 0.0;
+ psigt = 0.0;
+ day_of_year = 1;
+ seconds_in_day = 0.0;
+ hoverbmac = hoverbcg = 0.0;
+
+ vPilotAccel.InitMatrix();
+ vPilotAccelN.InitMatrix();
+ vToEyePt.InitMatrix();
+ vAeroPQR.InitMatrix();
+ vEulerRates.InitMatrix();
+
+ bind();
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGAuxiliary::~FGAuxiliary()
+{
+ unbind();
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGAuxiliary::Run()
+{
+ double A,B,D, hdot_Vt;
+ const FGColumnVector3& vPQR = Propagate->GetPQR();
+ const FGColumnVector3& vUVW = Propagate->GetUVW();
+ const FGColumnVector3& vUVWdot = Propagate->GetUVWdot();
+ const FGColumnVector3& vVel = Propagate->GetVel();
+
+ if (FGModel::Run()) return true;
+ if (FDMExec->Holding()) return false;
+
+ p = Atmosphere->GetPressure();
+ rhosl = Atmosphere->GetDensitySL();
+ psl = Atmosphere->GetPressureSL();
+ sat = Atmosphere->GetTemperature();
+
+// Rotation
+
+ double cTht = Propagate->GetCosEuler(eTht);
+ double cPhi = Propagate->GetCosEuler(ePhi);
+ double sPhi = Propagate->GetSinEuler(ePhi);
+
+ vEulerRates(eTht) = vPQR(eQ)*cPhi - vPQR(eR)*sPhi;
+ if (cTht != 0.0) {
+ vEulerRates(ePsi) = (vPQR(eQ)*sPhi + vPQR(eR)*cPhi)/cTht;
+ vEulerRates(ePhi) = vPQR(eP) + vEulerRates(ePsi)*sPhi;
+ }
+
+// 12/16/2005, JSB: For ground handling purposes, at this time, let's ramp
+// in the effects of wind from 10 fps to 30 fps when there is weight on the
+// landing gear wheels.
+
+ if (GroundReactions->GetWOW() && vUVW(eU) < 10) {
+ vAeroPQR = vPQR;
+ vAeroUVW = vUVW;
+ } else if (GroundReactions->GetWOW() && vUVW(eU) < 30) {
+ double factor = (vUVW(eU) - 10.0)/20.0;
+ vAeroPQR = vPQR + factor*Atmosphere->GetTurbPQR();
+ vAeroUVW = vUVW + factor*Propagate->GetTl2b()*Atmosphere->GetWindNED();
+ } else {
+ vAeroPQR = vPQR + Atmosphere->GetTurbPQR();
+ vAeroUVW = vUVW + Propagate->GetTl2b()*Atmosphere->GetWindNED();
+ }
+
+ Vt = vAeroUVW.Magnitude();
+ if ( Vt > 0.05) {
+ if (vAeroUVW(eW) != 0.0)
+ alpha = vAeroUVW(eU)*vAeroUVW(eU) > 0.0 ? atan2(vAeroUVW(eW), vAeroUVW(eU)) : 0.0;
+ if (vAeroUVW(eV) != 0.0)
+ beta = vAeroUVW(eU)*vAeroUVW(eU)+vAeroUVW(eW)*vAeroUVW(eW) > 0.0 ? atan2(vAeroUVW(eV),
+ sqrt(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW))) : 0.0;
+
+ double mUW = (vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW));
+ double signU=1;
+ if (vAeroUVW(eU) != 0.0)
+ signU = vAeroUVW(eU)/fabs(vAeroUVW(eU));
+
+ if ( (mUW == 0.0) || (Vt == 0.0) ) {
+ adot = 0.0;
+ bdot = 0.0;
+ } else {
+ adot = (vAeroUVW(eU)*vUVWdot(eW) - vAeroUVW(eW)*vUVWdot(eU))/mUW;
+ bdot = (signU*mUW*vUVWdot(eV) - vAeroUVW(eV)*(vAeroUVW(eU)*vUVWdot(eU)
+ + vAeroUVW(eW)*vUVWdot(eW)))/(Vt*Vt*sqrt(mUW));
+ }
+ } else {
+ alpha = beta = adot = bdot = 0;
+ }
+
+ qbar = 0.5*Atmosphere->GetDensity()*Vt*Vt;
+ qbarUW = 0.5*Atmosphere->GetDensity()*(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW));
+ qbarUV = 0.5*Atmosphere->GetDensity()*(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eV)*vAeroUVW(eV));
+ Mach = Vt / Atmosphere->GetSoundSpeed();
+ MachU = vMachUVW(eU) = vAeroUVW(eU) / Atmosphere->GetSoundSpeed();
+ vMachUVW(eV) = vAeroUVW(eV) / Atmosphere->GetSoundSpeed();
+ vMachUVW(eW) = vAeroUVW(eW) / Atmosphere->GetSoundSpeed();
+
+// Position
+
+ Vground = sqrt( vVel(eNorth)*vVel(eNorth) + vVel(eEast)*vVel(eEast) );
+
+ if (vVel(eNorth) == 0) psigt = 0;
+ else psigt = atan2(vVel(eEast), vVel(eNorth));
+
+ if (psigt < 0.0) psigt += 2*M_PI;
+
+ if (Vt != 0) {
+ hdot_Vt = -vVel(eDown)/Vt;
+ if (fabs(hdot_Vt) <= 1) gamma = asin(hdot_Vt);
+ } else {
+ gamma = 0.0;
+ }
+
+ tat = sat*(1 + 0.2*Mach*Mach); // Total Temperature, isentropic flow
+ tatc = RankineToCelsius(tat);
+
+ if (MachU < 1) { // Calculate total pressure assuming isentropic flow
+ pt = p*pow((1 + 0.2*MachU*MachU),3.5);
+ } else {
+ // Use Rayleigh pitot tube formula for normal shock in front of pitot tube
+ B = 5.76*MachU*MachU/(5.6*MachU*MachU - 0.8);
+ D = (2.8*MachU*MachU-0.4)*0.4167;
+ pt = p*pow(B,3.5)*D;
+ }
+
+ A = pow(((pt-p)/psl+1),0.28571);
+ if (MachU > 0.0) {
+ vcas = sqrt(7*psl/rhosl*(A-1));
+ veas = sqrt(2*qbar/rhosl);
+ } else {
+ vcas = veas = 0.0;
+ }
+
+ vPilotAccel.InitMatrix();
+ if ( Vt > 1.0 ) {
+ vPilotAccel = Aerodynamics->GetForces()
+ + Propulsion->GetForces()
+ + GroundReactions->GetForces();
+ vPilotAccel /= MassBalance->GetMass();
+ vToEyePt = MassBalance->StructuralToBody(Aircraft->GetXYZep());
+ vPilotAccel += Propagate->GetPQRdot() * vToEyePt;
+ vPilotAccel += vPQR * (vPQR * vToEyePt);
+ } else {
+ vPilotAccel = Propagate->GetTl2b() * FGColumnVector3( 0.0, 0.0, Inertial->gravity() );
+ }
+
+ vPilotAccelN = vPilotAccel/Inertial->gravity();
+
+ earthPosAngle += State->Getdt()*Inertial->omega();
+
+ // VRP computation
+ const FGLocation& vLocation = Propagate->GetLocation();
+ FGColumnVector3 vrpStructural = Aircraft->GetXYZvrp();
+ FGColumnVector3 vrpBody = MassBalance->StructuralToBody( vrpStructural );
+ FGColumnVector3 vrpLocal = Propagate->GetTb2l() * vrpBody;
+ vLocationVRP = vLocation.LocalToLocation( vrpLocal );
+
+ // Recompute some derived values now that we know the dependent parameters values ...
+ hoverbcg = Propagate->GetDistanceAGL() / Aircraft->GetWingSpan();
+
+ FGColumnVector3 vMac = Propagate->GetTb2l()*MassBalance->StructuralToBody(Aircraft->GetXYZrp());
+ hoverbmac = (Propagate->GetDistanceAGL() + vMac(3)) / Aircraft->GetWingSpan();
+
+ return false;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGAuxiliary::GetHeadWind(void)
+{
+ double psiw,vw;
+
+ psiw = Atmosphere->GetWindPsi();
+ vw = Atmosphere->GetWindNED().Magnitude();
+
+ return vw*cos(psiw - Propagate->GetEuler(ePsi));
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGAuxiliary::GetCrossWind(void)
+{
+ double psiw,vw;
+
+ psiw = Atmosphere->GetWindPsi();
+ vw = Atmosphere->GetWindNED().Magnitude();
+
+ return vw*sin(psiw - Propagate->GetEuler(ePsi));
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGAuxiliary::bind(void)
+{
+ typedef double (FGAuxiliary::*PMF)(int) const;
+ typedef double (FGAuxiliary::*PF)(void) const;
+ PropertyManager->Tie("velocities/vc-fps", this, &FGAuxiliary::GetVcalibratedFPS);
+ PropertyManager->Tie("velocities/vc-kts", this, &FGAuxiliary::GetVcalibratedKTS);
+ PropertyManager->Tie("velocities/ve-fps", this, &FGAuxiliary::GetVequivalentFPS);
+ PropertyManager->Tie("velocities/ve-kts", this, &FGAuxiliary::GetVequivalentKTS);
+ PropertyManager->Tie("velocities/machU", this, &FGAuxiliary::GetMachU);
+ PropertyManager->Tie("velocities/tat-r", this, &FGAuxiliary::GetTotalTemperature);
+ PropertyManager->Tie("velocities/tat-c", this, &FGAuxiliary::GetTAT_C);
+ PropertyManager->Tie("velocities/pt-lbs_sqft", this, &FGAuxiliary::GetTotalPressure);
+ PropertyManager->Tie("velocities/p-aero-rad_sec", this, eX, (PMF)&FGAuxiliary::GetAeroPQR);
+ PropertyManager->Tie("velocities/q-aero-rad_sec", this, eY, (PMF)&FGAuxiliary::GetAeroPQR);
+ PropertyManager->Tie("velocities/r-aero-rad_sec", this, eZ, (PMF)&FGAuxiliary::GetAeroPQR);
+ PropertyManager->Tie("velocities/phidot-rad_sec", this, ePhi, (PMF)&FGAuxiliary::GetEulerRates);
+ PropertyManager->Tie("velocities/thetadot-rad_sec", this, eTht, (PMF)&FGAuxiliary::GetEulerRates);
+ PropertyManager->Tie("velocities/psidot-rad_sec", this, ePsi, (PMF)&FGAuxiliary::GetEulerRates);
+ PropertyManager->Tie("velocities/u-aero-fps", this, eU, (PMF)&FGAuxiliary::GetAeroUVW);
+ PropertyManager->Tie("velocities/v-aero-fps", this, eV, (PMF)&FGAuxiliary::GetAeroUVW);
+ PropertyManager->Tie("velocities/w-aero-fps", this, eW, (PMF)&FGAuxiliary::GetAeroUVW);
+ PropertyManager->Tie("velocities/vt-fps", this, &FGAuxiliary::GetVt, &FGAuxiliary::SetVt, true);
+ PropertyManager->Tie("velocities/mach", this, &FGAuxiliary::GetMach, &FGAuxiliary::SetMach, true);
+ PropertyManager->Tie("velocities/vg-fps", this, &FGAuxiliary::GetVground);
+ PropertyManager->Tie("accelerations/a-pilot-x-ft_sec2", this, eX, (PMF)&FGAuxiliary::GetPilotAccel);
+ PropertyManager->Tie("accelerations/a-pilot-y-ft_sec2", this, eY, (PMF)&FGAuxiliary::GetPilotAccel);
+ PropertyManager->Tie("accelerations/a-pilot-z-ft_sec2", this, eZ, (PMF)&FGAuxiliary::GetPilotAccel);
+ PropertyManager->Tie("accelerations/n-pilot-x-norm", this, eX, (PMF)&FGAuxiliary::GetNpilot);
+ PropertyManager->Tie("accelerations/n-pilot-y-norm", this, eY, (PMF)&FGAuxiliary::GetNpilot);
+ PropertyManager->Tie("accelerations/n-pilot-z-norm", this, eZ, (PMF)&FGAuxiliary::GetNpilot);
+ PropertyManager->Tie("position/epa-rad", this, &FGAuxiliary::GetEarthPositionAngle);
+ /* PropertyManager->Tie("atmosphere/headwind-fps", this, &FGAuxiliary::GetHeadWind, true);
+ PropertyManager->Tie("atmosphere/crosswind-fps", this, &FGAuxiliary::GetCrossWind, true); */
+ PropertyManager->Tie("aero/alpha-rad", this, (PF)&FGAuxiliary::Getalpha, &FGAuxiliary::Setalpha, true);
+ PropertyManager->Tie("aero/beta-rad", this, (PF)&FGAuxiliary::Getbeta, &FGAuxiliary::Setbeta, true);
+ PropertyManager->Tie("aero/mag-beta-rad", this, (PF)&FGAuxiliary::GetMagBeta);
+ PropertyManager->Tie("aero/alpha-deg", this, inDegrees, (PMF)&FGAuxiliary::Getalpha);
+ PropertyManager->Tie("aero/beta-deg", this, inDegrees, (PMF)&FGAuxiliary::Getbeta);
+ PropertyManager->Tie("aero/mag-beta-deg", this, inDegrees, (PMF)&FGAuxiliary::GetMagBeta);
+ PropertyManager->Tie("aero/qbar-psf", this, &FGAuxiliary::Getqbar, &FGAuxiliary::Setqbar, true);
+ PropertyManager->Tie("aero/qbarUW-psf", this, &FGAuxiliary::GetqbarUW, &FGAuxiliary::SetqbarUW, true);
+ PropertyManager->Tie("aero/qbarUV-psf", this, &FGAuxiliary::GetqbarUV, &FGAuxiliary::SetqbarUV, true);
+ PropertyManager->Tie("aero/alphadot-rad_sec", this, (PF)&FGAuxiliary::Getadot, &FGAuxiliary::Setadot, true);
+ PropertyManager->Tie("aero/betadot-rad_sec", this, (PF)&FGAuxiliary::Getbdot, &FGAuxiliary::Setbdot, true);
+ PropertyManager->Tie("aero/alphadot-deg_sec", this, inDegrees, (PMF)&FGAuxiliary::Getadot);
+ PropertyManager->Tie("aero/betadot-deg_sec", this, inDegrees, (PMF)&FGAuxiliary::Getbdot);
+ PropertyManager->Tie("aero/h_b-cg-ft", this, &FGAuxiliary::GetHOverBCG);
+ PropertyManager->Tie("aero/h_b-mac-ft", this, &FGAuxiliary::GetHOverBMAC);
+ PropertyManager->Tie("flight-path/gamma-rad", this, &FGAuxiliary::GetGamma, &FGAuxiliary::SetGamma);
+ PropertyManager->Tie("flight-path/psi-gt-rad", this, &FGAuxiliary::GetGroundTrack);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGAuxiliary::unbind(void)
+{
+ PropertyManager->Untie("velocities/vc-fps");
+ PropertyManager->Untie("velocities/vc-kts");
+ PropertyManager->Untie("velocities/ve-fps");
+ PropertyManager->Untie("velocities/ve-kts");
+ PropertyManager->Untie("velocities/machU");
+ PropertyManager->Untie("velocities/tat-r");
+ PropertyManager->Untie("velocities/tat-c");
+ PropertyManager->Untie("velocities/p-aero-rad_sec");
+ PropertyManager->Untie("velocities/q-aero-rad_sec");
+ PropertyManager->Untie("velocities/r-aero-rad_sec");
+ PropertyManager->Untie("velocities/pt-lbs_sqft");
+ PropertyManager->Untie("velocities/phidot-rad_sec");
+ PropertyManager->Untie("velocities/thetadot-rad_sec");
+ PropertyManager->Untie("velocities/psidot-rad_sec");
+ PropertyManager->Untie("velocities/u-aero-fps");
+ PropertyManager->Untie("velocities/v-aero-fps");
+ PropertyManager->Untie("velocities/w-aero-fps");
+ PropertyManager->Untie("velocities/vt-fps");
+ PropertyManager->Untie("velocities/mach");
+ PropertyManager->Untie("velocities/vg-fps");
+ PropertyManager->Untie("accelerations/a-pilot-x-ft_sec2");
+ PropertyManager->Untie("accelerations/a-pilot-y-ft_sec2");
+ PropertyManager->Untie("accelerations/a-pilot-z-ft_sec2");
+ PropertyManager->Untie("accelerations/n-pilot-x-norm");
+ PropertyManager->Untie("accelerations/n-pilot-y-norm");
+ PropertyManager->Untie("accelerations/n-pilot-z-norm");
+ PropertyManager->Untie("position/epa-rad");
+ /* PropertyManager->Untie("atmosphere/headwind-fps");
+ PropertyManager->Untie("atmosphere/crosswind-fps"); */
+ PropertyManager->Untie("aero/qbar-psf");
+ PropertyManager->Untie("aero/qbarUW-psf");
+ PropertyManager->Untie("aero/qbarUV-psf");
+ PropertyManager->Untie("aero/alpha-rad");
+ PropertyManager->Untie("aero/beta-rad");
+ PropertyManager->Untie("aero/alpha-deg");
+ PropertyManager->Untie("aero/beta-deg");
+ PropertyManager->Untie("aero/alphadot-rad_sec");
+ PropertyManager->Untie("aero/betadot-rad_sec");
+ PropertyManager->Untie("aero/mag-beta-rad");
+ PropertyManager->Untie("aero/alphadot-deg_sec");
+ PropertyManager->Untie("aero/betadot-deg_sec");
+ PropertyManager->Untie("aero/mag-beta-deg");
+ PropertyManager->Untie("aero/h_b-cg-ft");
+ PropertyManager->Untie("aero/h_b-mac-ft");
+ PropertyManager->Untie("flight-path/gamma-rad");
+ PropertyManager->Untie("flight-path/psi-gt-rad");
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGAuxiliary::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGAuxiliary" << endl;
+ if (from == 1) cout << "Destroyed: FGAuxiliary" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ if (Mach > 100 || Mach < 0.00)
+ cout << "FGPropagate::Mach is out of bounds: " << Mach << endl;
+ if (qbar > 1e6 || qbar < 0.00)
+ cout << "FGPropagate::qbar is out of bounds: " << qbar << endl;
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+
+} // namespace JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGAuxiliary.h
+ Author: Jon Berndt
+ Date started: 01/26/99
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+11/22/98 JSB Created
+ 1/1/00 TP Added calcs and getters for VTAS, VCAS, VEAS, Vground, in knots
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGAUXILIARY_H
+#define FGAUXILIARY_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGModel.h"
+#include <math/FGColumnVector3.h>
+#include <math/FGLocation.h>
+#include "FGPropagate.h"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_AUXILIARY "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Encapsulates various uncategorized scheduled functions.
+ Pilot sensed accelerations are calculated here. This is used
+ for the coordinated turn ball instrument. Motion base platforms sometimes
+ use the derivative of pilot sensed accelerations as the driving parameter,
+ rather than straight accelerations.
+
+ The theory behind pilot-sensed calculations is presented:
+
+ For purposes of discussion and calculation, assume for a minute that the
+ pilot is in space and motionless in inertial space. She will feel
+ no accelerations. If the aircraft begins to accelerate along any axis or
+ axes (without rotating), the pilot will sense those accelerations. If
+ any rotational moment is applied, the pilot will sense an acceleration
+ due to that motion in the amount:
+
+ [wdot X R] + [w X (w X R)]
+ Term I Term II
+
+ where:
+
+ wdot = omegadot, the rotational acceleration rate vector
+ w = omega, the rotational rate vector
+ R = the vector from the aircraft CG to the pilot eyepoint
+
+ The sum total of these two terms plus the acceleration of the aircraft
+ body axis gives the acceleration the pilot senses in inertial space.
+ In the presence of a large body such as a planet, a gravity field also
+ provides an accelerating attraction. This acceleration can be transformed
+ from the reference frame of the planet so as to be expressed in the frame
+ of reference of the aircraft. This gravity field accelerating attraction
+ is felt by the pilot as a force on her tushie as she sits in her aircraft
+ on the runway awaiting takeoff clearance.
+
+ In JSBSim the acceleration of the body frame in inertial space is given
+ by the F = ma relation. If the vForces vector is divided by the aircraft
+ mass, the acceleration vector is calculated. The term wdot is equivalent
+ to the JSBSim vPQRdot vector, and the w parameter is equivalent to vPQR.
+ The radius R is calculated below in the vector vToEyePt.
+
+ @author Tony Peden, Jon Berndt
+ @version $Id$
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGAuxiliary : public FGModel {
+public:
+ /** Constructor
+ @param Executive a pointer to the parent executive object */
+ FGAuxiliary(FGFDMExec* Executive);
+
+ /// Destructor
+ ~FGAuxiliary();
+
+ /** Runs the Auxiliary routines; called by the Executive
+ @return false if no error */
+ bool Run(void);
+
+// GET functions
+
+ // Atmospheric parameters GET functions
+ double GetVcalibratedFPS(void) const { return vcas; }
+ double GetVcalibratedKTS(void) const { return vcas*fpstokts; }
+ double GetVequivalentFPS(void) const { return veas; }
+ double GetVequivalentKTS(void) const { return veas*fpstokts; }
+
+ // total pressure above is freestream total pressure for subsonic only
+ // for supersonic it is the 1D total pressure behind a normal shock
+ double GetTotalPressure(void) const { return pt; }
+ double GetTotalTemperature(void) const { return tat; }
+ double GetTAT_C(void) const { return tatc; }
+
+ double GetPilotAccel(int idx) const { return vPilotAccel(idx); }
+ double GetNpilot(int idx) const { return vPilotAccelN(idx); }
+ double GetAeroPQR(int axis) const { return vAeroPQR(axis); }
+ double GetEulerRates(int axis) const { return vEulerRates(axis); }
+
+ const FGColumnVector3& GetPilotAccel (void) const { return vPilotAccel; }
+ const FGColumnVector3& GetNpilot (void) const { return vPilotAccelN; }
+ const FGColumnVector3& GetAeroPQR (void) const { return vAeroPQR; }
+ const FGColumnVector3& GetEulerRates (void) const { return vEulerRates; }
+ const FGColumnVector3& GetAeroUVW (void) const { return vAeroUVW; }
+ const FGLocation& GetLocationVRP(void) const { return vLocationVRP; }
+
+ double GethVRP(void) const { return vLocationVRP.GetRadius() - Propagate->GetSeaLevelRadius(); }
+ double GetAeroUVW (int idx) const { return vAeroUVW(idx); }
+ double Getalpha (void) const { return alpha; }
+ double Getbeta (void) const { return beta; }
+ double Getadot (void) const { return adot; }
+ double Getbdot (void) const { return bdot; }
+ double GetMagBeta (void) const { return fabs(beta); }
+
+ double Getalpha (int unit) const { if (unit == inDegrees) return alpha*radtodeg;
+ else cerr << "Bad units" << endl; return 0.0;}
+ double Getbeta (int unit) const { if (unit == inDegrees) return beta*radtodeg;
+ else cerr << "Bad units" << endl; return 0.0;}
+ double Getadot (int unit) const { if (unit == inDegrees) return adot*radtodeg;
+ else cerr << "Bad units" << endl; return 0.0;}
+ double Getbdot (int unit) const { if (unit == inDegrees) return bdot*radtodeg;
+ else cerr << "Bad units" << endl; return 0.0;}
+ double GetMagBeta (int unit) const { if (unit == inDegrees) return fabs(beta)*radtodeg;
+ else cerr << "Bad units" << endl; return 0.0;}
+
+ double Getqbar (void) const { return qbar; }
+ double GetqbarUW (void) const { return qbarUW; }
+ double GetqbarUV (void) const { return qbarUV; }
+ double GetVt (void) const { return Vt; }
+ double GetVground (void) const { return Vground; }
+ double GetMach (void) const { return Mach; }
+ double GetMachU (void) const { return MachU; }
+
+ double GetHOverBCG(void) const { return hoverbcg; }
+ double GetHOverBMAC(void) const { return hoverbmac; }
+
+ double GetGamma(void) const { return gamma; }
+ double GetGroundTrack(void) const { return psigt; }
+ double GetEarthPositionAngle(void) const { return earthPosAngle; }
+
+ double GetHeadWind(void);
+ double GetCrossWind(void);
+
+// SET functions
+
+ void SetAeroUVW(FGColumnVector3 tt) { vAeroUVW = tt; }
+
+ void Setalpha (double tt) { alpha = tt; }
+ void Setbeta (double tt) { beta = tt; }
+ void Setqbar (double tt) { qbar = tt; }
+ void SetqbarUW (double tt) { qbarUW = tt; }
+ void SetqbarUV (double tt) { qbarUV = tt; }
+ void SetVt (double tt) { Vt = tt; }
+ void SetMach (double tt) { Mach=tt; }
+ void Setadot (double tt) { adot = tt; }
+ void Setbdot (double tt) { bdot = tt; }
+
+ void SetAB (double t1, double t2) { alpha=t1; beta=t2; }
+ void SetGamma (double tt) { gamma = tt; }
+
+// Time routines, SET and GET functions
+
+ void SetDayOfYear (int doy) { day_of_year = doy; }
+ void SetSecondsInDay (double sid) { seconds_in_day = sid; }
+
+ int GetDayOfYear (void) const { return day_of_year; }
+ double GetSecondsInDay (void) const { return seconds_in_day; }
+
+ void bind(void);
+ void unbind(void);
+
+private:
+ double vcas, veas;
+ double rhosl, rho, p, psl, pt, tat, sat, tatc; // Don't add a getter for pt!
+
+ FGColumnVector3 vPilotAccel;
+ FGColumnVector3 vPilotAccelN;
+ FGColumnVector3 vToEyePt;
+ FGColumnVector3 vAeroPQR;
+ FGColumnVector3 vAeroUVW;
+ FGColumnVector3 vEuler;
+ FGColumnVector3 vEulerRates;
+ FGColumnVector3 vMachUVW;
+ FGLocation vLocationVRP;
+
+ double Vt, Vground, Mach, MachU;
+ double qbar, qbarUW, qbarUV;
+ double alpha, beta;
+ double adot,bdot;
+ double psigt, gamma;
+ double seconds_in_day; // seconds since current GMT day began
+ int day_of_year; // GMT day, 1 .. 366
+
+ double earthPosAngle;
+ double hoverbcg, hoverbmac;
+
+ void Debug(int from);
+};
+
+} // namespace JSBSim
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGFCS.cpp
+ Author: Jon Berndt
+ Date started: 12/12/98
+ Purpose: Model the flight controls
+ Called by: FDMExec
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+This class models the flight controls for a specific airplane
+
+HISTORY
+--------------------------------------------------------------------------------
+12/12/98 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGFCS.h"
+#include <FGFDMExec.h>
+#include <input_output/FGPropertyManager.h>
+#include <fstream>
+
+#include <models/flight_control/FGFilter.h>
+#include <models/flight_control/FGDeadBand.h>
+#include <models/flight_control/FGGain.h>
+#include <models/flight_control/FGGradient.h>
+#include <models/flight_control/FGSwitch.h>
+#include <models/flight_control/FGSummer.h>
+#include <models/flight_control/FGKinemat.h>
+#include <models/flight_control/FGFCSFunction.h>
+#include <models/flight_control/FGSensor.h>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_FCS;
+
+#if defined(WIN32) && !defined(__CYGWIN__)
+#define snprintf _snprintf
+#endif
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGFCS::FGFCS(FGFDMExec* fdmex) : FGModel(fdmex)
+{
+ int i;
+ Name = "FGFCS";
+
+ DaCmd = DeCmd = DrCmd = DsCmd = DfCmd = DsbCmd = DspCmd = 0;
+ PTrimCmd = YTrimCmd = RTrimCmd = 0.0;
+ GearCmd = GearPos = 1; // default to gear down
+ LeftBrake = RightBrake = CenterBrake = 0.0;
+
+ bind();
+ for (i=0;i<=NForms;i++) {
+ DePos[i] = DaLPos[i] = DaRPos[i] = DrPos[i] = 0.0;
+ DfPos[i] = DsbPos[i] = DspPos[i] = 0.0;
+ }
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGFCS::~FGFCS()
+{
+ if (PropertyManager->HasNode("fcs")) unbind( PropertyManager->GetNode("fcs") );
+ if (PropertyManager->HasNode("ap")) unbind( PropertyManager->GetNode("ap") );
+ PropertyManager->Untie( "gear/gear-cmd-norm" );
+ PropertyManager->Untie( "gear/gear-pos-norm" );
+
+ ThrottleCmd.clear();
+ ThrottlePos.clear();
+ MixtureCmd.clear();
+ MixturePos.clear();
+ PropAdvanceCmd.clear();
+ PropAdvance.clear();
+ SteerPosDeg.clear();
+ PropFeatherCmd.clear();
+ PropFeather.clear();
+
+ unsigned int i;
+
+ for (i=0;i<APComponents.size();i++) delete APComponents[i];
+ for (i=0;i<FCSComponents.size();i++) delete FCSComponents[i];
+ for (i=0;i<sensors.size();i++) delete sensors[i];
+
+ APComponents.clear();
+ FCSComponents.clear();
+ sensors.clear();
+ interface_properties.clear();
+
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// Notes: In this logic the default engine commands are set. This is simply a
+// sort of safe-mode method in case the user has not defined control laws for
+// throttle, mixture, and prop-advance. The throttle, mixture, and prop advance
+// positions are set equal to the respective commands. Any control logic that is
+// actually present in the flight_control or autopilot section will override
+// these simple assignments.
+
+bool FGFCS::Run(void)
+{
+ unsigned int i;
+
+ if (FGModel::Run()) return true; // fast exit if nothing to do
+ if (FDMExec->Holding()) return false;
+
+ for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = ThrottleCmd[i];
+ for (i=0; i<MixturePos.size(); i++) MixturePos[i] = MixtureCmd[i];
+ for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i];
+ for (i=0; i<PropFeather.size(); i++) PropFeather[i] = PropFeatherCmd[i];
+
+
+ // Set the default steering angle
+ for (i=0; i<SteerPosDeg.size(); i++) {
+ FGLGear* gear = GroundReactions->GetGearUnit(i);
+ SteerPosDeg[i] = gear->GetDefaultSteerAngle( GetDsCmd() );
+ }
+
+ // Cycle through the sensor, autopilot, and flight control components
+ for (i=0; i<sensors.size(); i++) sensors[i]->Run();
+ for (i=0; i<APComponents.size(); i++) APComponents[i]->Run();
+ for (i=0; i<FCSComponents.size(); i++) FCSComponents[i]->Run();
+
+ return false;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::SetDaLPos( int form , double pos )
+{
+ switch(form) {
+ case ofRad:
+ DaLPos[ofRad] = pos;
+ DaLPos[ofDeg] = pos*radtodeg;
+ break;
+ case ofDeg:
+ DaLPos[ofRad] = pos*degtorad;
+ DaLPos[ofDeg] = pos;
+ break;
+ case ofNorm:
+ DaLPos[ofNorm] = pos;
+ }
+ DaLPos[ofMag] = fabs(DaLPos[ofRad]);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::SetDaRPos( int form , double pos )
+{
+ switch(form) {
+ case ofRad:
+ DaRPos[ofRad] = pos;
+ DaRPos[ofDeg] = pos*radtodeg;
+ break;
+ case ofDeg:
+ DaRPos[ofRad] = pos*degtorad;
+ DaRPos[ofDeg] = pos;
+ break;
+ case ofNorm:
+ DaRPos[ofNorm] = pos;
+ }
+ DaRPos[ofMag] = fabs(DaRPos[ofRad]);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::SetDePos( int form , double pos )
+{
+ switch(form) {
+ case ofRad:
+ DePos[ofRad] = pos;
+ DePos[ofDeg] = pos*radtodeg;
+ break;
+ case ofDeg:
+ DePos[ofRad] = pos*degtorad;
+ DePos[ofDeg] = pos;
+ break;
+ case ofNorm:
+ DePos[ofNorm] = pos;
+ }
+ DePos[ofMag] = fabs(DePos[ofRad]);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::SetDrPos( int form , double pos )
+{
+ switch(form) {
+ case ofRad:
+ DrPos[ofRad] = pos;
+ DrPos[ofDeg] = pos*radtodeg;
+ break;
+ case ofDeg:
+ DrPos[ofRad] = pos*degtorad;
+ DrPos[ofDeg] = pos;
+ break;
+ case ofNorm:
+ DrPos[ofNorm] = pos;
+ }
+ DrPos[ofMag] = fabs(DrPos[ofRad]);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::SetDfPos( int form , double pos )
+{
+ switch(form) {
+ case ofRad:
+ DfPos[ofRad] = pos;
+ DfPos[ofDeg] = pos*radtodeg;
+ break;
+ case ofDeg:
+ DfPos[ofRad] = pos*degtorad;
+ DfPos[ofDeg] = pos;
+ break;
+ case ofNorm:
+ DfPos[ofNorm] = pos;
+ }
+ DfPos[ofMag] = fabs(DfPos[ofRad]);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::SetDsbPos( int form , double pos )
+{
+ switch(form) {
+ case ofRad:
+ DsbPos[ofRad] = pos;
+ DsbPos[ofDeg] = pos*radtodeg;
+ break;
+ case ofDeg:
+ DsbPos[ofRad] = pos*degtorad;
+ DsbPos[ofDeg] = pos;
+ break;
+ case ofNorm:
+ DsbPos[ofNorm] = pos;
+ }
+ DsbPos[ofMag] = fabs(DsbPos[ofRad]);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::SetDspPos( int form , double pos )
+{
+ switch(form) {
+ case ofRad:
+ DspPos[ofRad] = pos;
+ DspPos[ofDeg] = pos*radtodeg;
+ break;
+ case ofDeg:
+ DspPos[ofRad] = pos*degtorad;
+ DspPos[ofDeg] = pos;
+ break;
+ case ofNorm:
+ DspPos[ofNorm] = pos;
+ }
+ DspPos[ofMag] = fabs(DspPos[ofRad]);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::SetThrottleCmd(int engineNum, double setting)
+{
+ unsigned int ctr;
+
+ if (engineNum < (int)ThrottlePos.size()) {
+ if (engineNum < 0) {
+ for (ctr=0;ctr<ThrottleCmd.size();ctr++) ThrottleCmd[ctr] = setting;
+ } else {
+ ThrottleCmd[engineNum] = setting;
+ }
+ } else {
+ cerr << "Throttle " << engineNum << " does not exist! " << ThrottleCmd.size()
+ << " engines exist, but attempted throttle command is for engine "
+ << engineNum << endl;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::SetThrottlePos(int engineNum, double setting)
+{
+ unsigned int ctr;
+
+ if (engineNum < (int)ThrottlePos.size()) {
+ if (engineNum < 0) {
+ for (ctr=0;ctr<ThrottlePos.size();ctr++) ThrottlePos[ctr] = setting;
+ } else {
+ ThrottlePos[engineNum] = setting;
+ }
+ } else {
+ cerr << "Throttle " << engineNum << " does not exist! " << ThrottlePos.size()
+ << " engines exist, but attempted throttle position setting is for engine "
+ << engineNum << endl;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGFCS::GetThrottleCmd(int engineNum) const
+{
+ if (engineNum < (int)ThrottlePos.size()) {
+ if (engineNum < 0) {
+ cerr << "Cannot get throttle value for ALL engines" << endl;
+ } else {
+ return ThrottleCmd[engineNum];
+ }
+ } else {
+ cerr << "Throttle " << engineNum << " does not exist! " << ThrottleCmd.size()
+ << " engines exist, but throttle setting for engine " << engineNum
+ << " is selected" << endl;
+ }
+ return 0.0;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGFCS::GetThrottlePos(int engineNum) const
+{
+ if (engineNum < (int)ThrottlePos.size()) {
+ if (engineNum < 0) {
+ cerr << "Cannot get throttle value for ALL engines" << endl;
+ } else {
+ return ThrottlePos[engineNum];
+ }
+ } else {
+ cerr << "Throttle " << engineNum << " does not exist! " << ThrottlePos.size()
+ << " engines exist, but attempted throttle position setting is for engine "
+ << engineNum << endl;
+ }
+ return 0.0;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::SetMixtureCmd(int engineNum, double setting)
+{
+ unsigned int ctr;
+
+ if (engineNum < (int)ThrottlePos.size()) {
+ if (engineNum < 0) {
+ for (ctr=0;ctr<MixtureCmd.size();ctr++) MixtureCmd[ctr] = setting;
+ } else {
+ MixtureCmd[engineNum] = setting;
+ }
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::SetMixturePos(int engineNum, double setting)
+{
+ unsigned int ctr;
+
+ if (engineNum < (int)ThrottlePos.size()) {
+ if (engineNum < 0) {
+ for (ctr=0;ctr<=MixtureCmd.size();ctr++) MixturePos[ctr] = MixtureCmd[ctr];
+ } else {
+ MixturePos[engineNum] = setting;
+ }
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::SetPropAdvanceCmd(int engineNum, double setting)
+{
+ unsigned int ctr;
+
+ if (engineNum < (int)ThrottlePos.size()) {
+ if (engineNum < 0) {
+ for (ctr=0;ctr<PropAdvanceCmd.size();ctr++) PropAdvanceCmd[ctr] = setting;
+ } else {
+ PropAdvanceCmd[engineNum] = setting;
+ }
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::SetPropAdvance(int engineNum, double setting)
+{
+ unsigned int ctr;
+
+ if (engineNum < (int)ThrottlePos.size()) {
+ if (engineNum < 0) {
+ for (ctr=0;ctr<=PropAdvanceCmd.size();ctr++) PropAdvance[ctr] = PropAdvanceCmd[ctr];
+ } else {
+ PropAdvance[engineNum] = setting;
+ }
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::SetFeatherCmd(int engineNum, bool setting)
+{
+ unsigned int ctr;
+
+ if (engineNum < (int)ThrottlePos.size()) {
+ if (engineNum < 0) {
+ for (ctr=0;ctr<PropFeatherCmd.size();ctr++) PropFeatherCmd[ctr] = setting;
+ } else {
+ PropFeatherCmd[engineNum] = setting;
+ }
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::SetPropFeather(int engineNum, bool setting)
+{
+ unsigned int ctr;
+
+ if (engineNum < (int)ThrottlePos.size()) {
+ if (engineNum < 0) {
+ for (ctr=0;ctr<=PropFeatherCmd.size();ctr++) PropFeather[ctr] = PropFeatherCmd[ctr];
+ } else {
+ PropFeather[engineNum] = setting;
+ }
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGFCS::Load(Element* el)
+{
+ string name, file, fname, comp_name, interface_property_string;
+ unsigned i;
+ vector <FGFCSComponent*> *Components;
+ Element *FCS_cfg, *document, *component_element, *property_element, *sensor_element;
+ Element *channel_element;
+ ifstream* controls_file = new ifstream();
+ FGXMLParse controls_file_parser;
+
+ Components=0;
+ // Determine if the FCS/Autopilot is defined inline in the aircraft configuration
+ // file or in a separate file. Set up the Element pointer as appropriate.
+
+ string separator = "/";
+#ifdef macintosh
+ separator = ";";
+#endif
+
+ name = el->GetAttributeValue("name");
+
+ if (name.empty()) {
+ fname = el->GetAttributeValue("file");
+ file = FDMExec->GetAircraftPath() + separator + FDMExec->GetModelName() + separator + fname + ".xml";
+ if (fname.empty()) {
+ cerr << "FCS/Autopilot does not appear to be defined inline nor in a file" << endl;
+ return false;
+ } else {
+ controls_file->open(file.c_str());
+ readXML(*controls_file, controls_file_parser);
+ delete controls_file;
+ document = controls_file_parser.GetDocument();
+ }
+ } else {
+ document = el;
+ }
+
+ if (document->GetName() == "autopilot") {
+ Components = &APComponents;
+ Name = "Autopilot: " + document->GetAttributeValue("name");
+ } else if (document->GetName() == "flight_control") {
+ Components = &FCSComponents;
+ Name = "FCS: " + document->GetAttributeValue("name");
+ }
+
+ Debug(2);
+
+ // ToDo: How do these get untied?
+ // ToDo: Consider having INPUT and OUTPUT interface properties. Would then
+ // have to duplicate this block of code after channel read code.
+ // Input properties could be write only (nah), and output could be read
+ // only.
+
+ if (document->GetName() == "flight_control") bindModel();
+
+ property_element = document->FindElement("property");
+ while (property_element) {
+ interface_properties.push_back(new double(0));
+ interface_property_string = property_element->GetDataLine();
+ PropertyManager->Tie(interface_property_string, interface_properties.back());
+ property_element = document->FindNextElement("property");
+ }
+
+ sensor_element = document->FindElement("sensor");
+ while (sensor_element) {
+ try {
+ sensors.push_back(new FGSensor(this, sensor_element));
+ } catch (string s) {
+ cerr << highint << fgred << endl << " " << s << endl;
+ return false;
+ }
+ sensor_element = document->FindNextElement("sensor");
+ }
+
+ channel_element = document->FindElement("channel");
+ while (channel_element) {
+ component_element = channel_element->FindElement("component");
+ if (component_element) {
+ cout << "This form of the component specification is being deprecated" << endl;
+ } else {
+ component_element = channel_element->GetElement();
+ }
+ while (component_element) {
+ comp_name = component_element->GetAttributeValue("type");
+ try {
+ if ((comp_name == "LAG_FILTER") ||
+ (comp_name == "LEAD_LAG_FILTER") ||
+ (comp_name == "SECOND_ORDER_FILTER") ||
+ (comp_name == "WASHOUT_FILTER") ||
+ (comp_name == "INTEGRATOR") ||
+ (component_element->GetName() == string("lag_filter")) ||
+ (component_element->GetName() == string("lead_lag_filter")) ||
+ (component_element->GetName() == string("washout_filter")) ||
+ (component_element->GetName() == string("second_order_filter")) ||
+ (component_element->GetName() == string("integrator")) )
+ {
+ Components->push_back(new FGFilter(this, component_element));
+ } else if ((comp_name == "PURE_GAIN") ||
+ (comp_name == "SCHEDULED_GAIN") ||
+ (comp_name == "AEROSURFACE_SCALE") ||
+ (component_element->GetName() == string("pure_gain")) ||
+ (component_element->GetName() == string("scheduled_gain")) ||
+ (component_element->GetName() == string("aerosurface_scale")))
+ {
+ Components->push_back(new FGGain(this, component_element));
+ } else if ((comp_name == "SUMMER") || (component_element->GetName() == string("summer"))) {
+ Components->push_back(new FGSummer(this, component_element));
+ } else if ((comp_name == "DEADBAND") || (component_element->GetName() == string("deadband"))) {
+ Components->push_back(new FGDeadBand(this, component_element));
+ } else if (comp_name == "GRADIENT") {
+ Components->push_back(new FGGradient(this, component_element));
+ } else if ((comp_name == "SWITCH") || (component_element->GetName() == string("switch"))) {
+ Components->push_back(new FGSwitch(this, component_element));
+ } else if ((comp_name == "KINEMAT") || (component_element->GetName() == string("kinematic"))) {
+ Components->push_back(new FGKinemat(this, component_element));
+ } else if ((comp_name == "FUNCTION") || (component_element->GetName() == string("fcs_function"))) {
+ Components->push_back(new FGFCSFunction(this, component_element));
+ } else {
+ cerr << "Unknown FCS component: " << comp_name << endl;
+ }
+ } catch(string s) {
+ cerr << highint << fgred << endl << " " << s << endl;
+ cerr << reset << endl;
+ return false;
+ }
+ if (comp_name.empty()) { // comp_name will be empty if using new format
+ component_element = channel_element->GetNextElement();
+ } else {
+ component_element = channel_element->FindNextElement("component");
+ }
+ }
+ channel_element = document->FindNextElement("channel");
+ }
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGFCS::GetBrake(FGLGear::BrakeGroup bg)
+{
+ switch (bg) {
+ case FGLGear::bgLeft:
+ return LeftBrake;
+ case FGLGear::bgRight:
+ return RightBrake;
+ case FGLGear::bgCenter:
+ return CenterBrake;
+ default:
+ cerr << "GetBrake asked to return a bogus brake value" << endl;
+ }
+ return 0.0;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGFCS::GetComponentStrings(string delimeter)
+{
+ unsigned int comp;
+ string CompStrings = "";
+ bool firstime = true;
+
+ for (comp = 0; comp < FCSComponents.size(); comp++) {
+ if (firstime) firstime = false;
+ else CompStrings += delimeter;
+
+ CompStrings += FCSComponents[comp]->GetName();
+ }
+
+ for (comp = 0; comp < APComponents.size(); comp++)
+ {
+ CompStrings += delimeter;
+ CompStrings += APComponents[comp]->GetName();
+ }
+
+ return CompStrings;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGFCS::GetComponentValues(string delimeter)
+{
+ unsigned int comp;
+ string CompValues = "";
+ char buffer[12];
+ bool firstime = true;
+
+ for (comp = 0; comp < FCSComponents.size(); comp++) {
+ if (firstime) firstime = false;
+ else CompValues += delimeter;
+
+ sprintf(buffer, "%9.6f", FCSComponents[comp]->GetOutput());
+ CompValues += string(buffer);
+ }
+
+ for (comp = 0; comp < APComponents.size(); comp++) {
+ sprintf(buffer, "%s%9.6f", delimeter.c_str(), APComponents[comp]->GetOutput());
+ CompValues += string(buffer);
+ }
+
+ return CompValues;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::AddThrottle(void)
+{
+ ThrottleCmd.push_back(0.0);
+ ThrottlePos.push_back(0.0);
+ MixtureCmd.push_back(0.0); // assume throttle and mixture are coupled
+ MixturePos.push_back(0.0);
+ PropAdvanceCmd.push_back(0.0); // assume throttle and prop pitch are coupled
+ PropAdvance.push_back(0.0);
+ PropFeatherCmd.push_back(false);
+ PropFeather.push_back(false);
+
+ unsigned int num = ThrottleCmd.size()-1;
+ bindThrottle(num);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::AddGear(void)
+{
+ SteerPosDeg.push_back(0.0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::bind(void)
+{
+ PropertyManager->Tie("fcs/aileron-cmd-norm", this, &FGFCS::GetDaCmd, &FGFCS::SetDaCmd);
+ PropertyManager->Tie("fcs/elevator-cmd-norm", this, &FGFCS::GetDeCmd, &FGFCS::SetDeCmd);
+ PropertyManager->Tie("fcs/rudder-cmd-norm", this, &FGFCS::GetDrCmd, &FGFCS::SetDrCmd);
+ PropertyManager->Tie("fcs/steer-cmd-norm", this, &FGFCS::GetDsCmd, &FGFCS::SetDsCmd);
+ PropertyManager->Tie("fcs/flap-cmd-norm", this, &FGFCS::GetDfCmd, &FGFCS::SetDfCmd);
+ PropertyManager->Tie("fcs/speedbrake-cmd-norm", this, &FGFCS::GetDsbCmd, &FGFCS::SetDsbCmd);
+ PropertyManager->Tie("fcs/spoiler-cmd-norm", this, &FGFCS::GetDspCmd, &FGFCS::SetDspCmd);
+ PropertyManager->Tie("fcs/pitch-trim-cmd-norm", this, &FGFCS::GetPitchTrimCmd, &FGFCS::SetPitchTrimCmd);
+ PropertyManager->Tie("fcs/roll-trim-cmd-norm", this, &FGFCS::GetRollTrimCmd, &FGFCS::SetRollTrimCmd);
+ PropertyManager->Tie("fcs/yaw-trim-cmd-norm", this, &FGFCS::GetYawTrimCmd, &FGFCS::SetYawTrimCmd);
+ PropertyManager->Tie("gear/gear-cmd-norm", this, &FGFCS::GetGearCmd, &FGFCS::SetGearCmd);
+
+ PropertyManager->Tie("fcs/left-aileron-pos-rad", this, ofRad, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
+ PropertyManager->Tie("fcs/left-aileron-pos-deg", this, ofDeg, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
+ PropertyManager->Tie("fcs/left-aileron-pos-norm", this, ofNorm, &FGFCS::GetDaLPos, &FGFCS::SetDaLPos);
+ PropertyManager->Tie("fcs/mag-left-aileron-pos-rad", this, ofMag, &FGFCS::GetDaLPos);
+
+ PropertyManager->Tie("fcs/right-aileron-pos-rad", this, ofRad, &FGFCS::GetDaRPos, &FGFCS::SetDaRPos);
+ PropertyManager->Tie("fcs/right-aileron-pos-deg", this, ofDeg, &FGFCS::GetDaRPos, &FGFCS::SetDaRPos);
+ PropertyManager->Tie("fcs/right-aileron-pos-norm", this, ofNorm, &FGFCS::GetDaRPos, &FGFCS::SetDaRPos);
+ PropertyManager->Tie("fcs/mag-right-aileron-pos-rad", this, ofMag, &FGFCS::GetDaRPos);
+
+ PropertyManager->Tie("fcs/elevator-pos-rad", this, ofRad, &FGFCS::GetDePos, &FGFCS::SetDePos);
+ PropertyManager->Tie("fcs/elevator-pos-deg", this, ofDeg, &FGFCS::GetDePos, &FGFCS::SetDePos);
+ PropertyManager->Tie("fcs/elevator-pos-norm", this, ofNorm, &FGFCS::GetDePos, &FGFCS::SetDePos);
+ PropertyManager->Tie("fcs/mag-elevator-pos-rad", this, ofMag, &FGFCS::GetDePos);
+
+ PropertyManager->Tie("fcs/rudder-pos-rad", this,ofRad, &FGFCS::GetDrPos, &FGFCS::SetDrPos);
+ PropertyManager->Tie("fcs/rudder-pos-deg", this,ofDeg, &FGFCS::GetDrPos, &FGFCS::SetDrPos);
+ PropertyManager->Tie("fcs/rudder-pos-norm", this,ofNorm, &FGFCS::GetDrPos, &FGFCS::SetDrPos);
+ PropertyManager->Tie("fcs/mag-rudder-pos-rad", this,ofMag, &FGFCS::GetDrPos);
+
+ PropertyManager->Tie("fcs/flap-pos-rad", this,ofRad, &FGFCS::GetDfPos, &FGFCS::SetDfPos);
+ PropertyManager->Tie("fcs/flap-pos-deg", this,ofDeg, &FGFCS::GetDfPos, &FGFCS::SetDfPos);
+ PropertyManager->Tie("fcs/flap-pos-norm", this,ofNorm, &FGFCS::GetDfPos, &FGFCS::SetDfPos);
+
+ PropertyManager->Tie("fcs/speedbrake-pos-rad", this,ofRad, &FGFCS::GetDsbPos, &FGFCS::SetDsbPos);
+ PropertyManager->Tie("fcs/speedbrake-pos-deg", this,ofDeg, &FGFCS::GetDsbPos, &FGFCS::SetDsbPos);
+ PropertyManager->Tie("fcs/speedbrake-pos-norm", this,ofNorm, &FGFCS::GetDsbPos, &FGFCS::SetDsbPos);
+ PropertyManager->Tie("fcs/mag-speedbrake-pos-rad", this,ofMag, &FGFCS::GetDsbPos);
+
+ PropertyManager->Tie("fcs/spoiler-pos-rad", this, ofRad, &FGFCS::GetDspPos, &FGFCS::SetDspPos);
+ PropertyManager->Tie("fcs/spoiler-pos-deg", this, ofDeg, &FGFCS::GetDspPos, &FGFCS::SetDspPos);
+ PropertyManager->Tie("fcs/spoiler-pos-norm", this, ofNorm, &FGFCS::GetDspPos, &FGFCS::SetDspPos);
+ PropertyManager->Tie("fcs/mag-spoiler-pos-rad", this, ofMag, &FGFCS::GetDspPos);
+
+ PropertyManager->Tie("gear/gear-pos-norm", this, &FGFCS::GetGearPos, &FGFCS::SetGearPos);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// Technically, this function should probably bind propulsion type specific controls
+// rather than mixture and prop-advance.
+//
+
+void FGFCS::bindThrottle(unsigned int num)
+{
+ char tmp[80];
+
+ snprintf(tmp, 80, "fcs/throttle-cmd-norm[%u]",num);
+ PropertyManager->Tie( tmp, this, num, &FGFCS::GetThrottleCmd,
+ &FGFCS::SetThrottleCmd);
+ snprintf(tmp, 80, "fcs/throttle-pos-norm[%u]",num);
+ PropertyManager->Tie( tmp, this, num, &FGFCS::GetThrottlePos,
+ &FGFCS::SetThrottlePos);
+ snprintf(tmp, 80, "fcs/mixture-cmd-norm[%u]",num);
+ PropertyManager->Tie( tmp, this, num, &FGFCS::GetMixtureCmd,
+ &FGFCS::SetMixtureCmd);
+ snprintf(tmp, 80, "fcs/mixture-pos-norm[%u]",num);
+ PropertyManager->Tie( tmp, this, num, &FGFCS::GetMixturePos,
+ &FGFCS::SetMixturePos);
+ snprintf(tmp, 80, "fcs/advance-cmd-norm[%u]",num);
+ PropertyManager->Tie( tmp, this, num, &FGFCS::GetPropAdvanceCmd,
+ &FGFCS::SetPropAdvanceCmd);
+ snprintf(tmp, 80, "fcs/advance-pos-norm[%u]", num);
+ PropertyManager->Tie( tmp, this, num, &FGFCS::GetPropAdvance,
+ &FGFCS::SetPropAdvance);
+ snprintf(tmp, 80, "fcs/feather-cmd-norm[%u]", num);
+ PropertyManager->Tie( tmp, this, num, &FGFCS::GetFeatherCmd,
+ &FGFCS::SetFeatherCmd);
+ snprintf(tmp, 80, "fcs/feather-pos-norm[%u]", num);
+ PropertyManager->Tie( tmp, this, num, &FGFCS::GetPropFeather,
+ &FGFCS::SetPropFeather);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::bindModel(void)
+{
+ unsigned int i;
+ char tmp[80];
+
+ for (i=0; i<SteerPosDeg.size(); i++) {
+ if (GroundReactions->GetGearUnit(i)->GetSteerable()) {
+ snprintf(tmp,80,"fcs/steer-pos-deg[%u]",i);
+ PropertyManager->Tie( tmp, this, i, &FGFCS::GetSteerPosDeg, &FGFCS::SetSteerPosDeg);
+ }
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCS::unbind(FGPropertyManager *node)
+{
+ int N = node->nChildren();
+ for (int i=0; i<N; i++) {
+ if (node->getChild(i)->nChildren() ) {
+ unbind( (FGPropertyManager*)node->getChild(i) );
+ } else if ( node->getChild(i)->isTied() ) {
+ node->getChild(i)->untie();
+ }
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGFCS::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 2) { // Loader
+ cout << endl << " Flight Control (" << Name << ")" << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGFCS" << endl;
+ if (from == 1) cout << "Destroyed: FGFCS" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGGFCS.h
+ Author: Jon S. Berndt
+ Date started: 12/12/98
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+12/12/98 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGFCS_H
+#define FGFCS_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# ifdef SG_HAVE_STD_INCLUDES
+# include <vector>
+# else
+# include <vector.h>
+# endif
+#else
+# include <vector>
+#endif
+
+#include <string>
+#include <models/flight_control/FGFCSComponent.h>
+#include <models/FGModel.h>
+#include <models/FGLGear.h>
+#include <input_output/FGXMLElement.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_FCS "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+typedef enum { ofRad=0, ofDeg, ofNorm, ofMag , NForms} OutputForm;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Encapsulates the Flight Control System (FCS) functionality.
+ This class owns and contains the list of FGFCSComponents
+ that define the control system for this aircraft. The config file for the
+ aircraft contains a description of the control path that starts at an input
+ or command and ends at an effector, e.g. an aerosurface. The FCS components
+ which comprise the control laws for an axis are defined sequentially in
+ the configuration file. For instance, for the X-15:
+
+ <pre>
+ \<flight_control name="X-15 SAS">
+ \<channel>
+ \<component name="Pitch Trim Sum" type="SUMMER">
+ <input> fcs/elevator-cmd-norm </input>
+ <input> fcs/pitch-trim-cmd-norm </input>
+ <clipto>
+ <min>-1</min>
+ <max>1</max>
+ </clipto>
+ \</component>
+
+ \<component name="Pitch Command Scale" TYPE="AEROSURFACE_SCALE">
+ <input> fcs/pitch-trim-sum </input>
+ <limit>
+ <min> -50 </min>
+ <max> 50 </max>
+ </limit>
+ \</component>
+
+ ... etc.
+ </pre>
+
+ In the above case we can see the first few components of the pitch channel
+ defined. The input to the first component, as can be seen in the "Pitch trim
+ sum" component, is really the sum of two parameters: elevator command (from
+ the stick - a pilot input), and pitch trim. The type of this component is
+ "Summer".
+ The next component created is an aerosurface scale component - a type of
+ gain (see the LoadFCS() method for insight on how the various types of
+ components map into the actual component classes). This continues until the
+ final component for an axis when the
+ \<output> element specifies where the output is supposed to go. See the
+ individual components for more information on how they are mechanized.
+
+ Another option for the flight controls portion of the config file is that in
+ addition to using the "NAME" attribute in,
+
+ <pre>
+ \<flight_control name="X-15 SAS">
+ </pre>
+
+ one can also supply a filename:
+
+ <pre>
+ \<flight_control name="X-15 SAS" file="X15.xml">
+ \</flight_control>
+ </pre>
+
+ In this case, the FCS would be read in from another file.
+
+ @author Jon S. Berndt
+ @version $Id$
+ @see FGFCSComponent
+ @see FGXMLElement
+ @see FGGain
+ @see FGSummer
+ @see FGSwitch
+ @see FGGradient
+ @see FGFilter
+ @see FGDeadBand
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGFCS : public FGModel {
+
+public:
+ /** Constructor
+ @param Executive a pointer to the parent executive object */
+ FGFCS(FGFDMExec*);
+ /// Destructor
+ ~FGFCS();
+
+ /** Runs the Flight Controls model; called by the Executive
+ @return false if no error */
+ bool Run(void);
+
+ /// @name Pilot input command retrieval
+ //@{
+ /** Gets the aileron command.
+ @return aileron command in range from -1.0 - 1.0 */
+ inline double GetDaCmd(void) const { return DaCmd; }
+
+ /** Gets the elevator command.
+ @return elevator command in range from -1.0 - 1.0 */
+ inline double GetDeCmd(void) const { return DeCmd; }
+
+ /** Gets the rudder command.
+ @return rudder command in range from -1.0 - 1.0 */
+ inline double GetDrCmd(void) const { return DrCmd; }
+
+ /** Gets the steering command.
+ @return steering command in range from -1.0 - 1.0 */
+ inline double GetDsCmd(void) const { return DsCmd; }
+
+ /** Gets the flaps command.
+ @return flaps command in range from 0 to 1.0 */
+ inline double GetDfCmd(void) const { return DfCmd; }
+
+ /** Gets the speedbrake command.
+ @return speedbrake command in range from 0 to 1.0 */
+ inline double GetDsbCmd(void) const { return DsbCmd; }
+
+ /** Gets the spoiler command.
+ @return spoiler command in range from 0 to 1.0 */
+ inline double GetDspCmd(void) const { return DspCmd; }
+
+ /** Gets the throttle command.
+ @param engine engine ID number
+ @return throttle command in range from 0 - 1.0 for the given engine */
+ double GetThrottleCmd(int engine) const;
+
+ /** Gets the mixture command.
+ @param engine engine ID number
+ @return mixture command in range from 0 - 1.0 for the given engine */
+ inline double GetMixtureCmd(int engine) const { return MixtureCmd[engine]; }
+
+ /** Gets the prop pitch command.
+ @param engine engine ID number
+ @return pitch command in range from 0.0 - 1.0 for the given engine */
+ inline double GetPropAdvanceCmd(int engine) const { return PropAdvanceCmd[engine]; }
+
+ /** Gets the prop feather command.
+ @param engine engine ID number
+ @return feather command for the given engine (on / off)*/
+ inline bool GetFeatherCmd(int engine) const { return PropFeatherCmd[engine]; }
+
+ /** Gets the pitch trim command.
+ @return pitch trim command in range from -1.0 to 1.0 */
+ inline double GetPitchTrimCmd(void) const { return PTrimCmd; }
+
+ /** Gets the rudder trim command.
+ @return rudder trim command in range from -1.0 - 1.0 */
+ inline double GetYawTrimCmd(void) const { return YTrimCmd; }
+
+ /** Gets the aileron trim command.
+ @return aileron trim command in range from -1.0 - 1.0 */
+ inline double GetRollTrimCmd(void) const { return RTrimCmd; }
+
+ /** Get the gear extend/retract command. 0 commands gear up, 1 down.
+ defaults to down.
+ @return the current value of the gear extend/retract command*/
+ inline double GetGearCmd(void) const { return GearCmd; }
+ //@}
+
+ /// @name Aerosurface position retrieval
+ //@{
+ /** Gets the left aileron position.
+ @return aileron position in radians */
+ inline double GetDaLPos( int form = ofRad )
+ const { return DaLPos[form]; }
+
+ /// @name Aerosurface position retrieval
+ //@{
+ /** Gets the right aileron position.
+ @return aileron position in radians */
+ inline double GetDaRPos( int form = ofRad )
+ const { return DaRPos[form]; }
+
+ /** Gets the elevator position.
+ @return elevator position in radians */
+ inline double GetDePos( int form = ofRad )
+ const { return DePos[form]; }
+
+ /** Gets the rudder position.
+ @return rudder position in radians */
+ inline double GetDrPos( int form = ofRad )
+ const { return DrPos[form]; }
+
+ /** Gets the speedbrake position.
+ @return speedbrake position in radians */
+ inline double GetDsbPos( int form = ofRad )
+ const { return DsbPos[form]; }
+
+ /** Gets the spoiler position.
+ @return spoiler position in radians */
+ inline double GetDspPos( int form = ofRad )
+ const { return DspPos[form]; }
+
+ /** Gets the flaps position.
+ @return flaps position in radians */
+ inline double GetDfPos( int form = ofRad )
+ const { return DfPos[form]; }
+
+ /** Gets the throttle position.
+ @param engine engine ID number
+ @return throttle position for the given engine in range from 0 - 1.0 */
+ double GetThrottlePos(int engine) const;
+
+ /** Gets the mixture position.
+ @param engine engine ID number
+ @return mixture position for the given engine in range from 0 - 1.0 */
+ inline double GetMixturePos(int engine) const { return MixturePos[engine]; }
+
+ /** Gets the steering position.
+ @return steering position in degrees */
+ double GetSteerPosDeg(int gear) const { return SteerPosDeg[gear]; }
+
+ /** Gets the gear position (0 up, 1 down), defaults to down
+ @return gear position (0 up, 1 down) */
+ inline double GetGearPos(void) const { return GearPos; }
+
+ /** Gets the prop pitch position.
+ @param engine engine ID number
+ @return prop pitch position for the given engine in range from 0 - 1.0 */
+ inline double GetPropAdvance(int engine) const { return PropAdvance[engine]; }
+
+ /** Gets the prop feather position.
+ @param engine engine ID number
+ @return prop fether for the given engine (on / off)*/
+ inline bool GetPropFeather(int engine) const { return PropFeather[engine]; }
+ //@}
+
+ /** Retrieves the State object pointer.
+ This is used by the FGFCS-owned components.
+ @return pointer to the State object */
+ inline FGState* GetState(void) { return State; }
+
+ /** Retrieves all component names for inclusion in output stream
+ @param delimeter either a tab or comma string depending on output type
+ @return a string containing the descriptive names for all components */
+ string GetComponentStrings(string delimeter);
+
+ /** Retrieves all component outputs for inclusion in output stream
+ @param delimeter either a tab or comma string depending on output type
+ @return a string containing the numeric values for the current set of
+ component outputs */
+ string GetComponentValues(string delimeter);
+
+ /// @name Pilot input command setting
+ //@{
+ /** Sets the aileron command
+ @param cmd aileron command */
+ inline void SetDaCmd( double cmd ) { DaCmd = cmd; }
+
+ /** Sets the elevator command
+ @param cmd elevator command in percent*/
+ inline void SetDeCmd(double cmd ) { DeCmd = cmd; }
+
+ /** Sets the rudder command
+ @param cmd rudder command in percent*/
+ inline void SetDrCmd(double cmd) { DrCmd = cmd; }
+
+ /** Sets the steering command
+ @param cmd steering command in percent*/
+ inline void SetDsCmd(double cmd) { DsCmd = cmd; }
+
+ /** Sets the flaps command
+ @param cmd flaps command in percent*/
+ inline void SetDfCmd(double cmd) { DfCmd = cmd; }
+
+ /** Sets the speedbrake command
+ @param cmd speedbrake command in percent*/
+ inline void SetDsbCmd(double cmd) { DsbCmd = cmd; }
+
+ /** Sets the spoilers command
+ @param cmd spoilers command in percent*/
+ inline void SetDspCmd(double cmd) { DspCmd = cmd; }
+
+ /** Sets the pitch trim command
+ @param cmd pitch trim command in percent*/
+ inline void SetPitchTrimCmd(double cmd) { PTrimCmd = cmd; }
+
+ /** Sets the rudder trim command
+ @param cmd rudder trim command in percent*/
+ inline void SetYawTrimCmd(double cmd) { YTrimCmd = cmd; }
+
+ /** Sets the aileron trim command
+ @param cmd aileron trim command in percent*/
+ inline void SetRollTrimCmd(double cmd) { RTrimCmd = cmd; }
+
+ /** Sets the throttle command for the specified engine
+ @param engine engine ID number
+ @param cmd throttle command in percent (0 - 100)*/
+ void SetThrottleCmd(int engine, double cmd);
+
+ /** Sets the mixture command for the specified engine
+ @param engine engine ID number
+ @param cmd mixture command in percent (0 - 100)*/
+ void SetMixtureCmd(int engine, double cmd);
+
+ /** Set the gear extend/retract command, defaults to down
+ @param gear command 0 for up, 1 for down */
+ void SetGearCmd(double gearcmd) { GearCmd = gearcmd; }
+
+ /** Sets the propeller pitch command for the specified engine
+ @param engine engine ID number
+ @param cmd mixture command in percent (0.0 - 1.0)*/
+ void SetPropAdvanceCmd(int engine, double cmd);
+
+ /** Sets the propeller feather command for the specified engine
+ @param engine engine ID number
+ @param cmd feather (bool)*/
+ void SetFeatherCmd(int engine, bool cmd);
+ //@}
+
+ /// @name Aerosurface position setting
+ //@{
+ /** Sets the left aileron position
+ @param cmd left aileron position in radians*/
+ inline void SetDaLPos( int form , double pos );
+
+ /** Sets the right aileron position
+ @param cmd right aileron position in radians*/
+ inline void SetDaRPos( int form , double pos );
+
+ /** Sets the elevator position
+ @param cmd elevator position in radians*/
+ inline void SetDePos( int form , double pos );
+
+ /** Sets the rudder position
+ @param cmd rudder position in radians*/
+ inline void SetDrPos( int form , double pos );
+
+ /** Sets the flaps position
+ @param cmd flaps position in radians*/
+ inline void SetDfPos( int form , double pos );
+
+ /** Sets the speedbrake position
+ @param cmd speedbrake position in radians*/
+ inline void SetDsbPos( int form , double pos );
+
+ /** Sets the spoiler position
+ @param cmd spoiler position in radians*/
+ inline void SetDspPos( int form , double pos );
+
+ /** Sets the actual throttle setting for the specified engine
+ @param engine engine ID number
+ @param cmd throttle setting in percent (0 - 100)*/
+ void SetThrottlePos(int engine, double cmd);
+
+ /** Sets the actual mixture setting for the specified engine
+ @param engine engine ID number
+ @param cmd mixture setting in percent (0 - 100)*/
+ void SetMixturePos(int engine, double cmd);
+
+ /** Sets the steering position
+ @param cmd steering position in degrees*/
+ void SetSteerPosDeg(int gear, double pos) { SteerPosDeg[gear] = pos; }
+
+ /** Set the gear extend/retract position, defaults to down
+ @param gear position 0 up, 1 down */
+ void SetGearPos(double gearpos) { GearPos = gearpos; }
+
+
+ /** Sets the actual prop pitch setting for the specified engine
+ @param engine engine ID number
+ @param cmd prop pitch setting in percent (0.0 - 1.0)*/
+ void SetPropAdvance(int engine, double cmd);
+
+ /** Sets the actual prop feather setting for the specified engine
+ @param engine engine ID number
+ @param cmd prop fether setting (bool)*/
+ void SetPropFeather(int engine, bool cmd);
+ //@}
+
+ /// @name Landing Gear brakes
+ //@{
+ /** Sets the left brake group
+ @param cmd brake setting in percent (0.0 - 1.0) */
+ void SetLBrake(double cmd) {LeftBrake = cmd;}
+
+ /** Sets the right brake group
+ @param cmd brake setting in percent (0.0 - 1.0) */
+ void SetRBrake(double cmd) {RightBrake = cmd;}
+
+ /** Sets the center brake group
+ @param cmd brake setting in percent (0.0 - 1.0) */
+ void SetCBrake(double cmd) {CenterBrake = cmd;}
+
+ /** Gets the brake for a specified group.
+ @param bg which brakegroup to retrieve the command for
+ @return the brake setting for the supplied brake group argument */
+ double GetBrake(FGLGear::BrakeGroup bg);
+ //@}
+
+ /** Loads the Flight Control System.
+ The FGAircraft instance is actually responsible for reading the config file
+ and calling the various Load() methods of the other systems, passing in
+ the XML Element instance pointer. Load() is called from FGAircraft.
+ @param el pointer to the Element instance
+ @return true if succesful */
+ bool Load(Element* el);
+
+ void AddThrottle(void);
+ void AddGear(void);
+
+ FGPropertyManager* GetPropertyManager(void) { return PropertyManager; }
+
+private:
+ double DaCmd, DeCmd, DrCmd, DsCmd, DfCmd, DsbCmd, DspCmd;
+ double DePos[NForms], DaLPos[NForms], DaRPos[NForms], DrPos[NForms];
+ double DfPos[NForms], DsbPos[NForms], DspPos[NForms];
+ double PTrimCmd, YTrimCmd, RTrimCmd;
+ vector <double> ThrottleCmd;
+ vector <double> ThrottlePos;
+ vector <double> MixtureCmd;
+ vector <double> MixturePos;
+ vector <double> PropAdvanceCmd;
+ vector <double> PropAdvance;
+ vector <bool> PropFeatherCmd;
+ vector <bool> PropFeather;
+ vector <double> SteerPosDeg;
+ double LeftBrake, RightBrake, CenterBrake; // Brake settings
+ double GearCmd,GearPos;
+
+ vector <FGFCSComponent*> FCSComponents;
+ vector <FGFCSComponent*> APComponents;
+ vector <double*> interface_properties;
+ vector <FGFCSComponent*> sensors;
+ void bind(void);
+ void bindModel(void);
+ void bindThrottle(unsigned int);
+ void unbind(FGPropertyManager *node);
+ void Debug(int from);
+};
+}
+
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGGroundReactions.cpp
+ Author: Jon S. Berndt
+ Date started: 09/13/00
+ Purpose: Encapsulates the ground reaction forces (gear and collision)
+
+ ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+09/13/00 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <sstream>
+#include <iomanip>
+
+#include "FGGroundReactions.h"
+#include <input_output/FGPropertyManager.h>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_GROUNDREACTIONS;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+FGGroundReactions::FGGroundReactions(FGFDMExec* fgex) : FGModel(fgex)
+{
+ Name = "FGGroundReactions";
+
+ bind();
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGGroundReactions::~FGGroundReactions(void)
+{
+ for (int i=0; i<lGear.size();i++) lGear[i].unbind();
+ lGear.clear();
+
+ unbind();
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGGroundReactions::Run(void)
+{
+ if (FGModel::Run()) return true;
+ if (FDMExec->Holding()) return false;
+
+ vForces.InitMatrix();
+ vMoments.InitMatrix();
+
+ if ( Propagate->GetDistanceAGL() < 300.0 ) { // Only execute gear code below 300 feet
+ vector <FGLGear>::iterator iGear = lGear.begin();
+
+ // Sum forces and moments for all gear, here.
+ // Some optimizations may be made here - or rather in the gear code itself.
+ // The gear ::Run() method is called several times - once for each gear.
+ // Perhaps there is some commonality for things which only need to be
+ // calculated once.
+
+ while (iGear != lGear.end()) {
+ vForces += iGear->Force();
+ vMoments += iGear->Moment();
+ iGear++;
+ }
+
+ }
+
+ return false;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGGroundReactions::GetWOW(void)
+{
+ bool result = false;
+ for (int i=0; i<lGear.size(); i++) {
+ if (lGear[i].IsBogey() && lGear[i].GetWOW()) {
+ result = true;
+ break;
+ }
+ }
+ return result;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGGroundReactions::Load(Element* el)
+{
+ int num=0;
+
+ Debug(2);
+
+ Element* contact_element = el->FindElement("contact");
+ while (contact_element) {
+ lGear.push_back(FGLGear(contact_element, FDMExec, num++));
+ FCS->AddGear(); // make the FCS aware of the landing gear
+ contact_element = el->FindNextElement("contact");
+ }
+
+ for (int i=0; i<lGear.size();i++) lGear[i].bind();
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGGroundReactions::GetGroundReactionStrings(string delimeter)
+{
+ std::ostringstream buf;
+
+ for (unsigned int i=0;i<lGear.size();i++) {
+ string name = lGear[i].GetName();
+ buf << name << "_WOW" << delimeter
+ << name << "_stroke" << delimeter
+ << name << "_strokeVel" << delimeter
+ << name << "_CompressForce" << delimeter
+ << name << "_WhlSideForce" << delimeter
+ << name << "_WhlVelVecX" << delimeter
+ << name << "_WhlVelVecY" << delimeter
+ << name << "_WhlRollForce" << delimeter
+ << name << "_BodyXForce" << delimeter
+ << name << "_BodyYForce" << delimeter
+ << name << "_WhlSlipDegrees" << delimeter;
+ }
+
+ buf << "TotalGearForce_X" << delimeter
+ << "TotalGearForce_Y" << delimeter
+ << "TotalGearForce_Z" << delimeter
+ << "TotalGearMoment_L" << delimeter
+ << "TotalGearMoment_M" << delimeter
+ << "TotalGearMoment_N";
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGGroundReactions::GetGroundReactionValues(string delimeter)
+{
+ std::ostringstream buf;
+
+ for (unsigned int i=0;i<lGear.size();i++) {
+ FGLGear& gear = lGear[i];
+ buf << (gear.GetWOW() ? "1, " : "0, ")
+ << setprecision(5) << gear.GetCompLen() << delimeter
+ << setprecision(6) << gear.GetCompVel() << delimeter
+ << setprecision(10) << gear.GetCompForce() << delimeter
+ << setprecision(6) << gear.GetWheelVel(eX) << delimeter
+ << gear.GetWheelVel(eY) << delimeter
+ << gear.GetWheelSideForce() << delimeter
+ << gear.GetWheelRollForce() << delimeter
+ << gear.GetBodyXForce() << delimeter
+ << gear.GetBodyYForce() << delimeter
+ << gear.GetWheelSlipAngle() << delimeter;
+ }
+
+ buf << vForces(eX) << delimeter
+ << vForces(eY) << delimeter
+ << vForces(eZ) << delimeter
+ << vMoments(eX) << delimeter
+ << vMoments(eY) << delimeter
+ << vMoments(eZ);
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGGroundReactions::bind(void)
+{
+ typedef double (FGGroundReactions::*PMF)(int) const;
+ PropertyManager->Tie("gear/num-units", this, &FGGroundReactions::GetNumGearUnits);
+ PropertyManager->Tie("moments/l-gear-lbsft", this, eL, (PMF)&FGGroundReactions::GetMoments);
+ PropertyManager->Tie("moments/m-gear-lbsft", this, eM, (PMF)&FGGroundReactions::GetMoments);
+ PropertyManager->Tie("moments/n-gear-lbsft", this, eN, (PMF)&FGGroundReactions::GetMoments);
+ PropertyManager->Tie("forces/fbx-gear-lbs", this, eX, (PMF)&FGGroundReactions::GetForces);
+ PropertyManager->Tie("forces/fby-gear-lbs", this, eY, (PMF)&FGGroundReactions::GetForces);
+ PropertyManager->Tie("forces/fbz-gear-lbs", this, eZ, (PMF)&FGGroundReactions::GetForces);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGGroundReactions::unbind(void)
+{
+ PropertyManager->Untie("gear/num-units");
+ PropertyManager->Untie("moments/l-gear-lbsft");
+ PropertyManager->Untie("moments/m-gear-lbsft");
+ PropertyManager->Untie("moments/n-gear-lbsft");
+ PropertyManager->Untie("forces/fbx-gear-lbs");
+ PropertyManager->Untie("forces/fby-gear-lbs");
+ PropertyManager->Untie("forces/fbz-gear-lbs");
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGGroundReactions::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 2) { // Loading
+ cout << endl << " Ground Reactions: " << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGGroundReactions" << endl;
+ if (from == 1) cout << "Destroyed: FGGroundReactions" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGGroundReactions.h
+ Author: Jon S. Berndt
+ Date started: 09/13/00
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+09/13/00 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGGROUNDREACTIONS_H
+#define FGGROUNDREACTIONS_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# ifdef SG_HAVE_STD_INCLUDES
+# include <vector>
+# else
+# include <vector.h>
+# endif
+#else
+# include <vector>
+#endif
+
+#include "FGModel.h"
+#include "FGLGear.h"
+#include <math/FGColumnVector3.h>
+#include <input_output/FGXMLElement.h>
+
+#define ID_GROUNDREACTIONS "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Manages ground reactions modeling.
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGGroundReactions : public FGModel
+{
+public:
+ FGGroundReactions(FGFDMExec*);
+ ~FGGroundReactions(void);
+
+ bool Run(void);
+ bool Load(Element* el);
+ FGColumnVector3& GetForces(void) {return vForces;}
+ double GetForces(int idx) const {return vForces(idx);}
+ FGColumnVector3& GetMoments(void) {return vMoments;}
+ double GetMoments(int idx) const {return vMoments(idx);}
+ string GetGroundReactionStrings(string delimeter);
+ string GetGroundReactionValues(string delimeter);
+ bool GetWOW(void);
+
+ inline int GetNumGearUnits(void) const { return lGear.size(); }
+
+ /** Gets a gear instance
+ @param gear index of gear instance
+ @return a pointer to the FGLGear instance of the gear unit requested */
+ inline FGLGear* GetGearUnit(int gear) { return &(lGear[gear]); }
+
+ void bind(void);
+ void unbind(void);
+
+private:
+ vector <FGLGear> lGear;
+ FGColumnVector3 vForces;
+ FGColumnVector3 vMoments;
+ FGColumnVector3 vMaxStaticGrip;
+ FGColumnVector3 vMaxMomentResist;
+
+ void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGInertial.cpp
+ Author: Jon S. Berndt
+ Date started: 09/13/00
+ Purpose: Encapsulates the inertial frame forces (coriolis and centrifugal)
+
+ ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+09/13/00 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGInertial.h"
+#include "FGPropagate.h"
+#include "FGState.h"
+#include "FGMassBalance.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_INERTIAL;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+FGInertial::FGInertial(FGFDMExec* fgex) : FGModel(fgex)
+{
+ Name = "FGInertial";
+
+ // Defaults
+ RotationRate = 0.00007272205217;
+ GM = 14.06252720E15;
+ RadiusReference = 20925650.00;
+ gAccelReference = GM/(RadiusReference*RadiusReference);
+ gAccel = GM/(RadiusReference*RadiusReference);
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGInertial::~FGInertial(void)
+{
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGInertial::Run(void)
+{
+ // Fast return if we have nothing to do ...
+ if (FGModel::Run()) return true;
+ if (FDMExec->Holding()) return false;
+
+ // Gravitation accel
+ double r = Propagate->GetRadius();
+ gAccel = GetGAccel(r);
+
+ return false;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGInertial::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGInertial" << endl;
+ if (from == 1) cout << "Destroyed: FGInertial" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGInertial.h
+ Author: Jon S. Berndt
+ Date started: 09/13/00
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+09/13/00 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGINERTIAL_H
+#define FGINERTIAL_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# ifdef SG_HAVE_STD_INCLUDES
+# include <vector>
+# else
+# include <vector.h>
+# endif
+#else
+# include <vector>
+#endif
+
+#include "FGModel.h"
+#include <math/FGColumnVector3.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_INERTIAL "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models inertial forces (e.g. centripetal and coriolis accelerations).
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGInertial : public FGModel {
+
+public:
+ FGInertial(FGFDMExec*);
+ ~FGInertial(void);
+
+ bool Run(void);
+ double SLgravity(void) const {return gAccelReference;}
+ double gravity(void) const {return gAccel;}
+ double omega(void) const {return RotationRate;}
+ double GetGAccel(double r) const { return GM/(r*r); }
+ double RefRadius(void) const {return RadiusReference;}
+
+private:
+ double gAccel;
+ double gAccelReference;
+ double RadiusReference;
+ double RotationRate;
+ double GM;
+ void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGInput.cpp
+ Author: Jon Berndt
+ Date started: 12/02/98
+ Purpose: Manage output of sim parameters to file or stdout
+ Called by: FGSimExec
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+This is the place where you create output routines to dump data for perusal
+later.
+
+HISTORY
+--------------------------------------------------------------------------------
+12/02/98 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGInput.h"
+#include "FGState.h"
+#include "FGFDMExec.h"
+
+#include <fstream>
+#include <iomanip>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_INPUT;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGInput::FGInput(FGFDMExec* fdmex) : FGModel(fdmex)
+{
+ Name = "FGInput";
+ sFirstPass = dFirstPass = true;
+ socket = 0;
+ port = 0;
+ enabled = true;
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGInput::~FGInput()
+{
+ if (socket) delete socket;
+
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+//
+// This function handles accepting input commands from the socket interface.
+//
+
+bool FGInput::Run(void)
+{
+ string line, token, info_string;
+ int start=0, string_start=0, string_end=0;
+ int token_start=0, token_end=0;
+ char buf[100];
+ double value=0;
+ FGPropertyManager* node=0;
+
+ if (FGModel::Run()) return true; // fast exit if nothing to do
+ if (port == 0) return true; // Do nothing here if port not defined
+ // This model DOES execute if "Exec->Holding"
+
+ data = socket->Receive(); // get socket transmission if present
+
+ if (data.size() > 0) {
+ // parse lines
+ while (1) {
+ string_start = data.find_first_not_of("\r\n", start);
+ if (string_start == string::npos) break;
+ string_end = data.find_first_of("\r\n", string_start);
+ if (string_end == string::npos) break;
+ line = data.substr(string_start, string_end-string_start);
+ if (line.size() == 0) break;
+
+ // now parse individual line
+ token_start = line.find_first_not_of(" ", 0);
+ token_end = line.find_first_of(" ", token_start);
+ token = line.substr(token_start, token_end - token_start);
+
+ if (token == "set" || token == "SET" ) { // SET PROPERTY
+
+ token_start = line.find_first_not_of(" ", token_end);
+ token_end = line.find_first_of(" ", token_start);
+ token = line.substr(token_start, token_end-token_start);
+ node = PropertyManager->GetNode(token);
+ if (node == 0) socket->Reply("Unknown property\n");
+ else {
+ token_start = line.find_first_not_of(" ", token_end);
+ token_end = line.find_first_of(" ", token_start);
+ token = line.substr(token_start, token_end-token_start);
+ value = atof(token.c_str());
+ node->setDoubleValue(value);
+ }
+
+ } else if (token == "get" || token == "GET") { // GET PROPERTY
+
+ token_start = line.find_first_not_of(" ", token_end);
+ if (token_start == string::npos) {
+ socket->Reply("No property argument supplied.\n");
+ break;
+ } else {
+ token = line.substr(token_start, line.size()-token_start);
+ }
+ try {
+ node = PropertyManager->GetNode(token);
+ } catch(...) {
+ socket->Reply("Badly formed property query\n");
+ break;
+ }
+ if (node == 0) {
+ if (FDMExec->Holding()) { // if holding can query property list
+ string query = FDMExec->QueryPropertyCatalog(token);
+ socket->Reply(query);
+ } else {
+ socket->Reply("Must be in HOLD to search properties\n");
+ }
+ } else if (node > 0) {
+ sprintf(buf, "%s = %12.6f\n", token.c_str(), node->getDoubleValue());
+ socket->Reply(buf);
+ }
+
+ } else if (token == "hold" || token == "HOLD") { // PAUSE
+
+ FDMExec->Hold();
+
+ } else if (token == "resume" || token == "RESUME") { // RESUME
+
+ FDMExec->Resume();
+
+ } else if (token == "quit" || token == "QUIT") { // QUIT
+
+ // close the socket connection
+ socket->Reply("");
+ socket->Close();
+
+ } else if (token == "info" || token == "INFO") { // INFO
+
+ // get info about the sim run and/or aircraft, etc.
+ sprintf(buf, "%8.3f\0", State->Getsim_time());
+ info_string = "JSBSim version: " + JSBSim_version + "\n";
+ info_string += "Config File version: " + needed_cfg_version + "\n";
+ info_string += "Aircraft simulated: " + Aircraft->GetAircraftName() + "\n";
+ info_string += "Simulation time: " + string(buf) + "\n";
+ socket->Reply(info_string);
+
+ } else if (token == "help" || token == "HELP") { // HELP
+
+ socket->Reply(
+ " JSBSim Server commands:\n\n"
+ " get {property name}\n"
+ " set {property name} {value}\n"
+ " hold\n"
+ " resume\n"
+ " help\n"
+ " quit\n"
+ " info\n\n");
+
+ } else {
+ socket->Reply(string("Unknown command: ") + token + string("\n"));
+ }
+
+ start = string_end;
+ }
+ }
+
+ return false;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGInput::Load(Element* element)
+{
+ string type="", parameter="";
+ string name="", fname="";
+ string property;
+
+ port = element->GetAttributeValueAsNumber("port");
+ if (port == 0) {
+ cerr << endl << "No port assigned in input element" << endl;
+ } else {
+ socket = new FGfdmSocket(port);
+ }
+
+ Debug(2);
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGInput::Debug(int from)
+{
+ string scratch="";
+
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+ }
+ if (from == 2) {
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGInput" << endl;
+ if (from == 1) cout << "Destroyed: FGInput" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGInput.h
+ Author: Jon Berndt
+ Date started: 12/2/98
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+12/02/98 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGINPUT_H
+#define FGINPUT_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGModel.h"
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# include STL_IOSTREAM
+# include STL_FSTREAM
+#else
+# if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
+# include <iostream.h>
+# include <fstream.h>
+# else
+# include <iostream>
+# include <fstream>
+# endif
+#endif
+
+#include <input_output/FGfdmSocket.h>
+#include <input_output/FGXMLElement.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_INPUT "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Handles simulation input.
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGInput : public FGModel
+{
+public:
+ FGInput(FGFDMExec*);
+ ~FGInput();
+
+ bool Run(void);
+
+ void SetType(string);
+ inline void Enable(void) { enabled = true; }
+ inline void Disable(void) { enabled = false; }
+ inline bool Toggle(void) {enabled = !enabled; return enabled;}
+ bool Load(Element* el);
+
+private:
+ bool sFirstPass, dFirstPass, enabled;
+ unsigned int port;
+ FGfdmSocket* socket;
+ string data;
+ void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGLGear.cpp
+ Author: Jon S. Berndt
+ Norman H. Princen
+ Date started: 11/18/99
+ Purpose: Encapsulates the landing gear elements
+ Called by: FGAircraft
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+11/18/99 JSB Created
+01/30/01 NHP Extended gear model to properly simulate steering and braking
+
+/%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGLGear.h"
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+GLOBAL DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_LGEAR;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number) : Exec(fdmex),
+ GearNumber(number)
+{
+ Element *force_table=0;
+ string force_type="";
+
+ kSpring = bDamp = bDampRebound = dynamicFCoeff = staticFCoeff = rollingFCoeff = maxSteerAngle = 0;
+ sSteerType = sBrakeGroup = sSteerType = "";
+ isRetractable = 0;
+
+ name = el->GetAttributeValue("name");
+ sContactType = el->GetAttributeValue("type");
+ if (el->FindElement("spring_coeff"))
+ kSpring = el->FindElementValueAsNumberConvertTo("spring_coeff", "LBS/FT");
+ if (el->FindElement("damping_coeff"))
+ bDamp = el->FindElementValueAsNumberConvertTo("damping_coeff", "LBS/FT/SEC");
+
+ if (el->FindElement("damping_coeff_rebound"))
+ bDampRebound = el->FindElementValueAsNumberConvertTo("damping_coeff_rebound", "LBS/FT/SEC");
+ else
+ bDampRebound = bDamp;
+
+ if (el->FindElement("dynamic_friction"))
+ dynamicFCoeff = el->FindElementValueAsNumber("dynamic_friction");
+ if (el->FindElement("static_friction"))
+ staticFCoeff = el->FindElementValueAsNumber("static_friction");
+ if (el->FindElement("rolling_friction"))
+ rollingFCoeff = el->FindElementValueAsNumber("rolling_friction");
+ if (el->FindElement("max_steer"))
+ maxSteerAngle = el->FindElementValueAsNumberConvertTo("max_steer", "DEG");
+ if (el->FindElement("retractable"))
+ isRetractable = (int)el->FindElementValueAsNumber("retractable");
+
+ ForceY_Table = 0;
+ force_table = el->FindElement("table");
+ while (force_table) {
+ force_type = force_table->GetAttributeValue("type");
+ if (force_type == "CORNERING_COEFF") {
+ ForceY_Table = new FGTable(Exec->GetPropertyManager(), force_table);
+ } else {
+ cerr << "Undefined force table for " << name << " contact point" << endl;
+ }
+ force_table = el->FindNextElement("table");
+ }
+
+ sBrakeGroup = el->FindElementValue("brake_group");
+
+ if (maxSteerAngle == 360) sSteerType = "CASTERED";
+ else if (maxSteerAngle == 0.0) sSteerType = "FIXED";
+ else sSteerType = "STEERABLE";
+
+ Element* element = el->FindElement("location");
+ if (element) vXYZ = element->FindElementTripletConvertTo("IN");
+ else {cerr << "No location given for contact " << name << endl; exit(-1);}
+
+ if (sBrakeGroup == "LEFT" ) eBrakeGrp = bgLeft;
+ else if (sBrakeGroup == "RIGHT" ) eBrakeGrp = bgRight;
+ else if (sBrakeGroup == "CENTER") eBrakeGrp = bgCenter;
+ else if (sBrakeGroup == "NOSE" ) eBrakeGrp = bgNose;
+ else if (sBrakeGroup == "TAIL" ) eBrakeGrp = bgTail;
+ else if (sBrakeGroup == "NONE" ) eBrakeGrp = bgNone;
+ else if (sBrakeGroup.empty() ) {eBrakeGrp = bgNone;
+ sBrakeGroup = "NONE (defaulted)";}
+ else {
+ cerr << "Improper braking group specification in config file: "
+ << sBrakeGroup << " is undefined." << endl;
+ }
+
+ if (sSteerType == "STEERABLE") eSteerType = stSteer;
+ else if (sSteerType == "FIXED" ) eSteerType = stFixed;
+ else if (sSteerType == "CASTERED" ) eSteerType = stCaster;
+ else if (sSteerType.empty() ) {eSteerType = stFixed;
+ sSteerType = "FIXED (defaulted)";}
+ else {
+ cerr << "Improper steering type specification in config file: "
+ << sSteerType << " is undefined." << endl;
+ }
+
+ GearUp = false;
+ GearDown = true;
+ Servicable = true;
+
+// Add some AI here to determine if gear is located properly according to its
+// brake group type ??
+
+ State = Exec->GetState();
+ Aircraft = Exec->GetAircraft();
+ Propagate = Exec->GetPropagate();
+ Auxiliary = Exec->GetAuxiliary();
+ FCS = Exec->GetFCS();
+ MassBalance = Exec->GetMassBalance();
+
+ WOW = lastWOW = true; // should the value be initialized to true?
+ ReportEnable = true;
+ FirstContact = false;
+ StartedGroundRun = false;
+ TakeoffReported = LandingReported = false;
+ LandingDistanceTraveled = TakeoffDistanceTraveled = TakeoffDistanceTraveled50ft = 0.0;
+ MaximumStrutForce = MaximumStrutTravel = 0.0;
+ SideForce = RollingForce = 0.0;
+ SinkRate = GroundSpeed = 0.0;
+
+ vWhlBodyVec = MassBalance->StructuralToBody(vXYZ);
+
+ vLocalGear = Propagate->GetTb2l() * vWhlBodyVec;
+
+ compressLength = 0.0;
+ compressSpeed = 0.0;
+ brakePct = 0.0;
+ maxCompLen = 0.0;
+
+ WheelSlip = last_WheelSlip = 0.0;
+ TirePressureNorm = 1.0;
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGLGear::FGLGear(const FGLGear& lgear)
+{
+ GearNumber = lgear.GearNumber;
+ State = lgear.State;
+ Aircraft = lgear.Aircraft;
+ Propagate = lgear.Propagate;
+ Auxiliary = lgear.Auxiliary;
+ Exec = lgear.Exec;
+ FCS = lgear.FCS;
+ MassBalance = lgear.MassBalance;
+
+ vXYZ = lgear.vXYZ;
+ vMoment = lgear.vMoment;
+ vWhlBodyVec = lgear.vWhlBodyVec;
+ vLocalGear = lgear.vLocalGear;
+
+ WOW = lgear.WOW;
+ lastWOW = lgear.lastWOW;
+ ReportEnable = lgear.ReportEnable;
+ FirstContact = lgear.FirstContact;
+ StartedGroundRun = lgear.StartedGroundRun;
+ LandingDistanceTraveled = lgear.LandingDistanceTraveled;
+ TakeoffDistanceTraveled = lgear.TakeoffDistanceTraveled;
+ TakeoffDistanceTraveled50ft = lgear.TakeoffDistanceTraveled50ft;
+ MaximumStrutForce = lgear.MaximumStrutForce;
+ MaximumStrutTravel = lgear.MaximumStrutTravel;
+ SideForce = lgear.SideForce;
+ RollingForce = lgear.RollingForce;
+
+ kSpring = lgear.kSpring;
+ bDamp = lgear.bDamp;
+ bDampRebound = lgear.bDampRebound;
+ compressLength = lgear.compressLength;
+ compressSpeed = lgear.compressSpeed;
+ staticFCoeff = lgear.staticFCoeff;
+ dynamicFCoeff = lgear.dynamicFCoeff;
+ rollingFCoeff = lgear.rollingFCoeff;
+ brakePct = lgear.brakePct;
+ maxCompLen = lgear.maxCompLen;
+ SinkRate = lgear.SinkRate;
+ GroundSpeed = lgear.GroundSpeed;
+ LandingReported = lgear.LandingReported;
+ TakeoffReported = lgear.TakeoffReported;
+ name = lgear.name;
+ sSteerType = lgear.sSteerType;
+ sRetractable = lgear.sRetractable;
+ sContactType = lgear.sContactType;
+ sBrakeGroup = lgear.sBrakeGroup;
+ eSteerType = lgear.eSteerType;
+ eBrakeGrp = lgear.eBrakeGrp;
+ maxSteerAngle = lgear.maxSteerAngle;
+ isRetractable = lgear.isRetractable;
+ GearUp = lgear.GearUp;
+ GearDown = lgear.GearDown;
+ WheelSlip = lgear.WheelSlip;
+ TirePressureNorm = lgear.TirePressureNorm;
+ Servicable = lgear.Servicable;
+ ForceY_Table = lgear.ForceY_Table;
+ CosWheel = lgear.CosWheel;
+ SinWheel = lgear.SinWheel;
+ In = lgear.In;
+ prevIn = lgear.prevIn;
+ prevOut = lgear.prevOut;
+ slipIn = lgear.slipIn;
+ last_SlipIn = lgear.last_SlipIn;
+ last_WheelSlip = lgear.last_WheelSlip;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGLGear::~FGLGear()
+{
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGColumnVector3& FGLGear::Force(void)
+{
+ FGColumnVector3 normal, cvel;
+ FGLocation contact, gearLoc;
+ double t = Exec->GetState()->Getsim_time();
+
+ vForce.InitMatrix();
+ vMoment.InitMatrix();
+
+ if (isRetractable) ComputeRetractionState();
+
+ if (GearUp) return vForce;
+
+ vWhlBodyVec = MassBalance->StructuralToBody(vXYZ); // Get wheel in body frame
+ vLocalGear = Propagate->GetTb2l() * vWhlBodyVec; // Get local frame wheel location
+
+ gearLoc = Propagate->GetLocation().LocalToLocation(vLocalGear);
+ compressLength = -Exec->GetGroundCallback()->GetAGLevel(t, gearLoc, contact, normal, cvel);
+
+ // The compression length is measured in the Z-axis, only, at this time.
+
+ if (compressLength > 0.00) {
+
+ WOW = true;
+
+ // [The next equation should really use the vector to the contact patch of
+ // the tire including the strut compression and not the original vWhlBodyVec.]
+
+ vWhlVelVec = Propagate->GetTb2l() * (Propagate->GetPQR() * vWhlBodyVec);
+ vWhlVelVec += Propagate->GetVel() - cvel;
+ compressSpeed = vWhlVelVec(eZ);
+
+ InitializeReporting();
+ ComputeBrakeForceCoefficient();
+ ComputeSteeringAngle();
+ ComputeSlipAngle();
+ ComputeSideForceCoefficient();
+ ComputeVerticalStrutForce();
+
+ // Compute the forces in the wheel ground plane.
+
+ RollingForce = (1.0 - TirePressureNorm) * 30
+ + vLocalForce(eZ) * BrakeFCoeff * (RollingWhlVel>=0?1.0:-1.0);
+ SideForce = vLocalForce(eZ) * FCoeff;
+
+ // Transform these forces back to the local reference frame.
+
+ vLocalForce(eX) = RollingForce*CosWheel - SideForce*SinWheel;
+ vLocalForce(eY) = SideForce*CosWheel + RollingForce*SinWheel;
+
+ // Transform the forces back to the body frame and compute the moment.
+
+ vForce = Propagate->GetTl2b() * vLocalForce;
+
+ // Lag and attenuate the XY-plane forces dependent on velocity
+
+ double RFRV = 0.015; // Rolling force relaxation velocity
+ double SFRV = 0.25; // Side force relaxation velocity
+ double dT = State->Getdt()*Exec->GetGroundReactions()->GetRate();
+
+ In = vForce;
+ vForce(eX) = (0.25)*(In(eX) + prevIn(eX)) + (0.50)*prevOut(eX);
+ vForce(eY) = (0.15)*(In(eY) + prevIn(eY)) + (0.70)*prevOut(eY);
+ prevOut = vForce;
+ prevIn = In;
+
+ if (fabs(RollingWhlVel) <= RFRV) vForce(eX) *= fabs(RollingWhlVel)/RFRV;
+ if (fabs(SideWhlVel) <= SFRV) vForce(eY) *= fabs(SideWhlVel)/SFRV;
+
+ vMoment = vWhlBodyVec * vForce;
+
+ } else { // Gear is NOT compressed
+
+ WOW = false;
+ compressLength = 0.0;
+
+ // Return to neutral position between 1.0 and 0.8 gear pos.
+ SteerAngle *= max(FCS->GetGearPos()-0.8, 0.0)/0.2;
+
+ ResetReporting();
+ }
+
+ ReportTakeoffOrLanding();
+ CrashDetect();
+
+ return vForce;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGLGear::ComputeRetractionState(void)
+{
+ if (FCS->GetGearPos() < 0.01) {
+ GearUp = true;
+ GearDown = false;
+ } else if (FCS->GetGearPos() > 0.99) {
+ GearDown = true;
+ GearUp = false;
+ } else {
+ GearUp = false;
+ GearDown = false;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGLGear::ComputeSlipAngle(void)
+{
+ double dT = State->Getdt()*Exec->GetGroundReactions()->GetRate();
+
+ // Transform the wheel velocities from the local axis system to the wheel axis system.
+
+ RollingWhlVel = vWhlVelVec(eX)*CosWheel + vWhlVelVec(eY)*SinWheel;
+ SideWhlVel = vWhlVelVec(eY)*CosWheel - vWhlVelVec(eX)*SinWheel;
+
+ // Calculate tire slip angle.
+
+ if (fabs(RollingWhlVel) < 0.1 && fabs(SideWhlVel) < 0.01) {
+ WheelSlip = -SteerAngle*radtodeg;
+ } else {
+ WheelSlip = atan2(SideWhlVel, fabs(RollingWhlVel))*radtodeg;
+ }
+ slipIn = WheelSlip;
+ WheelSlip = (0.46)*(slipIn + last_SlipIn) + (0.08)*last_WheelSlip;
+ last_WheelSlip = WheelSlip;
+ last_SlipIn = slipIn;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// Compute the steering angle in any case.
+// This will also make sure that animations will look right.
+
+void FGLGear::ComputeSteeringAngle(void)
+{
+ switch (eSteerType) {
+ case stSteer:
+ SteerAngle = degtorad * FCS->GetSteerPosDeg(GearNumber);
+ break;
+ case stFixed:
+ SteerAngle = 0.0;
+ break;
+ case stCaster:
+ // This is not correct for castering gear. Should make steer angle parallel
+ // to the actual velocity vector of the wheel, given aircraft velocity vector
+ // and omega.
+ SteerAngle = 0.0;
+ break;
+ default:
+ cerr << "Improper steering type membership detected for this gear." << endl;
+ break;
+ }
+
+ SinWheel = sin(Propagate->GetEuler(ePsi) + SteerAngle);
+ CosWheel = cos(Propagate->GetEuler(ePsi) + SteerAngle);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// Reset reporting functionality after takeoff
+
+void FGLGear::ResetReporting(void)
+{
+ if (Propagate->GetDistanceAGL() > 200.0) {
+ FirstContact = false;
+ StartedGroundRun = false;
+ LandingReported = false;
+ LandingDistanceTraveled = 0.0;
+ MaximumStrutForce = MaximumStrutTravel = 0.0;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGLGear::InitializeReporting(void)
+{
+ // If this is the first time the wheel has made contact, remember some values
+ // for later printout.
+
+ if (!FirstContact) {
+ FirstContact = true;
+ SinkRate = compressSpeed;
+ GroundSpeed = Propagate->GetVel().Magnitude();
+ TakeoffReported = false;
+ }
+
+ // If the takeoff run is starting, initialize.
+
+ if ((Propagate->GetVel().Magnitude() > 0.1) &&
+ (FCS->GetBrake(bgLeft) == 0) &&
+ (FCS->GetBrake(bgRight) == 0) &&
+ (FCS->GetThrottlePos(0) == 1) && !StartedGroundRun)
+ {
+ TakeoffDistanceTraveled = 0;
+ TakeoffDistanceTraveled50ft = 0;
+ StartedGroundRun = true;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// Takeoff and landing reporting functionality
+
+void FGLGear::ReportTakeoffOrLanding(void)
+{
+ double deltaT = State->Getdt()*Exec->GetGroundReactions()->GetRate();
+
+ if (FirstContact) LandingDistanceTraveled += Auxiliary->GetVground()*deltaT;
+
+ if (StartedGroundRun) {
+ TakeoffDistanceTraveled50ft += Auxiliary->GetVground()*deltaT;
+ if (WOW) TakeoffDistanceTraveled += Auxiliary->GetVground()*deltaT;
+ }
+
+ if (ReportEnable && Auxiliary->GetVground() <= 0.05 && !LandingReported) {
+ if (debug_lvl > 0) Report(erLand);
+ }
+
+ if (ReportEnable && !TakeoffReported &&
+ (vLocalGear(eZ) - Propagate->GetDistanceAGL()) < -50.0)
+ {
+ if (debug_lvl > 0) Report(erTakeoff);
+ }
+
+ if (lastWOW != WOW) PutMessage("GEAR_CONTACT: " + name, WOW);
+ lastWOW = WOW;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// Crash detection logic (really out-of-bounds detection)
+
+void FGLGear::CrashDetect(void)
+{
+ if (compressLength > 500.0 ||
+ vForce.Magnitude() > 100000000.0 ||
+ vMoment.Magnitude() > 5000000000.0 ||
+ SinkRate > 1.4666*30)
+ {
+ PutMessage("Crash Detected: Simulation FREEZE.");
+ State->SuspendIntegration();
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The following needs work regarding friction coefficients and braking and
+// steering The BrakeFCoeff formula assumes that an anti-skid system is used.
+// It also assumes that we won't be turning and braking at the same time.
+// Will fix this later.
+// [JSB] The braking force coefficients include normal rolling coefficient +
+// a percentage of the static friction coefficient based on braking applied.
+
+void FGLGear::ComputeBrakeForceCoefficient(void)
+{
+ switch (eBrakeGrp) {
+ case bgLeft:
+ BrakeFCoeff = ( rollingFCoeff*(1.0 - FCS->GetBrake(bgLeft)) +
+ staticFCoeff*FCS->GetBrake(bgLeft) );
+ break;
+ case bgRight:
+ BrakeFCoeff = ( rollingFCoeff*(1.0 - FCS->GetBrake(bgRight)) +
+ staticFCoeff*FCS->GetBrake(bgRight) );
+ break;
+ case bgCenter:
+ BrakeFCoeff = ( rollingFCoeff*(1.0 - FCS->GetBrake(bgCenter)) +
+ staticFCoeff*FCS->GetBrake(bgCenter) );
+ break;
+ case bgNose:
+ BrakeFCoeff = ( rollingFCoeff*(1.0 - FCS->GetBrake(bgCenter)) +
+ staticFCoeff*FCS->GetBrake(bgCenter) );
+ break;
+ case bgTail:
+ BrakeFCoeff = ( rollingFCoeff*(1.0 - FCS->GetBrake(bgCenter)) +
+ staticFCoeff*FCS->GetBrake(bgCenter) );
+ break;
+ case bgNone:
+ BrakeFCoeff = rollingFCoeff;
+ break;
+ default:
+ cerr << "Improper brake group membership detected for this gear." << endl;
+ break;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// Compute the sideforce coefficients using similar assumptions to LaRCSim for now.
+// Allow a maximum of 10 degrees tire slip angle before wheel slides. At that point,
+// transition from static to dynamic friction. There are more complicated formulations
+// of this that avoid the discrete jump (similar to Pacejka). Will fix this later.
+
+void FGLGear::ComputeSideForceCoefficient(void)
+{
+ if (ForceY_Table) {
+
+ FCoeff = ForceY_Table->GetValue(WheelSlip);
+
+ } else {
+
+ if (fabs(WheelSlip) <= 10.0) {
+ FCoeff = staticFCoeff*WheelSlip/10.0;
+ } else if (fabs(WheelSlip) <= 40.0) {
+ FCoeff = (dynamicFCoeff*(fabs(WheelSlip) - 10.0)/10.0
+ + staticFCoeff*(40.0 - fabs(WheelSlip))/10.0)*(WheelSlip>=0?1.0:-1.0);
+ } else {
+ FCoeff = dynamicFCoeff*(WheelSlip>=0?1.0:-1.0);
+ }
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// Compute the vertical force on the wheel using square-law damping (per comment
+// in paper AIAA-2000-4303 - see header prologue comments). We might consider
+// allowing for both square and linear damping force calculation. Also need to
+// possibly give a "rebound damping factor" that differs from the compression
+// case.
+
+void FGLGear::ComputeVerticalStrutForce(void)
+{
+ double springForce = 0;
+ double dampForce = 0;
+
+ springForce = -compressLength * kSpring;
+
+ if (compressSpeed >= 0.0) {
+ dampForce = -compressSpeed * bDamp;
+ } else {
+ dampForce = -compressSpeed * bDampRebound;
+ }
+ vLocalForce(eZ) = min(springForce + dampForce, (double)0.0);
+
+ // Remember these values for reporting
+ MaximumStrutForce = max(MaximumStrutForce, fabs(vLocalForce(eZ)));
+ MaximumStrutTravel = max(MaximumStrutTravel, fabs(compressLength));
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGLGear::bind(void)
+{
+ char property_name[80];
+ snprintf(property_name, 80, "gear/unit[%d]/slip-angle-deg", GearNumber);
+ Exec->GetPropertyManager()->Tie( property_name, &WheelSlip );
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGLGear::unbind(void)
+{
+ char property_name[80];
+ snprintf(property_name, 80, "gear/unit[%d]/slip-angle-deg", GearNumber);
+ Exec->GetPropertyManager()->Untie( property_name );
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGLGear::Report(ReportType repType)
+{
+ switch(repType) {
+ case erLand:
+ cout << endl << "Touchdown report for " << name << endl;
+ cout << " Sink rate at contact: " << SinkRate << " fps, "
+ << SinkRate*0.3048 << " mps" << endl;
+ cout << " Contact ground speed: " << GroundSpeed*.5925 << " knots, "
+ << GroundSpeed*0.3048 << " mps" << endl;
+ cout << " Maximum contact force: " << MaximumStrutForce << " lbs, "
+ << MaximumStrutForce*4.448 << " Newtons" << endl;
+ cout << " Maximum strut travel: " << MaximumStrutTravel*12.0 << " inches, "
+ << MaximumStrutTravel*30.48 << " cm" << endl;
+ cout << " Distance traveled: " << LandingDistanceTraveled << " ft, "
+ << LandingDistanceTraveled*0.3048 << " meters" << endl;
+ LandingReported = true;
+ break;
+ case erTakeoff:
+ cout << endl << "Takeoff report for " << name << endl;
+ cout << " Distance traveled: " << TakeoffDistanceTraveled
+ << " ft, " << TakeoffDistanceTraveled*0.3048 << " meters" << endl;
+ cout << " Distance traveled (over 50'): " << TakeoffDistanceTraveled50ft
+ << " ft, " << TakeoffDistanceTraveled50ft*0.3048 << " meters" << endl;
+ TakeoffReported = true;
+ break;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGLGear::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor - loading and initialization
+ cout << " " << sContactType << " " << name << endl;
+ cout << " Location: " << vXYZ << endl;
+ cout << " Spring Constant: " << kSpring << endl;
+ cout << " Damping Constant: " << bDamp << endl;
+ cout << " Dynamic Friction: " << dynamicFCoeff << endl;
+ cout << " Static Friction: " << staticFCoeff << endl;
+ if (sContactType == "BOGEY") {
+ cout << " Rolling Friction: " << rollingFCoeff << endl;
+ cout << " Steering Type: " << sSteerType << endl;
+ cout << " Grouping: " << sBrakeGroup << endl;
+ cout << " Max Steer Angle: " << maxSteerAngle << endl;
+ cout << " Retractable: " << isRetractable << endl;
+ }
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGLGear" << endl;
+ if (from == 1) cout << "Destroyed: FGLGear" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+
+} // namespace JSBSim
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGLGear.h
+ Author: Jon S. Berndt
+ Date started: 11/18/99
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+11/18/99 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGLGEAR_H
+#define FGLGEAR_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+#endif
+
+#include <FGJSBBase.h>
+#include <FGFDMExec.h>
+#include <input_output/FGXMLElement.h>
+#include <math/FGColumnVector3.h>
+#include <math/FGTable.h>
+#include <string>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_LGEAR "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+class FGAircraft;
+class FGPropagate;
+class FGFCS;
+class FGState;
+class FGMassBalance;
+class FGAuxiliary;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Landing gear model.
+ Calculates forces and moments due to landing gear reactions. This is done in
+ several steps, and is dependent on what kind of gear is being modeled. Here
+ are the parameters that can be specified in the config file for modeling
+ landing gear:
+ <p>
+ <b><u>Physical Characteristics</u></b><br>
+ <ol>
+ <li>X, Y, Z location, in inches in structural coordinate frame</li>
+ <li>Spring constant, in lbs/ft</li>
+ <li>Damping coefficient, in lbs/ft/sec</li>
+ <li>Dynamic Friction Coefficient</li>
+ <li>Static Friction Coefficient</li>
+ </ol></p><p>
+ <b><u>Operational Properties</b></u><br>
+ <ol>
+ <li>Name</li>
+ <li>Steerability attribute {one of STEERABLE | FIXED | CASTERED}</li>
+ <li>Brake Group Membership {one of LEFT | CENTER | RIGHT | NOSE | TAIL | NONE}</li>
+ <li>Max Steer Angle, in degrees</li>
+ </ol></p>
+ <p>
+ <b><u>Algorithm and Approach to Modeling</u></b><br>
+ <ol>
+ <li>Find the location of the uncompressed landing gear relative to the CG of
+ the aircraft. Remember, the structural coordinate frame that the aircraft is
+ defined in is: X positive towards the tail, Y positive out the right side, Z
+ positive upwards. The locations of the various parts are given in inches in
+ the config file.</li>
+ <li>The vector giving the location of the gear (relative to the cg) is
+ rotated 180 degrees about the Y axis to put the coordinates in body frame (X
+ positive forwards, Y positive out the right side, Z positive downwards, with
+ the origin at the cg). The lengths are also now given in feet.</li>
+ <li>The new gear location is now transformed to the local coordinate frame
+ using the body-to-local matrix. (Mb2l).</li>
+ <li>Knowing the location of the center of gravity relative to the ground
+ (height above ground level or AGL) now enables gear deflection to be
+ calculated. The gear compression value is the local frame gear Z location
+ value minus the height AGL. [Currently, we make the assumption that the gear
+ is oriented - and the deflection occurs in - the Z axis only. Additionally,
+ the vector to the landing gear is currently not modified - which would
+ (correctly) move the point of contact to the actual compressed-gear point of
+ contact. Eventually, articulated gear may be modeled, but initially an
+ effort must be made to model a generic system.] As an example, say the
+ aircraft left main gear location (in local coordinates) is Z = 3 feet
+ (positive) and the height AGL is 2 feet. This tells us that the gear is
+ compressed 1 foot.</li>
+ <li>If the gear is compressed, a Weight-On-Wheels (WOW) flag is set.</li>
+ <li>With the compression length calculated, the compression velocity may now
+ be calculated. This will be used to determine the damping force in the
+ strut. The aircraft rotational rate is multiplied by the vector to the wheel
+ to get a wheel velocity in body frame. That velocity vector is then
+ transformed into the local coordinate frame.</li>
+ <li>The aircraft cg velocity in the local frame is added to the
+ just-calculated wheel velocity (due to rotation) to get a total wheel
+ velocity in the local frame.</li>
+ <li>The compression speed is the Z-component of the vector.</li>
+ <li>With the wheel velocity vector no longer needed, it is normalized and
+ multiplied by a -1 to reverse it. This will be used in the friction force
+ calculation.</li>
+ <li>Since the friction force takes place solely in the runway plane, the Z
+ coordinate of the normalized wheel velocity vector is set to zero.</li>
+ <li>The gear deflection force (the force on the aircraft acting along the
+ local frame Z axis) is now calculated given the spring and damper
+ coefficients, and the gear deflection speed and stroke length. Keep in mind
+ that gear forces always act in the negative direction (in both local and
+ body frames), and are not capable of generating a force in the positive
+ sense (one that would attract the aircraft to the ground). So, the gear
+ forces are always negative - they are limited to values of zero or less. The
+ gear force is simply the negative of the sum of the spring compression
+ length times the spring coefficient and the gear velocity times the damping
+ coefficient.</li>
+ <li>The lateral/directional force acting on the aircraft through the landing
+
+ gear (along the local frame X and Y axes) is calculated next. First, the
+ friction coefficient is multiplied by the recently calculated Z-force. This
+ is the friction force. It must be given direction in addition to magnitude.
+ We want the components in the local frame X and Y axes. From step 9, above,
+ the conditioned wheel velocity vector is taken and the X and Y parts are
+ multiplied by the friction force to get the X and Y components of friction.
+ </li>
+ <li>The wheel force in local frame is next converted to body frame.</li>
+ <li>The moment due to the gear force is calculated by multiplying r x F
+ (radius to wheel crossed into the wheel force). Both of these operands are
+ in body frame.</li>
+ </ol>
+ @author Jon S. Berndt
+ @version $Id$
+ @see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
+ NASA-Ames", NASA CR-2497, January 1975
+ @see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
+ Wiley & Sons, 1979 ISBN 0-471-03032-5
+ @see W. A. Ragsdale, "A Generic Landing Gear Dynamics Model for LASRS++",
+ AIAA-2000-4303
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGLGear : public FGJSBBase
+{
+public:
+ /// Brake grouping enumerators
+ enum BrakeGroup {bgNone=0, bgLeft, bgRight, bgCenter, bgNose, bgTail };
+ /// Steering group membership enumerators
+ enum SteerType {stSteer, stFixed, stCaster};
+ /// Report type enumerators
+ enum ReportType {erNone=0, erTakeoff, erLand};
+ /** Constructor
+ @param el a pointer to the XML element that contains the CONTACT info.
+ @param Executive a pointer to the parent executive object
+ @param File a pointer to the config file instance */
+ FGLGear(Element* el, FGFDMExec* Executive, int number);
+ /** Constructor
+ @param lgear a reference to an existing FGLGear object */
+ FGLGear(const FGLGear& lgear);
+ /// Destructor
+ ~FGLGear();
+
+
+ /// The Force vector for this gear
+ FGColumnVector3& Force(void);
+ /// The Moment vector for this gear
+ FGColumnVector3& Moment(void) {return vMoment;}
+
+ /// Gets the location of the gear in Body axes
+ FGColumnVector3& GetBodyLocation(void) { return vWhlBodyVec; }
+ double GetBodyLocation(int idx) { return vWhlBodyVec(idx); }
+
+ FGColumnVector3& GetLocalGear(void) { return vLocalGear; }
+ double GetLocalGear(int idx) { return vLocalGear(idx); }
+
+ /// Gets the name of the gear
+ inline string GetName(void) {return name; }
+ /// Gets the Weight On Wheels flag value
+ inline bool GetWOW(void) {return WOW; }
+ /// Gets the current compressed length of the gear in feet
+ inline double GetCompLen(void) {return compressLength;}
+ /// Gets the current gear compression velocity in ft/sec
+ inline double GetCompVel(void) {return compressSpeed; }
+ /// Gets the gear compression force in pounds
+ inline double GetCompForce(void) {return Force()(3); }
+ inline double GetBrakeFCoeff(void) {return BrakeFCoeff;}
+
+ /// Gets the current normalized tire pressure
+ inline double GetTirePressure(void) { return TirePressureNorm; }
+ /// Sets the new normalized tire pressure
+ inline void SetTirePressure(double p) { TirePressureNorm = p; }
+
+ /// Sets the brake value in percent (0 - 100)
+ inline void SetBrake(double bp) {brakePct = bp;}
+
+ /** Set the console touchdown reporting feature
+ @param flag true turns on touchdown reporting, false turns it off */
+ inline void SetReport(bool flag) { ReportEnable = flag; }
+ /** Get the console touchdown reporting feature
+ @return true if reporting is turned on */
+ inline bool GetReport(void) { return ReportEnable; }
+ double GetSteerNorm(void) const { return radtodeg/maxSteerAngle*SteerAngle; }
+ double GetDefaultSteerAngle(double cmd) const { return cmd*maxSteerAngle; }
+ double GetstaticFCoeff(void) { return staticFCoeff; }
+
+ inline int GetBrakeGroup(void) { return (int)eBrakeGrp; }
+ inline int GetSteerType(void) { return (int)eSteerType; }
+
+ bool GetSteerable(void) const { return eSteerType != stFixed; }
+ inline bool GetRetractable(void) { return isRetractable; }
+ inline bool GetGearUnitUp(void) { return GearUp; }
+ inline bool GetGearUnitDown(void) { return GearDown; }
+ inline double GetWheelSideForce(void) { return SideForce; }
+ inline double GetWheelRollForce(void) { return RollingForce; }
+ inline double GetBodyXForce(void) { return vLocalForce(eX); }
+ inline double GetBodyYForce(void) { return vLocalForce(eY); }
+ inline double GetWheelSlipAngle(void) { return WheelSlip; }
+ double GetWheelVel(int axis) { return vWhlVelVec(axis);}
+
+ bool IsBogey(void) {return (sContactType == string("BOGEY"));}
+
+ void bind(void);
+ void unbind(void);
+
+private:
+ int GearNumber;
+ FGColumnVector3 vXYZ;
+ FGColumnVector3 vMoment;
+ FGColumnVector3 vWhlBodyVec;
+ FGColumnVector3 vLocalGear;
+ FGColumnVector3 vForce;
+ FGColumnVector3 last_vForce; // remove this
+ FGColumnVector3 vLocalForce;
+ FGColumnVector3 vWhlVelVec; // Velocity of this wheel (Local)
+ FGColumnVector3 In;
+ FGColumnVector3 prevIn;
+ FGColumnVector3 prevOut;
+ FGTable *ForceY_Table;
+ double SteerAngle;
+ double kSpring;
+ double bDamp;
+ double bDampRebound;
+ double compressLength;
+ double compressSpeed;
+ double staticFCoeff, dynamicFCoeff, rollingFCoeff;
+ double brakePct;
+ double BrakeFCoeff;
+ double maxCompLen;
+ double SinkRate;
+ double GroundSpeed;
+ double TakeoffDistanceTraveled;
+ double TakeoffDistanceTraveled50ft;
+ double LandingDistanceTraveled;
+ double MaximumStrutForce;
+ double MaximumStrutTravel;
+ double SideWhlVel, RollingWhlVel;
+ double RollingForce, SideForce, FCoeff;
+ double WheelSlip;
+ double last_WheelSlip;
+ double slipIn;
+ double last_SlipIn;
+ double TirePressureNorm;
+ double SinWheel, CosWheel;
+ bool WOW;
+ bool lastWOW;
+ bool FirstContact;
+ bool StartedGroundRun;
+ bool LandingReported;
+ bool TakeoffReported;
+ bool ReportEnable;
+ bool isRetractable;
+ bool GearUp, GearDown;
+ bool Servicable;
+ string name;
+ string sSteerType;
+ string sBrakeGroup;
+ string sRetractable;
+ string sContactType;
+
+ BrakeGroup eBrakeGrp;
+ SteerType eSteerType;
+ double maxSteerAngle;
+
+ FGFDMExec* Exec;
+ FGState* State;
+ FGAircraft* Aircraft;
+ FGPropagate* Propagate;
+ FGAuxiliary* Auxiliary;
+ FGFCS* FCS;
+ FGMassBalance* MassBalance;
+
+ void ComputeRetractionState(void);
+ void ComputeBrakeForceCoefficient(void);
+ void ComputeSteeringAngle(void);
+ void ComputeSlipAngle(void);
+ void ComputeSideForceCoefficient(void);
+ void ComputeVerticalStrutForce(void);
+ void CrashDetect(void);
+ void InitializeReporting(void);
+ void ResetReporting(void);
+ void ReportTakeoffOrLanding(void);
+ void Report(ReportType rt);
+ void Debug(int from);
+};
+}
+#include "FGAircraft.h"
+#include "FGPropagate.h"
+#include "FGAuxiliary.h"
+#include "FGFCS.h"
+#include "FGMassBalance.h"
+#include "FGState.h"
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGMassBalance.cpp
+ Author: Jon S. Berndt
+ Date started: 09/12/2000
+ Purpose: This module models weight and balance
+
+ ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) --------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+This class models the change in weight and balance of the aircraft due to fuel
+burnoff, etc.
+
+HISTORY
+--------------------------------------------------------------------------------
+09/12/2000 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGMassBalance.h"
+#include "FGPropulsion.h"
+#include <input_output/FGPropertyManager.h>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_MASSBALANCE;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+FGMassBalance::FGMassBalance(FGFDMExec* fdmex) : FGModel(fdmex)
+{
+ Name = "FGMassBalance";
+ Weight = EmptyWeight = Mass = 0.0;
+
+ vbaseXYZcg.InitMatrix(0.0);
+ baseJ.InitMatrix();
+ mJ.InitMatrix();
+ mJinv.InitMatrix();
+ pmJ.InitMatrix();
+
+ bind();
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGMassBalance::~FGMassBalance()
+{
+ unbind();
+ PointMasses.clear();
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGMassBalance::Load(Element* el)
+{
+ Element *element;
+ string element_name = "";
+ double bixx, biyy, bizz, bixy, bixz, biyz;
+
+ bixx = biyy = bizz = bixy = bixz = biyz = 0.0;
+ if (el->FindElement("ixx"))
+ bixx = el->FindElementValueAsNumberConvertTo("ixx", "SLUG*FT2");
+ if (el->FindElement("iyy"))
+ biyy = el->FindElementValueAsNumberConvertTo("iyy", "SLUG*FT2");
+ if (el->FindElement("izz"))
+ bizz = el->FindElementValueAsNumberConvertTo("izz", "SLUG*FT2");
+ if (el->FindElement("ixy"))
+ bixy = el->FindElementValueAsNumberConvertTo("ixy", "SLUG*FT2");
+ if (el->FindElement("ixz"))
+ bixz = el->FindElementValueAsNumberConvertTo("ixz", "SLUG*FT2");
+ if (el->FindElement("iyz"))
+ biyz = el->FindElementValueAsNumberConvertTo("iyz", "SLUG*FT2");
+ SetAircraftBaseInertias(FGMatrix33( bixx, -bixy, -bixz,
+ -bixy, biyy, -biyz,
+ -bixz, -biyz, bizz ));
+ EmptyWeight = el->FindElementValueAsNumberConvertTo("emptywt", "LBS");
+
+ element = el->FindElement("location");
+ while (element) {
+ element_name = element->GetAttributeValue("name");
+ if (element_name == "CG") vbaseXYZcg = element->FindElementTripletConvertTo("IN");
+ element = el->FindNextElement("location");
+ }
+
+// Find all POINTMASS elements that descend from this METRICS branch of the
+// config file.
+
+ element = el->FindElement("pointmass");
+ while (element) {
+ AddPointMass(element);
+ element = el->FindNextElement("pointmass");
+ }
+
+ Debug(2);
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGMassBalance::Run(void)
+{
+ double denom, k1, k2, k3, k4, k5, k6;
+ double Ixx, Iyy, Izz, Ixy, Ixz, Iyz;
+
+ if (FGModel::Run()) return true;
+ if (FDMExec->Holding()) return false;
+
+ Weight = EmptyWeight + Propulsion->GetTanksWeight() + GetPointMassWeight();
+
+ Mass = lbtoslug*Weight;
+
+// Calculate new CG
+
+// printf("%s:%i\n", __FILE__, __LINE__);
+ vXYZcg = (Propulsion->GetTanksMoment() + EmptyWeight*vbaseXYZcg
+ + GetPointMassMoment() ) / Weight;
+
+// Calculate new total moments of inertia
+
+ // At first it is the base configuration inertia matrix ...
+ mJ = baseJ;
+ // ... with the additional term originating from the parallel axis theorem.
+ mJ += GetPointmassInertia( lbtoslug * EmptyWeight, vbaseXYZcg );
+ // Then add the contributions from the additional pointmasses.
+ mJ += CalculatePMInertias();
+ mJ += Propulsion->CalculateTankInertias();
+
+ Ixx = mJ(1,1);
+ Iyy = mJ(2,2);
+ Izz = mJ(3,3);
+ Ixy = -mJ(1,2);
+ Ixz = -mJ(1,3);
+ Iyz = -mJ(2,3);
+
+// Calculate inertia matrix inverse (ref. Stevens and Lewis, "Flight Control & Simulation")
+
+ k1 = (Iyy*Izz - Iyz*Iyz);
+ k2 = (Iyz*Ixz + Ixy*Izz);
+ k3 = (Ixy*Iyz + Iyy*Ixz);
+
+ denom = 1.0/(Ixx*k1 - Ixy*k2 - Ixz*k3 );
+ k1 = k1*denom;
+ k2 = k2*denom;
+ k3 = k3*denom;
+ k4 = (Izz*Ixx - Ixz*Ixz)*denom;
+ k5 = (Ixy*Ixz + Iyz*Ixx)*denom;
+ k6 = (Ixx*Iyy - Ixy*Ixy)*denom;
+
+ mJinv.InitMatrix( k1, k2, k3,
+ k2, k4, k5,
+ k3, k5, k6 );
+
+ Debug(0);
+
+ return false;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGMassBalance::AddPointMass(Element* el)
+{
+ Element* loc_element = el->FindElement("location");
+ string pointmass_name = el->GetAttributeValue("name");
+ if (!el) {
+ cerr << "Pointmass " << pointmass_name << "has no location." << endl;
+ exit(-1);
+ }
+ string loc_unit = loc_element->GetAttributeValue("unit");
+ double w, x, y, z;
+
+ w = el->FindElementValueAsNumberConvertTo("weight", "LBS");
+ x = loc_element->FindElementValueAsNumberConvertTo("x", loc_unit);
+ y = loc_element->FindElementValueAsNumberConvertTo("y", loc_unit);
+ z = loc_element->FindElementValueAsNumberConvertTo("z", loc_unit);
+
+ PointMasses.push_back(PointMass(w, x, y, z));
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGMassBalance::GetPointMassWeight(void)
+{
+ double PM_total_weight = 0.0;
+
+ for (unsigned int i=0; i<PointMasses.size(); i++) {
+ PM_total_weight += PointMasses[i].Weight;
+ }
+ return PM_total_weight;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGColumnVector3& FGMassBalance::GetPointMassMoment(void)
+{
+ PointMassCG.InitMatrix();
+
+ for (unsigned int i=0; i<PointMasses.size(); i++) {
+ PointMassCG += PointMasses[i].Weight*PointMasses[i].Location;
+ }
+ return PointMassCG;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGMatrix33& FGMassBalance::CalculatePMInertias(void)
+{
+ unsigned int size;
+
+ size = PointMasses.size();
+ if (size == 0) return pmJ;
+
+ pmJ = FGMatrix33();
+
+ for (unsigned int i=0; i<size; i++)
+ pmJ += GetPointmassInertia( lbtoslug * PointMasses[i].Weight, PointMasses[i].Location );
+
+ return pmJ;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGColumnVector3 FGMassBalance::StructuralToBody(const FGColumnVector3& r) const
+{
+ // Under the assumption that in the structural frame the:
+ //
+ // - X-axis is directed afterwards,
+ // - Y-axis is directed towards the right,
+ // - Z-axis is directed upwards,
+ //
+ // (as documented in http://jsbsim.sourceforge.net/JSBSimCoordinates.pdf)
+ // we have to subtract first the center of gravity of the plane which
+ // is also defined in the structural frame:
+ //
+ // FGColumnVector3 cgOff = r - vXYZcg;
+ //
+ // Next, we do a change of units:
+ //
+ // cgOff *= inchtoft;
+ //
+ // And then a 180 degree rotation is done about the Y axis so that the:
+ //
+ // - X-axis is directed forward,
+ // - Y-axis is directed towards the right,
+ // - Z-axis is directed downward.
+ //
+ // This is needed because the structural and body frames are 180 degrees apart.
+
+ return FGColumnVector3(inchtoft*(vXYZcg(1)-r(1)),
+ inchtoft*(r(2)-vXYZcg(2)),
+ inchtoft*(vXYZcg(3)-r(3)));
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGMassBalance::bind(void)
+{
+ typedef double (FGMassBalance::*PMF)(int) const;
+ PropertyManager->Tie("inertia/mass-slugs", this,
+ &FGMassBalance::GetMass);
+ PropertyManager->Tie("inertia/weight-lbs", this,
+ &FGMassBalance::GetWeight);
+ PropertyManager->Tie("inertia/cg-x-ft", this,1,
+ (PMF)&FGMassBalance::GetXYZcg);
+ PropertyManager->Tie("inertia/cg-y-ft", this,2,
+ (PMF)&FGMassBalance::GetXYZcg);
+ PropertyManager->Tie("inertia/cg-z-ft", this,3,
+ (PMF)&FGMassBalance::GetXYZcg);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGMassBalance::unbind(void)
+{
+ PropertyManager->Untie("inertia/mass-slugs");
+ PropertyManager->Untie("inertia/weight-lbs");
+ PropertyManager->Untie("inertia/cg-x-ft");
+ PropertyManager->Untie("inertia/cg-y-ft");
+ PropertyManager->Untie("inertia/cg-z-ft");
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGMassBalance::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 2) { // Loading
+ cout << endl << " Mass and Balance:" << endl;
+ cout << " baseIxx: " << baseJ(1,1) << " slug-ft2" << endl;
+ cout << " baseIyy: " << baseJ(2,2) << " slug-ft2" << endl;
+ cout << " baseIzz: " << baseJ(3,3) << " slug-ft2" << endl;
+ cout << " baseIxy: " << baseJ(1,2) << " slug-ft2" << endl;
+ cout << " baseIxz: " << baseJ(1,3) << " slug-ft2" << endl;
+ cout << " baseIyz: " << baseJ(2,3) << " slug-ft2" << endl;
+ cout << " EmptyWeight: " << EmptyWeight << " lbm" << endl;
+ cout << " CG (x, y, z): " << vbaseXYZcg << endl;
+ // ToDo: Need to add point mass outputs here
+ for (int i=0; i<PointMasses.size(); i++) {
+ cout << " Point Mass Object: " << PointMasses[i].Weight << " lbs. at "
+ << "X, Y, Z (in.): " << PointMasses[i].Location(eX) << " "
+ << PointMasses[i].Location(eY) << " "
+ << PointMasses[i].Location(eZ) << endl;
+ }
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGMassBalance" << endl;
+ if (from == 1) cout << "Destroyed: FGMassBalance" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ if (from == 2) {
+ if (EmptyWeight <= 0.0 || EmptyWeight > 1e9)
+ cout << "MassBalance::EmptyWeight out of bounds: " << EmptyWeight << endl;
+ if (Weight <= 0.0 || Weight > 1e9)
+ cout << "MassBalance::Weight out of bounds: " << Weight << endl;
+ if (Mass <= 0.0 || Mass > 1e9)
+ cout << "MassBalance::Mass out of bounds: " << Mass << endl;
+ }
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGMassBalance.h
+ Author: Jon S. Berndt
+ Date started: 09/12/2000
+
+ ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) --------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+09/12/2000 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGMASSBALANCE_H
+#define FGMASSBALANCE_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGModel.h"
+#include <math/FGColumnVector3.h>
+#include <math/FGMatrix33.h>
+#include <input_output/FGXMLElement.h>
+#include <vector>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_MASSBALANCE "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONSS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models weight and balance information.
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGMassBalance : public FGModel
+{
+
+public:
+ FGMassBalance(FGFDMExec*);
+ ~FGMassBalance();
+
+ bool Load(Element* el);
+
+ bool Run(void);
+
+ inline double GetMass(void) const {return Mass;}
+ inline double GetWeight(void) const {return Weight;}
+ inline FGColumnVector3& GetXYZcg(void) {return vXYZcg;}
+ inline double GetXYZcg(int axis) const {return vXYZcg(axis);}
+
+ /** Computes the inertia contribution of a pointmass.
+ Computes and returns the inertia matrix of a pointmass of mass
+ slugs at the given vector r in the structural frame. The units
+ should be for the mass in slug and the vector in the structural
+ frame as usual in inches.
+ @param slugs the mass of this single pointmass given in slugs
+ @param r the location of this single pointmass in the structural frame
+ */
+ FGMatrix33 GetPointmassInertia(double slugs, const FGColumnVector3& r) const
+ {
+ FGColumnVector3 v = StructuralToBody( r );
+ FGColumnVector3 sv = slugs*v;
+ double xx = sv(1)*v(1);
+ double yy = sv(2)*v(2);
+ double zz = sv(3)*v(3);
+ double xy = -sv(1)*v(2);
+ double xz = -sv(1)*v(3);
+ double yz = -sv(2)*v(3);
+ return FGMatrix33( yy+zz, xy, xz,
+ xy, xx+zz, yz,
+ xz, yz, xx+yy );
+ }
+
+ /** Conversion from the structural frame to the body frame.
+ Converts the location given in the structural frame
+ coordinate system to the body frame. The units of the structural
+ frame are assumed to be in inches. The unit of the result is in
+ ft.
+ @param r vector coordinate in the structural reference frame (X positive
+ aft, measurements in inches).
+ @return vector coordinate in the body frame, in feet.
+ */
+ FGColumnVector3 StructuralToBody(const FGColumnVector3& r) const;
+
+ inline void SetEmptyWeight(double EW) { EmptyWeight = EW;}
+ inline void SetBaseCG(const FGColumnVector3& CG) {vbaseXYZcg = vXYZcg = CG;}
+
+ void AddPointMass(Element* el);
+ double GetPointMassWeight(void);
+ FGColumnVector3& GetPointMassMoment(void);
+ FGMatrix33& GetJ(void) {return mJ;}
+ FGMatrix33& GetJinv(void) {return mJinv;}
+ void SetAircraftBaseInertias(FGMatrix33 BaseJ) {baseJ = BaseJ;}
+
+ void bind(void);
+ void unbind(void);
+
+private:
+ double Weight;
+ double EmptyWeight;
+ double Mass;
+ FGMatrix33 mJ;
+ FGMatrix33 mJinv;
+ FGMatrix33 pmJ;
+ FGMatrix33 baseJ;
+ FGColumnVector3 vXYZcg;
+ FGColumnVector3 vXYZtank;
+ FGColumnVector3 vbaseXYZcg;
+ FGColumnVector3 vPMxyz;
+ FGColumnVector3 PointMassCG;
+ FGMatrix33& CalculatePMInertias(void);
+
+ struct PointMass {
+ PointMass(double w, double x, double y, double z) {
+ Weight = w;
+ Location.InitMatrix(x, y, z);
+ }
+ FGColumnVector3 Location;
+ double Weight;
+ };
+
+ vector <struct PointMass> PointMasses;
+
+ void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGModel.cpp
+ Author: Jon Berndt
+ Date started: 11/11/98
+ Purpose: Base class for all models
+ Called by: FGSimExec, et. al.
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+This base class for the FGAerodynamics, FGPropagate, etc. classes defines methods
+common to all models.
+
+HISTORY
+--------------------------------------------------------------------------------
+11/11/98 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGModel.h"
+#include "FGState.h"
+#include "FGFDMExec.h"
+#include "FGAtmosphere.h"
+#include "FGFCS.h"
+#include "FGPropulsion.h"
+#include "FGMassBalance.h"
+#include "FGAerodynamics.h"
+#include "FGInertial.h"
+#include "FGGroundReactions.h"
+#include "FGAircraft.h"
+#include "FGPropagate.h"
+#include "FGAuxiliary.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_MODEL;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+GLOBAL DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGModel::FGModel(FGFDMExec* fdmex)
+{
+ FDMExec = fdmex;
+ NextModel = 0L;
+
+ State = 0;
+ Atmosphere = 0;
+ FCS = 0;
+ Propulsion = 0;
+ MassBalance = 0;
+ Aerodynamics = 0;
+ Inertial = 0;
+ GroundReactions = 0;
+ Aircraft = 0;
+ Propagate = 0;
+ Auxiliary = 0;
+
+ //in order for FGModel derived classes to self-bind (that is, call
+ //their bind function in the constructor, the PropertyManager pointer
+ //must be brought up now.
+ PropertyManager = FDMExec->GetPropertyManager();
+
+ exe_ctr = 1;
+ rate = 1;
+
+ if (debug_lvl & 2) cout << " FGModel Base Class" << endl;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGModel::~FGModel()
+{
+ if (debug_lvl & 2) cout << "Destroyed: FGModel" << endl;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGModel::InitModel(void)
+{
+ State = FDMExec->GetState();
+ Atmosphere = FDMExec->GetAtmosphere();
+ FCS = FDMExec->GetFCS();
+ Propulsion = FDMExec->GetPropulsion();
+ MassBalance = FDMExec->GetMassBalance();
+ Aerodynamics = FDMExec->GetAerodynamics();
+ Inertial = FDMExec->GetInertial();
+ GroundReactions = FDMExec->GetGroundReactions();
+ Aircraft = FDMExec->GetAircraft();
+ Propagate = FDMExec->GetPropagate();
+ Auxiliary = FDMExec->GetAuxiliary();
+
+ if (!State ||
+ !Atmosphere ||
+ !FCS ||
+ !Propulsion ||
+ !MassBalance ||
+ !Aerodynamics ||
+ !Inertial ||
+ !GroundReactions ||
+ !Aircraft ||
+ !Propagate ||
+ !Auxiliary) return(false);
+ else return(true);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGModel::Run()
+{
+ if (debug_lvl & 4) cout << "Entering Run() for model " << Name << endl;
+
+ if (exe_ctr == 1) {
+ if (exe_ctr++ >= rate) exe_ctr = 1;
+ return false;
+ } else {
+ if (exe_ctr++ >= rate) exe_ctr = 1;
+ return true;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGModel::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGModel" << endl;
+ if (from == 1) cout << "Destroyed: FGModel" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGModel.h
+ Author: Jon Berndt
+ Date started: 11/21/98
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+11/22/98 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGMODEL_H
+#define FGMODEL_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <FGJSBBase.h>
+#include <input_output/FGPropertyManager.h>
+#include <input_output/FGXMLElement.h>
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# ifdef SG_HAVE_STD_INCLUDES
+# include <iostream>
+# else
+# include <iostream.h>
+# endif
+#else
+# if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
+# include <iostream.h>
+# else
+# include <iostream>
+# endif
+#endif
+
+#include <string>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_MODEL "$Id$"
+
+using namespace std;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+class FGFDMExec;
+class FGState;
+class FGAtmosphere;
+class FGFCS;
+class FGPropulsion;
+class FGMassBalance;
+class FGAerodynamics;
+class FGInertial;
+class FGGroundReactions;
+class FGAircraft;
+class FGPropagate;
+class FGAuxiliary;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Base class for all scheduled JSBSim models
+ @author Jon S. Berndt
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGModel : public FGJSBBase
+{
+public:
+
+ /// Constructor
+ FGModel(FGFDMExec*);
+ /// Destructor
+ virtual ~FGModel();
+
+ /** Loads this model.
+ @param el a pointer to the element
+ @return true if model is successfully loaded*/
+ virtual bool Load(Element* el) {return true;}
+
+ FGModel* NextModel;
+ string Name;
+
+ /** Runs the model; called by the Executive
+ @see JSBSim.cpp documentation
+ @return false if no error */
+ virtual bool Run(void);
+ virtual bool InitModel(void);
+ virtual void SetRate(int tt) {rate = tt;}
+ virtual int GetRate(void) {return rate;}
+
+ void SetPropertyManager(FGPropertyManager *fgpm) { PropertyManager=fgpm;}
+
+protected:
+ int exe_ctr;
+ int rate;
+
+ virtual void Debug(int from);
+
+ FGFDMExec* FDMExec;
+ FGState* State;
+ FGAtmosphere* Atmosphere;
+ FGFCS* FCS;
+ FGPropulsion* Propulsion;
+ FGMassBalance* MassBalance;
+ FGAerodynamics* Aerodynamics;
+ FGInertial* Inertial;
+ FGGroundReactions* GroundReactions;
+ FGAircraft* Aircraft;
+ FGPropagate* Propagate;
+ FGAuxiliary* Auxiliary;
+ FGPropertyManager* PropertyManager;
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGOutput.cpp
+ Author: Jon Berndt
+ Date started: 12/02/98
+ Purpose: Manage output of sim parameters to file or stdout
+ Called by: FGSimExec
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+This is the place where you create output routines to dump data for perusal
+later.
+
+HISTORY
+--------------------------------------------------------------------------------
+12/02/98 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGOutput.h"
+#include "FGState.h"
+#include "FGFDMExec.h"
+#include "FGAtmosphere.h"
+#include "FGFCS.h"
+#include "FGAerodynamics.h"
+#include "FGGroundReactions.h"
+#include "FGAircraft.h"
+#include "FGMassBalance.h"
+#include "FGPropagate.h"
+#include "FGAuxiliary.h"
+#include "FGInertial.h"
+
+#include <fstream>
+#include <iomanip>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_OUTPUT;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGOutput::FGOutput(FGFDMExec* fdmex) : FGModel(fdmex)
+{
+ Name = "FGOutput";
+ sFirstPass = dFirstPass = true;
+ socket = 0;
+ Type = otNone;
+ SubSystems = 0;
+ enabled = true;
+ delimeter = ", ";
+ Filename = "";
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGOutput::~FGOutput()
+{
+ if (socket) delete socket;
+ OutputProperties.clear();
+
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGOutput::Run(void)
+{
+ if (FGModel::Run()) return true;
+
+ if (enabled && !State->IntegrationSuspended()&& !FDMExec->Holding()) {
+ if (Type == otSocket) {
+ SocketOutput();
+ } else if (Type == otCSV || Type == otTab) {
+ DelimitedOutput(Filename);
+ } else if (Type == otTerminal) {
+ // Not done yet
+ } else if (Type == otNone) {
+ // Do nothing
+ } else {
+ // Not a valid type of output
+ }
+ }
+ return false;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGOutput::SetType(string type)
+{
+ if (type == "CSV") {
+ Type = otCSV;
+ delimeter = ", ";
+ } else if (type == "TABULAR") {
+ Type = otTab;
+ delimeter = "\t";
+ } else if (type == "SOCKET") {
+ Type = otSocket;
+ } else if (type == "TERMINAL") {
+ Type = otTerminal;
+ } else if (type != string("NONE")) {
+ Type = otUnknown;
+ cerr << "Unknown type of output specified in config file" << endl;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGOutput::DelimitedOutput(string fname)
+{
+ streambuf* buffer;
+ string scratch = "";
+
+ if (fname == "COUT" || fname == "cout") {
+ buffer = cout.rdbuf();
+ } else {
+ datafile.open(fname.c_str());
+ buffer = datafile.rdbuf();
+ }
+
+ ostream outstream(buffer);
+
+ if (dFirstPass) {
+ outstream << "Time";
+ if (SubSystems & ssSimulation) {
+ // Nothing here, yet
+ }
+ if (SubSystems & ssAerosurfaces) {
+ outstream << delimeter;
+ outstream << "Aileron Cmd" + delimeter;
+ outstream << "Elevator Cmd" + delimeter;
+ outstream << "Rudder Cmd" + delimeter;
+ outstream << "Flap Cmd" + delimeter;
+ outstream << "Left Aileron Pos" + delimeter;
+ outstream << "Right Aileron Pos" + delimeter;
+ outstream << "Elevator Pos" + delimeter;
+ outstream << "Rudder Pos" + delimeter;
+ outstream << "Flap Pos";
+ }
+ if (SubSystems & ssRates) {
+ outstream << delimeter;
+ outstream << "P" + delimeter + "Q" + delimeter + "R" + delimeter;
+ outstream << "Pdot" + delimeter + "Qdot" + delimeter + "Rdot";
+ }
+ if (SubSystems & ssVelocities) {
+ outstream << delimeter;
+ outstream << "QBar" + delimeter;
+ outstream << "Vtotal" + delimeter;
+ outstream << "UBody" + delimeter + "VBody" + delimeter + "WBody" + delimeter;
+ outstream << "UAero" + delimeter + "VAero" + delimeter + "WAero" + delimeter;
+ outstream << "Vn" + delimeter + "Ve" + delimeter + "Vd";
+ }
+ if (SubSystems & ssForces) {
+ outstream << delimeter;
+ outstream << "Drag" + delimeter + "Side" + delimeter + "Lift" + delimeter;
+ outstream << "L/D" + delimeter;
+ outstream << "Xforce" + delimeter + "Yforce" + delimeter + "Zforce";
+ }
+ if (SubSystems & ssMoments) {
+ outstream << delimeter;
+ outstream << "L" + delimeter + "M" + delimeter + "N";
+ }
+ if (SubSystems & ssAtmosphere) {
+ outstream << delimeter;
+ outstream << "Rho" + delimeter;
+ outstream << "SL pressure" + delimeter;
+ outstream << "Ambient pressure" + delimeter;
+ outstream << "NWind" + delimeter + "EWind" + delimeter + "DWind";
+ }
+ if (SubSystems & ssMassProps) {
+ outstream << delimeter;
+ outstream << "Ixx" + delimeter;
+ outstream << "Ixy" + delimeter;
+ outstream << "Ixz" + delimeter;
+ outstream << "Iyx" + delimeter;
+ outstream << "Iyy" + delimeter;
+ outstream << "Iyz" + delimeter;
+ outstream << "Izx" + delimeter;
+ outstream << "Izy" + delimeter;
+ outstream << "Izz" + delimeter;
+ outstream << "Mass" + delimeter;
+ outstream << "Xcg" + delimeter + "Ycg" + delimeter + "Zcg";
+ }
+ if (SubSystems & ssPropagate) {
+ outstream << delimeter;
+ outstream << "Altitude" + delimeter;
+ outstream << "Phi" + delimeter + "Tht" + delimeter + "Psi" + delimeter;
+ outstream << "Alpha" + delimeter;
+ outstream << "Beta" + delimeter;
+ outstream << "Latitude (Deg)" + delimeter;
+ outstream << "Longitude (Deg)" + delimeter;
+ outstream << "Distance AGL" + delimeter;
+ outstream << "Runway Radius";
+ }
+ if (SubSystems & ssCoefficients) {
+ scratch = Aerodynamics->GetCoefficientStrings(delimeter);
+ if (scratch.length() != 0) outstream << delimeter << scratch;
+ }
+ if (SubSystems & ssFCS) {
+ scratch = FCS->GetComponentStrings(delimeter);
+ if (scratch.length() != 0) outstream << delimeter << scratch;
+ }
+ if (SubSystems & ssGroundReactions) {
+ outstream << delimeter;
+ outstream << GroundReactions->GetGroundReactionStrings(delimeter);
+ }
+ if (SubSystems & ssPropulsion && Propulsion->GetNumEngines() > 0) {
+ outstream << delimeter;
+ outstream << Propulsion->GetPropulsionStrings(delimeter);
+ }
+ if (OutputProperties.size() > 0) {
+ for (unsigned int i=0;i<OutputProperties.size();i++) {
+ outstream << delimeter << OutputProperties[i]->GetName();
+ }
+ }
+
+ outstream << endl;
+ dFirstPass = false;
+ }
+
+ outstream << State->Getsim_time();
+ if (SubSystems & ssSimulation) {
+ }
+ if (SubSystems & ssAerosurfaces) {
+ outstream << delimeter;
+ outstream << FCS->GetDaCmd() << delimeter;
+ outstream << FCS->GetDeCmd() << delimeter;
+ outstream << FCS->GetDrCmd() << delimeter;
+ outstream << FCS->GetDfCmd() << delimeter;
+ outstream << FCS->GetDaLPos() << delimeter;
+ outstream << FCS->GetDaRPos() << delimeter;
+ outstream << FCS->GetDePos() << delimeter;
+ outstream << FCS->GetDrPos() << delimeter;
+ outstream << FCS->GetDfPos();
+ }
+ if (SubSystems & ssRates) {
+ outstream << delimeter;
+ outstream << Propagate->GetPQR().Dump(delimeter) << delimeter;
+ outstream << Propagate->GetPQRdot().Dump(delimeter);
+ }
+ if (SubSystems & ssVelocities) {
+ outstream << delimeter;
+ outstream << Auxiliary->Getqbar() << delimeter;
+ outstream << setprecision(12) << Auxiliary->GetVt() << delimeter;
+ outstream << setprecision(12) << Propagate->GetUVW().Dump(delimeter) << delimeter;
+ outstream << Auxiliary->GetAeroUVW().Dump(delimeter) << delimeter;
+ outstream << Propagate->GetVel().Dump(delimeter);
+ }
+ if (SubSystems & ssForces) {
+ outstream << delimeter;
+ outstream << Aerodynamics->GetvFs() << delimeter;
+ outstream << Aerodynamics->GetLoD() << delimeter;
+ outstream << Aircraft->GetForces().Dump(delimeter);
+ }
+ if (SubSystems & ssMoments) {
+ outstream << delimeter;
+ outstream << Aircraft->GetMoments().Dump(delimeter);
+ }
+ if (SubSystems & ssAtmosphere) {
+ outstream << delimeter;
+ outstream << Atmosphere->GetDensity() << delimeter;
+ outstream << Atmosphere->GetPressureSL() << delimeter;
+ outstream << Atmosphere->GetPressure() << delimeter;
+ outstream << Atmosphere->GetWindNED().Dump(delimeter);
+ }
+ if (SubSystems & ssMassProps) {
+ outstream << delimeter;
+ outstream << MassBalance->GetJ() << delimeter;
+ outstream << MassBalance->GetMass() << delimeter;
+ outstream << MassBalance->GetXYZcg();
+ }
+ if (SubSystems & ssPropagate) {
+ outstream << delimeter;
+ outstream << Propagate->Geth() << delimeter;
+ outstream << Propagate->GetEuler().Dump(delimeter) << delimeter;
+ outstream << Auxiliary->Getalpha(inDegrees) << delimeter;
+ outstream << Auxiliary->Getbeta(inDegrees) << delimeter;
+ outstream << Propagate->GetLocation().GetLatitudeDeg() << delimeter;
+ outstream << Propagate->GetLocation().GetLongitudeDeg() << delimeter;
+ outstream << Propagate->GetDistanceAGL() << delimeter;
+ outstream << Propagate->GetRunwayRadius();
+ }
+ if (SubSystems & ssCoefficients) {
+ scratch = Aerodynamics->GetCoefficientValues(delimeter);
+ if (scratch.length() != 0) outstream << delimeter << scratch;
+ }
+ if (SubSystems & ssFCS) {
+ scratch = FCS->GetComponentValues(delimeter);
+ if (scratch.length() != 0) outstream << delimeter << scratch;
+ }
+ if (SubSystems & ssGroundReactions) {
+ outstream << delimeter;
+ outstream << GroundReactions->GetGroundReactionValues(delimeter);
+ }
+ if (SubSystems & ssPropulsion && Propulsion->GetNumEngines() > 0) {
+ outstream << delimeter;
+ outstream << Propulsion->GetPropulsionValues(delimeter);
+ }
+
+ for (unsigned int i=0;i<OutputProperties.size();i++) {
+ outstream << delimeter << OutputProperties[i]->getDoubleValue();
+ }
+
+ outstream << endl;
+ outstream.flush();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGOutput::SocketOutput(void)
+{
+ string asciiData, scratch;
+
+ if (socket == NULL) return;
+ if (!socket->GetConnectStatus()) return;
+
+ socket->Clear();
+ if (sFirstPass) {
+ socket->Clear("<LABELS>");
+ socket->Append("Time");
+
+ if (SubSystems & ssAerosurfaces) {
+ socket->Append("Aileron Command");
+ socket->Append("Elevator Command");
+ socket->Append("Rudder Command");
+ socket->Append("Flap Command");
+ socket->Append("Left Aileron Position");
+ socket->Append("Right Aileron Position");
+ socket->Append("Elevator Position");
+ socket->Append("Rudder Position");
+ socket->Append("Flap Position");
+ }
+
+ if (SubSystems & ssRates) {
+ socket->Append("P");
+ socket->Append("Q");
+ socket->Append("R");
+ socket->Append("PDot");
+ socket->Append("QDot");
+ socket->Append("RDot");
+ }
+
+ if (SubSystems & ssVelocities) {
+ socket->Append("QBar");
+ socket->Append("Vtotal");
+ socket->Append("UBody");
+ socket->Append("VBody");
+ socket->Append("WBody");
+ socket->Append("UAero");
+ socket->Append("VAero");
+ socket->Append("WAero");
+ socket->Append("Vn");
+ socket->Append("Ve");
+ socket->Append("Vd");
+ }
+ if (SubSystems & ssForces) {
+ socket->Append("F_Drag");
+ socket->Append("F_Side");
+ socket->Append("F_Lift");
+ socket->Append("LoD");
+ socket->Append("Fx");
+ socket->Append("Fy");
+ socket->Append("Fz");
+ }
+ if (SubSystems & ssMoments) {
+ socket->Append("L");
+ socket->Append("M");
+ socket->Append("N");
+ }
+ if (SubSystems & ssAtmosphere) {
+ socket->Append("Rho");
+ socket->Append("SL pressure");
+ socket->Append("Ambient pressure");
+ socket->Append("NWind");
+ socket->Append("EWind");
+ socket->Append("DWind");
+ }
+ if (SubSystems & ssMassProps) {
+ socket->Append("Ixx");
+ socket->Append("Ixy");
+ socket->Append("Ixz");
+ socket->Append("Iyx");
+ socket->Append("Iyy");
+ socket->Append("Iyz");
+ socket->Append("Izx");
+ socket->Append("Izy");
+ socket->Append("Izz");
+ socket->Append("Mass");
+ socket->Append("Xcg");
+ socket->Append("Ycg");
+ socket->Append("Zcg");
+ }
+ if (SubSystems & ssPropagate) {
+ socket->Append("Altitude");
+ socket->Append("Phi");
+ socket->Append("Tht");
+ socket->Append("Psi");
+ socket->Append("Alpha");
+ socket->Append("Beta");
+ socket->Append("Latitude (Deg)");
+ socket->Append("Longitude (Deg)");
+ }
+ if (SubSystems & ssCoefficients) {
+ scratch = Aerodynamics->GetCoefficientStrings(",");
+ if (scratch.length() != 0) socket->Append(scratch);
+ }
+ if (SubSystems & ssFCS) {
+ scratch = FCS->GetComponentStrings(",");
+ if (scratch.length() != 0) socket->Append(scratch);
+ }
+ if (SubSystems & ssGroundReactions) {
+ socket->Append(GroundReactions->GetGroundReactionStrings(","));
+ }
+ if (SubSystems & ssPropulsion && Propulsion->GetNumEngines() > 0) {
+ socket->Append(Propulsion->GetPropulsionStrings(","));
+ }
+ if (OutputProperties.size() > 0) {
+ for (unsigned int i=0;i<OutputProperties.size();i++) {
+ socket->Append(OutputProperties[i]->GetName());
+ }
+ }
+
+ sFirstPass = false;
+ socket->Send();
+ }
+
+ socket->Clear();
+ socket->Append(State->Getsim_time());
+
+ if (SubSystems & ssAerosurfaces) {
+ socket->Append(FCS->GetDaCmd());
+ socket->Append(FCS->GetDeCmd());
+ socket->Append(FCS->GetDrCmd());
+ socket->Append(FCS->GetDfCmd());
+ socket->Append(FCS->GetDaLPos());
+ socket->Append(FCS->GetDaRPos());
+ socket->Append(FCS->GetDePos());
+ socket->Append(FCS->GetDrPos());
+ socket->Append(FCS->GetDfPos());
+ }
+ if (SubSystems & ssRates) {
+ socket->Append(Propagate->GetPQR(eP));
+ socket->Append(Propagate->GetPQR(eQ));
+ socket->Append(Propagate->GetPQR(eR));
+ socket->Append(Propagate->GetPQRdot(eP));
+ socket->Append(Propagate->GetPQRdot(eQ));
+ socket->Append(Propagate->GetPQRdot(eR));
+ }
+ if (SubSystems & ssVelocities) {
+ socket->Append(Auxiliary->Getqbar());
+ socket->Append(Auxiliary->GetVt());
+ socket->Append(Propagate->GetUVW(eU));
+ socket->Append(Propagate->GetUVW(eV));
+ socket->Append(Propagate->GetUVW(eW));
+ socket->Append(Auxiliary->GetAeroUVW(eU));
+ socket->Append(Auxiliary->GetAeroUVW(eV));
+ socket->Append(Auxiliary->GetAeroUVW(eW));
+ socket->Append(Propagate->GetVel(eNorth));
+ socket->Append(Propagate->GetVel(eEast));
+ socket->Append(Propagate->GetVel(eDown));
+ }
+ if (SubSystems & ssForces) {
+ socket->Append(Aerodynamics->GetvFs()(eDrag));
+ socket->Append(Aerodynamics->GetvFs()(eSide));
+ socket->Append(Aerodynamics->GetvFs()(eLift));
+ socket->Append(Aerodynamics->GetLoD());
+ socket->Append(Aircraft->GetForces(eX));
+ socket->Append(Aircraft->GetForces(eY));
+ socket->Append(Aircraft->GetForces(eZ));
+ }
+ if (SubSystems & ssMoments) {
+ socket->Append(Aircraft->GetMoments(eL));
+ socket->Append(Aircraft->GetMoments(eM));
+ socket->Append(Aircraft->GetMoments(eN));
+ }
+ if (SubSystems & ssAtmosphere) {
+ socket->Append(Atmosphere->GetDensity());
+ socket->Append(Atmosphere->GetPressureSL());
+ socket->Append(Atmosphere->GetPressure());
+ socket->Append(Atmosphere->GetWindNED().Dump(","));
+ }
+ if (SubSystems & ssMassProps) {
+ socket->Append(MassBalance->GetJ()(1,1));
+ socket->Append(MassBalance->GetJ()(1,2));
+ socket->Append(MassBalance->GetJ()(1,3));
+ socket->Append(MassBalance->GetJ()(2,1));
+ socket->Append(MassBalance->GetJ()(2,2));
+ socket->Append(MassBalance->GetJ()(2,3));
+ socket->Append(MassBalance->GetJ()(3,1));
+ socket->Append(MassBalance->GetJ()(3,2));
+ socket->Append(MassBalance->GetJ()(3,3));
+ socket->Append(MassBalance->GetMass());
+ socket->Append(MassBalance->GetXYZcg()(eX));
+ socket->Append(MassBalance->GetXYZcg()(eY));
+ socket->Append(MassBalance->GetXYZcg()(eZ));
+ }
+ if (SubSystems & ssPropagate) {
+ socket->Append(Propagate->Geth());
+ socket->Append(Propagate->GetEuler(ePhi));
+ socket->Append(Propagate->GetEuler(eTht));
+ socket->Append(Propagate->GetEuler(ePsi));
+ socket->Append(Auxiliary->Getalpha(inDegrees));
+ socket->Append(Auxiliary->Getbeta(inDegrees));
+ socket->Append(Propagate->GetLocation().GetLatitudeDeg());
+ socket->Append(Propagate->GetLocation().GetLongitudeDeg());
+ }
+ if (SubSystems & ssCoefficients) {
+ scratch = Aerodynamics->GetCoefficientValues(",");
+ if (scratch.length() != 0) socket->Append(scratch);
+ }
+ if (SubSystems & ssFCS) {
+ scratch = FCS->GetComponentValues(",");
+ if (scratch.length() != 0) socket->Append(scratch);
+ }
+ if (SubSystems & ssGroundReactions) {
+ socket->Append(GroundReactions->GetGroundReactionValues(","));
+ }
+ if (SubSystems & ssPropulsion && Propulsion->GetNumEngines() > 0) {
+ socket->Append(Propulsion->GetPropulsionValues(","));
+ }
+
+ for (unsigned int i=0;i<OutputProperties.size();i++) {
+ socket->Append(OutputProperties[i]->getDoubleValue());
+ }
+
+ socket->Send();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGOutput::SocketStatusOutput(string out_str)
+{
+ string asciiData;
+
+ if (socket == NULL) return;
+
+ socket->Clear();
+ asciiData = string("<STATUS>") + out_str;
+ socket->Append(asciiData.c_str());
+ socket->Send();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGOutput::Load(Element* element)
+{
+ string type="", parameter="";
+ string name="", fname="";
+ int OutRate = 0;
+ string property;
+ unsigned int port;
+ FGXMLParse output_file_parser;
+ Element *document, *property_element;
+ ifstream* output_file = new ifstream();
+
+ string separator = "/";
+# ifdef macintosh
+ separator = ";";
+# endif
+
+ fname = element->GetAttributeValue("file");
+ if (!fname.empty()) {
+ output_file_name = FDMExec->GetAircraftPath() + separator
+ + FDMExec->GetModelName() + separator + fname + ".xml";
+
+ output_file->open(output_file_name.c_str());
+ readXML(*output_file, output_file_parser);
+ delete output_file;
+ document = output_file_parser.GetDocument();
+ } else {
+ document = element;
+ }
+
+ name = document->GetAttributeValue("name");
+ type = document->GetAttributeValue("type");
+ SetType(type);
+ if (!document->GetAttributeValue("port").empty() && type == string("SOCKET")) {
+ port = atoi(document->GetAttributeValue("port").c_str());
+ socket = new FGfdmSocket(name, port);
+ } else {
+ Filename = name;
+ }
+ if (!document->GetAttributeValue("rate").empty()) {
+ OutRate = (int)document->GetAttributeValueAsNumber("rate");
+ } else {
+ OutRate = 1;
+ }
+
+ if (document->FindElementValue("simulation") == string("ON"))
+ SubSystems += ssSimulation;
+ if (document->FindElementValue("aerosurfaces") == string("ON"))
+ SubSystems += ssAerosurfaces;
+ if (document->FindElementValue("rates") == string("ON"))
+ SubSystems += ssRates;
+ if (document->FindElementValue("velocities") == string("ON"))
+ SubSystems += ssVelocities;
+ if (document->FindElementValue("forces") == string("ON"))
+ SubSystems += ssForces;
+ if (document->FindElementValue("moments") == string("ON"))
+ SubSystems += ssMoments;
+ if (document->FindElementValue("atmosphere") == string("ON"))
+ SubSystems += ssAtmosphere;
+ if (document->FindElementValue("massprops") == string("ON"))
+ SubSystems += ssMassProps;
+ if (document->FindElementValue("position") == string("ON"))
+ SubSystems += ssPropagate;
+ if (document->FindElementValue("coefficients") == string("ON"))
+ SubSystems += ssCoefficients;
+ if (document->FindElementValue("ground_reactions") == string("ON"))
+ SubSystems += ssGroundReactions;
+ if (document->FindElementValue("fcs") == string("ON"))
+ SubSystems += ssFCS;
+ if (document->FindElementValue("propulsion") == string("ON"))
+ SubSystems += ssPropulsion;
+ property_element = document->FindElement("property");
+ while (property_element) {
+ string property = property_element->GetDataLine();
+ OutputProperties.push_back(PropertyManager->GetNode(property));
+ property_element = document->FindNextElement("property");
+ }
+
+ OutRate = OutRate>120?120:(OutRate<0?0:OutRate);
+ rate = (int)(0.5 + 1.0/(State->Getdt()*OutRate));
+
+ Debug(2);
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGOutput::Debug(int from)
+{
+ string scratch="";
+
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ }
+ if (from == 2) {
+ if (output_file_name.empty())
+ cout << " " << "Output parameters read inline" << endl;
+ else
+ cout << " Output parameters read from file: " << output_file_name << endl;
+
+ if (Filename == "cout" || Filename == "COUT") {
+ scratch = " Log output goes to screen console";
+ } else if (!Filename.empty()) {
+ scratch = " Log output goes to file: " + Filename;
+ }
+ switch (Type) {
+ case otCSV:
+ cout << scratch << " in CSV format output at rate " << 120/rate << " Hz" << endl;
+ break;
+ case otNone:
+ cout << " No log output" << endl;
+ break;
+ }
+
+ if (SubSystems & ssSimulation) cout << " Simulation parameters logged" << endl;
+ if (SubSystems & ssAerosurfaces) cout << " Aerosurface parameters logged" << endl;
+ if (SubSystems & ssRates) cout << " Rate parameters logged" << endl;
+ if (SubSystems & ssVelocities) cout << " Velocity parameters logged" << endl;
+ if (SubSystems & ssForces) cout << " Force parameters logged" << endl;
+ if (SubSystems & ssMoments) cout << " Moments parameters logged" << endl;
+ if (SubSystems & ssAtmosphere) cout << " Atmosphere parameters logged" << endl;
+ if (SubSystems & ssMassProps) cout << " Mass parameters logged" << endl;
+ if (SubSystems & ssCoefficients) cout << " Coefficient parameters logged" << endl;
+ if (SubSystems & ssPropagate) cout << " Propagate parameters logged" << endl;
+ if (SubSystems & ssGroundReactions) cout << " Ground parameters logged" << endl;
+ if (SubSystems & ssFCS) cout << " FCS parameters logged" << endl;
+ if (SubSystems & ssPropulsion) cout << " Propulsion parameters logged" << endl;
+ if (OutputProperties.size() > 0) cout << " Properties logged:" << endl;
+ for (unsigned int i=0;i<OutputProperties.size();i++) {
+ cout << " - " << OutputProperties[i]->GetName() << endl;
+ }
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGOutput" << endl;
+ if (from == 1) cout << "Destroyed: FGOutput" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGOutput.h
+ Author: Jon Berndt
+ Date started: 12/2/98
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+12/02/98 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGOUTPUT_H
+#define FGOUTPUT_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGModel.h"
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# include STL_IOSTREAM
+# include STL_FSTREAM
+#else
+# if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
+# include <iostream.h>
+# include <fstream.h>
+# else
+# include <iostream>
+# include <fstream>
+# endif
+#endif
+
+#include <input_output/FGfdmSocket.h>
+#include <input_output/FGXMLElement.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_OUTPUT "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Handles simulation output.
+ OUTPUT section definition
+
+ The following specifies the way that JSBSim writes out data.
+
+ NAME is the filename you want the output to go to
+
+ TYPE can be:
+ CSV Comma separated data. If a filename is supplied then the data
+ goes to that file. If COUT or cout is specified, the data goes
+ to stdout. If the filename is a null filename the data goes to
+ stdout, as well.
+ SOCKET Will eventually send data to a socket output, where NAME
+ would then be the IP address of the machine the data should be
+ sent to. DON'T USE THIS YET!
+ TABULAR Columnar data. NOT IMPLEMENTED YET!
+ TERMINAL Output to terminal. NOT IMPLEMENTED YET!
+ NONE Specifies to do nothing. THis setting makes it easy to turn on and
+ off the data output without having to mess with anything else.
+
+ The arguments that can be supplied, currently, are
+
+ RATE_IN_HZ An integer rate in times-per-second that the data is output. This
+ value may not be *exactly* what you want, due to the dependence
+ on dt, the cycle rate for the FDM.
+
+ The following parameters tell which subsystems of data to output:
+
+ SIMULATION ON|OFF
+ ATMOSPHERE ON|OFF
+ MASSPROPS ON|OFF
+ AEROSURFACES ON|OFF
+ RATES ON|OFF
+ VELOCITIES ON|OFF
+ FORCES ON|OFF
+ MOMENTS ON|OFF
+ POSITION ON|OFF
+ COEFFICIENTS ON|OFF
+ GROUND_REACTIONS ON|OFF
+ FCS ON|OFF
+ PROPULSION ON|OFF
+
+ NOTE that Time is always output with the data.
+ @version $Id$
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGOutput : public FGModel
+{
+public:
+ FGOutput(FGFDMExec*);
+ ~FGOutput();
+
+ bool Run(void);
+
+ void DelimitedOutput(string);
+ void SocketOutput(void);
+ void SocketStatusOutput(string);
+ void SetType(string);
+ void SetSubsystems(int tt) {SubSystems = tt;}
+ inline void Enable(void) { enabled = true; }
+ inline void Disable(void) { enabled = false; }
+ inline bool Toggle(void) {enabled = !enabled; return enabled;}
+ bool Load(Element* el);
+
+ /// Subsystem types for specifying which will be output in the FDM data logging
+ enum eSubSystems {
+ /** Subsystem: Simulation (= 1) */ ssSimulation = 1,
+ /** Subsystem: Aerosurfaces (= 2) */ ssAerosurfaces = 2,
+ /** Subsystem: Body rates (= 4) */ ssRates = 4,
+ /** Subsystem: Velocities (= 8) */ ssVelocities = 8,
+ /** Subsystem: Forces (= 16) */ ssForces = 16,
+ /** Subsystem: Moments (= 32) */ ssMoments = 32,
+ /** Subsystem: Atmosphere (= 64) */ ssAtmosphere = 64,
+ /** Subsystem: Mass Properties (= 128) */ ssMassProps = 128,
+ /** Subsystem: Coefficients (= 256) */ ssCoefficients = 256,
+ /** Subsystem: Propagate (= 512) */ ssPropagate = 512,
+ /** Subsystem: Ground Reactions (= 1024) */ ssGroundReactions = 1024,
+ /** Subsystem: FCS (= 2048) */ ssFCS = 2048,
+ /** Subsystem: Propulsion (= 4096) */ ssPropulsion = 4096
+ } subsystems;
+
+private:
+ bool sFirstPass, dFirstPass, enabled;
+ int SubSystems;
+ string output_file_name, delimeter, Filename;
+ enum {otNone, otCSV, otTab, otSocket, otTerminal, otUnknown} Type;
+ ofstream datafile;
+ FGfdmSocket* socket;
+ vector <FGPropertyManager*> OutputProperties;
+ void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGPropagate.cpp
+ Author: Jon S. Berndt
+ Date started: 01/05/99
+ Purpose: Integrate the EOM to determine instantaneous position
+ Called by: FGFDMExec
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+This class encapsulates the integration of rates and accelerations to get the
+current position of the aircraft.
+
+HISTORY
+--------------------------------------------------------------------------------
+01/05/99 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+COMMENTS, REFERENCES, and NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[1] Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
+ Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
+ School, January 1994
+[2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
+ JSC 12960, July 1977
+[3] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
+ NASA-Ames", NASA CR-2497, January 1975
+[4] Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
+ Wiley & Sons, 1979 ISBN 0-471-03032-5
+[5] Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
+ 1982 ISBN 0-471-08936-2
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# ifdef SG_HAVE_STD_INCLUDES
+# include <cmath>
+# include <iomanip>
+# else
+# include <math.h>
+# include <iomanip.h>
+# endif
+#else
+# if defined(sgi) && !defined(__GNUC__)
+# include <math.h>
+# if (_COMPILER_VERSION < 740)
+# include <iomanip.h>
+# else
+# include <iomanip>
+# endif
+# else
+# include <cmath>
+# include <iomanip>
+# endif
+#endif
+
+#include "FGPropagate.h"
+#include <FGState.h>
+#include <FGFDMExec.h>
+#include "FGAircraft.h"
+#include "FGMassBalance.h"
+#include "FGInertial.h"
+#include <input_output/FGPropertyManager.h>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_PROPAGATE;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGPropagate::FGPropagate(FGFDMExec* fdmex) : FGModel(fdmex)
+{
+ Name = "FGPropagate";
+
+ bind();
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGPropagate::~FGPropagate(void)
+{
+ unbind();
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGPropagate::InitModel(void)
+{
+ FGModel::InitModel();
+
+ SeaLevelRadius = Inertial->RefRadius(); // For initialization ONLY
+ RunwayRadius = SeaLevelRadius;
+
+ VState.vLocation.SetRadius( SeaLevelRadius + 4.0 );
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
+{
+ SeaLevelRadius = FGIC->GetSeaLevelRadiusFtIC();
+ RunwayRadius = SeaLevelRadius;
+
+ // Set the position lat/lon/radius
+ VState.vLocation = FGLocation( FGIC->GetLongitudeRadIC(),
+ FGIC->GetLatitudeRadIC(),
+ FGIC->GetAltitudeFtIC() + FGIC->GetSeaLevelRadiusFtIC() );
+
+ // Set the Orientation from the euler angles
+ VState.vQtrn = FGQuaternion( FGIC->GetPhiRadIC(),
+ FGIC->GetThetaRadIC(),
+ FGIC->GetPsiRadIC() );
+
+ // Set the velocities in the instantaneus body frame
+ VState.vUVW = FGColumnVector3( FGIC->GetUBodyFpsIC(),
+ FGIC->GetVBodyFpsIC(),
+ FGIC->GetWBodyFpsIC() );
+
+ // Set the angular velocities in the instantaneus body frame.
+ VState.vPQR = FGColumnVector3( FGIC->GetPRadpsIC(),
+ FGIC->GetQRadpsIC(),
+ FGIC->GetRRadpsIC() );
+
+ // Compute some derived values.
+ vVel = VState.vQtrn.GetTInv()*VState.vUVW;
+
+ // Finally, make sure that the quaternion stays normalized.
+ VState.vQtrn.Normalize();
+
+ // Recompute the RunwayRadius level.
+ RecomputeRunwayRadius();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+/*
+Purpose: Called on a schedule to perform EOM integration
+Notes: [JB] Run in standalone mode, SeaLevelRadius will be reference radius.
+ In FGFS, SeaLevelRadius is stuffed from FGJSBSim in JSBSim.cxx each pass.
+
+At the top of this Run() function, see several "shortcuts" (or, aliases) being
+set up for use later, rather than using the longer class->function() notation.
+
+Here, propagation of state is done using a simple explicit Euler scheme (see the
+bottom of the function). This propagation is done using the current state values
+and current derivatives. Based on these values we compute an approximation to the
+state values for (now + dt).
+
+*/
+
+bool FGPropagate::Run(void)
+{
+ if (FGModel::Run()) return true; // Fast return if we have nothing to do ...
+ if (FDMExec->Holding()) return false;
+
+ RecomputeRunwayRadius();
+
+ double dt = State->Getdt()*rate; // The 'stepsize'
+ const FGColumnVector3 omega( 0.0, 0.0, Inertial->omega() ); // earth rotation
+ const FGColumnVector3& vForces = Aircraft->GetForces(); // current forces
+ const FGColumnVector3& vMoments = Aircraft->GetMoments(); // current moments
+
+ double mass = MassBalance->GetMass(); // mass
+ const FGMatrix33& J = MassBalance->GetJ(); // inertia matrix
+ const FGMatrix33& Jinv = MassBalance->GetJinv(); // inertia matrix inverse
+ double r = GetRadius(); // radius
+ if (r == 0.0) {cerr << "radius = 0 !" << endl; r = 1e-16;} // radius check
+ double rInv = 1.0/r;
+ FGColumnVector3 gAccel( 0.0, 0.0, Inertial->GetGAccel(r) );
+
+ // The rotation matrices:
+ const FGMatrix33& Tl2b = GetTl2b(); // local to body frame
+ const FGMatrix33& Tb2l = GetTb2l(); // body to local frame
+ const FGMatrix33& Tec2l = VState.vLocation.GetTec2l(); // earth centered to local frame
+ const FGMatrix33& Tl2ec = VState.vLocation.GetTl2ec(); // local to earth centered frame
+
+ // Inertial angular velocity measured in the body frame.
+ const FGColumnVector3 pqri = VState.vPQR + Tl2b*(Tec2l*omega);
+
+ // Compute vehicle velocity wrt EC frame, expressed in Local horizontal frame.
+ vVel = Tb2l * VState.vUVW;
+
+ // First compute the time derivatives of the vehicle state values:
+
+ // Compute body frame rotational accelerations based on the current body moments
+ vPQRdot = Jinv*(vMoments - pqri*(J*pqri));
+
+ // Compute body frame accelerations based on the current body forces
+ vUVWdot = VState.vUVW*VState.vPQR + vForces/mass;
+
+ // Coriolis acceleration.
+ FGColumnVector3 ecVel = Tl2ec*vVel;
+ FGColumnVector3 ace = 2.0*omega*ecVel;
+ vUVWdot -= Tl2b*(Tec2l*ace);
+
+ if (!GroundReactions->GetWOW()) {
+ // Centrifugal acceleration.
+ FGColumnVector3 aeec = omega*(omega*VState.vLocation);
+ vUVWdot -= Tl2b*(Tec2l*aeec);
+ }
+
+ // Gravitation accel
+ vUVWdot += Tl2b*gAccel;
+
+ // Compute vehicle velocity wrt EC frame, expressed in EC frame
+ FGColumnVector3 vLocationDot = Tl2ec * vVel;
+
+ FGColumnVector3 omegaLocal( rInv*vVel(eEast),
+ -rInv*vVel(eNorth),
+ -rInv*vVel(eEast)*VState.vLocation.GetTanLatitude() );
+
+ // Compute quaternion orientation derivative on current body rates
+ FGQuaternion vQtrndot = VState.vQtrn.GetQDot( VState.vPQR - Tl2b*omegaLocal );
+
+ // Propagate velocities
+ VState.vPQR += dt*vPQRdot;
+ VState.vUVW += dt*vUVWdot;
+
+ // Propagate positions
+ VState.vQtrn += dt*vQtrndot;
+ VState.vLocation += dt*vLocationDot;
+
+ return false;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropagate::RecomputeRunwayRadius(void)
+{
+ // Get the runway radius.
+ FGLocation contactloc;
+ FGColumnVector3 dv;
+ FGGroundCallback* gcb = FDMExec->GetGroundCallback();
+ double t = State->Getsim_time();
+ gcb->GetAGLevel(t, VState.vLocation, contactloc, dv, dv);
+ RunwayRadius = contactloc.GetRadius();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropagate::Seth(double tt)
+{
+ VState.vLocation.SetRadius( tt + SeaLevelRadius );
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGPropagate::GetRunwayRadius(void) const
+{
+ return RunwayRadius;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGPropagate::GetDistanceAGL(void) const
+{
+ return VState.vLocation.GetRadius() - RunwayRadius;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropagate::SetDistanceAGL(double tt)
+{
+ VState.vLocation.SetRadius( tt + RunwayRadius );
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropagate::bind(void)
+{
+ typedef double (FGPropagate::*PMF)(int) const;
+ PropertyManager->Tie("velocities/h-dot-fps", this, &FGPropagate::Gethdot);
+
+ PropertyManager->Tie("velocities/v-north-fps", this, eNorth, (PMF)&FGPropagate::GetVel);
+ PropertyManager->Tie("velocities/v-east-fps", this, eEast, (PMF)&FGPropagate::GetVel);
+ PropertyManager->Tie("velocities/v-down-fps", this, eDown, (PMF)&FGPropagate::GetVel);
+
+ PropertyManager->Tie("velocities/u-fps", this, eU, (PMF)&FGPropagate::GetUVW);
+ PropertyManager->Tie("velocities/v-fps", this, eV, (PMF)&FGPropagate::GetUVW);
+ PropertyManager->Tie("velocities/w-fps", this, eW, (PMF)&FGPropagate::GetUVW);
+
+ PropertyManager->Tie("velocities/p-rad_sec", this, eP, (PMF)&FGPropagate::GetPQR);
+ PropertyManager->Tie("velocities/q-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQR);
+ PropertyManager->Tie("velocities/r-rad_sec", this, eR, (PMF)&FGPropagate::GetPQR);
+
+ PropertyManager->Tie("accelerations/pdot-rad_sec", this, eP, (PMF)&FGPropagate::GetPQRdot);
+ PropertyManager->Tie("accelerations/qdot-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQRdot);
+ PropertyManager->Tie("accelerations/rdot-rad_sec", this, eR, (PMF)&FGPropagate::GetPQRdot);
+
+ PropertyManager->Tie("accelerations/udot-fps", this, eU, (PMF)&FGPropagate::GetUVWdot);
+ PropertyManager->Tie("accelerations/vdot-fps", this, eV, (PMF)&FGPropagate::GetUVWdot);
+ PropertyManager->Tie("accelerations/wdot-fps", this, eW, (PMF)&FGPropagate::GetUVWdot);
+
+ PropertyManager->Tie("position/h-sl-ft", this, &FGPropagate::Geth, &FGPropagate::Seth, true);
+ PropertyManager->Tie("position/lat-gc-rad", this, &FGPropagate::GetLatitude, &FGPropagate::SetLatitude);
+ PropertyManager->Tie("position/long-gc-rad", this, &FGPropagate::GetLongitude, &FGPropagate::SetLongitude);
+ PropertyManager->Tie("position/h-agl-ft", this, &FGPropagate::GetDistanceAGL, &FGPropagate::SetDistanceAGL);
+ PropertyManager->Tie("position/radius-to-vehicle-ft", this, &FGPropagate::GetRadius);
+
+ PropertyManager->Tie("metrics/runway-radius", this, &FGPropagate::GetRunwayRadius);
+
+ PropertyManager->Tie("attitude/phi-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
+ PropertyManager->Tie("attitude/theta-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
+ PropertyManager->Tie("attitude/psi-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
+
+ PropertyManager->Tie("attitude/roll-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
+ PropertyManager->Tie("attitude/pitch-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
+ PropertyManager->Tie("attitude/heading-true-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropagate::unbind(void)
+{
+ PropertyManager->Untie("velocities/v-north-fps");
+ PropertyManager->Untie("velocities/v-east-fps");
+ PropertyManager->Untie("velocities/v-down-fps");
+ PropertyManager->Untie("velocities/h-dot-fps");
+ PropertyManager->Untie("velocities/u-fps");
+ PropertyManager->Untie("velocities/v-fps");
+ PropertyManager->Untie("velocities/w-fps");
+ PropertyManager->Untie("velocities/p-rad_sec");
+ PropertyManager->Untie("velocities/q-rad_sec");
+ PropertyManager->Untie("velocities/r-rad_sec");
+ PropertyManager->Untie("accelerations/udot-fps");
+ PropertyManager->Untie("accelerations/vdot-fps");
+ PropertyManager->Untie("accelerations/wdot-fps");
+ PropertyManager->Untie("accelerations/pdot-rad_sec");
+ PropertyManager->Untie("accelerations/qdot-rad_sec");
+ PropertyManager->Untie("accelerations/rdot-rad_sec");
+ PropertyManager->Untie("position/h-sl-ft");
+ PropertyManager->Untie("position/lat-gc-rad");
+ PropertyManager->Untie("position/long-gc-rad");
+ PropertyManager->Untie("position/h-agl-ft");
+ PropertyManager->Untie("position/radius-to-vehicle-ft");
+ PropertyManager->Untie("metrics/runway-radius");
+ PropertyManager->Untie("attitude/phi-rad");
+ PropertyManager->Untie("attitude/theta-rad");
+ PropertyManager->Untie("attitude/psi-rad");
+ PropertyManager->Untie("attitude/roll-rad");
+ PropertyManager->Untie("attitude/pitch-rad");
+ PropertyManager->Untie("attitude/heading-true-rad");
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGPropagate::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGPropagate" << endl;
+ if (from == 1) cout << "Destroyed: FGPropagate" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGPropagate.h
+ Author: Jon S. Berndt
+ Date started: 1/5/99
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+01/05/99 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGPROPAGATE_H
+#define FGPROPAGATE_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <models/FGModel.h>
+#include <math/FGColumnVector3.h>
+#include <initialization/FGInitialCondition.h>
+#include <math/FGLocation.h>
+#include <math/FGQuaternion.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_PROPAGATE "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models the EOM and integration/propagation of state
+ @author Jon S. Berndt, Mathias Froehlich
+ @version $Id$
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+// state vector
+
+struct VehicleState {
+ FGLocation vLocation;
+ FGColumnVector3 vUVW;
+ FGColumnVector3 vPQR;
+ FGQuaternion vQtrn;
+};
+
+class FGPropagate : public FGModel {
+public:
+ /** Constructor
+ @param Executive a pointer to the parent executive object */
+ FGPropagate(FGFDMExec* Executive);
+
+ /// Destructor
+ ~FGPropagate();
+
+ bool InitModel(void);
+
+ /** Runs the Propagate model; called by the Executive
+ @return false if no error */
+ bool Run(void);
+
+ const FGColumnVector3& GetVel(void) const { return vVel; }
+ const FGColumnVector3& GetUVW(void) const { return VState.vUVW; }
+ const FGColumnVector3& GetUVWdot(void) const { return vUVWdot; }
+ const FGColumnVector3& GetPQR(void) const {return VState.vPQR;}
+ const FGColumnVector3& GetPQRdot(void) const {return vPQRdot;}
+ const FGColumnVector3& GetEuler(void) const { return VState.vQtrn.GetEuler(); }
+
+ double GetUVW (int idx) const { return VState.vUVW(idx); }
+ double GetUVWdot(int idx) const { return vUVWdot(idx); }
+ double GetVel(int idx) const { return vVel(idx); }
+ double Geth(void) const { return VState.vLocation.GetRadius() - SeaLevelRadius; }
+ double GetPQR(int axis) const {return VState.vPQR(axis);}
+ double GetPQRdot(int idx) const {return vPQRdot(idx);}
+ double GetEuler(int axis) const { return VState.vQtrn.GetEuler(axis); }
+ double GetCosEuler(int idx) const { return VState.vQtrn.GetCosEuler(idx); }
+ double GetSinEuler(int idx) const { return VState.vQtrn.GetSinEuler(idx); }
+ double Gethdot(void) const { return -vVel(eDown); }
+
+ /** Returns the "constant" RunwayRadius.
+ The RunwayRadius parameter is set by the calling application or set to
+ zero if JSBSim is running in standalone mode.
+ @return distance of the runway from the center of the earth.
+ @units feet */
+ double GetRunwayRadius(void) const;
+ double GetSeaLevelRadius(void) const { return SeaLevelRadius; }
+ double GetDistanceAGL(void) const;
+ double GetRadius(void) const { return VState.vLocation.GetRadius(); }
+ double GetLongitude(void) const { return VState.vLocation.GetLongitude(); }
+ double GetLatitude(void) const { return VState.vLocation.GetLatitude(); }
+ const FGLocation& GetLocation(void) const { return VState.vLocation; }
+
+ /** Retrieves the local-to-body transformation matrix.
+ @return a reference to the local-to-body transformation matrix. */
+ const FGMatrix33& GetTl2b(void) const { return VState.vQtrn.GetT(); }
+
+ /** Retrieves the body-to-local transformation matrix.
+ @return a reference to the body-to-local matrix. */
+ const FGMatrix33& GetTb2l(void) const { return VState.vQtrn.GetTInv(); }
+
+// SET functions
+
+ void SetLongitude(double lon) { VState.vLocation.SetLongitude(lon); }
+ void SetLatitude(double lat) { VState.vLocation.SetLatitude(lat); }
+ void SetRadius(double r) { VState.vLocation.SetRadius(r); }
+ void SetLocation(const FGLocation& l) { VState.vLocation = l; }
+ void Seth(double tt);
+ void SetSeaLevelRadius(double tt) { SeaLevelRadius = tt; }
+ void SetDistanceAGL(double tt);
+ void SetInitialState(const FGInitialCondition *);
+ void RecomputeRunwayRadius(void);
+
+ void bind(void);
+ void unbind(void);
+
+private:
+
+// state vector
+
+ struct VehicleState VState;
+
+ FGColumnVector3 vVel;
+ FGColumnVector3 vPQRdot;
+ FGColumnVector3 vUVWdot;
+
+ double RunwayRadius, SeaLevelRadius;
+
+ void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGPropulsion.cpp
+ Author: Jon S. Berndt
+ Date started: 08/20/00
+ Purpose: Encapsulates the set of engines and tanks associated
+ with this aircraft
+
+ ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+The Propulsion class is the container for the entire propulsion system, which is
+comprised of engines and tanks. Once the Propulsion class gets the config file,
+it reads in information which is specific to a type of engine. Then:
+
+1) The appropriate engine type instance is created
+2) At least one tank object is created, and is linked to an engine.
+
+At Run time each engines Calculate() method is called.
+
+HISTORY
+--------------------------------------------------------------------------------
+08/20/00 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#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 <sstream>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_PROPULSION;
+
+extern short debug_lvl;
+
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)
+{
+ Name = "FGPropulsion";
+
+ numSelectedFuelTanks = numSelectedOxiTanks = 0;
+ numTanks = numEngines = 0;
+ numOxiTanks = numFuelTanks = 0;
+ ActiveEngine = -1; // -1: ALL, 0: Engine 1, 1: Engine 2 ...
+ tankJ.InitMatrix();
+ refuel = false;
+ fuel_freeze = false;
+ TotalFuelQuantity = 0.0;
+ IsBound =
+ HavePistonEngine =
+ HaveTurbineEngine =
+ HaveRocketEngine =
+ HaveTurboPropEngine =
+ HaveElectricEngine = false;
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGPropulsion::~FGPropulsion()
+{
+ for (unsigned int i=0; i<Engines.size(); i++) delete Engines[i];
+ Engines.clear();
+ unbind();
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGPropulsion::Run(void)
+{
+ unsigned int i;
+
+ if (FGModel::Run()) return true;
+ if (FDMExec->Holding()) return false;
+
+ double dt = State->Getdt();
+
+ vForces.InitMatrix();
+ vMoments.InitMatrix();
+
+ for (i=0; i<numEngines; i++) {
+ Engines[i]->Calculate();
+ vForces += Engines[i]->GetBodyForces(); // sum body frame forces
+ vMoments += Engines[i]->GetMoments(); // sum body frame moments
+ }
+
+ TotalFuelQuantity = 0.0;
+ for (i=0; i<numTanks; i++) {
+ Tanks[i]->Calculate( dt * rate );
+ if (Tanks[i]->GetType() == FGTank::ttFUEL) {
+ TotalFuelQuantity += Tanks[i]->GetContents();
+ }
+ }
+
+ if (refuel) DoRefuel( dt * rate );
+
+ return false;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGPropulsion::GetSteadyState(void)
+{
+ double currentThrust = 0, lastThrust=-1;
+ int steady_count,j=0;
+ bool steady=false;
+
+ vForces.InitMatrix();
+ vMoments.InitMatrix();
+
+ if (!FGModel::Run()) {
+ for (unsigned int i=0; i<numEngines; i++) {
+ Engines[i]->SetTrimMode(true);
+ steady=false;
+ steady_count=0;
+ while (!steady && j < 6000) {
+ Engines[i]->Calculate();
+ lastThrust = currentThrust;
+ currentThrust = Engines[i]->GetThrust();
+ if (fabs(lastThrust-currentThrust) < 0.0001) {
+ steady_count++;
+ if (steady_count > 120) { steady=true; }
+ } else {
+ steady_count=0;
+ }
+ j++;
+ }
+ vForces += Engines[i]->GetBodyForces(); // sum body frame forces
+ vMoments += Engines[i]->GetMoments(); // sum body frame moments
+ Engines[i]->SetTrimMode(false);
+ }
+
+ return false;
+ } else {
+ return true;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGPropulsion::ICEngineStart(void)
+{
+ int j;
+
+ vForces.InitMatrix();
+ vMoments.InitMatrix();
+
+ for (unsigned int i=0; i<numEngines; i++) {
+ Engines[i]->SetTrimMode(true);
+ j=0;
+ while (!Engines[i]->GetRunning() && j < 2000) {
+ Engines[i]->Calculate();
+ j++;
+ }
+ vForces += Engines[i]->GetBodyForces(); // sum body frame forces
+ vMoments += Engines[i]->GetMoments(); // sum body frame moments
+ Engines[i]->SetTrimMode(false);
+ }
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGPropulsion::Load(Element* el)
+{
+ string type, engine_filename;
+ int Feed;
+ bool ThrottleAdded = false;
+ Element* document;
+ FGXMLParse engine_file_parser;
+ ifstream* engine_file;
+
+ Debug(2);
+
+ Element* engine_element = el->FindElement("engine");
+ while (engine_element) {
+ engine_filename = engine_element->GetAttributeValue("file");
+
+ if (engine_filename.empty()) {
+ cerr << "Engine definition did not supply an engine file." << endl;
+ return false;
+ }
+
+ engine_filename = FindEngineFullPathname(engine_filename);
+ readXML(engine_filename, engine_file_parser);
+ document = engine_file_parser.GetDocument(); // document holds the engine description
+ 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);
+ }
+
+ FCS->AddThrottle();
+ ThrottleAdded = true;
+
+ numEngines++;
+
+ engine_element = el->FindNextElement("engine");
+ engine_file_parser.reset();
+ }
+
+ // Process tank definitions
+
+ 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;
+
+ CalculateTankInertias();
+ if (!ThrottleAdded) FCS->AddThrottle(); // need to have at least one throttle
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGPropulsion::FindEngineFullPathname(string engine_filename)
+{
+ string fullpath, localpath;
+ string enginePath = FDMExec->GetEnginePath();
+ string aircraftPath = FDMExec->GetAircraftPath();
+ ifstream* engine_file = new ifstream();
+
+ 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()) {
+ cerr << " Could not open engine file: " << engine_filename << " in path "
+ << fullpath << " or " << localpath << endl;
+ return string("");
+ } else {
+ return string(localpath + engine_filename + ".xml");
+ }
+ }
+ return string(fullpath + engine_filename + ".xml");
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ifstream* FGPropulsion::FindEngineFile(string engine_filename)
+{
+ string fullpath, localpath;
+ string enginePath = FDMExec->GetEnginePath();
+ string aircraftPath = FDMExec->GetAircraftPath();
+ ifstream* engine_file = new ifstream();
+
+ 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()) {
+ cerr << " Could not open engine file: " << engine_filename << " in path "
+ << fullpath << " or " << localpath << endl;
+ }
+ }
+ return engine_file;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGPropulsion::GetPropulsionStrings(string delimeter)
+{
+ unsigned int i;
+
+ string PropulsionStrings = "";
+ bool firstime = true;
+ stringstream buf;
+
+ for (i=0; i<Engines.size(); i++) {
+ if (firstime) firstime = false;
+ else PropulsionStrings += delimeter;
+
+ PropulsionStrings += Engines[i]->GetEngineLabels(delimeter);
+ }
+ 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;
+ }
+
+ return PropulsionStrings;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGPropulsion::GetPropulsionValues(string delimeter)
+{
+ unsigned int i;
+
+ string PropulsionValues = "";
+ bool firstime = true;
+ stringstream buf;
+
+ for (i=0; i<Engines.size(); i++) {
+ if (firstime) firstime = false;
+ else PropulsionValues += delimeter;
+
+ PropulsionValues += Engines[i]->GetEngineValues(delimeter);
+ }
+ for (i=0; i<Tanks.size(); i++) {
+ buf << delimeter;
+ buf << Tanks[i]->GetContents();
+ }
+
+ return PropulsionValues;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+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++;
+ }
+ return vXYZtank_arm;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGPropulsion::GetTanksWeight(void)
+{
+ double Tw = 0.0;
+
+ iTank = Tanks.begin();
+ while (iTank < Tanks.end()) {
+ Tw += (*iTank)->GetContents();
+ iTank++;
+ }
+ return Tw;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGMatrix33& FGPropulsion::CalculateTankInertias(void)
+{
+ unsigned int size;
+
+ size = Tanks.size();
+ if (size == 0) return tankJ;
+
+ tankJ = FGMatrix33();
+
+ for (unsigned int i=0; i<size; i++)
+ tankJ += MassBalance->GetPointmassInertia( lbtoslug * Tanks[i]->GetContents(),
+ Tanks[i]->GetXYZ() );
+
+ return tankJ;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropulsion::SetMagnetos(int setting)
+{
+ if (ActiveEngine < 0) {
+ for (unsigned i=0; i<Engines.size(); i++) {
+ // ToDo: first need to make sure the engine Type is really appropriate:
+ // do a check to see if it is of type Piston. This should be done for
+ // all of this kind of possibly across-the-board settings.
+ ((FGPiston*)Engines[i])->SetMagnetos(setting);
+ }
+ } else {
+ ((FGPiston*)Engines[ActiveEngine])->SetMagnetos(setting);
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropulsion::SetStarter(int setting)
+{
+ if (ActiveEngine < 0) {
+ for (unsigned i=0; i<Engines.size(); i++) {
+ if (setting == 0)
+ Engines[i]->SetStarter(false);
+ else
+ Engines[i]->SetStarter(true);
+ }
+ } else {
+ if (setting == 0)
+ Engines[ActiveEngine]->SetStarter(false);
+ else
+ Engines[ActiveEngine]->SetStarter(true);
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropulsion::SetCutoff(int setting)
+{
+ if (ActiveEngine < 0) {
+ for (unsigned i=0; i<Engines.size(); i++) {
+ if (setting == 0)
+ ((FGTurbine*)Engines[i])->SetCutoff(false);
+ else
+ ((FGTurbine*)Engines[i])->SetCutoff(true);
+ }
+ } else {
+ if (setting == 0)
+ ((FGTurbine*)Engines[ActiveEngine])->SetCutoff(false);
+ else
+ ((FGTurbine*)Engines[ActiveEngine])->SetCutoff(true);
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropulsion::SetActiveEngine(int engine)
+{
+ if (engine >= Engines.size() || engine < 0)
+ ActiveEngine = -1;
+ else
+ ActiveEngine = engine;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGPropulsion::Transfer(int source, int target, double amount)
+{
+ double shortage, overage;
+
+ if (source == -1) {
+ shortage = 0.0;
+ } else {
+ shortage = Tanks[source]->Drain(amount);
+ }
+ if (target == -1) {
+ overage = 0.0;
+ } else {
+ overage = Tanks[target]->Fill(amount - shortage);
+ }
+ return overage;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropulsion::DoRefuel(double time_slice)
+{
+ unsigned int i;
+
+ double fillrate = 100 * time_slice; // 100 lbs/sec = 6000 lbs/min
+ int TanksNotFull = 0;
+
+ for (i=0; i<numTanks; i++) {
+ if (Tanks[i]->GetPctFull() < 99.99) ++TanksNotFull;
+ }
+
+ if (TanksNotFull) {
+ for (i=0; i<numTanks; i++) {
+ if (Tanks[i]->GetPctFull() < 99.99)
+ Transfer(-1, i, fillrate/TanksNotFull);
+ }
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropulsion::SetFuelFreeze(bool f)
+{
+ fuel_freeze = f;
+ for (unsigned int i=0; i<numEngines; i++) {
+ Engines[i]->SetFuelFreeze(f);
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropulsion::bind(void)
+{
+ typedef double (FGPropulsion::*PMF)(int) const;
+ typedef int (FGPropulsion::*iPMF)(void) const;
+
+ IsBound = true;
+
+ if (HaveTurbineEngine) {
+ PropertyManager->Tie("propulsion/starter_cmd", this, (iPMF)0, &FGPropulsion::SetStarter, true);
+ PropertyManager->Tie("propulsion/cutoff_cmd", this, (iPMF)0, &FGPropulsion::SetCutoff, true);
+ }
+
+ 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/active_engine", this, (iPMF)&FGPropulsion::GetActiveEngine,
+ &FGPropulsion::SetActiveEngine, true);
+ PropertyManager->Tie("propulsion/total-fuel-lbs", this, &FGPropulsion::GetTotalFuelQuantity);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropulsion::unbind(void)
+{
+ 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");
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGPropulsion::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 2) { // Loader
+ cout << endl << " Propulsion:" << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGPropulsion" << endl;
+ if (from == 1) cout << "Destroyed: FGPropulsion" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGPropulsion.h
+ Author: Jon S. Berndt
+ Date started: 08/20/00
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+08/20/00 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGPROPULSION_H
+#define FGPROPULSION_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# ifdef SG_HAVE_STD_INCLUDES
+# include <vector>
+# include <iterator>
+# include <fstream>
+# else
+# include <vector.h>
+# include <iterator.h>
+# include <fstream.h>
+# endif
+#else
+# include <vector>
+# include <iterator>
+# include <fstream>
+#endif
+
+#include "FGModel.h"
+#include <models/propulsion/FGEngine.h>
+#include <models/propulsion/FGTank.h>
+#include <math/FGMatrix33.h>
+#include <input_output/FGXMLElement.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_PROPULSION "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Propulsion management class.
+ The Propulsion class is the container for the entire propulsion system, which is
+ comprised of engines, and tanks. Once the Propulsion class gets the config file,
+ it reads in information which is specific to a type of engine. Then:
+
+ -# The appropriate engine type instance is created
+ -# At least one tank object is created, and is linked to an engine.
+
+ At Run time each engines Calculate() method is called.
+ @author Jon S. Berndt
+ @version $Id$
+ @see
+ FGEngine
+ FGTank
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGPropulsion : public FGModel
+{
+public:
+ /// Constructor
+ FGPropulsion(FGFDMExec*);
+ /// Destructor
+ ~FGPropulsion();
+
+ /** Executes the propulsion model.
+ The initial plan for the FGPropulsion class calls for Run() to be executed,
+ calculating the power available from the engine.
+
+ [Note: Should we be checking the Starved flag here?] */
+ bool Run(void);
+
+ /** Loads the propulsion system (engine[s] and tank[s]).
+ Characteristics of the propulsion system are read in from the config file.
+ @param el pointer to an XML element that contains the engine information.
+ @return true if successfully loaded, otherwise false */
+ bool Load(Element* el);
+
+ /// Retrieves the number of engines defined for the aircraft.
+ inline unsigned int GetNumEngines(void) const {return Engines.size();}
+
+ /** Retrieves an engine object pointer from the list of engines.
+ @param index the engine index within the vector container
+ @return the address of the specific engine, or zero if no such engine is
+ available */
+ inline FGEngine* GetEngine(unsigned int index) {
+ if (index <= Engines.size()-1) return Engines[index];
+ else return 0L; }
+
+ /// Retrieves the number of tanks defined for the aircraft.
+ inline unsigned int GetNumTanks(void) const {return Tanks.size();}
+
+ /** Retrieves a tank object pointer from the list of tanks.
+ @param index the tank index within the vector container
+ @return the address of the specific tank, or zero if no such tank is
+ available */
+ inline FGTank* GetTank(unsigned int index) {
+ if (index <= Tanks.size()-1) return Tanks[index];
+ else return 0L; }
+
+ /** Returns the number of fuel tanks currently actively supplying fuel */
+ inline int GetnumSelectedFuelTanks(void) const {return numSelectedFuelTanks;}
+
+ /** Returns the number of oxidizer tanks currently actively supplying oxidizer */
+ inline int GetnumSelectedOxiTanks(void) const {return numSelectedOxiTanks;}
+
+ /** Loops the engines until thrust output steady (used for trimming) */
+ bool GetSteadyState(void);
+
+ /** starts the engines in IC mode (dt=0). All engine-specific setup must
+ be done before calling this (i.e. magnetos, starter engage, etc.) */
+ bool ICEngineStart(void);
+
+ string GetPropulsionStrings(string delimeter);
+ string GetPropulsionValues(string delimeter);
+
+ inline FGColumnVector3& GetForces(void) {return vForces; }
+ inline double GetForces(int n) const { return vForces(n);}
+ inline FGColumnVector3& GetMoments(void) {return vMoments;}
+ inline double GetMoments(int n) const {return vMoments(n);}
+
+ inline bool GetRefuel(void) {return refuel;}
+ inline void SetRefuel(bool setting) {refuel = setting;}
+ double Transfer(int source, int target, double amount);
+ void DoRefuel(double time_slice);
+
+ FGColumnVector3& GetTanksMoment(void);
+ double GetTanksWeight(void);
+
+ ifstream* FindEngineFile(string filename);
+ string FindEngineFullPathname(string engine_filename);
+ inline int GetActiveEngine(void) const {return ActiveEngine;}
+ inline bool GetFuelFreeze(void) {return fuel_freeze;}
+ double GetTotalFuelQuantity(void) const {return TotalFuelQuantity;}
+
+ void SetMagnetos(int setting);
+ void SetStarter(int setting);
+ void SetCutoff(int setting=0);
+ void SetActiveEngine(int engine);
+ void SetFuelFreeze(bool f);
+ FGMatrix33& CalculateTankInertias(void);
+
+ void bind();
+ void unbind();
+
+private:
+ vector <FGEngine*> Engines;
+ vector <FGTank*> Tanks;
+ vector <FGTank*>::iterator iTank;
+ unsigned int numSelectedFuelTanks;
+ unsigned int numSelectedOxiTanks;
+ unsigned int numFuelTanks;
+ unsigned int numOxiTanks;
+ unsigned int numEngines;
+ unsigned int numTanks;
+ int ActiveEngine;
+ FGColumnVector3 vForces;
+ FGColumnVector3 vMoments;
+ FGColumnVector3 vTankXYZ;
+ FGColumnVector3 vXYZtank_arm;
+ FGMatrix33 tankJ;
+ bool refuel;
+ bool fuel_freeze;
+ double TotalFuelQuantity;
+ bool IsBound;
+ bool HavePistonEngine;
+ bool HaveTurbineEngine;
+ bool HaveTurboPropEngine;
+ bool HaveRocketEngine;
+ bool HaveElectricEngine;
+
+ void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
+
--- /dev/null
+SUBDIRS = atmosphere propulsion flight_control
+
+noinst_LIBRARIES = libModels.a
+
+libModels_a_SOURCES = FGAerodynamics.cpp FGAircraft.cpp FGAtmosphere.cpp \
+ FGAuxiliary.cpp FGFCS.cpp FGGroundReactions.cpp FGInertial.cpp \
+ FGLGear.cpp FGMassBalance.cpp FGModel.cpp FGOutput.cpp \
+ FGPropagate.cpp FGPropulsion.cpp FGInput.cpp
+
+noinst_HEADERS = FGAerodynamics.h FGAircraft.h FGAtmosphere.h FGAuxiliary.h \
+ FGFCS.h FGGroundReactions.h FGInertial.h FGLGear.h FGMassBalance.h \
+ FGModel.h FGOutput.h FGPropagate.h FGPropulsion.h FGInput.h
+
+INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGMSIS.cpp
+ Author: David Culp
+ (incorporated into C++ JSBSim class heirarchy, see model authors below)
+ Date started: 12/14/03
+ Purpose: Models the MSIS-00 atmosphere
+
+ ------------- Copyright (C) 2003 David P. Culp (davidculp2@comcast.net) ------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+Models the MSIS-00 atmosphere. Provides temperature and density to FGAtmosphere,
+given day-of-year, time-of-day, altitude, latitude, longitude and local time.
+
+HISTORY
+--------------------------------------------------------------------------------
+12/14/03 DPC Created
+01/11/04 DPC Derived from FGAtmosphere
+
+ --------------------------------------------------------------------
+ --------- N R L M S I S E - 0 0 M O D E L 2 0 0 1 ----------
+ --------------------------------------------------------------------
+
+ This file is part of the NRLMSISE-00 C source code package - release
+ 20020503
+
+ The NRLMSISE-00 model was developed by Mike Picone, Alan Hedin, and
+ Doug Drob. They also wrote a NRLMSISE-00 distribution package in
+ FORTRAN which is available at
+ http://uap-www.nrl.navy.mil/models_web/msis/msis_home.htm
+
+ Dominik Brodowski implemented and maintains this C version. You can
+ reach him at devel@brodo.de. See the file "DOCUMENTATION" for details,
+ and check http://www.brodo.de/english/pub/nrlmsise/index.html for
+ updated releases of this package.
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGMSIS.h"
+#include "FGState.h"
+#include <math.h> /* maths functions */
+#include <stdlib.h> /* for malloc/free */
+#include <stdio.h> /* for printf */
+#include <iostream> // for cout, endl
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_MSIS;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+EXTERNAL GLOBAL DATA
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+ /* POWER7 */
+ extern double pt[150];
+ extern double pd[9][150];
+ extern double ps[150];
+ extern double pdl[2][25];
+ extern double ptl[4][100];
+ extern double pma[10][100];
+ extern double sam[100];
+
+ /* LOWER7 */
+ extern double ptm[10];
+ extern double pdm[8][10];
+ extern double pavgm[10];
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+MSIS::MSIS(FGFDMExec* fdmex) : FGAtmosphere(fdmex)
+{
+ Name = "MSIS";
+ bind();
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+MSIS::~MSIS()
+{
+ unbind();
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool MSIS::InitModel(void)
+{
+ FGModel::InitModel();
+
+ unsigned int i;
+
+ flags.switches[0] = 0;
+ for (i=1;i<24;i++) flags.switches[i] = 1;
+
+ for (i=0;i<7;i++) aph.a[i] = 100.0;
+
+ // set some common magnetic flux values
+ input.f107A = 150.0;
+ input.f107 = 150.0;
+ input.ap = 4.0;
+
+ SLtemperature = intTemperature = 518.0;
+ SLpressure = intPressure = 2116.7;
+ SLdensity = intDensity = 0.002378;
+ SLsoundspeed = sqrt(2403.0832 * SLtemperature);
+ rSLtemperature = 1.0/intTemperature;
+ rSLpressure = 1.0/intPressure;
+ rSLdensity = 1.0/intDensity;
+ rSLsoundspeed = 1.0/SLsoundspeed;
+ temperature = &intTemperature;
+ pressure = &intPressure;
+ density = &intDensity;
+
+ useExternal=false;
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool MSIS::Run(void)
+{
+ if (FGModel::Run()) return true;
+ if (FDMExec->Holding()) return false;
+
+ //do temp, pressure, and density first
+ if (!useExternal) {
+ // get sea-level values
+ Calculate(Auxiliary->GetDayOfYear(),
+ Auxiliary->GetSecondsInDay(),
+ 0.0,
+ Propagate->GetLocation().GetLatitudeDeg(),
+ Propagate->GetLocation().GetLongitudeDeg());
+ SLtemperature = output.t[1] * 1.8;
+ SLdensity = output.d[5] * 1.940321;
+ SLpressure = 1716.488 * SLdensity * SLtemperature;
+ SLsoundspeed = sqrt(2403.0832 * SLtemperature);
+ rSLtemperature = 1.0/SLtemperature;
+ rSLpressure = 1.0/SLpressure;
+ rSLdensity = 1.0/SLdensity;
+ rSLsoundspeed = 1.0/SLsoundspeed;
+
+ // get at-altitude values
+ Calculate(Auxiliary->GetDayOfYear(),
+ Auxiliary->GetSecondsInDay(),
+ Propagate->Geth(),
+ Propagate->GetLocation().GetLatitudeDeg(),
+ Propagate->GetLocation().GetLongitudeDeg());
+ intTemperature = output.t[1] * 1.8;
+ intDensity = output.d[5] * 1.940321;
+ intPressure = 1716.488 * intDensity * intTemperature;
+ soundspeed = sqrt(2403.0832 * intTemperature);
+ //cout << "T=" << intTemperature << " D=" << intDensity << " P=";
+ //cout << intPressure << " a=" << soundspeed << endl;
+ }
+
+ if (turbType != ttNone) {
+ Turbulence();
+ vWindNED += vTurbulence;
+ }
+
+ if (vWindNED(1) != 0.0) psiw = atan2( vWindNED(2), vWindNED(1) );
+
+ if (psiw < 0) psiw += 2*M_PI;
+
+ Debug(2);
+
+ return false;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void MSIS::Calculate(int day, double sec, double alt, double lat, double lon)
+{
+ input.year = 2000;
+ input.doy = day;
+ input.sec = sec;
+ input.alt = alt / 3281; //feet to kilometers
+ input.g_lat = lat;
+ input.g_long = lon;
+
+ input.lst = (sec/3600) + (lon/15);
+ if (input.lst > 24.0) input.lst -= 24.0;
+ if (input.lst < 0.0) input.lst = 24 - input.lst;
+
+ gtd7d(&input, &flags, &output);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+void MSIS::UseExternal(void){
+ // do nothing, external control not allowed
+}
+
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+void MSIS::tselec(struct nrlmsise_flags *flags)
+{
+ int i;
+ for (i=0;i<24;i++) {
+ if (i!=9) {
+ if (flags->switches[i]==1)
+ flags->sw[i]=1;
+ else
+ flags->sw[i]=0;
+ if (flags->switches[i]>0)
+ flags->swc[i]=1;
+ else
+ flags->swc[i]=0;
+ } else {
+ flags->sw[i]=flags->switches[i];
+ flags->swc[i]=flags->switches[i];
+ }
+ }
+}
+
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void MSIS::glatf(double lat, double *gv, double *reff)
+{
+ double dgtr = 1.74533E-2;
+ double c2;
+ c2 = cos(2.0*dgtr*lat);
+ *gv = 980.616 * (1.0 - 0.0026373 * c2);
+ *reff = 2.0 * (*gv) / (3.085462E-6 + 2.27E-9 * c2) * 1.0E-5;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double MSIS::ccor(double alt, double r, double h1, double zh)
+{
+/* CHEMISTRY/DISSOCIATION CORRECTION FOR MSIS MODELS
+ * ALT - altitude
+ * R - target ratio
+ * H1 - transition scale length
+ * ZH - altitude of 1/2 R
+ */
+ double e;
+ double ex;
+ e = (alt - zh) / h1;
+ if (e>70)
+ return exp(0.0);
+ if (e<-70)
+ return exp(r);
+ ex = exp(e);
+ e = r / (1.0 + ex);
+ return exp(e);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double MSIS::ccor2(double alt, double r, double h1, double zh, double h2)
+{
+/* CHEMISTRY/DISSOCIATION CORRECTION FOR MSIS MODELS
+ * ALT - altitude
+ * R - target ratio
+ * H1 - transition scale length
+ * ZH - altitude of 1/2 R
+ * H2 - transition scale length #2 ?
+ */
+ double e1, e2;
+ double ex1, ex2;
+ double ccor2v;
+ e1 = (alt - zh) / h1;
+ e2 = (alt - zh) / h2;
+ if ((e1 > 70) || (e2 > 70))
+ return exp(0.0);
+ if ((e1 < -70) && (e2 < -70))
+ return exp(r);
+ ex1 = exp(e1);
+ ex2 = exp(e2);
+ ccor2v = r / (1.0 + 0.5 * (ex1 + ex2));
+ return exp(ccor2v);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double MSIS::scalh(double alt, double xm, double temp)
+{
+ double g;
+ double rgas=831.4;
+ g = gsurf / (pow((1.0 + alt/re),2.0));
+ g = rgas * temp / (g * xm);
+ return g;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double MSIS::dnet (double dd, double dm, double zhm, double xmm, double xm)
+{
+/* TURBOPAUSE CORRECTION FOR MSIS MODELS
+ * Root mean density
+ * DD - diffusive density
+ * DM - full mixed density
+ * ZHM - transition scale length
+ * XMM - full mixed molecular weight
+ * XM - species molecular weight
+ * DNET - combined density
+ */
+ double a;
+ double ylog;
+ a = zhm / (xmm-xm);
+ if (!((dm>0) && (dd>0))) {
+ printf("dnet log error %e %e %e\n",dm,dd,xm);
+ if ((dd==0) && (dm==0))
+ dd=1;
+ if (dm==0)
+ return dd;
+ if (dd==0)
+ return dm;
+ }
+ ylog = a * log(dm/dd);
+ if (ylog<-10)
+ return dd;
+ if (ylog>10)
+ return dm;
+ a = dd*pow((1.0 + exp(ylog)),(1.0/a));
+ return a;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void MSIS::splini (double *xa, double *ya, double *y2a, int n, double x, double *y)
+{
+/* INTEGRATE CUBIC SPLINE FUNCTION FROM XA(1) TO X
+ * XA,YA: ARRAYS OF TABULATED FUNCTION IN ASCENDING ORDER BY X
+ * Y2A: ARRAY OF SECOND DERIVATIVES
+ * N: SIZE OF ARRAYS XA,YA,Y2A
+ * X: ABSCISSA ENDPOINT FOR INTEGRATION
+ * Y: OUTPUT VALUE
+ */
+ double yi=0;
+ int klo=0;
+ int khi=1;
+ double xx, h, a, b, a2, b2;
+ while ((x>xa[klo]) && (khi<n)) {
+ xx=x;
+ if (khi<(n-1)) {
+ if (x<xa[khi])
+ xx=x;
+ else
+ xx=xa[khi];
+ }
+ h = xa[khi] - xa[klo];
+ a = (xa[khi] - xx)/h;
+ b = (xx - xa[klo])/h;
+ a2 = a*a;
+ b2 = b*b;
+ yi += ((1.0 - a2) * ya[klo] / 2.0 + b2 * ya[khi] / 2.0 + ((-(1.0+a2*a2)/4.0 + a2/2.0) * y2a[klo] + (b2*b2/4.0 - b2/2.0) * y2a[khi]) * h * h / 6.0) * h;
+ klo++;
+ khi++;
+ }
+ *y = yi;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void MSIS::splint (double *xa, double *ya, double *y2a, int n, double x, double *y)
+{
+/* CALCULATE CUBIC SPLINE INTERP VALUE
+ * ADAPTED FROM NUMERICAL RECIPES BY PRESS ET AL.
+ * XA,YA: ARRAYS OF TABULATED FUNCTION IN ASCENDING ORDER BY X
+ * Y2A: ARRAY OF SECOND DERIVATIVES
+ * N: SIZE OF ARRAYS XA,YA,Y2A
+ * X: ABSCISSA FOR INTERPOLATION
+ * Y: OUTPUT VALUE
+ */
+ int klo=0;
+ int khi=n-1;
+ int k;
+ double h;
+ double a, b, yi;
+ while ((khi-klo)>1) {
+ k=(khi+klo)/2;
+ if (xa[k]>x)
+ khi=k;
+ else
+ klo=k;
+ }
+ h = xa[khi] - xa[klo];
+ if (h==0.0)
+ printf("bad XA input to splint");
+ a = (xa[khi] - x)/h;
+ b = (x - xa[klo])/h;
+ yi = a * ya[klo] + b * ya[khi] + ((a*a*a - a) * y2a[klo] + (b*b*b - b) * y2a[khi]) * h * h/6.0;
+ *y = yi;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void MSIS::spline (double *x, double *y, int n, double yp1, double ypn, double *y2)
+{
+/* CALCULATE 2ND DERIVATIVES OF CUBIC SPLINE INTERP FUNCTION
+ * ADAPTED FROM NUMERICAL RECIPES BY PRESS ET AL
+ * X,Y: ARRAYS OF TABULATED FUNCTION IN ASCENDING ORDER BY X
+ * N: SIZE OF ARRAYS X,Y
+ * YP1,YPN: SPECIFIED DERIVATIVES AT X[0] AND X[N-1]; VALUES
+ * >= 1E30 SIGNAL SIGNAL SECOND DERIVATIVE ZERO
+ * Y2: OUTPUT ARRAY OF SECOND DERIVATIVES
+ */
+ double *u;
+ double sig, p, qn, un;
+ int i, k;
+ u=(double*)malloc(sizeof(double)*n);
+ if (u==NULL) {
+ printf("Out Of Memory in spline - ERROR");
+ return;
+ }
+ if (yp1>0.99E30) {
+ y2[0]=0;
+ u[0]=0;
+ } else {
+ y2[0]=-0.5;
+ u[0]=(3.0/(x[1]-x[0]))*((y[1]-y[0])/(x[1]-x[0])-yp1);
+ }
+ for (i=1;i<(n-1);i++) {
+ sig = (x[i]-x[i-1])/(x[i+1] - x[i-1]);
+ p = sig * y2[i-1] + 2.0;
+ y2[i] = (sig - 1.0) / p;
+ u[i] = (6.0 * ((y[i+1] - y[i])/(x[i+1] - x[i]) -(y[i] - y[i-1]) / (x[i] - x[i-1]))/(x[i+1] - x[i-1]) - sig * u[i-1])/p;
+ }
+ if (ypn>0.99E30) {
+ qn = 0;
+ un = 0;
+ } else {
+ qn = 0.5;
+ un = (3.0 / (x[n-1] - x[n-2])) * (ypn - (y[n-1] - y[n-2])/(x[n-1] - x[n-2]));
+ }
+ y2[n-1] = (un - qn * u[n-2]) / (qn * y2[n-2] + 1.0);
+ for (k=n-2;k>=0;k--)
+ y2[k] = y2[k] * y2[k+1] + u[k];
+
+ free(u);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double MSIS::zeta(double zz, double zl)
+{
+ return ((zz-zl)*(re+zl)/(re+zz));
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double MSIS::densm(double alt, double d0, double xm, double *tz, int mn3,
+ double *zn3, double *tn3, double *tgn3, int mn2, double *zn2,
+ double *tn2, double *tgn2)
+{
+/* Calculate Temperature and Density Profiles for lower atmos. */
+ double xs[10], ys[10], y2out[10];
+ double rgas = 831.4;
+ double z, z1, z2, t1, t2, zg, zgdif;
+ double yd1, yd2;
+ double x, y, yi;
+ double expl, gamm, glb;
+ double densm_tmp;
+ int mn;
+ int k;
+ densm_tmp=d0;
+ if (alt>zn2[0]) {
+ if (xm==0.0)
+ return *tz;
+ else
+ return d0;
+ }
+
+ /* STRATOSPHERE/MESOSPHERE TEMPERATURE */
+ if (alt>zn2[mn2-1])
+ z=alt;
+ else
+ z=zn2[mn2-1];
+ mn=mn2;
+ z1=zn2[0];
+ z2=zn2[mn-1];
+ t1=tn2[0];
+ t2=tn2[mn-1];
+ zg = zeta(z, z1);
+ zgdif = zeta(z2, z1);
+
+ /* set up spline nodes */
+ for (k=0;k<mn;k++) {
+ xs[k]=zeta(zn2[k],z1)/zgdif;
+ ys[k]=1.0 / tn2[k];
+ }
+ yd1=-tgn2[0] / (t1*t1) * zgdif;
+ yd2=-tgn2[1] / (t2*t2) * zgdif * (pow(((re+z2)/(re+z1)),2.0));
+
+ /* calculate spline coefficients */
+ spline (xs, ys, mn, yd1, yd2, y2out);
+ x = zg/zgdif;
+ splint (xs, ys, y2out, mn, x, &y);
+
+ /* temperature at altitude */
+ *tz = 1.0 / y;
+ if (xm!=0.0) {
+ /* calaculate stratosphere / mesospehere density */
+ glb = gsurf / (pow((1.0 + z1/re),2.0));
+ gamm = xm * glb * zgdif / rgas;
+
+ /* Integrate temperature profile */
+ splini(xs, ys, y2out, mn, x, &yi);
+ expl=gamm*yi;
+ if (expl>50.0)
+ expl=50.0;
+
+ /* Density at altitude */
+ densm_tmp = densm_tmp * (t1 / *tz) * exp(-expl);
+ }
+
+ if (alt>zn3[0]) {
+ if (xm==0.0)
+ return *tz;
+ else
+ return densm_tmp;
+ }
+
+ /* troposhere / stratosphere temperature */
+ z = alt;
+ mn = mn3;
+ z1=zn3[0];
+ z2=zn3[mn-1];
+ t1=tn3[0];
+ t2=tn3[mn-1];
+ zg=zeta(z,z1);
+ zgdif=zeta(z2,z1);
+
+ /* set up spline nodes */
+ for (k=0;k<mn;k++) {
+ xs[k] = zeta(zn3[k],z1) / zgdif;
+ ys[k] = 1.0 / tn3[k];
+ }
+ yd1=-tgn3[0] / (t1*t1) * zgdif;
+ yd2=-tgn3[1] / (t2*t2) * zgdif * (pow(((re+z2)/(re+z1)),2.0));
+
+ /* calculate spline coefficients */
+ spline (xs, ys, mn, yd1, yd2, y2out);
+ x = zg/zgdif;
+ splint (xs, ys, y2out, mn, x, &y);
+
+ /* temperature at altitude */
+ *tz = 1.0 / y;
+ if (xm!=0.0) {
+ /* calaculate tropospheric / stratosphere density */
+ glb = gsurf / (pow((1.0 + z1/re),2.0));
+ gamm = xm * glb * zgdif / rgas;
+
+ /* Integrate temperature profile */
+ splini(xs, ys, y2out, mn, x, &yi);
+ expl=gamm*yi;
+ if (expl>50.0)
+ expl=50.0;
+
+ /* Density at altitude */
+ densm_tmp = densm_tmp * (t1 / *tz) * exp(-expl);
+ }
+ if (xm==0.0)
+ return *tz;
+ else
+ return densm_tmp;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double MSIS::densu(double alt, double dlb, double tinf, double tlb, double xm,
+ double alpha, double *tz, double zlb, double s2, int mn1,
+ double *zn1, double *tn1, double *tgn1)
+{
+/* Calculate Temperature and Density Profiles for MSIS models
+ * New lower thermo polynomial
+ */
+ double yd2, yd1, x=0.0, y=0.0;
+ double rgas=831.4;
+ double densu_temp=1.0;
+ double za, z, zg2, tt, ta=0.0;
+ double dta, z1=0.0, z2, t1=0.0, t2, zg, zgdif=0.0;
+ int mn=0;
+ int k;
+ double glb;
+ double expl;
+ double yi;
+ double densa;
+ double gamma, gamm;
+ double xs[5], ys[5], y2out[5];
+ /* joining altitudes of Bates and spline */
+ za=zn1[0];
+ if (alt>za)
+ z=alt;
+ else
+ z=za;
+
+ /* geopotential altitude difference from ZLB */
+ zg2 = zeta(z, zlb);
+
+ /* Bates temperature */
+ tt = tinf - (tinf - tlb) * exp(-s2*zg2);
+ ta = tt;
+ *tz = tt;
+ densu_temp = *tz;
+
+ if (alt<za) {
+ /* calculate temperature below ZA
+ * temperature gradient at ZA from Bates profile */
+ dta = (tinf - ta) * s2 * pow(((re+zlb)/(re+za)),2.0);
+ tgn1[0]=dta;
+ tn1[0]=ta;
+ if (alt>zn1[mn1-1])
+ z=alt;
+ else
+ z=zn1[mn1-1];
+ mn=mn1;
+ z1=zn1[0];
+ z2=zn1[mn-1];
+ t1=tn1[0];
+ t2=tn1[mn-1];
+ /* geopotental difference from z1 */
+ zg = zeta (z, z1);
+ zgdif = zeta(z2, z1);
+ /* set up spline nodes */
+ for (k=0;k<mn;k++) {
+ xs[k] = zeta(zn1[k], z1) / zgdif;
+ ys[k] = 1.0 / tn1[k];
+ }
+ /* end node derivatives */
+ yd1 = -tgn1[0] / (t1*t1) * zgdif;
+ yd2 = -tgn1[1] / (t2*t2) * zgdif * pow(((re+z2)/(re+z1)),2.0);
+ /* calculate spline coefficients */
+ spline (xs, ys, mn, yd1, yd2, y2out);
+ x = zg / zgdif;
+ splint (xs, ys, y2out, mn, x, &y);
+ /* temperature at altitude */
+ *tz = 1.0 / y;
+ densu_temp = *tz;
+ }
+ if (xm==0)
+ return densu_temp;
+
+ /* calculate density above za */
+ glb = gsurf / pow((1.0 + zlb/re),2.0);
+ gamma = xm * glb / (s2 * rgas * tinf);
+ expl = exp(-s2 * gamma * zg2);
+ if (expl>50.0)
+ expl=50.0;
+ if (tt<=0)
+ expl=50.0;
+
+ /* density at altitude */
+ densa = dlb * pow((tlb/tt),((1.0+alpha+gamma))) * expl;
+ densu_temp=densa;
+ if (alt>=za)
+ return densu_temp;
+
+ /* calculate density below za */
+ glb = gsurf / pow((1.0 + z1/re),2.0);
+ gamm = xm * glb * zgdif / rgas;
+
+ /* integrate spline temperatures */
+ splini (xs, ys, y2out, mn, x, &yi);
+ expl = gamm * yi;
+ if (expl>50.0)
+ expl=50.0;
+ if (*tz<=0)
+ expl=50.0;
+
+ /* density at altitude */
+ densu_temp = densu_temp * pow ((t1 / *tz),(1.0 + alpha)) * exp(-expl);
+ return densu_temp;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/* 3hr Magnetic activity functions */
+/* Eq. A24d */
+double MSIS::g0(double a, double *p)
+{
+ return (a - 4.0 + (p[25] - 1.0) * (a - 4.0 + (exp(-sqrt(p[24]*p[24]) *
+ (a - 4.0)) - 1.0) / sqrt(p[24]*p[24])));
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/* Eq. A24c */
+double MSIS::sumex(double ex)
+{
+ return (1.0 + (1.0 - pow(ex,19.0)) / (1.0 - ex) * pow(ex,0.5));
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/* Eq. A24a */
+double MSIS::sg0(double ex, double *p, double *ap)
+{
+ return (g0(ap[1],p) + (g0(ap[2],p)*ex + g0(ap[3],p)*ex*ex +
+ g0(ap[4],p)*pow(ex,3.0) + (g0(ap[5],p)*pow(ex,4.0) +
+ g0(ap[6],p)*pow(ex,12.0))*(1.0-pow(ex,8.0))/(1.0-ex)))/sumex(ex);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double MSIS::globe7(double *p, struct nrlmsise_input *input,
+ struct nrlmsise_flags *flags)
+{
+/* CALCULATE G(L) FUNCTION
+ * Upper Thermosphere Parameters */
+ double t[15];
+ int i,j;
+ int sw9=1;
+ double apd;
+ double xlong;
+ double tloc;
+ double c, s, c2, c4, s2;
+ double sr = 7.2722E-5;
+ double dgtr = 1.74533E-2;
+ double dr = 1.72142E-2;
+ double hr = 0.2618;
+ double cd32, cd18, cd14, cd39;
+ double p32, p18, p14, p39;
+ double df, dfa;
+ double f1, f2;
+ double tinf;
+ struct ap_array *ap;
+
+ tloc=input->lst;
+ for (j=0;j<14;j++)
+ t[j]=0;
+ if (flags->sw[9]>0)
+ sw9=1;
+ else if (flags->sw[9]<0)
+ sw9=-1;
+ xlong = input->g_long;
+
+ /* calculate legendre polynomials */
+ c = sin(input->g_lat * dgtr);
+ s = cos(input->g_lat * dgtr);
+ c2 = c*c;
+ c4 = c2*c2;
+ s2 = s*s;
+
+ plg[0][1] = c;
+ plg[0][2] = 0.5*(3.0*c2 -1.0);
+ plg[0][3] = 0.5*(5.0*c*c2-3.0*c);
+ plg[0][4] = (35.0*c4 - 30.0*c2 + 3.0)/8.0;
+ plg[0][5] = (63.0*c2*c2*c - 70.0*c2*c + 15.0*c)/8.0;
+ plg[0][6] = (11.0*c*plg[0][5] - 5.0*plg[0][4])/6.0;
+/* plg[0][7] = (13.0*c*plg[0][6] - 6.0*plg[0][5])/7.0; */
+ plg[1][1] = s;
+ plg[1][2] = 3.0*c*s;
+ plg[1][3] = 1.5*(5.0*c2-1.0)*s;
+ plg[1][4] = 2.5*(7.0*c2*c-3.0*c)*s;
+ plg[1][5] = 1.875*(21.0*c4 - 14.0*c2 +1.0)*s;
+ plg[1][6] = (11.0*c*plg[1][5]-6.0*plg[1][4])/5.0;
+/* plg[1][7] = (13.0*c*plg[1][6]-7.0*plg[1][5])/6.0; */
+/* plg[1][8] = (15.0*c*plg[1][7]-8.0*plg[1][6])/7.0; */
+ plg[2][2] = 3.0*s2;
+ plg[2][3] = 15.0*s2*c;
+ plg[2][4] = 7.5*(7.0*c2 -1.0)*s2;
+ plg[2][5] = 3.0*c*plg[2][4]-2.0*plg[2][3];
+ plg[2][6] =(11.0*c*plg[2][5]-7.0*plg[2][4])/4.0;
+ plg[2][7] =(13.0*c*plg[2][6]-8.0*plg[2][5])/5.0;
+ plg[3][3] = 15.0*s2*s;
+ plg[3][4] = 105.0*s2*s*c;
+ plg[3][5] =(9.0*c*plg[3][4]-7.*plg[3][3])/2.0;
+ plg[3][6] =(11.0*c*plg[3][5]-8.*plg[3][4])/3.0;
+
+ if (!(((flags->sw[7]==0)&&(flags->sw[8]==0))&&(flags->sw[14]==0))) {
+ stloc = sin(hr*tloc);
+ ctloc = cos(hr*tloc);
+ s2tloc = sin(2.0*hr*tloc);
+ c2tloc = cos(2.0*hr*tloc);
+ s3tloc = sin(3.0*hr*tloc);
+ c3tloc = cos(3.0*hr*tloc);
+ }
+
+ cd32 = cos(dr*(input->doy-p[31]));
+ cd18 = cos(2.0*dr*(input->doy-p[17]));
+ cd14 = cos(dr*(input->doy-p[13]));
+ cd39 = cos(2.0*dr*(input->doy-p[38]));
+ p32=p[31];
+ p18=p[17];
+ p14=p[13];
+ p39=p[38];
+
+ /* F10.7 EFFECT */
+ df = input->f107 - input->f107A;
+ dfa = input->f107A - 150.0;
+ t[0] = p[19]*df*(1.0+p[59]*dfa) + p[20]*df*df + p[21]*dfa + p[29]*pow(dfa,2.0);
+ f1 = 1.0 + (p[47]*dfa +p[19]*df+p[20]*df*df)*flags->swc[1];
+ f2 = 1.0 + (p[49]*dfa+p[19]*df+p[20]*df*df)*flags->swc[1];
+
+ /* TIME INDEPENDENT */
+ t[1] = (p[1]*plg[0][2]+ p[2]*plg[0][4]+p[22]*plg[0][6]) +
+ (p[14]*plg[0][2])*dfa*flags->swc[1] +p[26]*plg[0][1];
+
+ /* SYMMETRICAL ANNUAL */
+ t[2] = p[18]*cd32;
+
+ /* SYMMETRICAL SEMIANNUAL */
+ t[3] = (p[15]+p[16]*plg[0][2])*cd18;
+
+ /* ASYMMETRICAL ANNUAL */
+ t[4] = f1*(p[9]*plg[0][1]+p[10]*plg[0][3])*cd14;
+
+ /* ASYMMETRICAL SEMIANNUAL */
+ t[5] = p[37]*plg[0][1]*cd39;
+
+ /* DIURNAL */
+ if (flags->sw[7]) {
+ double t71, t72;
+ t71 = (p[11]*plg[1][2])*cd14*flags->swc[5];
+ t72 = (p[12]*plg[1][2])*cd14*flags->swc[5];
+ t[6] = f2*((p[3]*plg[1][1] + p[4]*plg[1][3] + p[27]*plg[1][5] + t71) * \
+ ctloc + (p[6]*plg[1][1] + p[7]*plg[1][3] + p[28]*plg[1][5] \
+ + t72)*stloc);
+}
+
+ /* SEMIDIURNAL */
+ if (flags->sw[8]) {
+ double t81, t82;
+ t81 = (p[23]*plg[2][3]+p[35]*plg[2][5])*cd14*flags->swc[5];
+ t82 = (p[33]*plg[2][3]+p[36]*plg[2][5])*cd14*flags->swc[5];
+ t[7] = f2*((p[5]*plg[2][2]+ p[41]*plg[2][4] + t81)*c2tloc +(p[8]*plg[2][2] + p[42]*plg[2][4] + t82)*s2tloc);
+ }
+
+ /* TERDIURNAL */
+ if (flags->sw[14]) {
+ t[13] = f2 * ((p[39]*plg[3][3]+(p[93]*plg[3][4]+p[46]*plg[3][6])*cd14*flags->swc[5])* s3tloc +(p[40]*plg[3][3]+(p[94]*plg[3][4]+p[48]*plg[3][6])*cd14*flags->swc[5])* c3tloc);
+}
+
+ /* magnetic activity based on daily ap */
+ if (flags->sw[9]==-1) {
+ ap = input->ap_a;
+ if (p[51]!=0) {
+ double exp1;
+ exp1 = exp(-10800.0*sqrt(p[51]*p[51])/(1.0+p[138]*(45.0-sqrt(input->g_lat*input->g_lat))));
+ if (exp1>0.99999)
+ exp1=0.99999;
+ if (p[24]<1.0E-4)
+ p[24]=1.0E-4;
+ apt[0]=sg0(exp1,p,ap->a);
+ /* apt[1]=sg2(exp1,p,ap->a);
+ apt[2]=sg0(exp2,p,ap->a);
+ apt[3]=sg2(exp2,p,ap->a);
+ */
+ if (flags->sw[9]) {
+ t[8] = apt[0]*(p[50]+p[96]*plg[0][2]+p[54]*plg[0][4]+ \
+ (p[125]*plg[0][1]+p[126]*plg[0][3]+p[127]*plg[0][5])*cd14*flags->swc[5]+ \
+ (p[128]*plg[1][1]+p[129]*plg[1][3]+p[130]*plg[1][5])*flags->swc[7]* \
+ cos(hr*(tloc-p[131])));
+ }
+ }
+ } else {
+ double p44, p45;
+ apd=input->ap-4.0;
+ p44=p[43];
+ p45=p[44];
+ if (p44<0)
+ p44 = 1.0E-5;
+ apdf = apd + (p45-1.0)*(apd + (exp(-p44 * apd) - 1.0)/p44);
+ if (flags->sw[9]) {
+ t[8]=apdf*(p[32]+p[45]*plg[0][2]+p[34]*plg[0][4]+ \
+ (p[100]*plg[0][1]+p[101]*plg[0][3]+p[102]*plg[0][5])*cd14*flags->swc[5]+
+ (p[121]*plg[1][1]+p[122]*plg[1][3]+p[123]*plg[1][5])*flags->swc[7]*
+ cos(hr*(tloc-p[124])));
+ }
+ }
+
+ if ((flags->sw[10])&&(input->g_long>-1000.0)) {
+
+ /* longitudinal */
+ if (flags->sw[11]) {
+ t[10] = (1.0 + p[80]*dfa*flags->swc[1])* \
+ ((p[64]*plg[1][2]+p[65]*plg[1][4]+p[66]*plg[1][6]\
+ +p[103]*plg[1][1]+p[104]*plg[1][3]+p[105]*plg[1][5]\
+ +flags->swc[5]*(p[109]*plg[1][1]+p[110]*plg[1][3]+p[111]*plg[1][5])*cd14)* \
+ cos(dgtr*input->g_long) \
+ +(p[90]*plg[1][2]+p[91]*plg[1][4]+p[92]*plg[1][6]\
+ +p[106]*plg[1][1]+p[107]*plg[1][3]+p[108]*plg[1][5]\
+ +flags->swc[5]*(p[112]*plg[1][1]+p[113]*plg[1][3]+p[114]*plg[1][5])*cd14)* \
+ sin(dgtr*input->g_long));
+ }
+
+ /* ut and mixed ut, longitude */
+ if (flags->sw[12]){
+ t[11]=(1.0+p[95]*plg[0][1])*(1.0+p[81]*dfa*flags->swc[1])*\
+ (1.0+p[119]*plg[0][1]*flags->swc[5]*cd14)*\
+ ((p[68]*plg[0][1]+p[69]*plg[0][3]+p[70]*plg[0][5])*\
+ cos(sr*(input->sec-p[71])));
+ t[11]+=flags->swc[11]*\
+ (p[76]*plg[2][3]+p[77]*plg[2][5]+p[78]*plg[2][7])*\
+ cos(sr*(input->sec-p[79])+2.0*dgtr*input->g_long)*(1.0+p[137]*dfa*flags->swc[1]);
+ }
+
+ /* ut, longitude magnetic activity */
+ if (flags->sw[13]) {
+ if (flags->sw[9]==-1) {
+ if (p[51]) {
+ t[12]=apt[0]*flags->swc[11]*(1.+p[132]*plg[0][1])*\
+ ((p[52]*plg[1][2]+p[98]*plg[1][4]+p[67]*plg[1][6])*\
+ cos(dgtr*(input->g_long-p[97])))\
+ +apt[0]*flags->swc[11]*flags->swc[5]*\
+ (p[133]*plg[1][1]+p[134]*plg[1][3]+p[135]*plg[1][5])*\
+ cd14*cos(dgtr*(input->g_long-p[136])) \
+ +apt[0]*flags->swc[12]* \
+ (p[55]*plg[0][1]+p[56]*plg[0][3]+p[57]*plg[0][5])*\
+ cos(sr*(input->sec-p[58]));
+ }
+ } else {
+ t[12] = apdf*flags->swc[11]*(1.0+p[120]*plg[0][1])*\
+ ((p[60]*plg[1][2]+p[61]*plg[1][4]+p[62]*plg[1][6])*\
+ cos(dgtr*(input->g_long-p[63])))\
+ +apdf*flags->swc[11]*flags->swc[5]* \
+ (p[115]*plg[1][1]+p[116]*plg[1][3]+p[117]*plg[1][5])* \
+ cd14*cos(dgtr*(input->g_long-p[118])) \
+ + apdf*flags->swc[12]* \
+ (p[83]*plg[0][1]+p[84]*plg[0][3]+p[85]*plg[0][5])* \
+ cos(sr*(input->sec-p[75]));
+ }
+ }
+ }
+
+ /* parms not used: 82, 89, 99, 139-149 */
+ tinf = p[30];
+ for (i=0;i<14;i++)
+ tinf = tinf + abs(flags->sw[i+1])*t[i];
+ return tinf;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double MSIS::glob7s(double *p, struct nrlmsise_input *input,
+ struct nrlmsise_flags *flags)
+{
+/* VERSION OF GLOBE FOR LOWER ATMOSPHERE 10/26/99
+ */
+ double pset=2.0;
+ double t[14];
+ double tt;
+ double cd32, cd18, cd14, cd39;
+ double p32, p18, p14, p39;
+ int i,j;
+ double dr=1.72142E-2;
+ double dgtr=1.74533E-2;
+ /* confirm parameter set */
+ if (p[99]==0)
+ p[99]=pset;
+ if (p[99]!=pset) {
+ printf("Wrong parameter set for glob7s\n");
+ return -1;
+ }
+ for (j=0;j<14;j++)
+ t[j]=0.0;
+ cd32 = cos(dr*(input->doy-p[31]));
+ cd18 = cos(2.0*dr*(input->doy-p[17]));
+ cd14 = cos(dr*(input->doy-p[13]));
+ cd39 = cos(2.0*dr*(input->doy-p[38]));
+ p32=p[31];
+ p18=p[17];
+ p14=p[13];
+ p39=p[38];
+
+ /* F10.7 */
+ t[0] = p[21]*dfa;
+
+ /* time independent */
+ t[1]=p[1]*plg[0][2] + p[2]*plg[0][4] + p[22]*plg[0][6] + p[26]*plg[0][1] + p[14]*plg[0][3] + p[59]*plg[0][5];
+
+ /* SYMMETRICAL ANNUAL */
+ t[2]=(p[18]+p[47]*plg[0][2]+p[29]*plg[0][4])*cd32;
+
+ /* SYMMETRICAL SEMIANNUAL */
+ t[3]=(p[15]+p[16]*plg[0][2]+p[30]*plg[0][4])*cd18;
+
+ /* ASYMMETRICAL ANNUAL */
+ t[4]=(p[9]*plg[0][1]+p[10]*plg[0][3]+p[20]*plg[0][5])*cd14;
+
+ /* ASYMMETRICAL SEMIANNUAL */
+ t[5]=(p[37]*plg[0][1])*cd39;
+
+ /* DIURNAL */
+ if (flags->sw[7]) {
+ double t71, t72;
+ t71 = p[11]*plg[1][2]*cd14*flags->swc[5];
+ t72 = p[12]*plg[1][2]*cd14*flags->swc[5];
+ t[6] = ((p[3]*plg[1][1] + p[4]*plg[1][3] + t71) * ctloc + (p[6]*plg[1][1] + p[7]*plg[1][3] + t72) * stloc) ;
+ }
+
+ /* SEMIDIURNAL */
+ if (flags->sw[8]) {
+ double t81, t82;
+ t81 = (p[23]*plg[2][3]+p[35]*plg[2][5])*cd14*flags->swc[5];
+ t82 = (p[33]*plg[2][3]+p[36]*plg[2][5])*cd14*flags->swc[5];
+ t[7] = ((p[5]*plg[2][2] + p[41]*plg[2][4] + t81) * c2tloc + (p[8]*plg[2][2] + p[42]*plg[2][4] + t82) * s2tloc);
+ }
+
+ /* TERDIURNAL */
+ if (flags->sw[14]) {
+ t[13] = p[39] * plg[3][3] * s3tloc + p[40] * plg[3][3] * c3tloc;
+ }
+
+ /* MAGNETIC ACTIVITY */
+ if (flags->sw[9]) {
+ if (flags->sw[9]==1)
+ t[8] = apdf * (p[32] + p[45] * plg[0][2] * flags->swc[2]);
+ if (flags->sw[9]==-1)
+ t[8]=(p[50]*apt[0] + p[96]*plg[0][2] * apt[0]*flags->swc[2]);
+ }
+
+ /* LONGITUDINAL */
+ if (!((flags->sw[10]==0) || (flags->sw[11]==0) || (input->g_long<=-1000.0))) {
+ t[10] = (1.0 + plg[0][1]*(p[80]*flags->swc[5]*cos(dr*(input->doy-p[81]))\
+ +p[85]*flags->swc[6]*cos(2.0*dr*(input->doy-p[86])))\
+ +p[83]*flags->swc[3]*cos(dr*(input->doy-p[84]))\
+ +p[87]*flags->swc[4]*cos(2.0*dr*(input->doy-p[88])))\
+ *((p[64]*plg[1][2]+p[65]*plg[1][4]+p[66]*plg[1][6]\
+ +p[74]*plg[1][1]+p[75]*plg[1][3]+p[76]*plg[1][5]\
+ )*cos(dgtr*input->g_long)\
+ +(p[90]*plg[1][2]+p[91]*plg[1][4]+p[92]*plg[1][6]\
+ +p[77]*plg[1][1]+p[78]*plg[1][3]+p[79]*plg[1][5]\
+ )*sin(dgtr*input->g_long));
+ }
+ tt=0;
+ for (i=0;i<14;i++)
+ tt+=abs(flags->sw[i+1])*t[i];
+ return tt;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void MSIS::gtd7(struct nrlmsise_input *input, struct nrlmsise_flags *flags,
+ struct nrlmsise_output *output)
+{
+ double xlat;
+ double xmm;
+ int mn3 = 5;
+ double zn3[5]={32.5,20.0,15.0,10.0,0.0};
+ int mn2 = 4;
+ double zn2[4]={72.5,55.0,45.0,32.5};
+ double altt;
+ double zmix=62.5;
+ double tmp;
+ double dm28m;
+ double tz;
+ double dmc;
+ double dmr;
+ double dz28;
+ struct nrlmsise_output soutput;
+ int i;
+
+ tselec(flags);
+
+ /* Latitude variation of gravity (none for sw[2]=0) */
+ xlat=input->g_lat;
+ if (flags->sw[2]==0)
+ xlat=45.0;
+ glatf(xlat, &gsurf, &re);
+
+ xmm = pdm[2][4];
+
+ /* THERMOSPHERE / MESOSPHERE (above zn2[0]) */
+ if (input->alt>zn2[0])
+ altt=input->alt;
+ else
+ altt=zn2[0];
+
+ tmp=input->alt;
+ input->alt=altt;
+ gts7(input, flags, &soutput);
+ altt=input->alt;
+ input->alt=tmp;
+ if (flags->sw[0]) /* metric adjustment */
+ dm28m=dm28*1.0E6;
+ else
+ dm28m=dm28;
+ output->t[0]=soutput.t[0];
+ output->t[1]=soutput.t[1];
+ if (input->alt>=zn2[0]) {
+ for (i=0;i<9;i++)
+ output->d[i]=soutput.d[i];
+ return;
+ }
+
+/* LOWER MESOSPHERE/UPPER STRATOSPHERE (between zn3[0] and zn2[0])
+ * Temperature at nodes and gradients at end nodes
+ * Inverse temperature a linear function of spherical harmonics
+ */
+ meso_tgn2[0]=meso_tgn1[1];
+ meso_tn2[0]=meso_tn1[4];
+ meso_tn2[1]=pma[0][0]*pavgm[0]/(1.0-flags->sw[20]*glob7s(pma[0], input, flags));
+ meso_tn2[2]=pma[1][0]*pavgm[1]/(1.0-flags->sw[20]*glob7s(pma[1], input, flags));
+ meso_tn2[3]=pma[2][0]*pavgm[2]/(1.0-flags->sw[20]*flags->sw[22]*glob7s(pma[2], input, flags));
+ meso_tgn2[1]=pavgm[8]*pma[9][0]*(1.0+flags->sw[20]*flags->sw[22]*glob7s(pma[9], input, flags))*meso_tn2[3]*meso_tn2[3]/(pow((pma[2][0]*pavgm[2]),2.0));
+ meso_tn3[0]=meso_tn2[3];
+
+ if (input->alt<zn3[0]) {
+/* LOWER STRATOSPHERE AND TROPOSPHERE (below zn3[0])
+ * Temperature at nodes and gradients at end nodes
+ * Inverse temperature a linear function of spherical harmonics
+ */
+ meso_tgn3[0]=meso_tgn2[1];
+ meso_tn3[1]=pma[3][0]*pavgm[3]/(1.0-flags->sw[22]*glob7s(pma[3], input, flags));
+ meso_tn3[2]=pma[4][0]*pavgm[4]/(1.0-flags->sw[22]*glob7s(pma[4], input, flags));
+ meso_tn3[3]=pma[5][0]*pavgm[5]/(1.0-flags->sw[22]*glob7s(pma[5], input, flags));
+ meso_tn3[4]=pma[6][0]*pavgm[6]/(1.0-flags->sw[22]*glob7s(pma[6], input, flags));
+ meso_tgn3[1]=pma[7][0]*pavgm[7]*(1.0+flags->sw[22]*glob7s(pma[7], input, flags)) *meso_tn3[4]*meso_tn3[4]/(pow((pma[6][0]*pavgm[6]),2.0));
+ }
+
+ /* LINEAR TRANSITION TO FULL MIXING BELOW zn2[0] */
+
+ dmc=0;
+ if (input->alt>zmix)
+ dmc = 1.0 - (zn2[0]-input->alt)/(zn2[0] - zmix);
+ dz28=soutput.d[2];
+
+ /**** N2 density ****/
+ dmr=soutput.d[2] / dm28m - 1.0;
+ output->d[2]=densm(input->alt,dm28m,xmm, &tz, mn3, zn3, meso_tn3, meso_tgn3, mn2, zn2, meso_tn2, meso_tgn2);
+ output->d[2]=output->d[2] * (1.0 + dmr*dmc);
+
+ /**** HE density ****/
+ dmr = soutput.d[0] / (dz28 * pdm[0][1]) - 1.0;
+ output->d[0] = output->d[2] * pdm[0][1] * (1.0 + dmr*dmc);
+
+ /**** O density ****/
+ output->d[1] = 0;
+ output->d[8] = 0;
+
+ /**** O2 density ****/
+ dmr = soutput.d[3] / (dz28 * pdm[3][1]) - 1.0;
+ output->d[3] = output->d[2] * pdm[3][1] * (1.0 + dmr*dmc);
+
+ /**** AR density ***/
+ dmr = soutput.d[4] / (dz28 * pdm[4][1]) - 1.0;
+ output->d[4] = output->d[2] * pdm[4][1] * (1.0 + dmr*dmc);
+
+ /**** Hydrogen density ****/
+ output->d[6] = 0;
+
+ /**** Atomic nitrogen density ****/
+ output->d[7] = 0;
+
+ /**** Total mass density */
+ output->d[5] = 1.66E-24 * (4.0 * output->d[0] + 16.0 * output->d[1] +
+ 28.0 * output->d[2] + 32.0 * output->d[3] + 40.0 * output->d[4]
+ + output->d[6] + 14.0 * output->d[7]);
+
+ if (flags->sw[0])
+ output->d[5]=output->d[5]/1000;
+
+ /**** temperature at altitude ****/
+ dd = densm(input->alt, 1.0, 0, &tz, mn3, zn3, meso_tn3, meso_tgn3,
+ mn2, zn2, meso_tn2, meso_tgn2);
+ output->t[1]=tz;
+
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void MSIS::gtd7d(struct nrlmsise_input *input, struct nrlmsise_flags *flags,
+ struct nrlmsise_output *output)
+{
+ gtd7(input, flags, output);
+ output->d[5] = 1.66E-24 * (4.0 * output->d[0] + 16.0 * output->d[1] +
+ 28.0 * output->d[2] + 32.0 * output->d[3] + 40.0 * output->d[4]
+ + output->d[6] + 14.0 * output->d[7] + 16.0 * output->d[8]);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void MSIS::ghp7(struct nrlmsise_input *input, struct nrlmsise_flags *flags,
+ struct nrlmsise_output *output, double press)
+{
+ double bm = 1.3806E-19;
+ double rgas = 831.4;
+ double test = 0.00043;
+ double ltest = 12;
+ double pl, p;
+ double zi = 0.0;
+ double z;
+ double cl, cl2;
+ double ca, cd;
+ double xn, xm, diff;
+ double g, sh;
+ int l;
+ pl = log10(press);
+ if (pl >= -5.0) {
+ if (pl>2.5)
+ zi = 18.06 * (3.00 - pl);
+ else if ((pl>0.075) && (pl<=2.5))
+ zi = 14.98 * (3.08 - pl);
+ else if ((pl>-1) && (pl<=0.075))
+ zi = 17.80 * (2.72 - pl);
+ else if ((pl>-2) && (pl<=-1))
+ zi = 14.28 * (3.64 - pl);
+ else if ((pl>-4) && (pl<=-2))
+ zi = 12.72 * (4.32 -pl);
+ else if (pl<=-4)
+ zi = 25.3 * (0.11 - pl);
+ cl = input->g_lat/90.0;
+ cl2 = cl*cl;
+ if (input->doy<182)
+ cd = (1.0 - (double) input->doy) / 91.25;
+ else
+ cd = ((double) input->doy) / 91.25 - 3.0;
+ ca = 0;
+ if ((pl > -1.11) && (pl<=-0.23))
+ ca = 1.0;
+ if (pl > -0.23)
+ ca = (2.79 - pl) / (2.79 + 0.23);
+ if ((pl <= -1.11) && (pl>-3))
+ ca = (-2.93 - pl)/(-2.93 + 1.11);
+ z = zi - 4.87 * cl * cd * ca - 1.64 * cl2 * ca + 0.31 * ca * cl;
+ } else
+ z = 22.0 * pow((pl + 4.0),2.0) + 110.0;
+
+ /* iteration loop */
+ l = 0;
+ do {
+ l++;
+ input->alt = z;
+ gtd7(input, flags, output);
+ z = input->alt;
+ xn = output->d[0] + output->d[1] + output->d[2] + output->d[3] + output->d[4] + output->d[6] + output->d[7];
+ p = bm * xn * output->t[1];
+ if (flags->sw[0])
+ p = p*1.0E-6;
+ diff = pl - log10(p);
+ if (sqrt(diff*diff)<test)
+ return;
+ if (l==ltest) {
+ printf("ERROR: ghp7 not converging for press %e, diff %e",press,diff);
+ return;
+ }
+ xm = output->d[5] / xn / 1.66E-24;
+ if (flags->sw[0])
+ xm = xm * 1.0E3;
+ g = gsurf / (pow((1.0 + z/re),2.0));
+ sh = rgas * output->t[1] / (xm * g);
+
+ /* new altitude estimate using scale height */
+ if (l < 6)
+ z = z - sh * diff * 2.302;
+ else
+ z = z - sh * diff;
+ } while (1==1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void MSIS::gts7(struct nrlmsise_input *input, struct nrlmsise_flags *flags,
+ struct nrlmsise_output *output)
+{
+/* Thermospheric portion of NRLMSISE-00
+ * See GTD7 for more extensive comments
+ * alt > 72.5 km!
+ */
+ double za;
+ int i, j;
+ double ddum, z;
+ double zn1[5] = {120.0, 110.0, 100.0, 90.0, 72.5};
+ double tinf;
+ int mn1 = 5;
+ double g0;
+ double tlb;
+ double s, z0, t0, tr12;
+ double db01, db04, db14, db16, db28, db32, db40, db48;
+ double zh28, zh04, zh16, zh32, zh40, zh01, zh14;
+ double zhm28, zhm04, zhm16, zhm32, zhm40, zhm01, zhm14;
+ double xmd;
+ double b28, b04, b16, b32, b40, b01, b14;
+ double tz;
+ double g28, g4, g16, g32, g40, g1, g14;
+ double zhf, xmm;
+ double zc04, zc16, zc32, zc40, zc01, zc14;
+ double hc04, hc16, hc32, hc40, hc01, hc14;
+ double hcc16, hcc32, hcc01, hcc14;
+ double zcc16, zcc32, zcc01, zcc14;
+ double rc16, rc32, rc01, rc14;
+ double rl;
+ double g16h, db16h, tho, zsht, zmho, zsho;
+ double dgtr=1.74533E-2;
+ double dr=1.72142E-2;
+ double alpha[9]={-0.38, 0.0, 0.0, 0.0, 0.17, 0.0, -0.38, 0.0, 0.0};
+ double altl[8]={200.0, 300.0, 160.0, 250.0, 240.0, 450.0, 320.0, 450.0};
+ double dd;
+ double hc216, hcc232;
+ za = pdl[1][15];
+ zn1[0] = za;
+ for (j=0;j<9;j++)
+ output->d[j]=0;
+
+ /* TINF VARIATIONS NOT IMPORTANT BELOW ZA OR ZN1(1) */
+ if (input->alt>zn1[0])
+ tinf = ptm[0]*pt[0] * \
+ (1.0+flags->sw[16]*globe7(pt,input,flags));
+ else
+ tinf = ptm[0]*pt[0];
+ output->t[0]=tinf;
+
+ /* GRADIENT VARIATIONS NOT IMPORTANT BELOW ZN1(5) */
+ if (input->alt>zn1[4])
+ g0 = ptm[3]*ps[0] * \
+ (1.0+flags->sw[19]*globe7(ps,input,flags));
+ else
+ g0 = ptm[3]*ps[0];
+ tlb = ptm[1] * (1.0 + flags->sw[17]*globe7(pd[3],input,flags))*pd[3][0];
+ s = g0 / (tinf - tlb);
+
+/* Lower thermosphere temp variations not significant for
+ * density above 300 km */
+ if (input->alt<300.0) {
+ meso_tn1[1]=ptm[6]*ptl[0][0]/(1.0-flags->sw[18]*glob7s(ptl[0], input, flags));
+ meso_tn1[2]=ptm[2]*ptl[1][0]/(1.0-flags->sw[18]*glob7s(ptl[1], input, flags));
+ meso_tn1[3]=ptm[7]*ptl[2][0]/(1.0-flags->sw[18]*glob7s(ptl[2], input, flags));
+ meso_tn1[4]=ptm[4]*ptl[3][0]/(1.0-flags->sw[18]*flags->sw[20]*glob7s(ptl[3], input, flags));
+ meso_tgn1[1]=ptm[8]*pma[8][0]*(1.0+flags->sw[18]*flags->sw[20]*glob7s(pma[8], input, flags))*meso_tn1[4]*meso_tn1[4]/(pow((ptm[4]*ptl[3][0]),2.0));
+ } else {
+ meso_tn1[1]=ptm[6]*ptl[0][0];
+ meso_tn1[2]=ptm[2]*ptl[1][0];
+ meso_tn1[3]=ptm[7]*ptl[2][0];
+ meso_tn1[4]=ptm[4]*ptl[3][0];
+ meso_tgn1[1]=ptm[8]*pma[8][0]*meso_tn1[4]*meso_tn1[4]/(pow((ptm[4]*ptl[3][0]),2.0));
+ }
+
+ z0 = zn1[3];
+ t0 = meso_tn1[3];
+ tr12 = 1.0;
+
+ /* N2 variation factor at Zlb */
+ g28=flags->sw[21]*globe7(pd[2], input, flags);
+
+ /* VARIATION OF TURBOPAUSE HEIGHT */
+ zhf=pdl[1][24]*(1.0+flags->sw[5]*pdl[0][24]*sin(dgtr*input->g_lat)*cos(dr*(input->doy-pt[13])));
+ output->t[0]=tinf;
+ xmm = pdm[2][4];
+ z = input->alt;
+
+
+ /**** N2 DENSITY ****/
+
+ /* Diffusive density at Zlb */
+ db28 = pdm[2][0]*exp(g28)*pd[2][0];
+ /* Diffusive density at Alt */
+ output->d[2]=densu(z,db28,tinf,tlb,28.0,alpha[2],&output->t[1],ptm[5],s,mn1,zn1,meso_tn1,meso_tgn1);
+ dd=output->d[2];
+ /* Turbopause */
+ zh28=pdm[2][2]*zhf;
+ zhm28=pdm[2][3]*pdl[1][5];
+ xmd=28.0-xmm;
+ /* Mixed density at Zlb */
+ b28=densu(zh28,db28,tinf,tlb,xmd,(alpha[2]-1.0),&tz,ptm[5],s,mn1, zn1,meso_tn1,meso_tgn1);
+ if ((flags->sw[15])&&(z<=altl[2])) {
+ /* Mixed density at Alt */
+ dm28=densu(z,b28,tinf,tlb,xmm,alpha[2],&tz,ptm[5],s,mn1,zn1,meso_tn1,meso_tgn1);
+ /* Net density at Alt */
+ output->d[2]=dnet(output->d[2],dm28,zhm28,xmm,28.0);
+ }
+
+
+ /**** HE DENSITY ****/
+
+ /* Density variation factor at Zlb */
+ g4 = flags->sw[21]*globe7(pd[0], input, flags);
+ /* Diffusive density at Zlb */
+ db04 = pdm[0][0]*exp(g4)*pd[0][0];
+ /* Diffusive density at Alt */
+ output->d[0]=densu(z,db04,tinf,tlb, 4.,alpha[0],&output->t[1],ptm[5],s,mn1,zn1,meso_tn1,meso_tgn1);
+ dd=output->d[0];
+ if ((flags->sw[15]) && (z<altl[0])) {
+ /* Turbopause */
+ zh04=pdm[0][2];
+ /* Mixed density at Zlb */
+ b04=densu(zh04,db04,tinf,tlb,4.-xmm,alpha[0]-1.,&output->t[1],ptm[5],s,mn1,zn1,meso_tn1,meso_tgn1);
+ /* Mixed density at Alt */
+ dm04=densu(z,b04,tinf,tlb,xmm,0.,&output->t[1],ptm[5],s,mn1,zn1,meso_tn1,meso_tgn1);
+ zhm04=zhm28;
+ /* Net density at Alt */
+ output->d[0]=dnet(output->d[0],dm04,zhm04,xmm,4.);
+ /* Correction to specified mixing ratio at ground */
+ rl=log(b28*pdm[0][1]/b04);
+ zc04=pdm[0][4]*pdl[1][0];
+ hc04=pdm[0][5]*pdl[1][1];
+ /* Net density corrected at Alt */
+ output->d[0]=output->d[0]*ccor(z,rl,hc04,zc04);
+ }
+
+
+ /**** O DENSITY ****/
+
+ /* Density variation factor at Zlb */
+ g16= flags->sw[21]*globe7(pd[1],input,flags);
+ /* Diffusive density at Zlb */
+ db16 = pdm[1][0]*exp(g16)*pd[1][0];
+ /* Diffusive density at Alt */
+ output->d[1]=densu(z,db16,tinf,tlb, 16.,alpha[1],&output->t[1],ptm[5],s,mn1, zn1,meso_tn1,meso_tgn1);
+ dd=output->d[1];
+ if ((flags->sw[15]) && (z<=altl[1])) {
+ /* Turbopause */
+ zh16=pdm[1][2];
+ /* Mixed density at Zlb */
+ b16=densu(zh16,db16,tinf,tlb,16.0-xmm,(alpha[1]-1.0), &output->t[1],ptm[5],s,mn1,zn1,meso_tn1,meso_tgn1);
+ /* Mixed density at Alt */
+ dm16=densu(z,b16,tinf,tlb,xmm,0.,&output->t[1],ptm[5],s,mn1,zn1,meso_tn1,meso_tgn1);
+ zhm16=zhm28;
+ /* Net density at Alt */
+ output->d[1]=dnet(output->d[1],dm16,zhm16,xmm,16.);
+ rl=pdm[1][1]*pdl[1][16]*(1.0+flags->sw[1]*pdl[0][23]*(input->f107A-150.0));
+ hc16=pdm[1][5]*pdl[1][3];
+ zc16=pdm[1][4]*pdl[1][2];
+ hc216=pdm[1][5]*pdl[1][4];
+ output->d[1]=output->d[1]*ccor2(z,rl,hc16,zc16,hc216);
+ /* Chemistry correction */
+ hcc16=pdm[1][7]*pdl[1][13];
+ zcc16=pdm[1][6]*pdl[1][12];
+ rc16=pdm[1][3]*pdl[1][14];
+ /* Net density corrected at Alt */
+ output->d[1]=output->d[1]*ccor(z,rc16,hcc16,zcc16);
+ }
+
+
+ /**** O2 DENSITY ****/
+
+ /* Density variation factor at Zlb */
+ g32= flags->sw[21]*globe7(pd[4], input, flags);
+ /* Diffusive density at Zlb */
+ db32 = pdm[3][0]*exp(g32)*pd[4][0];
+ /* Diffusive density at Alt */
+ output->d[3]=densu(z,db32,tinf,tlb, 32.,alpha[3],&output->t[1],ptm[5],s,mn1, zn1,meso_tn1,meso_tgn1);
+ dd=output->d[3];
+ if (flags->sw[15]) {
+ if (z<=altl[3]) {
+ /* Turbopause */
+ zh32=pdm[3][2];
+ /* Mixed density at Zlb */
+ b32=densu(zh32,db32,tinf,tlb,32.-xmm,alpha[3]-1., &output->t[1],ptm[5],s,mn1,zn1,meso_tn1,meso_tgn1);
+ /* Mixed density at Alt */
+ dm32=densu(z,b32,tinf,tlb,xmm,0.,&output->t[1],ptm[5],s,mn1,zn1,meso_tn1,meso_tgn1);
+ zhm32=zhm28;
+ /* Net density at Alt */
+ output->d[3]=dnet(output->d[3],dm32,zhm32,xmm,32.);
+ /* Correction to specified mixing ratio at ground */
+ rl=log(b28*pdm[3][1]/b32);
+ hc32=pdm[3][5]*pdl[1][7];
+ zc32=pdm[3][4]*pdl[1][6];
+ output->d[3]=output->d[3]*ccor(z,rl,hc32,zc32);
+ }
+ /* Correction for general departure from diffusive equilibrium above Zlb */
+ hcc32=pdm[3][7]*pdl[1][22];
+ hcc232=pdm[3][7]*pdl[0][22];
+ zcc32=pdm[3][6]*pdl[1][21];
+ rc32=pdm[3][3]*pdl[1][23]*(1.+flags->sw[1]*pdl[0][23]*(input->f107A-150.));
+ /* Net density corrected at Alt */
+ output->d[3]=output->d[3]*ccor2(z,rc32,hcc32,zcc32,hcc232);
+ }
+
+
+ /**** AR DENSITY ****/
+
+ /* Density variation factor at Zlb */
+ g40= flags->sw[20]*globe7(pd[5],input,flags);
+ /* Diffusive density at Zlb */
+ db40 = pdm[4][0]*exp(g40)*pd[5][0];
+ /* Diffusive density at Alt */
+ output->d[4]=densu(z,db40,tinf,tlb, 40.,alpha[4],&output->t[1],ptm[5],s,mn1,zn1,meso_tn1,meso_tgn1);
+ dd=output->d[4];
+ if ((flags->sw[15]) && (z<=altl[4])) {
+ /* Turbopause */
+ zh40=pdm[4][2];
+ /* Mixed density at Zlb */
+ b40=densu(zh40,db40,tinf,tlb,40.-xmm,alpha[4]-1.,&output->t[1],ptm[5],s,mn1,zn1,meso_tn1,meso_tgn1);
+ /* Mixed density at Alt */
+ dm40=densu(z,b40,tinf,tlb,xmm,0.,&output->t[1],ptm[5],s,mn1,zn1,meso_tn1,meso_tgn1);
+ zhm40=zhm28;
+ /* Net density at Alt */
+ output->d[4]=dnet(output->d[4],dm40,zhm40,xmm,40.);
+ /* Correction to specified mixing ratio at ground */
+ rl=log(b28*pdm[4][1]/b40);
+ hc40=pdm[4][5]*pdl[1][9];
+ zc40=pdm[4][4]*pdl[1][8];
+ /* Net density corrected at Alt */
+ output->d[4]=output->d[4]*ccor(z,rl,hc40,zc40);
+ }
+
+
+ /**** HYDROGEN DENSITY ****/
+
+ /* Density variation factor at Zlb */
+ g1 = flags->sw[21]*globe7(pd[6], input, flags);
+ /* Diffusive density at Zlb */
+ db01 = pdm[5][0]*exp(g1)*pd[6][0];
+ /* Diffusive density at Alt */
+ output->d[6]=densu(z,db01,tinf,tlb,1.,alpha[6],&output->t[1],ptm[5],s,mn1,zn1,meso_tn1,meso_tgn1);
+ dd=output->d[6];
+ if ((flags->sw[15]) && (z<=altl[6])) {
+ /* Turbopause */
+ zh01=pdm[5][2];
+ /* Mixed density at Zlb */
+ b01=densu(zh01,db01,tinf,tlb,1.-xmm,alpha[6]-1., &output->t[1],ptm[5],s,mn1,zn1,meso_tn1,meso_tgn1);
+ /* Mixed density at Alt */
+ dm01=densu(z,b01,tinf,tlb,xmm,0.,&output->t[1],ptm[5],s,mn1,zn1,meso_tn1,meso_tgn1);
+ zhm01=zhm28;
+ /* Net density at Alt */
+ output->d[6]=dnet(output->d[6],dm01,zhm01,xmm,1.);
+ /* Correction to specified mixing ratio at ground */
+ rl=log(b28*pdm[5][1]*sqrt(pdl[1][17]*pdl[1][17])/b01);
+ hc01=pdm[5][5]*pdl[1][11];
+ zc01=pdm[5][4]*pdl[1][10];
+ output->d[6]=output->d[6]*ccor(z,rl,hc01,zc01);
+ /* Chemistry correction */
+ hcc01=pdm[5][7]*pdl[1][19];
+ zcc01=pdm[5][6]*pdl[1][18];
+ rc01=pdm[5][3]*pdl[1][20];
+ /* Net density corrected at Alt */
+ output->d[6]=output->d[6]*ccor(z,rc01,hcc01,zcc01);
+}
+
+
+ /**** ATOMIC NITROGEN DENSITY ****/
+
+ /* Density variation factor at Zlb */
+ g14 = flags->sw[21]*globe7(pd[7],input,flags);
+ /* Diffusive density at Zlb */
+ db14 = pdm[6][0]*exp(g14)*pd[7][0];
+ /* Diffusive density at Alt */
+ output->d[7]=densu(z,db14,tinf,tlb,14.,alpha[7],&output->t[1],ptm[5],s,mn1,zn1,meso_tn1,meso_tgn1);
+ dd=output->d[7];
+ if ((flags->sw[15]) && (z<=altl[7])) {
+ /* Turbopause */
+ zh14=pdm[6][2];
+ /* Mixed density at Zlb */
+ b14=densu(zh14,db14,tinf,tlb,14.-xmm,alpha[7]-1., &output->t[1],ptm[5],s,mn1,zn1,meso_tn1,meso_tgn1);
+ /* Mixed density at Alt */
+ dm14=densu(z,b14,tinf,tlb,xmm,0.,&output->t[1],ptm[5],s,mn1,zn1,meso_tn1,meso_tgn1);
+ zhm14=zhm28;
+ /* Net density at Alt */
+ output->d[7]=dnet(output->d[7],dm14,zhm14,xmm,14.);
+ /* Correction to specified mixing ratio at ground */
+ rl=log(b28*pdm[6][1]*sqrt(pdl[0][2]*pdl[0][2])/b14);
+ hc14=pdm[6][5]*pdl[0][1];
+ zc14=pdm[6][4]*pdl[0][0];
+ output->d[7]=output->d[7]*ccor(z,rl,hc14,zc14);
+ /* Chemistry correction */
+ hcc14=pdm[6][7]*pdl[0][4];
+ zcc14=pdm[6][6]*pdl[0][3];
+ rc14=pdm[6][3]*pdl[0][5];
+ /* Net density corrected at Alt */
+ output->d[7]=output->d[7]*ccor(z,rc14,hcc14,zcc14);
+ }
+
+
+ /**** Anomalous OXYGEN DENSITY ****/
+
+ g16h = flags->sw[21]*globe7(pd[8],input,flags);
+ db16h = pdm[7][0]*exp(g16h)*pd[8][0];
+ tho = pdm[7][9]*pdl[0][6];
+ dd=densu(z,db16h,tho,tho,16.,alpha[8],&output->t[1],ptm[5],s,mn1, zn1,meso_tn1,meso_tgn1);
+ zsht=pdm[7][5];
+ zmho=pdm[7][4];
+ zsho=scalh(zmho,16.0,tho);
+ output->d[8]=dd*exp(-zsht/zsho*(exp(-(z-zmho)/zsht)-1.));
+
+
+ /* total mass density */
+ output->d[5] = 1.66E-24*(4.0*output->d[0]+16.0*output->d[1]+28.0*output->d[2]+32.0*output->d[3]+40.0*output->d[4]+ output->d[6]+14.0*output->d[7]);
+ db48=1.66E-24*(4.0*db04+16.0*db16+28.0*db28+32.0*db32+40.0*db40+db01+14.0*db14);
+
+
+
+ /* temperature */
+ z = sqrt(input->alt*input->alt);
+ ddum = densu(z,1.0, tinf, tlb, 0.0, 0.0, &output->t[1], ptm[5], s, mn1, zn1, meso_tn1, meso_tgn1);
+ if (flags->sw[0]) {
+ for(i=0;i<9;i++)
+ output->d[i]=output->d[i]*1.0E6;
+ output->d[5]=output->d[5]/1000;
+ }
+}
+
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void MSIS::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: MSIS" << endl;
+ if (from == 1) cout << "Destroyed: MSIS" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 32) { // Turbulence
+ if (frame == 0 && from == 2) {
+ cout << "vTurbulence(X), vTurbulence(Y), vTurbulence(Z), "
+ << "vTurbulenceGrad(X), vTurbulenceGrad(Y), vTurbulenceGrad(Z), "
+ << "vDirection(X), vDirection(Y), vDirection(Z), "
+ << "Magnitude, "
+ << "vTurbPQR(P), vTurbPQR(Q), vTurbPQR(R), " << endl;
+ } else if (from == 2) {
+ cout << vTurbulence << ", " << vTurbulenceGrad << ", " << vDirection << ", " << Magnitude << ", " << vTurbPQR << endl;
+ }
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+
+
+
+} // namespace JSBSim
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGMSIS.h
+ Description: MSIS-00 Atmosphere
+ Author: David Culp
+ Date started: 12/14/03
+
+ ------------- Copyright (C) 2003 David P. Culp (davidculp2@comcast.net) ------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+12/14/03 DPC Created
+01/11/04 DPC Derive from FGAtmosphere
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGMSIS_H
+#define FGMSIS_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <models/FGAtmosphere.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_MSIS "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models the MSIS-00 atmosphere.
+ This is a wrapper for the NRL-MSIS-00 model 2001:
+
+ This C++ format model wraps the NRLMSISE-00 C source code package - release
+ 20020503
+
+ The NRLMSISE-00 model was developed by Mike Picone, Alan Hedin, and
+ Doug Drob. They also wrote a NRLMSISE-00 distribution package in
+ FORTRAN which is available at
+ http://uap-www.nrl.navy.mil/models_web/msis/msis_home.htm
+
+ Dominik Brodowski implemented and maintains this C version. You can
+ reach him at devel@brodo.de. See the file "DOCUMENTATION" for details,
+ and check http://www.brodo.de/english/pub/nrlmsise/index.html for
+ updated releases of this package.
+ @author David Culp
+ @version $Id$
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+STRUCT DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+struct nrlmsise_flags {
+ int switches[24];
+ double sw[24];
+ double swc[24];
+};
+
+struct ap_array {
+ double a[7];
+};
+
+struct nrlmsise_input {
+ int year; /* year, currently ignored */
+ int doy; /* day of year */
+ double sec; /* seconds in day (UT) */
+ double alt; /* altitude in kilometers */
+ double g_lat; /* geodetic latitude */
+ double g_long; /* geodetic longitude */
+ double lst; /* local apparent solar time (hours), see note below */
+ double f107A; /* 81 day average of F10.7 flux (centered on DOY) */
+ double f107; /* daily F10.7 flux for previous day */
+ double ap; /* magnetic index(daily) */
+ struct ap_array *ap_a; /* see above */
+};
+
+struct nrlmsise_output {
+ double d[9]; /* densities */
+ double t[2]; /* temperatures */
+};
+
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class MSIS : public FGAtmosphere
+{
+public:
+
+ /// Constructor
+ MSIS(FGFDMExec*);
+ /// Destructor
+ ~MSIS();
+ /** Runs the MSIS-00 atmosphere model; called by the Executive
+ @return false if no error */
+ bool Run(void);
+
+ bool InitModel(void);
+
+ /// Does nothing. External control is not allowed.
+ void UseExternal(void);
+
+private:
+
+ void Calculate(int day, // day of year (1 to 366)
+ double sec, // seconds in day (0.0 to 86400.0)
+ double alt, // altitude, feet
+ double lat, // geodetic latitude, degrees
+ double lon // geodetic longitude, degrees
+ );
+
+ void Debug(int from);
+
+ nrlmsise_flags flags;
+ nrlmsise_input input;
+ nrlmsise_output output;
+ ap_array aph;
+
+ /* PARMB */
+ double gsurf;
+ double re;
+
+ /* GTS3C */
+ double dd;
+
+ /* DMIX */
+ double dm04, dm16, dm28, dm32, dm40, dm01, dm14;
+
+ /* MESO7 */
+ double meso_tn1[5];
+ double meso_tn2[4];
+ double meso_tn3[3];
+ double meso_tgn1[2];
+ double meso_tgn2[2];
+ double meso_tgn3[2];
+
+ /* LPOLY */
+ double dfa;
+ double plg[4][9];
+ double ctloc, stloc;
+ double c2tloc, s2tloc;
+ double s3tloc, c3tloc;
+ double apdf, apt[4];
+
+ void tselec(struct nrlmsise_flags *flags);
+ void glatf(double lat, double *gv, double *reff);
+ double ccor(double alt, double r, double h1, double zh);
+ double ccor2(double alt, double r, double h1, double zh, double h2);
+ double scalh(double alt, double xm, double temp);
+ double dnet(double dd, double dm, double zhm, double xmm, double xm);
+ void splini(double *xa, double *ya, double *y2a, int n, double x, double *y);
+ void splint(double *xa, double *ya, double *y2a, int n, double x, double *y);
+ void spline(double *x, double *y, int n, double yp1, double ypn, double *y2);
+ double zeta(double zz, double zl);
+ double densm(double alt, double d0, double xm, double *tz, int mn3, double *zn3,
+ double *tn3, double *tgn3, int mn2, double *zn2, double *tn2,
+ double *tgn2);
+ double densu(double alt, double dlb, double tinf, double tlb, double xm,
+ double alpha, double *tz, double zlb, double s2, int mn1,
+ double *zn1, double *tn1, double *tgn1);
+ double g0(double a, double *p);
+ double sumex(double ex);
+ double sg0(double ex, double *p, double *ap);
+ double globe7(double *p, nrlmsise_input *input, nrlmsise_flags *flags);
+ double glob7s(double *p, nrlmsise_input *input, nrlmsise_flags *flags);
+ void gtd7(nrlmsise_input *input, nrlmsise_flags *flags, nrlmsise_output *output);
+ void gtd7d(nrlmsise_input *input, nrlmsise_flags *flags, nrlmsise_output *output);
+ void ghp7(nrlmsise_input *input, nrlmsise_flags *flags, nrlmsise_output *output, double press);
+ void gts7(nrlmsise_input *input, nrlmsise_flags *flags, nrlmsise_output *output);
+
+};
+
+} // namespace JSBSim
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
+
--- /dev/null
+// MSIS-00 Data
+// Adapted for use in JSBSim
+// David Culp, davidculp2@comcast.net
+
+/* -------------------------------------------------------------------- */
+/* --------- N R L M S I S E - 0 0 M O D E L 2 0 0 1 ---------- */
+/* -------------------------------------------------------------------- */
+
+/* This file is part of the NRLMSISE-00 C source code package - release
+ * 20020503
+ *
+ * The NRLMSISE-00 model was developed by Mike Picone, Alan Hedin, and
+ * Doug Drob. They also wrote a NRLMSISE-00 distribution package in
+ * FORTRAN which is available at
+ * http://uap-www.nrl.navy.mil/models_web/msis/msis_home.htm
+ *
+ * Dominik Brodowski implemented and maintains this C version. You can
+ * reach him at devel@brodo.de. See the file "DOCUMENTATION" for details,
+ * and check http://www.brodo.de/english/pub/nrlmsise/index.html for
+ * updated releases of this package.
+ */
+
+
+
+/* ------------------------------------------------------------------- */
+/* ------------------------ BLOCK DATA GTD7BK ------------------------ */
+/* ------------------------------------------------------------------- */
+
+namespace JSBSim {
+
+/* TEMPERATURE */
+double pt[150] = {
+ 9.86573E-01, 1.62228E-02, 1.55270E-02,-1.04323E-01,-3.75801E-03,
+ -1.18538E-03,-1.24043E-01, 4.56820E-03, 8.76018E-03,-1.36235E-01,
+ -3.52427E-02, 8.84181E-03,-5.92127E-03,-8.61650E+00, 0.00000E+00,
+ 1.28492E-02, 0.00000E+00, 1.30096E+02, 1.04567E-02, 1.65686E-03,
+ -5.53887E-06, 2.97810E-03, 0.00000E+00, 5.13122E-03, 8.66784E-02,
+ 1.58727E-01, 0.00000E+00, 0.00000E+00, 0.00000E+00,-7.27026E-06,
+ 0.00000E+00, 6.74494E+00, 4.93933E-03, 2.21656E-03, 2.50802E-03,
+ 0.00000E+00, 0.00000E+00,-2.08841E-02,-1.79873E+00, 1.45103E-03,
+ 2.81769E-04,-1.44703E-03,-5.16394E-05, 8.47001E-02, 1.70147E-01,
+ 5.72562E-03, 5.07493E-05, 4.36148E-03, 1.17863E-04, 4.74364E-03,
+ 6.61278E-03, 4.34292E-05, 1.44373E-03, 2.41470E-05, 2.84426E-03,
+ 8.56560E-04, 2.04028E-03, 0.00000E+00,-3.15994E+03,-2.46423E-03,
+ 1.13843E-03, 4.20512E-04, 0.00000E+00,-9.77214E+01, 6.77794E-03,
+ 5.27499E-03, 1.14936E-03, 0.00000E+00,-6.61311E-03,-1.84255E-02,
+ -1.96259E-02, 2.98618E+04, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 6.44574E+02, 8.84668E-04, 5.05066E-04, 0.00000E+00, 4.02881E+03,
+ -1.89503E-03, 0.00000E+00, 0.00000E+00, 8.21407E-04, 2.06780E-03,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ -1.20410E-02,-3.63963E-03, 9.92070E-05,-1.15284E-04,-6.33059E-05,
+ -6.05545E-01, 8.34218E-03,-9.13036E+01, 3.71042E-04, 0.00000E+00,
+ 4.19000E-04, 2.70928E-03, 3.31507E-03,-4.44508E-03,-4.96334E-03,
+ -1.60449E-03, 3.95119E-03, 2.48924E-03, 5.09815E-04, 4.05302E-03,
+ 2.24076E-03, 0.00000E+00, 6.84256E-03, 4.66354E-04, 0.00000E+00,
+ -3.68328E-04, 0.00000E+00, 0.00000E+00,-1.46870E+02, 0.00000E+00,
+ 0.00000E+00, 1.09501E-03, 4.65156E-04, 5.62583E-04, 3.21596E+00,
+ 6.43168E-04, 3.14860E-03, 3.40738E-03, 1.78481E-03, 9.62532E-04,
+ 5.58171E-04, 3.43731E+00,-2.33195E-01, 5.10289E-04, 0.00000E+00,
+ 0.00000E+00,-9.25347E+04, 0.00000E+00,-1.99639E-03, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00
+};
+
+double pd[9][150] = {
+/* HE DENSITY */ {
+ 1.09979E+00,-4.88060E-02,-1.97501E-01,-9.10280E-02,-6.96558E-03,
+ 2.42136E-02, 3.91333E-01,-7.20068E-03,-3.22718E-02, 1.41508E+00,
+ 1.68194E-01, 1.85282E-02, 1.09384E-01,-7.24282E+00, 0.00000E+00,
+ 2.96377E-01,-4.97210E-02, 1.04114E+02,-8.61108E-02,-7.29177E-04,
+ 1.48998E-06, 1.08629E-03, 0.00000E+00, 0.00000E+00, 8.31090E-02,
+ 1.12818E-01,-5.75005E-02,-1.29919E-02,-1.78849E-02,-2.86343E-06,
+ 0.00000E+00,-1.51187E+02,-6.65902E-03, 0.00000E+00,-2.02069E-03,
+ 0.00000E+00, 0.00000E+00, 4.32264E-02,-2.80444E+01,-3.26789E-03,
+ 2.47461E-03, 0.00000E+00, 0.00000E+00, 9.82100E-02, 1.22714E-01,
+ -3.96450E-02, 0.00000E+00,-2.76489E-03, 0.00000E+00, 1.87723E-03,
+ -8.09813E-03, 4.34428E-05,-7.70932E-03, 0.00000E+00,-2.28894E-03,
+ -5.69070E-03,-5.22193E-03, 6.00692E-03,-7.80434E+03,-3.48336E-03,
+ -6.38362E-03,-1.82190E-03, 0.00000E+00,-7.58976E+01,-2.17875E-02,
+ -1.72524E-02,-9.06287E-03, 0.00000E+00, 2.44725E-02, 8.66040E-02,
+ 1.05712E-01, 3.02543E+04, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ -6.01364E+03,-5.64668E-03,-2.54157E-03, 0.00000E+00, 3.15611E+02,
+ -5.69158E-03, 0.00000E+00, 0.00000E+00,-4.47216E-03,-4.49523E-03,
+ 4.64428E-03, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 4.51236E-02, 2.46520E-02, 6.17794E-03, 0.00000E+00, 0.00000E+00,
+ -3.62944E-01,-4.80022E-02,-7.57230E+01,-1.99656E-03, 0.00000E+00,
+ -5.18780E-03,-1.73990E-02,-9.03485E-03, 7.48465E-03, 1.53267E-02,
+ 1.06296E-02, 1.18655E-02, 2.55569E-03, 1.69020E-03, 3.51936E-02,
+ -1.81242E-02, 0.00000E+00,-1.00529E-01,-5.10574E-03, 0.00000E+00,
+ 2.10228E-03, 0.00000E+00, 0.00000E+00,-1.73255E+02, 5.07833E-01,
+ -2.41408E-01, 8.75414E-03, 2.77527E-03,-8.90353E-05,-5.25148E+00,
+ -5.83899E-03,-2.09122E-02,-9.63530E-03, 9.77164E-03, 4.07051E-03,
+ 2.53555E-04,-5.52875E+00,-3.55993E-01,-2.49231E-03, 0.00000E+00,
+ 0.00000E+00, 2.86026E+01, 0.00000E+00, 3.42722E-04, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00
+}, /* O DENSITY */ {
+ 1.02315E+00,-1.59710E-01,-1.06630E-01,-1.77074E-02,-4.42726E-03,
+ 3.44803E-02, 4.45613E-02,-3.33751E-02,-5.73598E-02, 3.50360E-01,
+ 6.33053E-02, 2.16221E-02, 5.42577E-02,-5.74193E+00, 0.00000E+00,
+ 1.90891E-01,-1.39194E-02, 1.01102E+02, 8.16363E-02, 1.33717E-04,
+ 6.54403E-06, 3.10295E-03, 0.00000E+00, 0.00000E+00, 5.38205E-02,
+ 1.23910E-01,-1.39831E-02, 0.00000E+00, 0.00000E+00,-3.95915E-06,
+ 0.00000E+00,-7.14651E-01,-5.01027E-03, 0.00000E+00,-3.24756E-03,
+ 0.00000E+00, 0.00000E+00, 4.42173E-02,-1.31598E+01,-3.15626E-03,
+ 1.24574E-03,-1.47626E-03,-1.55461E-03, 6.40682E-02, 1.34898E-01,
+ -2.42415E-02, 0.00000E+00, 0.00000E+00, 0.00000E+00, 6.13666E-04,
+ -5.40373E-03, 2.61635E-05,-3.33012E-03, 0.00000E+00,-3.08101E-03,
+ -2.42679E-03,-3.36086E-03, 0.00000E+00,-1.18979E+03,-5.04738E-02,
+ -2.61547E-03,-1.03132E-03, 1.91583E-04,-8.38132E+01,-1.40517E-02,
+ -1.14167E-02,-4.08012E-03, 1.73522E-04,-1.39644E-02,-6.64128E-02,
+ -6.85152E-02,-1.34414E+04, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 6.07916E+02,-4.12220E-03,-2.20996E-03, 0.00000E+00, 1.70277E+03,
+ -4.63015E-03, 0.00000E+00, 0.00000E+00,-2.25360E-03,-2.96204E-03,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 3.92786E-02, 1.31186E-02,-1.78086E-03, 0.00000E+00, 0.00000E+00,
+ -3.90083E-01,-2.84741E-02,-7.78400E+01,-1.02601E-03, 0.00000E+00,
+ -7.26485E-04,-5.42181E-03,-5.59305E-03, 1.22825E-02, 1.23868E-02,
+ 6.68835E-03,-1.03303E-02,-9.51903E-03, 2.70021E-04,-2.57084E-02,
+ -1.32430E-02, 0.00000E+00,-3.81000E-02,-3.16810E-03, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00,-9.05762E-04,-2.14590E-03,-1.17824E-03, 3.66732E+00,
+ -3.79729E-04,-6.13966E-03,-5.09082E-03,-1.96332E-03,-3.08280E-03,
+ -9.75222E-04, 4.03315E+00,-2.52710E-01, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00
+}, /* N2 DENSITY */ {
+ 1.16112E+00, 0.00000E+00, 0.00000E+00, 3.33725E-02, 0.00000E+00,
+ 3.48637E-02,-5.44368E-03, 0.00000E+00,-6.73940E-02, 1.74754E-01,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 1.74712E+02, 0.00000E+00,
+ 1.26733E-01, 0.00000E+00, 1.03154E+02, 5.52075E-02, 0.00000E+00,
+ 0.00000E+00, 8.13525E-04, 0.00000E+00, 0.00000E+00, 8.66784E-02,
+ 1.58727E-01, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00,-2.50482E+01, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-2.48894E-03,
+ 6.16053E-04,-5.79716E-04, 2.95482E-03, 8.47001E-02, 1.70147E-01,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 2.47425E-05, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00
+}, /* TLB */ {
+ 9.44846E-01, 0.00000E+00, 0.00000E+00,-3.08617E-02, 0.00000E+00,
+ -2.44019E-02, 6.48607E-03, 0.00000E+00, 3.08181E-02, 4.59392E-02,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 1.74712E+02, 0.00000E+00,
+ 2.13260E-02, 0.00000E+00,-3.56958E+02, 0.00000E+00, 1.82278E-04,
+ 0.00000E+00, 3.07472E-04, 0.00000E+00, 0.00000E+00, 8.66784E-02,
+ 1.58727E-01, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 3.83054E-03, 0.00000E+00, 0.00000E+00,
+ -1.93065E-03,-1.45090E-03, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00,-1.23493E-03, 1.36736E-03, 8.47001E-02, 1.70147E-01,
+ 3.71469E-03, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 5.10250E-03, 2.47425E-05, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 3.68756E-03, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00
+}, /* O2 DENSITY */ {
+ 1.35580E+00, 1.44816E-01, 0.00000E+00, 6.07767E-02, 0.00000E+00,
+ 2.94777E-02, 7.46900E-02, 0.00000E+00,-9.23822E-02, 8.57342E-02,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 2.38636E+01, 0.00000E+00,
+ 7.71653E-02, 0.00000E+00, 8.18751E+01, 1.87736E-02, 0.00000E+00,
+ 0.00000E+00, 1.49667E-02, 0.00000E+00, 0.00000E+00, 8.66784E-02,
+ 1.58727E-01, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00,-3.67874E+02, 5.48158E-03, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 8.47001E-02, 1.70147E-01,
+ 1.22631E-02, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 8.17187E-03, 3.71617E-05, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-2.10826E-03,
+ -3.13640E-03, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ -7.35742E-02,-5.00266E-02, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 1.94965E-02, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00
+}, /* AR DENSITY */ {
+ 1.04761E+00, 2.00165E-01, 2.37697E-01, 3.68552E-02, 0.00000E+00,
+ 3.57202E-02,-2.14075E-01, 0.00000E+00,-1.08018E-01,-3.73981E-01,
+ 0.00000E+00, 3.10022E-02,-1.16305E-03,-2.07596E+01, 0.00000E+00,
+ 8.64502E-02, 0.00000E+00, 9.74908E+01, 5.16707E-02, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 8.66784E-02,
+ 1.58727E-01, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 3.46193E+02, 1.34297E-02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-3.48509E-03,
+ -1.54689E-04, 0.00000E+00, 0.00000E+00, 8.47001E-02, 1.70147E-01,
+ 1.47753E-02, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 1.89320E-02, 3.68181E-05, 1.32570E-02, 0.00000E+00, 0.00000E+00,
+ 3.59719E-03, 7.44328E-03,-1.00023E-03,-6.50528E+03, 0.00000E+00,
+ 1.03485E-02,-1.00983E-03,-4.06916E-03,-6.60864E+01,-1.71533E-02,
+ 1.10605E-02, 1.20300E-02,-5.20034E-03, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ -2.62769E+03, 7.13755E-03, 4.17999E-03, 0.00000E+00, 1.25910E+04,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00,-2.23595E-03, 4.60217E-03,
+ 5.71794E-03, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ -3.18353E-02,-2.35526E-02,-1.36189E-02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 2.03522E-02,-6.67837E+01,-1.09724E-03, 0.00000E+00,
+ -1.38821E-02, 1.60468E-02, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 1.51574E-02,
+ -5.44470E-04, 0.00000E+00, 7.28224E-02, 6.59413E-02, 0.00000E+00,
+ -5.15692E-03, 0.00000E+00, 0.00000E+00,-3.70367E+03, 0.00000E+00,
+ 0.00000E+00, 1.36131E-02, 5.38153E-03, 0.00000E+00, 4.76285E+00,
+ -1.75677E-02, 2.26301E-02, 0.00000E+00, 1.76631E-02, 4.77162E-03,
+ 0.00000E+00, 5.39354E+00, 0.00000E+00,-7.51710E-03, 0.00000E+00,
+ 0.00000E+00,-8.82736E+01, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00
+}, /* H DENSITY */ {
+ 1.26376E+00,-2.14304E-01,-1.49984E-01, 2.30404E-01, 2.98237E-02,
+ 2.68673E-02, 2.96228E-01, 2.21900E-02,-2.07655E-02, 4.52506E-01,
+ 1.20105E-01, 3.24420E-02, 4.24816E-02,-9.14313E+00, 0.00000E+00,
+ 2.47178E-02,-2.88229E-02, 8.12805E+01, 5.10380E-02,-5.80611E-03,
+ 2.51236E-05,-1.24083E-02, 0.00000E+00, 0.00000E+00, 8.66784E-02,
+ 1.58727E-01,-3.48190E-02, 0.00000E+00, 0.00000E+00, 2.89885E-05,
+ 0.00000E+00, 1.53595E+02,-1.68604E-02, 0.00000E+00, 1.01015E-02,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 2.84552E-04,
+ -1.22181E-03, 0.00000E+00, 0.00000E+00, 8.47001E-02, 1.70147E-01,
+ -1.04927E-02, 0.00000E+00, 0.00000E+00, 0.00000E+00,-5.91313E-03,
+ -2.30501E-02, 3.14758E-05, 0.00000E+00, 0.00000E+00, 1.26956E-02,
+ 8.35489E-03, 3.10513E-04, 0.00000E+00, 3.42119E+03,-2.45017E-03,
+ -4.27154E-04, 5.45152E-04, 1.89896E-03, 2.89121E+01,-6.49973E-03,
+ -1.93855E-02,-1.48492E-02, 0.00000E+00,-5.10576E-02, 7.87306E-02,
+ 9.51981E-02,-1.49422E+04, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 2.65503E+02, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 6.37110E-03, 3.24789E-04,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 6.14274E-02, 1.00376E-02,-8.41083E-04, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00,-1.27099E-02, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ -3.94077E-03,-1.28601E-02,-7.97616E-03, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00,-6.71465E-03,-1.69799E-03, 1.93772E-03, 3.81140E+00,
+ -7.79290E-03,-1.82589E-02,-1.25860E-02,-1.04311E-02,-3.02465E-03,
+ 2.43063E-03, 3.63237E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00
+}, /* N DENSITY */ {
+ 7.09557E+01,-3.26740E-01, 0.00000E+00,-5.16829E-01,-1.71664E-03,
+ 9.09310E-02,-6.71500E-01,-1.47771E-01,-9.27471E-02,-2.30862E-01,
+ -1.56410E-01, 1.34455E-02,-1.19717E-01, 2.52151E+00, 0.00000E+00,
+ -2.41582E-01, 5.92939E-02, 4.39756E+00, 9.15280E-02, 4.41292E-03,
+ 0.00000E+00, 8.66807E-03, 0.00000E+00, 0.00000E+00, 8.66784E-02,
+ 1.58727E-01, 9.74701E-02, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 6.70217E+01,-1.31660E-03, 0.00000E+00,-1.65317E-02,
+ 0.00000E+00, 0.00000E+00, 8.50247E-02, 2.77428E+01, 4.98658E-03,
+ 6.15115E-03, 9.50156E-03,-2.12723E-02, 8.47001E-02, 1.70147E-01,
+ -2.38645E-02, 0.00000E+00, 0.00000E+00, 0.00000E+00, 1.37380E-03,
+ -8.41918E-03, 2.80145E-05, 7.12383E-03, 0.00000E+00,-1.66209E-02,
+ 1.03533E-04,-1.68898E-02, 0.00000E+00, 3.64526E+03, 0.00000E+00,
+ 6.54077E-03, 3.69130E-04, 9.94419E-04, 8.42803E+01,-1.16124E-02,
+ -7.74414E-03,-1.68844E-03, 1.42809E-03,-1.92955E-03, 1.17225E-01,
+ -2.41512E-02, 1.50521E+04, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 1.60261E+03, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00,-3.54403E-04,-1.87270E-02,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 2.76439E-02, 6.43207E-03,-3.54300E-02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00,-2.80221E-02, 8.11228E+01,-6.75255E-04, 0.00000E+00,
+ -1.05162E-02,-3.48292E-03,-6.97321E-03, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00,-1.45546E-03,-1.31970E-02,-3.57751E-03,-1.09021E+00,
+ -1.50181E-02,-7.12841E-03,-6.64590E-03,-3.52610E-03,-1.87773E-02,
+ -2.22432E-03,-3.93895E-01, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00
+}, /* HOT O DENSITY */ {
+ 6.04050E-02, 1.57034E+00, 2.99387E-02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-1.51018E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00,-8.61650E+00, 1.26454E-02,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 5.50878E-03, 0.00000E+00, 0.00000E+00, 8.66784E-02,
+ 1.58727E-01, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 6.23881E-02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 8.47001E-02, 1.70147E-01,
+ -9.45934E-02, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00
+}};
+/* S PARAM */
+double ps[150] = {
+ 9.56827E-01, 6.20637E-02, 3.18433E-02, 0.00000E+00, 0.00000E+00,
+ 3.94900E-02, 0.00000E+00, 0.00000E+00,-9.24882E-03,-7.94023E-03,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 1.74712E+02, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 2.74677E-03, 0.00000E+00, 1.54951E-02, 8.66784E-02,
+ 1.58727E-01, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00,-6.99007E-04, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 1.24362E-02,-5.28756E-03, 8.47001E-02, 1.70147E-01,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 2.47425E-05, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00
+};
+
+/* TURBO */
+double pdl[2][25] = {
+ { 1.09930E+00, 3.90631E+00, 3.07165E+00, 9.86161E-01, 1.63536E+01,
+ 4.63830E+00, 1.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 1.28840E+00, 3.10302E-02, 1.18339E-01 },
+ { 1.00000E+00, 7.00000E-01, 1.15020E+00, 3.44689E+00, 1.28840E+00,
+ 1.00000E+00, 1.08738E+00, 1.22947E+00, 1.10016E+00, 7.34129E-01,
+ 1.15241E+00, 2.22784E+00, 7.95046E-01, 4.01612E+00, 4.47749E+00,
+ 1.23435E+02,-7.60535E-02, 1.68986E-06, 7.44294E-01, 1.03604E+00,
+ 1.72783E+02, 1.15020E+00, 3.44689E+00,-7.46230E-01, 9.49154E-01 }
+};
+/* LOWER BOUNDARY */
+double ptm[50] = {
+ 1.04130E+03, 3.86000E+02, 1.95000E+02, 1.66728E+01, 2.13000E+02,
+ 1.20000E+02, 2.40000E+02, 1.87000E+02,-2.00000E+00, 0.00000E+00
+};
+double pdm[8][10] = {
+{ 2.45600E+07, 6.71072E-06, 1.00000E+02, 0.00000E+00, 1.10000E+02,
+ 1.00000E+01, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00 },\
+{ 8.59400E+10, 1.00000E+00, 1.05000E+02,-8.00000E+00, 1.10000E+02,
+ 1.00000E+01, 9.00000E+01, 2.00000E+00, 0.00000E+00, 0.00000E+00 },\
+{ 2.81000E+11, 0.00000E+00, 1.05000E+02, 2.80000E+01, 2.89500E+01,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00 },
+{ 3.30000E+10, 2.68270E-01, 1.05000E+02, 1.00000E+00, 1.10000E+02,
+ 1.00000E+01, 1.10000E+02,-1.00000E+01, 0.00000E+00, 0.00000E+00 },
+{ 1.33000E+09, 1.19615E-02, 1.05000E+02, 0.00000E+00, 1.10000E+02,
+ 1.00000E+01, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00 },
+{ 1.76100E+05, 1.00000E+00, 9.50000E+01,-8.00000E+00, 1.10000E+02,
+ 1.00000E+01, 9.00000E+01, 2.00000E+00, 0.00000E+00, 0.00000E+00, },
+{ 1.00000E+07, 1.00000E+00, 1.05000E+02,-8.00000E+00, 1.10000E+02,
+ 1.00000E+01, 9.00000E+01, 2.00000E+00, 0.00000E+00, 0.00000E+00 },
+{ 1.00000E+06, 1.00000E+00, 1.05000E+02,-8.00000E+00, 5.50000E+02,
+ 7.60000E+01, 9.00000E+01, 2.00000E+00, 0.00000E+00, 4.00000E+03 }};
+
+
+double ptl[4][100] = {
+/* TN1(2) */ {
+ 1.00858E+00, 4.56011E-02,-2.22972E-02,-5.44388E-02, 5.23136E-04,
+ -1.88849E-02, 5.23707E-02,-9.43646E-03, 6.31707E-03,-7.80460E-02,
+ -4.88430E-02, 0.00000E+00, 0.00000E+00,-7.60250E+00, 0.00000E+00,
+ -1.44635E-02,-1.76843E-02,-1.21517E+02, 2.85647E-02, 0.00000E+00,
+ 0.00000E+00, 6.31792E-04, 0.00000E+00, 5.77197E-03, 8.66784E-02,
+ 1.58727E-01, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00,-8.90272E+03, 3.30611E-03, 3.02172E-03, 0.00000E+00,
+ -2.13673E-03,-3.20910E-04, 0.00000E+00, 0.00000E+00, 2.76034E-03,
+ 2.82487E-03,-2.97592E-04,-4.21534E-03, 8.47001E-02, 1.70147E-01,
+ 8.96456E-03, 0.00000E+00,-1.08596E-02, 0.00000E+00, 0.00000E+00,
+ 5.57917E-03, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 9.65405E-03, 0.00000E+00, 0.00000E+00, 2.00000E+00
+}, /* TN1(3) */ {
+ 9.39664E-01, 8.56514E-02,-6.79989E-03, 2.65929E-02,-4.74283E-03,
+ 1.21855E-02,-2.14905E-02, 6.49651E-03,-2.05477E-02,-4.24952E-02,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 1.19148E+01, 0.00000E+00,
+ 1.18777E-02,-7.28230E-02,-8.15965E+01, 1.73887E-02, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00,-1.44691E-02, 2.80259E-04, 8.66784E-02,
+ 1.58727E-01, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 2.16584E+02, 3.18713E-03, 7.37479E-03, 0.00000E+00,
+ -2.55018E-03,-3.92806E-03, 0.00000E+00, 0.00000E+00,-2.89757E-03,
+ -1.33549E-03, 1.02661E-03, 3.53775E-04, 8.47001E-02, 1.70147E-01,
+ -9.17497E-03, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 3.56082E-03, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00,-1.00902E-02, 0.00000E+00, 0.00000E+00, 2.00000E+00
+}, /* TN1(4) */ {
+ 9.85982E-01,-4.55435E-02, 1.21106E-02, 2.04127E-02,-2.40836E-03,
+ 1.11383E-02,-4.51926E-02, 1.35074E-02,-6.54139E-03, 1.15275E-01,
+ 1.28247E-01, 0.00000E+00, 0.00000E+00,-5.30705E+00, 0.00000E+00,
+ -3.79332E-02,-6.24741E-02, 7.71062E-01, 2.96315E-02, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 6.81051E-03,-4.34767E-03, 8.66784E-02,
+ 1.58727E-01, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 1.07003E+01,-2.76907E-03, 4.32474E-04, 0.00000E+00,
+ 1.31497E-03,-6.47517E-04, 0.00000E+00,-2.20621E+01,-1.10804E-03,
+ -8.09338E-04, 4.18184E-04, 4.29650E-03, 8.47001E-02, 1.70147E-01,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ -4.04337E-03, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-9.52550E-04,
+ 8.56253E-04, 4.33114E-04, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 1.21223E-03,
+ 2.38694E-04, 9.15245E-04, 1.28385E-03, 8.67668E-04,-5.61425E-06,
+ 1.04445E+00, 3.41112E+01, 0.00000E+00,-8.40704E-01,-2.39639E+02,
+ 7.06668E-01,-2.05873E+01,-3.63696E-01, 2.39245E+01, 0.00000E+00,
+ -1.06657E-03,-7.67292E-04, 1.54534E-04, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 2.00000E+00
+}, /* TN1(5) TN2(1) */ {
+ 1.00320E+00, 3.83501E-02,-2.38983E-03, 2.83950E-03, 4.20956E-03,
+ 5.86619E-04, 2.19054E-02,-1.00946E-02,-3.50259E-03, 4.17392E-02,
+ -8.44404E-03, 0.00000E+00, 0.00000E+00, 4.96949E+00, 0.00000E+00,
+ -7.06478E-03,-1.46494E-02, 3.13258E+01,-1.86493E-03, 0.00000E+00,
+ -1.67499E-02, 0.00000E+00, 0.00000E+00, 5.12686E-04, 8.66784E-02,
+ 1.58727E-01,-4.64167E-03, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 4.37353E-03,-1.99069E+02, 0.00000E+00,-5.34884E-03, 0.00000E+00,
+ 1.62458E-03, 2.93016E-03, 2.67926E-03, 5.90449E+02, 0.00000E+00,
+ 0.00000E+00,-1.17266E-03,-3.58890E-04, 8.47001E-02, 1.70147E-01,
+ 0.00000E+00, 0.00000E+00, 1.38673E-02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 1.60571E-03,
+ 6.28078E-04, 5.05469E-05, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-1.57829E-03,
+ -4.00855E-04, 5.04077E-05,-1.39001E-03,-2.33406E-03,-4.81197E-04,
+ 1.46758E+00, 6.20332E+00, 0.00000E+00, 3.66476E-01,-6.19760E+01,
+ 3.09198E-01,-1.98999E+01, 0.00000E+00,-3.29933E+02, 0.00000E+00,
+ -1.10080E-03,-9.39310E-05, 1.39638E-04, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 2.00000E+00
+} };
+
+double pma[10][100] = {
+/* TN2(2) */ {
+ 9.81637E-01,-1.41317E-03, 3.87323E-02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-3.58707E-02,
+ -8.63658E-03, 0.00000E+00, 0.00000E+00,-2.02226E+00, 0.00000E+00,
+ -8.69424E-03,-1.91397E-02, 8.76779E+01, 4.52188E-03, 0.00000E+00,
+ 2.23760E-02, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00,-7.07572E-03, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ -4.11210E-03, 3.50060E+01, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00,-8.36657E-03, 1.61347E+01, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00,-1.45130E-02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 1.24152E-03,
+ 6.43365E-04, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 1.33255E-03,
+ 2.42657E-03, 1.60666E-03,-1.85728E-03,-1.46874E-03,-4.79163E-06,
+ 1.22464E+00, 3.53510E+01, 0.00000E+00, 4.49223E-01,-4.77466E+01,
+ 4.70681E-01, 8.41861E+00,-2.88198E-01, 1.67854E+02, 0.00000E+00,
+ 7.11493E-04, 6.05601E-04, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 2.00000E+00
+}, /* TN2(3) */ {
+ 1.00422E+00,-7.11212E-03, 5.24480E-03, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-5.28914E-02,
+ -2.41301E-02, 0.00000E+00, 0.00000E+00,-2.12219E+01,-1.03830E-02,
+ -3.28077E-03, 1.65727E-02, 1.68564E+00,-6.68154E-03, 0.00000E+00,
+ 1.45155E-02, 0.00000E+00, 8.42365E-03, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00,-4.34645E-03, 0.00000E+00, 0.00000E+00, 2.16780E-02,
+ 0.00000E+00,-1.38459E+02, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 7.04573E-03,-4.73204E+01, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 1.08767E-02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-8.08279E-03,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 5.21769E-04,
+ -2.27387E-04, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 3.26769E-03,
+ 3.16901E-03, 4.60316E-04,-1.01431E-04, 1.02131E-03, 9.96601E-04,
+ 1.25707E+00, 2.50114E+01, 0.00000E+00, 4.24472E-01,-2.77655E+01,
+ 3.44625E-01, 2.75412E+01, 0.00000E+00, 7.94251E+02, 0.00000E+00,
+ 2.45835E-03, 1.38871E-03, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 2.00000E+00
+}, /* TN2(4) TN3(1) */ {
+ 1.01890E+00,-2.46603E-02, 1.00078E-02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-6.70977E-02,
+ -4.02286E-02, 0.00000E+00, 0.00000E+00,-2.29466E+01,-7.47019E-03,
+ 2.26580E-03, 2.63931E-02, 3.72625E+01,-6.39041E-03, 0.00000E+00,
+ 9.58383E-03, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00,-1.85291E-03, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 1.39717E+02, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 9.19771E-03,-3.69121E+02, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00,-1.57067E-02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-7.07265E-03,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-2.92953E-03,
+ -2.77739E-03,-4.40092E-04, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 2.47280E-03,
+ 2.95035E-04,-1.81246E-03, 2.81945E-03, 4.27296E-03, 9.78863E-04,
+ 1.40545E+00,-6.19173E+00, 0.00000E+00, 0.00000E+00,-7.93632E+01,
+ 4.44643E-01,-4.03085E+02, 0.00000E+00, 1.15603E+01, 0.00000E+00,
+ 2.25068E-03, 8.48557E-04,-2.98493E-04, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 2.00000E+00
+}, /* TN3(2) */ {
+ 9.75801E-01, 3.80680E-02,-3.05198E-02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 3.85575E-02,
+ 5.04057E-02, 0.00000E+00, 0.00000E+00,-1.76046E+02, 1.44594E-02,
+ -1.48297E-03,-3.68560E-03, 3.02185E+01,-3.23338E-03, 0.00000E+00,
+ 1.53569E-02, 0.00000E+00,-1.15558E-02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 4.89620E-03, 0.00000E+00, 0.00000E+00,-1.00616E-02,
+ -8.21324E-03,-1.57757E+02, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 6.63564E-03, 4.58410E+01, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00,-2.51280E-02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 9.91215E-03,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-8.73148E-04,
+ -1.29648E-03,-7.32026E-05, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-4.68110E-03,
+ -4.66003E-03,-1.31567E-03,-7.39390E-04, 6.32499E-04,-4.65588E-04,
+ -1.29785E+00,-1.57139E+02, 0.00000E+00, 2.58350E-01,-3.69453E+01,
+ 4.10672E-01, 9.78196E+00,-1.52064E-01,-3.85084E+03, 0.00000E+00,
+ -8.52706E-04,-1.40945E-03,-7.26786E-04, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 2.00000E+00
+}, /* TN3(3) */ {
+ 9.60722E-01, 7.03757E-02,-3.00266E-02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 2.22671E-02,
+ 4.10423E-02, 0.00000E+00, 0.00000E+00,-1.63070E+02, 1.06073E-02,
+ 5.40747E-04, 7.79481E-03, 1.44908E+02, 1.51484E-04, 0.00000E+00,
+ 1.97547E-02, 0.00000E+00,-1.41844E-02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 5.77884E-03, 0.00000E+00, 0.00000E+00, 9.74319E-03,
+ 0.00000E+00,-2.88015E+03, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00,-4.44902E-03,-2.92760E+01, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 2.34419E-02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 5.36685E-03,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-4.65325E-04,
+ -5.50628E-04, 3.31465E-04, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-2.06179E-03,
+ -3.08575E-03,-7.93589E-04,-1.08629E-04, 5.95511E-04,-9.05050E-04,
+ 1.18997E+00, 4.15924E+01, 0.00000E+00,-4.72064E-01,-9.47150E+02,
+ 3.98723E-01, 1.98304E+01, 0.00000E+00, 3.73219E+03, 0.00000E+00,
+ -1.50040E-03,-1.14933E-03,-1.56769E-04, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 2.00000E+00
+}, /* TN3(4) */ {
+ 1.03123E+00,-7.05124E-02, 8.71615E-03, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-3.82621E-02,
+ -9.80975E-03, 0.00000E+00, 0.00000E+00, 2.89286E+01, 9.57341E-03,
+ 0.00000E+00, 0.00000E+00, 8.66153E+01, 7.91938E-04, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 4.68917E-03, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 7.86638E-03, 0.00000E+00, 0.00000E+00, 9.90827E-03,
+ 0.00000E+00, 6.55573E+01, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00,-4.00200E+01, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 7.07457E-03, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 5.72268E-03,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-2.04970E-04,
+ 1.21560E-03,-8.05579E-06, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-2.49941E-03,
+ -4.57256E-04,-1.59311E-04, 2.96481E-04,-1.77318E-03,-6.37918E-04,
+ 1.02395E+00, 1.28172E+01, 0.00000E+00, 1.49903E-01,-2.63818E+01,
+ 0.00000E+00, 4.70628E+01,-2.22139E-01, 4.82292E-02, 0.00000E+00,
+ -8.67075E-04,-5.86479E-04, 5.32462E-04, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 2.00000E+00
+}, /* TN3(5) SURFACE TEMP TSL */ {
+ 1.00828E+00,-9.10404E-02,-2.26549E-02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-2.32420E-02,
+ -9.08925E-03, 0.00000E+00, 0.00000E+00, 3.36105E+01, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00,-1.24957E+01,-5.87939E-03, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 2.79765E+01, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 2.01237E+03, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00,-1.75553E-02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 3.29699E-03,
+ 1.26659E-03, 2.68402E-04, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 1.17894E-03,
+ 1.48746E-03, 1.06478E-04, 1.34743E-04,-2.20939E-03,-6.23523E-04,
+ 6.36539E-01, 1.13621E+01, 0.00000E+00,-3.93777E-01, 2.38687E+03,
+ 0.00000E+00, 6.61865E+02,-1.21434E-01, 9.27608E+00, 0.00000E+00,
+ 1.68478E-04, 1.24892E-03, 1.71345E-03, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 2.00000E+00
+}, /* TGN3(2) SURFACE GRAD TSLG */ {
+ 1.57293E+00,-6.78400E-01, 6.47500E-01, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-7.62974E-02,
+ -3.60423E-01, 0.00000E+00, 0.00000E+00, 1.28358E+02, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 4.68038E+01, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00,-1.67898E-01, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 2.90994E+04, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 3.15706E+01, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 2.00000E+00
+}, /* TGN2(1) TGN1(2) */ {
+ 8.60028E-01, 3.77052E-01, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-1.17570E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 7.77757E-03, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 1.01024E+02, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 6.54251E+02, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,-1.56959E-02,
+ 1.91001E-02, 3.15971E-02, 1.00982E-02,-6.71565E-03, 2.57693E-03,
+ 1.38692E+00, 2.82132E-01, 0.00000E+00, 0.00000E+00, 3.81511E+02,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 2.00000E+00
+}, /* TGN3(1) TGN2(2) */ {
+ 1.06029E+00,-5.25231E-02, 3.73034E-01, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 3.31072E-02,
+ -3.88409E-01, 0.00000E+00, 0.00000E+00,-1.65295E+02,-2.13801E-01,
+ -4.38916E-02,-3.22716E-01,-8.82393E+01, 1.18458E-01, 0.00000E+00,
+ -4.35863E-01, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00,-1.19782E-01, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 2.62229E+01, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00,-5.37443E+01, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00,-4.55788E-01, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 3.84009E-02,
+ 3.96733E-02, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 5.05494E-02,
+ 7.39617E-02, 1.92200E-02,-8.46151E-03,-1.34244E-02, 1.96338E-02,
+ 1.50421E+00, 1.88368E+01, 0.00000E+00, 0.00000E+00,-5.13114E+01,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 5.11923E-02, 3.61225E-02, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 2.00000E+00
+} };
+
+/* SEMIANNUAL MULT SAM */
+double sam[100] = {
+ 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00,
+ 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00,
+ 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00,
+ 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00,
+ 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00,
+ 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00,
+ 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00,
+ 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00,
+ 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00,
+ 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00, 1.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00,
+ 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00, 0.00000E+00
+};
+
+
+/* MIDDLE ATMOSPHERE AVERAGES */
+double pavgm[10] = {
+ 2.61000E+02, 2.64000E+02, 2.29000E+02, 2.17000E+02, 2.17000E+02,
+ 2.23000E+02, 2.86760E+02,-2.93940E+00, 2.50000E+00, 0.00000E+00 };
+
+} // namespace
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGMars.cpp
+ Author: Jon Berndt
+ Date started: 1/4/04
+ Purpose: Models the Martian atmosphere very simply
+ Called by: FGFDMExec
+
+ ------------- Copyright (C) 2004 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+Models the Martian atmosphere.
+
+HISTORY
+--------------------------------------------------------------------------------
+1/04/2004 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+COMMENTS, REFERENCES, and NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGMars.h"
+#include "FGState.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_MARS;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+FGMars::FGMars(FGFDMExec* fdmex) : FGAtmosphere(fdmex)
+{
+ Name = "FGMars";
+ Reng = 53.5 * 44.01;
+
+/*
+ lastIndex = 0;
+ h = 0.0;
+ psiw = 0.0;
+
+ MagnitudedAccelDt = MagnitudeAccel = Magnitude = 0.0;
+// turbType = ttNone;
+ turbType = ttStandard;
+// turbType = ttBerndt;
+ TurbGain = 0.0;
+ TurbRate = 1.0;
+*/
+
+ bind();
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+/*
+FGMars::~FGMars()
+{
+ unbind();
+ Debug(1);
+}
+*/
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGMars::InitModel(void)
+{
+ FGModel::InitModel();
+
+ Calculate(h);
+ SLtemperature = intTemperature;
+ SLpressure = intPressure;
+ SLdensity = intDensity;
+ SLsoundspeed = sqrt(SHRatio*Reng*intTemperature);
+ rSLtemperature = 1.0/intTemperature;
+ rSLpressure = 1.0/intPressure;
+ rSLdensity = 1.0/intDensity;
+ rSLsoundspeed = 1.0/SLsoundspeed;
+ temperature = &intTemperature;
+ pressure = &intPressure;
+ density = &intDensity;
+
+ useExternal=false;
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGMars::Run(void)
+{
+ if (FGModel::Run()) return true;
+ if (FDMExec->Holding()) return false;
+
+ //do temp, pressure, and density first
+ if (!useExternal) {
+ h = Propagate->Geth();
+ Calculate(h);
+ }
+
+ if (turbType != ttNone) {
+ Turbulence();
+ vWindNED += vTurbulence;
+ }
+
+ if (vWindNED(1) != 0.0) psiw = atan2( vWindNED(2), vWindNED(1) );
+
+ if (psiw < 0) psiw += 2*M_PI;
+
+ soundspeed = sqrt(SHRatio*Reng*(*temperature));
+
+ Debug(2);
+
+ return false;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGMars::Calculate(double altitude)
+{
+ //Calculate reftemp, refpress, and density
+
+ // LIMIT the temperatures so they do not descend below absolute zero.
+
+ if (altitude < 22960.0) {
+ intTemperature = -25.68 - 0.000548*altitude; // Deg Fahrenheit
+ } else {
+ intTemperature = -10.34 - 0.001217*altitude; // Deg Fahrenheit
+ }
+ intPressure = 14.62*exp(-0.00003*altitude); // psf - 14.62 psf =~ 7 millibars
+ intDensity = intPressure/(Reng*intTemperature); // slugs/ft^3 (needs deg R. as input
+
+ //cout << "Atmosphere: h=" << altitude << " rho= " << intDensity << endl;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+// square a value, but preserve the original sign
+
+static inline double
+square_signed (double value)
+{
+ if (value < 0)
+ return value * value * -1;
+ else
+ return value * value;
+}
+
+void FGMars::Turbulence(void)
+{
+ switch (turbType) {
+ case ttStandard: {
+ vDirectiondAccelDt(eX) = 1 - 2.0*(double(rand())/double(RAND_MAX));
+ vDirectiondAccelDt(eY) = 1 - 2.0*(double(rand())/double(RAND_MAX));
+ vDirectiondAccelDt(eZ) = 1 - 2.0*(double(rand())/double(RAND_MAX));
+
+ MagnitudedAccelDt = 1 - 2.0*(double(rand())/double(RAND_MAX)) - Magnitude;
+ // Scale the magnitude so that it moves
+ // away from the peaks
+ MagnitudedAccelDt = ((MagnitudedAccelDt - Magnitude) /
+ (1 + fabs(Magnitude)));
+ MagnitudeAccel += MagnitudedAccelDt*rate*TurbRate*State->Getdt();
+ Magnitude += MagnitudeAccel*rate*State->Getdt();
+
+ vDirectiondAccelDt.Normalize();
+
+ // deemphasise non-vertical forces
+ vDirectiondAccelDt(eX) = square_signed(vDirectiondAccelDt(eX));
+ vDirectiondAccelDt(eY) = square_signed(vDirectiondAccelDt(eY));
+
+ vDirectionAccel += vDirectiondAccelDt*rate*TurbRate*State->Getdt();
+ vDirectionAccel.Normalize();
+ vDirection += vDirectionAccel*rate*State->Getdt();
+
+ vDirection.Normalize();
+
+ // Diminish turbulence within three wingspans
+ // of the ground
+ vTurbulence = TurbGain * Magnitude * vDirection;
+ double HOverBMAC = Auxiliary->GetHOverBMAC();
+ if (HOverBMAC < 3.0)
+ vTurbulence *= (HOverBMAC / 3.0) * (HOverBMAC / 3.0);
+
+ vTurbulenceGrad = TurbGain*MagnitudeAccel * vDirection;
+
+ vBodyTurbGrad = Propagate->GetTl2b()*vTurbulenceGrad;
+ vTurbPQR(eP) = vBodyTurbGrad(eY)/Aircraft->GetWingSpan();
+// if (Aircraft->GetHTailArm() != 0.0)
+// vTurbPQR(eQ) = vBodyTurbGrad(eZ)/Aircraft->GetHTailArm();
+// else
+// vTurbPQR(eQ) = vBodyTurbGrad(eZ)/10.0;
+
+ if (Aircraft->GetVTailArm())
+ vTurbPQR(eR) = vBodyTurbGrad(eX)/Aircraft->GetVTailArm();
+ else
+ vTurbPQR(eR) = vBodyTurbGrad(eX)/10.0;
+
+ // Clear the horizontal forces
+ // actually felt by the plane, now
+ // that we've used them to calculate
+ // moments.
+ vTurbulence(eX) = 0.0;
+ vTurbulence(eY) = 0.0;
+
+ break;
+ }
+ case ttBerndt: {
+ vDirectiondAccelDt(eX) = 1 - 2.0*(double(rand())/double(RAND_MAX));
+ vDirectiondAccelDt(eY) = 1 - 2.0*(double(rand())/double(RAND_MAX));
+ vDirectiondAccelDt(eZ) = 1 - 2.0*(double(rand())/double(RAND_MAX));
+
+
+ MagnitudedAccelDt = 1 - 2.0*(double(rand())/double(RAND_MAX)) - Magnitude;
+ MagnitudeAccel += MagnitudedAccelDt*rate*State->Getdt();
+ Magnitude += MagnitudeAccel*rate*State->Getdt();
+
+ vDirectiondAccelDt.Normalize();
+ vDirectionAccel += vDirectiondAccelDt*rate*State->Getdt();
+ vDirectionAccel.Normalize();
+ vDirection += vDirectionAccel*rate*State->Getdt();
+
+ // Diminish z-vector within two wingspans
+ // of the ground
+ double HOverBMAC = Auxiliary->GetHOverBMAC();
+ if (HOverBMAC < 2.0)
+ vDirection(eZ) *= HOverBMAC / 2.0;
+
+ vDirection.Normalize();
+
+ vTurbulence = TurbGain*Magnitude * vDirection;
+ vTurbulenceGrad = TurbGain*MagnitudeAccel * vDirection;
+
+ vBodyTurbGrad = Propagate->GetTl2b()*vTurbulenceGrad;
+ vTurbPQR(eP) = vBodyTurbGrad(eY)/Aircraft->GetWingSpan();
+ if (Aircraft->GetHTailArm() != 0.0)
+ vTurbPQR(eQ) = vBodyTurbGrad(eZ)/Aircraft->GetHTailArm();
+ else
+ vTurbPQR(eQ) = vBodyTurbGrad(eZ)/10.0;
+
+ if (Aircraft->GetVTailArm())
+ vTurbPQR(eR) = vBodyTurbGrad(eX)/Aircraft->GetVTailArm();
+ else
+ vTurbPQR(eR) = vBodyTurbGrad(eX)/10.0;
+
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGMars::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGMars" << endl;
+ if (from == 1) cout << "Destroyed: FGMars" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 32) { // Turbulence
+ if (frame == 0 && from == 2) {
+ cout << "vTurbulence(X), vTurbulence(Y), vTurbulence(Z), "
+ << "vTurbulenceGrad(X), vTurbulenceGrad(Y), vTurbulenceGrad(Z), "
+ << "vDirection(X), vDirection(Y), vDirection(Z), "
+ << "Magnitude, "
+ << "vTurbPQR(P), vTurbPQR(Q), vTurbPQR(R), " << endl;
+ } else if (from == 2) {
+ cout << vTurbulence << ", " << vTurbulenceGrad << ", " << vDirection << ", " << Magnitude << ", " << vTurbPQR << endl;
+ }
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+
+} // namespace JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGMars.h
+ Author: Jon Berndt
+ Date started: 01/05/2004
+
+ ------------- Copyright (C) 2004 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+01/05/2004 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGMars_H
+#define FGMars_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <models/FGAtmosphere.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_MARS "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models the Martian atmosphere.
+ @author Jon Berndt
+ @version $Id$
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGMars : public FGAtmosphere {
+public:
+
+ /// Constructor
+ FGMars(FGFDMExec*);
+ /// Destructor
+ ~FGMars();
+ /** Runs the Martian atmosphere model; called by the Executive
+ @return false if no error */
+ bool Run(void);
+
+ bool InitModel(void);
+
+ /// Returns the temperature in degrees Rankine.
+ inline double GetTemperature(void) const {return *temperature;}
+ /** Returns the density in slugs/ft^3.
+ <i>This function may <b>only</b> be used if Run() is called first.</i> */
+ inline double GetDensity(void) const {return *density;}
+ /// Returns the pressure in psf.
+ inline double GetPressure(void) const {return *pressure;}
+ /// Returns the speed of sound in ft/sec.
+ inline double GetSoundSpeed(void) const {return soundspeed;}
+
+ /// Returns the sea level temperature in degrees Rankine.
+ inline double GetTemperatureSL(void) const { return SLtemperature; }
+ /// Returns the sea level density in slugs/ft^3
+ inline double GetDensitySL(void) const { return SLdensity; }
+ /// Returns the sea level pressure in psf.
+ inline double GetPressureSL(void) const { return SLpressure; }
+ /// Returns the sea level speed of sound in ft/sec.
+ inline double GetSoundSpeedSL(void) const { return SLsoundspeed; }
+
+ /// Returns the ratio of at-altitude temperature over the sea level value.
+ inline double GetTemperatureRatio(void) const { return (*temperature)*rSLtemperature; }
+ /// Returns the ratio of at-altitude density over the sea level value.
+ inline double GetDensityRatio(void) const { return (*density)*rSLdensity; }
+ /// Returns the ratio of at-altitude pressure over the sea level value.
+ inline double GetPressureRatio(void) const { return (*pressure)*rSLpressure; }
+ /// Returns the ratio of at-altitude sound speed over the sea level value.
+ inline double GetSoundSpeedRatio(void) const { return soundspeed*rSLsoundspeed; }
+
+ /// Tells the simulator to use an externally calculated atmosphere model.
+ void UseExternal(void);
+ /// Tells the simulator to use the internal atmosphere model.
+ void UseInternal(void); //this is the default
+ /// Gets the boolean that tells if the external atmosphere model is being used.
+ bool External(void) { return useExternal; }
+
+ /// Provides the external atmosphere model with an interface to set the temperature.
+ inline void SetExTemperature(double t) { exTemperature=t; }
+ /// Provides the external atmosphere model with an interface to set the density.
+ inline void SetExDensity(double d) { exDensity=d; }
+ /// Provides the external atmosphere model with an interface to set the pressure.
+ inline void SetExPressure(double p) { exPressure=p; }
+
+ /// Sets the wind components in NED frame.
+ inline void SetWindNED(double wN, double wE, double wD) { vWindNED(1)=wN; vWindNED(2)=wE; vWindNED(3)=wD;}
+
+ /// Retrieves the wind components in NED frame.
+ inline FGColumnVector3& GetWindNED(void) { return vWindNED; }
+
+ /** Retrieves the wind direction. The direction is defined as north=0 and
+ increases counterclockwise. The wind heading is returned in radians.*/
+ inline double GetWindPsi(void) const { return psiw; }
+
+ inline void SetTurbGain(double tt) {TurbGain = tt;}
+ inline void SetTurbRate(double tt) {TurbRate = tt;}
+
+ inline double GetTurbPQR(int idx) const {return vTurbPQR(idx);}
+ inline FGColumnVector3& GetTurbPQR(void) {return vTurbPQR;}
+
+ void bind(void);
+ void unbind(void);
+
+
+private:
+ double rho;
+
+ enum tType {ttStandard, ttBerndt, ttNone} turbType;
+
+ int lastIndex;
+ double h;
+ double htab[8];
+ double SLtemperature,SLdensity,SLpressure,SLsoundspeed;
+ double rSLtemperature,rSLdensity,rSLpressure,rSLsoundspeed; //reciprocals
+ double *temperature,*density,*pressure;
+ double soundspeed;
+ bool useExternal;
+ double exTemperature,exDensity,exPressure;
+ double intTemperature, intDensity, intPressure;
+
+ double MagnitudedAccelDt, MagnitudeAccel, Magnitude;
+ double TurbGain;
+ double TurbRate;
+ FGColumnVector3 vDirectiondAccelDt;
+ FGColumnVector3 vDirectionAccel;
+ FGColumnVector3 vDirection;
+ FGColumnVector3 vTurbulence;
+ FGColumnVector3 vTurbulenceGrad;
+ FGColumnVector3 vBodyTurbGrad;
+ FGColumnVector3 vTurbPQR;
+
+ FGColumnVector3 vWindNED;
+ double psiw;
+
+ void Calculate(double altitude);
+ void Turbulence(void);
+ void Debug(int from);
+};
+
+} // namespace JSBSim
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
+
--- /dev/null
+noinst_LIBRARIES = libAtmosphere.a
+
+libAtmosphere_a_SOURCES = FGMSIS.cpp FGMSISData.cpp FGMars.cpp
+
+noinst_HEADERS = FGMSIS.h FGMars.h
+
+INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGCondition.cpp
+ Author: Jon S. Berndt
+ Date started: 1/2/2003
+
+ -------------- Copyright (C) 2003 Jon S. Berndt (jsb@hal-pc.org) --------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+COMMENTS, REFERENCES, and NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGCondition.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_CONDITION;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+string FGCondition::indent = " ";
+
+
+FGCondition::FGCondition(Element* element, FGPropertyManager* PropertyManager) :
+ PropertyManager(PropertyManager), isGroup(true)
+{
+ string property1, property2, logic;
+ Element* condition_element;
+
+ InitializeConditionals();
+
+ TestParam1 = TestParam2 = 0L;
+ TestValue = 0.0;
+ Comparison = ecUndef;
+ Logic = elUndef;
+ conditions.clear();
+
+ logic = element->GetAttributeValue("logic");
+ if (logic == "OR") Logic = eOR;
+ else if (logic == "AND") Logic = eAND;
+ else { // error
+ cerr << "Unrecognized LOGIC token " << logic << " in switch component: " << logic << endl;
+ }
+ condition_element = element->GetElement();
+ while (condition_element) {
+ conditions.push_back(FGCondition(condition_element, PropertyManager));
+ condition_element = element->GetNextElement();
+ }
+ for (int i=0; i<element->GetNumDataLines(); i++) {
+ conditions.push_back(FGCondition(element->GetDataLine(i), PropertyManager));
+ }
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGCondition::FGCondition(string test, FGPropertyManager* PropertyManager) :
+ PropertyManager(PropertyManager), isGroup(false)
+{
+ string property1, property2, compare_string;
+ Element* condition_element;
+
+ InitializeConditionals();
+
+ TestParam1 = TestParam2 = 0L;
+ TestValue = 0.0;
+ Comparison = ecUndef;
+ Logic = elUndef;
+ conditions.clear();
+
+ int start = 0, end = 0;
+ start = test.find_first_not_of(" ");
+ end = test.find_first_of(" ", start+1);
+ property1 = test.substr(start,end-start);
+ start = test.find_first_not_of(" ",end);
+ end = test.find_first_of(" ",start+1);
+ conditional = test.substr(start,end-start);
+ start = test.find_first_not_of(" ",end);
+ end = test.find_first_of(" ",start+1);
+ property2 = test.substr(start,end-start);
+
+ TestParam1 = PropertyManager->GetNode(property1, true);
+ Comparison = mComparison[conditional];
+ if (property2.find_first_not_of("-.0123456789eE") == string::npos) {
+ TestValue = atof(property2.c_str());
+ } else {
+ TestParam2 = PropertyManager->GetNode(property2, true);
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGCondition::InitializeConditionals(void)
+{
+ mComparison["EQ"] = eEQ;
+ mComparison["NE"] = eNE;
+ mComparison["GT"] = eGT;
+ mComparison["GE"] = eGE;
+ mComparison["LT"] = eLT;
+ mComparison["LE"] = eLE;
+ mComparison["eq"] = eEQ;
+ mComparison["ne"] = eNE;
+ mComparison["gt"] = eGT;
+ mComparison["ge"] = eGE;
+ mComparison["lt"] = eLT;
+ mComparison["le"] = eLE;
+ mComparison["=="] = eEQ;
+ mComparison["!="] = eNE;
+ mComparison[">"] = eGT;
+ mComparison[">="] = eGE;
+ mComparison["<"] = eLT;
+ mComparison["<="] = eLE;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGCondition::~FGCondition(void)
+{
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGCondition::Evaluate(void )
+{
+ vector <FGCondition>::iterator iConditions;
+ bool pass = false;
+ double compareValue;
+
+ if (Logic == eAND) {
+
+ iConditions = conditions.begin();
+ pass = true;
+ while (iConditions < conditions.end()) {
+ if (!iConditions->Evaluate()) pass = false;
+ *iConditions++;
+ }
+
+ } else if (Logic == eOR) {
+
+ pass = false;
+ while (iConditions < conditions.end()) {
+ if (iConditions->Evaluate()) pass = true;
+ *iConditions++;
+ }
+
+ } else {
+
+ if (TestParam2 != 0L) compareValue = TestParam2->getDoubleValue();
+ else compareValue = TestValue;
+
+ switch (Comparison) {
+ case ecUndef:
+ cerr << "Undefined comparison operator." << endl;
+ break;
+ case eEQ:
+ pass = TestParam1->getDoubleValue() == compareValue;
+ break;
+ case eNE:
+ pass = TestParam1->getDoubleValue() != compareValue;
+ break;
+ case eGT:
+ pass = TestParam1->getDoubleValue() > compareValue;
+ break;
+ case eGE:
+ pass = TestParam1->getDoubleValue() >= compareValue;
+ break;
+ case eLT:
+ pass = TestParam1->getDoubleValue() < compareValue;
+ break;
+ case eLE:
+ pass = TestParam1->getDoubleValue() <= compareValue;
+ break;
+ default:
+ cerr << "Unknown comparison operator." << endl;
+ }
+ }
+
+ return pass;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGCondition::PrintCondition(void )
+{
+ vector <FGCondition>::iterator iConditions;
+ string scratch;
+
+ if (isGroup) {
+ switch(Logic) {
+ case (elUndef):
+ scratch = " UNSET";
+ cerr << "unset logic for test condition" << endl;
+ break;
+ case (eAND):
+ scratch = " if all of the following are true";
+ break;
+ case (eOR):
+ scratch = " if any of the following are true:";
+ break;
+ default:
+ scratch = " UNKNOWN";
+ cerr << "Unknown logic for test condition" << endl;
+ }
+
+ iConditions = conditions.begin();
+ cout << scratch << endl;
+ while (iConditions < conditions.end()) {
+ iConditions->PrintCondition();
+ *iConditions++;
+ }
+ } else {
+ if (TestParam2 != 0L)
+ cout << TestParam1->GetName() << " " << conditional << " " << TestParam2->GetName();
+ else
+ cout << TestParam1->GetName() << " " << conditional << " " << TestValue;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGCondition::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGCondition" << endl;
+ if (from == 1) cout << "Destroyed: FGCondition" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+
+} //namespace JSBSim
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGCondition.h
+ Author: Jon S. Berndt
+ Date started: 1/02/2003
+
+ ------------- Copyright (C) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGCONDITION_H
+#define FGCONDITION_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <map>
+#include <FGJSBBase.h>
+#include <input_output/FGXMLElement.h>
+#include <input_output/FGPropertyManager.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_CONDITION "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Encapsulates a condition, which is used in parts of JSBSim including switches
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGCondition : public FGJSBBase
+{
+public:
+ FGCondition(Element* element, FGPropertyManager* PropertyManager);
+ FGCondition(string test, FGPropertyManager* PropertyManager);
+ ~FGCondition(void);
+
+ bool Evaluate(void);
+ void PrintCondition(void);
+
+private:
+ enum eComparison {ecUndef=0, eEQ, eNE, eGT, eGE, eLT, eLE};
+ enum eLogic {elUndef=0, eAND, eOR};
+ map <string, eComparison> mComparison;
+ eLogic Logic;
+
+ FGPropertyManager *TestParam1, *TestParam2, *PropertyManager;
+ double TestValue;
+ eComparison Comparison;
+ bool isGroup;
+ string conditional;
+
+ static string indent;
+
+ vector <FGCondition> conditions;
+ void InitializeConditionals(void);
+
+ void Debug(int from);
+};
+}
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGDeadBand.cpp
+ Author: Jon S. Berndt
+ Date started: 11/1999
+
+ ------------- Copyright (C) 2000 -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+COMMENTS, REFERENCES, and NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGDeadBand.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_DEADBAND;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGDeadBand::FGDeadBand(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
+{
+ gain = 1.0;
+ width = 0.0;
+
+ if (element->FindElement("width")) {
+ width = element->FindElementValueAsNumber("width");
+ }
+
+ if (element->FindElement("gain")) {
+ gain = element->FindElementValueAsNumber("gain");
+ }
+
+ FGFCSComponent::bind();
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGDeadBand::~FGDeadBand()
+{
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGDeadBand::Run(void )
+{
+ Input = InputNodes[0]->getDoubleValue() * InputSigns[0];
+
+ if (Input < -width/2.0) {
+ Output = (Input + width/2.0)*gain;
+ } else if (Input > width/2.0) {
+ Output = (Input - width/2.0)*gain;
+ } else {
+ Output = 0.0;
+ }
+
+ Clip();
+
+ if (IsOutput) SetOutput();
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGDeadBand::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+ cout << " INPUT: " << InputNodes[0]->getName() << endl;
+ cout << " DEADBAND WIDTH: " << width << endl;
+ cout << " GAIN: " << gain << endl;
+ if (clip) cout << " CLIPTO: " << clipmin
+ << ", " << clipmax << endl;
+ if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGDeadBand" << endl;
+ if (from == 1) cout << "Destroyed: FGDeadBand" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGDeadBand.h
+ Author: Jon Berndt
+ Date started: 2001
+
+ ------------- Copyright (C) 2001 Jon S. Berndt -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGDEADBAND_H
+#define FGDEADBAND_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGFCSComponent.h"
+#include <input_output/FGXMLElement.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_DEADBAND "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+class FGFCS;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models a deadband object.
+ Here is the format of the deadband control specification:
+ <pre>
+ \<COMPONENT NAME="Deadbeat1" TYPE="DEADBAND">
+ INPUT {input}
+ WIDTH {deadband width}
+ MIN {minimum value}
+ MAX {maximum value}
+ [GAIN {optional deadband gain}]
+ [OUTPUT {optional output parameter to set}]
+ \</COMPONENT>
+ </pre>
+ The WIDTH value is the total deadband region within which an input will
+ produce no output. For example, say that the WIDTH value is 2.0. If the
+ input is between -1.0 and +1.0, the output will be zero.
+ @author Jon S. Berndt
+ @version $Id$
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGDeadBand : public FGFCSComponent
+{
+public:
+ FGDeadBand(FGFCS* fcs, Element* element);
+ ~FGDeadBand();
+
+ bool Run(void);
+
+private:
+ double width;
+ double gain;
+
+ void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGFCSComponent.cpp
+ Author: Jon S. Berndt
+ Date started: 11/1999
+
+ ------------- Copyright (C) 2000 -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+COMMENTS, REFERENCES, and NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGFCSComponent.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_FCSCOMPONENT;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGFCSComponent::FGFCSComponent(FGFCS* _fcs, Element* element) : fcs(_fcs)
+{
+ Element *input_element, *clip_el;
+ Input = Output = clipmin = clipmax = 0.0;
+ OutputNode = treenode = 0;
+ ClipMinPropertyNode = ClipMaxPropertyNode = 0;
+ IsOutput = clip = false;
+ string input, clip_string;
+
+ PropertyManager = fcs->GetPropertyManager();
+ Type = element->GetAttributeValue("type"); // Old, deprecated format
+ if (Type.empty()) {
+ if (element->GetName() == string("lag_filter")) {
+ Type = "LAG_FILTER";
+ } else if (element->GetName() == string("lead_lag_filter")) {
+ Type = "LEAD_LAG_FILTER";
+ } else if (element->GetName() == string("washout_filter")) {
+ Type = "WASHOUT_FILTER";
+ } else if (element->GetName() == string("second_order_filter")) {
+ Type = "SECOND_ORDER_FILTER";
+ } else if (element->GetName() == string("integrator")) {
+ Type = "INTEGRATOR";
+ } else if (element->GetName() == string("summer")) {
+ Type = "SUMMER";
+ } else if (element->GetName() == string("pure_gain")) {
+ Type = "PURE_GAIN";
+ } else if (element->GetName() == string("scheduled_gain")) {
+ Type = "SCHEDULED_GAIN";
+ } else if (element->GetName() == string("aerosurface_scale")) {
+ Type = "AEROSURFACE_SCALE";
+ } else if (element->GetName() == string("switch")) {
+ Type = "SWITCH";
+ } else if (element->GetName() == string("kinematic")) {
+ Type = "KINEMATIC";
+ } else if (element->GetName() == string("deadband")) {
+ Type = "DEADBAND";
+ } else if (element->GetName() == string("fcs_function")) {
+ Type = "FCS_FUNCTION";
+ } else if (element->GetName() == string("sensor")) {
+ Type = "SENSOR";
+ } else { // illegal component in this channel
+ Type = "UNKNOWN";
+ }
+ }
+
+ Name = element->GetAttributeValue("name");
+
+ input_element = element->FindElement("input");
+ while (input_element) {
+ input = input_element->GetDataLine();
+ if (input[0] == '-') {
+ InputSigns.push_back(-1.0);
+ input.erase(0,1);
+ } else {
+ InputSigns.push_back( 1.0);
+ }
+ InputNodes.push_back( resolveSymbol(input) );
+ input_element = element->FindNextElement("input");
+ }
+
+ if (element->FindElement("output")) {
+ IsOutput = true;
+ OutputNode = PropertyManager->GetNode( element->FindElementValue("output") );
+ if (!OutputNode) {
+ cerr << endl << " Unable to process property: " << element->FindElementValue("output") << endl;
+ throw(string("Invalid output property name in flight control definition"));
+ }
+ }
+
+ clip_el = element->FindElement("clipto");
+ if (clip_el) {
+ clip_string = clip_el->FindElementValue("min");
+ if (clip_string.find_first_not_of("+-.0123456789") != string::npos) { // it's a property
+ ClipMinPropertyNode = PropertyManager->GetNode( clip_string );
+ } else {
+ clipmin = clip_el->FindElementValueAsNumber("min");
+ }
+ clip_string = clip_el->FindElementValue("max");
+ if (clip_string.find_first_not_of("+-.0123456789") != string::npos) { // it's a property
+ ClipMaxPropertyNode = PropertyManager->GetNode( clip_string );
+ } else {
+ clipmax = clip_el->FindElementValueAsNumber("max");
+ }
+ clip = true;
+ }
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGFCSComponent::~FGFCSComponent()
+{
+// string tmp = "fcs/" + PropertyManager->mkPropertyName(Name, true);
+// PropertyManager->Untie( tmp);
+
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCSComponent::SetOutput(void)
+{
+ OutputNode->setDoubleValue(Output);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGFCSComponent::Run(void)
+{
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCSComponent::Clip(void)
+{
+ if (clip) {
+ if (ClipMinPropertyNode != 0) clipmin = ClipMinPropertyNode->getDoubleValue();
+ if (ClipMaxPropertyNode != 0) clipmax = ClipMaxPropertyNode->getDoubleValue();
+ if (Output > clipmax) Output = clipmax;
+ else if (Output < clipmin) Output = clipmin;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGPropertyManager* FGFCSComponent::resolveSymbol(string token)
+{
+ string prop;
+ FGPropertyManager* tmp = PropertyManager->GetNode(token,false);
+ if (!tmp) {
+ if (token.find("/") == token.npos) prop = "model/" + token;
+ cerr << "Creating new property " << prop << endl;
+ tmp = PropertyManager->GetNode(token,true);
+ }
+ return tmp;
+}
+
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGFCSComponent::bind(void)
+{
+ string tmp = "fcs/" + PropertyManager->mkPropertyName(Name, true);
+ PropertyManager->Tie( tmp, this, &FGFCSComponent::GetOutput);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGFCSComponent::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) {
+ cout << endl << " Loading Component \"" << Name
+ << "\" of type: " << Type << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGFCSComponent" << endl;
+ if (from == 1) cout << "Destroyed: FGFCSComponent" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGFCSComponent.h
+ Author: Jon S. Berndt
+ Date started: 05/01/2000
+
+ ------------- Copyright (C) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGFCSCOMPONENT_H
+#define FGFCSCOMPONENT_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+#endif
+
+#include <string>
+#include <vector>
+#include <FGJSBBase.h>
+#include <input_output/FGPropertyManager.h>
+#include <input_output/FGXMLElement.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_FCSCOMPONENT "$Id$"
+
+using std::string;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+class FGFCS;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Base class for JSBSim Flight Control System Components.
+ The Flight Control System (FCS) for JSBSim consists of the FCS container
+ class (see \URL[FGFCS]{FGFCS.html}), the FGFCSComponent base class, and the
+ component classes from which can be constructed a string, or channel. See:
+
+ - FGSwitch
+ - FGGain
+ - FGKinemat
+ - FGFilter
+ - FGDeadBand
+ - FGSummer
+ - FGGradient
+
+ @author Jon S. Berndt
+ @version $Id$
+ @see Documentation for the FGFCS class, and for the configuration file class
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGFCSComponent : public FGJSBBase
+{
+public:
+ /// Constructor
+ FGFCSComponent(FGFCS* fcs, Element* el);
+ /// Destructor
+ virtual ~FGFCSComponent();
+
+ virtual bool Run(void);
+ virtual void SetOutput(void);
+ inline double GetOutput (void) const {return Output;}
+ inline FGPropertyManager* GetOutputNode(void) { return OutputNode; }
+ inline string GetName(void) const {return Name;}
+ inline string GetType(void) const { return Type; }
+ virtual double GetOutputPct(void) const { return 0; }
+
+protected:
+ FGFCS* fcs;
+ FGPropertyManager* PropertyManager;
+ FGPropertyManager* treenode;
+ FGPropertyManager* OutputNode;
+ FGPropertyManager* ClipMinPropertyNode;
+ FGPropertyManager* ClipMaxPropertyNode;
+ vector <FGPropertyManager*> InputNodes;
+ vector <float> InputSigns;
+ string Type;
+ string Name;
+ double Input;
+ double Output;
+ double clipmax, clipmin;
+ bool IsOutput;
+ bool clip;
+
+ void Clip(void);
+ virtual void bind();
+ FGPropertyManager* resolveSymbol(string token);
+
+ virtual void Debug(int from);
+};
+
+} //namespace JSBSim
+
+#include "../FGFCS.h"
+
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGFCSFunction.cpp
+ Author: Jon S. Berndt
+ Date started: 6/2005
+
+ ------------- Copyright (C) 2005 -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+COMMENTS, REFERENCES, and NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGFCSFunction.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_FCSFUNCTION;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGFCSFunction::FGFCSFunction(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
+{
+ Element *function_element = element->FindElement("function");
+
+ function = new FGFunction(PropertyManager, function_element);
+
+ FGFCSComponent::bind();
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGFCSFunction::~FGFCSFunction()
+{
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGFCSFunction::Run(void )
+{
+ Output = function->GetValue();
+
+ if (InputNodes.size() > 0) {
+ Input = InputNodes[0]->getDoubleValue() * InputSigns[0];
+ Output*= Input;
+ }
+
+ Clip();
+
+ if (IsOutput) SetOutput();
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGFCSFunction::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+ if (InputNodes.size()>0)
+ cout << " INPUT: " << InputNodes[0]->getName() << endl;
+// cout << " Function: " << endl;
+ if (clip) cout << " CLIPTO: " << clipmin
+ << ", " << clipmax << endl;
+ if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGFCSFunction" << endl;
+ if (from == 1) cout << "Destroyed: FGFCSFunction" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGFCSFunction.h
+ Author: Jon Berndt
+ Date started: 2005
+
+ ------------- Copyright (C) 2005 Jon S. Berndt -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGFCSFUNCTION_H
+#define FGFCSFUNCTION_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGFCSComponent.h"
+#include <input_output/FGXMLElement.h>
+#include <math/FGFunction.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_FCSFUNCTION "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+class FGFCS;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models a FCSFunction object.
+ @author Jon S. Berndt
+ @version $Id$
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGFCSFunction : public FGFCSComponent
+{
+public:
+ FGFCSFunction(FGFCS* fcs, Element* element);
+ ~FGFCSFunction();
+
+ bool Run(void);
+
+private:
+ FGFunction* function;
+
+ void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGFilter.cpp
+ Author: Jon S. Berndt
+ Date started: 11/2000
+
+ ------------- Copyright (C) 2000 -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+COMMENTS, REFERENCES, and NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGFilter.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_FILTER;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGFilter::FGFilter(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
+{
+ double denom;
+
+ dt = fcs->GetState()->Getdt();
+ Trigger = 0;
+
+ C1 = C2 = C3 = C4 = C5 = C6 = 0.0;
+
+ if (Type == "LAG_FILTER") FilterType = eLag ;
+ else if (Type == "LEAD_LAG_FILTER") FilterType = eLeadLag ;
+ else if (Type == "SECOND_ORDER_FILTER") FilterType = eOrder2 ;
+ else if (Type == "WASHOUT_FILTER") FilterType = eWashout ;
+ else if (Type == "INTEGRATOR") FilterType = eIntegrator ;
+ else FilterType = eUnknown ;
+
+ if (element->FindElement("c1")) C1 = element->FindElementValueAsNumber("c1");
+ if (element->FindElement("c2")) C2 = element->FindElementValueAsNumber("c2");
+ if (element->FindElement("c3")) C3 = element->FindElementValueAsNumber("c3");
+ if (element->FindElement("c4")) C4 = element->FindElementValueAsNumber("c4");
+ if (element->FindElement("c5")) C5 = element->FindElementValueAsNumber("c5");
+ if (element->FindElement("c6")) C6 = element->FindElementValueAsNumber("c6");
+ if (element->FindElement("trigger")) {
+ Trigger = resolveSymbol(element->FindElementValue("trigger"));
+ }
+
+ Initialize = true;
+
+ switch (FilterType) {
+ case eLag:
+ denom = 2.00 + dt*C1;
+ ca = dt*C1 / denom;
+ cb = (2.00 - dt*C1) / denom;
+ break;
+ case eLeadLag:
+ denom = 2.00*C3 + dt*C4;
+ ca = (2.00*C1 + dt*C2) / denom;
+ cb = (dt*C2 - 2.00*C1) / denom;
+ cc = (2.00*C3 - dt*C4) / denom;
+ break;
+ case eOrder2:
+ denom = 4.0*C4 + 2.0*C5*dt + C6*dt*dt;
+ ca = (4.0*C1 + 2.0*C2*dt + C3*dt*dt) / denom;
+ cb = (2.0*C3*dt*dt - 8.0*C1) / denom;
+ cc = (4.0*C1 - 2.0*C2*dt + C3*dt*dt) / denom;
+ cd = (2.0*C6*dt*dt - 8.0*C4) / denom;
+ ce = (4.0*C4 - 2.0*C5*dt + C6*dt*dt) / denom;
+ break;
+ case eWashout:
+ denom = 2.00 + dt*C1;
+ ca = 2.00 / denom;
+ cb = (2.00 - dt*C1) / denom;
+ break;
+ case eIntegrator:
+ ca = dt*C1 / 2.00;
+ break;
+ case eUnknown:
+ cerr << "Unknown filter type" << endl;
+ break;
+ }
+ FGFCSComponent::bind();
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGFilter::~FGFilter()
+{
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGFilter::Run(void)
+{
+ double test = 0.0;
+
+ if (Initialize) {
+
+ PreviousOutput1 = PreviousInput1 = Output = Input;
+ Initialize = false;
+
+ } else {
+
+ Input = InputNodes[0]->getDoubleValue() * InputSigns[0];
+ switch (FilterType) {
+ case eLag:
+ Output = Input * ca + PreviousInput1 * ca + PreviousOutput1 * cb;
+ break;
+ case eLeadLag:
+ Output = Input * ca + PreviousInput1 * cb + PreviousOutput1 * cc;
+ break;
+ case eOrder2:
+ Output = Input * ca + PreviousInput1 * cb + PreviousInput2 * cc
+ - PreviousOutput1 * cd - PreviousOutput2 * ce;
+ break;
+ case eWashout:
+ Output = Input * ca - PreviousInput1 * ca + PreviousOutput1 * cb;
+ break;
+ case eIntegrator:
+ if (Trigger != 0) {
+ test = Trigger->getDoubleValue();
+ if (fabs(test) > 0.000001) {
+ Input = PreviousInput1 = PreviousInput2 = 0.0;
+ }
+ }
+ Output = Input * ca + PreviousInput1 * ca + PreviousOutput1;
+ break;
+ case eUnknown:
+ break;
+ }
+
+ }
+
+ PreviousOutput2 = PreviousOutput1;
+ PreviousOutput1 = Output;
+ PreviousInput2 = PreviousInput1;
+ PreviousInput1 = Input;
+
+ Clip();
+ if (IsOutput) SetOutput();
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGFilter::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+ cout << " INPUT: " << InputNodes[0]->getName() << endl;
+ cout << " C1: " << C1 << endl;
+ cout << " C2: " << C2 << endl;
+ cout << " C3: " << C3 << endl;
+ cout << " C4: " << C4 << endl;
+ cout << " C5: " << C5 << endl;
+ cout << " C6: " << C6 << endl;
+ if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGFilter" << endl;
+ if (from == 1) cout << "Destroyed: FGFilter" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGFilter.h
+ Author: Jon S. Berndt
+ Date started: 4/2000
+
+ ------------- Copyright (C) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGFILTER_H
+#define FGFILTER_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGFCSComponent.h"
+#include <input_output/FGXMLElement.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_FILTER "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Encapsulates a filter for the flight control system.
+The filter component can simulate any filter up to second order. The
+Tustin substitution is used to take filter definitions from LaPlace space to the
+time domain. The general format for a filter specification is:
+
+<pre>
+\<component name="name" type="type">
+ \<input> property \</input>
+ \<c1> value \<c/1>
+ [\<c2> value \<c/2>]
+ [\<c3> value \<c/3>]
+ [\<c4> value \<c/4>]
+ [\<c5> value \<c/5>]
+ [\<c6> value \<c/6>]
+ [\<output> property \<output>]
+\</component>
+</pre>
+
+For a lag filter of the form,
+<pre>
+ C1
+------
+s + C1
+</pre>
+the corresponding filter definition is:
+<pre>
+\<component name="name" type="LAG_FILTER">
+ \<input> property \</input>
+ \<c1> value \<c/1>
+ [\<output> property \<output>]
+\</component>
+</pre>
+As an example, for the specific filter:
+<pre>
+ 600
+------
+s + 600
+</pre>
+the corresponding filter definition could be:
+<pre>
+\<component name="Heading Roll Error Lag" type="LAG_FILTER">
+ \<input> fcs/heading-command \</input>
+ \<c1> 600 \</c1>
+\</component>
+</pre>
+For a lead-lag filter of the form:
+<pre>
+C1*s + C2
+---------
+C3*s + C4
+</pre>
+The corresponding filter definition is:
+<pre>
+\<component name="name" type="LEAD_LAG_FILTER">
+ \<input> property \</input>
+ \<c1> value \<c/1>
+ \<c2> value \<c/2>
+ \<c3> value \<c/3>
+ \<c4> value \<c/4>
+ [\<output> property \<output>]
+\</component>
+</pre>
+For a washout filter of the form:
+<pre>
+ s
+------
+s + C1
+</pre>
+The corresponding filter definition is:
+<pre>
+\<component name="name" type="WASHOUT_FILTER">
+ \<input> property \</input>
+ \<c1> value \</c1>
+ [\<output> property \<output>]
+\</component>
+</pre>
+For a second order filter of the form:
+<pre>
+C1*s^2 + C2*s + C3
+------------------
+C4*s^2 + C5*s + C6
+</pre>
+The corresponding filter definition is:
+<pre>
+\<component name="name" type="SECOND_ORDER_FILTER">
+ \<input> property \</input>
+ \<c1> value \<c/1>
+ \<c2> value \<c/2>
+ \<c3> value \<c/3>
+ \<c4> value \<c/4>
+ \<c5> value \<c/5>
+ \<c6> value \<c/6>
+ [\<output> property \<output>]
+\</component>
+</pre>
+For an integrator of the form:
+<pre>
+ C1
+ ---
+ s
+</pre>
+The corresponding filter definition is:
+<pre>
+\<component name="name" type="INTEGRATOR">
+ \<input> property \</input>
+ \<c1> value \<c/1>
+ [\<trigger> property \</trigger>]
+ [\<output> property \<output>]
+\</component>
+</pre>
+For the integrator, the trigger features the following behavior. If the trigger
+property value is:
+ - 0: no action is taken - the output is calculated normally
+ - not 0: (or simply greater than zero), all current and previous inputs will
+ be set to 0.0
+
+In all the filter specifications above, an \<output> element is also seen. This
+is so that the last component in a "string" can copy its value to the appropriate
+output, such as the elevator, or speedbrake, etc.
+
+@author Jon S. Berndt
+@version $Id$
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGFilter : public FGFCSComponent
+{
+public:
+ FGFilter(FGFCS* fcs, Element* element);
+ ~FGFilter();
+
+ bool Run (void);
+
+ /** When true, causes previous values to be set to current values. This
+ is particularly useful for first pass. */
+ bool Initialize;
+
+ enum {eLag, eLeadLag, eOrder2, eWashout, eIntegrator, eUnknown} FilterType;
+
+private:
+ double dt;
+ double ca;
+ double cb;
+ double cc;
+ double cd;
+ double ce;
+ double C1;
+ double C2;
+ double C3;
+ double C4;
+ double C5;
+ double C6;
+ double PreviousInput1;
+ double PreviousInput2;
+ double PreviousOutput1;
+ double PreviousOutput2;
+ FGPropertyManager* Trigger;
+ void Debug(int from);
+};
+}
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGGain.cpp
+ Author: Jon S. Berndt
+ Date started: 4/2000
+
+ ------------- Copyright (C) 2000 -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+COMMENTS, REFERENCES, and NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGGain.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_GAIN;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGGain::FGGain(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
+{
+ Element *scale_element, *zero_centered;
+ string strScheduledBy, gain_string, sZeroCentered;
+
+ GainPropertyNode = 0;
+ Gain = 1.000;
+ Rows = 0;
+ Table = 0;
+ InMin = -1.0;
+ InMax = 1.0;
+ OutMin = OutMax = 0.0;
+
+ if (Type == "PURE_GAIN") {
+ if ( !element->FindElement("gain") ) {
+ cout << highint << " No GAIN specified (default: 1.0)" << normint << endl;
+ }
+ }
+
+ if ( element->FindElement("gain") ) {
+ gain_string = element->FindElementValue("gain");
+ if (gain_string.find_first_not_of("+-.0123456789") != string::npos) { // property
+ GainPropertyNode = PropertyManager->GetNode(gain_string);
+ } else {
+ Gain = element->FindElementValueAsNumber("gain");
+ }
+ }
+
+ if (Type == "AEROSURFACE_SCALE") {
+ scale_element = element->FindElement("domain");
+ if (scale_element) {
+ if (scale_element->FindElement("max") && scale_element->FindElement("min") )
+ {
+ InMax = scale_element->FindElementValueAsNumber("max");
+ InMin = scale_element->FindElementValueAsNumber("min");
+ }
+ }
+ scale_element = element->FindElement("range");
+ if (!scale_element) throw(string("No range supplied for aerosurface scale component"));
+ if (scale_element->FindElement("max") && scale_element->FindElement("min") )
+ {
+ OutMax = scale_element->FindElementValueAsNumber("max");
+ OutMin = scale_element->FindElementValueAsNumber("min");
+ } else {
+ cerr << "Maximum and minimum output values must be supplied for the "
+ "aerosurface scale component" << endl;
+ exit(-1);
+ }
+ ZeroCentered = true;
+ zero_centered = element->FindElement("zero_centered");
+ if (zero_centered) {
+ sZeroCentered = zero_centered->FindElementValue("zero_centered");
+ if (sZeroCentered == string("0") || sZeroCentered == string("false")) {
+ ZeroCentered = false;
+ }
+ }
+ }
+
+ if (Type == "SCHEDULED_GAIN") {
+ if (element->FindElement("table")) {
+ Table = new FGTable(PropertyManager, element->FindElement("table"));
+ } else {
+ cerr << "A table must be provided for the scheduled gain component" << endl;
+ exit(-1);
+ }
+ }
+
+ FGFCSComponent::bind();
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGGain::~FGGain()
+{
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGGain::Run(void )
+{
+ double SchedGain = 1.0;
+
+ Input = InputNodes[0]->getDoubleValue() * InputSigns[0];
+
+ if (GainPropertyNode != 0) Gain = GainPropertyNode->getDoubleValue();
+
+ if (Type == "PURE_GAIN") { // PURE_GAIN
+
+ Output = Gain * Input;
+
+ } else if (Type == "SCHEDULED_GAIN") { // SCHEDULED_GAIN
+
+ SchedGain = Table->GetValue();
+ Output = Gain * SchedGain * Input;
+
+ } else if (Type == "AEROSURFACE_SCALE") { // AEROSURFACE_SCALE
+
+ if (ZeroCentered) {
+ if (Input == 0.0) {
+ Output = 0.0;
+ } else if (Input > 0) {
+ Output = (Input / InMax) * OutMax;
+ } else {
+ Output = (Input / InMin) * OutMin;
+ }
+ } else {
+ Output = OutMin + ((Input - InMin) / (InMax - InMin)) * (OutMax - OutMin);
+ }
+
+ Output *= Gain;
+ }
+
+ Clip();
+ if (IsOutput) SetOutput();
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGGain::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+ if (InputSigns[0] < 0)
+ cout << " INPUT: -" << InputNodes[0]->getName() << endl;
+ else
+ cout << " INPUT: " << InputNodes[0]->getName() << endl;
+
+ cout << " GAIN: " << Gain << endl;
+ if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
+ if (Type == "AEROSURFACE_SCALE") {
+ cout << " In/Out Mapping:" << endl;
+ cout << " Input MIN: " << InMin << endl;
+ cout << " Input MAX: " << InMax << endl;
+ cout << " Output MIN: " << OutMin << endl;
+ cout << " Output MAX: " << OutMax << endl;
+ }
+ if (Table != 0) {
+ cout << " Scheduled by table: " << endl;
+ Table->Print();
+ }
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGGain" << endl;
+ if (from == 1) cout << "Destroyed: FGGain" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGGain.h
+ Author:
+ Date started:
+
+ ------------- Copyright (C) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGGAIN_H
+#define FGGAIN_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# include STL_STRING
+ SG_USING_STD(string);
+#else
+# include <string>
+#endif
+
+#include "FGFCSComponent.h"
+#include <input_output/FGXMLElement.h>
+#include <math/FGTable.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_GAIN "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+class FGFCS;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Encapsulates a gain component for the flight control system.
+ The gain component merely multiplies the input by a gain. The form of the
+ gain component specification is:
+ <pre>
+ \<component name="name" type="PURE_GAIN">
+ \<input> property \</input>
+ \<gain> value \</gain>
+ [\<output> property \</output>]
+ \</component>
+ </pre>
+ Note: as is the case with the Summer component, the input property name may be
+ immediately preceded by a minus sign to invert that signal.
+
+ The scheduled gain component multiplies the input by a variable gain that is
+ dependent on another property (such as qbar, altitude, etc.). The lookup
+ mapping is in the form of a table. This kind of component might be used, for
+ example, in a case where aerosurface deflection must only be commanded to
+ acceptable settings - i.e at higher qbar the commanded elevator setting might
+ be attenuated. The form of the scheduled gain component specification is:
+ <pre>
+ \<COMPONENT NAME="name" TYPE="SCHEDULED_GAIN">
+ INPUT \<property>
+ [GAIN \<value>]
+ SCHEDULED_BY \<property>
+ ROWS \<number_of_rows>
+ \<lookup_value gain_value>
+ ?
+ [CLIPTO \<min> \<max> 1]
+ [OUTPUT \<property>]
+ \</COMPONENT>
+ </pre>
+ An overall GAIN may be supplied that is multiplicative with the scheduled gain.
+
+ Note: as is the case with the Summer component, the input property name may
+ be immediately preceded by a minus sign to invert that signal.
+
+ Here is an example of a scheduled gain component specification:
+ <pre>
+ \<COMPONENT NAME="Pitch Scheduled Gain 1" TYPE="SCHEDULED_GAIN">
+ INPUT fcs/pitch-gain-1
+ GAIN 0.017
+ SCHEDULED_BY fcs/elevator-pos-rad
+ ROWS 22
+ -0.68 -26.548
+ -0.595 -20.513
+ -0.51 -15.328
+ -0.425 -10.993
+ -0.34 -7.508
+ -0.255 -4.873
+ -0.17 -3.088
+ -0.085 -2.153
+ 0 -2.068
+ 0.085 -2.833
+ 0.102 -3.088
+ 0.119 -3.377
+ 0.136 -3.7
+ 0.153 -4.057
+ 0.17 -4.448
+ 0.187 -4.873
+ 0.272 -7.508
+ 0.357 -10.993
+ 0.442 -15.328
+ 0.527 -20.513
+ 0.612 -26.548
+ 0.697 -33.433
+ \</COMPONENT>
+ </pre>
+ In the example above, we see the utility of the overall GAIN value in
+ effecting a degrees-to-radians conversion.
+
+ The aerosurface scale component is a modified version of the simple gain
+ component. The normal purpose
+ for this component is to take control inputs that range from -1 to +1 or
+ from 0 to +1 and scale them to match the expected inputs to a flight control
+ system. For instance, the normal and expected ability of a pilot to push or
+ pull on a control stick is about 50 pounds. The input to the pitch channelb
+ lock diagram of a flight control system is in units of pounds. Yet, the
+ joystick control input is usually in a range from -1 to +1. The form of the
+ aerosurface scaling component specification is:
+<pre>
+ \<COMPONENT NAME="name" TYPE="AEROSURFACE_SCALE">
+ INPUT \<property>
+ MIN \<value>
+ MAX \<value>
+ [GAIN \<value>]
+ [OUTPUT \<property>]
+ \</COMPONENT>
+</pre>
+ Note: as is the case with the Summer component, the input property name may be
+ immediately preceded by a minus sign to invert that signal.
+
+ @author Jon S. Berndt
+ @version $Id$
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGGain : public FGFCSComponent
+{
+public:
+ FGGain(FGFCS* fcs, Element* element);
+ ~FGGain();
+
+ bool Run (void);
+
+private:
+ FGTable* Table;
+ FGPropertyManager* GainPropertyNode;
+ double Gain;
+ double InMin, InMax, OutMin, OutMax;
+ int Rows;
+ bool ZeroCentered;
+
+ void Debug(int from);
+};
+}
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGGradient.cpp
+ Author:
+ Date started:
+
+ ------------- Copyright (C) 2000 -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+COMMENTS, REFERENCES, and NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGGradient.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_GRADIENT;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+FGGradient::FGGradient(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
+{
+ FGFCSComponent::bind();
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGGradient::~FGGradient()
+{
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGGradient::Run(void )
+{
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGGradient::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGGradient" << endl;
+ if (from == 1) cout << "Destroyed: FGGradient" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGGradient.h
+ Author:
+ Date started:
+
+ ------------- Copyright (C) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGGRADIENT_H
+#define FGGRADIENT_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGFCSComponent.h"
+#include <input_output/FGXMLElement.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_GRADIENT "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+class FGFCS;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Encapsulates a gradient component for the flight control system.
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGGradient : public FGFCSComponent
+{
+public:
+ FGGradient(FGFCS* fcs, Element* element);
+ ~FGGradient();
+
+ bool Run (void);
+
+private:
+ void Debug(int from);
+};
+}
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGKinemat.cpp
+ Author: Tony Peden, for flight control system authored by Jon S. Berndt
+ Date started: 12/02/01
+
+ ------------- Copyright (C) 2000 Anthony K. Peden -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+COMMENTS, REFERENCES, and NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <math.h>
+#include <float.h>
+
+#include "FGKinemat.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_FLAPS;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGKinemat::FGKinemat(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
+{
+ Element *traverse_element, *setting_element;
+ double tmpDetent;
+ double tmpTime;
+
+ Detents.clear();
+ TransitionTimes.clear();
+
+ Output = OutputPct = 0;
+ DoScale = true;
+
+ if (element->FindElement("noscale")) DoScale = false;
+
+ traverse_element = element->FindElement("traverse");
+ setting_element = traverse_element->FindElement("setting");
+ while (setting_element) {
+ tmpDetent = setting_element->FindElementValueAsNumber("position");
+ tmpTime = setting_element->FindElementValueAsNumber("time");
+ Detents.push_back(tmpDetent);
+ TransitionTimes.push_back(tmpTime);
+ setting_element = traverse_element->FindNextElement("setting");
+ }
+ NumDetents = Detents.size();
+
+ if (NumDetents <= 1) {
+ cerr << "Kinematic component " << Name
+ << " must have more than 1 setting element" << endl;
+ exit(-1);
+ }
+
+ FGFCSComponent::bind();
+// treenode->Tie("output-norm", this, &FGKinemat::GetOutputPct );
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGKinemat::~FGKinemat()
+{
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGKinemat::Run(void )
+{
+ double dt = fcs->GetState()->Getdt();
+
+ Input = InputNodes[0]->getDoubleValue() * InputSigns[0];
+
+ if (DoScale) Input *= Detents[NumDetents-1];
+
+ if (IsOutput) Output = OutputNode->getDoubleValue();
+
+ if (Input < Detents[0])
+ Input = Detents[0];
+ else if (Detents[NumDetents-1] < Input)
+ Input = Detents[NumDetents-1];
+
+ // Process all detent intervals the movement traverses until either the
+ // final value is reached or the time interval has finished.
+ while ( 0.0 < dt && !EqualToRoundoff(Input, Output) ) {
+
+ // Find the area where Output is in
+ int ind;
+ for (ind = 1; (Input < Output) ? Detents[ind] < Output : Detents[ind] <= Output ; ++ind)
+ if (NumDetents <= ind)
+ break;
+
+ // A transition time of 0.0 means an infinite rate.
+ // The output is reached in one step
+ if (TransitionTimes[ind] <= 0.0) {
+ Output = Input;
+ break;
+ } else {
+ // Compute the rate in this area
+ double Rate = (Detents[ind] - Detents[ind-1])/TransitionTimes[ind];
+ // Compute the maximum input value inside this area
+ double ThisInput = Input;
+ if (ThisInput < Detents[ind-1]) ThisInput = Detents[ind-1];
+ if (Detents[ind] < ThisInput) ThisInput = Detents[ind];
+ // Compute the time to reach the value in ThisInput
+ double ThisDt = fabs((ThisInput-Output)/Rate);
+
+ // and clip to the timestep size
+ if (dt < ThisDt) {
+ ThisDt = dt;
+ if (Output < Input)
+ Output += ThisDt*Rate;
+ else
+ Output -= ThisDt*Rate;
+ } else
+ // Handle this case separate to make shure the termination condition
+ // is met even in inexact arithmetics ...
+ Output = ThisInput;
+
+ dt -= ThisDt;
+ }
+ }
+
+ OutputPct = (Output-Detents[0])/(Detents[NumDetents-1]-Detents[0]);
+
+ Clip();
+ if (IsOutput) SetOutput();
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGKinemat::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+ cout << " INPUT: " << InputNodes[0]->getName() << endl;
+ cout << " DETENTS: " << NumDetents << endl;
+ for (int i=0;i<NumDetents;i++) {
+ cout << " " << Detents[i] << " " << TransitionTimes[i] << endl;
+ }
+ if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
+ if (!DoScale) cout << " NOSCALE" << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGKinemat" << endl;
+ if (from == 1) cout << "Destroyed: FGKinemat" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGKinemat.h
+ Author: Tony Peden, for flight control system authored by Jon S. Berndt
+ Date started: 12/02/01
+
+ ------------- Copyright (C) Anthony K. Peden -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGKinemat_H
+#define FGKinemat_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# ifdef SG_HAVE_STD_INCLUDES
+# include <vector>
+# else
+# include <vector.h>
+# endif
+#else
+# include <vector>
+#endif
+
+#include <string>
+#include "FGFCSComponent.h"
+#include <input_output/FGXMLElement.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_FLAPS "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Encapsulates a kinematic component for the flight control system.
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGKinemat : public FGFCSComponent {
+public:
+ /** Initializer.
+ @param fcs A reference to the ccurrent flightcontrolsystem.
+ @param AC_cfg reference to the current aircraft configuration file.
+ Initializes the FGKinemat object from the given configuration
+ file. The Configuration file is expected to be at the stream
+ position where the KINEMAT object starts. Also it is expected to
+ be past the end of the current KINEMAT configuration on exit.
+ */
+ FGKinemat(FGFCS* fcs, Element* element);
+
+ /** Destructor.
+ */
+ ~FGKinemat();
+
+ /** Kinemat output value.
+ @return the current output of the kinemat object on the range of [0,1].
+ */
+ double GetOutputPct() const { return OutputPct; }
+
+ /** Run method, overwrites FGModel::Run().
+ @return false on success, true on failure.
+ The routine doing the work.
+ */
+ bool Run (void);
+
+private:
+ vector<double> Detents;
+ vector<double> TransitionTimes;
+ int NumDetents;
+ double OutputPct;
+ bool DoScale;
+
+ void Debug(int from);
+};
+}
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGSensor.cpp
+ Author: Jon Berndt
+ Date started: 9 July 2005
+
+ ------------- Copyright (C) 2005 -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+COMMENTS, REFERENCES, and NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGSensor.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_SENSOR;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+FGSensor::FGSensor(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
+{
+ double denom;
+ dt = fcs->GetState()->Getdt();
+
+ // inputs are read from the base class constructor
+
+ dt = fcs->GetState()->Getdt();
+
+ bits = quantized = divisions = 0;
+ PreviousInput = PreviousOutput = 0.0;
+ min = max = bias = noise_variance = lag = drift_rate = drift = span = 0.0;
+ granularity = 0.0;
+ noise_type = 0;
+ fail_low = fail_high = fail_stuck = false;
+
+ Element* quantization_element = element->FindElement("quantization");
+ if ( quantization_element) {
+ if ( quantization_element->FindElement("bits") ) {
+ bits = (int)quantization_element->FindElementValueAsNumber("bits");
+ }
+ divisions = (1<<bits);
+ if ( quantization_element->FindElement("min") ) {
+ min = quantization_element->FindElementValueAsNumber("min");
+ }
+ if ( quantization_element->FindElement("max") ) {
+ max = quantization_element->FindElementValueAsNumber("max");
+ }
+ span = max - min;
+ granularity = span/divisions;
+ }
+ if ( element->FindElement("bias") ) {
+ bias = element->FindElementValueAsNumber("bias");
+ }
+ if ( element->FindElement("drift_rate") ) {
+ drift_rate = element->FindElementValueAsNumber("drift_rate");
+ }
+ if ( element->FindElement("lag") ) {
+ lag = element->FindElementValueAsNumber("lag");
+ denom = 2.00 + dt*lag;
+ ca = dt*lag / denom;
+ cb = (2.00 - dt*lag) / denom;
+ }
+ if ( element->FindElement("noise") ) {
+ noise_variance = element->FindElementValueAsNumber("noise");
+ string variation = element->FindElement("noise")->GetAttributeValue("variation");
+ if (variation == "PERCENT") {
+ NoiseType = ePercent;
+ } else if (variation == "ABSOLUTE") {
+ NoiseType = eAbsolute;
+ } else {
+ NoiseType = ePercent;
+ cerr << "Unknown noise type in sensor: " << Name << endl;
+ cerr << " defaulting to PERCENT." << endl;
+ }
+ }
+
+ FGFCSComponent::bind();
+ bind();
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGSensor::~FGSensor()
+{
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGSensor::Run(void )
+{
+ Input = InputNodes[0]->getDoubleValue() * InputSigns[0];
+
+ Output = Input; // perfect sensor
+
+ // Degrade signal as specified
+
+ if (fail_stuck) {
+ Output = PreviousOutput;
+ return true;
+ }
+
+ if (lag != 0.0) Lag(); // models sensor lag
+ if (noise_variance != 0.0) Noise(); // models noise
+ if (drift_rate != 0.0) Drift(); // models drift over time
+ if (bias != 0.0) Bias(); // models a finite bias
+
+ if (fail_low) Output = -HUGE_VAL;
+ if (fail_high) Output = HUGE_VAL;
+
+ if (bits != 0) Quantize(); // models quantization degradation
+// if (delay != 0.0) Delay(); // models system signal transport latencies
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGSensor::Noise(void)
+{
+ double random_value = ((double)rand()/(double)RAND_MAX) - 0.5;
+
+ switch( NoiseType ) {
+ case ePercent:
+ Output *= (1.0 + noise_variance*random_value);
+ break;
+
+ case eAbsolute:
+ Output += noise_variance*random_value;
+ break;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGSensor::Bias(void)
+{
+ Output += bias;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGSensor::Drift(void)
+{
+ drift += drift_rate*dt;
+ Output += drift;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGSensor::Quantize(void)
+{
+ if (Output < min) Output = min;
+ if (Output > max) Output = max;
+ double portion = Output - min;
+ quantized = (int)(portion/granularity);
+ Output = quantized*granularity + min;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGSensor::Lag(void)
+{
+ // "Output" on the right side of the "=" is the current frame input
+ Output = ca * (Output + PreviousInput) + PreviousOutput * cb;
+
+ PreviousOutput = Output;
+ PreviousInput = Input;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGSensor::bind(void)
+{
+ string tmp = "fcs/" + PropertyManager->mkPropertyName(Name, true);
+ const string tmp_low = tmp + "/malfunction/fail_low";
+ const string tmp_high = tmp + "/malfunction/fail_high";
+ const string tmp_stuck = tmp + "/malfunction/fail_stuck";
+
+ PropertyManager->Tie( tmp_low, this, &FGSensor::GetFailLow, &FGSensor::SetFailLow);
+ PropertyManager->Tie( tmp_high, this, &FGSensor::GetFailHigh, &FGSensor::SetFailHigh);
+ PropertyManager->Tie( tmp_stuck, this, &FGSensor::GetFailStuck, &FGSensor::SetFailStuck);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGSensor::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGSensor" << endl;
+ if (from == 1) cout << "Destroyed: FGSensor" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGSensor.h
+ Author: Jon Berndt
+ Date started: 9 July 2005
+
+ ------------- Copyright (C) 2005 -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGSENSOR_H
+#define FGSENSOR_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGFCSComponent.h"
+#include <input_output/FGXMLElement.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_SENSOR "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+class FGFCS;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Encapsulates a Sensor component for the flight control system.
+
+Syntax:
+
+<sensor name=\94name\94 rate_group=\94name\94>
+ <input> property </input>
+ <lag> number </lag>
+ <noise variation=\94PERCENT|ABSOLUTE\94> number </noise>
+ <quantization name="name">
+ <bits> number </bits>
+ <min> number </min>
+ <max> number </max>
+ </quantization>
+ <drift_rate> number </drift_rate>
+ <bias> number </bias>
+</sensor>
+
+Example:
+
+<sensor name=\94aero/sensor/qbar\94 rate_group=\94HFCS\94>
+ <input> aero/qbar </input>
+ <lag> 0.5 </lag>
+ <noise variation=\94PERCENT\94> 2 </noise>
+ <quantization name="aero/sensor/quantized/qbar">
+ <bits> 12 </bits>
+ <min> 0 </min>
+ <max> 400 </max>
+ </quantization>
+ <bias> 0.5 </bias>
+</sensor>
+
+The only required element in the sensor definition is the input element. In that
+case, no degradation would be modeled, and the output would simply be the input.
+
+For noise, if the type is PERCENT, then the value supplied is understood to be a
+percentage variance. That is, if the number given is 0.05, the the variance is
+understood to be +/-0.05 percent maximum variance. So, the actual value for the sensor
+will be *anywhere* from 0.95 to 1.05 of the actual "perfect" value at any time -
+even varying all the way from 0.95 to 1.05 in adjacent frames - whatever the delta
+time.
+
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGSensor : public FGFCSComponent
+{
+public:
+ FGSensor(FGFCS* fcs, Element* element);
+ ~FGSensor();
+
+ inline void SetFailLow(double val) {if (val > 0.0) fail_low = true; else fail_low = false;}
+ inline void SetFailHigh(double val) {if (val > 0.0) fail_high = true; else fail_high = false;}
+ inline void SetFailStuck(double val) {if (val > 0.0) fail_stuck = true; else fail_stuck = false;}
+
+ inline double GetFailLow(void) const {if (fail_low) return 1.0; else return 0.0;}
+ inline double GetFailHigh(void) const {if (fail_high) return 1.0; else return 0.0;}
+ inline double GetFailStuck(void) const {if (fail_stuck) return 1.0; else return 0.0;}
+
+ bool Run (void);
+
+private:
+ enum eNoiseType {ePercent=0, eAbsolute} NoiseType;
+ double dt;
+ double min, max;
+ double span;
+ double bias;
+ double drift_rate;
+ double drift;
+ double noise_variance;
+ double lag;
+ double granularity;
+ double ca; /// lag filter coefficient "a"
+ double cb; /// lag filter coefficient "b"
+ double PreviousOutput;
+ double PreviousInput;
+ int noise_type;
+ int bits;
+ int quantized;
+ int divisions;
+ bool fail_low;
+ bool fail_high;
+ bool fail_stuck;
+
+ void Noise(void);
+ void Bias(void);
+ void Drift(void);
+ void Quantize(void);
+ void Lag(void);
+
+ void bind(void);
+
+ void Debug(int from);
+};
+}
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGSummer.cpp
+ Author: Jon S. Berndt
+ Date started: 4/2000
+
+ ------------- Copyright (C) 2000 -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+COMMENTS, REFERENCES, and NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGSummer.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_SUMMER;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGSummer::FGSummer(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
+{
+ Bias = 0.0;
+
+ if (element->FindElement("bias")) Bias = element->FindElementValueAsNumber("bias");
+
+ FGFCSComponent::bind();
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGSummer::~FGSummer()
+{
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGSummer::Run(void )
+{
+ unsigned int idx;
+
+ Output = 0.0;
+
+ for (idx=0; idx<InputNodes.size(); idx++) {
+ Output += InputNodes[idx]->getDoubleValue() * InputSigns[idx];
+ }
+
+ Output += Bias;
+
+ Clip();
+ if (IsOutput) SetOutput();
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGSummer::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+ cout << " INPUTS: " << endl;
+ for (unsigned i=0;i<InputNodes.size();i++) {
+ if (InputSigns[i] < 0)
+ cout << " -" << InputNodes[i]->getName() << endl;
+ else
+ cout << " " << InputNodes[i]->getName() << endl;
+ }
+ if (Bias != 0.0) cout << " Bias: " << Bias << endl;
+ if (clip) cout << " CLIPTO: " << clipmin
+ << ", " << clipmax << endl;
+ if (IsOutput) cout << " OUTPUT: " <<OutputNode->getName() << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGSummer" << endl;
+ if (from == 1) cout << "Destroyed: FGSummer" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+
+} //namespace JSBSim
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGSummer.h
+ Author:
+ Date started:
+
+ ------------- Copyright (C) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGSUMMER_H
+#define FGSUMMER_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# ifdef SG_HAVE_STD_INCLUDES
+# include <vector>
+# else
+# include <vector.h>
+# endif
+#else
+# include <vector>
+#endif
+
+#include <string>
+#include "FGFCSComponent.h"
+#include <input_output/FGXMLElement.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_SUMMER "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models a flight control system summing component.
+ The Summer component sums two or more inputs. These can be pilot control
+ inputs or state variables, and a bias can also be added in using the BIAS
+ keyword. The form of the summer component specification is:
+<pre>
+ \<COMPONENT NAME="name" TYPE="SUMMER">
+ INPUT \<property>
+ INPUT \<property>
+ [BIAS \<value>]
+ [?]
+ [CLIPTO \<min> \<max> 1]
+ [OUTPUT \<property>]
+ \</COMPONENT>
+</pre>
+ Note that in the case of an input property the property name may be
+ immediately preceded by a minus sign. Here's an example of a summer
+ component specification:
+<pre>
+ \<COMPONENT NAME="Roll A/P Error summer" TYPE="SUMMER">
+ INPUT velocities/p-rad_sec
+ INPUT -fcs/roll-ap-wing-leveler
+ INPUT fcs/roll-ap-error-integrator
+ CLIPTO -1 1
+ \</COMPONENT>
+</pre>
+ Note that there can be only one BIAS statement per component.
+
+ @author Jon S. Berndt
+ @version $Id$
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGSummer : public FGFCSComponent
+{
+public:
+ /** Constructor.
+ @param fcs a pointer to the parent FGFCS object.
+ @param AC_cfg a pointer to the configuration file object. */
+ FGSummer(FGFCS* fcs, Element* element);
+ /// Destructor
+ ~FGSummer();
+
+ /// The execution method for this FCS component.
+ bool Run(void);
+
+private:
+ double Bias;
+ void Debug(int from);
+};
+}
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGSwitch.cpp
+ Author: Jon S. Berndt
+ Date started: 4/2000
+
+ ------------- Copyright (C) 2000 -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+COMMENTS, REFERENCES, and NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+The SWITCH component is defined as follows (see the API documentation for more
+information):
+
+<COMPONENT NAME="switch1" TYPE="SWITCH">
+ <TEST LOGIC="{AND|OR|DEFAULT}" OUTPUT="{property|value}">
+ {property} {conditional} {property|value}
+ <CONDITION_GROUP LOGIC="{AND|OR}">
+ {property} {conditional} {property|value}
+ ...
+ </CONDITION_GROUP>
+ ...
+ </TEST>
+ <TEST LOGIC="{AND|OR}" OUTPUT="{property|value}">
+ {property} {conditional} {property|value}
+ ...
+ </TEST>
+ ...
+</COMPONENT>
+
+Also, see the header file (FGSwitch.h) for further details.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGSwitch.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_SWITCH;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGSwitch::FGSwitch(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
+{
+ string value, logic;
+ struct test *current_test;
+ Element *test_element, *condition_element;
+
+ test_element = element->GetElement();
+ while (test_element) {
+ if (test_element->GetName() == "default") {
+ tests.push_back(test());
+ current_test = &tests.back();
+ current_test->Logic = eDefault;
+ } else if (test_element->GetName() == "test") { // here's a test
+ tests.push_back(test());
+ current_test = &tests.back();
+ logic = test_element->GetAttributeValue("logic");
+ if (logic == "OR") current_test->Logic = eOR;
+ else if (logic == "AND") current_test->Logic = eAND;
+ else if (logic.size() == 0) current_test->Logic == eAND; // default
+ else { // error
+ cerr << "Unrecognized LOGIC token " << logic << " in switch component: " << Name << endl;
+ }
+ for (int i=0; i<test_element->GetNumDataLines(); i++)
+ current_test->conditions.push_back(FGCondition(test_element->GetDataLine(i), PropertyManager));
+
+ condition_element = test_element->GetElement(); // retrieve condition groups
+ while (condition_element) {
+ current_test->conditions.push_back(FGCondition(condition_element, PropertyManager));
+ condition_element = test_element->GetNextElement();
+ }
+
+ }
+
+ if (test_element->GetName() != "output") { // this is not an output element
+ value = test_element->GetAttributeValue("value");
+ if (value.empty()) {
+ cerr << "No VALUE supplied for switch component: " << Name << endl;
+ } else {
+ if (value.find_first_not_of("-.0123456789eE") == string::npos) {
+ // if true (and execution falls into this block), "value" is a number.
+ current_test->OutputVal = atof(value.c_str());
+ } else {
+ // "value" must be a property if execution passes to here.
+ if (value[0] == '-') {
+ current_test->sign = -1.0;
+ value.erase(0,1);
+ } else {
+ current_test->sign = 1.0;
+ }
+ current_test->OutputProp = PropertyManager->GetNode(value);
+ }
+ }
+ }
+
+ test_element = element->GetNextElement();
+ }
+
+ FGFCSComponent::bind();
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGSwitch::~FGSwitch()
+{
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGSwitch::Run(void )
+{
+ vector <test>::iterator iTests = tests.begin();
+ vector <FGCondition>::iterator iConditions;
+ bool pass = false;
+
+ while (iTests < tests.end()) {
+ iConditions = iTests->conditions.begin();
+
+ if (iTests->Logic == eDefault) {
+ Output = iTests->GetValue();
+ } else if (iTests->Logic == eAND) {
+ pass = true;
+ while (iConditions < iTests->conditions.end()) {
+ if (!iConditions->Evaluate()) pass = false;
+ *iConditions++;
+ }
+ } else if (iTests->Logic == eOR) {
+ pass = false;
+ while (iConditions < iTests->conditions.end()) {
+ if (iConditions->Evaluate()) pass = true;
+ *iConditions++;
+ }
+ } else {
+ cerr << "Invalid logic test" << endl;
+ }
+
+ if (pass) {
+ Output = iTests->GetValue();
+ break;
+ }
+ *iTests++;
+ }
+
+ Clip();
+ if (IsOutput) SetOutput();
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGSwitch::Debug(int from)
+{
+ vector <test>::iterator iTests = tests.begin();
+ vector <FGCondition>::iterator iConditions;
+ string comp, scratch;
+ string indent = " ";
+ bool first = false;
+
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+ while (iTests < tests.end()) {
+
+ scratch = " if ";
+
+ switch(iTests->Logic) {
+ case (elUndef):
+ comp = " UNSET ";
+ cerr << "Unset logic for test condition" << endl;
+ break;
+ case (eAND):
+ comp = " AND ";
+ break;
+ case (eOR):
+ comp=" OR ";
+ break;
+ case (eDefault):
+ scratch = " by default.";
+ break;
+ default:
+ comp = " UNKNOWN ";
+ cerr << "Unknown logic for test condition" << endl;
+ }
+
+ if (iTests->OutputProp != 0L)
+ if (iTests->sign < 0)
+ cout << indent << "Switch VALUE is - " << iTests->OutputProp->GetName() << scratch << endl;
+ else
+ cout << indent << "Switch VALUE is " << iTests->OutputProp->GetName() << scratch << endl;
+ else
+ cout << indent << "Switch VALUE is " << iTests->OutputVal << scratch << endl;
+
+ iConditions = iTests->conditions.begin();
+ first = true;
+ while (iConditions < iTests->conditions.end()) {
+ if (!first) cout << indent << comp << " ";
+ else cout << indent << " ";
+ first = false;
+ iConditions->PrintCondition();
+ cout << endl;
+ *iConditions++;
+ }
+ cout << endl;
+ *iTests++;
+ }
+ if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGSwitch" << endl;
+ if (from == 1) cout << "Destroyed: FGSwitch" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+
+} //namespace JSBSim
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGSwitch.h
+ Author: Jon S. Berndt
+ Date started: 12/23/2002
+
+ ------------- Copyright (C) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGSWITCH_H
+#define FGSWITCH_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGFCSComponent.h"
+#include <input_output/FGXMLElement.h>
+#include "FGCondition.h"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_SWITCH "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Encapsulates a switch for the flight control system.
+
+The SWITCH component models a switch - either on/off or a multi-choice rotary
+switch. The switch can represent a physical cockpit switch, or can represent a
+logical switch, where several conditions might need to be satisfied before a
+particular state is reached. The VALUE of the switch - the output value for the
+component - is chosen depending on the state of the switch. Each switch is
+comprised of two or more TESTs. Each TEST has a VALUE associated with it. The
+first TEST that evaluates to TRUE will set the output value of the switch
+according to the VALUE parameter belonging to that TEST. Each TEST contains one
+or more CONDITIONS, which each must be logically related (if there are more than
+one) given the value of the LOGIC parameter, and which takes the form:
+
+ property conditional property|value
+
+e.g.
+
+ qbar GE 21.0
+
+or,
+
+ roll_rate < pitch_rate
+
+Within a TEST, a CONDITION_GROUP can be specified. A CONDITION_GROUP allows for
+complex groupings of logical comparisons. Each CONDITION_GROUP contains
+additional conditions, as well as possibly additional CONDITION_GROUPs.
+
+<pre>
+\<COMPONENT NAME="switch1" TYPE="SWITCH"\>
+ \<TEST LOGIC="{AND|OR|DEFAULT}" VALUE="{property|value}"\>
+ {property} {conditional} {property|value}
+ \<CONDITION_GROUP LOGIC="{AND|OR}"\>
+ {property} {conditional} {property|value}
+ ...
+ \</CONDITION_GROUP\>
+ ...
+ \</TEST>
+ \<TEST LOGIC="{AND|OR}" VALUE="{property|value}"\>
+ {property} {conditional} {property|value}
+ ...
+ \</TEST\>
+ ...
+ [OUTPUT \<property>]
+\</COMPONENT\>
+</pre>
+
+Here's an example:
+<pre>
+\<COMPONENT NAME="Roll A/P Autoswitch" TYPE="SWITCH">
+ \<TEST LOGIC="DEFAULT" VALUE="0.0">
+ \</TEST>
+ \<TEST LOGIC="AND" VALUE="fcs/roll-ap-error-summer">
+ ap/attitude_hold == 1
+ \</TEST>
+\</COMPONENT>
+</pre>
+The above example specifies that the default value of the component (i.e. the
+output property of the component, addressed by the property, ap/roll-ap-autoswitch)
+is 0.0. If or when the attitude hold switch is selected (property
+ap/attitude_hold takes the value 1), the value of the switch component will be
+whatever value fcs/roll-ap-error-summer is.
+@author Jon S. Berndt
+@version $Id$
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGSwitch : public FGFCSComponent
+{
+public:
+ FGSwitch(FGFCS* fcs, Element* element);
+ ~FGSwitch();
+
+ bool Run(void);
+
+ enum eLogic {elUndef=0, eAND, eOR, eDefault};
+ enum eComparison {ecUndef=0, eEQ, eNE, eGT, eGE, eLT, eLE};
+
+private:
+ FGFCS* fcs;
+
+ struct test {
+ vector <FGCondition> conditions;
+ eLogic Logic;
+ double OutputVal;
+ FGPropertyManager *OutputProp;
+ float sign;
+
+ double GetValue(void) {
+ if (OutputProp == 0L) return OutputVal;
+ else return OutputProp->getDoubleValue()*sign;
+ }
+
+ test(void) { // constructor for the test structure
+ Logic = elUndef;
+ OutputVal = 0.0;
+ OutputProp = 0L;
+ sign = 1.0;
+ }
+
+ };
+
+ vector <test> tests;
+
+ void Debug(int from);
+};
+}
+#endif
--- /dev/null
+noinst_LIBRARIES = libFlightControl.a
+
+libFlightControl_a_SOURCES = FGCondition.cpp FGDeadBand.cpp FGFCSComponent.cpp \
+ FGFilter.cpp FGGain.cpp FGGradient.cpp FGKinemat.cpp \
+ FGSummer.cpp FGSwitch.cpp FGFCSFunction.cpp FGSensor.cpp
+
+noinst_HEADERS = FGCondition.h FGDeadBand.h FGFCSComponent.h FGFilter.h \
+ FGGain.h FGGradient.h FGKinemat.h FGSummer.h FGSwitch.h FGFCSFunction.h \
+ FGSensor.h
+
+INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGElectric.cpp
+ Author: David Culp
+ Date started: 04/07/2004
+ Purpose: This module models an electric motor
+
+ --------- Copyright (C) 2004 David Culp (davidculp2@comcast.net) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+This class descends from the FGEngine class and models an electric motor based on
+parameters given in the engine config file for this class
+
+HISTORY
+--------------------------------------------------------------------------------
+04/07/2004 DPC Created
+01/06/2005 DPC Converted to new XML format
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGElectric.h"
+#include <models/FGPropulsion.h>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_ELECTRIC;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGElectric::FGElectric(FGFDMExec* exec, Element *el, int engine_number)
+ : FGEngine(exec, el, engine_number)
+{
+ string token;
+
+ Type = etElectric;
+ PowerWatts = 745.7;
+ hptowatts = 745.7;
+
+ dt = State->Getdt();
+
+ if (el->FindElement("power"))
+ PowerWatts = el->FindElementValueAsNumberConvertTo("power","WATTS");
+
+ Debug(0); // Call Debug() routine from constructor if needed
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGElectric::~FGElectric()
+{
+ Debug(1); // Call Debug() routine from constructor if needed
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGElectric::Calculate(void)
+{
+ Throttle = FCS->GetThrottlePos(EngineNumber);
+
+ RPM = Thruster->GetRPM() * Thruster->GetGearRatio();
+
+ HP = PowerWatts * Throttle / hptowatts;
+
+ PowerAvailable = (HP * hptoftlbssec) - Thruster->GetPowerRequired();
+
+ return Thruster->Calculate(PowerAvailable);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGElectric::GetEngineLabels(string delimeter)
+{
+ return ""; // currently no labels are returned for this engine
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGElectric::GetEngineValues(string delimeter)
+{
+ return ""; // currently no values are returned for this engine
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+//
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGElectric::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ cout << "\n Engine Name: " << Name << endl;
+ cout << " Power Watts: " << PowerWatts << endl;
+
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGElectric" << endl;
+ if (from == 1) cout << "Destroyed: FGElectric" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+
+double
+FGElectric::CalcFuelNeed(void)
+{
+ return 0;
+}
+
+} // namespace JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGElectric.h
+ Author: David Culp
+ Date started: 04/07/2004
+
+ ----- Copyright (C) 2004 David P. Culp (davidculp2@comcast.net) --------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+04/07/2004 DPC Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGELECTRIC_H
+#define FGELECTRIC_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGEngine.h"
+#include <input_output/FGXMLElement.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_ELECTRIC "$Id$";
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models and electric motor.
+ FGElectric models an electric motor based on the configuration file
+ POWER_WATTS parameter. The throttle controls motor output linearly from
+ zero to POWER_WATTS. This power value (converted internally to horsepower)
+ is then used by FGPropeller to apply torque to the propeller.
+ @author David Culp
+ @version "$Id$"
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGElectric : public FGEngine
+{
+public:
+ /// Constructor
+ FGElectric(FGFDMExec* exec, Element *el, int engine_number);
+ /// Destructor
+ ~FGElectric();
+
+ double Calculate(void);
+ double GetPowerAvailable(void) {return PowerAvailable;}
+ double CalcFuelNeed(void);
+ double getRPM(void) {return RPM;}
+ string GetEngineLabels(string delimeter);
+ string GetEngineValues(string delimeter);
+
+private:
+
+ double BrakeHorsePower;
+ double PowerAvailable;
+
+ // timestep
+ double dt;
+
+ // constants
+ double hptowatts;
+
+ double PowerWatts; // maximum engine power
+ double RPM; // revolutions per minute
+ double HP;
+
+ void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGEngine.cpp
+ Author: Jon Berndt
+ Date started: 01/21/99
+ Called by: FGAircraft
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+See header file.
+
+HISTORY
+--------------------------------------------------------------------------------
+01/21/99 JSB Created
+09/03/99 JSB Changed Rocket thrust equation to correct -= Thrust instead of
+ += Thrust (thanks to Tony Peden)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# ifdef SG_HAVE_STD_INCLUDES
+# include <fstream>
+# else
+# include <fstream.h>
+# endif
+#else
+# if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
+# include <fstream.h>
+# else
+# include <fstream>
+# endif
+#endif
+
+#include "FGEngine.h"
+#include "FGTank.h"
+#include "FGPropeller.h"
+#include "FGNozzle.h"
+#include <input_output/FGXMLParse.h>
+#include <math/FGColumnVector3.h>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_ENGINE;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number)
+ : EngineNumber(engine_number)
+{
+ Element* local_element;
+ FGColumnVector3 location, orientation;
+
+ Name = "";
+ Type = etUnknown;
+ X = Y = Z = 0.0;
+ EnginePitch = EngineYaw = 0.0;
+ SLFuelFlowMax = SLOxiFlowMax = 0.0;
+ MaxThrottle = 1.0;
+ MinThrottle = 0.0;
+ Thrust = 0.0;
+ Throttle = 0.0;
+ Mixture = 1.0;
+ Starter = false;
+ FuelNeed = OxidizerNeed = 0.0;
+ Starved = Running = Cranking = false;
+ PctPower = 0.0;
+ TrimMode = false;
+ FuelFlow_gph = 0.0;
+ FuelFlow_pph = 0.0;
+ FuelFreeze = false;
+
+ FDMExec = exec;
+ State = FDMExec->GetState();
+ Atmosphere = FDMExec->GetAtmosphere();
+ FCS = FDMExec->GetFCS();
+ Propulsion = FDMExec->GetPropulsion();
+ Aircraft = FDMExec->GetAircraft();
+ Propagate = FDMExec->GetPropagate();
+ Auxiliary = FDMExec->GetAuxiliary();
+
+ PropertyManager = FDMExec->GetPropertyManager();
+
+ Name = engine_element->GetAttributeValue("name");
+
+// Find and set engine location
+
+ local_element = engine_element->GetParent()->FindElement("location");
+ if (local_element) location = local_element->FindElementTripletConvertTo("IN");
+ else cerr << "No engine location found for this engine." << endl;
+
+ local_element = engine_element->GetParent()->FindElement("orient");
+ if (local_element) orientation = local_element->FindElementTripletConvertTo("IN");
+ else cerr << "No engine orientation found for this engine." << endl;
+
+ SetPlacement(location, orientation);
+
+ // Load thruster
+ local_element = engine_element->GetParent()->FindElement("thruster");
+ if (local_element) {
+ LoadThruster(local_element);
+ } else {
+ cerr << "No thruster definition supplied with engine definition." << endl;
+ }
+
+ // Load feed tank[s] references
+ local_element = engine_element->GetParent()->FindElement("feed");
+ if (local_element) {
+ while (local_element) {
+ AddFeedTank((int)local_element->GetDataAsNumber());
+ local_element = engine_element->GetParent()->FindNextElement("feed");
+ }
+ } else {
+ cerr << "No feed tank specified in engine definition." << endl;
+ }
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGEngine::~FGEngine()
+{
+ if (Thruster) delete Thruster;
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// This base class function should be called from within the
+// derived class' Calculate() function before any other calculations are done.
+// This base class method removes fuel from the fuel tanks as appropriate,
+// and sets the starved flag if necessary.
+
+void FGEngine::ConsumeFuel(void)
+{
+ if (FuelFreeze) return;
+ if (TrimMode) return;
+
+ unsigned int i;
+ double Fshortage, Oshortage, TanksWithFuel, TanksWithOxidizer;
+ FGTank* Tank;
+ bool haveOxTanks = false;
+ Fshortage = Oshortage = TanksWithFuel = TanksWithOxidizer = 0.0;
+
+ // count how many assigned tanks have fuel
+ for (i=0; i<SourceTanks.size(); i++) {
+ Tank = Propulsion->GetTank(SourceTanks[i]);
+ if (Tank->GetType() == FGTank::ttFUEL){
+ if (Tank->GetContents() > 0.0) ++TanksWithFuel;
+ } else if (Tank->GetType() == FGTank::ttOXIDIZER) {
+ haveOxTanks = true;
+ if (Tank->GetContents() > 0.0) ++TanksWithOxidizer;
+ }
+ }
+ if (TanksWithFuel==0 || (haveOxTanks && TanksWithOxidizer==0)) return;
+
+ for (i=0; i<SourceTanks.size(); i++) {
+ Tank = Propulsion->GetTank(SourceTanks[i]);
+ if (Tank->GetType() == FGTank::ttFUEL) {
+ Fshortage += Tank->Drain(CalcFuelNeed()/TanksWithFuel);
+ } else if (Tank->GetType() == FGTank::ttOXIDIZER) {
+ Oshortage += Tank->Drain(CalcOxidizerNeed()/TanksWithOxidizer);
+ }
+ }
+
+ if (Fshortage < 0.00 || Oshortage < 0.00) Starved = true;
+ else Starved = false;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGEngine::CalcFuelNeed(void)
+{
+ FuelNeed = SLFuelFlowMax*PctPower*State->Getdt()*Propulsion->GetRate();
+ return FuelNeed;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGEngine::CalcOxidizerNeed(void)
+{
+ OxidizerNeed = SLOxiFlowMax*PctPower*State->Getdt()*Propulsion->GetRate();
+ return OxidizerNeed;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGEngine::SetPlacement(FGColumnVector3& location, FGColumnVector3& orientation)
+{
+ X = location(eX);
+ Y = location(eY);
+ Z = location(eZ);
+ EnginePitch = orientation(ePitch);
+ EngineYaw = orientation (eYaw);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGEngine::AddFeedTank(int tkID)
+{
+ SourceTanks.push_back(tkID);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGColumnVector3& FGEngine::GetBodyForces(void)
+{
+ return Thruster->GetBodyForces();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGColumnVector3& FGEngine::GetMoments(void)
+{
+ return Thruster->GetMoments();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGEngine::LoadThruster(Element *thruster_element)
+{
+ string token, fullpath, localpath;
+ string thruster_filename, thruster_fullpathname, thrType;
+ double xLoc, yLoc, zLoc, Pitch, Yaw;
+ double P_Factor = 0, Sense = 0.0;
+ string enginePath = FDMExec->GetEnginePath();
+ string aircraftPath = FDMExec->GetAircraftPath();
+ FGXMLParse thruster_file_parser;
+ Element *document, *element;
+ ifstream thruster_file;
+ FGColumnVector3 location, orientation;
+
+# ifndef macintosh
+ string separator = "/";
+# else
+ string separator = ";";
+# endif
+
+ fullpath = enginePath + separator;
+ localpath = aircraftPath + separator + "Engines" + separator;
+
+ thruster_filename = thruster_element->GetAttributeValue("file");
+ if ( !thruster_filename.empty()) {
+ thruster_fullpathname = fullpath + thruster_filename + ".xml";
+ thruster_file.open(thruster_fullpathname.c_str());
+ if ( !thruster_file.is_open()) {
+ thruster_fullpathname = localpath + thruster_filename + ".xml";
+ thruster_file.open(thruster_fullpathname.c_str());
+ if ( !thruster_file.is_open()) {
+ cerr << "Could not open thruster file: " << thruster_filename << ".xml" << endl;
+ return false;
+ } else {
+ thruster_file.close();
+ }
+ } else {
+ thruster_file.close();
+ }
+ } else {
+ cerr << "No thruster filename given." << endl;
+ return false;
+ }
+
+ readXML(thruster_fullpathname, thruster_file_parser);
+ document = thruster_file_parser.GetDocument(); // document holds the thruster description
+ document->SetParent(thruster_element);
+
+ thrType = document->GetName();
+
+ if (thrType == "propeller") {
+ Thruster = new FGPropeller(FDMExec, document, EngineNumber);
+ } else if (thrType == "nozzle") {
+ Thruster = new FGNozzle(FDMExec, document, EngineNumber);
+ } else if (thrType == "direct") {
+ Thruster = new FGThruster( FDMExec, document, EngineNumber);
+ }
+
+ Thruster->SetdeltaT(State->Getdt() * Propulsion->GetRate());
+
+ Debug(2);
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGEngine::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ }
+ if (from == 2) { // After thruster loading
+ cout << " X = " << Thruster->GetLocationX() << endl;
+ cout << " Y = " << Thruster->GetLocationY() << endl;
+ cout << " Z = " << Thruster->GetLocationZ() << endl;
+ cout << " Pitch = " << Thruster->GetAnglesToBody(ePitch) << endl;
+ cout << " Yaw = " << Thruster->GetAnglesToBody(eYaw) << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGEngine" << endl;
+ if (from == 1) cout << "Destroyed: FGEngine" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGEngine.h
+ Author: Jon S. Berndt
+ Date started: 01/21/99
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+Based on Flightgear code, which is based on LaRCSim. This class simulates
+a generic engine.
+
+HISTORY
+--------------------------------------------------------------------------------
+01/21/99 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGENGINE_H
+#define FGENGINE_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# include STL_STRING
+ SG_USING_STD(string);
+# ifdef SG_HAVE_STD_INCLUDES
+# include <vector>
+# else
+# include <vector.h>
+# endif
+#else
+# include <vector>
+# include <string>
+#endif
+
+#include <FGJSBBase.h>
+#include "FGThruster.h"
+#include <input_output/FGPropertyManager.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_ENGINE "$Id$"
+
+using std::string;
+using std::vector;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+class FGFDMExec;
+class FGState;
+class FGAtmosphere;
+class FGFCS;
+class FGAircraft;
+class FGPropagate;
+class FGPropulsion;
+class FGAuxiliary;
+class FGThruster;
+class Element;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Base class for all engines.
+ This base class contains methods and members common to all engines, such as
+ logic to drain fuel from the appropriate tank, etc.
+ @author Jon S. Berndt
+ @version $Id$
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGEngine : public FGJSBBase
+{
+public:
+ FGEngine(FGFDMExec* exec, Element* el, int engine_number);
+ virtual ~FGEngine();
+
+ enum EngineType {etUnknown, etRocket, etPiston, etTurbine, etTurboprop, etElectric};
+
+ EngineType GetType(void) { return Type; }
+ virtual string GetName(void) { return Name; }
+
+ // Engine controls
+ virtual double GetThrottleMin(void) { return MinThrottle; }
+ virtual double GetThrottleMax(void) { return MaxThrottle; }
+ virtual double GetThrottle(void) { return Throttle; }
+ virtual double GetMixture(void) { return Mixture; }
+ virtual bool GetStarter(void) { return Starter; }
+
+ virtual double getFuelFlow_gph () const {return FuelFlow_gph;}
+ virtual double getFuelFlow_pph () const {return FuelFlow_pph;}
+ virtual double GetThrust(void) { return Thrust; }
+ virtual bool GetStarved(void) { return Starved; }
+ virtual bool GetRunning(void) { return Running; }
+ virtual bool GetCranking(void) { return Cranking; }
+
+ virtual void SetStarved(bool tt) { Starved = tt; }
+ virtual void SetStarved(void) { Starved = true; }
+
+ virtual void SetRunning(bool bb) { Running=bb; }
+ virtual void SetName(string name) { Name = name; }
+ virtual void AddFeedTank(int tkID);
+ virtual void SetFuelFreeze(bool f) { FuelFreeze = f; }
+
+ virtual void SetStarter(bool s) { Starter = s; }
+
+ /** Calculates the thrust of the engine, and other engine functions.
+ @return Thrust in pounds */
+ virtual double Calculate(void) {return 0.0;}
+
+ /** Reduces the fuel in the active tanks by the amount required.
+ This function should be called from within the
+ derived class' Calculate() function before any other calculations are
+ done. This base class method removes fuel from the fuel tanks as
+ appropriate, and sets the starved flag if necessary. */
+ virtual void ConsumeFuel(void);
+
+ /** The fuel need is calculated based on power levels and flow rate for that
+ power level. It is also turned from a rate into an actual amount (pounds)
+ by multiplying it by the delta T and the rate.
+ @return Total fuel requirement for this engine in pounds. */
+ virtual double CalcFuelNeed(void);
+
+ /** The oxidizer need is calculated based on power levels and flow rate for that
+ power level. It is also turned from a rate into an actual amount (pounds)
+ by multiplying it by the delta T and the rate.
+ @return Total oxidizer requirement for this engine in pounds. */
+ virtual double CalcOxidizerNeed(void);
+
+ /// Sets engine placement information
+ virtual void SetPlacement(FGColumnVector3& location, FGColumnVector3& orientation);
+
+ virtual double GetPowerAvailable(void) {return 0.0;};
+
+ virtual bool GetTrimMode(void) {return TrimMode;}
+ virtual void SetTrimMode(bool state) {TrimMode = state;}
+
+ virtual FGColumnVector3& GetBodyForces(void);
+ virtual FGColumnVector3& GetMoments(void);
+
+ bool LoadThruster(Element *el);
+ FGThruster* GetThruster(void) {return Thruster;}
+
+ virtual string GetEngineLabels(string delimeter) = 0;
+ virtual string GetEngineValues(string delimeter) = 0;
+
+protected:
+ FGPropertyManager* PropertyManager;
+ string Name;
+ const int EngineNumber;
+ EngineType Type;
+ double X, Y, Z;
+ double EnginePitch;
+ double EngineYaw;
+ double SLFuelFlowMax;
+ double SLOxiFlowMax;
+ double MaxThrottle;
+ double MinThrottle;
+
+ double Thrust;
+ double Throttle;
+ double Mixture;
+ double FuelNeed;
+ double OxidizerNeed;
+ double PctPower;
+ bool Starter;
+ bool Starved;
+ bool Running;
+ bool Cranking;
+ bool TrimMode;
+ bool FuelFreeze;
+
+ double FuelFlow_gph;
+ double FuelFlow_pph;
+
+ FGFDMExec* FDMExec;
+ FGState* State;
+ FGAtmosphere* Atmosphere;
+ FGFCS* FCS;
+ FGPropulsion* Propulsion;
+ FGAircraft* Aircraft;
+ FGPropagate* Propagate;
+ FGAuxiliary* Auxiliary;
+ FGThruster* Thruster;
+
+ vector <int> SourceTanks;
+ void Debug(int from);
+};
+}
+#include <FGState.h>
+#include <FGFDMExec.h>
+#include <models/FGAtmosphere.h>
+#include <models/FGFCS.h>
+#include <models/FGAircraft.h>
+#include <models/FGPropagate.h>
+#include <models/FGPropulsion.h>
+#include <models/FGAuxiliary.h>
+#include <models/propulsion/FGThruster.h>
+#include <input_output/FGXMLElement.h>
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Source: FGForce.cpp
+ Author: Tony Peden
+ Date started: 6/10/00
+
+ ------------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+
+ HISTORY
+--------------------------------------------------------------------------------
+6/10/00 TP Created
+
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+The purpose of this class is to provide storage for computed forces and
+encapsulate all the functionality associated with transforming those
+forces from their native coord system to the body system. This includes
+computing the moments due to the difference between the point of application
+and the cg.
+
+*/
+
+#include <FGFDMExec.h>
+#include <models/FGAircraft.h>
+#include <models/FGPropagate.h>
+#include <models/FGMassBalance.h>
+#include <FGState.h>
+#include "FGForce.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_FORCE;
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGForce::FGForce(FGFDMExec *FDMExec) :
+ ttype(tNone),
+ fdmex(FDMExec)
+{
+ mT(1,1) = 1; //identity matrix
+ mT(2,2) = 1;
+ mT(3,3) = 1;
+ vSense.InitMatrix(1);
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGForce::~FGForce()
+{
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGColumnVector3& FGForce::GetBodyForces(void)
+{
+ vFb = Transform()*(vFn.multElementWise(vSense));
+
+ // Find the distance from this vector's acting location to the cg; this
+ // needs to be done like this to convert from structural to body coords.
+ // CG and RP values are in inches
+
+ vDXYZ = fdmex->GetMassBalance()->StructuralToBody(vActingXYZn);
+
+ vM = vMn + vDXYZ*vFb;
+
+ return vFb;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGMatrix33 FGForce::Transform(void)
+{
+ switch(ttype) {
+ case tWindBody:
+ return fdmex->GetState()->GetTs2b();
+ case tLocalBody:
+ return fdmex->GetPropagate()->GetTl2b();
+ case tCustom:
+ case tNone:
+ return mT;
+ default:
+ cout << "Unrecognized tranform requested from FGForce::Transform()" << endl;
+ exit(1);
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGForce::SetAnglesToBody(double broll, double bpitch, double byaw)
+{
+ if (ttype == tCustom) {
+ double cp,sp,cr,sr,cy,sy;
+ vOrient(ePitch) = bpitch;
+ vOrient(eRoll) = broll;
+ vOrient(eYaw) = byaw;
+
+ cp=cos(bpitch); sp=sin(bpitch);
+ cr=cos(broll); sr=sin(broll);
+ cy=cos(byaw); sy=sin(byaw);
+
+ mT(1,1)=cp*cy;
+ mT(1,2)=cp*sy;
+ mT(1,3)=-1*sp;
+
+ mT(2,1)=sr*sp*cy-cr*sy;
+ mT(2,2)=sr*sp*sy+cr*cy;
+ mT(2,3)=sr*cp;
+
+ mT(3,1)=cr*sp*cy+sr*sy;
+ mT(3,2)=cr*sp*sy-sr*cy;
+ mT(3,3)=cr*cp;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGForce::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGForce" << endl;
+ if (from == 1) cout << "Destroyed: FGForce" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGForce.h
+ Author: Tony Peden
+ Date started: 5/20/00
+
+ ------------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+
+ HISTORY
+--------------------------------------------------------------------------------
+5/20/00 TP Created
+
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+The purpose of this class is to provide storage for computed forces and
+encapsulate all the functionality associated with transforming those
+forces from their native coord system to the body system. This includes
+computing the moments due to the difference between the point of application
+and the cg.
+
+CAVEAT: if the custom transform is used for wind-to-body transforms then the
+ user *must* always pass this class the negative of beta. This is true
+ because sideslip angle does not follow the right hand rule i.e. it is
+ positive for aircraft nose left sideslip. Note that use of the custom
+ transform for this purpose shouldn't be necessary as it is already
+ provided by SetTransform(tWindBody) and is not subject to the same
+ restriction.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGFORCE_H
+#define FGFORCE_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <FGFDMExec.h>
+#include <FGJSBBase.h>
+#include <math/FGMatrix33.h>
+#include <math/FGColumnVector3.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_FORCE "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Utility class that aids in the conversion of forces between coordinate systems
+ and calculation of moments.
+<br><h3>Resolution of Applied Forces into Moments and Body Axes Components</h3>
+<br><p>
+All forces acting on the aircraft that cannot be considered a change in weight
+need to be resolved into body axis components so that the aircraft acceleration
+vectors, both translational and rotational, can be computed. Furthermore, the
+moments produced by each force that does not act at a location corresponding to
+the center of gravity also need to be computed. Unfortunately, the math required
+to do this can be a bit messy and errors are easily introduced so the class
+FGForce was created to provide these services in a consistent and reusable
+manner.<br><br></p>
+
+<h4>Basic usage</h4>
+
+<p>FGForce requires that its users supply it with the location of the applied
+force vector in JSBSim structural coordinates, the sense of each axis in that
+coordinate system relative to the body system, the orientation of the vector
+also relative to body coordinates and, of course, the force vector itself. With
+this information it will compute both the body axis force components and the
+resulting moments. Any moments inherently produced by the native system can be
+supplied as well and they will be summed with those computed.</p>
+
+<p>A good example for demonstrating the use of this class are the aerodynamic
+forces: lift, drag, and side force and the aerodynamic moments about the pitch,
+roll and yaw axes. These "native" forces and moments are computed and stored
+in the FGColumnVector objects vFs and vMoments. Their native coordinate system
+is often referred to as the wind system and is defined as a right-handed system
+having its x-axis aligned with the relative velocity vector and pointing towards
+the rear of the aircraft , the y-axis extending out the right wing, and the
+z-axis directed upwards. This is different than body axes; they are defined such
+that the x-axis is lies on the aircraft's roll axis and positive forward, the
+y-axis is positive out the right wing, and the z-axis is positive downwards. In
+this instance, JSBSim already provides the needed transform and FGForce can make
+use of it by calling SetTransformType() once an object is created:</p>
+
+<p><tt>FGForce fgf(FDMExec);</tt><br>
+<tt>fgf.SetTransformType(tWindBody);</tt><br><br>
+
+This call need only be made once for each object. The available transforms are
+defined in the enumerated type TransformType and are tWindBody, tLocalBody,
+tCustom, and tNone. The local-to-body transform, like the wind-to-body, also
+makes use of that already available in JSBSim. tNone sets FGForce to do no
+angular transform at all, and tCustom allows for modeling force vectors at
+arbitrary angles relative to the body system such as that produced by propulsion
+systems. Setting up and using a custom transform is covered in more detail below.
+Continuing with the example, the point of application of the aerodynamic forces,
+the aerodynamic reference point in JSBSim, also needs to be set:</p>
+<p><tt>
+fgf.SetLocation(x, y, z)</tt></p>
+
+<p>where x, y, and z are in JSBSim structural coordinates.</p>
+
+<p>Initialization is complete and the FGForce object is ready to do its job. As
+stated above, the lift, drag, and side force are computed and stored in the
+vector vFs and need to be passed to FGForce:</p>
+
+<p><tt>fgf.SetNativeForces(vFs);</tt> </p>
+
+<p>The same applies to the aerodynamic pitching, rolling and yawing moments:</p>
+
+<p><tt>fgf.SetNativeMoments(vMoments);</tt></p>
+
+<p>Note that storing the native forces and moments outside of this class is not
+strictly necessary, overloaded SetNativeForces() and SetNativeMoments() methods
+which each accept three doubles (rather than a vector) are provided and can be
+repeatedly called without incurring undue overhead. The body axes force vector
+can now be retrieved by calling:</p>
+
+<p><tt>vFb=fgf.GetBodyForces();</tt></p>
+
+<p>This method is where the bulk of the work gets done so calling it more than
+once for the same set of native forces and moments should probably be avoided.
+Note that the moment calculations are done here as well so they should not be
+retrieved after calling the GetBodyForces() method:</p>
+
+<p><tt>vM=fgf.GetMoments();</tt> </p>
+
+<p>As an aside, the native moments are not needed to perform the computations
+correctly so, if the FGForce object is not being used to store them then an
+alternate approach is to avoid the SetNativeMoments call and perform the sum</p>
+
+<p><tt>vMoments+=fgf.GetMoments();</tt> <br><br>
+
+after the forces have been retrieved. </p>
+
+<h4>Use of the Custom Transform Type</h4>
+
+<p>In cases where the native force vector is not aligned with the body, wind, or
+local coordinate systems a custom transform type is provided. A vectorable engine
+nozzle will be used to demonstrate its usage. Initialization is much the same:</p>
+
+<p><tt>FGForce fgf(FDMExec);</tt> <br>
+<tt>fgf.SetTransformType(tCustom);</tt> <br>
+<tt>fgf.SetLocation(x,y,z);</tt> </p>
+
+<p>Except that here the tCustom transform type is specified and the location of
+the thrust vector is used rather than the aerodynamic reference point. Thrust is
+typically considered to be positive when directed aft while the body x-axis is
+positive forward and, if the native system is right handed, the z-axis will be
+reversed as well. These differences in sense need to be specified using by the
+call: </p>
+
+<p><tt>fgf.SetSense(-1,1,-1);</tt></p>
+
+<p>The angles are specified by calling the method: </p>
+
+<p><tt>fgf.SetAnglesToBody(pitch, roll, yaw);</tt> </p>
+
+<p>in which the transform matrix is computed. Note that these angles should be
+taken relative to the body system and not the local as the names might suggest.
+For an aircraft with vectorable thrust, this method will need to be called
+every time the nozzle angle changes, a fixed engine/nozzle installation, on the
+other hand, will require it to be be called only once.</p>
+
+<p>Retrieval of the computed forces and moments is done as detailed above.</p>
+<br>
+<blockquote>
+ <p><i>CAVEAT: If the custom system is used to compute
+ the wind-to-body transform, then the sign of the sideslip
+ angle must be reversed when calling SetAnglesToBody().
+ This is true because sideslip angle does not follow the right
+ hand rule. Using the custom transform type this way
+ should not be necessary, as it is already provided as a built
+ in type (and the sign differences are correctly accounted for).</i>
+ <br></p>
+</blockquote>
+
+<h4>Use as a Base Type</h4>
+
+<p>For use as a base type, the native force and moment vector data members are
+defined as protected. In this case the SetNativeForces() and SetNativeMoments()
+methods need not be used and, instead, the assignments to vFn, the force vector,
+and vMn, the moments, can be made directly. Otherwise, the usage is similar.<br>
+<br><br></p>
+
+ @author Tony Peden
+ @version $Id$
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGForce : public FGJSBBase
+{
+public:
+ /// Constructor
+ FGForce(FGFDMExec *FDMExec);
+ /// Destructor
+ ~FGForce();
+
+ enum TransformType { tNone, tWindBody, tLocalBody, tCustom } ttype;
+
+ inline void SetNativeForces(double Fnx, double Fny, double Fnz) {
+ vFn(1)=Fnx;
+ vFn(2)=Fny;
+ vFn(3)=Fnz;
+ }
+ inline void SetNativeForces(FGColumnVector3 vv) { vFn = vv; };
+
+ inline void SetNativeMoments(double Ln,double Mn, double Nn) {
+ vMn(1)=Ln;
+ vMn(2)=Mn;
+ vMn(3)=Nn;
+ }
+ inline void SetNativeMoments(FGColumnVector3 vv) { vMn = vv; }
+
+ inline FGColumnVector3& GetNativeForces(void) { return vFn; }
+ inline FGColumnVector3& GetNativeMoments(void) { return vMn; }
+
+ FGColumnVector3& GetBodyForces(void);
+
+ inline FGColumnVector3& GetMoments(void) { return vM; }
+
+ // Normal point of application, JSBsim structural coords
+ // (inches, x +back, y +right, z +up)
+ inline void SetLocation(double x, double y, double z) {
+ vXYZn(eX) = x;
+ vXYZn(eY) = y;
+ vXYZn(eZ) = z;
+ SetActingLocation(x, y, z);
+ }
+
+ /** Acting point of application.
+ JSBsim structural coords used (inches, x +back, y +right, z +up).
+ This function sets the point at which the force acts - this may
+ not be the same as where the object resides. One area where this
+ is true is P-Factor modeling.
+ @param x acting location of force
+ @param y acting location of force
+ @param z acting location of force */
+ inline void SetActingLocation(double x, double y, double z) {
+ vActingXYZn(eX) = x;
+ vActingXYZn(eY) = y;
+ vActingXYZn(eZ) = z;
+ }
+ inline void SetLocationX(double x) {vXYZn(eX) = x; vActingXYZn(eX) = x;}
+ inline void SetLocationY(double y) {vXYZn(eY) = y; vActingXYZn(eY) = y;}
+ inline void SetLocationZ(double z) {vXYZn(eZ) = z; vActingXYZn(eZ) = z;}
+ inline double SetActingLocationX(double x) {vActingXYZn(eX) = x; return x;}
+ inline double SetActingLocationY(double y) {vActingXYZn(eY) = y; return y;}
+ inline double SetActingLocationZ(double z) {vActingXYZn(eZ) = z; return z;}
+ inline void SetLocation(FGColumnVector3 vv) { vXYZn = vv; SetActingLocation(vv);}
+ inline void SetActingLocation(FGColumnVector3 vv) { vActingXYZn = vv; }
+
+ inline double GetLocationX( void ) { return vXYZn(eX);}
+ inline double GetLocationY( void ) { return vXYZn(eY);}
+ inline double GetLocationZ( void ) { return vXYZn(eZ);}
+ inline double GetActingLocationX( void ) { return vActingXYZn(eX);}
+ inline double GetActingLocationY( void ) { return vActingXYZn(eY);}
+ inline double GetActingLocationZ( void ) { return vActingXYZn(eZ);}
+ FGColumnVector3& GetLocation(void) { return vXYZn; }
+ FGColumnVector3& GetActingLocation(void) { return vActingXYZn; }
+
+ //these angles are relative to body axes, not earth!!!!!
+ //I'm using these because pitch, roll, and yaw are easy to visualize,
+ //there's no equivalent to roll in wind axes i.e. alpha, ? , beta
+ //making up new names or using these is a toss-up: either way people
+ //are going to get confused.
+ //They are in radians.
+
+ void SetAnglesToBody(double broll, double bpitch, double byaw);
+ inline void SetAnglesToBody(FGColumnVector3 vv) {
+ SetAnglesToBody(vv(eRoll), vv(ePitch), vv(eYaw));
+ }
+
+ inline void SetSense(double x, double y, double z) { vSense(eX)=x, vSense(eY)=y, vSense(eZ)=z; }
+ inline void SetSense(FGColumnVector3 vv) { vSense=vv; }
+
+ inline FGColumnVector3& GetAnglesToBody(void) {return vOrient;}
+ inline double GetAnglesToBody(int axis) {return vOrient(axis);}
+ inline FGColumnVector3& GetSense(void) { return vSense; }
+
+ inline void SetTransformType(TransformType ii) { ttype=ii; }
+ inline TransformType GetTransformType(void) { return ttype; }
+
+ FGMatrix33 Transform(void);
+
+protected:
+ FGFDMExec *fdmex;
+ FGColumnVector3 vFn;
+ FGColumnVector3 vMn;
+ FGColumnVector3 vH;
+ FGColumnVector3 vOrient;
+
+private:
+ FGColumnVector3 vFb;
+ FGColumnVector3 vM;
+ FGColumnVector3 vXYZn;
+ FGColumnVector3 vActingXYZn;
+ FGColumnVector3 vDXYZ;
+ FGColumnVector3 vSense;
+
+ FGMatrix33 mT;
+
+ void Debug(int from);
+};
+}
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGNozzle.cpp
+ Author: Jon S. Berndt
+ Date started: 08/24/00
+ Purpose: Encapsulates the nozzle object
+
+ ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+08/24/00 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <sstream>
+
+#include "FGNozzle.h"
+#include <models/FGAtmosphere.h>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_NOZZLE;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+FGNozzle::FGNozzle(FGFDMExec* FDMExec, Element* nozzle_element, int num) : FGThruster(FDMExec)
+{
+
+ if (nozzle_element->FindElement("pe"))
+ PE = nozzle_element->FindElementValueAsNumberConvertTo("pe", "PSF");
+ else {
+ cerr << "Fatal Error: Nozzle exit pressure must be given in nozzle config file." << endl;
+ exit(-1);
+ }
+ if (nozzle_element->FindElement("expr"))
+ ExpR = nozzle_element->FindElementValueAsNumber("expr");
+ else {
+ cerr << "Fatal Error: Nozzle expansion ratio must be given in nozzle config file." << endl;
+ exit(-1);
+ }
+ if (nozzle_element->FindElement("nzl_eff"))
+ nzlEff = nozzle_element->FindElementValueAsNumber("nzl_eff");
+ else {
+ cerr << "Fatal Error: Nozzle efficiency must be given in nozzle config file." << endl;
+ exit(-1);
+ }
+ if (nozzle_element->FindElement("diam"))
+ Diameter = nozzle_element->FindElementValueAsNumberConvertTo("diam", "FT");
+ else {
+ cerr << "Fatal Error: Nozzle diameter must be given in nozzle config file." << endl;
+ exit(-1);
+ }
+
+ Thrust = 0;
+ ReverserAngle = 0.0;
+ Type = ttNozzle;
+ Area2 = (Diameter*Diameter/4.0)*M_PI;
+ AreaT = Area2/ExpR;
+
+// char property_name[80];
+// snprintf(property_name, 80, "propulsion/c-thrust[%u]", EngineNum);
+// PropertyManager->Tie( property_name, &ThrustCoeff );
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGNozzle::~FGNozzle()
+{
+// char property_name[80];
+// snprintf(property_name, 80, "propulsion/c-thrust[%u]", EngineNum);
+// PropertyManager->Untie( property_name );
+
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGNozzle::Calculate(double CfPc)
+{
+ double pAtm = fdmex->GetAtmosphere()->GetPressure();
+ Thrust = max((double)0.0, (CfPc * AreaT + (PE - pAtm)*Area2) * nzlEff);
+ vFn(1) = Thrust * cos(ReverserAngle);
+
+ ThrustCoeff = max((double)0.0, CfPc / ((pAtm - PE) * Area2));
+
+ return Thrust;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGNozzle::GetPowerRequired(void)
+{
+ return PE;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGNozzle::GetThrusterLabels(int id, string delimeter)
+{
+ std::ostringstream buf;
+
+ buf << Name << "_Thrust[" << id << ']';
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGNozzle::GetThrusterValues(int id, string delimeter)
+{
+ std::ostringstream buf;
+
+ buf << Thrust;
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGNozzle::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+ cout << " Nozzle Name: " << Name << endl;
+ cout << " Nozzle Exit Pressure = " << PE << endl;
+ cout << " Nozzle Expansion Ratio = " << ExpR << endl;
+ cout << " Nozzle Efficiency = " << nzlEff << endl;
+ cout << " Nozzle Diameter = " << Diameter << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGNozzle" << endl;
+ if (from == 1) cout << "Destroyed: FGNozzle" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGNozzle.h
+ Author: Jon S. Berndt
+ Date started: 08/24/00
+
+ ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+08/24/00 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGNOZZLE_H
+#define FGNOZZLE_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGThruster.h"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_NOZZLE "$Id$";
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models a rocket nozzle.
+ @author Jon S. Berndt
+ @version $Id$
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGNozzle : public FGThruster {
+
+public:
+ /// Constructor
+ FGNozzle(FGFDMExec* exec, Element* el, int num = 0);
+ /// Destructor
+ ~FGNozzle();
+
+ double Calculate(double CfPc);
+ double GetPowerRequired(void);
+ string GetThrusterLabels(int id, string delimeter);
+ string GetThrusterValues(int id, string delimeter);
+
+private:
+ double ReverserAngle;
+ double PE;
+ double ExpR;
+ double nzlEff;
+ double Diameter;
+ double AreaT;
+ double Area2;
+ void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGPiston.cpp
+ Author: Jon S. Berndt, JSBSim framework
+ Dave Luff, Piston engine model
+ Date started: 09/12/2000
+ Purpose: This module models a Piston engine
+
+ ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) --------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+This class descends from the FGEngine class and models a Piston engine based on
+parameters given in the engine config file for this class
+
+HISTORY
+--------------------------------------------------------------------------------
+09/12/2000 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <sstream>
+
+#include "FGPiston.h"
+#include <models/FGPropulsion.h>
+#include "FGPropeller.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_PISTON;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number)
+ : FGEngine(exec, el, engine_number),
+ R_air(287.3), // Gas constant for air J/Kg/K
+ rho_fuel(800), // estimate
+ calorific_value_fuel(47.3e6),
+ Cp_air(1005), // Specific heat (constant pressure) J/Kg/K
+ Cp_fuel(1700)
+{
+ string token;
+
+ // Defaults and initializations
+
+ Type = etPiston;
+
+ // These items are read from the configuration file
+
+ Cycles = 2;
+ IdleRPM = 600;
+ Displacement = 360;
+ MaxHP = 200;
+ MinManifoldPressure_inHg = 6.5;
+ MaxManifoldPressure_inHg = 28.5;
+
+ // These are internal program variables
+
+ crank_counter = 0;
+ OilTemp_degK = 298;
+ ManifoldPressure_inHg = Atmosphere->GetPressure() * psftoinhg; // psf to in Hg
+ minMAP = 21950;
+ maxMAP = 96250;
+ MAP = Atmosphere->GetPressure() * psftopa;
+ CylinderHeadTemp_degK = 0.0;
+ Magnetos = 0;
+ ExhaustGasTemp_degK = 0.0;
+ EGT_degC = 0.0;
+
+ dt = State->Getdt();
+
+ // Supercharging
+ BoostSpeeds = 0; // Default to no supercharging
+ BoostSpeed = 0;
+ Boosted = false;
+ BoostOverride = 0;
+ bBoostOverride = false;
+ bTakeoffBoost = false;
+ TakeoffBoost = 0.0; // Default to no extra takeoff-boost
+ int i;
+ for (i=0; i<FG_MAX_BOOST_SPEEDS; i++) {
+ RatedBoost[i] = 0.0;
+ RatedPower[i] = 0.0;
+ RatedAltitude[i] = 0.0;
+ BoostMul[i] = 1.0;
+ RatedMAP[i] = 100000;
+ RatedRPM[i] = 2500;
+ TakeoffMAP[i] = 100000;
+ }
+ for (i=0; i<FG_MAX_BOOST_SPEEDS-1; i++) {
+ BoostSwitchAltitude[i] = 0.0;
+ BoostSwitchPressure[i] = 0.0;
+ }
+ // Initialisation
+ volumetric_efficiency = 0.8; // Actually f(speed, load) but this will get us running
+
+ // First column is thi, second is neta (combustion efficiency)
+ Lookup_Combustion_Efficiency = new FGTable(12);
+ *Lookup_Combustion_Efficiency << 0.00 << 0.980;
+ *Lookup_Combustion_Efficiency << 0.90 << 0.980;
+ *Lookup_Combustion_Efficiency << 1.00 << 0.970;
+ *Lookup_Combustion_Efficiency << 1.05 << 0.950;
+ *Lookup_Combustion_Efficiency << 1.10 << 0.900;
+ *Lookup_Combustion_Efficiency << 1.15 << 0.850;
+ *Lookup_Combustion_Efficiency << 1.20 << 0.790;
+ *Lookup_Combustion_Efficiency << 1.30 << 0.700;
+ *Lookup_Combustion_Efficiency << 1.40 << 0.630;
+ *Lookup_Combustion_Efficiency << 1.50 << 0.570;
+ *Lookup_Combustion_Efficiency << 1.60 << 0.525;
+ *Lookup_Combustion_Efficiency << 2.00 << 0.345;
+
+ Power_Mixture_Correlation = new FGTable(13);
+ *Power_Mixture_Correlation << (14.7/1.6) << 78.0;
+ *Power_Mixture_Correlation << 10 << 86.0;
+ *Power_Mixture_Correlation << 11 << 93.5;
+ *Power_Mixture_Correlation << 12 << 98.0;
+ *Power_Mixture_Correlation << 13 << 100.0;
+ *Power_Mixture_Correlation << 14 << 99.0;
+ *Power_Mixture_Correlation << 15 << 96.4;
+ *Power_Mixture_Correlation << 16 << 92.5;
+ *Power_Mixture_Correlation << 17 << 88.0;
+ *Power_Mixture_Correlation << 18 << 83.0;
+ *Power_Mixture_Correlation << 19 << 78.5;
+ *Power_Mixture_Correlation << 20 << 74.0;
+ *Power_Mixture_Correlation << (14.7/0.6) << 58;
+
+ // Read inputs from engine data file where present.
+
+ if (el->FindElement("minmp")) // Should have ELSE statement telling default value used?
+ MinManifoldPressure_inHg = el->FindElementValueAsNumberConvertTo("minmp","INHG");
+ if (el->FindElement("maxmp"))
+ MaxManifoldPressure_inHg = el->FindElementValueAsNumberConvertTo("maxmp","INHG");
+ if (el->FindElement("displacement"))
+ Displacement = el->FindElementValueAsNumberConvertTo("displacement","IN3");
+ if (el->FindElement("maxhp"))
+ MaxHP = el->FindElementValueAsNumberConvertTo("maxhp","HP");
+ if (el->FindElement("cycles"))
+ Cycles = el->FindElementValueAsNumber("cycles");
+ if (el->FindElement("idlerpm"))
+ IdleRPM = el->FindElementValueAsNumber("idlerpm");
+ if (el->FindElement("maxthrottle"))
+ MaxThrottle = el->FindElementValueAsNumber("maxthrottle");
+ if (el->FindElement("minthrottle"))
+ MinThrottle = el->FindElementValueAsNumber("minthrottle");
+ if (el->FindElement("numboostspeeds")) { // Turbo- and super-charging parameters
+ BoostSpeeds = (int)el->FindElementValueAsNumber("numboostspeeds");
+ if (el->FindElement("boostoverride"))
+ BoostOverride = (int)el->FindElementValueAsNumber("boostoverride");
+ if (el->FindElement("takeoffboost"))
+ TakeoffBoost = el->FindElementValueAsNumberConvertTo("takeoffboost", "PSI");
+ if (el->FindElement("ratedboost1"))
+ RatedBoost[0] = el->FindElementValueAsNumberConvertTo("ratedboost1", "PSI");
+ if (el->FindElement("ratedboost2"))
+ RatedBoost[1] = el->FindElementValueAsNumberConvertTo("ratedboost2", "PSI");
+ if (el->FindElement("ratedboost3"))
+ RatedBoost[2] = el->FindElementValueAsNumberConvertTo("ratedboost3", "PSI");
+ if (el->FindElement("ratedpower1"))
+ RatedPower[0] = el->FindElementValueAsNumberConvertTo("ratedpower1", "HP");
+ if (el->FindElement("ratedpower2"))
+ RatedPower[1] = el->FindElementValueAsNumberConvertTo("ratedpower2", "HP");
+ if (el->FindElement("ratedpower3"))
+ RatedPower[2] = el->FindElementValueAsNumberConvertTo("ratedpower3", "HP");
+ if (el->FindElement("ratedrpm1"))
+ RatedRPM[0] = el->FindElementValueAsNumber("ratedrpm1");
+ if (el->FindElement("ratedrpm2"))
+ RatedRPM[1] = el->FindElementValueAsNumber("ratedrpm2");
+ if (el->FindElement("ratedrpm3"))
+ RatedRPM[2] = el->FindElementValueAsNumber("ratedrpm3");
+ if (el->FindElement("ratedaltitude1"))
+ RatedAltitude[0] = el->FindElementValueAsNumberConvertTo("ratedaltitude1", "FT");
+ if (el->FindElement("ratedaltitude2"))
+ RatedAltitude[1] = el->FindElementValueAsNumberConvertTo("ratedaltitude2", "FT");
+ if (el->FindElement("ratedaltitude3"))
+ RatedAltitude[2] = el->FindElementValueAsNumberConvertTo("ratedaltitude3", "FT");
+ }
+ minMAP = MinManifoldPressure_inHg * 3376.85; // inHg to Pa
+ maxMAP = MaxManifoldPressure_inHg * 3376.85;
+
+ // Set up and sanity-check the turbo/supercharging configuration based on the input values.
+ if (TakeoffBoost > RatedBoost[0]) bTakeoffBoost = true;
+ for (i=0; i<BoostSpeeds; ++i) {
+ bool bad = false;
+ if (RatedBoost[i] <= 0.0) bad = true;
+ if (RatedPower[i] <= 0.0) bad = true;
+ if (RatedAltitude[i] < 0.0) bad = true; // 0.0 is deliberately allowed - this corresponds to unregulated supercharging.
+ if (i > 0 && RatedAltitude[i] < RatedAltitude[i - 1]) bad = true;
+ if (bad) {
+ // We can't recover from the above - don't use this supercharger speed.
+ BoostSpeeds--;
+ // TODO - put out a massive error message!
+ break;
+ }
+ // Now sanity-check stuff that is recoverable.
+ if (i < BoostSpeeds - 1) {
+ if (BoostSwitchAltitude[i] < RatedAltitude[i]) {
+ // TODO - put out an error message
+ // But we can also make a reasonable estimate, as below.
+ BoostSwitchAltitude[i] = RatedAltitude[i] + 1000;
+ }
+ BoostSwitchPressure[i] = Atmosphere->GetPressure(BoostSwitchAltitude[i]) * psftopa;
+ //cout << "BoostSwitchAlt = " << BoostSwitchAltitude[i] << ", pressure = " << BoostSwitchPressure[i] << '\n';
+ // Assume there is some hysteresis on the supercharger gear switch, and guess the value for now
+ BoostSwitchHysteresis = 1000;
+ }
+ // Now work out the supercharger pressure multiplier of this speed from the rated boost and altitude.
+ RatedMAP[i] = Atmosphere->GetPressureSL() * psftopa + RatedBoost[i] * 6895; // psi*6895 = Pa.
+ // Sometimes a separate BCV setting for takeoff or extra power is fitted.
+ if (TakeoffBoost > RatedBoost[0]) {
+ // Assume that the effect on the BCV is the same whichever speed is in use.
+ TakeoffMAP[i] = RatedMAP[i] + ((TakeoffBoost - RatedBoost[0]) * 6895);
+ bTakeoffBoost = true;
+ } else {
+ TakeoffMAP[i] = RatedMAP[i];
+ bTakeoffBoost = false;
+ }
+ BoostMul[i] = RatedMAP[i] / (Atmosphere->GetPressure(RatedAltitude[i]) * psftopa);
+
+ }
+
+ if (BoostSpeeds > 0) {
+ Boosted = true;
+ BoostSpeed = 0;
+ }
+ bBoostOverride = (BoostOverride == 1 ? true : false);
+
+ Debug(0); // Call Debug() routine from constructor if needed
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGPiston::~FGPiston()
+{
+ Debug(1); // Call Debug() routine from constructor if needed
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGPiston::Calculate(void)
+{
+ if (FuelFlow_gph > 0.0) ConsumeFuel();
+
+ Throttle = FCS->GetThrottlePos(EngineNumber);
+ Mixture = FCS->GetMixturePos(EngineNumber);
+
+ //
+ // Input values.
+ //
+
+ p_amb = Atmosphere->GetPressure() * psftopa;
+ p_amb_sea_level = Atmosphere->GetPressureSL() * psftopa;
+ T_amb = Atmosphere->GetTemperature() * (5.0 / 9.0); // convert from Rankine to Kelvin
+
+ RPM = Thruster->GetRPM() * Thruster->GetGearRatio();
+
+ IAS = Auxiliary->GetVcalibratedKTS();
+
+ doEngineStartup();
+ if (Boosted) doBoostControl();
+ doMAP();
+ doAirFlow();
+ doFuelFlow();
+
+ //Now that the fuel flow is done check if the mixture is too lean to run the engine
+ //Assume lean limit at 22 AFR for now - thats a thi of 0.668
+ //This might be a bit generous, but since there's currently no audiable warning of impending
+ //cutout in the form of misfiring and/or rough running its probably reasonable for now.
+ if (equivalence_ratio < 0.668)
+ Running = false;
+
+ doEnginePower();
+ doEGT();
+ doCHT();
+ doOilTemperature();
+ doOilPressure();
+
+ if (Thruster->GetType() == FGThruster::ttPropeller) {
+ ((FGPropeller*)Thruster)->SetAdvance(FCS->GetPropAdvance(EngineNumber));
+ }
+
+ PowerAvailable = (HP * hptoftlbssec) - Thruster->GetPowerRequired();
+
+ return Thruster->Calculate(PowerAvailable);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+/**
+ * Start or stop the engine.
+ */
+
+void FGPiston::doEngineStartup(void)
+{
+ // Check parameters that may alter the operating state of the engine.
+ // (spark, fuel, starter motor etc)
+ bool spark;
+ bool fuel;
+
+ // Check for spark
+ Magneto_Left = false;
+ Magneto_Right = false;
+ // Magneto positions:
+ // 0 -> off
+ // 1 -> left only
+ // 2 -> right only
+ // 3 -> both
+ if (Magnetos != 0) {
+ spark = true;
+ } else {
+ spark = false;
+ } // neglects battery voltage, master on switch, etc for now.
+
+ if ((Magnetos == 1) || (Magnetos > 2)) Magneto_Left = true;
+ if (Magnetos > 1) Magneto_Right = true;
+
+ // Assume we have fuel for now
+ fuel = !Starved;
+
+ // Check if we are turning the starter motor
+ if (Cranking != Starter) {
+ // This check saves .../cranking from getting updated every loop - they
+ // only update when changed.
+ Cranking = Starter;
+ crank_counter = 0;
+ }
+
+ if (Cranking) crank_counter++; //Check mode of engine operation
+
+ if (!Running && spark && fuel) { // start the engine if revs high enough
+ if (Cranking) {
+ if ((RPM > 450) && (crank_counter > 175)) // Add a little delay to startup
+ Running = true; // on the starter
+ } else {
+ if (RPM > 450) // This allows us to in-air start
+ Running = true; // when windmilling
+ }
+ }
+
+ // Cut the engine *power* - Note: the engine may continue to
+ // spin if the prop is in a moving airstream
+
+ if ( Running && (!spark || !fuel) ) Running = false;
+
+ // Check for stalling (RPM = 0).
+ if (Running) {
+ if (RPM == 0) {
+ Running = false;
+ } else if ((RPM <= 480) && (Cranking)) {
+ Running = false;
+ }
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/**
+ * Calculate the Current Boost Speed
+ *
+ * This function calculates the current turbo/supercharger boost speed
+ * based on altitude and the (automatic) boost-speed control valve configuration.
+ *
+ * Inputs: p_amb, BoostSwitchPressure, BoostSwitchHysteresis
+ *
+ * Outputs: BoostSpeed
+ */
+
+void FGPiston::doBoostControl(void)
+{
+ if(BoostSpeed < BoostSpeeds - 1) {
+ // Check if we need to change to a higher boost speed
+ if(p_amb < BoostSwitchPressure[BoostSpeed] - BoostSwitchHysteresis) {
+ BoostSpeed++;
+ }
+ } else if(BoostSpeed > 0) {
+ // Check if we need to change to a lower boost speed
+ if(p_amb > BoostSwitchPressure[BoostSpeed - 1] + BoostSwitchHysteresis) {
+ BoostSpeed--;
+ }
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/**
+ * Calculate the manifold absolute pressure (MAP) in inches hg
+ *
+ * This function calculates manifold absolute pressure (MAP)
+ * from the throttle position, turbo/supercharger boost control
+ * system, engine speed and local ambient air density.
+ *
+ * TODO: changes in MP should not be instantaneous -- introduce
+ * a lag between throttle changes and MP changes, to allow pressure
+ * to build up or disperse.
+ *
+ * Inputs: minMAP, maxMAP, p_amb, Throttle
+ *
+ * Outputs: MAP, ManifoldPressure_inHg
+ */
+
+void FGPiston::doMAP(void)
+{
+ if(RPM > 10) {
+ // Naturally aspirated
+ MAP = minMAP + (Throttle * (maxMAP - minMAP));
+ MAP *= p_amb / p_amb_sea_level;
+ if(Boosted) {
+ // If takeoff boost is fitted, we currently assume the following throttle map:
+ // (In throttle % - actual input is 0 -> 1)
+ // 99 / 100 - Takeoff boost
+ // 96 / 97 / 98 - Rated boost
+ // 0 - 95 - Idle to Rated boost (MinManifoldPressure to MaxManifoldPressure)
+ // In real life, most planes would be fitted with a mechanical 'gate' between
+ // the rated boost and takeoff boost positions.
+ double T = Throttle; // processed throttle value.
+ bool bTakeoffPos = false;
+ if(bTakeoffBoost) {
+ if(Throttle > 0.98) {
+ //cout << "Takeoff Boost!!!!\n";
+ bTakeoffPos = true;
+ } else if(Throttle <= 0.95) {
+ bTakeoffPos = false;
+ T *= 1.0 / 0.95;
+ } else {
+ bTakeoffPos = false;
+ //cout << "Rated Boost!!\n";
+ T = 1.0;
+ }
+ }
+ // Boost the manifold pressure.
+ MAP *= BoostMul[BoostSpeed];
+ // Now clip the manifold pressure to BCV or Wastegate setting.
+ if(bTakeoffPos) {
+ if(MAP > TakeoffMAP[BoostSpeed]) {
+ MAP = TakeoffMAP[BoostSpeed];
+ }
+ } else {
+ if(MAP > RatedMAP[BoostSpeed]) {
+ MAP = RatedMAP[BoostSpeed];
+ }
+ }
+ }
+ } else {
+ // rpm < 10 - effectively stopped.
+ // TODO - add a better variation of MAP with engine speed
+ MAP = Atmosphere->GetPressure() * psftopa;
+ }
+
+ // And set the value in American units as well
+ ManifoldPressure_inHg = MAP / 3376.85;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+/**
+ * Calculate the air flow through the engine.
+ * Also calculates ambient air density
+ * (used in CHT calculation for air-cooled engines).
+ *
+ * Inputs: p_amb, R_air, T_amb, MAP, Displacement,
+ * RPM, volumetric_efficiency
+ *
+ * TODO: Model inlet manifold air temperature.
+ *
+ * Outputs: rho_air, m_dot_air
+ */
+
+void FGPiston::doAirFlow(void)
+{
+ rho_air = p_amb / (R_air * T_amb);
+ double rho_air_manifold = MAP / (R_air * T_amb);
+ double displacement_SI = Displacement * in3tom3;
+ double swept_volume = (displacement_SI * (RPM/60)) / 2;
+ double v_dot_air = swept_volume * volumetric_efficiency;
+ m_dot_air = v_dot_air * rho_air_manifold;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+/**
+ * Calculate the fuel flow into the engine.
+ *
+ * Inputs: Mixture, thi_sea_level, p_amb_sea_level, p_amb, m_dot_air
+ *
+ * Outputs: equivalence_ratio, m_dot_fuel
+ */
+
+void FGPiston::doFuelFlow(void)
+{
+ double thi_sea_level = 1.3 * Mixture;
+ equivalence_ratio = thi_sea_level * p_amb_sea_level / p_amb;
+ m_dot_fuel = m_dot_air / 14.7 * equivalence_ratio;
+ FuelFlow_gph = m_dot_fuel
+ * 3600 // seconds to hours
+ * 2.2046 // kg to lb
+ / 6.6; // lb to gal_us of kerosene
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+/**
+ * Calculate the power produced by the engine.
+ *
+ * Currently, the JSBSim propellor model does not allow the
+ * engine to produce enough RPMs to get up to a high horsepower.
+ * When tested with sufficient RPM, it has no trouble reaching
+ * 200HP.
+ *
+ * Inputs: ManifoldPressure_inHg, p_amb, p_amb_sea_level, RPM, T_amb,
+ * equivalence_ratio, Cycles, MaxHP
+ *
+ * Outputs: Percentage_Power, HP
+ */
+
+void FGPiston::doEnginePower(void)
+{
+ if (Running) {
+ double T_amb_degF = KelvinToFahrenheit(T_amb);
+ double T_amb_sea_lev_degF = KelvinToFahrenheit(288);
+
+ // FIXME: this needs to be generalized
+ double ManXRPM; // Convienience term for use in the calculations
+ if(Boosted) {
+ // Currently a simple linear fit.
+ // The zero crossing is moved up the speed-load range to reduce the idling power.
+ // This will change!
+ double zeroOffset = (minMAP / 2.0) * (IdleRPM / 2.0);
+ ManXRPM = MAP * (RPM > RatedRPM[BoostSpeed] ? RatedRPM[BoostSpeed] : RPM);
+ // The speed clip in the line above is deliberate.
+ Percentage_Power = ((ManXRPM - zeroOffset) / ((RatedMAP[BoostSpeed] * RatedRPM[BoostSpeed]) - zeroOffset)) * 107.0;
+ Percentage_Power -= 7.0; // Another idle power reduction offset - see line above with 107.
+ if (Percentage_Power < 0.0) Percentage_Power = 0.0;
+ // Note that %power is allowed to go over 100 for boosted powerplants
+ // such as for the BCV-override or takeoff power settings.
+ // TODO - currently no altitude effect (temperature & exhaust back-pressure) modelled
+ // for boosted engines.
+ } else {
+ ManXRPM = ManifoldPressure_inHg * RPM; // Note that inHg must be used for the following correlation.
+ Percentage_Power = (6e-9 * ManXRPM * ManXRPM) + (8e-4 * ManXRPM) - 1.0;
+ Percentage_Power += ((T_amb_sea_lev_degF - T_amb_degF) * 7 /120);
+ if (Percentage_Power < 0.0) Percentage_Power = 0.0;
+ else if (Percentage_Power > 100.0) Percentage_Power = 100.0;
+ }
+
+ double Percentage_of_best_power_mixture_power =
+ Power_Mixture_Correlation->GetValue(14.7 / equivalence_ratio);
+
+ Percentage_Power *= Percentage_of_best_power_mixture_power / 100.0;
+
+ if (Boosted) {
+ HP = Percentage_Power * RatedPower[BoostSpeed] / 100.0;
+ } else {
+ HP = Percentage_Power * MaxHP / 100.0;
+ }
+
+ } else {
+
+ // Power output when the engine is not running
+ if (Cranking) {
+ if (RPM < 10) {
+ HP = 3.0; // This is a hack to prevent overshooting the idle rpm in
+ // the first time step. It may possibly need to be changed
+ // if the prop model is changed.
+ } else if (RPM < 480) {
+ HP = 3.0 + ((480 - RPM) / 10.0);
+ // This is a guess - would be nice to find a proper starter moter torque curve
+ } else {
+ HP = 3.0;
+ }
+ } else {
+ // Quick hack until we port the FMEP stuff
+ if (RPM > 0.0)
+ HP = -1.5;
+ else
+ HP = 0.0;
+ }
+ }
+ //cout << "Power = " << HP << '\n';
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+/**
+ * Calculate the exhaust gas temperature.
+ *
+ * Inputs: equivalence_ratio, m_dot_fuel, calorific_value_fuel,
+ * Cp_air, m_dot_air, Cp_fuel, m_dot_fuel, T_amb, Percentage_Power
+ *
+ * Outputs: combustion_efficiency, ExhaustGasTemp_degK
+ */
+
+void FGPiston::doEGT(void)
+{
+ double delta_T_exhaust;
+ double enthalpy_exhaust;
+ double heat_capacity_exhaust;
+ double dEGTdt;
+
+ if ((Running) && (m_dot_air > 0.0)) { // do the energy balance
+ combustion_efficiency = Lookup_Combustion_Efficiency->GetValue(equivalence_ratio);
+ enthalpy_exhaust = m_dot_fuel * calorific_value_fuel *
+ combustion_efficiency * 0.33;
+ heat_capacity_exhaust = (Cp_air * m_dot_air) + (Cp_fuel * m_dot_fuel);
+ delta_T_exhaust = enthalpy_exhaust / heat_capacity_exhaust;
+ ExhaustGasTemp_degK = T_amb + delta_T_exhaust;
+ ExhaustGasTemp_degK *= 0.444 + ((0.544 - 0.444) * Percentage_Power / 100.0);
+ } else { // Drop towards ambient - guess an appropriate time constant for now
+ dEGTdt = (298.0 - ExhaustGasTemp_degK) / 100.0;
+ delta_T_exhaust = dEGTdt * dt;
+ ExhaustGasTemp_degK += delta_T_exhaust;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+/**
+ * Calculate the cylinder head temperature.
+ *
+ * Inputs: T_amb, IAS, rho_air, m_dot_fuel, calorific_value_fuel,
+ * combustion_efficiency, RPM
+ *
+ * Outputs: CylinderHeadTemp_degK
+ */
+
+void FGPiston::doCHT(void)
+{
+ double h1 = -95.0;
+ double h2 = -3.95;
+ double h3 = -0.05;
+
+ double arbitary_area = 1.0;
+ double CpCylinderHead = 800.0;
+ double MassCylinderHead = 8.0;
+
+ double temperature_difference = CylinderHeadTemp_degK - T_amb;
+ double v_apparent = IAS * 0.5144444;
+ double v_dot_cooling_air = arbitary_area * v_apparent;
+ double m_dot_cooling_air = v_dot_cooling_air * rho_air;
+ double dqdt_from_combustion =
+ m_dot_fuel * calorific_value_fuel * combustion_efficiency * 0.33;
+ double dqdt_forced = (h2 * m_dot_cooling_air * temperature_difference) +
+ (h3 * RPM * temperature_difference);
+ double dqdt_free = h1 * temperature_difference;
+ double dqdt_cylinder_head = dqdt_from_combustion + dqdt_forced + dqdt_free;
+
+ double HeatCapacityCylinderHead = CpCylinderHead * MassCylinderHead;
+
+ CylinderHeadTemp_degK +=
+ (dqdt_cylinder_head / HeatCapacityCylinderHead) * dt;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+/**
+ * Calculate the oil temperature.
+ *
+ * Inputs: Percentage_Power, running flag.
+ *
+ * Outputs: OilTemp_degK
+ */
+
+void FGPiston::doOilTemperature(void)
+{
+ double idle_percentage_power = 2.3; // approximately
+ double target_oil_temp; // Steady state oil temp at the current engine conditions
+ double time_constant; // The time constant for the differential equation
+
+ if (Running) {
+ target_oil_temp = 363;
+ time_constant = 500; // Time constant for engine-on idling.
+ if (Percentage_Power > idle_percentage_power) {
+ time_constant /= ((Percentage_Power / idle_percentage_power) / 10.0); // adjust for power
+ }
+ } else {
+ target_oil_temp = 298;
+ time_constant = 1000; // Time constant for engine-off; reflects the fact
+ // that oil is no longer getting circulated
+ }
+
+ double dOilTempdt = (target_oil_temp - OilTemp_degK) / time_constant;
+
+ OilTemp_degK += (dOilTempdt * dt);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+/**
+ * Calculate the oil pressure.
+ *
+ * Inputs: RPM
+ *
+ * Outputs: OilPressure_psi
+ */
+
+void FGPiston::doOilPressure(void)
+{
+ double Oil_Press_Relief_Valve = 60; // FIXME: may vary by engine
+ double Oil_Press_RPM_Max = 1800; // FIXME: may vary by engine
+ double Design_Oil_Temp = 358; // degK; FIXME: may vary by engine
+ double Oil_Viscosity_Index = 0.25;
+
+ OilPressure_psi = (Oil_Press_Relief_Valve / Oil_Press_RPM_Max) * RPM;
+
+ if (OilPressure_psi >= Oil_Press_Relief_Valve) {
+ OilPressure_psi = Oil_Press_Relief_Valve;
+ }
+
+ OilPressure_psi += (Design_Oil_Temp - OilTemp_degK) * Oil_Viscosity_Index;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGPiston::GetEngineLabels(string delimeter)
+{
+ std::ostringstream buf;
+
+ buf << Name << "_PwrAvail[" << EngineNumber << "]" << delimeter
+ << Name << "_HP[" << EngineNumber << "]" << delimeter
+ << Name << "_equiv_ratio[" << EngineNumber << "]" << delimeter
+ << Name << "_MAP[" << EngineNumber << "]" << delimeter
+ << Thruster->GetThrusterLabels(EngineNumber, delimeter);
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGPiston::GetEngineValues(string delimeter)
+{
+ std::ostringstream buf;
+
+ buf << PowerAvailable << delimeter << HP << delimeter
+ << equivalence_ratio << delimeter << MAP << delimeter
+ << Thruster->GetThrusterValues(EngineNumber, delimeter);
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+//
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGPiston::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ cout << "\n Engine Name: " << Name << endl;
+ cout << " MinManifoldPressure: " << MinManifoldPressure_inHg << endl;
+ cout << " MaxManifoldPressure: " << MaxManifoldPressure_inHg << endl;
+ cout << " MinMaP (Pa): " << minMAP << endl;
+ cout << " MaxMaP (Pa): " << maxMAP << endl;
+ cout << " Displacement: " << Displacement << endl;
+ cout << " MaxHP: " << MaxHP << endl;
+ cout << " Cycles: " << Cycles << endl;
+ cout << " IdleRPM: " << IdleRPM << endl;
+ cout << " MaxThrottle: " << MaxThrottle << endl;
+ cout << " MinThrottle: " << MinThrottle << endl;
+
+ cout << endl;
+ cout << " Combustion Efficiency table:" << endl;
+ Lookup_Combustion_Efficiency->Print();
+ cout << endl;
+
+ cout << endl;
+ cout << " Power Mixture Correlation table:" << endl;
+ Power_Mixture_Correlation->Print();
+ cout << endl;
+
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGPiston" << endl;
+ if (from == 1) cout << "Destroyed: FGPiston" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+
+double
+FGPiston::CalcFuelNeed(void)
+{
+ return FuelFlow_gph / 3600 * 6 * State->Getdt() * Propulsion->GetRate();
+}
+
+} // namespace JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGPiston.h
+ Author: Jon S. Berndt
+ Date started: 09/12/2000
+
+ ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) --------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+09/12/2000 JSB Created
+10/01/2001 DPM Modified to use equations from Dave Luff's piston model.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGPISTON_H
+#define FGPISTON_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGEngine.h"
+#include <math/FGTable.h>
+#include <input_output/FGXMLElement.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_PISTON "$Id$";
+#define FG_MAX_BOOST_SPEEDS 3
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models Dave Luff's Turbo/Supercharged Piston engine model.
+ Additional elements are required for a supercharged engine. These can be
+ left off a non-supercharged engine, ie. the changes are all backward
+ compatible at present.
+
+ - NUMBOOSTSPEEDS - zero (or not present) for a naturally-aspirated engine,
+ either 1, 2 or 3 for a boosted engine. This corresponds to the number of
+ supercharger speeds. Merlin XII had 1 speed, Merlin 61 had 2, a late
+ Griffon engine apparently had 3. No known engine more than 3, although
+ some German engines apparently had a continuously variable-speed
+ supercharger.
+
+ - BOOSTOVERRIDE - whether the boost pressure control system (either a boost
+ control valve for superchargers or wastegate for turbochargers) can be
+ overriden by the pilot. During wartime this was commonly possible, and
+ known as "War Emergency Power" by the Brits. 1 or 0 in the config file.
+ This isn't implemented in the model yet though, there would need to be
+ some way of getting the boost control cutout lever position (on or off)
+ from FlightGear first.
+
+ - The next items are all appended with either 1, 2 or 3 depending on which
+ boost speed they refer to, eg RATEDBOOST1. The rated values seems to have
+ been a common convention at the time to express the maximum continuously
+ available power, and the conditions to attain that power.
+
+ - RATEDBOOST[123] - the absolute rated boost above sea level ambient for a
+ given boost speed, in psi. Eg the Merlin XII had a rated boost of 9psi,
+ giving approximately 42inHg manifold pressure up to the rated altitude.
+
+ - RATEDALTITUDE[123] - The altitude up to which rated boost can be
+ maintained. Up to this altitude the boost is maintained constant for a
+ given throttle position by the BCV or wastegate. Beyond this altitude the
+ manifold pressure must drop, since the supercharger is now at maximum
+ unregulated output. The actual pressure multiplier of the supercharger
+ system is calculated at initialisation from this value.
+
+ - RATEDPOWER[123] - The power developed at rated boost at rated altitude at
+ rated rpm.
+
+ - RATEDRPM[123] - The rpm at which rated power is developed.
+
+ - TAKEOFFBOOST - Takeoff boost in psi above ambient. Many aircraft had an
+ extra boost setting beyond rated boost, but not totally uncontrolled as in
+ the already mentioned boost-control-cutout, typically attained by pushing
+ the throttle past a mechanical 'gate' preventing its inadvertant use. This
+ was typically used for takeoff, and emergency situations, generally for
+ not more than five minutes. This is a change in the boost control
+ setting, not the actual supercharger speed, and so would only give extra
+ power below the rated altitude. When TAKEOFFBOOST is specified in the
+ config file (and is above RATEDBOOST1), then the throttle position is
+ interpreted as:
+
+ - 0 to 0.95 : idle manifold pressure to rated boost (where attainable)
+ - 0.96, 0.97, 0.98 : rated boost (where attainable).
+ - 0.99, 1.0 : takeoff boost (where attainable).
+
+ A typical takeoff boost for an earlyish Merlin was about 12psi, compared
+ with a rated boost of 9psi.
+
+ It is quite possible that other boost control settings could have been used
+ on some aircraft, or that takeoff/extra boost could have activated by other
+ means than pushing the throttle full forward through a gate, but this will
+ suffice for now.
+
+ Note that MAXMP is still the non-boosted max manifold pressure even for
+ boosted engines - effectively this is simply a measure of the pressure drop
+ through the fully open throttle.
+
+ @author Jon S. Berndt (Engine framework code and framework-related mods)
+ @author Dave Luff (engine operational code)
+ @author David Megginson (initial porting and additional code)
+ @version $Id$
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGPiston : public FGEngine
+{
+public:
+ /// Constructor
+ FGPiston(FGFDMExec* exec, Element* el, int engine_number);
+ /// Destructor
+ ~FGPiston();
+
+ string GetEngineLabels(string delimeter);
+ string GetEngineValues(string delimeter);
+
+ double Calculate(void);
+ double GetPowerAvailable(void) {return PowerAvailable;}
+ double CalcFuelNeed(void);
+
+ void SetMagnetos(int magnetos) {Magnetos = magnetos;}
+
+ double GetEGT(void) { return EGT_degC; }
+ int GetMagnetos(void) {return Magnetos;}
+
+ double getExhaustGasTemp_degF(void) {return KelvinToFahrenheit(ExhaustGasTemp_degK);}
+ double getManifoldPressure_inHg(void) const {return ManifoldPressure_inHg;}
+ double getCylinderHeadTemp_degF(void) {return KelvinToFahrenheit(CylinderHeadTemp_degK);}
+ double getOilPressure_psi(void) const {return OilPressure_psi;}
+ double getOilTemp_degF (void) {return KelvinToFahrenheit(OilTemp_degK);}
+ double getRPM(void) {return RPM;}
+
+private:
+ int crank_counter;
+
+ double BrakeHorsePower;
+ double SpeedSlope;
+ double SpeedIntercept;
+ double AltitudeSlope;
+ double PowerAvailable;
+
+ // timestep
+ double dt;
+
+ void doEngineStartup(void);
+ void doBoostControl(void);
+ void doMAP(void);
+ void doAirFlow(void);
+ void doFuelFlow(void);
+ void doEnginePower(void);
+ void doEGT(void);
+ void doCHT(void);
+ void doOilPressure(void);
+ void doOilTemperature(void);
+
+ //
+ // constants
+ //
+
+ const double R_air;
+ const double rho_fuel; // kg/m^3
+ const double calorific_value_fuel; // W/Kg (approximate)
+ const double Cp_air; // J/KgK
+ const double Cp_fuel; // J/KgK
+
+ FGTable *Lookup_Combustion_Efficiency;
+ FGTable *Power_Mixture_Correlation;
+
+ //
+ // Configuration
+ //
+ double MinManifoldPressure_inHg; // Inches Hg
+ double MaxManifoldPressure_inHg; // Inches Hg
+ double Displacement; // cubic inches
+ double MaxHP; // horsepower
+ double Cycles; // cycles/power stroke
+ double IdleRPM; // revolutions per minute
+ int BoostSpeeds; // Number of super/turbocharger boost speeds - zero implies no turbo/supercharging.
+ int BoostSpeed; // The current boost-speed (zero-based).
+ bool Boosted; // Set true for boosted engine.
+ int BoostOverride; // The raw value read in from the config file - should be 1 or 0 - see description below.
+ bool bBoostOverride; // Set true if pilot override of the boost regulator was fitted.
+ // (Typically called 'war emergency power').
+ bool bTakeoffBoost; // Set true if extra takeoff / emergency boost above rated boost could be attained.
+ // (Typically by extra throttle movement past a mechanical 'gate').
+ double TakeoffBoost; // Sea-level takeoff boost in psi. (if fitted).
+ double RatedBoost[FG_MAX_BOOST_SPEEDS]; // Sea-level rated boost in psi.
+ double RatedAltitude[FG_MAX_BOOST_SPEEDS]; // Altitude at which full boost is reached (boost regulation ends)
+ // and at which power starts to fall with altitude [ft].
+ double RatedRPM[FG_MAX_BOOST_SPEEDS]; // Engine speed at which the rated power for each boost speed is delivered [rpm].
+ double RatedPower[FG_MAX_BOOST_SPEEDS]; // Power at rated throttle position at rated altitude [HP].
+ double BoostSwitchAltitude[FG_MAX_BOOST_SPEEDS - 1]; // Altitude at which switchover (currently assumed automatic)
+ // from one boost speed to next occurs [ft].
+ double BoostSwitchPressure[FG_MAX_BOOST_SPEEDS - 1]; // Pressure at which boost speed switchover occurs [Pa]
+ double BoostMul[FG_MAX_BOOST_SPEEDS]; // Pressure multipier of unregulated supercharger
+ double RatedMAP[FG_MAX_BOOST_SPEEDS]; // Rated manifold absolute pressure [Pa] (BCV clamp)
+ double TakeoffMAP[FG_MAX_BOOST_SPEEDS]; // Takeoff setting manifold absolute pressure [Pa] (BCV clamp)
+ double BoostSwitchHysteresis; // Pa.
+
+ double minMAP; // Pa
+ double maxMAP; // Pa
+ double MAP; // Pa
+
+ //
+ // Inputs (in addition to those in FGEngine).
+ //
+ double p_amb; // Pascals
+ double p_amb_sea_level; // Pascals
+ double T_amb; // degrees Kelvin
+ double RPM; // revolutions per minute
+ double IAS; // knots
+ bool Magneto_Left;
+ bool Magneto_Right;
+ int Magnetos;
+
+ //
+ // Outputs (in addition to those in FGEngine).
+ //
+ double rho_air;
+ double volumetric_efficiency;
+ double m_dot_air;
+ double equivalence_ratio;
+ double m_dot_fuel;
+ double Percentage_Power;
+ double HP;
+ double combustion_efficiency;
+ double ExhaustGasTemp_degK;
+ double EGT_degC;
+ double ManifoldPressure_inHg;
+ double CylinderHeadTemp_degK;
+ double OilPressure_psi;
+ double OilTemp_degK;
+
+ void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGPropeller.cpp
+ Author: Jon S. Berndt
+ Date started: 08/24/00
+ Purpose: Encapsulates the propeller object
+
+ ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+08/24/00 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <sstream>
+
+#include "FGPropeller.h"
+#include <models/FGPropagate.h>
+#include <models/FGAtmosphere.h>
+#include <models/FGAuxiliary.h>
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_PROPELLER;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+// This class currently makes certain assumptions when calculating torque and
+// p-factor. That is, that the axis of rotation is the X axis of the aircraft -
+// not just the X-axis of the engine/propeller. This may or may not work for a
+// helicopter.
+
+FGPropeller::FGPropeller(FGFDMExec* exec, Element* prop_element, int num)
+ : FGThruster(exec, prop_element, num)
+{
+ string token;
+ int rows, cols;
+ Element *table_element, *local_element;
+ string name="";
+ FGPropertyManager* PropertyManager = exec->GetPropertyManager();
+
+ MaxPitch = MinPitch = P_Factor = Pitch = Advance = MinRPM = MaxRPM = 0.0;
+ Sense = 1; // default clockwise rotation
+ ReversePitch = 0.0;
+ Reversed = false;
+ Feathered = false;
+ Reverse_coef = 0.0;
+ GearRatio = 1.0;
+
+ if (prop_element->FindElement("ixx"))
+ Ixx = prop_element->FindElementValueAsNumberConvertTo("ixx", "SLUG*FT2");
+ if (prop_element->FindElement("diameter"))
+ Diameter = prop_element->FindElementValueAsNumberConvertTo("diameter", "FT");
+ if (prop_element->FindElement("numblades"))
+ numBlades = (int)prop_element->FindElementValueAsNumber("numblades");
+ if (prop_element->FindElement("gearratio"))
+ GearRatio = prop_element->FindElementValueAsNumber("gearratio");
+ if (prop_element->FindElement("minpitch"))
+ MinPitch = prop_element->FindElementValueAsNumber("minpitch");
+ if (prop_element->FindElement("maxpitch"))
+ MaxPitch = prop_element->FindElementValueAsNumber("maxpitch");
+ if (prop_element->FindElement("minrpm"))
+ MinRPM = prop_element->FindElementValueAsNumber("minrpm");
+ if (prop_element->FindElement("maxrpm"))
+ MaxRPM = prop_element->FindElementValueAsNumber("maxrpm");
+ if (prop_element->FindElement("reversepitch"))
+ ReversePitch = prop_element->FindElementValueAsNumber("reversepitch");
+ for (int i=0; i<2; i++) {
+ table_element = prop_element->FindNextElement("table");
+ name = table_element->GetAttributeValue("name");
+ if (name == "C_THRUST") {
+ cThrust = new FGTable(PropertyManager, table_element);
+ } else if (name == "C_POWER") {
+ cPower = new FGTable(PropertyManager, table_element);
+ } else {
+ cerr << "Unknown table type: " << name << " in propeller definition." << endl;
+ }
+ }
+
+ local_element = prop_element->GetParent()->FindElement("sense");
+ if (local_element) {
+ double Sense = local_element->GetDataAsNumber();
+ SetSense(fabs(Sense)/Sense);
+ }
+ local_element = prop_element->GetParent()->FindElement("p_factor");
+ if (local_element) {
+ P_Factor = local_element->GetDataAsNumber();
+ }
+ if (P_Factor < 0) {
+ cerr << "P-Factor value in config file must be greater than zero" << endl;
+ }
+
+ Type = ttPropeller;
+ RPM = 0;
+ vTorque.InitMatrix();
+ D4 = Diameter*Diameter*Diameter*Diameter;
+ D5 = D4*Diameter;
+
+ char property_name[80];
+ snprintf(property_name, 80, "propulsion/engine[%d]/advance-ratio", EngineNum);
+ PropertyManager->Tie( property_name, &J );
+ snprintf(property_name, 80, "propulsion/engine[%d]/blade-angle", EngineNum);
+ PropertyManager->Tie( property_name, &Pitch );
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGPropeller::~FGPropeller()
+{
+ if (cThrust) delete cThrust;
+ if (cPower) delete cPower;
+
+ char property_name[80];
+ snprintf(property_name, 80, "propulsion/engine[%d]/advance-ratio", EngineNum);
+ PropertyManager->Untie( property_name );
+ snprintf(property_name, 80, "propulsion/engine[%d]/blade-angle", EngineNum);
+ PropertyManager->Untie( property_name );
+
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+//
+// We must be getting the aerodynamic velocity here, NOT the inertial velocity.
+// We need the velocity with respect to the wind.
+//
+// Note that PowerAvailable is the excess power available after the drag of the
+// propeller has been subtracted. At equilibrium, PowerAvailable will be zero -
+// indicating that the propeller will not accelerate or decelerate.
+// Remembering that Torque * omega = Power, we can derive the torque on the
+// propeller and its acceleration to give a new RPM. The current RPM will be
+// used to calculate thrust.
+//
+// Because RPM could be zero, we need to be creative about what RPM is stated as.
+
+double FGPropeller::Calculate(double PowerAvailable)
+{
+ double omega, alpha, beta;
+
+ double Vel = fdmex->GetAuxiliary()->GetAeroUVW(eU);
+ double rho = fdmex->GetAtmosphere()->GetDensity();
+ double RPS = RPM/60.0;
+
+ if (RPS > 0.00) J = Vel / (Diameter * RPS); // Calculate J normally
+ else J = 1000.0; // Set J to a high number
+
+ if (MaxPitch == MinPitch) ThrustCoeff = cThrust->GetValue(J);
+ else ThrustCoeff = cThrust->GetValue(J, Pitch);
+
+ if (P_Factor > 0.0001) {
+ alpha = fdmex->GetAuxiliary()->Getalpha();
+ beta = fdmex->GetAuxiliary()->Getbeta();
+ SetActingLocationY( GetLocationY() + P_Factor*alpha*Sense);
+ SetActingLocationZ( GetLocationZ() + P_Factor*beta*Sense);
+ }
+
+ Thrust = ThrustCoeff*RPS*RPS*D4*rho;
+ omega = RPS*2.0*M_PI;
+
+ vFn(1) = Thrust;
+
+ // The Ixx value and rotation speed given below are for rotation about the
+ // natural axis of the engine. The transform takes place in the base class
+ // FGForce::GetBodyForces() function.
+
+ vH(eX) = Ixx*omega*Sense;
+ vH(eY) = 0.0;
+ vH(eZ) = 0.0;
+
+ if (omega > 0.0) ExcessTorque = GearRatio * PowerAvailable / omega;
+ else ExcessTorque = GearRatio * PowerAvailable / 1.0;
+
+ RPM = (RPS + ((ExcessTorque / Ixx) / (2.0 * M_PI)) * deltaT) * 60.0;
+
+ if (RPM < 1.0) RPM = 0; // Engine friction stops rotation arbitrarily at 1 RPM.
+
+ vMn = fdmex->GetPropagate()->GetPQR()*vH + vTorque*Sense;
+
+ return Thrust; // return thrust in pounds
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGPropeller::GetPowerRequired(void)
+{
+ double cPReq, J;
+ double rho = fdmex->GetAtmosphere()->GetDensity();
+ double RPS = RPM / 60.0;
+
+ if (RPS != 0) J = fdmex->GetAuxiliary()->GetAeroUVW(eU) / (Diameter * RPS);
+ else J = 1000.0; // Set J to a high number
+
+ if (MaxPitch == MinPitch) { // Fixed pitch prop
+ Pitch = MinPitch;
+ cPReq = cPower->GetValue(J);
+ } else { // Variable pitch prop
+
+ if (MaxRPM != MinRPM) { // fixed-speed prop
+
+ // do normal calculation when propeller is neither feathered nor reversed
+ if (!Feathered) {
+ if (!Reversed) {
+
+ double rpmReq = MinRPM + (MaxRPM - MinRPM) * Advance;
+ double dRPM = rpmReq - RPM;
+ // The pitch of a variable propeller cannot be changed when the RPMs are
+ // too low - the oil pump does not work.
+ if (RPM > 200) Pitch -= dRPM / 10;
+
+ if (Pitch < MinPitch) Pitch = MinPitch;
+ else if (Pitch > MaxPitch) Pitch = MaxPitch;
+
+ } else { // Reversed propeller
+
+ // when reversed calculate propeller pitch depending on throttle lever position
+ // (beta range for taxing full reverse for braking)
+ double PitchReq = MinPitch - ( MinPitch - ReversePitch ) * Reverse_coef;
+ // The pitch of a variable propeller cannot be changed when the RPMs are
+ // too low - the oil pump does not work.
+ if (RPM > 200) Pitch += (PitchReq - Pitch) / 200;
+ if (RPM > MaxRPM) {
+ Pitch += (MaxRPM - RPM) / 50;
+ if (Pitch < ReversePitch) Pitch = ReversePitch;
+ else if (Pitch > MaxPitch) Pitch = MaxPitch;
+ }
+ }
+
+ } else { // Feathered propeller
+ // ToDo: Make feathered and reverse settings done via FGKinemat
+ Pitch += (MaxPitch - Pitch) / 300; // just a guess (about 5 sec to fully feathered)
+ }
+
+ } else { // Variable Speed Prop
+ Pitch = MinPitch + (MaxPitch - MinPitch) * Advance;
+ }
+ cPReq = cPower->GetValue(J, Pitch);
+ }
+
+ if (RPS > 0) {
+ PowerRequired = cPReq*RPS*RPS*RPS*D5*rho;
+ vTorque(eX) = -Sense*PowerRequired / (RPS*2.0*M_PI);
+ } else {
+ PowerRequired = 0.0;
+ vTorque(eX) = 0.0;
+ }
+
+ return PowerRequired;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGColumnVector3 FGPropeller::GetPFactor()
+{
+ double px=0.0, py, pz;
+
+ py = Thrust * Sense * (GetActingLocationY() - GetLocationY()) / 12.0;
+ pz = Thrust * Sense * (GetActingLocationZ() - GetLocationZ()) / 12.0;
+
+ return FGColumnVector3(px, py, pz);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGPropeller::GetThrusterLabels(int id, string delimeter)
+{
+ std::ostringstream buf;
+
+ buf << Name << "_Torque[" << id << "]" << delimeter
+ << Name << "_PFactor_Pitch[" << id << "]" << delimeter
+ << Name << "_PFactor_Yaw[" << id << "]" << delimeter
+ << Name << "_Thrust[" << id << "]" << delimeter;
+ if (IsVPitch())
+ buf << Name << "_Pitch[" << id << "]" << delimeter;
+ buf << Name << "_RPM[" << id << "]";
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGPropeller::GetThrusterValues(int id, string delimeter)
+{
+ std::ostringstream buf;
+
+ FGColumnVector3 vPFactor = GetPFactor();
+ buf << vTorque(eX) << delimeter
+ << vPFactor(ePitch) << delimeter
+ << vPFactor(eYaw) << delimeter
+ << Thrust << delimeter;
+ if (IsVPitch())
+ buf << Pitch << delimeter;
+ buf << RPM;
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGPropeller::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+ cout << "\n Propeller Name: " << Name << endl;
+ cout << " IXX = " << Ixx << endl;
+ cout << " Diameter = " << Diameter << " ft." << endl;
+ cout << " Number of Blades = " << numBlades << endl;
+ cout << " Gear Ratio = " << GearRatio << endl;
+ cout << " Minimum Pitch = " << MinPitch << endl;
+ cout << " Maximum Pitch = " << MaxPitch << endl;
+ cout << " Minimum RPM = " << MinRPM << endl;
+ cout << " Maximum RPM = " << MaxRPM << endl;
+// cout << " Thrust Coefficient: " << endl;
+// cThrust->Print();
+// cout << " Power Coefficient: " << endl;
+// cPower->Print();
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGPropeller" << endl;
+ if (from == 1) cout << "Destroyed: FGPropeller" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGPropeller.h
+ Author: Jon S. Berndt
+ Date started: 08/24/00
+
+ ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+08/24/00 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGPROPELLER_H
+#define FGPROPELLER_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGThruster.h"
+#include <math/FGTable.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_PROPELLER "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Propeller modeling class.
+ FGPropeller models a propeller given the tabular data for Ct and Cp
+ indexed by advance ratio "J". The data for the propeller is
+ stored in a config file named "prop_name.xml". The propeller config file
+ is referenced from the main aircraft config file in the "Propulsion" section.
+ See the constructor for FGPropeller to see what is read in and what should
+ be stored in the config file.<br>
+ Several references were helpful, here:<ul>
+ <li>Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
+ Wiley & Sons, 1979 ISBN 0-471-03032-5</li>
+ <li>Edwin Hartman, David Biermann, "The Aerodynamic Characteristics of
+ Full Scale Propellers Having 2, 3, and 4 Blades of Clark Y and R.A.F. 6
+ Airfoil Sections", NACA Report TN-640, 1938 (?)</li>
+ <li>Various NACA Technical Notes and Reports</li>
+ </ul>
+ @author Jon S. Berndt
+ @version $Id$
+ @see FGEngine
+ @see FGThruster
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGPropeller : public FGThruster {
+
+public:
+ /** Constructor for FGPropeller.
+ @param exec a pointer to the main executive object
+ @param el a pointer to the thruster config file XML element*/
+ FGPropeller(FGFDMExec* exec, Element* el, int num = 0);
+
+ /// Destructor for FGPropeller - deletes the FGTable objects
+ ~FGPropeller();
+
+ /** Sets the Revolutions Per Minute for the propeller. Normally the propeller
+ instance will calculate its own rotational velocity, given the Torque
+ produced by the engine and integrating over time using the standard
+ equation for rotational acceleration "a": a = Q/I , where Q is Torque and
+ I is moment of inertia for the propeller.
+ @param rpm the rotational velocity of the propeller */
+ void SetRPM(double rpm) {RPM = rpm;}
+
+ /// Returns true of this propeller is variable pitch
+ bool IsVPitch(void) {return MaxPitch != MinPitch;}
+
+ /** This commands the pitch of the blade to change to the value supplied.
+ This call is meant to be issued either from the cockpit or by the flight
+ control system (perhaps to maintain constant RPM for a constant-speed
+ propeller). This value will be limited to be within whatever is specified
+ in the config file for Max and Min pitch. It is also one of the lookup
+ indices to the power and thrust tables for variable-pitch propellers.
+ @param pitch the pitch of the blade in degrees. */
+ void SetPitch(double pitch) {Pitch = pitch;}
+
+ void SetAdvance(double advance) {Advance = advance;}
+
+ /// Sets the P-Factor constant
+ void SetPFactor(double pf) {P_Factor = pf;}
+
+ /** Sets the rotation sense of the propeller.
+ @param s this value should be +/- 1 ONLY. +1 indicates clockwise rotation as
+ viewed by someone standing behind the engine looking forward into
+ the direction of flight. */
+ void SetSense(double s) { Sense = s;}
+
+ /// Retrieves the pitch of the propeller in degrees.
+ double GetPitch(void) { return Pitch; }
+
+ /// Retrieves the RPMs of the propeller
+ double GetRPM(void) { return RPM; }
+
+ /// Retrieves the propeller moment of inertia
+ double GetIxx(void) { return Ixx; }
+
+ /// Retrieves the Torque in foot-pounds (Don't you love the English system?)
+ double GetTorque(void) { return vTorque(eX); }
+
+ /** Retrieves the power required (or "absorbed") by the propeller -
+ i.e. the power required to keep spinning the propeller at the current
+ velocity, air density, and rotational rate. */
+ double GetPowerRequired(void);
+
+ /** Calculates and returns the thrust produced by this propeller.
+ Given the excess power available from the engine (in foot-pounds), the thrust is
+ calculated, as well as the current RPM. The RPM is calculated by integrating
+ the torque provided by the engine over what the propeller "absorbs"
+ (essentially the "drag" of the propeller).
+ @param PowerAvailable this is the excess power provided by the engine to
+ accelerate the prop. It could be negative, dictating that the propeller
+ would be slowed.
+ @return the thrust in pounds */
+ double Calculate(double PowerAvailable);
+ FGColumnVector3 GetPFactor(void);
+ string GetThrusterLabels(int id, string delimeter);
+ string GetThrusterValues(int id, string delimeter);
+
+ void SetReverseCoef (double c) { Reverse_coef = c; }
+ double GetReverseCoef (void) { return Reverse_coef; }
+ void SetReverse (bool r) { Reversed = r; }
+ bool GetReverse (void) { return Reversed; }
+ void SetFeather (bool f) { Feathered = f; }
+ bool GetFeather (void) { return Feathered; }
+
+private:
+ int numBlades;
+ double J;
+ double RPM;
+ double Ixx;
+ double Diameter;
+ double MaxPitch;
+ double MinPitch;
+ double MinRPM;
+ double MaxRPM;
+ double Pitch;
+ double P_Factor;
+ double Sense;
+ double Advance;
+ double ExcessTorque;
+ double D4;
+ double D5;
+ FGColumnVector3 vTorque;
+ FGTable *cThrust;
+ FGTable *cPower;
+ void Debug(int from);
+ double ReversePitch; // Pitch, when fully reversed
+ bool Reversed; // true, when propeller is reversed
+ double Reverse_coef; // 0 - 1 defines AdvancePitch (0=MIN_PITCH 1=REVERSE_PITCH)
+ bool Feathered; // true, if feather command
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGRocket.cpp
+ Author: Jon S. Berndt
+ Date started: 09/12/2000
+ Purpose: This module models a rocket engine
+
+ ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) --------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+This class descends from the FGEngine class and models a rocket engine based on
+parameters given in the engine config file for this class
+
+HISTORY
+--------------------------------------------------------------------------------
+09/12/2000 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <sstream>
+
+#include "FGRocket.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_ROCKET;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number)
+ : FGEngine(exec, el, engine_number)
+{
+ if (el->FindElement("shr"))
+ SHR = el->FindElementValueAsNumber("shr");
+ if (el->FindElement("max_pc"))
+ maxPC = el->FindElementValueAsNumberConvertTo("max_pc", "PSF");
+ if (el->FindElement("prop_eff"))
+ propEff = el->FindElementValueAsNumber("prop_eff");
+ if (el->FindElement("maxthrottle"))
+ MaxThrottle = el->FindElementValueAsNumber("maxthrottle");
+ if (el->FindElement("minthrottle"))
+ MinThrottle = el->FindElementValueAsNumber("minthrottle");
+ if (el->FindElement("slfuelflowmax"))
+ SLFuelFlowMax = el->FindElementValueAsNumberConvertTo("slfuelflowmax", "LBS/SEC");
+ if (el->FindElement("sloxiflowmax"))
+ SLOxiFlowMax = el->FindElementValueAsNumberConvertTo("sloxiflowmax", "LBS/SEC");
+ if (el->FindElement("variance"))
+ Variance = el->FindElementValueAsNumber("variance");
+
+ Debug(0);
+
+ Type = etRocket;
+ Flameout = false;
+
+ PC = 0.0;
+ kFactor = (2.0*SHR*SHR/(SHR-1.0))*pow(2.0/(SHR+1), (SHR+1)/(SHR-1));
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGRocket::~FGRocket(void)
+{
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGRocket::Calculate(void)
+{
+ double Cf=0;
+
+ if (!Flameout && !Starved) ConsumeFuel();
+
+ Throttle = FCS->GetThrottlePos(EngineNumber);
+
+ if (Throttle < MinThrottle || Starved) {
+ PctPower = Thrust = 0.0; // desired thrust
+ Flameout = true;
+ PC = 0.0;
+ } else {
+ PctPower = Throttle / MaxThrottle;
+ //todo: remove Variance?
+ PC = maxPC*PctPower * (1.0 + Variance * ((double)rand()/(double)RAND_MAX - 0.5));
+ // The Cf (below) is CF from Eqn. 3-30, "Rocket Propulsion Elements", Fifth Edition,
+ // George P. Sutton. Note that the thruster function GetPowerRequired() might
+ // be better called GetResistance() or something; this function returns the
+ // nozzle exit pressure.
+ Cf = sqrt(kFactor*(1 - pow(Thruster->GetPowerRequired()/(PC), (SHR-1)/SHR)));
+ Flameout = false;
+ }
+
+ return Thruster->Calculate(Cf*maxPC*PctPower*propEff);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGRocket::GetEngineLabels(string delimeter)
+{
+ std::ostringstream buf;
+
+ buf << Name << "_ChamberPress[" << EngineNumber << "]" << delimeter
+ << Thruster->GetThrusterLabels(EngineNumber, delimeter);
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGRocket::GetEngineValues(string delimeter)
+{
+ std::ostringstream buf;
+
+ buf << PC << delimeter << Thruster->GetThrusterValues(EngineNumber, delimeter);
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGRocket::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+ cout << " Engine Name: " << Name << endl;
+ cout << " Specific Heat Ratio = " << SHR << endl;
+ cout << " Maximum Chamber Pressure = " << maxPC << endl;
+ cout << " Propulsive Efficiency = " << propEff << endl;
+ cout << " MaxThrottle = " << MaxThrottle << endl;
+ cout << " MinThrottle = " << MinThrottle << endl;
+ cout << " FuelFlowMax = " << SLFuelFlowMax << endl;
+ cout << " OxiFlowMax = " << SLOxiFlowMax << endl;
+ cout << " Variance = " << Variance << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGRocket" << endl;
+ if (from == 1) cout << "Destroyed: FGRocket" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGRocket.h
+ Author: Jon S. Berndt
+ Date started: 09/12/2000
+
+ ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) --------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+09/12/2000 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGROCKET_H
+#define FGROCKET_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGEngine.h"
+#include <input_output/FGXMLElement.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_ROCKET "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models a generic rocket engine.
+ The rocket engine is modeled given the following parameters:
+ <ul>
+ <li>Chamber pressure (in psf)</li>
+ <li>Specific heat ratio (usually about 1.2 for hydrocarbon fuel and LOX)</li>
+ <li>Propulsive efficiency (in percent, from 0 to 1.0)</li>
+ <li>Variance (in percent, from 0 to 1.0, nominally 0.05)</li>
+ </ul>
+ Additionally, the following control inputs, operating characteristics, and
+ location are required, as with all other engine types:
+ <ul>
+ <li>Throttle setting (in percent, from 0 to 1.0)</li>
+ <li>Maximum allowable throttle setting</li>
+ <li>Minimum working throttle setting</li>
+ <li>Sea level fuel flow at maximum thrust</li>
+ <li>Sea level oxidizer flow at maximum thrust</li>
+ <li>X, Y, Z location in structural coordinate frame</li>
+ <li>Pitch and Yaw</li>
+ </ul>
+ The nozzle exit pressure (p2) is returned via a
+ call to FGNozzle::GetPowerRequired(). This exit pressure is used,
+ along with chamber pressure and specific heat ratio, to get the
+ thrust coefficient for the throttle setting. This thrust
+ coefficient is multiplied by the chamber pressure and then passed
+ to the nozzle Calculate() routine, where the thrust force is
+ determined.
+
+ @author Jon S. Berndt
+ $Id$
+ @see FGNozzle,
+ FGThruster,
+ FGForce,
+ FGEngine,
+ FGPropulsion,
+ FGTank
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGRocket : public FGEngine
+{
+public:
+ /** Constructor.
+ @param exec pointer to JSBSim parent object, the FDM Executive.
+ @param el a pointer to the XML Element instance representing the engine.
+ @param engine_number engine number */
+ FGRocket(FGFDMExec* exec, Element *el, int engine_number);
+
+ /** Destructor */
+ ~FGRocket(void);
+
+ /** Determines the thrust coefficient.
+ @return thrust coefficient times chamber pressure */
+ double Calculate(void);
+
+ /** Gets the chamber pressure.
+ @return chamber pressure in psf. */
+ double GetChamberPressure(void) {return PC;}
+
+ /** Gets the flame-out status.
+ The engine will "flame out" if the throttle is set below the minimum
+ sustainable setting.
+ @return true if engine has flamed out. */
+ bool GetFlameout(void) {return Flameout;}
+ string GetEngineLabels(string delimeter);
+ string GetEngineValues(string delimeter);
+
+private:
+ double SHR;
+ double maxPC;
+ double propEff;
+ double kFactor;
+ double Variance;
+ double PC;
+ bool Flameout;
+
+ void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGRotor.cpp
+ Author: Jon S. Berndt
+ Date started: 08/24/00
+ Purpose: Encapsulates the rotor object
+
+ ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+08/24/00 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGRotor.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_ROTOR;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+FGRotor::FGRotor(FGFDMExec *FDMExec) : FGThruster(FDMExec)
+{
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGRotor::~FGRotor()
+{
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGRotor::Calculate(double PowerAvailable)
+{
+ return 0.0;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGRotor::GetThrusterLabels(int id, string delimeter)
+{
+ return "";
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGRotor::GetThrusterValues(int id, string delimeter)
+{
+ return "";
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGRotor::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGRotor" << endl;
+ if (from == 1) cout << "Destroyed: FGRotor" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGRotor.h
+ Author: Jon S. Berndt
+ Date started: 08/24/00
+
+ ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+08/24/00 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGROTOR_H
+#define FGROTOR_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGThruster.h"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_ROTOR "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models a rotor (such as for a helicopter); NOT YET IMPLEMENTED.
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGRotor : public FGThruster {
+
+public:
+ FGRotor(FGFDMExec *FDMExec);
+ ~FGRotor();
+
+ double Calculate(double);
+ string GetThrusterLabels(int id, string delimeter);
+ string GetThrusterValues(int id, string delimeter);
+
+private:
+ void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGTank.cpp
+ Author: Jon Berndt
+ Date started: 01/21/99
+ Called by: FGAircraft
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+See header file.
+
+HISTORY
+--------------------------------------------------------------------------------
+01/21/99 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <FGFDMExec.h>
+#include <models/FGAuxiliary.h>
+#include "FGTank.h"
+
+#if !defined ( sgi ) || defined( __GNUC__ ) && (_COMPILER_VERSION < 740)
+using std::cerr;
+using std::endl;
+using std::cout;
+#endif
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_TANK;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGTank::FGTank(FGFDMExec* exec, Element* el)
+{
+ string token;
+ Element* element;
+ Area = 1.0;
+ Temperature = -9999.0;
+ Auxiliary = exec->GetAuxiliary();
+ Radius = Capacity = Contents = 0.0;
+
+ type = el->GetAttributeValue("type");
+ if (type == "FUEL") Type = ttFUEL;
+ else if (type == "OXIDIZER") Type = ttOXIDIZER;
+ else Type = ttUNKNOWN;
+
+ element = el->FindElement("location");
+ if (element) vXYZ = element->FindElementTripletConvertTo("IN");
+ else cerr << "No location found for this tank." << endl;
+
+ if (el->FindElement("radius"))
+ Radius = el->FindElementValueAsNumberConvertTo("radius", "IN");
+ if (el->FindElement("capacity"))
+ Capacity = el->FindElementValueAsNumberConvertTo("capacity", "LBS");
+ if (el->FindElement("contents"))
+ Contents = el->FindElementValueAsNumberConvertTo("contents", "LBS");
+ if (el->FindElement("temperature"))
+ Temperature = el->FindElementValueAsNumber("temperature");
+
+ Selected = true;
+
+ if (Capacity != 0) {
+ PctFull = 100.0*Contents/Capacity; // percent full; 0 to 100.0
+ } else {
+ Contents = 0;
+ PctFull = 0;
+ }
+
+ if (Temperature != -9999.0) Temperature = FahrenheitToCelsius(Temperature);
+ Area = 40.0 * pow(Capacity/1975, 0.666666667);
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGTank::~FGTank()
+{
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTank::Drain(double used)
+{
+ double shortage = Contents - used;
+
+ if (shortage >= 0) {
+ Contents -= used;
+ PctFull = 100.0*Contents/Capacity;
+ } else {
+ Contents = 0.0;
+ PctFull = 0.0;
+ Selected = false;
+ }
+ return shortage;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTank::Fill(double amount)
+{
+ double overage = 0.0;
+
+ Contents += amount;
+
+ if (Contents > Capacity) {
+ overage = Contents - Capacity;
+ Contents = Capacity;
+ PctFull = 100.0;
+ } else {
+ PctFull = Contents/Capacity*100.0;
+ }
+ return overage;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGTank::SetContents(double amount)
+{
+ Contents = amount;
+ if (Contents > Capacity) {
+ Contents = Capacity;
+ PctFull = 100.0;
+ } else {
+ PctFull = Contents/Capacity*100.0;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTank::Calculate(double dt)
+{
+ if (Temperature == -9999.0) return 0.0;
+ double HeatCapacity = 900.0; // Joules/lbm/C
+ double TempFlowFactor = 1.115; // Watts/sqft/C
+ double TAT = Auxiliary->GetTAT_C();
+ double Tdiff = TAT - Temperature;
+ double dT = 0.0; // Temp change due to one surface
+ if (fabs(Tdiff) > 0.1) {
+ dT = (TempFlowFactor * Area * Tdiff * dt) / (Contents * HeatCapacity);
+ }
+ return Temperature += (dT + dT); // For now, assume upper/lower the same
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGTank::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+ cout << " " << type << " tank holds " << Capacity << " lbs. " << type << endl;
+ cout << " currently at " << PctFull << "% of maximum capacity" << endl;
+ cout << " Tank location (X, Y, Z): " << vXYZ(eX) << ", " << vXYZ(eY) << ", " << vXYZ(eZ) << endl;
+ cout << " Effective radius: " << Radius << " inches" << endl;
+ cout << " Initial temperature: " << Temperature << " Fahrenheit" << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGTank" << endl;
+ if (from == 1) cout << "Destroyed: FGTank" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGTank.h
+ Author: Jon S. Berndt
+ Date started: 01/21/99
+
+ ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+Based on Flightgear code, which is based on LaRCSim. This class simulates
+a generic Tank.
+
+HISTORY
+--------------------------------------------------------------------------------
+01/21/99 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGTank_H
+#define FGTank_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <FGJSBBase.h>
+#include <input_output/FGXMLElement.h>
+#include <math/FGColumnVector3.h>
+// #include <FGAuxiliary.h>
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# include STL_STRING
+ SG_USING_STD(string);
+ SG_USING_STD(cerr);
+ SG_USING_STD(endl);
+ SG_USING_STD(cout);
+#else
+# include <string>
+ using std::string;
+# if !defined(sgi) || defined(__GNUC__) || (_COMPILER_VERSION >= 740)
+ using std::cerr;
+ using std::endl;
+ using std::cout;
+# endif
+#endif
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_TANK "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models a fuel tank.
+ @author Jon Berndt
+ @see Akbar, Raza et al. "A Simple Analysis of Fuel Addition to the CWT of
+ 747", California Institute of Technology, 1998
+<P>
+ Fuel temperature is calculated using the following assumptions:
+<P>
+ Fuel temperature will only be calculated for tanks which have an initial fuel
+ temperature specified in the configuration file.
+<P>
+ The surface area of the tank is estimated from the capacity in pounds. It
+ is assumed that the tank is a wing tank with dimensions h by 4h by 10h. The
+ volume of the tank is then 40(h)(h)(h). The area of the upper or lower
+ surface is then 40(h)(h). The volume is also equal to the capacity divided
+ by 49.368 lbs/cu-ft, for jet fuel. The surface area of one side can then be
+ derived from the tank's capacity.
+<P>
+ The heat capacity of jet fuel is assumed to be 900 Joules/lbm/K, and the
+ heat transfer factor of the tank is 1.115 Watts/sq-ft/K.
+<P>
+Configuration File Format
+<pre>
+\<AC_TANK TYPE="\<FUEL | OXIDIZER>" NUMBER="\<n>">
+ XLOC \<x location>
+ YLOC \<y location>
+ ZLOC \<z location>
+ RADIUS \<radius>
+ CAPACITY \<capacity>
+ CONTENTS \<contents>
+ TEMPERATURE \<fuel temperature>
+\</AC_TANK>
+</pre>
+Definition of the tank configuration file parameters:
+<pre>
+<b>TYPE</b> - One of FUEL or OXIDIZER.
+<b>XLOC</b> - Location of tank on aircraft's x-axis, inches.
+<b>YLOC</b> - Location of tank on aircraft's y-axis, inches.
+<b>ZLOC</b> - Location of tank on aircraft's z-axis, inches.
+<b>RADIUS</b> - Equivalent radius of tank, inches, for modeling slosh.
+<b>CAPACITY</b> - Capacity in pounds.
+<b>CONTENTS</b> - Initial contents in pounds.
+<b>TEMPERATURE</b> - Initial temperature in degrees Fahrenheit.
+</pre>
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGTank : public FGJSBBase
+{
+public:
+ FGTank(FGFDMExec* exec, Element* el);
+ ~FGTank();
+
+ double Drain(double);
+ double Calculate(double dt);
+ int GetType(void) {return Type;}
+ bool GetSelected(void) {return Selected;}
+ double GetPctFull(void) {return PctFull;}
+ double GetContents(void) {return Contents;}
+ double GetTemperature_degC(void) {return Temperature;}
+ double GetTemperature(void) {return CelsiusToFahrenheit(Temperature);}
+ const FGColumnVector3& GetXYZ(void) {return vXYZ;}
+ double GetXYZ(int idx) {return vXYZ(idx);}
+
+ double Fill(double amount);
+ void SetContents(double amount);
+ void SetTemperature(double temp) { Temperature = temp; }
+
+ enum TankType {ttUNKNOWN, ttFUEL, ttOXIDIZER};
+
+private:
+ TankType Type;
+ string type;
+ FGColumnVector3 vXYZ;
+ double Capacity;
+ double Radius;
+ double PctFull;
+ double Contents;
+ double Area;
+ double Temperature;
+ bool Selected;
+ FGAuxiliary* Auxiliary;
+ void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGThruster.cpp
+ Author: Jon S. Berndt
+ Date started: 08/23/00
+ Purpose: Encapsulates the thruster object
+
+ ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+HISTORY
+--------------------------------------------------------------------------------
+08/23/00 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <sstream>
+
+#include "FGThruster.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_THRUSTER;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+FGThruster::FGThruster(FGFDMExec *FDMExec) : FGForce(FDMExec)
+{
+ Type = ttDirect;
+ SetTransformType(FGForce::tCustom);
+
+ EngineNum = 0;
+ PropertyManager = FDMExec->GetPropertyManager();
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGThruster::FGThruster(FGFDMExec *FDMExec, Element *el, int num ): FGForce(FDMExec)
+{
+ Element* thruster_element = el->GetParent();
+ Element* element;
+ FGColumnVector3 location, orientation;
+
+ Type = ttDirect;
+ SetTransformType(FGForce::tCustom);
+
+ Name = el->GetName();
+
+ GearRatio = 1.0;
+
+ EngineNum = num;
+ ThrustCoeff = 0.0;
+ PropertyManager = FDMExec->GetPropertyManager();
+
+// Determine the initial location and orientation of this thruster and load the
+// thruster with this information.
+
+ element = thruster_element->FindElement("location");
+ if (element) location = element->FindElementTripletConvertTo("IN");
+ else cerr << "No thruster location found." << endl;
+
+ element = thruster_element->FindElement("orient");
+ if (element) orientation = element->FindElementTripletConvertTo("IN");
+ else cerr << "No thruster orientation found." << endl;
+
+ SetLocation(location);
+ SetAnglesToBody(orientation);
+
+// char property_name[80];
+// snprintf(property_name, 80, "propulsion/c-thrust[%u]", EngineNum);
+// PropertyManager->Tie( property_name, &ThrustCoeff );
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGThruster::~FGThruster()
+{
+// char property_name[80];
+// snprintf(property_name, 80, "propulsion/c-thrust[%u]", EngineNum);
+// PropertyManager->Untie( property_name );
+
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGThruster::GetThrusterLabels(int id, string delimeter)
+{
+ std::ostringstream buf;
+
+ buf << Name << "_Thrust[" << id << "]";
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGThruster::GetThrusterValues(int id, string delimeter)
+{
+ std::ostringstream buf;
+
+ buf << Thrust;
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGThruster::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGThruster" << endl;
+ if (from == 1) cout << "Destroyed: FGThruster" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGThruster.h
+ Author: Jon S. Berndt
+ Date started: 08/23/00
+
+ ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+08/24/00 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGTHRUSTER_H
+#define FGTHRUSTER_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGForce.h"
+#include <input_output/FGXMLElement.h>
+#include <input_output/FGPropertyManager.h>
+#include <math/FGColumnVector3.h>
+#include <string>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_THRUSTER "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Base class for specific thrusting devices such as propellers, nozzles, etc.
+ @author Jon Berndt
+ @version $Id$
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGThruster : public FGForce {
+
+public:
+ /// Constructor
+ FGThruster(FGFDMExec *FDMExec);
+ FGThruster(FGFDMExec *FDMExec, Element *el, int num );
+ /// Destructor
+ virtual ~FGThruster();
+
+ enum eType {ttNozzle, ttRotor, ttPropeller, ttDirect};
+
+ virtual double Calculate(double tt) {
+ Thrust = tt; vFn(1) = Thrust;
+ return Thrust;
+ }
+ void SetName(string name) {Name = name;}
+ virtual void SetRPM(double rpm) {};
+ virtual double GetPowerRequired(void) {return 0.0;}
+ virtual void SetdeltaT(double dt) {deltaT = dt;}
+ double GetThrust(void) {return Thrust;}
+ eType GetType(void) {return Type;}
+ string GetName(void) {return Name;}
+ virtual double GetRPM(void) { return 0.0; };
+ double GetGearRatio(void) {return GearRatio; }
+ virtual string GetThrusterLabels(int id, string delimeter);
+ virtual string GetThrusterValues(int id, string delimeter);
+
+ inline void SetThrustCoefficient(double ct) { ThrustCoeff = ct; }
+
+protected:
+ eType Type;
+ string Name;
+ double Thrust;
+ double PowerRequired;
+ double deltaT;
+ double GearRatio;
+ double ThrustCoeff;
+ int EngineNum;
+ FGPropertyManager* PropertyManager;
+ virtual void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGTurbine.cpp
+ Author: David Culp
+ Date started: 03/11/2003
+ Purpose: This module models a turbine engine.
+
+ ------------- Copyright (C) 2003 David Culp (davidculp2@comcast.net) ---------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+This class descends from the FGEngine class and models a turbine engine based
+on parameters given in the engine config file for this class
+
+HISTORY
+--------------------------------------------------------------------------------
+03/11/2003 DPC Created
+09/08/2003 DPC Changed Calculate() and added engine phases
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <vector>
+#include <sstream>
+
+#include "FGTurbine.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_TURBINE;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+
+FGTurbine::FGTurbine(FGFDMExec* exec, Element *el, int engine_number)
+ : FGEngine(exec, el, engine_number)
+{
+ SetDefaults();
+
+ Load(exec, el);
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGTurbine::~FGTurbine()
+{
+ if (IdleThrustLookup) delete IdleThrustLookup;
+ if (MilThrustLookup) delete MilThrustLookup;
+ if (MaxThrustLookup) delete MaxThrustLookup;
+ if (InjectionLookup) delete InjectionLookup;
+ unbind();
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The main purpose of Calculate() is to determine what phase the engine should
+// be in, then call the corresponding function.
+
+double FGTurbine::Calculate(void)
+{
+ TAT = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556;
+ dt = State->Getdt() * Propulsion->GetRate();
+ ThrottlePos = FCS->GetThrottlePos(EngineNumber);
+ if (ThrottlePos > 1.0) {
+ AugmentCmd = ThrottlePos - 1.0;
+ ThrottlePos -= AugmentCmd;
+ } else {
+ AugmentCmd = 0.0;
+ }
+
+ // When trimming is finished check if user wants engine OFF or RUNNING
+ if ((phase == tpTrim) && (dt > 0)) {
+ if (Running && !Starved) {
+ phase = tpRun;
+ N2 = IdleN2 + ThrottlePos * N2_factor;
+ N1 = IdleN1 + ThrottlePos * N1_factor;
+ OilTemp_degK = 366.0;
+ Cutoff = false;
+ }
+ else {
+ phase = tpOff;
+ Cutoff = true;
+ EGT_degC = TAT;
+ }
+ }
+
+ if (!Running && Cutoff && Starter) {
+ if (phase == tpOff) phase = tpSpinUp;
+ }
+ if (!Running && !Cutoff && (N2 > 15.0)) phase = tpStart;
+ if (Cutoff && (phase != tpSpinUp)) phase = tpOff;
+ if (dt == 0) phase = tpTrim;
+ if (Starved) phase = tpOff;
+ if (Stalled) phase = tpStall;
+ if (Seized) phase = tpSeize;
+
+ switch (phase) {
+ case tpOff: Thrust = Off(); break;
+ case tpRun: Thrust = Run(); break;
+ case tpSpinUp: Thrust = SpinUp(); break;
+ case tpStart: Thrust = Start(); break;
+ case tpStall: Thrust = Stall(); break;
+ case tpSeize: Thrust = Seize(); break;
+ case tpTrim: Thrust = Trim(); break;
+ default: Thrust = Off();
+ }
+
+ Thrust = Thruster->Calculate(Thrust); // allow thruster to modify thrust (i.e. reversing)
+
+ return Thrust;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTurbine::Off(void)
+{
+ double qbar = Auxiliary->Getqbar();
+ Running = false;
+ FuelFlow_pph = Seek(&FuelFlow_pph, 0, 1000.0, 10000.0);
+ N1 = Seek(&N1, qbar/10.0, N1/2.0, N1/2.0);
+ N2 = Seek(&N2, qbar/15.0, N2/2.0, N2/2.0);
+ EGT_degC = Seek(&EGT_degC, TAT, 11.7, 7.3);
+ OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0.2, 0.2);
+ OilPressure_psi = N2 * 0.62;
+ NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
+ EPR = Seek(&EPR, 1.0, 0.2, 0.2);
+ Augmentation = false;
+ return 0.0;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTurbine::Run()
+{
+ double idlethrust, milthrust, thrust;
+ double N2norm; // 0.0 = idle N2, 1.0 = maximum N2
+
+ idlethrust = MilThrust * IdleThrustLookup->GetValue();
+ milthrust = (MilThrust - idlethrust) * MilThrustLookup->GetValue();
+
+ Running = true;
+ Starter = false;
+
+ N2 = Seek(&N2, IdleN2 + ThrottlePos * N2_factor, delay, delay * 3.0);
+ N1 = Seek(&N1, IdleN1 + ThrottlePos * N1_factor, delay, delay * 2.4);
+ N2norm = (N2 - IdleN2) / N2_factor;
+ thrust = idlethrust + (milthrust * N2norm * N2norm);
+ EGT_degC = TAT + 363.1 + ThrottlePos * 357.1;
+ OilPressure_psi = N2 * 0.62;
+ OilTemp_degK = Seek(&OilTemp_degK, 366.0, 1.2, 0.1);
+
+ if (!Augmentation) {
+ correctedTSFC = TSFC * (0.84 + (1-N2norm)*(1-N2norm));
+ FuelFlow_pph = Seek(&FuelFlow_pph, thrust * correctedTSFC, 1000.0, 100000);
+ if (FuelFlow_pph < IdleFF) FuelFlow_pph = IdleFF;
+ NozzlePosition = Seek(&NozzlePosition, 1.0 - N2norm, 0.8, 0.8);
+ thrust = thrust * (1.0 - BleedDemand);
+ EPR = 1.0 + thrust/MilThrust;
+ }
+
+ if (AugMethod == 1) {
+ if ((ThrottlePos > 0.99) && (N2 > 97.0)) {Augmentation = true;}
+ else {Augmentation = false;}
+ }
+
+ if ((Augmented == 1) && Augmentation && (AugMethod < 2)) {
+ thrust = MaxThrustLookup->GetValue() * MaxThrust;
+ FuelFlow_pph = Seek(&FuelFlow_pph, thrust * ATSFC, 5000.0, 10000.0);
+ NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
+ }
+
+ if (AugMethod == 2) {
+ if (AugmentCmd > 0.0) {
+ Augmentation = true;
+ double tdiff = (MaxThrust * MaxThrustLookup->GetValue()) - thrust;
+ thrust += (tdiff * AugmentCmd);
+ FuelFlow_pph = Seek(&FuelFlow_pph, thrust * ATSFC, 5000.0, 10000.0);
+ NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
+ } else {
+ Augmentation = false;
+ }
+ }
+
+ if ((Injected == 1) && Injection) {
+ thrust = thrust * InjectionLookup->GetValue();
+ }
+
+ ConsumeFuel();
+ if (Cutoff) phase = tpOff;
+ if (Starved) phase = tpOff;
+
+ return thrust;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTurbine::SpinUp(void)
+{
+ Running = false;
+ FuelFlow_pph = 0.0;
+ N2 = Seek(&N2, 25.18, 3.0, N2/2.0);
+ N1 = Seek(&N1, 5.21, 1.0, N1/2.0);
+ EGT_degC = Seek(&EGT_degC, TAT, 11.7, 7.3);
+ OilPressure_psi = N2 * 0.62;
+ OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0.2, 0.2);
+ EPR = 1.0;
+ NozzlePosition = 1.0;
+ return 0.0;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTurbine::Start(void)
+{
+ if ((N2 > 15.0) && !Starved) { // minimum 15% N2 needed for start
+ Cranking = true; // provided for sound effects signal
+ if (N2 < IdleN2) {
+ N2 = Seek(&N2, IdleN2, 2.0, N2/2.0);
+ N1 = Seek(&N1, IdleN1, 1.4, N1/2.0);
+ EGT_degC = Seek(&EGT_degC, TAT + 363.1, 21.3, 7.3);
+ FuelFlow_pph = Seek(&FuelFlow_pph, IdleFF, 103.7, 103.7);
+ OilPressure_psi = N2 * 0.62;
+ ConsumeFuel();
+ }
+ else {
+ phase = tpRun;
+ Running = true;
+ Starter = false;
+ Cranking = false;
+ }
+ }
+ else { // no start if N2 < 15%
+ phase = tpOff;
+ Starter = false;
+ }
+
+ return 0.0;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTurbine::Stall(void)
+{
+ double qbar = Auxiliary->Getqbar();
+ EGT_degC = TAT + 903.14;
+ FuelFlow_pph = IdleFF;
+ N1 = Seek(&N1, qbar/10.0, 0, N1/10.0);
+ N2 = Seek(&N2, qbar/15.0, 0, N2/10.0);
+ ConsumeFuel();
+ if (ThrottlePos < 0.01) phase = tpRun; // clear the stall with throttle
+
+ return 0.0;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTurbine::Seize(void)
+{
+ double qbar = Auxiliary->Getqbar();
+ N2 = 0.0;
+ N1 = Seek(&N1, qbar/20.0, 0, N1/15.0);
+ FuelFlow_pph = IdleFF;
+ ConsumeFuel();
+ OilPressure_psi = 0.0;
+ OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0, 0.2);
+ Running = false;
+ return 0.0;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTurbine::Trim()
+{
+ double idlethrust, milthrust, thrust, tdiff;
+ idlethrust = MilThrust * IdleThrustLookup->GetValue();
+ milthrust = (MilThrust - idlethrust) * MilThrustLookup->GetValue();
+ thrust = (idlethrust + (milthrust * ThrottlePos * ThrottlePos))
+ * (1.0 - BleedDemand);
+
+ if (AugMethod == 1) {
+ if ((ThrottlePos > 0.99) && (N2 > 97.0)) {Augmentation = true;}
+ else {Augmentation = false;}
+ }
+
+ if ((Augmented == 1) && Augmentation && (AugMethod < 2)) {
+ thrust = MaxThrust * MaxThrustLookup->GetValue();
+ }
+
+ if (AugMethod == 2) {
+ if (AugmentCmd > 0.0) {
+ tdiff = (MaxThrust * MaxThrustLookup->GetValue()) - thrust;
+ thrust += (tdiff * AugmentCmd);
+ }
+ }
+
+ if ((Injected == 1) && Injection) {
+ thrust = thrust * InjectionLookup->GetValue();
+ }
+
+ return thrust;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTurbine::CalcFuelNeed(void)
+{
+ return FuelFlow_pph /3600 * State->Getdt() * Propulsion->GetRate();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTurbine::GetPowerAvailable(void) {
+ if( ThrottlePos <= 0.77 )
+ return 64.94*ThrottlePos;
+ else
+ return 217.38*ThrottlePos - 117.38;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTurbine::Seek(double *var, double target, double accel, double decel) {
+ double v = *var;
+ if (v > target) {
+ v -= dt * decel;
+ if (v < target) v = target;
+ } else if (v < target) {
+ v += dt * accel;
+ if (v > target) v = target;
+ }
+ return v;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGTurbine::SetDefaults(void)
+{
+ N1 = N2 = 0.0;
+ Type = etTurbine;
+ MilThrust = 10000.0;
+ MaxThrust = 10000.0;
+ BypassRatio = 0.0;
+ TSFC = 0.8;
+ correctedTSFC = TSFC;
+ ATSFC = 1.7;
+ IdleN1 = 30.0;
+ IdleN2 = 60.0;
+ MaxN1 = 100.0;
+ MaxN2 = 100.0;
+ Augmented = 0;
+ AugMethod = 0;
+ Injected = 0;
+ BleedDemand = 0.0;
+ ThrottlePos = 0.0;
+ AugmentCmd = 0.0;
+ InletPosition = 1.0;
+ NozzlePosition = 1.0;
+ Augmentation = false;
+ Injection = false;
+ Reversed = false;
+ Cutoff = true;
+ phase = tpOff;
+ Stalled = false;
+ Seized = false;
+ Overtemp = false;
+ Fire = false;
+ EGT_degC = 0.0;
+ IdleThrustLookup = MilThrustLookup = MaxThrustLookup = InjectionLookup = 0;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGTurbine::Load(FGFDMExec* exec, Element *el)
+{
+ char property_prefix[80];
+ snprintf(property_prefix, 80, "propulsion/engine[%u]/", EngineNumber);
+
+ if (el->FindElement("milthrust"))
+ MilThrust = el->FindElementValueAsNumberConvertTo("milthrust","LBS");
+ if (el->FindElement("maxthrust"))
+ MaxThrust = el->FindElementValueAsNumberConvertTo("maxthrust","LBS");
+ if (el->FindElement("bypassratio"))
+ BypassRatio = el->FindElementValueAsNumber("bypassratio");
+ if (el->FindElement("bleed"))
+ BleedDemand = el->FindElementValueAsNumber("bleed");
+ if (el->FindElement("tsfc"))
+ TSFC = el->FindElementValueAsNumber("tsfc");
+ if (el->FindElement("atsfc"))
+ ATSFC = el->FindElementValueAsNumber("atsfc");
+ if (el->FindElement("idlen1"))
+ IdleN1 = el->FindElementValueAsNumber("idlen1");
+ if (el->FindElement("idlen2"))
+ IdleN2 = el->FindElementValueAsNumber("idlen2");
+ if (el->FindElement("maxn1"))
+ MaxN1 = el->FindElementValueAsNumber("maxn1");
+ if (el->FindElement("maxn2"))
+ MaxN2 = el->FindElementValueAsNumber("maxn2");
+ if (el->FindElement("augmented"))
+ Augmented = (int)el->FindElementValueAsNumber("augmented");
+ if (el->FindElement("augmethod"))
+ AugMethod = (int)el->FindElementValueAsNumber("augmethod");
+ if (el->FindElement("injected"))
+ Injected = (int)el->FindElementValueAsNumber("injected");
+
+ Element *function_element;
+ string name;
+ FGPropertyManager* PropertyManager = exec->GetPropertyManager();
+
+ while (true) {
+ function_element = el->FindNextElement("function");
+ if (!function_element) break;
+ name = function_element->GetAttributeValue("name");
+ if (name == "IdleThrust") {
+ IdleThrustLookup = new FGFunction(PropertyManager, function_element, property_prefix);
+ } else if (name == "MilThrust") {
+ MilThrustLookup = new FGFunction(PropertyManager, function_element, property_prefix);
+ } else if (name == "AugThrust") {
+ MaxThrustLookup = new FGFunction(PropertyManager, function_element, property_prefix);
+ } else if (name == "Injection") {
+ InjectionLookup = new FGFunction(PropertyManager, function_element, property_prefix);
+ } else {
+ cerr << "Unknown function type: " << name << " in turbine definition." <<
+ endl;
+ }
+ }
+
+ // Pre-calculations and initializations
+
+ delay = 60.0 / (BypassRatio + 3.0);
+ N1_factor = MaxN1 - IdleN1;
+ N2_factor = MaxN2 - IdleN2;
+ OilTemp_degK = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556 + 273.0;
+ IdleFF = pow(MilThrust, 0.2) * 107.0; // just an estimate
+
+ bindmodel();
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGTurbine::GetEngineLabels(string delimeter)
+{
+ std::ostringstream buf;
+
+ buf << Name << "_N1[" << EngineNumber << "]" << delimeter
+ << Name << "_N2[" << EngineNumber << "]" << delimeter
+ << Thruster->GetThrusterLabels(EngineNumber, delimeter);
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGTurbine::GetEngineValues(string delimeter)
+{
+ std::ostringstream buf;
+
+ buf << N1 << delimeter
+ << N2 << delimeter
+ << Thruster->GetThrusterValues(EngineNumber, delimeter);
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGTurbine::bindmodel()
+{
+ char property_name[80];
+
+ snprintf(property_name, 80, "propulsion/engine[%u]/n1", EngineNumber);
+ PropertyManager->Tie( property_name, &N1);
+ snprintf(property_name, 80, "propulsion/engine[%u]/n2", EngineNumber);
+ PropertyManager->Tie( property_name, &N2);
+ snprintf(property_name, 80, "propulsion/engine[%u]/thrust", EngineNumber);
+ PropertyManager->Tie( property_name, this, &FGTurbine::GetThrust);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGTurbine::unbind()
+{
+ char property_name[80];
+
+ snprintf(property_name, 80, "propulsion/engine[%u]/n1", EngineNumber);
+ PropertyManager->Untie(property_name);
+ snprintf(property_name, 80, "propulsion/engine[%u]/n2", EngineNumber);
+ PropertyManager->Untie(property_name);
+ snprintf(property_name, 80, "propulsion/engine[%u]/thrust", EngineNumber);
+ PropertyManager->Untie(property_name);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGTurbine::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ }
+ if (from == 2) { // called from Load()
+ cout << "\n Engine Name: " << Name << endl;
+ cout << " MilThrust: " << MilThrust << endl;
+ cout << " MaxThrust: " << MaxThrust << endl;
+ cout << " BypassRatio: " << BypassRatio << endl;
+ cout << " TSFC: " << TSFC << endl;
+ cout << " ATSFC: " << ATSFC << endl;
+ cout << " IdleN1: " << IdleN1 << endl;
+ cout << " IdleN2: " << IdleN2 << endl;
+ cout << " MaxN1: " << MaxN1 << endl;
+ cout << " MaxN2: " << MaxN2 << endl;
+ cout << " Augmented: " << Augmented << endl;
+ cout << " AugMethod: " << AugMethod << endl;
+ cout << " Injected: " << Injected << endl;
+ cout << " MinThrottle: " << MinThrottle << endl;
+
+ cout << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGTurbine" << endl;
+ if (from == 1) cout << "Destroyed: FGTurbine" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGTurbine.h
+ Author: David Culp
+ Date started: 03/11/2003
+
+ ------------- Copyright (C) 2003 David Culp (davidculp2@comcast.net)----------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+03/11/2003 DPC Created, based on FGTurbine
+09/22/2003 DPC Added starting, stopping, new framework
+04/29/2004 DPC Renamed from FGSimTurbine to FGTurbine
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGTURBINE_H
+#define FGTURBINE_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <vector>
+#include "FGEngine.h"
+#include <input_output/FGXMLElement.h>
+#include <math/FGFunction.h>
+
+#define ID_TURBINE "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** This class models a turbine engine. Based on Jon Berndt's FGTurbine module.
+ Here the term "phase" signifies the engine's mode of operation. At any given
+ time the engine is in only one phase. At simulator startup the engine will be
+ placed in the Trim phase in order to provide a simplified thrust value without
+ throttle lag. When trimming is complete the engine will go to the Off phase,
+ unless the value FGEngine::Running has been previously set to true, in which
+ case the engine will go to the Run phase. Once an engine is in the Off phase
+ the full starting procedure (or airstart) must be used to get it running.
+<P>
+ - STARTING (on ground):
+ -# Set the control FGEngine::Starter to true. The engine will spin up to
+ a maximum of about %25 N2 (%5.2 N1). This simulates the action of a
+ pneumatic starter.
+ -# After reaching %15 N2 set the control FGEngine::Cutoff to false. If fuel
+ is available the engine will now accelerate to idle. The starter will
+ automatically be set to false after the start cycle.
+<P>
+ - STARTING (in air):
+ -# Increase speed to obtain a minimum of %15 N2. If this is not possible,
+ the starter may be used to assist.
+ -# Place the control FGEngine::Cutoff to false.
+<P>
+ Ignition is assumed to be on anytime the Cutoff control is set to false,
+ therefore a seperate ignition system is not modeled.
+
+Configuration File Format
+<pre>
+\<FG_TURBINE NAME="<name>">
+ MILTHRUST \<thrust>
+ MAXTHRUST \<thrust>
+ BYPASSRATIO \<bypass ratio>
+ TSFC \<thrust specific fuel consumption>
+ ATSFC \<afterburning thrust specific fuel consumption>
+ IDLEN1 \<idle N1>
+ IDLEN2 \<idle N2>
+ MAXN1 \<max N1>
+ MAXN2 \<max N2>
+ AUGMENTED \<0|1>
+ AUGMETHOD \<0|1>
+ INJECTED \<0|1>
+ ...
+\</FG_TURBINE>
+</pre>
+Definition of the turbine engine configuration file parameters:
+<pre>
+<b>MILTHRUST</b> - Maximum thrust, static, at sea level, lbf.
+<b>MAXTHRUST</b> - Afterburning thrust, static, at sea level, lbf
+[this value will be ignored when AUGMENTED is zero (false)].
+<b>BYPASSRATIO</b> - Ratio of bypass air flow to core air flow.
+<b>TSFC</b> - Thrust-specific fuel consumption, lbm/hr/lbf
+[i.e. fuel flow divided by thrust].
+<b>ATSFC</b> - Afterburning TSFC, lbm/hr/lbf
+[this value will be ignored when AUGMENTED is zero (false)]
+<b>IDLEN1</b> - Fan rotor rpm (% of max) at idle
+<b>IDLEN2</b> - Core rotor rpm (% of max) at idle
+<b>MAXN1</b> - Fan rotor rpm (% of max) at full throttle [not always 100!]
+<b>MAXN2</b> - Core rotor rpm (% of max) at full throttle [not always 100!]
+<b>AUGMENTED</b>
+ 0 == afterburner not installed
+ 1 == afterburner installed
+<b>AUGMETHOD</b>
+ 0 == afterburner activated by property /engines/engine[n]/augmentation
+ 1 == afterburner activated by pushing throttle above 99% position
+ 2 == throttle range is expanded in the FCS, and values above 1.0 are afterburner range
+ [this item will be ignored when AUGMENTED == 0]
+<b>INJECTED</b>
+ 0 == Water injection not installed
+ 1 == Water injection installed
+</pre>
+ @author David P. Culp
+ @version "$Id$"
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGTurbine : public FGEngine
+{
+public:
+ /** Constructor
+ @param Executive pointer to executive structure
+ @param el pointer to the XML element representing the turbine engine
+ @param engine_number engine number*/
+ FGTurbine(FGFDMExec* Executive, Element *el, int engine_number);
+ /// Destructor
+ ~FGTurbine();
+
+ enum phaseType { tpOff, tpRun, tpSpinUp, tpStart, tpStall, tpSeize, tpTrim };
+
+ double Calculate(void);
+ double CalcFuelNeed(void);
+ double GetPowerAvailable(void);
+ double GetThrust(void) const {return Thrust;}
+ double Seek(double* var, double target, double accel, double decel);
+
+ phaseType GetPhase(void) { return phase; }
+
+ bool GetOvertemp(void) const {return Overtemp; }
+ bool GetInjection(void) const {return Injection;}
+ bool GetFire(void) const { return Fire; }
+ bool GetAugmentation(void) const {return Augmentation;}
+ bool GetReversed(void) const { return Reversed; }
+ bool GetCutoff(void) const { return Cutoff; }
+ int GetIgnition(void) const {return Ignition;}
+
+ double GetInlet(void) const { return InletPosition; }
+ double GetNozzle(void) const { return NozzlePosition; }
+ double GetBleedDemand(void) const {return BleedDemand;}
+ double GetN1(void) const {return N1;}
+ double GetN2(void) const {return N2;}
+ double GetEPR(void) const {return EPR;}
+ double GetEGT(void) const {return EGT_degC;}
+
+ double getOilPressure_psi () const {return OilPressure_psi;}
+ double getOilTemp_degF (void) {return KelvinToFahrenheit(OilTemp_degK);}
+
+ void SetInjection(bool injection) {Injection = injection;}
+ void SetIgnition(int ignition) {Ignition = ignition;}
+ void SetAugmentation(bool augmentation) {Augmentation = augmentation;}
+ void SetPhase( phaseType p ) { phase = p; }
+ void SetEPR(double epr) {EPR = epr;}
+ void SetBleedDemand(double bleedDemand) {BleedDemand = bleedDemand;}
+ void SetReverse(bool reversed) { Reversed = reversed; }
+ void SetCutoff(bool cutoff) { Cutoff = cutoff; }
+
+ string GetEngineLabels(string delimeter);
+ string GetEngineValues(string delimeter);
+
+private:
+
+ phaseType phase; ///< Operating mode, or "phase"
+ double MilThrust; ///< Maximum Unaugmented Thrust, static @ S.L. (lbf)
+ double MaxThrust; ///< Maximum Augmented Thrust, static @ S.L. (lbf)
+ double BypassRatio; ///< Bypass Ratio
+ double TSFC; ///< Thrust Specific Fuel Consumption (lbm/hr/lbf)
+ double ATSFC; ///< Augmented TSFC (lbm/hr/lbf)
+ double IdleN1; ///< Idle N1
+ double IdleN2; ///< Idle N2
+ double N1; ///< N1
+ double N2; ///< N2
+ double MaxN1; ///< N1 at 100% throttle
+ double MaxN2; ///< N2 at 100% throttle
+ double IdleFF; ///< Idle Fuel Flow (lbm/hr)
+ double delay; ///< Inverse spool-up time from idle to 100% (seconds)
+ double dt; ///< Simulator time slice
+ double N1_factor; ///< factor to tie N1 and throttle
+ double N2_factor; ///< factor to tie N2 and throttle
+ double ThrottlePos; ///< FCS-supplied throttle position
+ double AugmentCmd; ///< modulated afterburner command (0.0 to 1.0)
+ double TAT; ///< total air temperature (deg C)
+ bool Stalled; ///< true if engine is compressor-stalled
+ bool Seized; ///< true if inner spool is seized
+ bool Overtemp; ///< true if EGT exceeds limits
+ bool Fire; ///< true if engine fire detected
+ bool Injection;
+ bool Augmentation;
+ bool Reversed;
+ bool Cutoff;
+ int Injected; ///< = 1 if water injection installed
+ int Ignition;
+ int Augmented; ///< = 1 if augmentation installed
+ int AugMethod; ///< = 0 if using property /engine[n]/augmentation
+ ///< = 1 if using last 1% of throttle movement
+ ///< = 2 if using FCS-defined throttle
+ double EGT_degC;
+ double EPR;
+ double OilPressure_psi;
+ double OilTemp_degK;
+ double BleedDemand;
+ double InletPosition;
+ double NozzlePosition;
+ double correctedTSFC;
+
+ double Off(void);
+ double Run();
+ double SpinUp(void);
+ double Start(void);
+ double Stall(void);
+ double Seize(void);
+ double Trim();
+
+ FGFunction *IdleThrustLookup;
+ FGFunction *MilThrustLookup;
+ FGFunction *MaxThrustLookup;
+ FGFunction *InjectionLookup;
+
+ void SetDefaults(void);
+ bool Load(FGFDMExec *exec, Element *el);
+ void bindmodel(void);
+ void unbind(void);
+ void Debug(int from);
+
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
+
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGTurboProp.cpp
+ Author: Jiri "Javky" Javurek
+ based on SimTurbine and Turbine engine from David Culp
+ Date started: 05/14/2004
+ Purpose: This module models a turbo propeller engine.
+
+ ------------- Copyright (C) 2004 (javky@email.cz) ---------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+
+This class descends from the FGEngine class and models a Turbo propeller engine
+based on parameters given in the engine config file for this class
+
+HISTORY
+--------------------------------------------------------------------------------
+05/14/2004 Created
+
+//JVK (mark)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <vector>
+#include <sstream>
+#include "FGTurboProp.h"
+
+#include "FGPropeller.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_TURBOPROP;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGTurboProp::FGTurboProp(FGFDMExec* exec, Element *el, int engine_number)
+ : FGEngine(exec, el, engine_number)
+{
+ SetDefaults();
+
+ Load(exec, el);
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGTurboProp::~FGTurboProp()
+{
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGTurboProp::Load(FGFDMExec* exec, Element *el)
+{
+ char property_prefix[80];
+ snprintf(property_prefix, 80, "propulsion/engine[%u]/", EngineNumber);
+
+ IdleFF=-1;
+ MaxStartingTime = 999999; //very big timeout -> infinite
+ Ielu_max_torque=-1;
+
+// ToDo: Need to make sure units are properly accounted for below.
+
+ if (el->FindElement("milthrust"))
+ MilThrust = el->FindElementValueAsNumberConvertTo("milthrust","LBS");
+ if (el->FindElement("idlen1"))
+ IdleN1 = el->FindElementValueAsNumber("idlen1");
+ if (el->FindElement("idlen2"))
+ IdleN2 = el->FindElementValueAsNumber("idlen1");
+ if (el->FindElement("maxn1"))
+ MaxN1 = el->FindElementValueAsNumber("maxn1");
+ if (el->FindElement("maxn2"))
+ MaxN2 = el->FindElementValueAsNumber("maxn2");
+ if (el->FindElement("betarangeend"))
+ BetaRangeThrottleEnd = el->FindElementValueAsNumber("betarangeend")/100.0;
+ if (el->FindElement("reversemaxpower"))
+ ReverseMaxPower = el->FindElementValueAsNumber("reversemaxpower")/100.0;
+
+ if (el->FindElement("maxpower"))
+ MaxPower = el->FindElementValueAsNumber("maxpower");
+ if (el->FindElement("idlefuelflow"))
+ IdleFF = el->FindElementValueAsNumber("idlefuelflow");
+ if (el->FindElement("psfc"))
+ PSFC = el->FindElementValueAsNumber("psfc");
+ if (el->FindElement("n1idle_max_delay"))
+ Idle_Max_Delay = el->FindElementValueAsNumber("n1idle_max_delay");
+ if (el->FindElement("maxstartingtime"))
+ MaxStartingTime = el->FindElementValueAsNumber("maxstartingtime");
+ if (el->FindElement("startern1"))
+ StarterN1 = el->FindElementValueAsNumber("startern1");
+ if (el->FindElement("ielumaxtorque"))
+ Ielu_max_torque = el->FindElementValueAsNumber("ielumaxtorque");
+ if (el->FindElement("itt_delay"))
+ ITT_Delay = el->FindElementValueAsNumber("itt_delay");
+
+ Element *table_element;
+ string name;
+ FGPropertyManager* PropertyManager = exec->GetPropertyManager();
+
+ while (true) {
+ table_element = el->FindNextElement("table");
+ if (!table_element) break;
+ name = table_element->GetAttributeValue("name");
+ if (name == "EnginePowerVC") {
+ EnginePowerVC = new FGTable(PropertyManager, table_element);
+ } else if (name == "EnginePowerRPM_N1") {
+ EnginePowerRPM_N1 = new FGTable(PropertyManager, table_element);
+ } else if (name == "ITT_N1") {
+ ITT_N1 = new FGTable(PropertyManager, table_element);
+ } else {
+ cerr << "Unknown table type: " << name << " in turbine definition." <<
+ endl;
+ }
+ }
+
+ // Pre-calculations and initializations
+
+ delay=1;
+ N1_factor = MaxN1 - IdleN1;
+ N2_factor = MaxN2 - IdleN2;
+ OilTemp_degK = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556 + 273.0;
+ if (IdleFF==-1) IdleFF = pow(MilThrust, 0.2) * 107.0; // just an estimate
+
+ cout << "ENG POWER:" << EnginePowerRPM_N1->GetValue(1200,90) << "\n";
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The main purpose of Calculate() is to determine what phase the engine should
+// be in, then call the corresponding function.
+
+double FGTurboProp::Calculate(void)
+{
+ TAT = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556;
+ dt = State->Getdt() * Propulsion->GetRate();
+
+ ThrottleCmd = FCS->GetThrottleCmd(EngineNumber);
+
+ Prop_RPM = Thruster->GetRPM() * Thruster->GetGearRatio();
+ if (Thruster->GetType() == FGThruster::ttPropeller) {
+ ((FGPropeller*)Thruster)->SetAdvance(FCS->GetPropAdvance(EngineNumber));
+ ((FGPropeller*)Thruster)->SetFeather(FCS->GetPropFeather(EngineNumber));
+ ((FGPropeller*)Thruster)->SetReverse(Reversed);
+ if (Reversed) {
+ ((FGPropeller*)Thruster)->SetReverseCoef(ThrottleCmd);
+ } else {
+ ((FGPropeller*)Thruster)->SetReverseCoef(0.0);
+ }
+ }
+
+ if (Reversed) {
+ if (ThrottleCmd < BetaRangeThrottleEnd) {
+ ThrottleCmd = 0.0; // idle when in Beta-range
+ } else {
+ // when reversed:
+ ThrottleCmd = (ThrottleCmd-BetaRangeThrottleEnd)/(1-BetaRangeThrottleEnd) * ReverseMaxPower;
+ }
+ }
+
+ // When trimming is finished check if user wants engine OFF or RUNNING
+ if ((phase == tpTrim) && (dt > 0)) {
+ if (Running && !Starved) {
+ phase = tpRun;
+ N2 = IdleN2;
+ N1 = IdleN1;
+ OilTemp_degK = 366.0;
+ Cutoff = false;
+ } else {
+ phase = tpOff;
+ Cutoff = true;
+ Eng_ITT_degC = TAT;
+ Eng_Temperature = TAT;
+ OilTemp_degK = TAT+273.15;
+ }
+ }
+
+ if (!Running && Starter) {
+ if (phase == tpOff) {
+ phase = tpSpinUp;
+ if (StartTime < 0) StartTime=0;
+ }
+ }
+ if (!Running && !Cutoff && (N1 > 15.0)) {
+ phase = tpStart;
+ StartTime = -1;
+ }
+ if (Cutoff && (phase != tpSpinUp)) phase = tpOff;
+ if (dt == 0) phase = tpTrim;
+ if (Starved) phase = tpOff;
+ if (Condition >= 10) {
+ phase = tpOff;
+ StartTime=-1;
+ }
+
+ if (Condition < 1) {
+ if (Ielu_max_torque > 0
+ && -Ielu_max_torque > ((FGPropeller*)(Thruster))->GetTorque()
+ && ThrottleCmd >= OldThrottle ) {
+ ThrottleCmd = OldThrottle - 0.1 * dt; //IELU down
+ Ielu_intervent = true;
+ } else if (Ielu_max_torque > 0 && Ielu_intervent && ThrottleCmd >= OldThrottle) {
+ ThrottleCmd = OldThrottle;
+ ThrottleCmd = OldThrottle + 0.05 * dt; //IELU up
+ Ielu_intervent = true;
+ } else {
+ Ielu_intervent = false;
+ }
+ } else {
+ Ielu_intervent = false;
+ }
+ OldThrottle = ThrottleCmd;
+
+ switch (phase) {
+ case tpOff: Eng_HP = Off(); break;
+ case tpRun: Eng_HP = Run(); break;
+ case tpSpinUp: Eng_HP = SpinUp(); break;
+ case tpStart: Eng_HP = Start(); break;
+ default: Eng_HP = 0;
+ }
+
+ //printf ("EngHP: %lf / Requi: %lf\n",Eng_HP,Prop_Required_Power);
+ return Thruster->Calculate((Eng_HP * hptoftlbssec)-Thruster->GetPowerRequired());
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTurboProp::Off(void)
+{
+ double qbar = Auxiliary->Getqbar();
+ Running = false; EngStarting = false;
+
+ FuelFlow_pph = Seek(&FuelFlow_pph, 0, 800.0, 800.0);
+
+ //allow the air turn with generator
+ N1 = ExpSeek(&N1, qbar/15.0, Idle_Max_Delay*2.5, Idle_Max_Delay * 5);
+
+ OilTemp_degK = ExpSeek(&OilTemp_degK,273.15 + TAT, 400 , 400);
+
+ Eng_Temperature = ExpSeek(&Eng_Temperature,TAT,300,400);
+ double ITT_goal = ITT_N1->GetValue(N1,0.1) + ((N1>20) ? 0.0 : (20-N1)/20.0 * Eng_Temperature);
+ Eng_ITT_degC = ExpSeek(&Eng_ITT_degC,ITT_goal,ITT_Delay,ITT_Delay*1.2);
+
+ OilPressure_psi = (N1/100.0*0.25+(0.1-(OilTemp_degK-273.15)*0.1/80.0)*N1/100.0) / 7692.0e-6; //from MPa to psi
+
+ ConsumeFuel(); // for possible setting Starved = false when fuel tank
+ // is refilled (fuel crossfeed etc.)
+
+ if (Prop_RPM>5) return -0.012; // friction in engine when propeller spining (estimate)
+ return 0.0;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTurboProp::Run(void)
+{
+ double idlethrust, milthrust, thrust, EngPower_HP, eff_coef;
+ Running = true; Starter = false; EngStarting = false;
+
+//---
+ double old_N1 = N1;
+ N1 = ExpSeek(&N1, IdleN1 + ThrottleCmd * N1_factor, Idle_Max_Delay, Idle_Max_Delay * 2.4);
+
+ EngPower_HP = EnginePowerRPM_N1->GetValue(Prop_RPM,N1);
+ EngPower_HP *= EnginePowerVC->GetValue();
+ if (EngPower_HP > MaxPower) EngPower_HP = MaxPower;
+
+ eff_coef = 9.333 - (N1)/12; // 430%Fuel at 60%N1
+ FuelFlow_pph = PSFC * EngPower_HP * eff_coef;
+
+ Eng_Temperature = ExpSeek(&Eng_Temperature,Eng_ITT_degC,300,400);
+ double ITT_goal = ITT_N1->GetValue((N1-old_N1)*300+N1,1);
+ Eng_ITT_degC = ExpSeek(&Eng_ITT_degC,ITT_goal,ITT_Delay,ITT_Delay*1.2);
+
+ OilPressure_psi = (N1/100.0*0.25+(0.1-(OilTemp_degK-273.15)*0.1/80.0)*N1/100.0) / 7692.0e-6; //from MPa to psi
+//---
+ EPR = 1.0 + thrust/MilThrust;
+
+ OilTemp_degK = Seek(&OilTemp_degK, 353.15, 0.4-N1*0.001, 0.04);
+
+ ConsumeFuel();
+
+ if (Cutoff) phase = tpOff;
+ if (Starved) phase = tpOff;
+
+ return EngPower_HP;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTurboProp::SpinUp(void)
+{
+ double EngPower_HP;
+ Running = false; EngStarting = true;
+ FuelFlow_pph = 0.0;
+
+ if (!GeneratorPower) {
+ EngStarting=false;
+ phase=tpOff;
+ StartTime = -1;
+ return 0.0;
+ }
+
+ N1 = ExpSeek(&N1, StarterN1, Idle_Max_Delay * 6, Idle_Max_Delay * 2.4);
+
+ Eng_Temperature = ExpSeek(&Eng_Temperature,TAT,300,400);
+ double ITT_goal = ITT_N1->GetValue(N1,0.1) + ((N1>20) ? 0.0 : (20-N1)/20.0 * Eng_Temperature);
+ Eng_ITT_degC = ExpSeek(&Eng_ITT_degC,ITT_goal,ITT_Delay,ITT_Delay*1.2);
+
+ OilTemp_degK = ExpSeek(&OilTemp_degK,273.15 + TAT, 400 , 400);
+
+ OilPressure_psi = (N1/100.0*0.25+(0.1-(OilTemp_degK-273.15)*0.1/80.0)*N1/100.0) / 7692.0e-6; //from MPa to psi
+ NozzlePosition = 1.0;
+
+ EngPower_HP = EnginePowerRPM_N1->GetValue(Prop_RPM,N1);
+ EngPower_HP *= EnginePowerVC->GetValue();
+ if (EngPower_HP > MaxPower) EngPower_HP = MaxPower;
+
+ if (StartTime>=0) StartTime+=dt;
+ if (StartTime > MaxStartingTime && MaxStartingTime > 0) { //start failed due timeout
+ phase = tpOff;
+ StartTime = -1;
+ }
+
+ ConsumeFuel(); // for possible setting Starved = false when fuel tank
+ // is refilled (fuel crossfeed etc.)
+
+ return EngPower_HP;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTurboProp::Start(void)
+{
+ double EngPower_HP,eff_coef;
+ EngStarting = false;
+ if ((N1 > 15.0) && !Starved) { // minimum 15% N2 needed for start
+ double old_N1 = N1;
+ Cranking = true; // provided for sound effects signal
+ if (N1 < IdleN1) {
+ EngPower_HP = EnginePowerRPM_N1->GetValue(Prop_RPM,N1);
+ EngPower_HP *= EnginePowerVC->GetValue();
+ if (EngPower_HP > MaxPower) EngPower_HP = MaxPower;
+ N1 = ExpSeek(&N1, IdleN1*1.1, Idle_Max_Delay*4, Idle_Max_Delay * 2.4);
+ eff_coef = 9.333 - (N1)/12; // 430%Fuel at 60%N1
+ FuelFlow_pph = PSFC * EngPower_HP * eff_coef;
+ Eng_Temperature = ExpSeek(&Eng_Temperature,Eng_ITT_degC,300,400);
+ double ITT_goal = ITT_N1->GetValue((N1-old_N1)*300+N1,1);
+ Eng_ITT_degC = ExpSeek(&Eng_ITT_degC,ITT_goal,ITT_Delay,ITT_Delay*1.2);
+
+ OilPressure_psi = (N1/100.0*0.25+(0.1-(OilTemp_degK-273.15)*0.1/80.0)*N1/100.0) / 7692.0e-6; //from MPa to psi
+ OilTemp_degK = Seek(&OilTemp_degK, 353.15, 0.4-N1*0.001, 0.04);
+
+ } else {
+ phase = tpRun;
+ Running = true;
+ Starter = false;
+ Cranking = false;
+ FuelFlow_pph = 0;
+ EngPower_HP=0.0;
+ }
+ } else { // no start if N2 < 15% or Starved
+ phase = tpOff;
+ Starter = false;
+ }
+
+ ConsumeFuel();
+
+ return EngPower_HP;
+}
+
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTurboProp::CalcFuelNeed(void)
+{
+ return FuelFlow_pph /3600 * State->Getdt() * Propulsion->GetRate();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTurboProp::Seek(double *var, double target, double accel, double decel)
+{
+ double v = *var;
+ if (v > target) {
+ v -= dt * decel;
+ if (v < target) v = target;
+ } else if (v < target) {
+ v += dt * accel;
+ if (v > target) v = target;
+ }
+ return v;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTurboProp::ExpSeek(double *var, double target, double accel_tau, double decel_tau)
+{
+// exponential delay instead of the linear delay used in Seek
+ double v = *var;
+ if (v > target) {
+ v = (v - target) * exp ( -dt / decel_tau) + target;
+ } else if (v < target) {
+ v = (target - v) * (1 - exp ( -dt / accel_tau)) + v;
+ }
+ return v;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGTurboProp::SetDefaults(void)
+{
+ Name = "Not defined";
+ N1 = N2 = 0.0;
+ Type = etTurboprop;
+ MilThrust = 10000.0;
+ IdleN1 = 30.0;
+ IdleN2 = 60.0;
+ MaxN1 = 100.0;
+ MaxN2 = 100.0;
+ ThrottleCmd = 0.0;
+ InletPosition = 1.0;
+ NozzlePosition = 1.0;
+ Reversed = false;
+ Cutoff = true;
+ phase = tpOff;
+ Stalled = false;
+ Seized = false;
+ Overtemp = false;
+ Fire = false;
+ Eng_ITT_degC = 0.0;
+
+ GeneratorPower=true;
+ Condition = 0;
+ Ielu_intervent=false;
+
+ Idle_Max_Delay = 1.0;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+string FGTurboProp::GetEngineLabels(string delimeter)
+{
+ std::ostringstream buf;
+
+ buf << Name << "_N1[" << EngineNumber << "]" << delimeter
+ << Name << "_N2[" << EngineNumber << "]" << delimeter
+ << Name << "__PwrAvailJVK[" << EngineNumber << "]" << delimeter
+ << Thruster->GetThrusterLabels(EngineNumber, delimeter);
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGTurboProp::GetEngineValues(string delimeter)
+{
+ std::ostringstream buf;
+
+ buf << N1 << delimeter
+ << N2 << delimeter
+ << Thruster->GetThrusterValues(EngineNumber,delimeter);
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGTurboProp::bindmodel()
+{
+ char property_name[80];
+
+// ToDo: Do a proper Tie here, this should be read only.
+
+ snprintf(property_name, 80, "propulsion/engine[%u]/n1", EngineNumber);
+ PropertyManager->Tie( property_name, &N1);
+ snprintf(property_name, 80, "propulsion/engine[%u]/n2", EngineNumber);
+ PropertyManager->Tie( property_name, &N2);
+ snprintf(property_name, 80, "propulsion/engine[%u]/reverser", EngineNumber);
+ PropertyManager->Tie( property_name, &Reversed);
+
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGTurboProp::unbind()
+{
+ char property_name[80];
+
+ snprintf(property_name, 80, "propulsion/engine[%u]/n1", EngineNumber);
+ PropertyManager->Untie(property_name);
+ snprintf(property_name, 80, "propulsion/engine[%u]/n2", EngineNumber);
+ PropertyManager->Untie(property_name);
+ snprintf(property_name, 80, "propulsion/engine[%u]/reverser", EngineNumber);
+ PropertyManager->Untie(property_name);
+}
+
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The bitmasked value choices are as follows:
+// unset: In this case (the default) JSBSim would only print
+// out the normally expected messages, essentially echoing
+// the config files as they are read. If the environment
+// variable is not set, debug_lvl is set to 1 internally
+// 0: This requests JSBSim not to output any messages
+// whatsoever.
+// 1: This value explicity requests the normal JSBSim
+// startup messages
+// 2: This value asks for a message to be printed out when
+// a class is instantiated
+// 4: When this value is set, a message is displayed when a
+// FGModel object executes its Run() method
+// 8: When this value is set, various runtime state variables
+// are printed out periodically
+// 16: When set various parameters are sanity checked and
+// a message is printed out when they go out of bounds
+
+void FGTurboProp::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ }
+ if (from == 2) { // called from Load()
+ cout << "\n ****MUJ MOTOR TURBOPROP****\n";
+ cout << "\n Engine Name: " << Name << endl;
+ cout << " MilThrust: " << MilThrust << endl;
+ cout << " IdleN1: " << IdleN1 << endl;
+ cout << " MaxN1: " << MaxN1 << endl;
+
+ cout << endl;
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGTurboProp" << endl;
+ if (from == 1) cout << "Destroyed: FGTurboProp" << endl;
+ }
+ if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
+ }
+ if (debug_lvl & 8 ) { // Runtime state variables
+ }
+ if (debug_lvl & 16) { // Sanity checking
+ }
+ if (debug_lvl & 64) {
+ if (from == 0) { // Constructor
+ cout << IdSrc << endl;
+ cout << IdHdr << endl;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGTurboProp.h
+ Author: Jiri "Javky" Javurek
+ based on SimTurbine and Turbine engine from David Culp
+ Date started: 05/14/2004
+
+ ------------- Copyright (C) 2004 (javky@email.cz)----------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA 02111-1307, USA.
+
+ Further information about the GNU General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+05/14/2004 Created
+
+//JVK (mark)
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGTURBOPROP_H
+#define FGTURBOPROP_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include <vector>
+#include "FGEngine.h"
+#include <input_output/FGXMLElement.h>
+#include <math/FGTable.h>
+
+#define ID_TURBOPROP "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Turboprop engine model.
+
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGTurboProp : public FGEngine
+{
+public:
+ /** Constructor
+ @param Executive pointer to executive structure
+ @param el pointer to the XML element representing the turbine engine
+ @param engine_number engine number*/
+ FGTurboProp(FGFDMExec* Executive, Element *el, int engine_number);
+ /// Destructor
+ ~FGTurboProp();
+
+ enum phaseType { tpOff, tpRun, tpSpinUp, tpStart, tpStall, tpSeize, tpTrim };
+
+ double Calculate(void);
+ double CalcFuelNeed(void);
+
+ inline double GetPowerAvailable(void) const {return (Eng_HP * hptoftlbssec);}
+ inline double GetPowerAvailable_HP(void) const {return (Eng_HP);}
+ inline double GetPropRPM(void) const {return (Prop_RPM);}
+ inline double GetThrottleCmd(void) const {return (ThrottleCmd);}
+ inline bool GetIeluIntervent(void) const { return Ielu_intervent; }
+
+ double Seek(double* var, double target, double accel, double decel);
+ double ExpSeek(double* var, double target, double accel, double decel);
+
+ phaseType GetPhase(void) const { return phase; }
+
+ bool GetOvertemp(void) const {return Overtemp; }
+ bool GetFire(void) const { return Fire; }
+ bool GetReversed(void) const { return Reversed; }
+ bool GetCutoff(void) const { return Cutoff; }
+ int GetIgnition(void) const {return Ignition;}
+
+ double GetInlet(void) const { return InletPosition; }
+ double GetNozzle(void) const { return NozzlePosition; }
+ double GetN1(void) const {return N1;}
+ double GetN2(void) const {return N2;}
+ double GetEPR(void) const {return EPR;}
+ double GetITT(void) const {return Eng_ITT_degC;}
+ double GetEngStarting(void) const { return EngStarting; }
+
+ double getOilPressure_psi () const {return OilPressure_psi;}
+ double getOilTemp_degF (void) {return KelvinToFahrenheit(OilTemp_degK);}
+
+ inline bool GetGeneratorPower(void) const { return GeneratorPower; }
+ inline int GetCondition(void) const { return Condition; }
+
+ void SetIgnition(int ignition) {Ignition = ignition;}
+ void SetPhase( phaseType p ) { phase = p; }
+ void SetEPR(double epr) {EPR = epr;}
+ void SetReverse(bool reversed) { Reversed = reversed; }
+ void SetCutoff(bool cutoff) { Cutoff = cutoff; }
+
+ inline void SetGeneratorPower(bool gp) { GeneratorPower=gp; }
+ inline void SetCondition(bool c) { Condition=c; }
+
+ string GetEngineLabels(string delimeter); // added from Turbine 0.9.6
+ string GetEngineValues(string delimeter); // added from Turbine 0.9.6
+
+private:
+
+ phaseType phase; ///< Operating mode, or "phase"
+ double MilThrust; ///< Maximum Unaugmented Thrust, static @ S.L. (lbf)
+ double IdleN1; ///< Idle N1
+ double IdleN2; ///< Idle N2
+ double N1; ///< N1
+ double N2; ///< N2
+ double MaxN1; ///< N1 at 100% throttle
+ double MaxN2; ///< N2 at 100% throttle
+ double IdleFF; ///< Idle Fuel Flow (lbm/hr)
+ double delay; ///< Inverse spool-up time from idle to 100% (seconds)
+ double dt; ///< Simulator time slice
+ double N1_factor; ///< factor to tie N1 and throttle
+ double N2_factor; ///< factor to tie N2 and throttle
+ double ThrottleCmd; ///< FCS-supplied throttle position
+ double TAT; ///< total air temperature (deg C)
+ bool Stalled; ///< true if engine is compressor-stalled
+ bool Seized; ///< true if inner spool is seized
+ bool Overtemp; ///< true if EGT exceeds limits
+ bool Fire; ///< true if engine fire detected
+ bool Reversed;
+ bool Cutoff;
+ int Ignition;
+
+ double EPR;
+ double OilPressure_psi;
+ double OilTemp_degK;
+ double InletPosition;
+ double NozzlePosition;
+
+ double Ielu_max_torque; // max propeller torque (before ielu intervent)
+ bool Ielu_intervent;
+ double OldThrottle;
+
+ double BetaRangeThrottleEnd; // coef (0-1) where is end of beta-range
+ double ReverseMaxPower; // coef (0-1) multiplies max throttle on reverse
+
+ double Idle_Max_Delay; // time delay for exponencial
+ double MaxPower; // max engine power [HP]
+ double StarterN1; // rotates of generator maked by starter [%]
+ double MaxStartingTime; // maximal time for start [s] (-1 means not used)
+ double Prop_RPM; // propeller RPM
+ double Velocity;
+ double rho;
+ double PSFC; // Power specific fuel comsumption [lb/(HP*hr)] at best efficiency
+
+ double Eng_HP; // current engine power
+
+ double StartTime; // engine strating time [s] (0 when start button pushed)
+
+ double ITT_Delay; // time delay for exponencial grow of ITT
+ double Eng_ITT_degC;
+ double Eng_Temperature; // temperature inside engine
+
+ bool EngStarting; // logicaly output - TRUE if engine is starting
+ bool GeneratorPower;
+ int Condition;
+
+ double Off(void);
+ double Run(void);
+ double SpinUp(void);
+ double Start(void);
+
+ void SetDefaults(void);
+ bool Load(FGFDMExec *exec, Element *el);
+ void bindmodel(void);
+ void unbind(void);
+ void Debug(int from);
+
+ FGTable* ITT_N1; // ITT temperature depending on throttle command
+ FGTable* EnginePowerRPM_N1;
+ FGTable* EnginePowerVC;
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
--- /dev/null
+noinst_LIBRARIES = libPropulsion.a
+
+libPropulsion_a_SOURCES = FGElectric.cpp FGEngine.cpp FGForce.cpp FGNozzle.cpp \
+ FGPiston.cpp FGPropeller.cpp FGRocket.cpp FGRotor.cpp \
+ FGTank.cpp FGThruster.cpp FGTurbine.cpp FGTurboProp.cpp
+
+noinst_HEADERS = FGElectric.h FGEngine.h FGForce.h FGNozzle.h FGPiston.h \
+ FGPropeller.h FGRocket.h FGRotor.h FGTank.h FGThruster.h \
+ FGTurbine.h FGTurboProp.h
+
+INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim
GFX_CODE = fg_os.cxx fg_os.hxx
endif
+JSBSIM_LIBS = \
+ $(top_builddir)/src/FDM/JSBSim/libJSBSim.a \
+ $(top_builddir)/src/FDM/JSBSim/initialization/libInit.a \
+ $(top_builddir)/src/FDM/JSBSim/models/libModels.a \
+ $(top_builddir)/src/FDM/JSBSim/models/flight_control/libFlightControl.a\
+ $(top_builddir)/src/FDM/JSBSim/models/atmosphere/libAtmosphere.a \
+ $(top_builddir)/src/FDM/JSBSim/models/propulsion/libPropulsion.a \
+ $(top_builddir)/src/FDM/JSBSim/input_output/libInputOutput.a \
+ $(top_builddir)/src/FDM/JSBSim/math/libMath.a
+
AM_CXXFLAGS = -DPKGLIBDIR=\"$(pkgdatadir)\"
bin_PROGRAMS = fgfs metar
$(top_builddir)/src/FDM/Balloon/libBalloon.a \
$(top_builddir)/src/FDM/ExternalNet/libExternalNet.a \
$(top_builddir)/src/FDM/ExternalPipe/libExternalPipe.a \
- $(top_builddir)/src/FDM/JSBSim/libJSBSim.a \
+ $(JSBSIM_LIBS) \
$(top_builddir)/src/FDM/YASim/libYASim.a \
$(top_builddir)/src/FDM/JSBSim/filtersjb/libfiltersjb.a \
$(top_builddir)/src/FDM/LaRCsim/libLaRCsim.a \
-lplibnet -lplibul $(network_LIBS) \
-lz $(base_LIBS)
-INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
+INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src -I$(top_srcdir)/src/FDM/JSBSim