Sync'ed JSBSim
* Removed the IAS dependency to the Pitot tube angle (real Pitot tube are less sensitive to AoA than was simulated) * Removed the class FGUDPOutputSocket which was redundant with FGOutputSocket * Added a new type of functions "template" which are intended to prevent duplication of functions. For now, they are available to compute output values and script notifications. * Aerodynamics forces can now be specified in stability axes. * Density altitude and pressure altitude are computed according to ISA standard atmosphere 1976. New properties: * Flight path angle (gamma) in degrees - fdm/jsbsim/flight-path/gamma-deg * Aerodynamics forces in stability axes - fdm/jsbsim/forces/fsx-aero-lbs - fdm/jsbsim/forces/fsy-aero-lbs - fdm/jsbsim/forces/fsz-aero-lbs * Aerodynamics moments in stability axes - moments/roll-stab-aero-lbsft - moments/pitch-stab-aero-lbsft - moments/yaw-stab-aero-lbsft * Pause JSBSim - fdm/jsbsim/simulation/pause * Fixed multiple bugs.
This commit is contained in:
parent
ccabc052bc
commit
6d83e6978d
59 changed files with 1121 additions and 859 deletions
|
@ -23,7 +23,6 @@ set(HEADERS
|
||||||
input_output/FGOutputFG.h
|
input_output/FGOutputFG.h
|
||||||
input_output/FGOutputFile.h
|
input_output/FGOutputFile.h
|
||||||
input_output/FGOutputSocket.h
|
input_output/FGOutputSocket.h
|
||||||
input_output/FGUDPOutputSocket.h
|
|
||||||
input_output/FGOutputTextFile.h
|
input_output/FGOutputTextFile.h
|
||||||
input_output/FGOutputType.h
|
input_output/FGOutputType.h
|
||||||
input_output/FGModelLoader.h
|
input_output/FGModelLoader.h
|
||||||
|
@ -40,6 +39,8 @@ set(HEADERS
|
||||||
math/FGRealValue.h
|
math/FGRealValue.h
|
||||||
math/FGRungeKutta.h
|
math/FGRungeKutta.h
|
||||||
math/FGTable.h
|
math/FGTable.h
|
||||||
|
math/FGFunctionValue.h
|
||||||
|
math/FGTemplateFunc.h
|
||||||
models/FGAccelerations.h
|
models/FGAccelerations.h
|
||||||
models/FGAerodynamics.h
|
models/FGAerodynamics.h
|
||||||
models/FGAircraft.h
|
models/FGAircraft.h
|
||||||
|
@ -117,7 +118,6 @@ set(SOURCES
|
||||||
input_output/FGOutputFG.cpp
|
input_output/FGOutputFG.cpp
|
||||||
input_output/FGOutputFile.cpp
|
input_output/FGOutputFile.cpp
|
||||||
input_output/FGOutputSocket.cpp
|
input_output/FGOutputSocket.cpp
|
||||||
input_output/FGUDPOutputSocket.cpp
|
|
||||||
input_output/FGOutputTextFile.cpp
|
input_output/FGOutputTextFile.cpp
|
||||||
input_output/FGOutputType.cpp
|
input_output/FGOutputType.cpp
|
||||||
input_output/FGModelLoader.cpp
|
input_output/FGModelLoader.cpp
|
||||||
|
@ -191,6 +191,8 @@ set(SOURCES
|
||||||
|
|
||||||
|
|
||||||
add_library(JSBSim STATIC ${SOURCES} ${HEADERS})
|
add_library(JSBSim STATIC ${SOURCES} ${HEADERS})
|
||||||
|
set(VERSION_MESSAGE "compiled from FlightGear ${FLIGHTGEAR_VERSION}")
|
||||||
|
add_definitions("-DJSBSIM_VERSION=\"${VERSION_MESSAGE}\"")
|
||||||
|
|
||||||
target_link_libraries(JSBSim SimGearCore)
|
target_link_libraries(JSBSim SimGearCore)
|
||||||
target_include_directories(JSBSim PRIVATE ${CMAKE_SOURCE_DIR}/src/FDM/JSBSim)
|
target_include_directories(JSBSim PRIVATE ${CMAKE_SOURCE_DIR}/src/FDM/JSBSim)
|
||||||
|
|
|
@ -169,6 +169,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr) : Root(root)
|
||||||
instance->Tie("simulation/disperse", this, &FGFDMExec::GetDisperse);
|
instance->Tie("simulation/disperse", this, &FGFDMExec::GetDisperse);
|
||||||
instance->Tie("simulation/randomseed", this, (iPMF)&FGFDMExec::SRand, &FGFDMExec::SRand, false);
|
instance->Tie("simulation/randomseed", this, (iPMF)&FGFDMExec::SRand, &FGFDMExec::SRand, false);
|
||||||
instance->Tie("simulation/terminate", (int *)&Terminate);
|
instance->Tie("simulation/terminate", (int *)&Terminate);
|
||||||
|
instance->Tie("simulation/pause", (int *)&holding);
|
||||||
instance->Tie("simulation/sim-time-sec", this, &FGFDMExec::GetSimTime);
|
instance->Tie("simulation/sim-time-sec", this, &FGFDMExec::GetSimTime);
|
||||||
instance->Tie("simulation/dt", this, &FGFDMExec::GetDeltaT);
|
instance->Tie("simulation/dt", this, &FGFDMExec::GetDeltaT);
|
||||||
instance->Tie("simulation/jsbsim-debug", this, &FGFDMExec::GetDebugLevel, &FGFDMExec::SetDebugLevel);
|
instance->Tie("simulation/jsbsim-debug", this, &FGFDMExec::GetDebugLevel, &FGFDMExec::SetDebugLevel);
|
||||||
|
@ -540,7 +541,6 @@ void FGFDMExec::LoadModelConstants(void)
|
||||||
Aerodynamics->in.Wingspan = Aircraft->GetWingSpan();
|
Aerodynamics->in.Wingspan = Aircraft->GetWingSpan();
|
||||||
Auxiliary->in.Wingspan = Aircraft->GetWingSpan();
|
Auxiliary->in.Wingspan = Aircraft->GetWingSpan();
|
||||||
Auxiliary->in.Wingchord = Aircraft->Getcbar();
|
Auxiliary->in.Wingchord = Aircraft->Getcbar();
|
||||||
Auxiliary->in.PitotAngle = Aircraft->GetPitotAngle();
|
|
||||||
GroundReactions->in.vXYZcg = MassBalance->GetXYZcg();
|
GroundReactions->in.vXYZcg = MassBalance->GetXYZcg();
|
||||||
|
|
||||||
LoadPlanetConstants();
|
LoadPlanetConstants();
|
||||||
|
|
|
@ -86,15 +86,11 @@ const double FGJSBBase::psftoinhg = 0.014138;
|
||||||
const double FGJSBBase::psftopa = 47.88;
|
const double FGJSBBase::psftopa = 47.88;
|
||||||
const double FGJSBBase::ktstofps = 1.68781;
|
const double FGJSBBase::ktstofps = 1.68781;
|
||||||
const double FGJSBBase::fpstokts = 1.0/ktstofps;
|
const double FGJSBBase::fpstokts = 1.0/ktstofps;
|
||||||
const double FGJSBBase::inchtoft = 0.08333333;
|
const double FGJSBBase::inchtoft = 1.0/12;
|
||||||
const double FGJSBBase::in3tom3 = 1.638706E-5;
|
const double FGJSBBase::in3tom3 = 1.638706E-5;
|
||||||
const double FGJSBBase::m3toft3 = 1.0/(fttom*fttom*fttom);
|
const double FGJSBBase::m3toft3 = 1.0/(fttom*fttom*fttom);
|
||||||
const double FGJSBBase::inhgtopa = 3386.38;
|
const double FGJSBBase::inhgtopa = 3386.38;
|
||||||
const double FGJSBBase::fttom = 0.3048;
|
const double FGJSBBase::fttom = 0.3048;
|
||||||
double FGJSBBase::Reng = 1716.56; // Gas constant for Air (ft-lb/slug-R)
|
|
||||||
double FGJSBBase::Rstar = 1545.348; // Universal gas constant
|
|
||||||
double FGJSBBase::Mair = 28.9645; //
|
|
||||||
const double FGJSBBase::SHRatio = 1.40;
|
|
||||||
|
|
||||||
// Note that definition of lbtoslug by the inverse of slugtolb and not
|
// Note that definition of lbtoslug by the inverse of slugtolb and not
|
||||||
// to a different constant you can also get from some tables will make
|
// to a different constant you can also get from some tables will make
|
||||||
|
@ -108,7 +104,7 @@ const double FGJSBBase::kgtolb = 2.20462;
|
||||||
const double FGJSBBase::kgtoslug = 0.06852168;
|
const double FGJSBBase::kgtoslug = 0.06852168;
|
||||||
|
|
||||||
const string FGJSBBase::needed_cfg_version = "2.0";
|
const string FGJSBBase::needed_cfg_version = "2.0";
|
||||||
const string FGJSBBase::JSBSim_version = "1.0 " __DATE__ " " __TIME__ ;
|
const string FGJSBBase::JSBSim_version = JSBSIM_VERSION " " __DATE__ " " __TIME__ ;
|
||||||
|
|
||||||
queue <FGJSBBase::Message> FGJSBBase::Messages;
|
queue <FGJSBBase::Message> FGJSBBase::Messages;
|
||||||
FGJSBBase::Message FGJSBBase::localMsg;
|
FGJSBBase::Message FGJSBBase::localMsg;
|
||||||
|
|
|
@ -358,10 +358,6 @@ protected:
|
||||||
static const double m3toft3;
|
static const double m3toft3;
|
||||||
static const double inhgtopa;
|
static const double inhgtopa;
|
||||||
static const double fttom;
|
static const double fttom;
|
||||||
static double Reng; // Specific Gas Constant,ft^2/(sec^2*R)
|
|
||||||
static double Rstar;
|
|
||||||
static double Mair;
|
|
||||||
static const double SHRatio;
|
|
||||||
static const double lbtoslug;
|
static const double lbtoslug;
|
||||||
static const double slugtolb;
|
static const double slugtolb;
|
||||||
static const double kgtolb;
|
static const double kgtolb;
|
||||||
|
|
|
@ -185,9 +185,8 @@ void FGInitialCondition::SetVcalibratedKtsIC(double vcas)
|
||||||
double rhoSL = Atmosphere->GetDensitySL();
|
double rhoSL = Atmosphere->GetDensitySL();
|
||||||
double mach = MachFromVcalibrated(fabs(vcas)*ktstofps, pressure, pressureSL, rhoSL);
|
double mach = MachFromVcalibrated(fabs(vcas)*ktstofps, pressure, pressureSL, rhoSL);
|
||||||
double soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
|
double soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
|
||||||
double PitotAngle = Aircraft->GetPitotAngle();
|
|
||||||
|
|
||||||
SetVtrueFpsIC(mach * soundSpeed / (cos(alpha+PitotAngle) * cos(beta)));
|
SetVtrueFpsIC(mach * soundSpeed);
|
||||||
lastSpeedSet = setvc;
|
lastSpeedSet = setvc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -703,7 +702,6 @@ void FGInitialCondition::SetAltitudeASLFtIC(double alt)
|
||||||
double mach0 = vt / soundSpeed;
|
double mach0 = vt / soundSpeed;
|
||||||
double vc0 = VcalibratedFromMach(mach0, pressure, pressureSL, rhoSL);
|
double vc0 = VcalibratedFromMach(mach0, pressure, pressureSL, rhoSL);
|
||||||
double ve0 = vt * sqrt(rho/rhoSL);
|
double ve0 = vt * sqrt(rho/rhoSL);
|
||||||
double PitotAngle = Aircraft->GetPitotAngle();
|
|
||||||
|
|
||||||
double geodLatitude = position.GetGeodLatitudeRad();
|
double geodLatitude = position.GetGeodLatitudeRad();
|
||||||
altitudeASL=alt;
|
altitudeASL=alt;
|
||||||
|
@ -720,9 +718,8 @@ void FGInitialCondition::SetAltitudeASLFtIC(double alt)
|
||||||
|
|
||||||
switch(lastSpeedSet) {
|
switch(lastSpeedSet) {
|
||||||
case setvc:
|
case setvc:
|
||||||
mach0 = MachFromVcalibrated(vc0 * cos(alpha+PitotAngle) * cos(beta),
|
mach0 = MachFromVcalibrated(vc0, pressure, pressureSL, rhoSL);
|
||||||
pressure, pressureSL, rhoSL);
|
SetVtrueFpsIC(mach0 * soundSpeed);
|
||||||
SetVtrueFpsIC(mach0 * soundSpeed / (cos(alpha+PitotAngle) * cos(beta)));
|
|
||||||
break;
|
break;
|
||||||
case setmach:
|
case setmach:
|
||||||
SetVtrueFpsIC(mach0 * soundSpeed);
|
SetVtrueFpsIC(mach0 * soundSpeed);
|
||||||
|
@ -843,8 +840,7 @@ double FGInitialCondition::GetVcalibratedKtsIC(void) const
|
||||||
double pressureSL = Atmosphere->GetPressureSL();
|
double pressureSL = Atmosphere->GetPressureSL();
|
||||||
double rhoSL = Atmosphere->GetDensitySL();
|
double rhoSL = Atmosphere->GetDensitySL();
|
||||||
double soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
|
double soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
|
||||||
double PitotAngle = Aircraft->GetPitotAngle();
|
double mach = vt / soundSpeed;
|
||||||
double mach = vt * cos(alpha+PitotAngle) * cos(beta) / soundSpeed;
|
|
||||||
|
|
||||||
return fpstokts * VcalibratedFromMach(mach, pressure, pressureSL, rhoSL);
|
return fpstokts * VcalibratedFromMach(mach, pressure, pressureSL, rhoSL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,8 @@ CLASS IMPLEMENTATION
|
||||||
|
|
||||||
FGInputSocket::FGInputSocket(FGFDMExec* fdmex) :
|
FGInputSocket::FGInputSocket(FGFDMExec* fdmex) :
|
||||||
FGInputType(fdmex),
|
FGInputType(fdmex),
|
||||||
socket(0)
|
socket(0),
|
||||||
|
SockProtocol(FGfdmSocket::ptTCP)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +96,7 @@ bool FGInputSocket::InitModel(void)
|
||||||
{
|
{
|
||||||
if (FGInputType::InitModel()) {
|
if (FGInputType::InitModel()) {
|
||||||
delete socket;
|
delete socket;
|
||||||
socket = new FGfdmSocket(SockPort);
|
socket = new FGfdmSocket(SockPort, SockProtocol);
|
||||||
|
|
||||||
if (socket == 0) return false;
|
if (socket == 0) return false;
|
||||||
if (!socket->GetConnectStatus()) return false;
|
if (!socket->GetConnectStatus()) return false;
|
||||||
|
|
|
@ -92,6 +92,7 @@ protected:
|
||||||
|
|
||||||
unsigned int SockPort;
|
unsigned int SockPort;
|
||||||
FGfdmSocket* socket;
|
FGfdmSocket* socket;
|
||||||
|
FGfdmSocket::ProtocolType SockProtocol;
|
||||||
std::string data;
|
std::string data;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ void FGInputType::SetIdx(unsigned int idx)
|
||||||
bool FGInputType::Load(Element* element)
|
bool FGInputType::Load(Element* element)
|
||||||
{
|
{
|
||||||
// Perform base class Load.
|
// Perform base class Load.
|
||||||
if(!FGModel::Load(element))
|
if(!FGModel::Load(element, true))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// no common attributes yet (see FGOutputType for example
|
// no common attributes yet (see FGOutputType for example
|
||||||
|
|
|
@ -46,7 +46,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
namespace JSBSim {
|
||||||
|
|
||||||
IDENT(IdSrc, "$Id: FGModelLoader.cpp,v 1.4 2017/02/25 14:23:18 bcoconni Exp $");
|
IDENT(IdSrc, "$Id: FGModelLoader.cpp,v 1.5 2017/03/18 16:17:42 bcoconni Exp $");
|
||||||
IDENT(IdHdr, ID_MODELLOADER);
|
IDENT(IdHdr, ID_MODELLOADER);
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -71,7 +71,7 @@ Element_ptr FGModelLoader::Open(Element *el)
|
||||||
document = XMLFileRead.LoadXMLDocument(path);
|
document = XMLFileRead.LoadXMLDocument(path);
|
||||||
if (document == 0L) {
|
if (document == 0L) {
|
||||||
cerr << endl << el->ReadFrom()
|
cerr << endl << el->ReadFrom()
|
||||||
<< "Could not open file: " << path << endl;
|
<< "Could not open file: " << fname << endl;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
CachedFiles[path.utf8Str()] = document;
|
CachedFiles[path.utf8Str()] = document;
|
||||||
|
|
|
@ -55,6 +55,7 @@ INCLUDES
|
||||||
#include "models/FGFCS.h"
|
#include "models/FGFCS.h"
|
||||||
#include "models/atmosphere/FGWinds.h"
|
#include "models/atmosphere/FGWinds.h"
|
||||||
#include "input_output/FGXMLElement.h"
|
#include "input_output/FGXMLElement.h"
|
||||||
|
#include "math/FGPropertyValue.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -260,13 +261,11 @@ void FGOutputSocket::PrintHeaders(void)
|
||||||
if (SubSystems & ssPropulsion && Propulsion->GetNumEngines() > 0)
|
if (SubSystems & ssPropulsion && Propulsion->GetNumEngines() > 0)
|
||||||
socket->Append(Propulsion->GetPropulsionStrings(","));
|
socket->Append(Propulsion->GetPropulsionStrings(","));
|
||||||
|
|
||||||
if (OutputProperties.size() > 0) {
|
for (unsigned int i=0;i<OutputParameters.size();++i) {
|
||||||
for (unsigned int i=0;i<OutputProperties.size();i++)
|
if (!OutputCaptions[i].empty())
|
||||||
if (OutputCaptions[i].size() > 0) {
|
socket->Append(OutputCaptions[i]);
|
||||||
socket->Append(OutputCaptions[i]);
|
else
|
||||||
} else {
|
socket->Append(OutputParameters[i]->GetPrintableName());
|
||||||
socket->Append(OutputProperties[i]->GetPrintableName());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
socket->Send();
|
socket->Send();
|
||||||
|
@ -378,8 +377,8 @@ void FGOutputSocket::Print(void)
|
||||||
socket->Append(Propulsion->GetPropulsionValues(","));
|
socket->Append(Propulsion->GetPropulsionValues(","));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (unsigned int i=0;i<OutputProperties.size();i++) {
|
for (unsigned int i=0;i<OutputParameters.size();++i) {
|
||||||
socket->Append(OutputProperties[i]->getDoubleValue());
|
socket->Append(OutputParameters[i]->GetValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
socket->Send();
|
socket->Send();
|
||||||
|
|
|
@ -59,6 +59,7 @@ INCLUDES
|
||||||
#include "models/FGFCS.h"
|
#include "models/FGFCS.h"
|
||||||
#include "models/atmosphere/FGWinds.h"
|
#include "models/atmosphere/FGWinds.h"
|
||||||
#include "input_output/FGXMLElement.h"
|
#include "input_output/FGXMLElement.h"
|
||||||
|
#include "math/FGPropertyValue.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -76,8 +77,6 @@ bool FGOutputTextFile::Load(Element* el)
|
||||||
if(!FGOutputFile::Load(el))
|
if(!FGOutputFile::Load(el))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// PreLoad(el, PropertyManager);
|
|
||||||
|
|
||||||
string type = el->GetAttributeValue("type");
|
string type = el->GetAttributeValue("type");
|
||||||
string delim;
|
string delim;
|
||||||
if (type == "TABULAR") {
|
if (type == "TABULAR") {
|
||||||
|
@ -234,14 +233,12 @@ bool FGOutputTextFile::OpenFile(void)
|
||||||
outstream << delimeter;
|
outstream << delimeter;
|
||||||
outstream << Propulsion->GetPropulsionStrings(delimeter);
|
outstream << Propulsion->GetPropulsionStrings(delimeter);
|
||||||
}
|
}
|
||||||
if (OutputProperties.size() > 0) {
|
|
||||||
for (unsigned int i=0;i<OutputProperties.size();i++) {
|
for (unsigned int i=0;i<OutputParameters.size();++i) {
|
||||||
if (OutputCaptions[i].size() > 0) {
|
if (!OutputCaptions[i].empty())
|
||||||
outstream << delimeter << OutputCaptions[i];
|
outstream << delimeter << OutputCaptions[i];
|
||||||
} else {
|
else
|
||||||
outstream << delimeter << OutputProperties[i]->GetFullyQualifiedName();
|
outstream << delimeter << OutputParameters[i]->GetFullyQualifiedName();
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PreFunctions.size() > 0) {
|
if (PreFunctions.size() > 0) {
|
||||||
|
@ -394,8 +391,8 @@ void FGOutputTextFile::Print(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
outstream.precision(18);
|
outstream.precision(18);
|
||||||
for (unsigned int i=0;i<OutputProperties.size();i++) {
|
for (unsigned int i=0;i<OutputParameters.size();++i) {
|
||||||
outstream << delimeter << OutputProperties[i]->getDoubleValue();
|
outstream << delimeter << OutputParameters[i]->GetValue();
|
||||||
}
|
}
|
||||||
for (unsigned int i=0;i<PreFunctions.size();i++) {
|
for (unsigned int i=0;i<PreFunctions.size();i++) {
|
||||||
outstream << delimeter << PreFunctions[i]->getDoubleValue();
|
outstream << delimeter << PreFunctions[i]->getDoubleValue();
|
||||||
|
|
|
@ -43,6 +43,8 @@ INCLUDES
|
||||||
#include "FGOutputType.h"
|
#include "FGOutputType.h"
|
||||||
#include "input_output/FGXMLElement.h"
|
#include "input_output/FGXMLElement.h"
|
||||||
#include "input_output/FGPropertyManager.h"
|
#include "input_output/FGPropertyManager.h"
|
||||||
|
#include "math/FGTemplateFunc.h"
|
||||||
|
#include "math/FGFunctionValue.h"
|
||||||
|
|
||||||
namespace JSBSim {
|
namespace JSBSim {
|
||||||
|
|
||||||
|
@ -81,7 +83,10 @@ FGOutputType::FGOutputType(FGFDMExec* fdmex) :
|
||||||
|
|
||||||
FGOutputType::~FGOutputType()
|
FGOutputType::~FGOutputType()
|
||||||
{
|
{
|
||||||
OutputProperties.clear();
|
vector<FGPropertyValue*>::iterator it;
|
||||||
|
for (it=OutputParameters.begin(); it != OutputParameters.end(); ++it)
|
||||||
|
delete *it;
|
||||||
|
|
||||||
Debug(1);
|
Debug(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,25 +138,41 @@ bool FGOutputType::Load(Element* element)
|
||||||
string property_str = property_element->GetDataLine();
|
string property_str = property_element->GetDataLine();
|
||||||
FGPropertyNode* node = PropertyManager->GetNode(property_str);
|
FGPropertyNode* node = PropertyManager->GetNode(property_str);
|
||||||
if (!node) {
|
if (!node) {
|
||||||
cerr << fgred << highint << endl << " No property by the name "
|
cerr << property_element->ReadFrom()
|
||||||
|
<< fgred << highint << endl << " No property by the name "
|
||||||
<< property_str << " has been defined. This property will " << endl
|
<< property_str << " has been defined. This property will " << endl
|
||||||
<< " not be logged. You should check your configuration file."
|
<< " not be logged. You should check your configuration file."
|
||||||
<< reset << endl;
|
<< reset << endl;
|
||||||
} else {
|
} else {
|
||||||
OutputProperties.push_back(node);
|
if (property_element->HasAttribute("apply")) {
|
||||||
if (property_element->HasAttribute("caption")) {
|
string function_str = property_element->GetAttributeValue("apply");
|
||||||
OutputCaptions.push_back(property_element->GetAttributeValue("caption"));
|
FGOutput* Output = FDMExec->GetOutput();
|
||||||
} else {
|
FGTemplateFunc* f = Output->GetTemplateFunc(function_str);
|
||||||
OutputCaptions.push_back("");
|
if (f)
|
||||||
|
OutputParameters.push_back(new FGFunctionValue(node, f));
|
||||||
|
else {
|
||||||
|
cerr << property_element->ReadFrom()
|
||||||
|
<< fgred << highint << " No function by the name "
|
||||||
|
<< function_str << " has been defined. This property will "
|
||||||
|
<< "not be logged. You should check your configuration file."
|
||||||
|
<< reset << endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
OutputParameters.push_back(new FGPropertyValue(node));
|
||||||
|
|
||||||
|
if (property_element->HasAttribute("caption"))
|
||||||
|
OutputCaptions.push_back(property_element->GetAttributeValue("caption"));
|
||||||
|
else
|
||||||
|
OutputCaptions.push_back("");
|
||||||
}
|
}
|
||||||
property_element = element->FindNextElement("property");
|
property_element = element->FindNextElement("property");
|
||||||
}
|
}
|
||||||
|
|
||||||
double outRate = 1.0;
|
double outRate = 1.0;
|
||||||
if (!element->GetAttributeValue("rate").empty()) {
|
if (element->HasAttribute("rate"))
|
||||||
outRate = element->GetAttributeValueAsNumber("rate");
|
outRate = element->GetAttributeValueAsNumber("rate");
|
||||||
}
|
|
||||||
SetRateHz(outRate);
|
SetRateHz(outRate);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -204,6 +225,16 @@ double FGOutputType::GetRateHz(void) const
|
||||||
return 1.0 / (rate * FDMExec->GetDeltaT());
|
return 1.0 / (rate * FDMExec->GetDeltaT());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGOutputType::SetOutputProperties(vector<FGPropertyNode_ptr> & outputProperties)
|
||||||
|
{
|
||||||
|
vector<FGPropertyNode_ptr>::iterator it;
|
||||||
|
for (it = outputProperties.begin(); it != outputProperties.end(); ++it)
|
||||||
|
OutputParameters.push_back(new FGPropertyValue(*it));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
// The bitmasked value choices are as follows:
|
// The bitmasked value choices are as follows:
|
||||||
// unset: In this case (the default) JSBSim would only print
|
// unset: In this case (the default) JSBSim would only print
|
||||||
|
@ -245,9 +276,9 @@ void FGOutputType::Debug(int from)
|
||||||
if (SubSystems & ssGroundReactions) cout << " Ground parameters logged" << endl;
|
if (SubSystems & ssGroundReactions) cout << " Ground parameters logged" << endl;
|
||||||
if (SubSystems & ssFCS) cout << " FCS parameters logged" << endl;
|
if (SubSystems & ssFCS) cout << " FCS parameters logged" << endl;
|
||||||
if (SubSystems & ssPropulsion) cout << " Propulsion parameters logged" << endl;
|
if (SubSystems & ssPropulsion) cout << " Propulsion parameters logged" << endl;
|
||||||
if (OutputProperties.size() > 0) cout << " Properties logged:" << endl;
|
if (!OutputParameters.empty()) cout << " Properties logged:" << endl;
|
||||||
for (unsigned int i=0;i<OutputProperties.size();i++) {
|
for (unsigned int i=0;i<OutputParameters.size();i++) {
|
||||||
cout << " - " << OutputProperties[i]->GetName() << endl;
|
cout << " - " << OutputParameters[i]->GetName() << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -67,6 +67,7 @@ class FGFCS;
|
||||||
class FGGroundReactions;
|
class FGGroundReactions;
|
||||||
class FGExternalReactions;
|
class FGExternalReactions;
|
||||||
class FGBuoyantForces;
|
class FGBuoyantForces;
|
||||||
|
class FGPropertyValue;
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
CLASS DOCUMENTATION
|
CLASS DOCUMENTATION
|
||||||
|
@ -124,10 +125,7 @@ public:
|
||||||
/** Set the list of properties that should be output for this output instance.
|
/** Set the list of properties that should be output for this output instance.
|
||||||
@param outputProperties list of properties that should be output
|
@param outputProperties list of properties that should be output
|
||||||
*/
|
*/
|
||||||
void SetOutputProperties(std::vector<FGPropertyNode_ptr> & outputProperties)
|
void SetOutputProperties(std::vector<FGPropertyNode_ptr> & outputProperties);
|
||||||
{
|
|
||||||
OutputProperties = outputProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Overwrites the name identifier under which the output will be logged.
|
/** Overwrites the name identifier under which the output will be logged.
|
||||||
This method is taken into account if it is called before
|
This method is taken into account if it is called before
|
||||||
|
@ -199,7 +197,7 @@ public:
|
||||||
protected:
|
protected:
|
||||||
unsigned int OutputIdx;
|
unsigned int OutputIdx;
|
||||||
int SubSystems;
|
int SubSystems;
|
||||||
std::vector <FGPropertyNode_ptr> OutputProperties;
|
std::vector <FGPropertyValue*> OutputParameters;
|
||||||
std::vector <std::string> OutputCaptions;
|
std::vector <std::string> OutputCaptions;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ INCLUDES
|
||||||
#include "models/FGInput.h"
|
#include "models/FGInput.h"
|
||||||
#include "math/FGCondition.h"
|
#include "math/FGCondition.h"
|
||||||
#include "math/FGFunction.h"
|
#include "math/FGFunction.h"
|
||||||
|
#include "math/FGFunctionValue.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -88,6 +89,8 @@ FGScript::~FGScript()
|
||||||
delete Events[i].Condition;
|
delete Events[i].Condition;
|
||||||
for (j=0; j<Events[i].Functions.size(); j++)
|
for (j=0; j<Events[i].Functions.size(); j++)
|
||||||
delete Events[i].Functions[j];
|
delete Events[i].Functions[j];
|
||||||
|
for (j=0; j<Events[i].NotifyProperties.size(); j++)
|
||||||
|
delete Events[i].NotifyProperties[j];
|
||||||
}
|
}
|
||||||
Events.clear();
|
Events.clear();
|
||||||
|
|
||||||
|
@ -206,8 +209,12 @@ bool FGScript::LoadScript(const SGPath& script, double default_dT,
|
||||||
|
|
||||||
// Now, read output spec if given.
|
// Now, read output spec if given.
|
||||||
element = document->FindElement("output");
|
element = document->FindElement("output");
|
||||||
|
SGPath scriptDir = SGPath(script.dir());
|
||||||
|
if (scriptDir.isNull())
|
||||||
|
scriptDir = SGPath(".");
|
||||||
|
|
||||||
while (element) {
|
while (element) {
|
||||||
if (!FDMExec->GetOutput()->Load(element))
|
if (!FDMExec->GetOutput()->Load(element, scriptDir))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
element = document->FindNextElement("output");
|
element = document->FindNextElement("output");
|
||||||
|
@ -282,14 +289,29 @@ bool FGScript::LoadScript(const SGPath& script, double default_dT,
|
||||||
while (notify_property_element) {
|
while (notify_property_element) {
|
||||||
notifyPropertyName = notify_property_element->GetDataLine();
|
notifyPropertyName = notify_property_element->GetDataLine();
|
||||||
|
|
||||||
newEvent->NotifyPropertyNames.push_back(notifyPropertyName);
|
if (notify_property_element->HasAttribute("apply")) {
|
||||||
newEvent->NotifyProperties.push_back(0);
|
string function_str = notify_property_element->GetAttributeValue("apply");
|
||||||
string caption_attribute = notify_property_element->GetAttributeValue("caption");
|
FGOutput* Output = FDMExec->GetOutput();
|
||||||
if (caption_attribute.empty()) {
|
FGTemplateFunc* f = Output->GetTemplateFunc(function_str);
|
||||||
newEvent->DisplayString.push_back(notifyPropertyName);
|
if (f)
|
||||||
} else {
|
newEvent->NotifyProperties.push_back(new FGFunctionValue(notifyPropertyName, PropertyManager, f));
|
||||||
newEvent->DisplayString.push_back(caption_attribute);
|
else {
|
||||||
|
cerr << notify_property_element->ReadFrom()
|
||||||
|
<< fgred << highint << " No function by the name "
|
||||||
|
<< function_str << " has been defined. This property will "
|
||||||
|
<< "not be logged. You should check your configuration file."
|
||||||
|
<< reset << endl;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
newEvent->NotifyProperties.push_back(new FGPropertyValue(notifyPropertyName, PropertyManager));
|
||||||
|
|
||||||
|
string caption_attribute = notify_property_element->GetAttributeValue("caption");
|
||||||
|
if (caption_attribute.empty()) {
|
||||||
|
newEvent->DisplayString.push_back(notifyPropertyName);
|
||||||
|
} else {
|
||||||
|
newEvent->DisplayString.push_back(caption_attribute);
|
||||||
|
}
|
||||||
|
|
||||||
notify_property_element = notify_element->FindNextElement("property");
|
notify_property_element = notify_element->FindNextElement("property");
|
||||||
}
|
}
|
||||||
|
@ -487,13 +509,6 @@ bool FGScript::RunScript(void)
|
||||||
cout << " " << thisEvent.Description << endl;
|
cout << " " << thisEvent.Description << endl;
|
||||||
}
|
}
|
||||||
for (j=0; j<thisEvent.NotifyProperties.size();j++) {
|
for (j=0; j<thisEvent.NotifyProperties.size();j++) {
|
||||||
if (thisEvent.NotifyProperties[j] == 0) {
|
|
||||||
if (PropertyManager->HasNode(thisEvent.NotifyPropertyNames[j])) {
|
|
||||||
thisEvent.NotifyProperties[j] = PropertyManager->GetNode(thisEvent.NotifyPropertyNames[j]);
|
|
||||||
} else {
|
|
||||||
throw("Could not find property named "+thisEvent.NotifyPropertyNames[j]+" in script.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cout << " " << thisEvent.DisplayString[j] << " = " << thisEvent.NotifyProperties[j]->getDoubleValue();
|
cout << " " << thisEvent.DisplayString[j] << " = " << thisEvent.NotifyProperties[j]->getDoubleValue();
|
||||||
if (thisEvent.NotifyKML) cout << " <br/>";
|
if (thisEvent.NotifyKML) cout << " <br/>";
|
||||||
cout << endl;
|
cout << endl;
|
||||||
|
@ -657,10 +672,10 @@ void FGScript::Debug(int from)
|
||||||
} else {
|
} else {
|
||||||
cout << " Notifications:" << endl << " {" << endl;
|
cout << " Notifications:" << endl << " {" << endl;
|
||||||
}
|
}
|
||||||
for (unsigned j=0; j<Events[i].NotifyPropertyNames.size();j++) {
|
for (unsigned j=0; j<Events[i].NotifyProperties.size();j++) {
|
||||||
cout << " "
|
cout << " "
|
||||||
<< Events[i].NotifyPropertyNames[j]
|
<< Events[i].NotifyProperties[j]->GetPrintableName()
|
||||||
<< endl;
|
<< endl;
|
||||||
}
|
}
|
||||||
cout << " }" << endl;
|
cout << " }" << endl;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,6 +60,7 @@ namespace JSBSim {
|
||||||
class FGFDMExec;
|
class FGFDMExec;
|
||||||
class FGCondition;
|
class FGCondition;
|
||||||
class FGFunction;
|
class FGFunction;
|
||||||
|
class FGPropertyValue;
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
CLASS DOCUMENTATION
|
CLASS DOCUMENTATION
|
||||||
|
@ -227,8 +228,7 @@ private:
|
||||||
std::string Description;
|
std::string Description;
|
||||||
std::vector <FGPropertyNode_ptr> SetParam;
|
std::vector <FGPropertyNode_ptr> SetParam;
|
||||||
std::vector <std::string> SetParamName;
|
std::vector <std::string> SetParamName;
|
||||||
std::vector <FGPropertyNode_ptr> NotifyProperties;
|
std::vector <FGPropertyValue*> NotifyProperties;
|
||||||
std::vector <std::string> NotifyPropertyNames;
|
|
||||||
std::vector <std::string> DisplayString;
|
std::vector <std::string> DisplayString;
|
||||||
std::vector <eAction> Action;
|
std::vector <eAction> Action;
|
||||||
std::vector <eType> Type;
|
std::vector <eType> Type;
|
||||||
|
|
|
@ -57,36 +57,21 @@ CLASS IMPLEMENTATION
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
FGUDPInputSocket::FGUDPInputSocket(FGFDMExec* fdmex) :
|
FGUDPInputSocket::FGUDPInputSocket(FGFDMExec* fdmex) :
|
||||||
FGInputType(fdmex),
|
FGInputSocket(fdmex), rate(20), oldTimeStamp(0.0)
|
||||||
socket(0)
|
|
||||||
{
|
{
|
||||||
rate = 20;
|
|
||||||
SockPort = 5139;
|
SockPort = 5139;
|
||||||
oldTimeStamp = 0.0;
|
SockProtocol = FGfdmSocket::ptUDP;
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
FGUDPInputSocket::~FGUDPInputSocket()
|
|
||||||
{
|
|
||||||
delete socket;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
bool FGUDPInputSocket::Load(Element* el)
|
bool FGUDPInputSocket::Load(Element* el)
|
||||||
{
|
{
|
||||||
if (!FGInputType::Load(el))
|
if (!FGInputSocket::Load(el))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
rate = atoi(el->GetAttributeValue("rate").c_str());
|
rate = atoi(el->GetAttributeValue("rate").c_str());
|
||||||
SetRate(0.5 + 1.0/(FDMExec->GetDeltaT()*rate));
|
SetRate(0.5 + 1.0/(FDMExec->GetDeltaT()*rate));
|
||||||
|
|
||||||
SockPort = atoi(el->GetAttributeValue("port").c_str());
|
|
||||||
if (SockPort == 0) {
|
|
||||||
cerr << endl << "No port assigned in input element" << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Element *property_element = el->FindElement("property");
|
Element *property_element = el->FindElement("property");
|
||||||
|
|
||||||
|
@ -107,25 +92,8 @@ bool FGUDPInputSocket::Load(Element* el)
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
bool FGUDPInputSocket::InitModel(void)
|
|
||||||
{
|
|
||||||
if (FGInputType::InitModel()) {
|
|
||||||
delete socket;
|
|
||||||
socket = new FGfdmSocket(SockPort, FGfdmSocket::ptUDP, FGfdmSocket::dIN);
|
|
||||||
|
|
||||||
if (socket == 0) return false;
|
|
||||||
cout << "UDP input socket established on port " << SockPort << endl;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
void FGUDPInputSocket::Read(bool Holding)
|
void FGUDPInputSocket::Read(bool Holding)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (socket == 0) return;
|
if (socket == 0) return;
|
||||||
|
|
||||||
data = socket->Receive();
|
data = socket->Receive();
|
||||||
|
@ -160,9 +128,7 @@ void FGUDPInputSocket::Read(bool Holding)
|
||||||
for (unsigned int i=1; i<values.size(); i++) {
|
for (unsigned int i=1; i<values.size(); i++) {
|
||||||
InputProperties[i-1]->setDoubleValue(values[i]);
|
InputProperties[i-1]->setDoubleValue(values[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,8 +38,7 @@ SENTRY
|
||||||
INCLUDES
|
INCLUDES
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
#include "FGInputType.h"
|
#include "FGInputSocket.h"
|
||||||
#include "input_output/FGfdmSocket.h"
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
DEFINITIONS
|
DEFINITIONS
|
||||||
|
@ -64,26 +63,17 @@ CLASS DOCUMENTATION
|
||||||
CLASS DECLARATION
|
CLASS DECLARATION
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
class FGUDPInputSocket : public FGInputType
|
class FGUDPInputSocket : public FGInputSocket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/** Constructor. */
|
/** Constructor. */
|
||||||
FGUDPInputSocket(FGFDMExec* fdmex);
|
FGUDPInputSocket(FGFDMExec* fdmex);
|
||||||
|
|
||||||
/** Destructor. */
|
|
||||||
~FGUDPInputSocket();
|
|
||||||
|
|
||||||
/** Reads the property names from an XML file.
|
/** Reads the property names from an XML file.
|
||||||
@param element The root XML Element of the input file.
|
@param element The root XML Element of the input file.
|
||||||
*/
|
*/
|
||||||
bool Load(Element* el);
|
bool Load(Element* el);
|
||||||
|
|
||||||
/** Initializes the instance. This method basically opens the socket to which
|
|
||||||
inputs will be directed.
|
|
||||||
@result true if the execution succeeded.
|
|
||||||
*/
|
|
||||||
bool InitModel(void);
|
|
||||||
|
|
||||||
/// Reads the socket and updates properties accordingly.
|
/// Reads the socket and updates properties accordingly.
|
||||||
void Read(bool Holding);
|
void Read(bool Holding);
|
||||||
|
|
||||||
|
@ -92,9 +82,6 @@ protected:
|
||||||
int rate;
|
int rate;
|
||||||
double oldTimeStamp;
|
double oldTimeStamp;
|
||||||
std::vector<FGPropertyNode_ptr> InputProperties;
|
std::vector<FGPropertyNode_ptr> InputProperties;
|
||||||
unsigned int SockPort;
|
|
||||||
FGfdmSocket* socket;
|
|
||||||
std::string data;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
|
@ -1,146 +0,0 @@
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
Module: FGUDPOutputSocket.cpp
|
|
||||||
Author: David Culp
|
|
||||||
Date started: 03/31/15
|
|
||||||
Purpose: Manage output of property values to a UDP socket
|
|
||||||
Called by: FGOutput
|
|
||||||
|
|
||||||
------------- Copyright (C) 2015 David Culp ----------------
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
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 Lesser General Public License for more
|
|
||||||
details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser 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 Lesser General Public License can also be found on
|
|
||||||
the world wide web at http://www.gnu.org.
|
|
||||||
|
|
||||||
FUNCTIONAL DESCRIPTION
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
This class sends comma-separated strings over a UDP socket. The format is that required
|
|
||||||
by the QtJSBSim application.
|
|
||||||
|
|
||||||
HISTORY
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
03/31/15 DC Created
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
INCLUDES
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#include <cstring>
|
|
||||||
#include <cstdlib>
|
|
||||||
|
|
||||||
#include "FGUDPOutputSocket.h"
|
|
||||||
#include "FGFDMExec.h"
|
|
||||||
#include "input_output/FGPropertyManager.h"
|
|
||||||
#include "input_output/FGXMLElement.h"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
namespace JSBSim {
|
|
||||||
|
|
||||||
IDENT(IdSrc,"$Id: FGUDPOutputSocket.cpp,v 1.2 2015/08/16 13:19:52 bcoconni Exp $");
|
|
||||||
IDENT(IdHdr,ID_UDPOUTPUTSOCKET);
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
CLASS IMPLEMENTATION
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
FGUDPOutputSocket::FGUDPOutputSocket(FGFDMExec* fdmex) :
|
|
||||||
FGOutputType(fdmex),
|
|
||||||
socket(0)
|
|
||||||
{
|
|
||||||
FDMExec = fdmex;
|
|
||||||
PropertyManager = fdmex->GetPropertyManager();
|
|
||||||
root = PropertyManager->GetNode();
|
|
||||||
root->SetDouble("simulation/null", 0.0);
|
|
||||||
SockName = "localhost";
|
|
||||||
SockPort = 5138;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
FGUDPOutputSocket::~FGUDPOutputSocket()
|
|
||||||
{
|
|
||||||
delete socket;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
bool FGUDPOutputSocket::Load(Element* el)
|
|
||||||
{
|
|
||||||
|
|
||||||
Element *property_element = el->FindElement("property");
|
|
||||||
|
|
||||||
while (property_element) {
|
|
||||||
string property_str = property_element->GetDataLine();
|
|
||||||
FGPropertyNode* node = PropertyManager->GetNode(property_str);
|
|
||||||
if (!node) {
|
|
||||||
node = PropertyManager->GetNode("simulation/null");
|
|
||||||
}
|
|
||||||
OutputProperties.push_back(node);
|
|
||||||
property_element = el->FindNextElement("property");
|
|
||||||
}
|
|
||||||
|
|
||||||
double outRate = 1.0;
|
|
||||||
if (!el->GetAttributeValue("rate").empty()) {
|
|
||||||
outRate = el->GetAttributeValueAsNumber("rate");
|
|
||||||
}
|
|
||||||
SetRateHz(outRate);
|
|
||||||
|
|
||||||
SockPort = atoi(el->GetAttributeValue("port").c_str());
|
|
||||||
if (SockPort == 0) {
|
|
||||||
cerr << endl << "No port assigned for output." << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
bool FGUDPOutputSocket::InitModel(void)
|
|
||||||
{
|
|
||||||
if (FGOutputType::InitModel()) {
|
|
||||||
delete socket;
|
|
||||||
socket = new FGfdmSocket(SockName, SockPort, FGfdmSocket::ptUDP);
|
|
||||||
|
|
||||||
if (socket == 0) return false;
|
|
||||||
if (!socket->GetConnectStatus()) return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
void FGUDPOutputSocket::Print(void)
|
|
||||||
{
|
|
||||||
|
|
||||||
if (socket == 0) return;
|
|
||||||
if (!socket->GetConnectStatus()) return;
|
|
||||||
|
|
||||||
socket->Clear();
|
|
||||||
socket->Append(FDMExec->GetSimTime());
|
|
||||||
|
|
||||||
for (unsigned int i=0;i<OutputProperties.size();i++) {
|
|
||||||
socket->Append(OutputProperties[i]->getDoubleValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
socket->Send();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,106 +0,0 @@
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
Header: FGOutputSocket.h
|
|
||||||
Author: David Culp
|
|
||||||
Date started: 03/31/15
|
|
||||||
|
|
||||||
------------- Copyright (C) 2015 David Culp ---------------
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU Lesser General Public License as published by the Free Software
|
|
||||||
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 Lesser General Public License for more
|
|
||||||
details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU Lesser 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 Lesser General Public License can also be found on
|
|
||||||
the world wide web at http://www.gnu.org.
|
|
||||||
|
|
||||||
HISTORY
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
03/31/15 DC Created
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
SENTRY
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#ifndef FGUDPOUTPUTSOCKET_H
|
|
||||||
#define FGUDPOUTPUTSOCKET_H
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
INCLUDES
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#include "FGOutputType.h"
|
|
||||||
#include "input_output/FGPropertyManager.h"
|
|
||||||
#include "input_output/FGfdmSocket.h"
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
DEFINITIONS
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#define ID_UDPOUTPUTSOCKET "$Id: FGUDPOutputSocket.h,v 1.1 2015/04/02 02:23:33 dpculp Exp $"
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
FORWARD DECLARATIONS
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
namespace JSBSim {
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
CLASS DOCUMENTATION
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
/** Implements the output to a UDP socket. This class outputs data to a socket
|
|
||||||
in a comma-separated strings format. The first string represents a time
|
|
||||||
stamp, and each string thereafter is the value of a property. If a
|
|
||||||
specified property does not exist, then a zero is sent, so that the
|
|
||||||
number of values sent will always equal the number of properties requested.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
CLASS DECLARATION
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
class FGUDPOutputSocket : public FGOutputType
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/** Constructor. */
|
|
||||||
FGUDPOutputSocket(FGFDMExec* fdmex);
|
|
||||||
|
|
||||||
/** Destructor. */
|
|
||||||
~FGUDPOutputSocket();
|
|
||||||
|
|
||||||
/** Init the output directives from an XML file.
|
|
||||||
@param element XML Element that is pointing to the output directives
|
|
||||||
*/
|
|
||||||
virtual bool Load(Element* el);
|
|
||||||
|
|
||||||
/** Initializes the instance. This method opens the ouput socket.
|
|
||||||
@result true if the execution succeeded.
|
|
||||||
*/
|
|
||||||
bool InitModel(void);
|
|
||||||
|
|
||||||
/// Generates and sends the output datagram.
|
|
||||||
void Print(void);
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
std::string SockName;
|
|
||||||
unsigned int SockPort;
|
|
||||||
FGfdmSocket* socket;
|
|
||||||
FGPropertyManager* PropertyManager;
|
|
||||||
FGPropertyNode* root;
|
|
||||||
FGFDMExec* FDMExec;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -131,46 +131,69 @@ FGfdmSocket::FGfdmSocket(const string& address, int port, int protocol)
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
// assumes UDP socket on localhost, for inbound datagrams
|
// assumes TCP or UDP socket on localhost, for inbound datagrams
|
||||||
FGfdmSocket::FGfdmSocket(int port, int protocol, int direction) // assumes UDP
|
FGfdmSocket::FGfdmSocket(int port, int protocol)
|
||||||
{
|
{
|
||||||
sckt = -1;
|
sckt = -1;
|
||||||
connected = false;
|
connected = false;
|
||||||
Protocol = (ProtocolType)protocol;
|
Protocol = (ProtocolType)protocol;
|
||||||
Direction = (DirectionType) direction;
|
string ProtocolName;
|
||||||
|
|
||||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
if (!LoadWinSockDLL()) return;
|
if (!LoadWinSockDLL()) return;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (Protocol == ptUDP) { //use udp protocol
|
if (Protocol == ptUDP) { //use udp protocol
|
||||||
|
ProtocolName = "UDP";
|
||||||
sckt = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
sckt = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
u_long NonBlock = 1; // True
|
u_long NonBlock = 1; // True
|
||||||
ioctlsocket(sckt, FIONBIO, &NonBlock);
|
ioctlsocket(sckt, FIONBIO, &NonBlock);
|
||||||
#else
|
#else
|
||||||
fcntl(sckt, F_SETFL, O_NONBLOCK);
|
fcntl(sckt, F_SETFL, O_NONBLOCK);
|
||||||
#endif
|
#endif
|
||||||
cout << "Creating UDP input socket on port " << port << endl;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
ProtocolName = "TCP";
|
||||||
|
sckt = socket(AF_INET, SOCK_STREAM, 0);
|
||||||
|
}
|
||||||
|
cout << "Creating input " << ProtocolName << " socket on port " << port << endl;
|
||||||
|
|
||||||
if (sckt != -1) {
|
if (sckt != -1) {
|
||||||
memset(&scktName, 0, sizeof(struct sockaddr_in));
|
memset(&scktName, 0, sizeof(struct sockaddr_in));
|
||||||
scktName.sin_family = AF_INET;
|
scktName.sin_family = AF_INET;
|
||||||
scktName.sin_port = htons(port);
|
scktName.sin_port = htons(port);
|
||||||
|
if (Protocol == ptUDP)
|
||||||
scktName.sin_addr.s_addr = htonl(INADDR_ANY);
|
scktName.sin_addr.s_addr = htonl(INADDR_ANY);
|
||||||
int len = sizeof(struct sockaddr_in);
|
int len = sizeof(struct sockaddr_in);
|
||||||
if (bind(sckt, (struct sockaddr*)&scktName, len) != -1) {
|
if (bind(sckt, (struct sockaddr*)&scktName, len) != -1) {
|
||||||
cout << "Successfully bound to UDP input socket on port " << port << endl <<endl;
|
cout << "Successfully bound to " << ProtocolName << " input socket on port "
|
||||||
|
<< port << endl <<endl;
|
||||||
|
if (Protocol == ptTCP) {
|
||||||
|
unsigned long NoBlock = true;
|
||||||
|
if (listen(sckt, 5) >= 0) { // successful listen()
|
||||||
|
#if 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
|
||||||
|
connected = true;
|
||||||
|
} else {
|
||||||
|
cerr << "Could not listen ..." << endl;
|
||||||
|
}
|
||||||
|
} else
|
||||||
connected = true;
|
connected = true;
|
||||||
} else { // unsuccessful
|
} else { // unsuccessful
|
||||||
cout << "Could not bind to UDP input socket, error = " << errno << endl;
|
cout << "Could not bind to " << ProtocolName << " input socket, error = "
|
||||||
}
|
<< errno << endl;
|
||||||
} else { // unsuccessful
|
|
||||||
cout << "Could not create socket for UDP input, error = " << errno << endl;
|
|
||||||
}
|
}
|
||||||
|
} else { // unsuccessful
|
||||||
|
cout << "Could not create " << ProtocolName << " socket for input, error = "
|
||||||
|
<< errno << endl;
|
||||||
|
}
|
||||||
|
|
||||||
Debug(0);
|
Debug(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,49 +248,6 @@ FGfdmSocket::FGfdmSocket(const string& address, int port) // assumes TCP
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
FGfdmSocket::FGfdmSocket(int port) // assumes TCP
|
|
||||||
{
|
|
||||||
connected = false;
|
|
||||||
unsigned long NoBlock = true;
|
|
||||||
Protocol = ptTCP;
|
|
||||||
|
|
||||||
#if defined(_MSC_VER) || defined(__MINGW32__)
|
|
||||||
if (!LoadWinSockDLL()) return;
|
|
||||||
#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);
|
|
||||||
int len = sizeof(struct sockaddr_in);
|
|
||||||
if (bind(sckt, (struct sockaddr*)&scktName, len) == 0) { // successful
|
|
||||||
cout << "Successfully bound to socket for input on port " << port << endl;
|
|
||||||
if (listen(sckt, 5) >= 0) { // successful listen()
|
|
||||||
#if 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 for input ..." << endl;
|
|
||||||
}
|
|
||||||
} else { // unsuccessful
|
|
||||||
cerr << "Could not create socket for FDM input, error = " << errno << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
Debug(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
FGfdmSocket::~FGfdmSocket()
|
FGfdmSocket::~FGfdmSocket()
|
||||||
{
|
{
|
||||||
if (sckt) shutdown(sckt,2);
|
if (sckt) shutdown(sckt,2);
|
||||||
|
|
|
@ -91,8 +91,7 @@ class FGfdmSocket : public FGJSBBase
|
||||||
public:
|
public:
|
||||||
FGfdmSocket(const std::string&, int);
|
FGfdmSocket(const std::string&, int);
|
||||||
FGfdmSocket(const std::string&, int, int);
|
FGfdmSocket(const std::string&, int, int);
|
||||||
FGfdmSocket(int, int, int);
|
FGfdmSocket(int, int);
|
||||||
FGfdmSocket(int);
|
|
||||||
~FGfdmSocket();
|
~FGfdmSocket();
|
||||||
void Send(void);
|
void Send(void);
|
||||||
void Send(const char *data, int length);
|
void Send(const char *data, int length);
|
||||||
|
@ -109,12 +108,10 @@ public:
|
||||||
bool GetConnectStatus(void) {return connected;}
|
bool GetConnectStatus(void) {return connected;}
|
||||||
|
|
||||||
enum ProtocolType {ptUDP, ptTCP};
|
enum ProtocolType {ptUDP, ptTCP};
|
||||||
enum DirectionType {dIN, dOUT};
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int sckt;
|
int sckt;
|
||||||
int sckt_in;
|
int sckt_in;
|
||||||
DirectionType Direction;
|
|
||||||
ProtocolType Protocol;
|
ProtocolType Protocol;
|
||||||
struct sockaddr_in scktName;
|
struct sockaddr_in scktName;
|
||||||
struct hostent *host;
|
struct hostent *host;
|
||||||
|
|
|
@ -33,6 +33,7 @@ INCLUDES
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
|
|
||||||
|
#include "simgear/misc/strutils.hxx"
|
||||||
#include "FGFunction.h"
|
#include "FGFunction.h"
|
||||||
#include "FGTable.h"
|
#include "FGTable.h"
|
||||||
#include "FGPropertyValue.h"
|
#include "FGPropertyValue.h"
|
||||||
|
@ -50,6 +51,8 @@ IDENT(IdHdr,ID_FUNCTION);
|
||||||
CLASS IMPLEMENTATION
|
CLASS IMPLEMENTATION
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
const double FGFunction::invlog2val = 1.0/log10(2.0);
|
||||||
|
|
||||||
const std::string FGFunction::property_string = "property";
|
const std::string FGFunction::property_string = "property";
|
||||||
const std::string FGFunction::value_string = "value";
|
const std::string FGFunction::value_string = "value";
|
||||||
const std::string FGFunction::table_string = "table";
|
const std::string FGFunction::table_string = "table";
|
||||||
|
@ -108,21 +111,21 @@ const std::string FGFunction::ifthen_string = "ifthen";
|
||||||
const std::string FGFunction::switch_string = "switch";
|
const std::string FGFunction::switch_string = "switch";
|
||||||
const std::string FGFunction::interpolate1d_string = "interpolate1d";
|
const std::string FGFunction::interpolate1d_string = "interpolate1d";
|
||||||
|
|
||||||
FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& prefix)
|
FGFunction::FGFunction(FGPropertyManager* PropertyManager, Element* el,
|
||||||
: PropertyManager(propMan), Prefix(prefix)
|
const string& prefix, FGPropertyValue* var)
|
||||||
|
: Prefix(prefix), cached(false), cachedValue(-HUGE_VAL), pCopyTo(0L)
|
||||||
{
|
{
|
||||||
Element* element;
|
Load(PropertyManager, el, var);
|
||||||
string operation, property_name;
|
}
|
||||||
cached = false;
|
|
||||||
cachedValue = -HUGE_VAL;
|
|
||||||
invlog2val = 1.0/log10(2.0);
|
|
||||||
pCopyTo = 0L;
|
|
||||||
|
|
||||||
|
void FGFunction::Load(FGPropertyManager* PropertyManager, Element* el,
|
||||||
|
FGPropertyValue* var)
|
||||||
|
{
|
||||||
Name = el->GetAttributeValue("name");
|
Name = el->GetAttributeValue("name");
|
||||||
operation = el->GetName();
|
string operation = el->GetName();
|
||||||
|
|
||||||
if (operation == function_string) {
|
if (operation == function_string) {
|
||||||
sCopyTo = el->GetAttributeValue("copyto");
|
string sCopyTo = el->GetAttributeValue("copyto");
|
||||||
if (!sCopyTo.empty()) {
|
if (!sCopyTo.empty()) {
|
||||||
|
|
||||||
if (sCopyTo.find("#") != string::npos) {
|
if (sCopyTo.find("#") != string::npos) {
|
||||||
|
@ -232,7 +235,7 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
|
||||||
cerr << "Bad operation " << operation << " detected in configuration file" << endl;
|
cerr << "Bad operation " << operation << " detected in configuration file" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
element = el->GetElement();
|
Element* element = el->GetElement();
|
||||||
if (!element && Type != eRandom && Type != eUrandom && Type != ePi) {
|
if (!element && Type != eRandom && Type != eUrandom && Type != ePi) {
|
||||||
cerr << fgred << highint << endl;
|
cerr << fgred << highint << endl;
|
||||||
cerr << " No element was specified as an argument to the \"" << operation << "\" operation" << endl;
|
cerr << " No element was specified as an argument to the \"" << operation << "\" operation" << endl;
|
||||||
|
@ -248,26 +251,36 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
|
||||||
|
|
||||||
// data types
|
// data types
|
||||||
if (operation == property_string || operation == p_string) {
|
if (operation == property_string || operation == p_string) {
|
||||||
property_name = element->GetDataLine();
|
string property_name = element->GetDataLine();
|
||||||
if (property_name.find("#") != string::npos) {
|
|
||||||
if (is_number(Prefix)) {
|
if (var && simgear::strutils::strip(property_name) == "#")
|
||||||
property_name = replace(property_name,"#",Prefix);
|
Parameters.push_back(var);
|
||||||
|
else {
|
||||||
|
if (property_name.find("#") != string::npos) {
|
||||||
|
if (is_number(Prefix)) {
|
||||||
|
property_name = replace(property_name,"#",Prefix);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
cerr << el->ReadFrom()
|
||||||
|
<< fgred << "Illegal use of the special character '#'"
|
||||||
|
<< reset << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (PropertyManager->HasNode(property_name)) {
|
||||||
|
FGPropertyNode* newNode = PropertyManager->GetNode(property_name);
|
||||||
|
Parameters.push_back(new FGPropertyValue( newNode ));
|
||||||
|
} else {
|
||||||
|
// cerr << fgcyan << "Warning: The property " + property_name + " is initially undefined."
|
||||||
|
// << reset << endl;
|
||||||
|
Parameters.push_back(new FGPropertyValue( property_name,
|
||||||
|
PropertyManager ));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (PropertyManager->HasNode(property_name)) {
|
|
||||||
FGPropertyNode* newNode = PropertyManager->GetNode(property_name);
|
|
||||||
Parameters.push_back(new FGPropertyValue( newNode ));
|
|
||||||
} else {
|
|
||||||
// cerr << fgcyan << "Warning: The property " + property_name + " is initially undefined."
|
|
||||||
// << reset << endl;
|
|
||||||
Parameters.push_back(new FGPropertyValue( property_name,
|
|
||||||
PropertyManager ));
|
|
||||||
}
|
}
|
||||||
} else if (operation == value_string || operation == v_string) {
|
} else if (operation == value_string || operation == v_string) {
|
||||||
Parameters.push_back(new FGRealValue(element->GetDataAsNumber()));
|
Parameters.push_back(new FGRealValue(element->GetDataAsNumber()));
|
||||||
} else if (operation == table_string || operation == t_string) {
|
} else if (operation == table_string || operation == t_string) {
|
||||||
Parameters.push_back(new FGTable(PropertyManager, element, Prefix));
|
Parameters.push_back(new FGTable(PropertyManager, element, Prefix));
|
||||||
// operations
|
// operations
|
||||||
} else if (operation == product_string ||
|
} else if (operation == product_string ||
|
||||||
operation == difference_string ||
|
operation == difference_string ||
|
||||||
operation == sum_string ||
|
operation == sum_string ||
|
||||||
|
@ -315,28 +328,21 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, const string& pr
|
||||||
operation == ifthen_string ||
|
operation == ifthen_string ||
|
||||||
operation == switch_string ||
|
operation == switch_string ||
|
||||||
operation == interpolate1d_string)
|
operation == interpolate1d_string)
|
||||||
{
|
{
|
||||||
Parameters.push_back(new FGFunction(PropertyManager, element, Prefix));
|
Parameters.push_back(new FGFunction(PropertyManager, element, Prefix, var));
|
||||||
} else if (operation != description_string) {
|
} else if (operation != description_string) {
|
||||||
cerr << "Bad operation " << operation << " detected in configuration file" << endl;
|
cerr << "Bad operation " << operation << " detected in configuration file" << endl;
|
||||||
}
|
}
|
||||||
element = el->GetNextElement();
|
element = el->GetNextElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
bind(el); // Allow any function to save its value
|
bind(el, PropertyManager); // Allow any function to save its value
|
||||||
|
|
||||||
Debug(0);
|
Debug(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
FGFunction::~FGFunction(void)
|
|
||||||
{
|
|
||||||
for (unsigned int i=0; i<Parameters.size(); i++) delete Parameters[i];
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
void FGFunction::cacheValue(bool cache)
|
void FGFunction::cacheValue(bool cache)
|
||||||
{
|
{
|
||||||
cached = false; // Must set cached to false prior to calling GetValue(), else
|
cached = false; // Must set cached to false prior to calling GetValue(), else
|
||||||
|
@ -784,7 +790,7 @@ string FGFunction::GetValueAsString(void) const
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
void FGFunction::bind(Element* el)
|
void FGFunction::bind(Element* el, FGPropertyManager* PropertyManager)
|
||||||
{
|
{
|
||||||
if ( !Name.empty() ) {
|
if ( !Name.empty() ) {
|
||||||
string tmp;
|
string tmp;
|
||||||
|
|
|
@ -52,6 +52,7 @@ FORWARD DECLARATIONS
|
||||||
namespace JSBSim {
|
namespace JSBSim {
|
||||||
|
|
||||||
class Element;
|
class Element;
|
||||||
|
class FGPropertyValue;
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
CLASS DOCUMENTATION
|
CLASS DOCUMENTATION
|
||||||
|
@ -696,28 +697,32 @@ DECLARATION: FGFunction
|
||||||
|
|
||||||
// Todo: Does this class need a copy constructor, like FGLGear?
|
// Todo: Does this class need a copy constructor, like FGLGear?
|
||||||
|
|
||||||
class FGFunction : public FGParameter
|
class FGFunction : public FGParameter, public FGJSBBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/// Default constructor.
|
||||||
|
FGFunction()
|
||||||
|
: cached(false), cachedValue(-HUGE_VAL), pCopyTo(0L) {}
|
||||||
|
|
||||||
/** Constructor.
|
/** Constructor.
|
||||||
When this constructor is called, the XML element pointed to in memory by the
|
When this constructor is called, the XML element pointed to in memory by the
|
||||||
element argument is traversed. If other FGParameter-derived objects (values,
|
element argument is traversed. If other FGParameter-derived objects (values,
|
||||||
functions, properties, or tables) are encountered, this instance of the
|
functions, properties, or tables) are encountered, this instance of the
|
||||||
FGFunction object will store a pointer to the found object and pass the relevant
|
FGFunction object will store a pointer to the found object and pass the
|
||||||
Element pointer to the constructor for the new object. In other words, each
|
relevant Element pointer to the constructor for the new object. In other
|
||||||
FGFunction object maintains a list of "child" FGParameter-derived objects which
|
words, each FGFunction object maintains a list of "child"
|
||||||
in turn may each contain its own list, and so on. At runtime, each object
|
FGParameter-derived objects which in turn may each contain its own list, and
|
||||||
evaluates its child parameters, which each may have its own child parameters to
|
so on. At runtime, each object evaluates its child parameters, which each
|
||||||
evaluate.
|
may have its own child parameters to evaluate.
|
||||||
|
|
||||||
@param PropertyManager a pointer to the property manager instance.
|
@param PropertyManager a pointer to the property manager instance.
|
||||||
@param element a pointer to the Element object containing the function definition.
|
@param element a pointer to the Element object containing the function
|
||||||
@param prefix an optional prefix to prepend to the name given to the property
|
definition.
|
||||||
that represents this function (if given).
|
@param prefix an optional prefix to prepend to the name given to the
|
||||||
|
property that represents this function (if given).
|
||||||
*/
|
*/
|
||||||
FGFunction(FGPropertyManager* PropertyManager, Element* element, const std::string& prefix="");
|
FGFunction(FGPropertyManager* PropertyManager, Element* element,
|
||||||
/// Destructor.
|
const std::string& prefix="", FGPropertyValue* var=0L);
|
||||||
virtual ~FGFunction();
|
|
||||||
|
|
||||||
/** Retrieves the value of the function object.
|
/** Retrieves the value of the function object.
|
||||||
@return the total value of the function. */
|
@return the total value of the function. */
|
||||||
|
@ -738,12 +743,13 @@ public:
|
||||||
@param shouldCache specifies whether the function should cache the computed value. */
|
@param shouldCache specifies whether the function should cache the computed value. */
|
||||||
void cacheValue(bool shouldCache);
|
void cacheValue(bool shouldCache);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void Load(FGPropertyManager* PropertyManager, Element* element,
|
||||||
|
FGPropertyValue* var);
|
||||||
|
virtual void bind(Element*, FGPropertyManager*);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector <FGParameter*> Parameters;
|
static const double invlog2val;
|
||||||
FGPropertyManager* const PropertyManager;
|
|
||||||
bool cached;
|
|
||||||
double invlog2val;
|
|
||||||
std::string Prefix;
|
|
||||||
static const std::string description_string;
|
static const std::string description_string;
|
||||||
static const std::string property_string;
|
static const std::string property_string;
|
||||||
static const std::string value_string;
|
static const std::string value_string;
|
||||||
|
@ -799,7 +805,7 @@ private:
|
||||||
static const std::string ifthen_string;
|
static const std::string ifthen_string;
|
||||||
static const std::string switch_string;
|
static const std::string switch_string;
|
||||||
static const std::string interpolate1d_string;
|
static const std::string interpolate1d_string;
|
||||||
double cachedValue;
|
|
||||||
enum functionType {eTopLevel=0, eProduct, eDifference, eSum, eQuotient, ePow, eSqrt, eToRadians,
|
enum functionType {eTopLevel=0, eProduct, eDifference, eSum, eQuotient, ePow, eSqrt, eToRadians,
|
||||||
eToDegrees, eExp, eAbs, eSign, eSin, eCos, eTan, eASin, eACos, eATan, eATan2,
|
eToDegrees, eExp, eAbs, eSign, eSin, eCos, eTan, eASin, eACos, eATan, eATan2,
|
||||||
eMin, eMax, eAvg, eFrac, eInteger, eMod, eRandom, eUrandom, ePi,
|
eMin, eMax, eAvg, eFrac, eInteger, eMod, eRandom, eUrandom, ePi,
|
||||||
|
@ -807,12 +813,14 @@ private:
|
||||||
eIfThen, eSwitch, eInterpolate1D, eRotation_alpha_local,
|
eIfThen, eSwitch, eInterpolate1D, eRotation_alpha_local,
|
||||||
eRotation_beta_local, eRotation_gamma_local, eRotation_bf_to_wf,
|
eRotation_beta_local, eRotation_gamma_local, eRotation_bf_to_wf,
|
||||||
eRotation_wf_to_bf} Type;
|
eRotation_wf_to_bf} Type;
|
||||||
|
std::string Prefix;
|
||||||
|
bool cached;
|
||||||
|
double cachedValue;
|
||||||
std::string Name;
|
std::string Name;
|
||||||
std::string sCopyTo; // Property name to copy function value to
|
std::vector <FGParameter_ptr> Parameters;
|
||||||
FGPropertyNode_ptr pCopyTo; // Property node for CopyTo property string
|
FGPropertyNode_ptr pCopyTo; // Property node for CopyTo property string
|
||||||
|
|
||||||
unsigned int GetBinary(double) const;
|
unsigned int GetBinary(double) const;
|
||||||
void bind(Element*);
|
|
||||||
void Debug(int from);
|
void Debug(int from);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
85
src/FDM/JSBSim/math/FGFunctionValue.h
Normal file
85
src/FDM/JSBSim/math/FGFunctionValue.h
Normal file
|
@ -0,0 +1,85 @@
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
Header: FGFunctionValue.h
|
||||||
|
Author: Bertrand Coconnier
|
||||||
|
Date started: March 10 2018
|
||||||
|
|
||||||
|
--------- Copyright (C) 2018 B. Coconnier (bcoconni@users.sf.net) -----------
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU Lesser General Public License as published by the Free
|
||||||
|
Software 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 Lesser General Public License for more
|
||||||
|
details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser 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 Lesser General Public License can also be
|
||||||
|
found on the world wide web at http://www.gnu.org.
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
SENTRY
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#ifndef FGFUNCTIONVALUE_H
|
||||||
|
#define FGFUNCTIONVALUE_H
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
INCLUDES
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#include "math/FGPropertyValue.h"
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
FORWARD DECLARATIONS
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
namespace JSBSim {
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
CLASS DOCUMENTATION
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
/** Represents a property value on which a function is applied
|
||||||
|
@author Bertrand Coconnier
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
DECLARATION: FGFunctionValue
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
class FGFunctionValue : public FGPropertyValue
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
FGFunctionValue(FGPropertyNode* propNode, FGTemplateFunc* f)
|
||||||
|
:FGPropertyValue(propNode), function(f) {}
|
||||||
|
FGFunctionValue(std::string propName, FGPropertyManager* propertyManager,
|
||||||
|
FGTemplateFunc* f)
|
||||||
|
:FGPropertyValue(propName, propertyManager), function(f) {}
|
||||||
|
|
||||||
|
double GetValue(void) const { return function->GetValue(GetNode()); }
|
||||||
|
|
||||||
|
std::string GetName(void) const {
|
||||||
|
return function->GetName() + "(" + FGPropertyValue::GetName() + ")";
|
||||||
|
}
|
||||||
|
std::string GetPrintableName(void) const {
|
||||||
|
return function->GetName() + "(" + FGPropertyValue::GetPrintableName() + ")";
|
||||||
|
}
|
||||||
|
std::string GetFullyQualifiedName(void) const {
|
||||||
|
return function->GetName() + "(" + FGPropertyValue::GetFullyQualifiedName() + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
FGTemplateFunc_ptr function;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace JSBSim
|
||||||
|
|
||||||
|
#endif
|
|
@ -34,7 +34,8 @@ SENTRY
|
||||||
INCLUDES
|
INCLUDES
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
#include "FGJSBBase.h"
|
#include <string>
|
||||||
|
#include "simgear/structure/SGSharedPtr.hxx"
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
DEFINITIONS
|
DEFINITIONS
|
||||||
|
@ -60,7 +61,7 @@ CLASS DOCUMENTATION
|
||||||
DECLARATION: FGParameter
|
DECLARATION: FGParameter
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
class FGParameter : public FGJSBBase
|
class FGParameter : public SGReferenced
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~FGParameter(void) {};
|
virtual ~FGParameter(void) {};
|
||||||
|
@ -73,6 +74,8 @@ public:
|
||||||
protected:
|
protected:
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef SGSharedPtr<FGParameter> FGParameter_ptr;
|
||||||
|
|
||||||
} // namespace JSBSim
|
} // namespace JSBSim
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -62,7 +62,7 @@ FGPropertyValue::FGPropertyValue(std::string propName, FGPropertyManager* proper
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
double FGPropertyValue::GetValue(void) const
|
FGPropertyNode* FGPropertyValue::GetNode(void) const
|
||||||
{
|
{
|
||||||
FGPropertyNode* node = PropertyNode;
|
FGPropertyNode* node = PropertyNode;
|
||||||
|
|
||||||
|
@ -76,18 +76,45 @@ double FGPropertyValue::GetValue(void) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return node->getDoubleValue()*Sign;
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
double FGPropertyValue::GetValue(void) const
|
||||||
|
{
|
||||||
|
|
||||||
|
return GetNode()->getDoubleValue()*Sign;
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
std::string FGPropertyValue::GetName(void) const
|
std::string FGPropertyValue::GetName(void) const
|
||||||
{
|
{
|
||||||
if (PropertyNode) {
|
if (PropertyNode)
|
||||||
return PropertyNode->GetName();
|
return PropertyNode->GetName();
|
||||||
} else {
|
else
|
||||||
return PropertyName;
|
return PropertyName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
std::string FGPropertyValue::GetFullyQualifiedName(void) const
|
||||||
|
{
|
||||||
|
if (PropertyNode)
|
||||||
|
return PropertyNode->GetFullyQualifiedName();
|
||||||
|
else
|
||||||
|
return PropertyName;
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
std::string FGPropertyValue::GetPrintableName(void) const
|
||||||
|
{
|
||||||
|
if (PropertyNode)
|
||||||
|
return PropertyNode->GetPrintableName();
|
||||||
|
else
|
||||||
|
return PropertyName;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,12 +68,16 @@ public:
|
||||||
|
|
||||||
FGPropertyValue(FGPropertyNode* propNode);
|
FGPropertyValue(FGPropertyNode* propNode);
|
||||||
FGPropertyValue(std::string propName, FGPropertyManager* propertyManager);
|
FGPropertyValue(std::string propName, FGPropertyManager* propertyManager);
|
||||||
~FGPropertyValue() {};
|
|
||||||
|
|
||||||
double GetValue(void) const;
|
virtual double GetValue(void) const;
|
||||||
void SetNode(FGPropertyNode* node) {PropertyNode = node;}
|
void SetNode(FGPropertyNode* node) {PropertyNode = node;}
|
||||||
|
|
||||||
std::string GetName(void) const;
|
virtual std::string GetName(void) const;
|
||||||
|
virtual std::string GetFullyQualifiedName(void) const;
|
||||||
|
virtual std::string GetPrintableName(void) const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
FGPropertyNode* GetNode(void) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FGPropertyManager* PropertyManager; // Property root used to do late binding.
|
FGPropertyManager* PropertyManager; // Property root used to do late binding.
|
||||||
|
|
|
@ -29,7 +29,7 @@ INCLUDES
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
#include "FGRealValue.h"
|
#include "FGRealValue.h"
|
||||||
|
#include "FGJSBBase.h"
|
||||||
#include "input_output/string_utilities.h"
|
#include "input_output/string_utilities.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
|
@ -240,7 +240,7 @@ combustion_efficiency = Lookup_Combustion_Efficiency->GetValue(equivalence_ratio
|
||||||
CLASS DECLARATION
|
CLASS DECLARATION
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
class FGTable : public FGParameter
|
class FGTable : public FGParameter, public FGJSBBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Destructor
|
/// Destructor
|
||||||
|
|
86
src/FDM/JSBSim/math/FGTemplateFunc.h
Normal file
86
src/FDM/JSBSim/math/FGTemplateFunc.h
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
Header: FGTemplateFunc.h
|
||||||
|
Author: Bertrand Coconnier
|
||||||
|
Date started: March 10 2018
|
||||||
|
|
||||||
|
--------- Copyright (C) 2018 B. Coconnier (bcoconni@users.sf.net) -----------
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU Lesser General Public License as published by the Free
|
||||||
|
Software 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 Lesser General Public License for more
|
||||||
|
details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser 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 Lesser General Public License can also be
|
||||||
|
found on the world wide web at http://www.gnu.org.
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
SENTRY
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#ifndef FGTEMPLATEFUNC_H
|
||||||
|
#define FGTEMPLATEFUNC_H
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
INCLUDES
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#include "math/FGFunction.h"
|
||||||
|
#include "math/FGPropertyValue.h"
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
FORWARD DECLARATIONS
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
namespace JSBSim {
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
CLASS DOCUMENTATION
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
DECLARATION: FGTemplateFunc
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
class FGTemplateFunc : public FGFunction
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
FGTemplateFunc(FGPropertyManager* PropertyManager, Element* element)
|
||||||
|
: var(0L)
|
||||||
|
{
|
||||||
|
Load(PropertyManager, element, &var);
|
||||||
|
// Since 'var' is a member of FGTemplateFunc, we don't want SGSharedPtr to
|
||||||
|
// destroy 'var' when it would no longer be referenced by any shared
|
||||||
|
// pointers. In order to avoid this, the reference counter is increased an
|
||||||
|
// extra time to make sure that it never reaches 0 when all shared pointers
|
||||||
|
// referencing 'var' are destroyed.
|
||||||
|
get(&var);
|
||||||
|
}
|
||||||
|
|
||||||
|
double GetValue(FGPropertyNode* node) {
|
||||||
|
var.SetNode(node);
|
||||||
|
return FGFunction::GetValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** FGTemplateFunc must not be bound to the property manager. The bind method
|
||||||
|
is therefore overloaded as a no-op */
|
||||||
|
virtual void bind(Element*, FGPropertyManager*) {}
|
||||||
|
FGPropertyValue var;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef SGSharedPtr<FGTemplateFunc> FGTemplateFunc_ptr;
|
||||||
|
|
||||||
|
} // namespace JSBSim
|
||||||
|
|
||||||
|
#endif
|
|
@ -76,7 +76,8 @@ FGAerodynamics::FGAerodynamics(FGFDMExec* FDMExec) : FGModel(FDMExec)
|
||||||
AxisIdx["Y"] = 1;
|
AxisIdx["Y"] = 1;
|
||||||
AxisIdx["Z"] = 2;
|
AxisIdx["Z"] = 2;
|
||||||
|
|
||||||
axisType = atNone;
|
forceAxisType = atNone;
|
||||||
|
momentAxisType = atNone;
|
||||||
|
|
||||||
AeroFunctions = new AeroFunctionArray[6];
|
AeroFunctions = new AeroFunctionArray[6];
|
||||||
AeroFunctionsAtCG = new AeroFunctionArray[6];
|
AeroFunctionsAtCG = new AeroFunctionArray[6];
|
||||||
|
@ -154,7 +155,7 @@ bool FGAerodynamics::Run(bool Holding)
|
||||||
// Skip the computation if qbar is close to zero to avoid huge values for
|
// Skip the computation if qbar is close to zero to avoid huge values for
|
||||||
// aero/cl-squared when a non-null lift coincides with a very small aero
|
// aero/cl-squared when a non-null lift coincides with a very small aero
|
||||||
// velocity (i.e. when qbar is close to zero).
|
// velocity (i.e. when qbar is close to zero).
|
||||||
clsq = (vFw(eLift) + vFwAtCG(eLift))/ (in.Wingarea*in.Qbar);
|
clsq = vFw(eLift) / (in.Wingarea*in.Qbar);
|
||||||
clsq *= clsq;
|
clsq *= clsq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -179,17 +180,18 @@ bool FGAerodynamics::Run(bool Holding)
|
||||||
|
|
||||||
if (alphahystmax != 0.0 && alphahystmin != 0.0) {
|
if (alphahystmax != 0.0 && alphahystmin != 0.0) {
|
||||||
if (in.Alpha > alphahystmax) {
|
if (in.Alpha > alphahystmax) {
|
||||||
stall_hyst = 1;
|
stall_hyst = 1;
|
||||||
} else if (in.Alpha < alphahystmin) {
|
} else if (in.Alpha < alphahystmin) {
|
||||||
stall_hyst = 0;
|
stall_hyst = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
vFw.InitMatrix();
|
vFw.InitMatrix();
|
||||||
vFwAtCG.InitMatrix();
|
|
||||||
vFnative.InitMatrix();
|
vFnative.InitMatrix();
|
||||||
vFnativeAtCG.InitMatrix();
|
vFnativeAtCG.InitMatrix();
|
||||||
|
|
||||||
|
BuildStabilityTransformMatrices();
|
||||||
|
|
||||||
for (axis_ctr = 0; axis_ctr < 3; ++axis_ctr) {
|
for (axis_ctr = 0; axis_ctr < 3; ++axis_ctr) {
|
||||||
AeroFunctionArray::iterator f;
|
AeroFunctionArray::iterator f;
|
||||||
|
|
||||||
|
@ -210,68 +212,46 @@ bool FGAerodynamics::Run(bool Holding)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note that we still need to convert to wind axes here, because it is
|
switch (forceAxisType) {
|
||||||
// used in the L/D calculation, and we still may want to look at Lift
|
case atBodyXYZ: // Forces already in body axes; no manipulation needed
|
||||||
// and Drag.
|
vForces = vFnative;
|
||||||
|
vForcesAtCG = vFnativeAtCG;
|
||||||
|
break;
|
||||||
|
case atWind: // Copy forces into wind axes
|
||||||
|
vFnative(eDrag)*=-1; vFnative(eLift)*=-1;
|
||||||
|
vForces = in.Tw2b*vFnative;
|
||||||
|
|
||||||
// JSB 4/27/12 - After use, convert wind axes to produce normal lift
|
vFnativeAtCG(eDrag)*=-1; vFnativeAtCG(eLift)*=-1;
|
||||||
// and drag values - not negative ones!
|
vForcesAtCG = in.Tw2b*vFnativeAtCG;
|
||||||
|
break;
|
||||||
|
case atBodyAxialNormal: // Convert native forces into Axial|Normal|Side system
|
||||||
|
vFnative(eX)*=-1; vFnative(eZ)*=-1;
|
||||||
|
vForces = vFnative;
|
||||||
|
|
||||||
// As a clarification, JSBSim assumes that drag and lift values are defined
|
vFnativeAtCG(eX)*=-1; vFnativeAtCG(eZ)*=-1;
|
||||||
// in wind axes - BUT with a 180 rotation about the Y axis. That is, lift and
|
vForcesAtCG = vFnativeAtCG;
|
||||||
// drag will be positive up and aft, respectively, so that they are reported
|
break;
|
||||||
// as positive numbers. However, the wind axes themselves assume that the X
|
case atStability: // Convert from stability axes to both body and wind axes
|
||||||
// and Z forces are positive forward and down.
|
vFnative(eDrag) *= -1; vFnative(eLift) *= -1;
|
||||||
|
vForces = Ts2b*vFnative;
|
||||||
|
|
||||||
switch (axisType) {
|
vFnativeAtCG(eDrag) *= -1; vFnativeAtCG(eLift) *= -1;
|
||||||
case atBodyXYZ: // Forces already in body axes; no manipulation needed
|
vForcesAtCG = Ts2b*vFnativeAtCG;
|
||||||
vFw = in.Tb2w*vFnative;
|
break;
|
||||||
vForces = vFnative;
|
default:
|
||||||
vFw(eDrag)*=-1; vFw(eLift)*=-1;
|
cerr << endl << " A proper axis type has NOT been selected. Check "
|
||||||
|
<< "your aerodynamics definition." << endl;
|
||||||
vFwAtCG = in.Tb2w*vFnativeAtCG;
|
exit(-1);
|
||||||
vForcesAtCG = vFnativeAtCG;
|
|
||||||
vFwAtCG(eDrag)*=-1; vFwAtCG(eLift)*=-1;
|
|
||||||
break;
|
|
||||||
case atLiftDrag: // Copy forces into wind axes
|
|
||||||
vFw = vFnative;
|
|
||||||
vFw(eDrag)*=-1; vFw(eLift)*=-1;
|
|
||||||
vForces = in.Tw2b*vFw;
|
|
||||||
vFw(eDrag)*=-1; vFw(eLift)*=-1;
|
|
||||||
|
|
||||||
vFwAtCG = vFnativeAtCG;
|
|
||||||
vFwAtCG(eDrag)*=-1; vFwAtCG(eLift)*=-1;
|
|
||||||
vForcesAtCG = in.Tw2b*vFwAtCG;
|
|
||||||
vFwAtCG(eDrag)*=-1; vFwAtCG(eLift)*=-1;
|
|
||||||
break;
|
|
||||||
case atAxialNormal: // Convert native forces into Axial|Normal|Side system
|
|
||||||
vFw = in.Tb2w*vFnative;
|
|
||||||
vFnative(eX)*=-1; vFnative(eZ)*=-1;
|
|
||||||
vForces = vFnative;
|
|
||||||
|
|
||||||
vFwAtCG = in.Tb2w*vFnativeAtCG;
|
|
||||||
vFnativeAtCG(eX)*=-1; vFnativeAtCG(eZ)*=-1;
|
|
||||||
vForcesAtCG = vFnativeAtCG;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cerr << endl << " A proper axis type has NOT been selected. Check "
|
|
||||||
<< "your aerodynamics definition." << endl;
|
|
||||||
exit(-1);
|
|
||||||
}
|
}
|
||||||
|
// Calculate aerodynamic reference point shift, if any. The shift takes place
|
||||||
// Calculate lift Lift over Drag
|
// in the structual axis. That is, if the shift is positive, it is towards the
|
||||||
if ( fabs(vFw(eDrag) + vFwAtCG(eDrag)) > 0.0)
|
// back (tail) of the vehicle. The AeroRPShift function should be
|
||||||
lod = fabs( (vFw(eLift) + vFwAtCG(eLift))/ (vFw(eDrag) + vFwAtCG(eDrag)));
|
// non-dimensionalized by the wing chord. The calculated vDeltaRP will be in
|
||||||
|
// feet.
|
||||||
// Calculate aerodynamic reference point shift, if any. The shift
|
|
||||||
// takes place in the structual axis. That is, if the shift is positive,
|
|
||||||
// it is towards the back (tail) of the vehicle. The AeroRPShift
|
|
||||||
// function should be non-dimensionalized by the wing chord. The
|
|
||||||
// calculated vDeltaRP will be in feet.
|
|
||||||
if (AeroRPShift) vDeltaRP(eX) = AeroRPShift->GetValue()*in.Wingchord;
|
if (AeroRPShift) vDeltaRP(eX) = AeroRPShift->GetValue()*in.Wingchord;
|
||||||
|
|
||||||
vDXYZcg(eX) = in.RPBody(eX) - vDeltaRP(eX); // vDeltaRP is given in the structural frame
|
vDXYZcg(eX) = in.RPBody(eX) - vDeltaRP(eX); // vDeltaRP is given in the
|
||||||
vDXYZcg(eY) = in.RPBody(eY) + vDeltaRP(eY);
|
vDXYZcg(eY) = in.RPBody(eY) + vDeltaRP(eY); // structural frame.
|
||||||
vDXYZcg(eZ) = in.RPBody(eZ) - vDeltaRP(eZ);
|
vDXYZcg(eZ) = in.RPBody(eZ) - vDeltaRP(eZ);
|
||||||
|
|
||||||
vMomentsMRC.InitMatrix();
|
vMomentsMRC.InitMatrix();
|
||||||
|
@ -287,11 +267,50 @@ bool FGAerodynamics::Run(bool Holding)
|
||||||
vMomentsMRC(axis_ctr+1) += (*f)->GetValue();
|
vMomentsMRC(axis_ctr+1) += (*f)->GetValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vMoments = vMomentsMRC + vDXYZcg*vForces; // M = r X F
|
|
||||||
// Now add the "at CG" values to base forces - after the moments have been transferred
|
// Transform moments to bodyXYZ if the moments are specified in stability or
|
||||||
|
// wind axes
|
||||||
|
vMomentsMRCBodyXYZ.InitMatrix();
|
||||||
|
switch (momentAxisType) {
|
||||||
|
case atBodyXYZ:
|
||||||
|
vMomentsMRCBodyXYZ = vMomentsMRC;
|
||||||
|
break;
|
||||||
|
case atStability:
|
||||||
|
vMomentsMRCBodyXYZ = Ts2b*vMomentsMRC;
|
||||||
|
break;
|
||||||
|
case atWind:
|
||||||
|
vMomentsMRCBodyXYZ = in.Tw2b*vMomentsMRC;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
cerr << endl << " A proper axis type has NOT been selected. Check "
|
||||||
|
<< "your aerodynamics definition." << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
vMoments = vMomentsMRCBodyXYZ + vDXYZcg*vForces; // M = r X F
|
||||||
|
|
||||||
|
// Now add the "at CG" values to base forces - after the moments have been
|
||||||
|
// transferred.
|
||||||
vForces += vForcesAtCG;
|
vForces += vForcesAtCG;
|
||||||
vFnative += vFnativeAtCG;
|
|
||||||
vFw += vFwAtCG;
|
// Note that we still need to convert to wind axes here, because it is used in
|
||||||
|
// the L/D calculation, and we still may want to look at Lift and Drag.
|
||||||
|
//
|
||||||
|
// JSB 4/27/12 - After use, convert wind axes to produce normal lift and drag
|
||||||
|
// values - not negative ones!
|
||||||
|
//
|
||||||
|
// As a clarification, JSBSim assumes that drag and lift values are defined in
|
||||||
|
// wind axes - BUT with a 180 rotation about the Y axis. That is, lift and
|
||||||
|
// drag will be positive up and aft, respectively, so that they are reported
|
||||||
|
// as positive numbers. However, the wind axes themselves assume that the X
|
||||||
|
// and Z forces are positive forward and down. Same applies to the stability
|
||||||
|
// axes.
|
||||||
|
vFw = in.Tb2w * vForces;
|
||||||
|
vFw(eDrag) *= -1; vFw(eLift) *= -1;
|
||||||
|
|
||||||
|
// Calculate Lift over Drag
|
||||||
|
if ( fabs(vFw(eDrag)) > 0.0)
|
||||||
|
lod = fabs( vFw(eLift) / vFw(eDrag));
|
||||||
|
|
||||||
RunPostFunctions();
|
RunPostFunctions();
|
||||||
|
|
||||||
|
@ -300,6 +319,17 @@ bool FGAerodynamics::Run(bool Holding)
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
FGColumnVector3 FGAerodynamics::GetForcesInStabilityAxes(void) const
|
||||||
|
{
|
||||||
|
FGColumnVector3 vFs = Tb2s*vForces;
|
||||||
|
// Need sign flips since drag is positive and lift is positive in stability axes
|
||||||
|
vFs(eDrag) *= -1; vFs(eLift) *= -1;
|
||||||
|
|
||||||
|
return vFs;
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
bool FGAerodynamics::Load(Element *document)
|
bool FGAerodynamics::Load(Element *document)
|
||||||
{
|
{
|
||||||
string axis;
|
string axis;
|
||||||
|
@ -309,7 +339,7 @@ bool FGAerodynamics::Load(Element *document)
|
||||||
Name = "Aerodynamics Model: " + document->GetAttributeValue("name");
|
Name = "Aerodynamics Model: " + document->GetAttributeValue("name");
|
||||||
|
|
||||||
// Perform base class Pre-Load
|
// Perform base class Pre-Load
|
||||||
if (!FGModel::Load(document))
|
if (!FGModel::Load(document, true))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DetermineAxisSystem(document); // Determine if Lift/Side/Drag, etc. is used.
|
DetermineAxisSystem(document); // Determine if Lift/Side/Drag, etc. is used.
|
||||||
|
@ -353,7 +383,8 @@ bool FGAerodynamics::Load(Element *document)
|
||||||
try {
|
try {
|
||||||
ca.push_back( new FGFunction(PropertyManager, function_element) );
|
ca.push_back( new FGFunction(PropertyManager, function_element) );
|
||||||
} catch (const string& str) {
|
} catch (const string& str) {
|
||||||
cerr << endl << fgred << "Error loading aerodynamic function in "
|
cerr << endl << axis_element->ReadFrom()
|
||||||
|
<< endl << fgred << "Error loading aerodynamic function in "
|
||||||
<< current_func_name << ":" << str << " Aborting." << reset << endl;
|
<< current_func_name << ":" << str << " Aborting." << reset << endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -361,7 +392,8 @@ bool FGAerodynamics::Load(Element *document)
|
||||||
try {
|
try {
|
||||||
ca_atCG.push_back( new FGFunction(PropertyManager, function_element) );
|
ca_atCG.push_back( new FGFunction(PropertyManager, function_element) );
|
||||||
} catch (const string& str) {
|
} catch (const string& str) {
|
||||||
cerr << endl << fgred << "Error loading aerodynamic function in "
|
cerr << endl << axis_element->ReadFrom()
|
||||||
|
<< endl << fgred << "Error loading aerodynamic function in "
|
||||||
<< current_func_name << ":" << str << " Aborting." << reset << endl;
|
<< current_func_name << ":" << str << " Aborting." << reset << endl;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -387,6 +419,9 @@ bool FGAerodynamics::Load(Element *document)
|
||||||
// a warning message will be given IF the AXIAL|NORMAL specifiers are also given.
|
// a warning message will be given IF the AXIAL|NORMAL specifiers are also given.
|
||||||
// This is OK, and the warning is due to the SIDE specifier used for both
|
// This is OK, and the warning is due to the SIDE specifier used for both
|
||||||
// the Lift/Drag and Axial/Normal axis systems.
|
// the Lift/Drag and Axial/Normal axis systems.
|
||||||
|
// Alternatively the axis name 'X|Y|Z or ROLL|PITCH|YAW' can be specified in
|
||||||
|
// conjunction with a frame 'BODY|STABILITY|WIND', for example:
|
||||||
|
// <axis name="X" frame="STABILITY"/>
|
||||||
|
|
||||||
void FGAerodynamics::DetermineAxisSystem(Element* document)
|
void FGAerodynamics::DetermineAxisSystem(Element* document)
|
||||||
{
|
{
|
||||||
|
@ -394,41 +429,85 @@ void FGAerodynamics::DetermineAxisSystem(Element* document)
|
||||||
string axis;
|
string axis;
|
||||||
while (axis_element) {
|
while (axis_element) {
|
||||||
axis = axis_element->GetAttributeValue("name");
|
axis = axis_element->GetAttributeValue("name");
|
||||||
if (axis == "LIFT" || axis == "DRAG") {
|
string frame = axis_element->GetAttributeValue("frame");
|
||||||
if (axisType == atNone) axisType = atLiftDrag;
|
if (axis == "X" || axis == "Y" || axis == "Z") {
|
||||||
else if (axisType != atLiftDrag) {
|
ProcessAxesNameAndFrame(forceAxisType, axis, frame, axis_element,
|
||||||
cerr << endl << " Mixed aerodynamic axis systems have been used in the"
|
"(X Y Z)");
|
||||||
<< " aircraft config file. (LIFT DRAG)" << endl;
|
} else if (axis == "ROLL" || axis == "PITCH" || axis == "YAW") {
|
||||||
|
ProcessAxesNameAndFrame(momentAxisType, axis, frame, axis_element,
|
||||||
|
"(ROLL PITCH YAW)");
|
||||||
|
} else if (axis == "LIFT" || axis == "DRAG") {
|
||||||
|
if (forceAxisType == atNone) forceAxisType = atWind;
|
||||||
|
else if (forceAxisType != atWind) {
|
||||||
|
cerr << endl << axis_element->ReadFrom()
|
||||||
|
<< endl << " Mixed aerodynamic axis systems have been used in the"
|
||||||
|
<< " aircraft config file. (LIFT DRAG)" << endl;
|
||||||
}
|
}
|
||||||
} else if (axis == "SIDE") {
|
} else if (axis == "SIDE") {
|
||||||
if (axisType != atNone && axisType != atLiftDrag && axisType != atAxialNormal) {
|
if (forceAxisType != atNone && forceAxisType != atWind && forceAxisType != atBodyAxialNormal) {
|
||||||
cerr << endl << " Mixed aerodynamic axis systems have been used in the"
|
cerr << endl << axis_element->ReadFrom()
|
||||||
<< " aircraft config file. (SIDE)" << endl;
|
<< endl << " Mixed aerodynamic axis systems have been used in the"
|
||||||
|
<< " aircraft config file. (SIDE)" << endl;
|
||||||
}
|
}
|
||||||
} else if (axis == "AXIAL" || axis == "NORMAL") {
|
} else if (axis == "AXIAL" || axis == "NORMAL") {
|
||||||
if (axisType == atNone) axisType = atAxialNormal;
|
if (forceAxisType == atNone) forceAxisType = atBodyAxialNormal;
|
||||||
else if (axisType != atAxialNormal) {
|
else if (forceAxisType != atBodyAxialNormal) {
|
||||||
cerr << endl << " Mixed aerodynamic axis systems have been used in the"
|
cerr << endl << axis_element->ReadFrom()
|
||||||
<< " aircraft config file. (NORMAL AXIAL)" << endl;
|
<< endl << " Mixed aerodynamic axis systems have been used in the"
|
||||||
|
<< " aircraft config file. (NORMAL AXIAL)" << endl;
|
||||||
}
|
}
|
||||||
} else if (axis == "X" || axis == "Y" || axis == "Z") {
|
} else { // error
|
||||||
if (axisType == atNone) axisType = atBodyXYZ;
|
cerr << endl << axis_element->ReadFrom()
|
||||||
else if (axisType != atBodyXYZ) {
|
<< endl << " An unknown axis type, " << axis << " has been specified"
|
||||||
cerr << endl << " Mixed aerodynamic axis systems have been used in the"
|
<< " in the aircraft configuration file." << endl;
|
||||||
<< " aircraft config file. (XYZ)" << endl;
|
|
||||||
}
|
|
||||||
} else if (axis != "ROLL" && axis != "PITCH" && axis != "YAW") { // error
|
|
||||||
cerr << endl << " An unknown axis type, " << axis << " has been specified"
|
|
||||||
<< " in the aircraft configuration file." << endl;
|
|
||||||
exit(-1);
|
exit(-1);
|
||||||
}
|
}
|
||||||
axis_element = document->FindNextElement("axis");
|
axis_element = document->FindNextElement("axis");
|
||||||
}
|
}
|
||||||
if (axisType == atNone) {
|
|
||||||
axisType = atLiftDrag;
|
if (forceAxisType == atNone) {
|
||||||
|
forceAxisType = atWind;
|
||||||
cerr << endl << " The aerodynamic axis system has been set by default"
|
cerr << endl << " The aerodynamic axis system has been set by default"
|
||||||
<< " to the Lift/Side/Drag system." << endl;
|
<< " to the Lift/Side/Drag system." << endl;
|
||||||
}
|
}
|
||||||
|
if (momentAxisType == atNone) {
|
||||||
|
momentAxisType = atBodyXYZ;
|
||||||
|
cerr << endl << " The aerodynamic moment axis system has been set by default"
|
||||||
|
<< " to the bodyXYZ system." << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGAerodynamics::ProcessAxesNameAndFrame(eAxisType& axisType, const string& name,
|
||||||
|
const string& frame, Element* el,
|
||||||
|
const string& validNames)
|
||||||
|
{
|
||||||
|
if (frame == "BODY" || frame.empty()) {
|
||||||
|
if (axisType == atNone) axisType = atBodyXYZ;
|
||||||
|
else if (axisType != atBodyXYZ)
|
||||||
|
cerr << endl << el->ReadFrom()
|
||||||
|
<< endl << " Mixed aerodynamic axis systems have been used in the "
|
||||||
|
<< " aircraft config file." << validNames << " - BODY" << endl;
|
||||||
|
}
|
||||||
|
else if (frame == "STABILITY") {
|
||||||
|
if (axisType == atNone) axisType = atStability;
|
||||||
|
else if (axisType != atStability)
|
||||||
|
cerr << endl << el->ReadFrom()
|
||||||
|
<< endl << " Mixed aerodynamic axis systems have been used in the "
|
||||||
|
<< " aircraft config file." << validNames << " - STABILITY" << endl;
|
||||||
|
}
|
||||||
|
else if (frame == "WIND") {
|
||||||
|
if (axisType == atNone) axisType = atWind;
|
||||||
|
else if (axisType != atWind)
|
||||||
|
cerr << endl << el->ReadFrom()
|
||||||
|
<< endl << " Mixed aerodynamic axis systems have been used in the "
|
||||||
|
<< " aircraft config file." << validNames << " - WIND" << endl;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cerr << endl << " Unknown axis frame type of - " << frame << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -495,15 +574,24 @@ void FGAerodynamics::bind(void)
|
||||||
{
|
{
|
||||||
typedef double (FGAerodynamics::*PMF)(int) const;
|
typedef double (FGAerodynamics::*PMF)(int) const;
|
||||||
|
|
||||||
PropertyManager->Tie("forces/fbx-aero-lbs", this, 1, (PMF)&FGAerodynamics::GetForces);
|
PropertyManager->Tie("forces/fbx-aero-lbs", this, eX, (PMF)&FGAerodynamics::GetForces);
|
||||||
PropertyManager->Tie("forces/fby-aero-lbs", this, 2, (PMF)&FGAerodynamics::GetForces);
|
PropertyManager->Tie("forces/fby-aero-lbs", this, eY, (PMF)&FGAerodynamics::GetForces);
|
||||||
PropertyManager->Tie("forces/fbz-aero-lbs", this, 3, (PMF)&FGAerodynamics::GetForces);
|
PropertyManager->Tie("forces/fbz-aero-lbs", this, eZ, (PMF)&FGAerodynamics::GetForces);
|
||||||
PropertyManager->Tie("moments/l-aero-lbsft", this, 1, (PMF)&FGAerodynamics::GetMoments);
|
PropertyManager->Tie("moments/l-aero-lbsft", this, eL, (PMF)&FGAerodynamics::GetMoments);
|
||||||
PropertyManager->Tie("moments/m-aero-lbsft", this, 2, (PMF)&FGAerodynamics::GetMoments);
|
PropertyManager->Tie("moments/m-aero-lbsft", this, eM, (PMF)&FGAerodynamics::GetMoments);
|
||||||
PropertyManager->Tie("moments/n-aero-lbsft", this, 3, (PMF)&FGAerodynamics::GetMoments);
|
PropertyManager->Tie("moments/n-aero-lbsft", this, eN, (PMF)&FGAerodynamics::GetMoments);
|
||||||
PropertyManager->Tie("forces/fwx-aero-lbs", this, 1, (PMF)&FGAerodynamics::GetvFw);
|
PropertyManager->Tie("forces/fwx-aero-lbs", this, eDrag, (PMF)&FGAerodynamics::GetvFw);
|
||||||
PropertyManager->Tie("forces/fwy-aero-lbs", this, 2, (PMF)&FGAerodynamics::GetvFw);
|
PropertyManager->Tie("forces/fwy-aero-lbs", this, eSide, (PMF)&FGAerodynamics::GetvFw);
|
||||||
PropertyManager->Tie("forces/fwz-aero-lbs", this, 3, (PMF)&FGAerodynamics::GetvFw);
|
PropertyManager->Tie("forces/fwz-aero-lbs", this, eLift, (PMF)&FGAerodynamics::GetvFw);
|
||||||
|
PropertyManager->Tie("forces/fsx-aero-lbs", this, eX, (PMF)&FGAerodynamics::GetForcesInStabilityAxes);
|
||||||
|
PropertyManager->Tie("forces/fsy-aero-lbs", this, eY, (PMF)&FGAerodynamics::GetForcesInStabilityAxes);
|
||||||
|
PropertyManager->Tie("forces/fsz-aero-lbs", this, eZ, (PMF)&FGAerodynamics::GetForcesInStabilityAxes);
|
||||||
|
PropertyManager->Tie("moments/roll-stab-aero-lbsft", this, eRoll, (PMF)&FGAerodynamics::GetMomentsInStabilityAxes);
|
||||||
|
PropertyManager->Tie("moments/pitch-stab-aero-lbsft", this, ePitch, (PMF)&FGAerodynamics::GetMomentsInStabilityAxes);
|
||||||
|
PropertyManager->Tie("moments/yaw-stab-aero-lbsft", this, eYaw, (PMF)&FGAerodynamics::GetMomentsInStabilityAxes);
|
||||||
|
PropertyManager->Tie("moments/roll-wind-aero-lbsft", this, eRoll, (PMF)&FGAerodynamics::GetMomentsInWindAxes);
|
||||||
|
PropertyManager->Tie("moments/pitch-wind-aero-lbsft", this, ePitch, (PMF)&FGAerodynamics::GetMomentsInWindAxes);
|
||||||
|
PropertyManager->Tie("moments/yaw-wind-aero-lbsft", this, eYaw, (PMF)&FGAerodynamics::GetMomentsInWindAxes);
|
||||||
PropertyManager->Tie("forces/lod-norm", this, &FGAerodynamics::GetLoD);
|
PropertyManager->Tie("forces/lod-norm", this, &FGAerodynamics::GetLoD);
|
||||||
PropertyManager->Tie("aero/cl-squared", this, &FGAerodynamics::GetClSquared);
|
PropertyManager->Tie("aero/cl-squared", this, &FGAerodynamics::GetClSquared);
|
||||||
PropertyManager->Tie("aero/qbar-area", &qbar_area);
|
PropertyManager->Tie("aero/qbar-area", &qbar_area);
|
||||||
|
@ -516,6 +604,44 @@ void FGAerodynamics::bind(void)
|
||||||
PropertyManager->Tie("aero/stall-hyst-norm", this, &FGAerodynamics::GetHysteresisParm);
|
PropertyManager->Tie("aero/stall-hyst-norm", this, &FGAerodynamics::GetHysteresisParm);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
//
|
||||||
|
// Build transformation matrices for transforming from stability axes to
|
||||||
|
// body axes and to wind axes. Where "a" is alpha and "B" is beta:
|
||||||
|
//
|
||||||
|
// The transform from body to stability axes is:
|
||||||
|
//
|
||||||
|
// cos(a) 0 sin(a)
|
||||||
|
// 0 1 0
|
||||||
|
// -sin(a) 0 cos(a)
|
||||||
|
//
|
||||||
|
// The transform from stability to body axes is:
|
||||||
|
//
|
||||||
|
// cos(a) 0 -sin(a)
|
||||||
|
// 0 1 0
|
||||||
|
// sin(a) 0 cos(a)
|
||||||
|
//
|
||||||
|
//
|
||||||
|
|
||||||
|
void FGAerodynamics::BuildStabilityTransformMatrices(void)
|
||||||
|
{
|
||||||
|
double ca = cos(in.Alpha);
|
||||||
|
double sa = sin(in.Alpha);
|
||||||
|
|
||||||
|
// Stability-to-body
|
||||||
|
Ts2b(1, 1) = ca;
|
||||||
|
Ts2b(1, 2) = 0.0;
|
||||||
|
Ts2b(1, 3) = -sa;
|
||||||
|
Ts2b(2, 1) = 0.0;
|
||||||
|
Ts2b(2, 2) = 1.0;
|
||||||
|
Ts2b(2, 3) = 0.0;
|
||||||
|
Ts2b(3, 1) = sa;
|
||||||
|
Ts2b(3, 2) = 0.0;
|
||||||
|
Ts2b(3, 3) = ca;
|
||||||
|
|
||||||
|
Tb2s = Ts2b.Transposed();
|
||||||
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
// The bitmasked value choices are as follows:
|
// The bitmasked value choices are as follows:
|
||||||
// unset: In this case (the default) JSBSim would only print
|
// unset: In this case (the default) JSBSim would only print
|
||||||
|
@ -541,19 +667,22 @@ void FGAerodynamics::Debug(int from)
|
||||||
|
|
||||||
if (debug_lvl & 1) { // Standard console startup message output
|
if (debug_lvl & 1) { // Standard console startup message output
|
||||||
if (from == 2) { // Loader
|
if (from == 2) { // Loader
|
||||||
switch (axisType) {
|
switch (forceAxisType) {
|
||||||
case (atLiftDrag):
|
case (atWind):
|
||||||
cout << endl << " Aerodynamics (Lift|Side|Drag axes):" << endl << endl;
|
cout << endl << " Aerodynamics (Lift|Side|Drag axes):" << endl << endl;
|
||||||
break;
|
break;
|
||||||
case (atAxialNormal):
|
case (atBodyAxialNormal):
|
||||||
cout << endl << " Aerodynamics (Axial|Side|Normal axes):" << endl << endl;
|
cout << endl << " Aerodynamics (Axial|Side|Normal axes):" << endl << endl;
|
||||||
break;
|
break;
|
||||||
case (atBodyXYZ):
|
case (atBodyXYZ):
|
||||||
cout << endl << " Aerodynamics (X|Y|Z axes):" << endl << endl;
|
cout << endl << " Aerodynamics (Body X|Y|Z axes):" << endl << endl;
|
||||||
break;
|
break;
|
||||||
|
case (atStability):
|
||||||
|
cout << endl << " Aerodynamics (Stability X|Y|Z axes):" << endl << endl;
|
||||||
|
break;
|
||||||
case (atNone):
|
case (atNone):
|
||||||
cout << endl << " Aerodynamics (undefined axes):" << endl << endl;
|
cout << endl << " Aerodynamics (undefined axes):" << endl << endl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,7 +141,7 @@ public:
|
||||||
have found the aerodynamics keyword in the configuration file.
|
have found the aerodynamics keyword in the configuration file.
|
||||||
@param element pointer to the current XML element for aerodynamics parameters.
|
@param element pointer to the current XML element for aerodynamics parameters.
|
||||||
@return true if successful */
|
@return true if successful */
|
||||||
bool Load(Element* element);
|
virtual bool Load(Element* element);
|
||||||
|
|
||||||
/** Gets the total aerodynamic force vector.
|
/** Gets the total aerodynamic force vector.
|
||||||
@return a force vector reference. */
|
@return a force vector reference. */
|
||||||
|
@ -181,6 +181,34 @@ public:
|
||||||
axis force. */
|
axis force. */
|
||||||
double GetvFw(int axis) const { return vFw(axis); }
|
double GetvFw(int axis) const { return vFw(axis); }
|
||||||
|
|
||||||
|
/** Retrieves the aerodynamic forces in the stability axes.
|
||||||
|
@return a reference to a column vector containing the stability axis forces. */
|
||||||
|
FGColumnVector3 GetForcesInStabilityAxes(void) const;
|
||||||
|
|
||||||
|
/** Retrieves the aerodynamic forces in the stability axes, given an axis.
|
||||||
|
@param axis the axis to return the force for (eX, eY, eZ).
|
||||||
|
@return a reference to a column vector containing the requested stability
|
||||||
|
axis force. */
|
||||||
|
double GetForcesInStabilityAxes(int n) const { return GetForcesInStabilityAxes()(n); }
|
||||||
|
|
||||||
|
/** Gets the total aerodynamic moment vector about the CG in the stability axes.
|
||||||
|
@return a moment vector reference. */
|
||||||
|
FGColumnVector3 GetMomentsInStabilityAxes(void) const { return Tb2s*vMoments; }
|
||||||
|
|
||||||
|
/** Gets the aerodynamic moment about the CG for an axis.
|
||||||
|
@return the moment about a single axis (as described also in the
|
||||||
|
similar call to GetForces(int n).*/
|
||||||
|
double GetMomentsInStabilityAxes(int n) const { return GetMomentsInStabilityAxes()(n); }
|
||||||
|
|
||||||
|
/** Gets the total aerodynamic moment vector about the CG in the wind axes.
|
||||||
|
@return a moment vector reference. */
|
||||||
|
FGColumnVector3 GetMomentsInWindAxes(void) const { return in.Tb2w*vMoments; }
|
||||||
|
|
||||||
|
/** Gets the aerodynamic moment about the CG for an axis.
|
||||||
|
@return the moment about a single axis (as described also in the
|
||||||
|
similar call to GetForces(int n).*/
|
||||||
|
double GetMomentsInWindAxes(int n) const { return GetMomentsInWindAxes()(n); }
|
||||||
|
|
||||||
/** Retrieves the lift over drag ratio */
|
/** Retrieves the lift over drag ratio */
|
||||||
double GetLoD(void) const { return lod; }
|
double GetLoD(void) const { return lod; }
|
||||||
|
|
||||||
|
@ -227,21 +255,22 @@ public:
|
||||||
} in;
|
} in;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum eAxisType {atNone, atLiftDrag, atAxialNormal, atBodyXYZ} axisType;
|
enum eAxisType {atNone, atWind, atBodyAxialNormal, atBodyXYZ, atStability} forceAxisType, momentAxisType;
|
||||||
typedef std::map<std::string,int> AxisIndex;
|
typedef std::map<std::string,int> AxisIndex;
|
||||||
AxisIndex AxisIdx;
|
AxisIndex AxisIdx;
|
||||||
FGFunction* AeroRPShift;
|
FGFunction* AeroRPShift;
|
||||||
typedef std::vector <FGFunction*> AeroFunctionArray;
|
typedef std::vector <FGFunction*> AeroFunctionArray;
|
||||||
AeroFunctionArray* AeroFunctions;
|
AeroFunctionArray* AeroFunctions;
|
||||||
|
FGMatrix33 Ts2b, Tb2s;
|
||||||
FGColumnVector3 vFnative;
|
FGColumnVector3 vFnative;
|
||||||
FGColumnVector3 vFw;
|
FGColumnVector3 vFw;
|
||||||
FGColumnVector3 vForces;
|
FGColumnVector3 vForces;
|
||||||
AeroFunctionArray* AeroFunctionsAtCG;
|
AeroFunctionArray* AeroFunctionsAtCG;
|
||||||
FGColumnVector3 vFwAtCG;
|
|
||||||
FGColumnVector3 vFnativeAtCG;
|
FGColumnVector3 vFnativeAtCG;
|
||||||
FGColumnVector3 vForcesAtCG;
|
FGColumnVector3 vForcesAtCG;
|
||||||
FGColumnVector3 vMoments;
|
FGColumnVector3 vMoments;
|
||||||
FGColumnVector3 vMomentsMRC;
|
FGColumnVector3 vMomentsMRC;
|
||||||
|
FGColumnVector3 vMomentsMRCBodyXYZ;
|
||||||
FGColumnVector3 vDXYZcg;
|
FGColumnVector3 vDXYZcg;
|
||||||
FGColumnVector3 vDeltaRP;
|
FGColumnVector3 vDeltaRP;
|
||||||
double alphaclmax, alphaclmin;
|
double alphaclmax, alphaclmin;
|
||||||
|
@ -253,7 +282,11 @@ private:
|
||||||
|
|
||||||
typedef double (FGAerodynamics::*PMF)(int) const;
|
typedef double (FGAerodynamics::*PMF)(int) const;
|
||||||
void DetermineAxisSystem(Element* document);
|
void DetermineAxisSystem(Element* document);
|
||||||
|
void ProcessAxesNameAndFrame(FGAerodynamics::eAxisType& axisType,
|
||||||
|
const string& name, const string& frame,
|
||||||
|
Element* el, const string& validNames);
|
||||||
void bind(void);
|
void bind(void);
|
||||||
|
void BuildStabilityTransformMatrices(void);
|
||||||
|
|
||||||
void Debug(int from);
|
void Debug(int from);
|
||||||
};
|
};
|
||||||
|
|
|
@ -78,7 +78,6 @@ FGAircraft::FGAircraft(FGFDMExec* fdmex) : FGModel(fdmex)
|
||||||
lbarh = lbarv = 0.0;
|
lbarh = lbarv = 0.0;
|
||||||
vbarh = vbarv = 0.0;
|
vbarh = vbarv = 0.0;
|
||||||
WingIncidence = 0.0;
|
WingIncidence = 0.0;
|
||||||
PitotAngle = 0.0;
|
|
||||||
|
|
||||||
bind();
|
bind();
|
||||||
|
|
||||||
|
@ -137,7 +136,7 @@ bool FGAircraft::Load(Element* el)
|
||||||
string element_name;
|
string element_name;
|
||||||
Element* element;
|
Element* element;
|
||||||
|
|
||||||
if (!FGModel::Load(el)) return false;
|
if (!FGModel::Load(el, true)) return false;
|
||||||
|
|
||||||
if (el->FindElement("wingarea"))
|
if (el->FindElement("wingarea"))
|
||||||
WingArea = el->FindElementValueAsNumberConvertTo("wingarea", "FT2");
|
WingArea = el->FindElementValueAsNumberConvertTo("wingarea", "FT2");
|
||||||
|
@ -155,8 +154,6 @@ bool FGAircraft::Load(Element* el)
|
||||||
VTailArea = el->FindElementValueAsNumberConvertTo("vtailarea", "FT2");
|
VTailArea = el->FindElementValueAsNumberConvertTo("vtailarea", "FT2");
|
||||||
if (el->FindElement("vtailarm"))
|
if (el->FindElement("vtailarm"))
|
||||||
VTailArm = el->FindElementValueAsNumberConvertTo("vtailarm", "FT");
|
VTailArm = el->FindElementValueAsNumberConvertTo("vtailarm", "FT");
|
||||||
if (el->FindElement("pitot_angle"))
|
|
||||||
PitotAngle = el->FindElementValueAsNumberConvertTo("pitot_angle", "RAD");
|
|
||||||
|
|
||||||
// Find all LOCATION elements that descend from this METRICS branch of the
|
// Find all LOCATION elements that descend from this METRICS branch of the
|
||||||
// config file. This would be CG location, eyepoint, etc.
|
// config file. This would be CG location, eyepoint, etc.
|
||||||
|
|
|
@ -78,7 +78,6 @@ CLASS DOCUMENTATION
|
||||||
<vtailarea unit="{FT2 | M}"> {number} </vtailarea>
|
<vtailarea unit="{FT2 | M}"> {number} </vtailarea>
|
||||||
<vtailarm unit="{FT | M}"> {number} </vtailarm>
|
<vtailarm unit="{FT | M}"> {number} </vtailarm>
|
||||||
<wing_incidence unit="{RAD | DEG}"> {number} </wing_incidence>
|
<wing_incidence unit="{RAD | DEG}"> {number} </wing_incidence>
|
||||||
<pitot_angle unit="{RAD | DEG}"> {number} </pitot_angle>
|
|
||||||
<location name="{AERORP | EYEPOINT | VRP}" unit="{IN | M}">
|
<location name="{AERORP | EYEPOINT | VRP}" unit="{IN | M}">
|
||||||
<x> {number} </x>
|
<x> {number} </x>
|
||||||
<y> {number} </y>
|
<y> {number} </y>
|
||||||
|
@ -132,7 +131,7 @@ public:
|
||||||
The executive calls this method to load the aircraft into JSBSim.
|
The executive calls this method to load the aircraft into JSBSim.
|
||||||
@param el a pointer to the element tree
|
@param el a pointer to the element tree
|
||||||
@return true if successful */
|
@return true if successful */
|
||||||
bool Load(Element* el);
|
virtual bool Load(Element* el);
|
||||||
|
|
||||||
/** Gets the aircraft name
|
/** Gets the aircraft name
|
||||||
@return the name of the aircraft as a string type */
|
@return the name of the aircraft as a string type */
|
||||||
|
@ -144,7 +143,6 @@ public:
|
||||||
double GetWingSpan(void) const { return WingSpan; }
|
double GetWingSpan(void) const { return WingSpan; }
|
||||||
/// Gets the average wing chord
|
/// Gets the average wing chord
|
||||||
double Getcbar(void) const { return cbar; }
|
double Getcbar(void) const { return cbar; }
|
||||||
double GetPitotAngle(void) const { return PitotAngle; }
|
|
||||||
double GetWingIncidence(void) const { return WingIncidence; }
|
double GetWingIncidence(void) const { return WingIncidence; }
|
||||||
double GetWingIncidenceDeg(void) const { return WingIncidence*radtodeg; }
|
double GetWingIncidenceDeg(void) const { return WingIncidence*radtodeg; }
|
||||||
double GetHTailArea(void) const { return HTailArea; }
|
double GetHTailArea(void) const { return HTailArea; }
|
||||||
|
@ -197,7 +195,7 @@ private:
|
||||||
|
|
||||||
double WingArea, WingSpan, cbar, WingIncidence;
|
double WingArea, WingSpan, cbar, WingIncidence;
|
||||||
double HTailArea, VTailArea, HTailArm, VTailArm;
|
double HTailArea, VTailArea, HTailArm, VTailArm;
|
||||||
double lbarh,lbarv,vbarh,vbarv,PitotAngle;
|
double lbarh,lbarv,vbarh,vbarv;
|
||||||
std::string AircraftName;
|
std::string AircraftName;
|
||||||
|
|
||||||
void Debug(int from);
|
void Debug(int from);
|
||||||
|
|
|
@ -50,13 +50,24 @@ INCLUDES
|
||||||
|
|
||||||
namespace JSBSim {
|
namespace JSBSim {
|
||||||
|
|
||||||
IDENT(IdSrc,"$Id: FGAtmosphere.cpp,v 1.61 2016/01/10 19:22:12 bcoconni Exp $");
|
IDENT(IdSrc,"$Id: FGAtmosphere.cpp,v 1.62 2016/01/16 12:05:47 bcoconni Exp $");
|
||||||
IDENT(IdHdr,ID_ATMOSPHERE);
|
IDENT(IdHdr,ID_ATMOSPHERE);
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
CLASS IMPLEMENTATION
|
CLASS IMPLEMENTATION
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
// Atmosphere constants in British units converted from the SI values specified in the
|
||||||
|
// ISA document - https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770009539.pdf
|
||||||
|
|
||||||
|
const double KtoDegR = 1.8; // Kelvin to degree Rankine
|
||||||
|
const double FGAtmosphere::Rstar = 8.31432 * (FGJSBBase::kgtoslug / (KtoDegR * FGJSBBase::fttom * FGJSBBase::fttom)); // ft*lbf/R/mol
|
||||||
|
const double FGAtmosphere::Mair = 28.9645 * FGJSBBase::kgtoslug / 1000.0; // slug/mol
|
||||||
|
const double FGAtmosphere::g0 = 9.80665 / FGJSBBase::fttom; // ft/s^2
|
||||||
|
double FGAtmosphere::Reng = Rstar / Mair;
|
||||||
|
|
||||||
|
const double FGAtmosphere::SHRatio = 1.40;
|
||||||
|
|
||||||
FGAtmosphere::FGAtmosphere(FGFDMExec* fdmex) : FGModel(fdmex),
|
FGAtmosphere::FGAtmosphere(FGFDMExec* fdmex) : FGModel(fdmex),
|
||||||
PressureAltitude(0.0), // ft
|
PressureAltitude(0.0), // ft
|
||||||
DensityAltitude(0.0), // ft
|
DensityAltitude(0.0), // ft
|
||||||
|
@ -84,7 +95,7 @@ bool FGAtmosphere::InitModel(void)
|
||||||
|
|
||||||
Calculate(0.0);
|
Calculate(0.0);
|
||||||
SLtemperature = Temperature = 518.67;
|
SLtemperature = Temperature = 518.67;
|
||||||
SLpressure = Pressure = 2116.22;
|
SLpressure = Pressure = 2116.228;
|
||||||
SLdensity = Density = Pressure/(Reng*Temperature);
|
SLdensity = Density = Pressure/(Reng*Temperature);
|
||||||
SLsoundspeed = Soundspeed = sqrt(SHRatio*Reng*(Temperature));
|
SLsoundspeed = Soundspeed = sqrt(SHRatio*Reng*(Temperature));
|
||||||
|
|
||||||
|
@ -130,8 +141,8 @@ void FGAtmosphere::Calculate(double altitude)
|
||||||
Density = node->GetDouble("atmosphere/override/density");
|
Density = node->GetDouble("atmosphere/override/density");
|
||||||
|
|
||||||
Soundspeed = sqrt(SHRatio*Reng*(Temperature));
|
Soundspeed = sqrt(SHRatio*Reng*(Temperature));
|
||||||
PressureAltitude = altitude;
|
PressureAltitude = CalculatePressureAltitude(Pressure, altitude);
|
||||||
DensityAltitude = altitude;
|
DensityAltitude = CalculateDensityAltitude(Density, altitude);
|
||||||
|
|
||||||
Viscosity = Beta * pow(Temperature, 1.5) / (SutherlandConstant + Temperature);
|
Viscosity = Beta * pow(Temperature, 1.5) / (SutherlandConstant + Temperature);
|
||||||
KinematicViscosity = Viscosity / Density;
|
KinematicViscosity = Viscosity / Density;
|
||||||
|
|
|
@ -232,6 +232,20 @@ protected:
|
||||||
/// Calculate the atmosphere for the given altitude.
|
/// Calculate the atmosphere for the given altitude.
|
||||||
void Calculate(double altitude);
|
void Calculate(double altitude);
|
||||||
|
|
||||||
|
/// Calculates the density altitude given any temperature or pressure bias.
|
||||||
|
/// Calculated density for the specified geometric altitude given any temperature
|
||||||
|
/// or pressure biases is passed in.
|
||||||
|
/// @param density
|
||||||
|
/// @param geometricAlt
|
||||||
|
virtual double CalculateDensityAltitude(double density, double geometricAlt) { return geometricAlt; }
|
||||||
|
|
||||||
|
/// Calculates the pressure altitude given any temperature or pressure bias.
|
||||||
|
/// Calculated pressure for the specified geometric altitude given any temperature
|
||||||
|
/// or pressure biases is passed in.
|
||||||
|
/// @param pressure
|
||||||
|
/// @param geometricAlt
|
||||||
|
virtual double CalculatePressureAltitude(double pressure, double geometricAlt) { return geometricAlt; }
|
||||||
|
|
||||||
// Converts to Rankine from one of several unit systems.
|
// Converts to Rankine from one of several unit systems.
|
||||||
virtual double ConvertToRankine(double t, eTemperature unit) const;
|
virtual double ConvertToRankine(double t, eTemperature unit) const;
|
||||||
|
|
||||||
|
@ -241,6 +255,14 @@ protected:
|
||||||
// Converts from PSF (pounds per square foot) to one of several unit systems.
|
// Converts from PSF (pounds per square foot) to one of several unit systems.
|
||||||
virtual double ConvertFromPSF(double t, ePressure unit=ePSF) const;
|
virtual double ConvertFromPSF(double t, ePressure unit=ePSF) const;
|
||||||
|
|
||||||
|
static const double Rstar; // Universal gas constant - ft*lbf/R/mol
|
||||||
|
static const double Mair; // Mean molecular weight - slug/mol
|
||||||
|
static const double g0; // Sea-level acceleration of gravity - ft/s^2
|
||||||
|
static double Reng; // Specific gas constant - ft*lbf/slug/R
|
||||||
|
|
||||||
|
static const double SHRatio;
|
||||||
|
|
||||||
|
|
||||||
virtual void bind(void);
|
virtual void bind(void);
|
||||||
void Debug(int from);
|
void Debug(int from);
|
||||||
};
|
};
|
||||||
|
|
|
@ -68,10 +68,10 @@ FGAuxiliary::FGAuxiliary(FGFDMExec* fdmex) : FGModel(fdmex)
|
||||||
|
|
||||||
vcas = veas = 0.0;
|
vcas = veas = 0.0;
|
||||||
qbar = qbarUW = qbarUV = 0.0;
|
qbar = qbarUW = qbarUV = 0.0;
|
||||||
Mach = MachU = MachPitot = 0.0;
|
Mach = MachU = 0.0;
|
||||||
alpha = beta = 0.0;
|
alpha = beta = 0.0;
|
||||||
adot = bdot = 0.0;
|
adot = bdot = 0.0;
|
||||||
gamma = Vt = Vground = Vpitot = 0.0;
|
gamma = Vt = Vground = 0.0;
|
||||||
psigt = 0.0;
|
psigt = 0.0;
|
||||||
day_of_year = 1;
|
day_of_year = 1;
|
||||||
seconds_in_day = 0.0;
|
seconds_in_day = 0.0;
|
||||||
|
@ -84,8 +84,6 @@ FGAuxiliary::FGAuxiliary(FGFDMExec* fdmex) : FGModel(fdmex)
|
||||||
vAeroUVW.InitMatrix();
|
vAeroUVW.InitMatrix();
|
||||||
vAeroPQR.InitMatrix();
|
vAeroPQR.InitMatrix();
|
||||||
vMachUVW.InitMatrix();
|
vMachUVW.InitMatrix();
|
||||||
vWindUVW.InitMatrix();
|
|
||||||
vPitotUVW.InitMatrix();
|
|
||||||
vEuler.InitMatrix();
|
vEuler.InitMatrix();
|
||||||
vEulerRates.InitMatrix();
|
vEulerRates.InitMatrix();
|
||||||
|
|
||||||
|
@ -106,10 +104,10 @@ bool FGAuxiliary::InitModel(void)
|
||||||
|
|
||||||
vcas = veas = 0.0;
|
vcas = veas = 0.0;
|
||||||
qbar = qbarUW = qbarUV = 0.0;
|
qbar = qbarUW = qbarUV = 0.0;
|
||||||
Mach = MachU = MachPitot = 0.0;
|
Mach = MachU = 0.0;
|
||||||
alpha = beta = 0.0;
|
alpha = beta = 0.0;
|
||||||
adot = bdot = 0.0;
|
adot = bdot = 0.0;
|
||||||
gamma = Vt = Vground = Vpitot = 0.0;
|
gamma = Vt = Vground = 0.0;
|
||||||
psigt = 0.0;
|
psigt = 0.0;
|
||||||
day_of_year = 1;
|
day_of_year = 1;
|
||||||
seconds_in_day = 0.0;
|
seconds_in_day = 0.0;
|
||||||
|
@ -206,20 +204,14 @@ bool FGAuxiliary::Run(bool Holding)
|
||||||
tat = in.Temperature*(1 + 0.2*Mach*Mach); // Total Temperature, isentropic flow
|
tat = in.Temperature*(1 + 0.2*Mach*Mach); // Total Temperature, isentropic flow
|
||||||
tatc = RankineToCelsius(tat);
|
tatc = RankineToCelsius(tat);
|
||||||
|
|
||||||
// Pitot
|
pt = PitotTotalPressure(Mach, in.Pressure);
|
||||||
|
|
||||||
vWindUVW(eU) = Vt;
|
if (abs(Mach) > 0.0) {
|
||||||
vPitotUVW = mTw2p * vWindUVW;
|
vcas = VcalibratedFromMach(Mach, in.Pressure, in.PressureSL, in.DensitySL);
|
||||||
Vpitot = vPitotUVW(eU);
|
|
||||||
if (Vpitot < 0.0) Vpitot = 0.0;
|
|
||||||
MachPitot = Vpitot / in.SoundSpeed;
|
|
||||||
pt = PitotTotalPressure(MachPitot, in.Pressure);
|
|
||||||
|
|
||||||
if (abs(MachPitot) > 0.0) {
|
|
||||||
vcas = VcalibratedFromMach(MachPitot, in.Pressure, in.PressureSL, in.DensitySL);
|
|
||||||
veas = sqrt(2 * qbar / in.DensitySL);
|
veas = sqrt(2 * qbar / in.DensitySL);
|
||||||
vtrue = 1116.43559 * Mach * sqrt(in.Temperature / 518.67);
|
vtrue = 1116.43559 * Mach * sqrt(in.Temperature / 518.67);
|
||||||
} else {
|
}
|
||||||
|
else {
|
||||||
vcas = veas = vtrue = 0.0;
|
vcas = veas = vtrue = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,23 +276,6 @@ void FGAuxiliary::UpdateWindMatrices(void)
|
||||||
mTw2b(3,3) = ca;
|
mTw2b(3,3) = ca;
|
||||||
|
|
||||||
mTb2w = mTw2b.Transposed();
|
mTb2w = mTw2b.Transposed();
|
||||||
|
|
||||||
// The pitot frame is the same as the body frame except rotated about the
|
|
||||||
// Y axis by the pitot attachment angle.
|
|
||||||
|
|
||||||
ca = cos(alpha + in.PitotAngle);
|
|
||||||
sa = sin(alpha + in.PitotAngle);
|
|
||||||
|
|
||||||
mTw2p(1,1) = ca*cb;
|
|
||||||
mTw2p(1,2) = -ca*sb;
|
|
||||||
mTw2p(1,3) = -sa;
|
|
||||||
mTw2p(2,1) = sb;
|
|
||||||
mTw2p(2,2) = cb;
|
|
||||||
mTw2p(2,3) = 0.0;
|
|
||||||
mTw2p(3,1) = sa*cb;
|
|
||||||
mTw2p(3,2) = -sa*sb;
|
|
||||||
mTw2p(3,3) = ca;
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -424,6 +399,7 @@ void FGAuxiliary::bind(void)
|
||||||
PropertyManager->Tie("aero/h_b-cg-ft", this, &FGAuxiliary::GetHOverBCG);
|
PropertyManager->Tie("aero/h_b-cg-ft", this, &FGAuxiliary::GetHOverBCG);
|
||||||
PropertyManager->Tie("aero/h_b-mac-ft", this, &FGAuxiliary::GetHOverBMAC);
|
PropertyManager->Tie("aero/h_b-mac-ft", this, &FGAuxiliary::GetHOverBMAC);
|
||||||
PropertyManager->Tie("flight-path/gamma-rad", this, &FGAuxiliary::GetGamma);
|
PropertyManager->Tie("flight-path/gamma-rad", this, &FGAuxiliary::GetGamma);
|
||||||
|
PropertyManager->Tie("flight-path/gamma-deg", this, inDegrees, (PMF)&FGAuxiliary::GetGamma);
|
||||||
PropertyManager->Tie("flight-path/psi-gt-rad", this, &FGAuxiliary::GetGroundTrack);
|
PropertyManager->Tie("flight-path/psi-gt-rad", this, &FGAuxiliary::GetGroundTrack);
|
||||||
|
|
||||||
PropertyManager->Tie("position/distance-from-start-lon-mt", this, &FGAuxiliary::GetLongitudeRelativePosition);
|
PropertyManager->Tie("position/distance-from-start-lon-mt", this, &FGAuxiliary::GetLongitudeRelativePosition);
|
||||||
|
|
|
@ -236,6 +236,11 @@ public:
|
||||||
double GetGamma(void) const { return gamma; }
|
double GetGamma(void) const { return gamma; }
|
||||||
double GetGroundTrack(void) const { return psigt; }
|
double GetGroundTrack(void) const { return psigt; }
|
||||||
|
|
||||||
|
double GetGamma(int unit) const {
|
||||||
|
if (unit == inDegrees) return gamma*radtodeg;
|
||||||
|
else return BadUnits();
|
||||||
|
}
|
||||||
|
|
||||||
double GetHeadWind(void) const;
|
double GetHeadWind(void) const;
|
||||||
double GetCrossWind(void) const;
|
double GetCrossWind(void) const;
|
||||||
|
|
||||||
|
@ -289,7 +294,6 @@ public:
|
||||||
FGColumnVector3 TurbPQR;
|
FGColumnVector3 TurbPQR;
|
||||||
double WindPsi;
|
double WindPsi;
|
||||||
double Vwind;
|
double Vwind;
|
||||||
double PitotAngle;
|
|
||||||
} in;
|
} in;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -298,7 +302,6 @@ private:
|
||||||
|
|
||||||
FGMatrix33 mTw2b;
|
FGMatrix33 mTw2b;
|
||||||
FGMatrix33 mTb2w;
|
FGMatrix33 mTb2w;
|
||||||
FGMatrix33 mTw2p;
|
|
||||||
|
|
||||||
FGColumnVector3 vPilotAccel;
|
FGColumnVector3 vPilotAccel;
|
||||||
FGColumnVector3 vPilotAccelN;
|
FGColumnVector3 vPilotAccelN;
|
||||||
|
@ -309,12 +312,10 @@ private:
|
||||||
FGColumnVector3 vEuler;
|
FGColumnVector3 vEuler;
|
||||||
FGColumnVector3 vEulerRates;
|
FGColumnVector3 vEulerRates;
|
||||||
FGColumnVector3 vMachUVW;
|
FGColumnVector3 vMachUVW;
|
||||||
FGColumnVector3 vWindUVW;
|
|
||||||
FGColumnVector3 vPitotUVW;
|
|
||||||
FGLocation vLocationVRP;
|
FGLocation vLocationVRP;
|
||||||
|
|
||||||
double Vt, Vground, Vpitot;
|
double Vt, Vground;
|
||||||
double Mach, MachU, MachPitot;
|
double Mach, MachU;
|
||||||
double qbar, qbarUW, qbarUV;
|
double qbar, qbarUW, qbarUV;
|
||||||
double Re; // Reynolds Number = V*c/mu
|
double Re; // Reynolds Number = V*c/mu
|
||||||
double alpha, beta;
|
double alpha, beta;
|
||||||
|
|
|
@ -123,7 +123,7 @@ bool FGBuoyantForces::Load(Element *document)
|
||||||
Debug(2);
|
Debug(2);
|
||||||
|
|
||||||
// Perform base class Pre-Load
|
// Perform base class Pre-Load
|
||||||
if (!FGModel::Load(document))
|
if (!FGModel::Load(document, true))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
gas_cell_element = document->FindElement("gas_cell");
|
gas_cell_element = document->FindElement("gas_cell");
|
||||||
|
|
|
@ -128,7 +128,7 @@ public:
|
||||||
have found the Buoyant_forces keyword in the configuration file.
|
have found the Buoyant_forces keyword in the configuration file.
|
||||||
@param element pointer to the current XML element for Buoyant forces parameters.
|
@param element pointer to the current XML element for Buoyant forces parameters.
|
||||||
@return true if successful */
|
@return true if successful */
|
||||||
bool Load(Element* element);
|
virtual bool Load(Element* element);
|
||||||
|
|
||||||
/** Gets the total Buoyant force vector.
|
/** Gets the total Buoyant force vector.
|
||||||
@return a force vector in lbs. */
|
@return a force vector in lbs. */
|
||||||
|
|
|
@ -72,7 +72,7 @@ FGExternalReactions::FGExternalReactions(FGFDMExec* fdmex) : FGModel(fdmex)
|
||||||
bool FGExternalReactions::Load(Element* el)
|
bool FGExternalReactions::Load(Element* el)
|
||||||
{
|
{
|
||||||
// Call the base class Load() function to load interface properties.
|
// Call the base class Load() function to load interface properties.
|
||||||
if (!FGModel::Load(el))
|
if (!FGModel::Load(el, true))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Debug(2);
|
Debug(2);
|
||||||
|
|
|
@ -155,7 +155,7 @@ public:
|
||||||
a FGExternalForce object will be instantiated for each force definition.
|
a FGExternalForce object will be instantiated for each force definition.
|
||||||
@param el a pointer to the XML element holding the external reactions definition.
|
@param el a pointer to the XML element holding the external reactions definition.
|
||||||
*/
|
*/
|
||||||
bool Load(Element* el);
|
virtual bool Load(Element* el);
|
||||||
|
|
||||||
/** Retrieves the total forces defined in the external reactions.
|
/** Retrieves the total forces defined in the external reactions.
|
||||||
@return the total force in pounds.
|
@return the total force in pounds.
|
||||||
|
|
|
@ -490,7 +490,7 @@ bool FGFCS::Load(Element* document)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load interface properties from document
|
// Load interface properties from document
|
||||||
if (!FGModel::Load(document))
|
if (!FGModel::Load(document, true))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
Name += document->GetAttributeValue("name");
|
Name += document->GetAttributeValue("name");
|
||||||
|
|
|
@ -542,7 +542,7 @@ public:
|
||||||
Load() is called from FGFDMExec.
|
Load() is called from FGFDMExec.
|
||||||
@param el pointer to the Element instance
|
@param el pointer to the Element instance
|
||||||
@return true if succesful */
|
@return true if succesful */
|
||||||
bool Load(Element* el);
|
virtual bool Load(Element* el);
|
||||||
|
|
||||||
SGPath FindFullPathName(const SGPath& path) const;
|
SGPath FindFullPathName(const SGPath& path) const;
|
||||||
|
|
||||||
|
|
|
@ -158,7 +158,7 @@ bool FGGroundReactions::Load(Element* document)
|
||||||
Debug(2);
|
Debug(2);
|
||||||
|
|
||||||
// Perform base class Pre-Load
|
// Perform base class Pre-Load
|
||||||
if (!FGModel::Load(document))
|
if (!FGModel::Load(document, true))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
unsigned int numContacts = document->GetNumElements("contact");
|
unsigned int numContacts = document->GetNumElements("contact");
|
||||||
|
|
|
@ -93,7 +93,7 @@ public:
|
||||||
"Resume" command to be given.
|
"Resume" command to be given.
|
||||||
@return false if no error */
|
@return false if no error */
|
||||||
bool Run(bool Holding);
|
bool Run(bool Holding);
|
||||||
bool Load(Element* el);
|
virtual bool Load(Element* el);
|
||||||
const FGColumnVector3& GetForces(void) const {return vForces;}
|
const FGColumnVector3& GetForces(void) const {return vForces;}
|
||||||
double GetForces(int idx) const {return vForces(idx);}
|
double GetForces(int idx) const {return vForces(idx);}
|
||||||
const FGColumnVector3& GetMoments(void) const {return vMoments;}
|
const FGColumnVector3& GetMoments(void) const {return vMoments;}
|
||||||
|
|
|
@ -134,7 +134,7 @@ bool FGMassBalance::Load(Element* document)
|
||||||
Name = "Mass Properties Model: " + document->GetAttributeValue("name");
|
Name = "Mass Properties Model: " + document->GetAttributeValue("name");
|
||||||
|
|
||||||
// Perform base class Pre-Load
|
// Perform base class Pre-Load
|
||||||
if (!FGModel::Load(document))
|
if (!FGModel::Load(document, true))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
SetAircraftBaseInertias(ReadInertiaMatrix(document));
|
SetAircraftBaseInertias(ReadInertiaMatrix(document));
|
||||||
|
|
|
@ -111,7 +111,7 @@ public:
|
||||||
FGMassBalance(FGFDMExec*);
|
FGMassBalance(FGFDMExec*);
|
||||||
~FGMassBalance();
|
~FGMassBalance();
|
||||||
|
|
||||||
bool Load(Element* el);
|
virtual bool Load(Element* el);
|
||||||
bool InitModel(void);
|
bool InitModel(void);
|
||||||
/** Runs the Mass Balance model; called by the Executive
|
/** Runs the Mass Balance model; called by the Executive
|
||||||
Can pass in a value indicating if the executive is directing the simulation to Hold.
|
Can pass in a value indicating if the executive is directing the simulation to Hold.
|
||||||
|
|
|
@ -110,7 +110,7 @@ SGPath FGModel::FindFullPathName(const SGPath& path) const
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
bool FGModel::Load(Element* el)
|
bool FGModel::Load(Element* el, bool preLoad)
|
||||||
{
|
{
|
||||||
FGModelLoader ModelLoader(this);
|
FGModelLoader ModelLoader(this);
|
||||||
Element* document = ModelLoader.Open(el);
|
Element* document = ModelLoader.Open(el);
|
||||||
|
@ -124,17 +124,21 @@ bool FGModel::Load(Element* el)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool result = FGModelFunctions::Load(document, PropertyManager);
|
bool result = true;
|
||||||
|
|
||||||
|
if (preLoad)
|
||||||
|
result = FGModelFunctions::Load(document, PropertyManager);
|
||||||
|
|
||||||
if (document != el) {
|
if (document != el) {
|
||||||
el->MergeAttributes(document);
|
el->MergeAttributes(document);
|
||||||
|
|
||||||
// After reading interface properties in a file, read properties in the
|
if (preLoad) {
|
||||||
// local model element. This allows general-purpose models to be defined in
|
// After reading interface properties in a file, read properties in the
|
||||||
// a file, with overrides or initial loaded constants supplied in the
|
// local model element. This allows general-purpose models to be defined
|
||||||
// relevant element of the aircraft configuration file.
|
// in a file, with overrides or initial loaded constants supplied in the
|
||||||
|
// relevant element of the aircraft configuration file.
|
||||||
LocalProperties.Load(el, PropertyManager, true);
|
LocalProperties.Load(el, PropertyManager, true);
|
||||||
|
}
|
||||||
|
|
||||||
Element* element = document->FindElement();
|
Element* element = document->FindElement();
|
||||||
while (element) {
|
while (element) {
|
||||||
|
|
|
@ -108,9 +108,11 @@ protected:
|
||||||
unsigned int rate;
|
unsigned int rate;
|
||||||
|
|
||||||
/** Loads this model.
|
/** Loads this model.
|
||||||
@param el a pointer to the element
|
@param el a pointer to the element
|
||||||
|
@param preLoad true if model functions and local properties must be
|
||||||
|
preloaded.
|
||||||
@return true if model is successfully loaded*/
|
@return true if model is successfully loaded*/
|
||||||
virtual bool Load(Element* el);
|
virtual bool Load(Element* el, bool preLoad);
|
||||||
|
|
||||||
virtual void Debug(int from);
|
virtual void Debug(int from);
|
||||||
|
|
||||||
|
|
|
@ -44,10 +44,10 @@ INCLUDES
|
||||||
#include "input_output/FGOutputSocket.h"
|
#include "input_output/FGOutputSocket.h"
|
||||||
#include "input_output/FGOutputTextFile.h"
|
#include "input_output/FGOutputTextFile.h"
|
||||||
#include "input_output/FGOutputFG.h"
|
#include "input_output/FGOutputFG.h"
|
||||||
#include "input_output/FGUDPOutputSocket.h"
|
|
||||||
#include "input_output/FGXMLFileRead.h"
|
#include "input_output/FGXMLFileRead.h"
|
||||||
#include "input_output/FGXMLElement.h"
|
#include "input_output/FGXMLElement.h"
|
||||||
#include "input_output/FGModelLoader.h"
|
#include "input_output/FGModelLoader.h"
|
||||||
|
#include "math/FGTemplateFunc.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
@ -76,9 +76,9 @@ FGOutput::FGOutput(FGFDMExec* fdmex) : FGModel(fdmex)
|
||||||
|
|
||||||
FGOutput::~FGOutput()
|
FGOutput::~FGOutput()
|
||||||
{
|
{
|
||||||
vector<FGOutputType*>::iterator it;
|
vector<FGOutputType*>::iterator itv;
|
||||||
for (it = OutputTypes.begin(); it != OutputTypes.end(); ++it)
|
for (itv = OutputTypes.begin(); itv != OutputTypes.end(); ++itv)
|
||||||
delete (*it);
|
delete (*itv);
|
||||||
|
|
||||||
Debug(1);
|
Debug(1);
|
||||||
}
|
}
|
||||||
|
@ -221,9 +221,6 @@ bool FGOutput::Load(int subSystems, std::string protocol, std::string type,
|
||||||
} else if (type == "FLIGHTGEAR") {
|
} else if (type == "FLIGHTGEAR") {
|
||||||
Output = new FGOutputFG(FDMExec);
|
Output = new FGOutputFG(FDMExec);
|
||||||
name += ":" + port + "/" + protocol;
|
name += ":" + port + "/" + protocol;
|
||||||
} else if (type == "QTJSBSIM") {
|
|
||||||
Output = new FGUDPOutputSocket(FDMExec);
|
|
||||||
name += ":" + port + "/" + protocol;
|
|
||||||
} else if (type == "TERMINAL") {
|
} else if (type == "TERMINAL") {
|
||||||
// Not done yet
|
// Not done yet
|
||||||
} else if (type != string("NONE")) {
|
} else if (type != string("NONE")) {
|
||||||
|
@ -246,22 +243,30 @@ bool FGOutput::Load(int subSystems, std::string protocol, std::string type,
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
bool FGOutput::Load(Element* el)
|
bool FGOutput::Load(Element* document, const SGPath& dir)
|
||||||
{
|
{
|
||||||
// Unlike the other FGModel classes, properties listed in the <output> section
|
// Optional path to use for included files
|
||||||
// are not intended to create new properties. For that reason, FGOutput
|
includePath = dir;
|
||||||
// cannot load its XML directives with FGModel::Load().
|
|
||||||
// Instead FGModelLoader::Open() and FGModel::PreLoad() must be explicitely
|
|
||||||
// called.
|
|
||||||
FGModelLoader ModelLoader(this);
|
|
||||||
Element* element = ModelLoader.Open(el);
|
|
||||||
|
|
||||||
if (!element) return false;
|
// Perform base class Pre-Load
|
||||||
|
if (!FGModel::Load(document, false))
|
||||||
|
return false;
|
||||||
|
|
||||||
FGModel::PreLoad(element, PropertyManager);
|
Element *function = document->FindElement("function");
|
||||||
|
|
||||||
|
while (function) {
|
||||||
|
string fType = function->GetAttributeValue("type");
|
||||||
|
|
||||||
|
if (fType == "template") {
|
||||||
|
string name = function->GetAttributeValue("name");
|
||||||
|
TemplateFunctions[name] = new FGTemplateFunc(PropertyManager, function);
|
||||||
|
}
|
||||||
|
|
||||||
|
function = document->FindNextElement("function");
|
||||||
|
}
|
||||||
|
|
||||||
size_t idx = OutputTypes.size();
|
size_t idx = OutputTypes.size();
|
||||||
string type = element->GetAttributeValue("type");
|
string type = document->GetAttributeValue("type");
|
||||||
FGOutputType* Output = 0;
|
FGOutputType* Output = 0;
|
||||||
|
|
||||||
if (debug_lvl > 0) cout << endl << " Output data set: " << idx << " " << endl;
|
if (debug_lvl > 0) cout << endl << " Output data set: " << idx << " " << endl;
|
||||||
|
@ -276,8 +281,6 @@ bool FGOutput::Load(Element* el)
|
||||||
Output = new FGOutputSocket(FDMExec);
|
Output = new FGOutputSocket(FDMExec);
|
||||||
} else if (type == "FLIGHTGEAR") {
|
} else if (type == "FLIGHTGEAR") {
|
||||||
Output = new FGOutputFG(FDMExec);
|
Output = new FGOutputFG(FDMExec);
|
||||||
} else if (type == "QTJSBSIM") {
|
|
||||||
Output = new FGUDPOutputSocket(FDMExec);
|
|
||||||
} else if (type == "TERMINAL") {
|
} else if (type == "TERMINAL") {
|
||||||
// Not done yet
|
// Not done yet
|
||||||
} else if (type != string("NONE")) {
|
} else if (type != string("NONE")) {
|
||||||
|
@ -287,8 +290,9 @@ bool FGOutput::Load(Element* el)
|
||||||
if (!Output) return false;
|
if (!Output) return false;
|
||||||
|
|
||||||
Output->SetIdx(idx);
|
Output->SetIdx(idx);
|
||||||
Output->Load(element);
|
Output->PreLoad(document, PropertyManager);
|
||||||
PostLoad(element, PropertyManager);
|
Output->Load(document);
|
||||||
|
Output->PostLoad(document, PropertyManager);
|
||||||
|
|
||||||
OutputTypes.push_back(Output);
|
OutputTypes.push_back(Output);
|
||||||
|
|
||||||
|
@ -296,6 +300,19 @@ bool FGOutput::Load(Element* el)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
SGPath FGOutput::FindFullPathName(const SGPath& path) const
|
||||||
|
{
|
||||||
|
// Check optional include path if set
|
||||||
|
if (!includePath.isNull()) {
|
||||||
|
SGPath name = CheckPathName(includePath, path);
|
||||||
|
if (!name.isNull()) return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FGModel::FindFullPathName(path);
|
||||||
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
// The bitmasked value choices are as follows:
|
// The bitmasked value choices are as follows:
|
||||||
// unset: In this case (the default) JSBSim would only print
|
// unset: In this case (the default) JSBSim would only print
|
||||||
|
|
|
@ -42,6 +42,7 @@ INCLUDES
|
||||||
|
|
||||||
#include "FGModel.h"
|
#include "FGModel.h"
|
||||||
#include "input_output/FGOutputType.h"
|
#include "input_output/FGOutputType.h"
|
||||||
|
#include "math/FGTemplateFunc.h"
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
DEFINITIONS
|
DEFINITIONS
|
||||||
|
@ -199,8 +200,9 @@ public:
|
||||||
/** Load the output directives and adds a new output instance to the Output
|
/** Load the output directives and adds a new output instance to the Output
|
||||||
Manager list.
|
Manager list.
|
||||||
@param el XMLElement that is pointing to the output directives
|
@param el XMLElement that is pointing to the output directives
|
||||||
|
@param dir optional directory path to load included files from
|
||||||
@result true if the execution succeeded. */
|
@result true if the execution succeeded. */
|
||||||
bool Load(Element* el);
|
virtual bool Load(Element* el, const SGPath& dir = SGPath());
|
||||||
/** Load the output directives and adds a new output instance to the Output
|
/** Load the output directives and adds a new output instance to the Output
|
||||||
Manager list. Unlike the Load() method, the new output instance is not
|
Manager list. Unlike the Load() method, the new output instance is not
|
||||||
generated from output directives read in a XML file but from a list of
|
generated from output directives read in a XML file but from a list of
|
||||||
|
@ -222,9 +224,20 @@ public:
|
||||||
@result the name identifier.*/
|
@result the name identifier.*/
|
||||||
std::string GetOutputName(unsigned int idx) const;
|
std::string GetOutputName(unsigned int idx) const;
|
||||||
|
|
||||||
|
SGPath FindFullPathName(const SGPath& path) const;
|
||||||
|
|
||||||
|
FGTemplateFunc* GetTemplateFunc(const std::string& name) {
|
||||||
|
if (TemplateFunctions.count(name))
|
||||||
|
return TemplateFunctions[name];
|
||||||
|
else
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<FGOutputType*> OutputTypes;
|
std::vector<FGOutputType*> OutputTypes;
|
||||||
|
std::map<std::string, FGTemplateFunc_ptr> TemplateFunctions;
|
||||||
bool enabled;
|
bool enabled;
|
||||||
|
SGPath includePath;
|
||||||
|
|
||||||
void Debug(int from);
|
void Debug(int from);
|
||||||
};
|
};
|
||||||
|
|
|
@ -373,7 +373,7 @@ bool FGPropulsion::Load(Element* el)
|
||||||
Name = "Propulsion Model: " + el->GetAttributeValue("name");
|
Name = "Propulsion Model: " + el->GetAttributeValue("name");
|
||||||
|
|
||||||
// Perform base class Pre-Load
|
// Perform base class Pre-Load
|
||||||
if (!FGModel::Load(el))
|
if (!FGModel::Load(el, true))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Process tank definitions first to establish the number of fuel tanks
|
// Process tank definitions first to establish the number of fuel tanks
|
||||||
|
|
|
@ -128,7 +128,7 @@ public:
|
||||||
Characteristics of the propulsion system are read in from the config file.
|
Characteristics of the propulsion system are read in from the config file.
|
||||||
@param el pointer to an XML element that contains the engine information.
|
@param el pointer to an XML element that contains the engine information.
|
||||||
@return true if successfully loaded, otherwise false */
|
@return true if successfully loaded, otherwise false */
|
||||||
bool Load(Element* el);
|
virtual bool Load(Element* el);
|
||||||
|
|
||||||
/// Retrieves the number of engines defined for the aircraft.
|
/// Retrieves the number of engines defined for the aircraft.
|
||||||
unsigned int GetNumEngines(void) const {return (unsigned int)Engines.size();}
|
unsigned int GetNumEngines(void) const {return (unsigned int)Engines.size();}
|
||||||
|
|
|
@ -57,14 +57,16 @@ IDENT(IdHdr,ID_STANDARDATMOSPHERE);
|
||||||
CLASS IMPLEMENTATION
|
CLASS IMPLEMENTATION
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
FGStandardAtmosphere::FGStandardAtmosphere(FGFDMExec* fdmex) : FGAtmosphere(fdmex),
|
// Effective radius of the earth at a specific latitude per ISA 1976 (converted to ft)
|
||||||
TemperatureBias(0.0),
|
// r0 = 6356766 m
|
||||||
TemperatureDeltaGradient(0.0)
|
const double FGStandardAtmosphere::EarthRadius = 6356766.0/FGJSBBase::fttom;
|
||||||
|
|
||||||
|
FGStandardAtmosphere::FGStandardAtmosphere(FGFDMExec* fdmex)
|
||||||
|
: FGAtmosphere(fdmex), TemperatureBias(0.0), TemperatureDeltaGradient(0.0),
|
||||||
|
StdAtmosTemperatureTable(9)
|
||||||
{
|
{
|
||||||
Name = "FGStandardAtmosphere";
|
Name = "FGStandardAtmosphere";
|
||||||
|
|
||||||
StdAtmosTemperatureTable = new FGTable(9);
|
|
||||||
|
|
||||||
// This is the U.S. Standard Atmosphere table for temperature in degrees
|
// This is the U.S. Standard Atmosphere table for temperature in degrees
|
||||||
// Rankine, based on geometric altitude. The table values are often given
|
// Rankine, based on geometric altitude. The table values are often given
|
||||||
// in literature relative to geopotential altitude.
|
// in literature relative to geopotential altitude.
|
||||||
|
@ -72,36 +74,35 @@ FGStandardAtmosphere::FGStandardAtmosphere(FGFDMExec* fdmex) : FGAtmosphere(fdme
|
||||||
// GeoMet Alt Temp GeoPot Alt GeoMet Alt
|
// GeoMet Alt Temp GeoPot Alt GeoMet Alt
|
||||||
// (ft) (deg R) (km) (km)
|
// (ft) (deg R) (km) (km)
|
||||||
// -------- -------- ---------- ----------
|
// -------- -------- ---------- ----------
|
||||||
//*StdAtmosTemperatureTable << 0.00 << 518.67 // 0.000 0.000
|
//StdAtmosTemperatureTable << 0.00 << 518.67 // 0.000 0.000
|
||||||
// << 36151.80 << 389.97 // 11.000 11.019
|
// << 36151.80 << 389.97 // 11.000 11.019
|
||||||
// << 65823.90 << 389.97 // 20.000 20.063
|
// << 65823.90 << 389.97 // 20.000 20.063
|
||||||
// << 105518.06 << 411.60 // 32.000 32.162
|
// << 105518.06 << 411.60 // 32.000 32.162
|
||||||
// << 155348.07 << 487.20 // 47.000 47.350
|
// << 155348.07 << 487.20 // 47.000 47.350
|
||||||
// << 168676.12 << 487.20 // 51.000 51.413
|
// << 168676.12 << 487.20 // 51.000 51.413
|
||||||
// << 235570.77 << 386.40 // 71.000 71.802
|
// << 235570.77 << 386.40 // 71.000 71.802
|
||||||
// << 282152.08 << 336.50 // 84.852 86.000
|
// << 282152.08 << 336.50 // 84.852 86.000
|
||||||
// << 298556.40 << 336.50; // 91.000 - First layer in high altitude regime
|
// << 298556.40 << 336.50; // 91.000 - First layer in high altitude regime
|
||||||
|
|
||||||
// GeoPot Alt Temp GeoPot Alt GeoMet Alt
|
// GeoPot Alt Temp GeoPot Alt GeoMet Alt
|
||||||
// (ft) (deg R) (km) (km)
|
// (ft) (deg R) (km) (km)
|
||||||
// ----------- -------- ---------- ----------
|
// ----------- -------- ---------- ----------
|
||||||
*StdAtmosTemperatureTable << 0.0000 << 518.67 // 0.000 0.000
|
StdAtmosTemperatureTable << 0.0000 << 518.67 // 0.000 0.000
|
||||||
<< 36089.2388 << 389.97 // 11.000 11.019
|
<< 36089.2388 << 389.97 // 11.000 11.019
|
||||||
<< 65616.7979 << 389.97 // 20.000 20.063
|
<< 65616.7979 << 389.97 // 20.000 20.063
|
||||||
<< 104986.8766 << 411.57 // 32.000 32.162
|
<< 104986.8766 << 411.57 // 32.000 32.162
|
||||||
<< 154199.4751 << 487.17 // 47.000 47.350
|
<< 154199.4751 << 487.17 // 47.000 47.350
|
||||||
<< 167322.8346 << 487.17 // 51.000 51.413
|
<< 167322.8346 << 487.17 // 51.000 51.413
|
||||||
<< 232939.6325 << 386.37 // 71.000 71.802
|
<< 232939.6325 << 386.37 // 71.000 71.802
|
||||||
<< 278385.8268 << 336.50 // 84.852 86.000
|
<< 278385.8268 << 336.5028 // 84.852 86.000
|
||||||
<< 298556.40 << 336.50; // 91.000 - First layer in high altitude regime
|
<< 298556.4304 << 336.5028; // 91.000 - First layer in high altitude regime
|
||||||
|
|
||||||
LapseRateVector.resize(StdAtmosTemperatureTable->GetNumRows()-1);
|
PressureBreakpointVector.resize(StdAtmosTemperatureTable.GetNumRows());
|
||||||
PressureBreakpointVector.resize(StdAtmosTemperatureTable->GetNumRows());
|
|
||||||
|
|
||||||
// Assume the altitude to fade out the gradient at is at the highest
|
// Assume the altitude to fade out the gradient at is at the highest
|
||||||
// altitude in the table. Above that, other functions are used to
|
// altitude in the table. Above that, other functions are used to
|
||||||
// calculate temperature.
|
// calculate temperature.
|
||||||
GradientFadeoutAltitude = (*StdAtmosTemperatureTable)(StdAtmosTemperatureTable->GetNumRows(),0);
|
GradientFadeoutAltitude = StdAtmosTemperatureTable(StdAtmosTemperatureTable.GetNumRows(),0);
|
||||||
|
|
||||||
bind();
|
bind();
|
||||||
Debug(0);
|
Debug(0);
|
||||||
|
@ -111,8 +112,6 @@ FGStandardAtmosphere::FGStandardAtmosphere(FGFDMExec* fdmex) : FGAtmosphere(fdme
|
||||||
|
|
||||||
FGStandardAtmosphere::~FGStandardAtmosphere()
|
FGStandardAtmosphere::~FGStandardAtmosphere()
|
||||||
{
|
{
|
||||||
delete StdAtmosTemperatureTable;
|
|
||||||
LapseRateVector.clear();
|
|
||||||
Debug(1);
|
Debug(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,16 +119,22 @@ FGStandardAtmosphere::~FGStandardAtmosphere()
|
||||||
|
|
||||||
bool FGStandardAtmosphere::InitModel(void)
|
bool FGStandardAtmosphere::InitModel(void)
|
||||||
{
|
{
|
||||||
PressureBreakpointVector[0] = StdSLpressure = 2116.22; // psf
|
PressureBreakpointVector[0] = StdSLpressure = SLpressure = Pressure = 2116.228; // psf
|
||||||
TemperatureDeltaGradient = 0.0;
|
TemperatureDeltaGradient = 0.0;
|
||||||
TemperatureBias = 0.0;
|
TemperatureBias = 0.0;
|
||||||
CalculateLapseRates();
|
CalculateLapseRates();
|
||||||
CalculatePressureBreakpoints();
|
CalculatePressureBreakpoints();
|
||||||
|
|
||||||
|
StdSLtemperature = SLtemperature = StdAtmosTemperatureTable(1, 1);
|
||||||
|
StdSLdensity = SLdensity = StdSLpressure / (Reng * StdSLtemperature);
|
||||||
|
|
||||||
|
StdPressureBreakpointVector = PressureBreakpointVector;
|
||||||
|
|
||||||
|
CalculateStdDensityBreakpoints();
|
||||||
|
|
||||||
Calculate(0.0);
|
Calculate(0.0);
|
||||||
StdSLtemperature = SLtemperature = Temperature;
|
|
||||||
SLpressure = Pressure;
|
StdSLsoundspeed = SLsoundspeed = Soundspeed;
|
||||||
StdSLdensity = SLdensity = Density;
|
|
||||||
StdSLsoundspeed = SLsoundspeed = Soundspeed;
|
|
||||||
|
|
||||||
rSLtemperature = 1/SLtemperature ;
|
rSLtemperature = 1/SLtemperature ;
|
||||||
rSLpressure = 1/SLpressure ;
|
rSLpressure = 1/SLpressure ;
|
||||||
|
@ -143,43 +148,39 @@ bool FGStandardAtmosphere::InitModel(void)
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
// Get the actual pressure as modeled at a specified altitude
|
// Get the actual pressure as modeled at a specified altitude
|
||||||
// These calculations are from equations 33a and 33b in the U.S. Standard Atmosphere
|
// These calculations are from equations 33a and 33b in the U.S. Standard
|
||||||
// document referenced in the documentation for this code.
|
// Atmosphere document referenced in the documentation for this code.
|
||||||
|
|
||||||
double FGStandardAtmosphere::GetPressure(double altitude) const
|
double FGStandardAtmosphere::GetPressure(double altitude) const
|
||||||
{
|
{
|
||||||
unsigned int b=0;
|
double GeoPotAlt = GeopotentialAltitude(altitude);
|
||||||
double pressure = 0.0;
|
|
||||||
double Lmb, Exp, Tmb, deltaH, factor;
|
|
||||||
double numRows = StdAtmosTemperatureTable->GetNumRows();
|
|
||||||
|
|
||||||
// Iterate through the altitudes to find the current Base Altitude
|
// Iterate through the altitudes to find the current Base Altitude
|
||||||
// in the table. That is, if the current altitude (the argument passed in)
|
// in the table. That is, if the current altitude (the argument passed in)
|
||||||
// is 20000 ft, then the base altitude from the table is 0.0. If the
|
// is 20000 ft, then the base altitude from the table is 0.0. If the
|
||||||
// passed-in altitude is 40000 ft, the base altitude is 36089.2388 ft (and
|
// passed-in altitude is 40000 ft, the base altitude is 36089.2388 ft (and
|
||||||
// the index "b" is 2 - the second entry in the table).
|
// the index "b" is 2 - the second entry in the table).
|
||||||
double testAlt = (*StdAtmosTemperatureTable)(b+1,0);
|
double BaseAlt = StdAtmosTemperatureTable(1,0);
|
||||||
double GeoPotAlt = (altitude*20855531.5)/(20855531.5+altitude);
|
unsigned int numRows = StdAtmosTemperatureTable.GetNumRows();
|
||||||
while ((GeoPotAlt >= testAlt) && (b <= numRows-2)) {
|
unsigned int b;
|
||||||
b++;
|
|
||||||
testAlt = (*StdAtmosTemperatureTable)(b+1,0);
|
|
||||||
}
|
|
||||||
if (b>0) b--;
|
|
||||||
|
|
||||||
double BaseAlt = (*StdAtmosTemperatureTable)(b+1,0);
|
for (b=0; b < numRows-2; ++b) {
|
||||||
Tmb = GetTemperature(BaseAlt);
|
double testAlt = StdAtmosTemperatureTable(b+2,0);
|
||||||
deltaH = GeoPotAlt - BaseAlt;
|
if (GeoPotAlt < testAlt)
|
||||||
|
break;
|
||||||
if (LapseRateVector[b] != 0.00) {
|
BaseAlt = testAlt;
|
||||||
Lmb = LapseRateVector[b];
|
|
||||||
Exp = Mair/(Rstar*Lmb);
|
|
||||||
factor = Tmb/(Tmb + Lmb*deltaH);
|
|
||||||
pressure = PressureBreakpointVector[b]*pow(factor, Exp);
|
|
||||||
} else {
|
|
||||||
pressure = PressureBreakpointVector[b]*exp(-Mair*deltaH/(Rstar*Tmb));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return pressure;
|
double Tmb = GetTemperature(GeometricAltitude(BaseAlt));
|
||||||
|
double deltaH = GeoPotAlt - BaseAlt;
|
||||||
|
double Lmb = LapseRateVector[b];
|
||||||
|
|
||||||
|
if (Lmb != 0.0) {
|
||||||
|
double Exp = g0*Mair / (Rstar*Lmb);
|
||||||
|
double factor = Tmb/(Tmb + Lmb*deltaH);
|
||||||
|
return PressureBreakpointVector[b]*pow(factor, Exp);
|
||||||
|
} else
|
||||||
|
return PressureBreakpointVector[b]*exp(-g0*Mair*deltaH/(Rstar*Tmb));
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -198,11 +199,23 @@ void FGStandardAtmosphere::SetPressureSL(ePressure unit, double pressure)
|
||||||
|
|
||||||
double FGStandardAtmosphere::GetTemperature(double altitude) const
|
double FGStandardAtmosphere::GetTemperature(double altitude) const
|
||||||
{
|
{
|
||||||
double GeoPotAlt = (altitude*20855531.5)/(20855531.5+altitude);
|
double GeoPotAlt = GeopotentialAltitude(altitude);
|
||||||
|
|
||||||
double T = StdAtmosTemperatureTable->GetValue(GeoPotAlt) + TemperatureBias;
|
double T;
|
||||||
if (altitude <= GradientFadeoutAltitude)
|
|
||||||
T += TemperatureDeltaGradient * (GradientFadeoutAltitude - altitude);
|
if (GeoPotAlt >= 0.0) {
|
||||||
|
T = StdAtmosTemperatureTable.GetValue(GeoPotAlt);
|
||||||
|
|
||||||
|
if (GeoPotAlt <= GradientFadeoutAltitude)
|
||||||
|
T -= TemperatureDeltaGradient * GeoPotAlt;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// We don't need to add TemperatureDeltaGradient*GeoPotAlt here because
|
||||||
|
// the lapse rate vector already accounts for the temperature gradient.
|
||||||
|
T = StdAtmosTemperatureTable.GetValue(0.0) + GeoPotAlt*LapseRateVector[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
T += TemperatureBias + TemperatureDeltaGradient * GradientFadeoutAltitude;
|
||||||
|
|
||||||
return T;
|
return T;
|
||||||
}
|
}
|
||||||
|
@ -218,8 +231,12 @@ double FGStandardAtmosphere::GetStdTemperature(double altitude) const
|
||||||
|
|
||||||
if (altitude < 298556.4) { // 91 km - station 8
|
if (altitude < 298556.4) { // 91 km - station 8
|
||||||
|
|
||||||
double GeoPotAlt = (altitude*20855531.5)/(20855531.5+altitude);
|
double GeoPotAlt = GeopotentialAltitude(altitude);
|
||||||
temp = StdAtmosTemperatureTable->GetValue(GeoPotAlt);
|
|
||||||
|
if (GeoPotAlt >= 0.0)
|
||||||
|
temp = StdAtmosTemperatureTable.GetValue(GeoPotAlt);
|
||||||
|
else
|
||||||
|
temp = StdAtmosTemperatureTable.GetValue(0.0) + GeoPotAlt*LapseRateVector[0];
|
||||||
|
|
||||||
} else if (altitude < 360892.4) { // 110 km - station 9
|
} else if (altitude < 360892.4) { // 110 km - station 9
|
||||||
|
|
||||||
|
@ -244,42 +261,34 @@ double FGStandardAtmosphere::GetStdTemperature(double altitude) const
|
||||||
|
|
||||||
double FGStandardAtmosphere::GetStdPressure(double altitude) const
|
double FGStandardAtmosphere::GetStdPressure(double altitude) const
|
||||||
{
|
{
|
||||||
double press=0;
|
double GeoPotAlt = GeopotentialAltitude(altitude);
|
||||||
if (TemperatureBias == 0.0 && TemperatureDeltaGradient == 0.0 && PressureBreakpointVector[0] == StdSLpressure) {
|
|
||||||
press = GetPressure(altitude);
|
// Iterate through the altitudes to find the current Base Altitude
|
||||||
} else if (altitude <= 100000.0) {
|
// in the table. That is, if the current altitude (the argument passed in)
|
||||||
GetStdPressure100K(altitude);
|
// is 20000 ft, then the base altitude from the table is 0.0. If the
|
||||||
} else {
|
// passed-in altitude is 40000 ft, the base altitude is 36089.2388 ft (and
|
||||||
// Cannot currently retrieve the standard pressure
|
// the index "b" is 2 - the second entry in the table).
|
||||||
|
double BaseAlt = StdAtmosTemperatureTable(1,0);
|
||||||
|
unsigned int numRows = StdAtmosTemperatureTable.GetNumRows();
|
||||||
|
unsigned int b;
|
||||||
|
|
||||||
|
for (b=0; b < numRows-2; ++b) {
|
||||||
|
double testAlt = StdAtmosTemperatureTable(b+2,0);
|
||||||
|
if (GeoPotAlt < testAlt)
|
||||||
|
break;
|
||||||
|
BaseAlt = testAlt;
|
||||||
}
|
}
|
||||||
return press;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
double Tmb = GetStdTemperature(GeometricAltitude(BaseAlt));
|
||||||
// This function calculates an approximation of the standard atmospheric pressure
|
double deltaH = GeoPotAlt - BaseAlt;
|
||||||
// up to an altitude of about 100,000 ft. If the temperature and pressure are not
|
double Lmb = LapseRateVector[b];
|
||||||
// altered for local conditions, the GetPressure(h) function should be used,
|
|
||||||
// as that is valid to a much higher altitude. This function is accurate to within
|
|
||||||
// a couple of psf up to 100K ft. This polynomial fit was determined using Excel.
|
|
||||||
|
|
||||||
double FGStandardAtmosphere::GetStdPressure100K(double altitude) const
|
if (Lmb != 0.0) {
|
||||||
{
|
double Exp = g0*Mair / (Rstar*Lmb);
|
||||||
// Limit this equation to input altitudes of 100000 ft.
|
double factor = Tmb/(Tmb + Lmb*deltaH);
|
||||||
if (altitude > 100000.0) altitude = 100000.0;
|
return StdPressureBreakpointVector[b]*pow(factor, Exp);
|
||||||
|
} else
|
||||||
double alt[5];
|
return StdPressureBreakpointVector[b]*exp(-g0*Mair*deltaH/(Rstar*Tmb));
|
||||||
const double coef[5] = { 2116.217,
|
|
||||||
-7.648932746E-2,
|
|
||||||
1.0925498604E-6,
|
|
||||||
-7.1135726027E-12,
|
|
||||||
1.7470331356E-17 };
|
|
||||||
|
|
||||||
alt[0] = 1;
|
|
||||||
for (int pwr=1; pwr<=4; pwr++) alt[pwr] = alt[pwr-1]*altitude;
|
|
||||||
|
|
||||||
double press = 0.0;
|
|
||||||
for (int ctr=0; ctr<=4; ctr++) press += coef[ctr]*alt[ctr];
|
|
||||||
return press;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -343,7 +352,7 @@ void FGStandardAtmosphere::SetTemperatureGradedDelta(double deltemp, double h, e
|
||||||
if (unit == eCelsius || unit == eKelvin)
|
if (unit == eCelsius || unit == eKelvin)
|
||||||
deltemp *= 1.80; // If temp delta "t" is given in metric, scale up to English
|
deltemp *= 1.80; // If temp delta "t" is given in metric, scale up to English
|
||||||
|
|
||||||
TemperatureDeltaGradient = deltemp/(GradientFadeoutAltitude - h);
|
TemperatureDeltaGradient = deltemp/(GradientFadeoutAltitude - GeopotentialAltitude(h));
|
||||||
CalculateLapseRates();
|
CalculateLapseRates();
|
||||||
CalculatePressureBreakpoints();
|
CalculatePressureBreakpoints();
|
||||||
}
|
}
|
||||||
|
@ -376,13 +385,16 @@ void FGStandardAtmosphere::SetTemperatureGradedDelta(double deltemp, double h, e
|
||||||
|
|
||||||
void FGStandardAtmosphere::CalculateLapseRates()
|
void FGStandardAtmosphere::CalculateLapseRates()
|
||||||
{
|
{
|
||||||
for (unsigned int bh=0; bh<LapseRateVector.size(); bh++)
|
unsigned int numRows = StdAtmosTemperatureTable.GetNumRows();
|
||||||
|
LapseRateVector.clear();
|
||||||
|
|
||||||
|
for (unsigned int bh=0; bh < numRows-1; bh++)
|
||||||
{
|
{
|
||||||
double t0 = (*StdAtmosTemperatureTable)(bh+1,1);
|
double t0 = StdAtmosTemperatureTable(bh+1,1);
|
||||||
double t1 = (*StdAtmosTemperatureTable)(bh+2,1);
|
double t1 = StdAtmosTemperatureTable(bh+2,1);
|
||||||
double h0 = (*StdAtmosTemperatureTable)(bh+1,0);
|
double h0 = StdAtmosTemperatureTable(bh+1,0);
|
||||||
double h1 = (*StdAtmosTemperatureTable)(bh+2,0);
|
double h1 = StdAtmosTemperatureTable(bh+2,0);
|
||||||
LapseRateVector[bh] = (t1 - t0) / (h1 - h0) + TemperatureDeltaGradient;
|
LapseRateVector.push_back((t1 - t0) / (h1 - h0) - TemperatureDeltaGradient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -391,20 +403,20 @@ void FGStandardAtmosphere::CalculateLapseRates()
|
||||||
void FGStandardAtmosphere::CalculatePressureBreakpoints()
|
void FGStandardAtmosphere::CalculatePressureBreakpoints()
|
||||||
{
|
{
|
||||||
for (unsigned int b=0; b<PressureBreakpointVector.size()-1; b++) {
|
for (unsigned int b=0; b<PressureBreakpointVector.size()-1; b++) {
|
||||||
double BaseTemp = (*StdAtmosTemperatureTable)(b+1,1);
|
double BaseTemp = StdAtmosTemperatureTable(b+1,1);
|
||||||
double BaseAlt = (*StdAtmosTemperatureTable)(b+1,0);
|
double BaseAlt = StdAtmosTemperatureTable(b+1,0);
|
||||||
double UpperAlt = (*StdAtmosTemperatureTable)(b+2,0);
|
double UpperAlt = StdAtmosTemperatureTable(b+2,0);
|
||||||
double deltaH = UpperAlt - BaseAlt;
|
double deltaH = UpperAlt - BaseAlt;
|
||||||
double Tmb = BaseTemp
|
double Tmb = BaseTemp
|
||||||
+ TemperatureBias
|
+ TemperatureBias
|
||||||
+ (GradientFadeoutAltitude - BaseAlt)*TemperatureDeltaGradient;
|
+ (GradientFadeoutAltitude - BaseAlt)*TemperatureDeltaGradient;
|
||||||
if (LapseRateVector[b] != 0.00) {
|
if (LapseRateVector[b] != 0.00) {
|
||||||
double Lmb = LapseRateVector[b];
|
double Lmb = LapseRateVector[b];
|
||||||
double Exp = Mair/(Rstar*Lmb);
|
double Exp = g0*Mair / (Rstar*Lmb);
|
||||||
double factor = Tmb/(Tmb + Lmb*deltaH);
|
double factor = Tmb/(Tmb + Lmb*deltaH);
|
||||||
PressureBreakpointVector[b+1] = PressureBreakpointVector[b]*pow(factor, Exp);
|
PressureBreakpointVector[b+1] = PressureBreakpointVector[b]*pow(factor, Exp);
|
||||||
} else {
|
} else {
|
||||||
PressureBreakpointVector[b+1] = PressureBreakpointVector[b]*exp(-Mair*deltaH/(Rstar*Tmb));
|
PressureBreakpointVector[b+1] = PressureBreakpointVector[b]*exp(-g0*Mair*deltaH/(Rstar*Tmb));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -428,6 +440,85 @@ void FGStandardAtmosphere::ResetSLPressure()
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGStandardAtmosphere::CalculateStdDensityBreakpoints()
|
||||||
|
{
|
||||||
|
StdDensityBreakpointVector.clear();
|
||||||
|
for (unsigned int i = 0; i < StdPressureBreakpointVector.size(); i++) {
|
||||||
|
StdDensityBreakpointVector.push_back(StdPressureBreakpointVector[i] / (Reng * StdAtmosTemperatureTable(i + 1, 1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
double FGStandardAtmosphere::CalculateDensityAltitude(double density, double geometricAlt)
|
||||||
|
{
|
||||||
|
// Work out which layer we're dealing with
|
||||||
|
unsigned int b = 0;
|
||||||
|
for (; b < StdDensityBreakpointVector.size() - 2; b++) {
|
||||||
|
if (density >= StdDensityBreakpointVector[b + 1])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get layer properties
|
||||||
|
double Tmb = StdAtmosTemperatureTable(b + 1, 1);
|
||||||
|
double Hb = StdAtmosTemperatureTable(b + 1, 0);
|
||||||
|
double UpperTemp = StdAtmosTemperatureTable(b + 2, 1);
|
||||||
|
double UpperAlt = StdAtmosTemperatureTable(b + 2, 0);
|
||||||
|
double deltaH = UpperAlt - Hb;
|
||||||
|
double Lmb = (UpperTemp - Tmb) / deltaH;
|
||||||
|
double pb = StdDensityBreakpointVector[b];
|
||||||
|
|
||||||
|
double density_altitude = 0.0;
|
||||||
|
|
||||||
|
// https://en.wikipedia.org/wiki/Barometric_formula for density solved for H
|
||||||
|
if (Lmb != 0.0) {
|
||||||
|
double Exp = -1.0 / (1.0 + (g0*Mair)/(Rstar*Lmb));
|
||||||
|
density_altitude = Hb + (Tmb / Lmb) * (pow(density / pb, Exp) - 1);
|
||||||
|
} else {
|
||||||
|
double Factor = -(Rstar*Tmb) / (g0*Mair);
|
||||||
|
density_altitude = Hb + Factor * log(density / pb);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GeometricAltitude(density_altitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
double FGStandardAtmosphere::CalculatePressureAltitude(double pressure, double geometricAlt)
|
||||||
|
{
|
||||||
|
// Work out which layer we're dealing with
|
||||||
|
unsigned int b = 0;
|
||||||
|
for (; b < StdPressureBreakpointVector.size() - 2; b++) {
|
||||||
|
if (pressure >= StdPressureBreakpointVector[b + 1])
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get layer properties
|
||||||
|
double Tmb = StdAtmosTemperatureTable(b + 1, 1);
|
||||||
|
double Hb = StdAtmosTemperatureTable(b + 1, 0);
|
||||||
|
double UpperTemp = StdAtmosTemperatureTable(b + 2, 1);
|
||||||
|
double UpperAlt = StdAtmosTemperatureTable(b + 2, 0);
|
||||||
|
double deltaH = UpperAlt - Hb;
|
||||||
|
double Lmb = (UpperTemp - Tmb) / deltaH;
|
||||||
|
double Pb = StdPressureBreakpointVector[b];
|
||||||
|
|
||||||
|
double pressure_altitude = 0.0;
|
||||||
|
|
||||||
|
if (Lmb != 0.00) {
|
||||||
|
// Equation 33(a) from ISA document solved for H
|
||||||
|
double Exp = -(Rstar*Lmb) / (g0*Mair);
|
||||||
|
pressure_altitude = Hb + (Tmb / Lmb) * (pow(pressure / Pb, Exp) - 1);
|
||||||
|
} else {
|
||||||
|
// Equation 33(b) from ISA document solved for H
|
||||||
|
double Factor = -(Rstar*Tmb) / (g0*Mair);
|
||||||
|
pressure_altitude = Hb + Factor * log(pressure / Pb);
|
||||||
|
}
|
||||||
|
|
||||||
|
return GeometricAltitude(pressure_altitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
void FGStandardAtmosphere::bind(void)
|
void FGStandardAtmosphere::bind(void)
|
||||||
{
|
{
|
||||||
typedef double (FGStandardAtmosphere::*PMFi)(int) const;
|
typedef double (FGStandardAtmosphere::*PMFi)(int) const;
|
||||||
|
|
|
@ -217,9 +217,6 @@ public:
|
||||||
/// Returns the pressure at a specified altitude in psf.
|
/// Returns the pressure at a specified altitude in psf.
|
||||||
virtual double GetPressure(double altitude) const;
|
virtual double GetPressure(double altitude) const;
|
||||||
|
|
||||||
/// Returns the standard pressure at a specified altitude in psf
|
|
||||||
virtual double GetStdPressure100K(double altitude) const;
|
|
||||||
|
|
||||||
/// Returns the standard pressure at the specified altitude.
|
/// Returns the standard pressure at the specified altitude.
|
||||||
virtual double GetStdPressure(double altitude) const;
|
virtual double GetStdPressure(double altitude) const;
|
||||||
|
|
||||||
|
@ -253,9 +250,11 @@ protected:
|
||||||
double TemperatureDeltaGradient;
|
double TemperatureDeltaGradient;
|
||||||
double GradientFadeoutAltitude;
|
double GradientFadeoutAltitude;
|
||||||
|
|
||||||
FGTable* StdAtmosTemperatureTable;
|
FGTable StdAtmosTemperatureTable;
|
||||||
std::vector<double> LapseRateVector;
|
std::vector<double> LapseRateVector;
|
||||||
std::vector<double> PressureBreakpointVector;
|
std::vector<double> PressureBreakpointVector;
|
||||||
|
std::vector<double> StdPressureBreakpointVector;
|
||||||
|
std::vector<double> StdDensityBreakpointVector;
|
||||||
|
|
||||||
/// Recalculate the lapse rate vectors when the temperature profile is altered
|
/// Recalculate the lapse rate vectors when the temperature profile is altered
|
||||||
/// in a way that would change the lapse rates, such as when a gradient is applied.
|
/// in a way that would change the lapse rates, such as when a gradient is applied.
|
||||||
|
@ -266,8 +265,42 @@ protected:
|
||||||
/// altitudes in the standard temperature table.
|
/// altitudes in the standard temperature table.
|
||||||
void CalculatePressureBreakpoints();
|
void CalculatePressureBreakpoints();
|
||||||
|
|
||||||
|
/// Calculate the atmospheric density breakpoints at the
|
||||||
|
/// altitudes in the standard temperature table.
|
||||||
|
void CalculateStdDensityBreakpoints();
|
||||||
|
|
||||||
|
/// Convert a geometric altitude to a geopotential altitude
|
||||||
|
double GeopotentialAltitude(double geometalt) const { return (geometalt * EarthRadius) / (EarthRadius + geometalt); }
|
||||||
|
|
||||||
|
/// Convert a geopotential altitude to a geometric altitude
|
||||||
|
double GeometricAltitude(double geopotalt) const { return (geopotalt * EarthRadius) / (EarthRadius - geopotalt); }
|
||||||
|
|
||||||
|
/** Calculates the density altitude given any temperature or pressure bias.
|
||||||
|
Calculated density for the specified geometric altitude given any temperature
|
||||||
|
or pressure biases is passed in.
|
||||||
|
@param density
|
||||||
|
@param geometricAlt
|
||||||
|
@see
|
||||||
|
https://en.wikipedia.org/wiki/Density_altitude
|
||||||
|
https://wahiduddin.net/calc/density_altitude.htm
|
||||||
|
*/
|
||||||
|
virtual double CalculateDensityAltitude(double density, double geometricAlt);
|
||||||
|
|
||||||
|
/** Calculates the pressure altitude given any temperature or pressure bias.
|
||||||
|
Calculated density for the specified geometric altitude given any temperature
|
||||||
|
or pressure biases is passed in.
|
||||||
|
@param pressure
|
||||||
|
@param geometricAlt
|
||||||
|
@see
|
||||||
|
https://en.wikipedia.org/wiki/Pressure_altitude
|
||||||
|
*/
|
||||||
|
virtual double CalculatePressureAltitude(double pressure, double geometricAlt);
|
||||||
|
|
||||||
virtual void bind(void);
|
virtual void bind(void);
|
||||||
void Debug(int from);
|
void Debug(int from);
|
||||||
|
|
||||||
|
/// Earth radius in ft as defined for ISA 1976
|
||||||
|
static const double EarthRadius;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace JSBSim
|
} // namespace JSBSim
|
||||||
|
|
|
@ -43,7 +43,7 @@ INCLUDES
|
||||||
DEFINITIONS
|
DEFINITIONS
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
#define ID_DEADBAND "$Id: FGDeadBand.h,v 1.10 2013/01/26 17:06:50 bcoconni Exp $"
|
#define ID_DEADBAND "$Id$"
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
FORWARD DECLARATIONS
|
FORWARD DECLARATIONS
|
||||||
|
@ -79,7 +79,7 @@ CLASS DOCUMENTATION
|
||||||
produce no output. For example, say that the width value is 2.0. If the
|
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.
|
input is between -1.0 and +1.0, the output will be zero.
|
||||||
@author Jon S. Berndt
|
@author Jon S. Berndt
|
||||||
@version $Id: FGDeadBand.h,v 1.10 2013/01/26 17:06:50 bcoconni Exp $
|
@version $Id$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
|
@ -44,7 +44,7 @@ INCLUDES
|
||||||
DEFINITIONS
|
DEFINITIONS
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
#define ID_GAIN "$Id: FGGain.h,v 1.15 2013/01/26 17:06:50 bcoconni Exp $"
|
#define ID_GAIN "$Id$"
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
FORWARD DECLARATIONS
|
FORWARD DECLARATIONS
|
||||||
|
@ -208,7 +208,7 @@ CLASS DOCUMENTATION
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
@author Jon S. Berndt
|
@author Jon S. Berndt
|
||||||
@version $Revision: 1.15 $
|
@version $Revision$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
|
@ -64,6 +64,7 @@ CLASS DOCUMENTATION
|
||||||
|
|
||||||
~~~{.xml}
|
~~~{.xml}
|
||||||
<sense> {1 | -1} </sense>
|
<sense> {1 | -1} </sense>
|
||||||
|
<p_factor> {number} </p_factor>
|
||||||
<propeller name="{string}" version="{string}">
|
<propeller name="{string}" version="{string}">
|
||||||
<ixx> {number} </ixx>
|
<ixx> {number} </ixx>
|
||||||
<diameter unit="IN"> {number} </diameter>
|
<diameter unit="IN"> {number} </diameter>
|
||||||
|
@ -75,7 +76,6 @@ CLASS DOCUMENTATION
|
||||||
<maxrpm> {number} </maxrpm>
|
<maxrpm> {number} </maxrpm>
|
||||||
<constspeed> {number} </constspeed>
|
<constspeed> {number} </constspeed>
|
||||||
<reversepitch> {number} </reversepitch>
|
<reversepitch> {number} </reversepitch>
|
||||||
<p_factor> {number} </p_factor>
|
|
||||||
<ct_factor> {number} </ct_factor>
|
<ct_factor> {number} </ct_factor>
|
||||||
<cp_factor> {number} </cp_factor>
|
<cp_factor> {number} </cp_factor>
|
||||||
|
|
||||||
|
@ -122,7 +122,8 @@ CLASS DOCUMENTATION
|
||||||
\<sense> - Direction of rotation (1=clockwise as viewed from cockpit,
|
\<sense> - Direction of rotation (1=clockwise as viewed from cockpit,
|
||||||
-1=anti-clockwise as viewed from cockpit). Sense is
|
-1=anti-clockwise as viewed from cockpit). Sense is
|
||||||
specified in the parent tag of the propeller.
|
specified in the parent tag of the propeller.
|
||||||
\<p_factor> - P factor.
|
\<p_factor> - P factor. It is specified in the parent tag of
|
||||||
|
the propeller.
|
||||||
\<ct_factor> - A multiplier for the coefficients of thrust.
|
\<ct_factor> - A multiplier for the coefficients of thrust.
|
||||||
\<cp_factor> - A multiplier for the coefficients of power.
|
\<cp_factor> - A multiplier for the coefficients of power.
|
||||||
</pre>
|
</pre>
|
||||||
|
@ -133,6 +134,11 @@ coefficient of power (Cp).
|
||||||
Two tables are optional. They apply a factor to Ct and Cp based on the
|
Two tables are optional. They apply a factor to Ct and Cp based on the
|
||||||
helical tip Mach.
|
helical tip Mach.
|
||||||
|
|
||||||
|
The parameters <sense> and <p_factor> must be specified at the parent level i.e.
|
||||||
|
in the <thruster> element. This allows to specify different sense and P factor
|
||||||
|
values for each propeller of the model while using the same definition file for
|
||||||
|
all the propellers.
|
||||||
|
|
||||||
In addition to thrust, the propeller applies two moments to the aircraft:
|
In addition to thrust, the propeller applies two moments to the aircraft:
|
||||||
- The torque that tends to roll the aircraft in the direction opposite to the
|
- The torque that tends to roll the aircraft in the direction opposite to the
|
||||||
propeller rotation,
|
propeller rotation,
|
||||||
|
|
Loading…
Reference in a new issue