for (int i=0; i<N; i++) {
if (node->getChild(i)->nChildren() ) {
-// cout << "Untieing " << node->getChild(i)->getName() << " property branch." << endl;
checkTied( (FGPropertyManager*)node->getChild(i) );
} else if ( node->getChild(i)->isTied() ) {
name = ((FGPropertyManager*)node->getChild(i))->GetFullyQualifiedName();
Script = 0;
modelLoaded = false;
- IsSlave = false;
+ IsChild = false;
holding = false;
Terminate = 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++;
+ IdFDM = FDMctr; // The main (parent) JSBSim instance is always the "zeroth"
+ FDMctr++; // instance. "child" instances are loaded last.
try {
char* num = getenv("JSBSIM_DEBUG");
cout << "Caught error: " << msg << endl;
}
- for (unsigned int i=1; i<SlaveFDMList.size(); i++) delete SlaveFDMList[i]->exec;
- SlaveFDMList.clear();
+ for (unsigned int i=1; i<ChildFDMList.size(); i++) delete ChildFDMList[i]->exec;
+ ChildFDMList.clear();
- //ToDo remove property catalog.
+ PropertyCatalog.clear();
Debug(1);
}
Debug(2);
- for (unsigned int i=1; i<SlaveFDMList.size(); i++) {
-// SlaveFDMList[i]->exec->State->Initialize(); // Transfer state to the slave FDM
-// SlaveFDMList[i]->exec->Run();
+ for (unsigned int i=1; i<ChildFDMList.size(); i++) {
+ ChildFDMList[i]->AssignState(Propagate); // Transfer state to the child FDM
+ ChildFDMList[i]->Run();
}
// returns true if success
FDMList.push_back(Aircraft->GetAircraftName());
- for (unsigned int i=1; i<SlaveFDMList.size(); i++) {
- FDMList.push_back(SlaveFDMList[i]->exec->GetAircraft()->GetAircraftName());
+ for (unsigned int i=1; i<ChildFDMList.size(); i++) {
+ FDMList.push_back(ChildFDMList[i]->exec->GetAircraft()->GetAircraftName());
}
return FDMList;
Allocate();
}
+ int saved_debug_lvl = debug_lvl;
+
document = LoadXMLDocument(aircraftCfgFileName); // "document" is a class member
if (document) {
+ if (IsChild) debug_lvl = 0;
+
ReadPrologue(document);
+ if (IsChild) debug_lvl = saved_debug_lvl;
+
// Process the fileheader element in the aircraft config file. This element is OPTIONAL.
element = document->FindElement("fileheader");
if (element) {
}
}
+ if (IsChild) debug_lvl = 0;
+
// Process the metrics element. This element is REQUIRED.
element = document->FindElement("metrics");
if (element) {
element = document->FindNextElement("output");
}
- // Lastly, process the slave element. This element is OPTIONAL - and NOT YET SUPPORTED.
- element = document->FindElement("slave");
+ // Lastly, process the child element. This element is OPTIONAL - and NOT YET SUPPORTED.
+ element = document->FindElement("child");
if (element) {
- result = ReadSlave(element);
+ result = ReadChild(element);
if (!result) {
- cerr << endl << "Aircraft slave element has problems in file " << aircraftCfgFileName << endl;
+ cerr << endl << "Aircraft child element has problems in file " << aircraftCfgFileName << endl;
return result;
}
}
modelLoaded = true;
+ if (debug_lvl > 0) {
+ cout << endl << fgblue << highint
+ << "End of vehicle configuration loading." << endl
+ << "-------------------------------------------------------------------------------"
+ << reset << endl;
+ }
+
+ if (IsChild) debug_lvl = saved_debug_lvl;
+
} else {
cerr << fgred
<< " JSBSim failed to open the configuration file: " << aircraftCfgFileName
{
bool result = true; // true for success
- if (debug_lvl & ~1) return result;
+ if (debug_lvl == 0) return result;
+
+ if (IsChild) {
+ cout << endl <<highint << fgblue << "Reading child model: " << IdFDM << reset << endl << endl;
+ }
+ if (el->FindElement("description"))
+ cout << " Description: " << el->FindElement("description")->GetDataLine() << endl;
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::ReadSlave(Element* el)
+bool FGFDMExec::ReadChild(Element* el)
{
- // Add a new slaveData object to the slave FDM list
- // Populate that slaveData element with a new FDMExec object
- // Set the IsSlave flag for that FDMExec object
+ // Add a new childData object to the child FDM list
+ // Populate that childData element with a new FDMExec object
+ // Set the IsChild flag for that FDMExec object
// Get the aircraft name
- // set debug level to print out no additional data for slave objects
+ // set debug level to print out no additional data for child objects
// Load the model given the aircraft name
// reset debug level to prior setting
- int saved_debug_lvl = debug_lvl;
string token;
- SlaveFDMList.push_back(new slaveData);
- SlaveFDMList.back()->exec = new FGFDMExec();
- SlaveFDMList.back()->exec->SetSlave(true);
-/*
- string AircraftName = AC_cfg->GetValue("file");
-
- debug_lvl = 0; // turn off debug output for slave vehicle
-
- SlaveFDMList.back()->exec->SetAircraftPath( AircraftPath );
- SlaveFDMList.back()->exec->SetEnginePath( EnginePath );
- SlaveFDMList.back()->exec->SetSystemsPath( SystemsPath );
- SlaveFDMList.back()->exec->LoadModel(AircraftName);
- debug_lvl = saved_debug_lvl; // turn debug output back on for master 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; }
- else cerr << "Unknown identifier: " << token << " in slave vehicle definition" << endl;
+ struct childData* child = new childData;
+
+ child->exec = new FGFDMExec();
+ child->exec->SetChild(true);
+
+ string childAircraft = el->GetAttributeValue("name");
+ string sMated = el->GetAttributeValue("mated");
+ if (sMated == "false") child->mated = false; // child objects are mated by default.
+ string sInternal = el->GetAttributeValue("internal");
+ if (sInternal == "true") child->internal = true; // child objects are external by default.
+
+ child->exec->SetAircraftPath( AircraftPath );
+ child->exec->SetEnginePath( EnginePath );
+ child->exec->SetSystemsPath( SystemsPath );
+ child->exec->LoadModel(childAircraft);
+
+ Element* location = el->FindElement("location");
+ if (location) {
+ child->Loc = location->FindElementTripletConvertTo("IN");
+ } else {
+ cerr << endl << highint << fgred << " No location was found for this child object!" << reset << endl;
+ exit(-1);
}
-*/
- if (debug_lvl > 0) {
- cout << " X = " << SlaveFDMList.back()->x << endl;
- cout << " Y = " << SlaveFDMList.back()->y << endl;
- cout << " Z = " << SlaveFDMList.back()->z << endl;
- cout << " Pitch = " << SlaveFDMList.back()->pitch << endl;
- cout << " Yaw = " << SlaveFDMList.back()->yaw << endl;
- cout << " Roll = " << SlaveFDMList.back()->roll << endl;
+
+ Element* orientation = el->FindElement("orient");
+ if (orientation) {
+ child->Orient = orientation->FindElementTripletConvertTo("RAD");
+ } else if (debug_lvl > 0) {
+ cerr << endl << highint << " No orientation was found for this child object! Assuming 0,0,0." << reset << endl;
}
+ ChildFDMList.push_back(child);
+
return true;
}
#include <input_output/FGGroundCallback.h>
#include <input_output/FGXMLFileRead.h>
#include <models/FGPropagate.h>
+#include <math/FGColumnVector3.h>
#include <vector>
#include <string>
class FGFDMExec : public FGJSBBase, public FGXMLFileRead
{
+ struct childData {
+ FGFDMExec* exec;
+ string info;
+ FGColumnVector3 Loc;
+ FGColumnVector3 Orient;
+ bool mated;
+ bool internal;
+
+ childData(void) {
+ info = "";
+ Loc = FGColumnVector3(0,0,0);
+ Orient = FGColumnVector3(0,0,0);
+ mated = true;
+ internal = false;
+ }
+
+ void Run(void) {exec->Run();}
+ void AssignState(FGPropagate* source_prop) {
+ exec->GetPropagate()->SetVState(source_prop->GetVState());
+ }
+
+ ~childData(void) {
+ delete exec;
+ }
+ };
+
public:
/// Default constructor
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(bool s) {IsSlave = s;}
+ /// Gets the number of child FDMs.
+ int GetFDMCount(void) {return ChildFDMList.size();}
+ /// Gets a particular child FDM.
+ childData* GetChildFDM(int i) {return ChildFDMList[i];}
+ /// Marks this instance of the Exec object as a "child" object.
+ void SetChild(bool ch) {IsChild = ch;}
/** Sets the output (logging) mechanism for this run.
Calling this function passes the name of an output directives file to
bool holding;
bool Constructing;
bool modelLoaded;
- bool IsSlave;
+ bool IsChild;
string modelName;
string AircraftPath;
string FullAircraftPath;
bool trim_status;
int ta_mode;
-
- struct slaveData {
- FGFDMExec* exec;
- string info;
- double x, y, z;
- double roll, pitch, yaw;
- bool mated;
-
- slaveData(void) {
- info = "";
- x = y = z = 0.0;
- roll = pitch = yaw = 0.0;
- mated = true;
- }
-
- ~slaveData(void) {
- delete exec;
- }
- };
-
static FGPropertyManager *master;
FGModel* FirstModel;
vector <string> PropertyCatalog;
vector <FGOutput*> Outputs;
- vector <slaveData*> SlaveFDMList;
+ vector <childData*> ChildFDMList;
bool ReadFileHeader(Element*);
- bool ReadSlave(Element*);
+ bool ReadChild(Element*);
bool ReadPrologue(Element*);
void ResetToInitialConditions(int mode);
bool Allocate(void);
/** Places a Message structure on the Message queue.
@param msg pointer to a Message structure
@return pointer to a Message structure */
-void PutMessage(const Message& msg);
+ void PutMessage(const Message& msg);
/** Creates a message with the given text and places it on the queue.
@param text message text
@return pointer to a Message structure */
@param text message text
@param bVal boolean value associated with the message
@return pointer to a Message structure */
-void PutMessage(const string& text, bool bVal);
+ void PutMessage(const string& text, bool bVal);
/** Creates a message with the given text and integer value and places it on the queue.
@param text message text
@param iVal integer value associated with the message
@return pointer to a Message structure */
-void PutMessage(const string& text, int iVal);
+ void PutMessage(const string& text, int iVal);
/** Creates a message with the given text and double value and places it on the queue.
@param text message text
@param dVal double value associated with the message
@return pointer to a Message structure */
-void PutMessage(const string& text, double dVal);
+ void PutMessage(const string& text, double dVal);
/** Reads the message on the queue (but does not delete it).
@return 1 if some messages */
int SomeMessages(void);
static double Constrain(double min, double value, double max) {
return value<min?(min):(value>max?(max):(value));
}
+
+ static double sign(double num) {return num>=0.0?1.0:-1.0;}
protected:
static Message localMsg;
static int phase = 0;
double X;
+ V1 = V2 = S = X = 0.0;
+
if (phase == 0) {
do {
double U1 = (double)rand() / RAND_MAX;
S = V1 * V1 + V2 * V2;
} while(S >= 1 || S == 0);
- X = V1 * sqrt(-2 * log(S) / S);
+ X = V1 * sqrt(-2 * log(S) / S);
} else
X = V2 * sqrt(-2 * log(S) / S);
FGFSGroundCallback(FGJSBsim* ifc) : mInterface(ifc) {}
virtual ~FGFSGroundCallback() {}
- /** Get the altitude above sea level depenent on the location. */
+ /** Get the altitude above sea level dependent on the location. */
virtual double GetAltitude(const FGLocation& l) const {
double pt[3] = { SG_FEET_TO_METER*l(eX),
SG_FEET_TO_METER*l(eY),
fdmex = new FGFDMExec( (FGPropertyManager*)globals->get_props() );
- // begin ugly hack
- // Untie the write-state-file property to avoid creating an initfile.xml
- // file on each FlightGear reset.
- fgGetNode("/fdm/jsbsim/simulation/write-state-file")->untie();
- fgGetNode("/fdm/jsbsim/simulation")->removeChild("write-state-file", false);
- // end ugly hack
-
// Register ground callback.
fdmex->SetGroundCallback( new FGFSGroundCallback(this) );
SG_LOG( SG_FLIGHT, SG_INFO, " Longitude: "
<< Propagate->GetLocation().GetLongitudeDeg() << " deg" );
SG_LOG( SG_FLIGHT, SG_INFO, " Altitude: "
- << Propagate->Geth() << " feet" );
+ << Propagate->GetAltitudeASL() << " feet" );
SG_LOG( SG_FLIGHT, SG_INFO, " loaded initial conditions" );
SG_LOG( SG_FLIGHT, SG_INFO, " set dt" );
double alt, slr, lat, lon;
FGColumnVector3 cart = Auxiliary->GetLocationVRP();
if ( needTrim && startup_trim->getBoolValue() ) {
- alt = fgic->GetAltitudeFtIC();
+ alt = fgic->GetAltitudeASLFtIC();
slr = fgic->GetSeaLevelRadiusFtIC();
lat = fgic->GetLatitudeDegIC() * SGD_DEGREES_TO_RADIANS;
lon = fgic->GetLongitudeDegIC() * SGD_DEGREES_TO_RADIANS;
SG_LOG(SG_FLIGHT, SG_WARN,
"FGInterface is being called without scenery below the aircraft!");
- alt = fgic->GetAltitudeFtIC();
+ alt = fgic->GetAltitudeASLFtIC();
SG_LOG(SG_FLIGHT, SG_WARN, "altitude = " << alt);
slr = fgic->GetSeaLevelRadiusFtIC();
+ contact[2]*contact[2]) - fgic->GetSeaLevelRadiusFtIC();
SG_LOG(SG_FLIGHT, SG_INFO,
- "Ready to trim, terrain altitude is: "
+ "Ready to trim, terrain elevation is: "
<< terrain_alt * SG_METER_TO_FEET );
- fgic->SetTerrainAltitudeFtIC( terrain_alt );
+ fgic->SetTerrainElevationFtIC( terrain_alt );
do_trim();
} else {
fdmex->RunIC(); //apply any changes made through the set_ functions
}
Propulsion->SetFuelFreeze((fgGetNode("/sim/freeze/fuel",true))->getBoolValue());
- fdmex->SetSlave(slaved->getBoolValue());
+ fdmex->SetChild(slaved->getBoolValue());
return true;
}
needTrim=true;
}
+// Sets the altitude above sea level.
void FGJSBsim::set_Altitude(double alt)
{
static SGConstPropertyNode_ptr latitude = fgGetNode("/position/latitude-deg");
_set_Sea_level_radius( sea_level_radius_meters * SG_METER_TO_FEET );
fgic->SetSeaLevelRadiusFtIC( sea_level_radius_meters * SG_METER_TO_FEET );
SG_LOG(SG_FLIGHT, SG_INFO,
- "Terrain altitude: " << cur_fdm_state->get_Runway_altitude() * SG_METER_TO_FEET );
+ "Terrain elevation: " << cur_fdm_state->get_Runway_altitude() * SG_METER_TO_FEET );
fgic->SetLatitudeRadIC( lat_geoc );
- fgic->SetAltitudeFtIC(alt);
+ fgic->SetAltitudeASLFtIC(alt);
needTrim=true;
}
if ( !needTrim ) {
fgic->SetLatitudeRadIC(get_Lat_geocentric() );
fgic->SetLongitudeRadIC( get_Longitude() );
- fgic->SetAltitudeFtIC( get_Altitude() );
+ fgic->SetAltitudeASLFtIC( get_Altitude() );
fgic->SetVcalibratedKtsIC( get_V_calibrated_kts() );
fgic->SetThetaRadIC( get_Theta() );
fgic->SetPhiRadIC( get_Phi() );
InitializeIC();
if(FDMExec != NULL ) {
- fdmex->GetPropagate()->Seth(altitude);
+ fdmex->GetPropagate()->SetAltitudeASL(altitudeASL);
fdmex->GetAtmosphere()->Run();
PropertyManager=fdmex->GetPropertyManager();
Constructing = true;
FGColumnVector3 _vUVW_BODY(u,v,w);
FGColumnVector3 _vUVW_NED = _Tb2l * _vUVW_BODY;
FGColumnVector3 _vWIND_NED(wnorth,weast,wdown);
- FGColumnVector3 _vUVWAero = _Tl2b * ( _vUVW_NED + _vWIND_NED );
+// FGColumnVector3 _vUVWAero = _Tl2b * ( _vUVW_NED + _vWIND_NED );
uw=_vWIND_NED(1); vw=_vWIND_NED(2); ww=_vWIND_NED(3);
mach=0;
alpha=beta=gamma=0;
theta=phi=psi=0;
- altitude=hdot=0;
+ altitudeASL=hdot=0;
latitude=longitude=0;
u=v=w=0;
p=q=r=0;
lastSpeedSet=setvt;
lastWindSet=setwned;
radius_to_vehicle = sea_level_radius = fdmex->GetInertial()->GetRefRadius();
- terrain_altitude = 0;
+ terrain_elevation = 0;
targetNlfIC = 1.0;
outfile << " <psi unit=\"DEG\"> " << Propagate->GetEuler(ePsi) << " </psi>" << endl;
outfile << " <longitude unit=\"DEG\"> " << Propagate->GetLongitudeDeg() << " </longitude>" << endl;
outfile << " <latitude unit=\"DEG\"> " << Propagate->GetLatitudeDeg() << " </latitude>" << endl;
- outfile << " <altitude unit=\"FT\"> " << Propagate->Geth() << " </altitude>" << endl;
+ outfile << " <altitude unit=\"FT\"> " << Propagate->GetAltitudeASL() << " </altitude>" << endl;
outfile << "</initialize>" << endl;
outfile.close();
} else {
//******************************************************************************
-void FGInitialCondition::SetAltitudeFtIC(double tt) {
- altitude=tt;
- fdmex->GetPropagate()->Seth(altitude);
+void FGInitialCondition::SetAltitudeASLFtIC(double tt)
+{
+ altitudeASL=tt;
+ fdmex->GetPropagate()->SetAltitudeASL(altitudeASL);
fdmex->GetAtmosphere()->Run();
//lets try to make sure the user gets what they intended
//******************************************************************************
-void FGInitialCondition::SetAltitudeAGLFtIC(double tt) {
- SetAltitudeFtIC(terrain_altitude + tt);
+void FGInitialCondition::SetAltitudeAGLFtIC(double tt)
+{
+ SetAltitudeASLFtIC(terrain_elevation + tt);
}
//******************************************************************************
-void FGInitialCondition::SetSeaLevelRadiusFtIC(double tt) {
+void FGInitialCondition::SetSeaLevelRadiusFtIC(double tt)
+{
sea_level_radius = tt;
}
//******************************************************************************
-void FGInitialCondition::SetTerrainAltitudeFtIC(double tt) {
- terrain_altitude=tt;
+void FGInitialCondition::SetTerrainElevationFtIC(double tt)
+{
+ terrain_elevation=tt;
}
//******************************************************************************
-void FGInitialCondition::calcUVWfromNED(void) {
+void FGInitialCondition::calcUVWfromNED(void)
+{
u=vnorth*ctheta*cpsi +
veast*ctheta*spsi -
vdown*stheta;
SetLatitudeDegIC(document->FindElementValueAsNumberConvertTo("latitude", "DEG"));
if (document->FindElement("longitude"))
SetLongitudeDegIC(document->FindElementValueAsNumberConvertTo("longitude", "DEG"));
- if (document->FindElement("altitude"))
- SetAltitudeFtIC(document->FindElementValueAsNumberConvertTo("altitude", "FT"));
+ if (document->FindElement("elevation"))
+ SetTerrainElevationFtIC(document->FindElementValueAsNumberConvertTo("elevation", "FT"));
+ if (document->FindElement("altitude")) // This is feet above ground level
+ SetAltitudeAGLFtIC(document->FindElementValueAsNumberConvertTo("altitude", "FT"));
if (document->FindElement("ubody"))
SetUBodyFpsIC(document->FindElementValueAsNumberConvertTo("ubody", "FT/SEC"));
if (document->FindElement("vbody"))
&FGInitialCondition::SetLongitudeDegIC,
true);
PropertyManager->Tie("ic/h-sl-ft", this,
- &FGInitialCondition::GetAltitudeFtIC,
- &FGInitialCondition::SetAltitudeFtIC,
+ &FGInitialCondition::GetAltitudeASLFtIC,
+ &FGInitialCondition::SetAltitudeASLFtIC,
true);
PropertyManager->Tie("ic/h-agl-ft", this,
&FGInitialCondition::GetAltitudeAGLFtIC,
&FGInitialCondition::GetSeaLevelRadiusFtIC,
&FGInitialCondition::SetSeaLevelRadiusFtIC,
true);
- PropertyManager->Tie("ic/terrain-altitude-ft", this,
- &FGInitialCondition::GetTerrainAltitudeFtIC,
- &FGInitialCondition::SetTerrainAltitudeFtIC,
+ PropertyManager->Tie("ic/terrain-elevation-ft", this,
+ &FGInitialCondition::GetTerrainElevationFtIC,
+ &FGInitialCondition::SetTerrainElevationFtIC,
true);
PropertyManager->Tie("ic/vg-fps", this,
&FGInitialCondition::GetVgroundFpsIC,
@code
FGInitialCondition fgic=new FGInitialCondition(FDMExec);
fgic->SetVcalibratedKtsIC()
- fgic->SetAltitudeFtIC();
+ fgic->SetAltitudeAGLFtIC();
// directly into Run
FDMExec->GetState()->Initialize(fgic)
- beta (angle, degrees)
- gamma (angle, degrees)
- roc (vertical velocity, ft/sec)
- - altitude (altitude, ft)
+ - altitude (altitude AGL, ft)
- winddir (wind from-angle, degrees)
- vwind (magnitude wind speed, ft/sec)
- hwind (headwind speed, knots)
@property ic/h-sl-ft (read/write) Height above sea level initial condition in feet
@property ic/h-agl-ft (read/write) Height above ground level initial condition in feet
@property ic/sea-level-radius-ft (read/write) Radius of planet at sea level in feet
- @property ic/terrain-altitude-ft (read/write) Terrain elevation above sea level in feet
+ @property ic/terrain-elevation-ft (read/write) Terrain elevation above sea level in feet
@property ic/vg-fps (read/write) Ground speed initial condition in feet/second
@property ic/vt-fps (read/write) True airspeed initial condition in feet/second
@property ic/vw-bx-fps (read/write) Wind velocity initial condition in Body X frame in feet/second
@param gamma Flight path angle in degrees */
inline void SetFlightPathAngleDegIC(double gamma) { SetFlightPathAngleRadIC(gamma*degtorad); }
- /** Sets the altitude initial condition in feet.
- @param alt Altitude in feet */
- void SetAltitudeFtIC(double alt);
+ /** Sets the altitude above sea level initial condition in feet.
+ @param altitudeASL Altitude above sea level in feet */
+ void SetAltitudeASLFtIC(double altitudeASL);
/** Sets the initial Altitude above ground level.
@param agl Altitude above ground level in feet */
/** Sets the initial terrain elevation.
@param elev Initial terrain elevation in feet */
- void SetTerrainAltitudeFtIC(double elev);
+ void SetTerrainElevationFtIC(double elev);
/** Sets the initial latitude.
@param lat Initial latitude in degrees */
@return Initial longitude in degrees */
inline double GetLongitudeDegIC(void) const { return longitude*radtodeg; }
- /** Gets the initial altitude.
+ /** Gets the initial altitude above sea level.
@return Initial altitude in feet. */
- inline double GetAltitudeFtIC(void) const { return altitude; }
+ inline double GetAltitudeASLFtIC(void) const { return altitudeASL; }
/** Gets the initial altitude above ground level.
@return Initial altitude AGL in feet */
- inline double GetAltitudeAGLFtIC(void) const { return altitude - terrain_altitude; }
+ inline double GetAltitudeAGLFtIC(void) const { return altitudeASL - terrain_elevation; }
/** Gets the initial sea level radius.
@return Initial sea level radius */
/** Gets the initial terrain elevation.
@return Initial terrain elevation in feet */
- inline double GetTerrainAltitudeFtIC(void) const { return terrain_altitude; }
+ inline double GetTerrainElevationFtIC(void) const { return terrain_elevation; }
/** Sets the initial ground speed.
@param vg Initial ground speed in feet/second */
private:
double vt,vc,ve,vg;
double mach;
- double altitude,hdot;
+ double altitudeASL,hdot;
double latitude,longitude;
double u,v,w;
double p,q,r;
double wnorth,weast,wdown;
double whead, wcross, wdir, wmag;
double sea_level_radius;
- double terrain_altitude;
+ double terrain_elevation;
double radius_to_vehicle;
double targetNlfIC;
while (property_element) {
double value=0.0;
+ string title="";
+
+ title = property_element->GetDataLine();
if ( ! property_element->GetAttributeValue("value").empty())
value = property_element->GetAttributeValueAsNumber("value");
LocalProps *localProp = new LocalProps(value);
- localProp->title = property_element->GetDataLine();
+ localProp->title = title;
local_properties.push_back(localProp);
-
- PropertyManager->Tie(localProp->title, (local_properties.back())->value);
+ if (PropertyManager->HasNode(title)) {
+ PropertyManager->GetNode(title)->setDoubleValue(value);
+ } else {
+ PropertyManager->Tie(localProp->title, localProp->value);
+ }
property_element = run_element->FindNextElement("property");
}
<< " seconds with dt = " << State->Getdt() << endl;
cout << endl;
+ for (unsigned int i=0; i<local_properties.size(); i++) {
+ cout << "Local property: " << local_properties[i]->title
+ << " = " << PropertyManager->GetNode(local_properties[i]->title)->getDoubleValue()
+ << endl;
+ }
+
+ if (local_properties.size() > 0) cout << endl;
+
for (unsigned i=0; i<Events.size(); i++) {
cout << "Event " << i;
if (!Events[i].Name.empty()) cout << " (" << Events[i].Name << ")";
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+#include <FGFDMExec.h>
#include "FGAerodynamics.h"
#include "FGPropagate.h"
#include "FGAircraft.h"
if (FDMExec->Holding()) return false;
T_dev = 0.0;
- h = Propagate->Geth();
+ h = Propagate->GetAltitudeASL();
if (!useExternal) {
Calculate(h);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGModel.h"
+#include <FGFDMExec.h>
#include <math/FGColumnVector3.h>
#include <math/FGLocation.h>
#include "FGPropagate.h"
double GetqbarUW (void) const { return qbarUW; }
double GetqbarUV (void) const { return qbarUV; }
double GetReynoldsNumber(void) const { return Re; }
+
+ /** Gets the magnitude of total vehicle velocity including wind effects in feet per second. */
double GetVt (void) const { return Vt; }
+
+ /** Gets the ground speed in feet per second.
+ The magnitude is the square root of the sum of the squares (RSS) of the
+ vehicle north and east velocity components.
+ @return The magnitude of the vehicle velocity in the horizontal plane. */
double GetVground (void) const { return Vground; }
+
+ /** Gets the Mach number. */
double GetMach (void) const { return Mach; }
+
+ /** The mach number calculated using the vehicle X axis velocity. */
double GetMachU (void) const { return MachU; }
+
+ /** The vertical acceleration in g's of the aircraft center of gravity. */
double GetNz (void) const { return Nz; }
double GetHOverBCG(void) const { return hoverbcg; }
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGInertial.h"
+#include <FGFDMExec.h>
#include "FGPropagate.h"
#include "FGState.h"
#include "FGMassBalance.h"
switch(repType) {
case erLand:
- cout << endl << "Touchdown report for " << name << endl;
+ cout << endl << "Touchdown report for " << name << " (WOW at time: "
+ << Exec->GetState()->Getsim_time() << " seconds)" << endl;
cout << " Sink rate at contact: " << SinkRate << " fps, "
<< SinkRate*0.3048 << " mps" << endl;
cout << " Contact ground speed: " << GroundSpeed*.5925 << " knots, "
LandingReported = true;
break;
case erTakeoff:
- cout << endl << "Takeoff report for " << name << endl;
+ cout << endl << "Takeoff report for " << name << " (Liftoff at time: "
+ << Exec->GetState()->Getsim_time() << " seconds)" << endl;
cout << " Distance traveled: " << TakeoffDistanceTraveled
<< " ft, " << TakeoffDistanceTraveled*0.3048 << " meters" << endl;
cout << " Distance traveled (over 50'): " << TakeoffDistanceTraveled50ft
<< " ft, " << TakeoffDistanceTraveled50ft*0.3048 << " meters" << endl;
+ cout << " [Altitude (ASL): " << Exec->GetPropagate()->GetAltitudeASL() << " ft. / "
+ << Exec->GetPropagate()->GetAltitudeASLmeters() << " m | Temperature: "
+ << Exec->GetAtmosphere()->GetTemperature() - 459.67 << " F / "
+ << RankineToCelsius(Exec->GetAtmosphere()->GetTemperature()) << " C]" << endl;
+ cout << " [Velocity (KCAS): " << Exec->GetAuxiliary()->GetVcalibratedKTS() << "]" << endl;
TakeoffReported = true;
break;
}
element = el->FindNextElement("pointmass");
}
+ double ChildFDMWeight = 0.0;
+ for (int fdm=0; fdm<FDMExec->GetFDMCount(); fdm++) {
+ if (FDMExec->GetChildFDM(fdm)->mated) ChildFDMWeight += FDMExec->GetChildFDM(fdm)->exec->GetMassBalance()->GetWeight();
+ }
+
Weight = EmptyWeight + Propulsion->GetTanksWeight() + GetTotalPointMassWeight()
- + BuoyantForces->GetGasMass()*slugtolb;
+ + BuoyantForces->GetGasMass()*slugtolb + ChildFDMWeight;
Mass = lbtoslug*Weight;
if (FGModel::Run()) return true;
if (FDMExec->Holding()) return false;
+ double ChildFDMWeight = 0.0;
+ for (int fdm=0; fdm<FDMExec->GetFDMCount(); fdm++) {
+ if (FDMExec->GetChildFDM(fdm)->mated) ChildFDMWeight += FDMExec->GetChildFDM(fdm)->exec->GetMassBalance()->GetWeight();
+ }
+
Weight = EmptyWeight + Propulsion->GetTanksWeight() + GetTotalPointMassWeight()
- + BuoyantForces->GetGasMass()*slugtolb;
+ + BuoyantForces->GetGasMass()*slugtolb + ChildFDMWeight;
Mass = lbtoslug*Weight;
}
if (SubSystems & ssPropagate) {
outstream << delimeter;
- outstream << "Altitude (ft)" + delimeter;
+ outstream << "Altitude ASL (ft)" + delimeter;
+ outstream << "Altitude AGL (ft)" + delimeter;
outstream << "Phi (deg)" + delimeter + "Theta (deg)" + delimeter + "Psi (deg)" + delimeter;
outstream << "Alpha (deg)" + delimeter;
outstream << "Beta (deg)" + delimeter;
outstream << "ECEF X (ft)" + delimeter + "ECEF Y (ft)" + delimeter + "ECEF Z (ft)" + delimeter;
outstream << "EPA (deg)" + delimeter;
outstream << "Distance AGL (ft)" + delimeter;
- outstream << "Runway Radius (ft)";
+ outstream << "Terrain Radius (ft)";
}
if (SubSystems & ssCoefficients) {
scratch = Aerodynamics->GetCoefficientStrings(delimeter);
if (SubSystems & ssPropagate) {
outstream.precision(14);
outstream << delimeter;
- outstream << Propagate->Geth() << delimeter;
+ outstream << Propagate->GetAltitudeASL() << delimeter;
+ outstream << Propagate->GetDistanceAGL() << delimeter;
outstream << (radtodeg*Propagate->GetEuler()).Dump(delimeter) << delimeter;
outstream << Auxiliary->Getalpha(inDegrees) << delimeter;
outstream << Auxiliary->Getbeta(inDegrees) << delimeter;
outstream.precision(14);
outstream << Inertial->GetEarthPositionAngleDeg() << delimeter;
outstream << Propagate->GetDistanceAGL() << delimeter;
- outstream << Propagate->GetRunwayRadius();
+ outstream << Propagate->GetLocalTerrainRadius();
outstream.precision(10);
}
if (SubSystems & ssCoefficients) {
// Positions
net->longitude = Propagate->GetLocation().GetLongitude(); // geodetic (radians)
net->latitude = Propagate->GetLocation().GetLatitude(); // geodetic (radians)
- net->altitude = Propagate->Geth()*0.3048; // altitude, above sea level (meters)
+ net->altitude = Propagate->GetAltitudeASL()*0.3048; // altitude, above sea level (meters)
net->agl = (float)(Propagate->GetDistanceAGL()*0.3048); // altitude, above ground level (meters)
net->phi = (float)(Propagate->GetEuler(ePhi)); // roll (radians)
socket->Append(MassBalance->GetXYZcg()(eZ));
}
if (SubSystems & ssPropagate) {
- socket->Append(Propagate->Geth());
+ socket->Append(Propagate->GetAltitudeASL());
socket->Append(radtodeg*Propagate->GetEuler(ePhi));
socket->Append(radtodeg*Propagate->GetEuler(eTht));
socket->Append(radtodeg*Propagate->GetEuler(ePsi));
{
if (!FGModel::InitModel()) return false;
- SeaLevelRadius = Inertial->GetRefRadius(); // For initialization ONLY
- RunwayRadius = SeaLevelRadius;
+ // For initialization ONLY:
+ SeaLevelRadius = LocalTerrainRadius = Inertial->GetRefRadius();
- VState.vLocation.SetRadius( SeaLevelRadius + 4.0 ); // Todo Add terrain elevation?
+ VState.vLocation.SetRadius( LocalTerrainRadius + 4.0 );
VState.vLocation.SetEllipse(Inertial->GetSemimajor(), Inertial->GetSemiminor());
vOmega = FGColumnVector3( 0.0, 0.0, Inertial->omega() ); // Earth rotation vector
void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
{
- SeaLevelRadius = FGIC->GetSeaLevelRadiusFtIC();
- RunwayRadius = SeaLevelRadius;
+ SetSeaLevelRadius(FGIC->GetSeaLevelRadiusFtIC());
+ SetTerrainElevation(FGIC->GetTerrainElevationFtIC());
// Set the position lat/lon/radius
VState.vLocation.SetPosition( FGIC->GetLongitudeRadIC(),
FGIC->GetLatitudeRadIC(),
- FGIC->GetAltitudeFtIC() + FGIC->GetSeaLevelRadiusFtIC() );
+ FGIC->GetAltitudeASLFtIC() + FGIC->GetSeaLevelRadiusFtIC() );
VehicleRadius = GetRadius();
radInv = 1.0/VehicleRadius;
// Finally, make sure that the quaternion stays normalized.
VState.vQtrn.Normalize();
- // Recompute the RunwayRadius level.
- RecomputeRunwayRadius();
+ // Recompute the LocalTerrainRadius.
+ RecomputeLocalTerrainRadius();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if (FGModel::Run()) return true; // Fast return if we have nothing to do ...
if (FDMExec->Holding()) return false;
- RecomputeRunwayRadius();
+ RecomputeLocalTerrainRadius();
// Calculate current aircraft radius from center of planet
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-void FGPropagate::RecomputeRunwayRadius(void)
+void FGPropagate::RecomputeLocalTerrainRadius(void)
{
- // Get the runway radius.
+ double t = State->Getsim_time();
+
+ // Get the LocalTerrain 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();
+ FDMExec->GetGroundCallback()->GetAGLevel(t, VState.vLocation, contactloc, dv, dv);
+ LocalTerrainRadius = contactloc.GetRadius();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-void FGPropagate::SetTerrainElevationASL(double tt)
+void FGPropagate::SetTerrainElevation(double terrainElev)
{
- FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(tt+SeaLevelRadius);
+ LocalTerrainRadius = terrainElev + SeaLevelRadius;
+ FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(LocalTerrainRadius);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-double FGPropagate::GetTerrainElevationASL(void) const
+double FGPropagate::GetTerrainElevation(void) const
{
return FDMExec->GetGroundCallback()->GetTerrainGeoCentRadius()-SeaLevelRadius;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-void FGPropagate::Seth(double tt)
+void FGPropagate::SetAltitudeASL(double altASL)
{
- VState.vLocation.SetRadius( tt + SeaLevelRadius );
+ VState.vLocation.SetRadius( altASL + SeaLevelRadius );
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-double FGPropagate::GetRunwayRadius(void) const
+double FGPropagate::GetLocalTerrainRadius(void) const
{
- return RunwayRadius;
+ return LocalTerrainRadius;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGPropagate::GetDistanceAGL(void) const
{
- return VState.vLocation.GetRadius() - RunwayRadius;
+ return VState.vLocation.GetRadius() - LocalTerrainRadius;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGPropagate::SetDistanceAGL(double tt)
{
- VState.vLocation.SetRadius( tt + RunwayRadius );
+ VState.vLocation.SetRadius( tt + LocalTerrainRadius );
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
PropertyManager->Tie("accelerations/vdot-ft_sec2", this, eV, (PMF)&FGPropagate::GetUVWdot);
PropertyManager->Tie("accelerations/wdot-ft_sec2", this, eW, (PMF)&FGPropagate::GetUVWdot);
- PropertyManager->Tie("position/h-sl-ft", this, &FGPropagate::Geth, &FGPropagate::Seth, true);
- PropertyManager->Tie("position/h-sl-meters", this, &FGPropagate::Gethmeters, &FGPropagate::Sethmeters, true);
+ PropertyManager->Tie("position/h-sl-ft", this, &FGPropagate::GetAltitudeASL, &FGPropagate::SetAltitudeASL, true);
+ PropertyManager->Tie("position/h-sl-meters", this, &FGPropagate::GetAltitudeASLmeters, &FGPropagate::SetAltitudeASLmeters, 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/lat-gc-deg", this, &FGPropagate::GetLatitudeDeg, &FGPropagate::SetLatitudeDeg);
PropertyManager->Tie("position/h-agl-ft", this, &FGPropagate::GetDistanceAGL, &FGPropagate::SetDistanceAGL);
PropertyManager->Tie("position/radius-to-vehicle-ft", this, &FGPropagate::GetRadius);
PropertyManager->Tie("position/terrain-elevation-asl-ft", this,
- &FGPropagate::GetTerrainElevationASL,
- &FGPropagate::SetTerrainElevationASL, false);
+ &FGPropagate::GetTerrainElevation,
+ &FGPropagate::SetTerrainElevation, false);
- PropertyManager->Tie("metrics/runway-radius", this, &FGPropagate::GetRunwayRadius);
+ PropertyManager->Tie("metrics/terrain-radius", this, &FGPropagate::GetLocalTerrainRadius);
PropertyManager->Tie("attitude/phi-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
PropertyManager->Tie("attitude/theta-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
*/
double GetInertialVelocityMagnitude(void) const { return vInertialVelocity.Magnitude(); }
- /** Returns the current altitude.
- Returns the current altitude. Specifically, this function returns the
- difference between the distance to the center of the Earth, and sea level.
+ /** Returns the current altitude above sea level.
+ This function returns the altitude above sea level.
units ft
@return The current altitude above sea level in feet.
*/
- double Geth(void) const { return VState.vLocation.GetRadius() - SeaLevelRadius; }
+ double GetAltitudeASL(void) const { return VState.vLocation.GetRadius() - SeaLevelRadius; }
- /** Returns the current altitude.
- Returns the curren altitude. Specifically, this function returns the
- difference between the distance to the center of the Earth, and sea level.
+ /** Returns the current altitude above sea level.
+ This function returns the altitude above sea level.
units meters
@return The current altitude above sea level in meters.
*/
- double Gethmeters(void) const { return Geth()*fttom;}
+ double GetAltitudeASLmeters(void) const { return GetAltitudeASL()*fttom;}
/** Retrieves a body frame angular velocity component relative to the ECEF frame.
Retrieves a body frame angular velocity component. The angular velocity
*/
double Gethdot(void) const { return -vVel(eDown); }
- /** Returns the "constant" RunwayRadius.
- The RunwayRadius parameter is set by the calling application or set to
- sea level if JSBSim is running in standalone mode.
+ /** Returns the "constant" LocalTerrainRadius.
+ The LocalTerrainRadius parameter is set by the calling application or set to
+ sea level + terrain elevation if JSBSim is running in standalone mode.
units feet
- @return distance of the runway from the center of the earth.
+ @return distance of the local terrain from the center of the earth.
*/
- double GetRunwayRadius(void) const;
+ double GetLocalTerrainRadius(void) const;
double GetSeaLevelRadius(void) const { return SeaLevelRadius; }
- double GetTerrainElevationASL(void) const;
+ double GetTerrainElevation(void) const;
double GetDistanceAGL(void) const;
double GetRadius(void) const {
if (VState.vLocation.GetRadius() == 0) return 1.0;
void SetLatitudeDeg(double lat) {SetLatitude(lat*degtorad);}
void SetRadius(double r) { VState.vLocation.SetRadius(r); }
void SetLocation(const FGLocation& l) { VState.vLocation = l; }
- void Seth(double tt);
- void Sethmeters(double tt) {Seth(tt/fttom);}
+ void SetAltitudeASL(double altASL);
+ void SetAltitudeASLmeters(double altASL) {SetAltitudeASL(altASL/fttom);}
void SetSeaLevelRadius(double tt) { SeaLevelRadius = tt; }
- void SetTerrainElevationASL(double tt);
+ void SetTerrainElevation(double tt);
void SetDistanceAGL(double tt);
void SetInitialState(const FGInitialCondition *);
- void RecomputeRunwayRadius(void);
+ void RecomputeLocalTerrainRadius(void);
void CalculatePQRdot(void);
void CalculateQuatdot(void);
FGMatrix33 Ti2b; // ECI to body frame rotation matrix
FGMatrix33 Tb2i; // body to ECI frame rotation matrix
- double RunwayRadius, SeaLevelRadius, VehicleRadius;
+ double LocalTerrainRadius, SeaLevelRadius, VehicleRadius;
double radInv;
int integrator_rotational_rate;
int integrator_translational_rate;
// get at-altitude values
Calculate(Auxiliary->GetDayOfYear(),
Auxiliary->GetSecondsInDay(),
- Propagate->Geth(),
+ Propagate->GetAltitudeASL(),
Propagate->GetLocation().GetLatitudeDeg(),
Propagate->GetLocation().GetLongitudeDeg());
intTemperature = output.t[1] * 1.8;
Input = InputNodes[0]->getDoubleValue() * InputSigns[0];
if (fail_zero) Input = 0;
- if (fail_hardover) Input = clipmax*fabs(Input)/Input;
+ if (fail_hardover) Input = clipmax*sign(Input);
Output = Input; // Perfect actuator. At this point, if no failures are present
// and no subsequent lag, limiting, etc. is done, the output
// inputs are read from the base class constructor
- bits = quantized = divisions = 0;
+ bits = quantized = divisions = index = delay = 0;
PreviousInput = PreviousOutput = 0.0;
min = max = bias = noise_variance = lag = drift_rate = drift = span = 0.0;
granularity = 0.0;
cerr << "Unknown noise type in sensor: " << Name << endl;
cerr << " defaulting to PERCENT." << endl;
}
+ string distribution = element->FindElement("noise")->GetAttributeValue("distribution");
+ if (distribution == "UNIFORM") {
+ DistributionType = eUniform;
+ } else if (distribution == "GAUSSIAN") {
+ DistributionType = eGaussian;
+ } else {
+ DistributionType = eUniform;
+ cerr << "Unknown random distribution type in sensor: " << Name << endl;
+ cerr << " defaulting to UNIFORM." << endl;
+ }
+ }
+ if ( element->FindElement("delay") ) {
+ delay = (unsigned int)element->FindElementValueAsNumber("delay");
+ output_array.resize(delay);
+ for (unsigned int i=0; i<delay; i++) output_array[i] = 0.0;
}
FGFCSComponent::bind();
return true;
}
- if (lag != 0.0) Lag(); // models sensor lag
+ if (lag != 0.0) Lag(); // models sensor lag and filter
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 (delay != 0.0) Delay(); // models system signal transport latencies
+
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
Clip(); // Is it right to clip a sensor?
return true;
void FGSensor::Noise(void)
{
- double random_value = ((double)rand()/(double)RAND_MAX) - 0.5;
+ double random_value=0.0;
+
+ if (DistributionType == eUniform) {
+ random_value = ((double)rand()/(double)RAND_MAX) - 0.5;
+ } else {
+ random_value = GaussianRandomNumber();
+ }
switch( NoiseType ) {
case ePercent:
void FGSensor::Lag(void)
{
- // "Output" on the right side of the "=" is the current frame input
+ // "Output" on the right side of the "=" is the current input
Output = ca * (Output + PreviousInput) + PreviousOutput * cb;
PreviousOutput = Output;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+void FGSensor::Delay(void)
+{
+ output_array[index] = Output;
+ if (index == delay-1) index = 0;
+ else index++;
+ Output = output_array[index];
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
void FGSensor::bind(void)
{
string tmp = Name;
else
cout << " INPUT: " << InputNodes[0]->getName() << endl;
}
- if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
+ if (delay > 0) cout <<" Frame delay: " << delay
+ << " frames (" << delay*dt << " sec)" << endl;
if (bits != 0) {
if (quant_property.empty())
cout << " Quantized output" << endl;
} else {
cout << " Noise variance type is invalid" << endl;
}
+ if (DistributionType == eUniform) {
+ cout << " Random noise is uniformly distributed." << endl;
+ } else if (DistributionType == eGaussian) {
+ cout << " Random noise is gaussian distributed." << endl;
+ }
}
+ if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
#include "FGFCSComponent.h"
#include <input_output/FGXMLElement.h>
+#include <vector>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
namespace JSBSim {
+using std::vector;
class FGFCS;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
</quantization>
<drift_rate> number </drift_rate>
<bias> number </bias>
+ <delay> number < /delay>
</sensor>
@endcode
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.
+time. The delay element can specify a frame delay. The integer number provided is
+the number of frames to delay the output signal.
@author Jon S. Berndt
@version $Revision$
protected:
enum eNoiseType {ePercent=0, eAbsolute} NoiseType;
+ enum eDistributionType {eUniform=0, eGaussian} DistributionType;
double dt;
double min, max;
double span;
int bits;
int quantized;
int divisions;
+ int delay;
+ int index;
bool fail_low;
bool fail_high;
bool fail_stuck;
string quant_property;
+ vector <double> output_array;
void Noise(void);
void Bias(void);
void Drift(void);
void Quantize(void);
void Lag(void);
+ void Delay(void);
void bind(void);
}
}
// Boost the manifold pressure.
- double boost_factor = BoostMul[BoostSpeed] * map_coefficient * RPM/RatedRPM[BoostSpeed];
+ double boost_factor = BoostMul[BoostSpeed] * RPM/RatedRPM[BoostSpeed];
if (boost_factor < 1.0) boost_factor = 1.0; // boost will never reduce the MAP
MAP = TMAP * boost_factor;
// Now clip the manifold pressure to BCV or Wastegate setting.
* Calculate the cylinder head temperature.
*
* Inputs: T_amb, IAS, rho_air, m_dot_fuel, calorific_value_fuel,
- * combustion_efficiency, RPM, MaxRPM
+ * combustion_efficiency, RPM, MaxRPM, Displacement
*
* Outputs: CylinderHeadTemp_degK
*/
buf << Name << " Power Available (engine " << EngineNumber << " in HP)" << delimeter
<< Name << " HP (engine " << EngineNumber << ")" << delimeter
<< Name << " equivalent ratio (engine " << EngineNumber << ")" << delimeter
- << Name << " MAP (engine " << EngineNumber << ")" << delimeter
+ << Name << " MAP (engine " << EngineNumber << " in inHg)" << delimeter
<< Thruster->GetThrusterLabels(EngineNumber, delimeter);
return buf.str();
std::ostringstream buf;
buf << PowerAvailable << delimeter << HP << delimeter
- << equivalence_ratio << delimeter << MAP << delimeter
+ << equivalence_ratio << delimeter << ManifoldPressure_inHg << delimeter
<< Thruster->GetThrusterValues(EngineNumber, delimeter);
return buf.str();
void FGTurbine::ResetToIC(void)
{
N1 = N2 = 0.0;
+ N2norm = 0.0;
correctedTSFC = TSFC;
ThrottlePos = AugmentCmd = 0.0;
InletPosition = NozzlePosition = 1.0;
double FGTurbine::Run()
{
double idlethrust, milthrust, thrust;
- double N2norm; // 0.0 = idle N2, 1.0 = maximum N2
+ double spoolup; // acceleration in pct/sec
+ double sigma = Atmosphere->GetDensityRatio();
+ double T = Atmosphere->GetTemperature();
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);
+ // adjust acceleration for N2 and atmospheric density
+ double n = N2norm + 0.1;
+ if (n > 1) n = 1;
+ spoolup = delay / (1 + 3 * (1-n)*(1-n)*(1-n) + (1 - sigma));
+
+ N2 = Seek(&N2, IdleN2 + ThrottlePos * N2_factor, spoolup, spoolup * 3.0);
+ N1 = Seek(&N1, IdleN1 + ThrottlePos * N1_factor, spoolup, spoolup * 2.4);
N2norm = (N2 - IdleN2) / N2_factor;
thrust = idlethrust + (milthrust * N2norm * N2norm);
EGT_degC = TAT + 363.1 + ThrottlePos * 357.1;
OilTemp_degK = Seek(&OilTemp_degK, 366.0, 1.2, 0.1);
if (!Augmentation) {
- correctedTSFC = TSFC * (0.84 + (1-N2norm)*(1-N2norm));
+ correctedTSFC = TSFC * sqrt(T/389.7) * (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);
double FGTurbine::Trim()
{
- double idlethrust, milthrust, thrust, tdiff, N2norm;
+ double idlethrust, milthrust, thrust, tdiff;
idlethrust = MilThrust * IdleThrustLookup->GetValue();
milthrust = (MilThrust - idlethrust) * MilThrustLookup->GetValue();
N2 = IdleN2 + ThrottlePos * N2_factor;
// Pre-calculations and initializations
- delay = 60.0 / (BypassRatio + 3.0);
+ delay = 90.0 / (BypassRatio + 3.0);
N1_factor = MaxN1 - IdleN1;
N2_factor = MaxN2 - IdleN2;
OilTemp_degK = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556 + 273.0;
double IdleN2; ///< Idle N2
double N1; ///< N1
double N2; ///< N2
+ double N2norm; ///< N2 normalized (0=idle, 1=max)
double MaxN1; ///< N1 at 100% throttle
double MaxN2; ///< N2 at 100% throttle
double IdleFF; ///< Idle Fuel Flow (lbm/hr)