Sync w. JSBSim CVS (merge from PRE_OSG_PLIB_20061029 branch)
This commit is contained in:
parent
2c3dc5fca1
commit
3cda82e0a9
56 changed files with 985 additions and 503 deletions
|
@ -134,6 +134,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root)
|
|||
modelLoaded = false;
|
||||
IsSlave = false;
|
||||
holding = false;
|
||||
Terminate = false;
|
||||
|
||||
// Multiple FDM's are stopped for now. We need to ensure that
|
||||
// the "user" instance always gets the zeroeth instance number,
|
||||
|
@ -168,6 +169,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root)
|
|||
Constructing = true;
|
||||
typedef int (FGFDMExec::*iPMF)(void) const;
|
||||
instance->Tie("simulation/do_trim", this, (iPMF)0, &FGFDMExec::DoTrim);
|
||||
instance->Tie("simulation/terminate", (int *)&Terminate);
|
||||
Constructing = false;
|
||||
}
|
||||
|
||||
|
@ -176,6 +178,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root)
|
|||
FGFDMExec::~FGFDMExec()
|
||||
{
|
||||
instance->Untie("simulation/do_trim");
|
||||
instance->Untie("simulation/terminate");
|
||||
|
||||
try {
|
||||
DeAllocate();
|
||||
|
@ -354,7 +357,7 @@ int FGFDMExec::Schedule(FGModel* model, int rate)
|
|||
|
||||
bool FGFDMExec::Run(void)
|
||||
{
|
||||
bool success = false;
|
||||
bool success=false;
|
||||
FGModel* model_iterator;
|
||||
|
||||
model_iterator = FirstModel;
|
||||
|
@ -376,6 +379,7 @@ bool FGFDMExec::Run(void)
|
|||
|
||||
Frame++;
|
||||
if (!Holding()) State->IncrTime();
|
||||
if (Terminate) success = false;
|
||||
return (success);
|
||||
}
|
||||
|
||||
|
@ -459,6 +463,9 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath)
|
|||
string token;
|
||||
string aircraftCfgFileName;
|
||||
string separator = "/";
|
||||
Element* element = 0L;
|
||||
|
||||
modelName = model; // Set the class modelName attribute
|
||||
|
||||
# ifdef macintosh
|
||||
separator = ";";
|
||||
|
@ -474,27 +481,12 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath)
|
|||
if (addModelToPath) FullAircraftPath += separator + model;
|
||||
aircraftCfgFileName = FullAircraftPath + separator + model + ".xml";
|
||||
|
||||
FGXMLParse *XMLParse = new FGXMLParse();
|
||||
Element* element = 0L;
|
||||
Element* document;
|
||||
|
||||
ifstream input_file(aircraftCfgFileName.c_str());
|
||||
|
||||
if (!input_file.is_open()) { // file open failed
|
||||
cerr << "Could not open file " << aircraftCfgFileName.c_str() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
readXML(input_file, *XMLParse);
|
||||
document = XMLParse->GetDocument();
|
||||
|
||||
modelName = model;
|
||||
|
||||
if (modelLoaded) {
|
||||
DeAllocate();
|
||||
Allocate();
|
||||
}
|
||||
|
||||
document = LoadXMLDocument(aircraftCfgFileName); // "document" is a class member
|
||||
ReadPrologue(document);
|
||||
element = document->GetElement();
|
||||
|
||||
|
@ -553,7 +545,7 @@ void FGFDMExec::BuildPropertyCatalog(struct PropertyCatalogStructure* pcs)
|
|||
int node_idx = 0;
|
||||
char int_buf[10];
|
||||
|
||||
for (int i=0; i<pcs->node->nChildren(); i++) {
|
||||
for (unsigned int i=0; i<pcs->node->nChildren(); i++) {
|
||||
pcsNew->base_string = pcs->base_string + "/" + pcs->node->getChild(i)->getName();
|
||||
node_idx = pcs->node->getChild(i)->getIndex();
|
||||
sprintf(int_buf, "[%d]", node_idx);
|
||||
|
|
|
@ -48,8 +48,8 @@ INCLUDES
|
|||
#include <initialization/FGInitialCondition.h>
|
||||
#include <FGJSBBase.h>
|
||||
#include <input_output/FGPropertyManager.h>
|
||||
#include <input_output/FGXMLParse.h>
|
||||
#include <input_output/FGGroundCallback.h>
|
||||
#include <input_output/FGXMLFileRead.h>
|
||||
#include <models/FGPropagate.h>
|
||||
|
||||
#include <vector>
|
||||
|
@ -173,7 +173,7 @@ CLASS DOCUMENTATION
|
|||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class FGFDMExec : public FGJSBBase
|
||||
class FGFDMExec : public FGJSBBase, public FGXMLFileRead
|
||||
{
|
||||
public:
|
||||
|
||||
|
@ -414,6 +414,7 @@ private:
|
|||
int Error;
|
||||
unsigned int Frame;
|
||||
unsigned int IdFDM;
|
||||
unsigned short Terminate;
|
||||
bool holding;
|
||||
bool Constructing;
|
||||
bool modelLoaded;
|
||||
|
|
|
@ -94,9 +94,9 @@ const double FGJSBBase::slugtolb = 32.174049;
|
|||
const double FGJSBBase::lbtoslug = 1.0/slugtolb;
|
||||
|
||||
const string FGJSBBase::needed_cfg_version = "2.0";
|
||||
const string FGJSBBase::JSBSim_version = "0.9.12 "__DATE__" "__TIME__;
|
||||
const string FGJSBBase::JSBSim_version = "Pre-1.0 "__DATE__" "__TIME__;
|
||||
|
||||
std::queue <FGJSBBase::Message*> FGJSBBase::Messages;
|
||||
std::queue <FGJSBBase::Message> FGJSBBase::Messages;
|
||||
FGJSBBase::Message FGJSBBase::localMsg;
|
||||
unsigned int FGJSBBase::messageId = 0;
|
||||
|
||||
|
@ -104,83 +104,75 @@ short FGJSBBase::debug_lvl = 1;
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGJSBBase::Message* FGJSBBase::PutMessage(Message* msg)
|
||||
void FGJSBBase::PutMessage(const Message& msg)
|
||||
{
|
||||
Messages.push(msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGJSBBase::Message* FGJSBBase::PutMessage(const string& text)
|
||||
void FGJSBBase::PutMessage(const string& text)
|
||||
{
|
||||
Message *msg = new Message();
|
||||
msg->text = text;
|
||||
msg->messageId = messageId++;
|
||||
msg->subsystem = "FDM";
|
||||
msg->type = Message::eText;
|
||||
Message msg;
|
||||
msg.text = text;
|
||||
msg.messageId = messageId++;
|
||||
msg.subsystem = "FDM";
|
||||
msg.type = Message::eText;
|
||||
Messages.push(msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGJSBBase::Message* FGJSBBase::PutMessage(const string& text, bool bVal)
|
||||
void FGJSBBase::PutMessage(const string& text, bool bVal)
|
||||
{
|
||||
Message *msg = new Message();
|
||||
msg->text = text;
|
||||
msg->messageId = messageId++;
|
||||
msg->subsystem = "FDM";
|
||||
msg->type = Message::eBool;
|
||||
msg->bVal = bVal;
|
||||
Message msg;
|
||||
msg.text = text;
|
||||
msg.messageId = messageId++;
|
||||
msg.subsystem = "FDM";
|
||||
msg.type = Message::eBool;
|
||||
msg.bVal = bVal;
|
||||
Messages.push(msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGJSBBase::Message* FGJSBBase::PutMessage(const string& text, int iVal)
|
||||
void FGJSBBase::PutMessage(const string& text, int iVal)
|
||||
{
|
||||
Message *msg = new Message();
|
||||
msg->text = text;
|
||||
msg->messageId = messageId++;
|
||||
msg->subsystem = "FDM";
|
||||
msg->type = Message::eInteger;
|
||||
msg->bVal = (iVal != 0);
|
||||
Message msg;
|
||||
msg.text = text;
|
||||
msg.messageId = messageId++;
|
||||
msg.subsystem = "FDM";
|
||||
msg.type = Message::eInteger;
|
||||
msg.bVal = (iVal != 0);
|
||||
Messages.push(msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGJSBBase::Message* FGJSBBase::PutMessage(const string& text, double dVal)
|
||||
void FGJSBBase::PutMessage(const string& text, double dVal)
|
||||
{
|
||||
Message *msg = new Message();
|
||||
msg->text = text;
|
||||
msg->messageId = messageId++;
|
||||
msg->subsystem = "FDM";
|
||||
msg->type = Message::eDouble;
|
||||
msg->bVal = (dVal != 0.0);
|
||||
Message msg;
|
||||
msg.text = text;
|
||||
msg.messageId = messageId++;
|
||||
msg.subsystem = "FDM";
|
||||
msg.type = Message::eDouble;
|
||||
msg.bVal = (dVal != 0.0);
|
||||
Messages.push(msg);
|
||||
return msg;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGJSBBase::Message* FGJSBBase::ReadMessage(void)
|
||||
int FGJSBBase::SomeMessages(void)
|
||||
{
|
||||
if (!Messages.empty()) return Messages.front();
|
||||
else return NULL;
|
||||
return !Messages.empty();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGJSBBase::Message* FGJSBBase::ProcessMessage(void)
|
||||
{
|
||||
if (!Messages.empty())
|
||||
localMsg = *(Messages.front());
|
||||
else
|
||||
return NULL;
|
||||
if (Messages.empty()) return NULL;
|
||||
localMsg = Messages.front();
|
||||
Messages.pop();
|
||||
return &localMsg;
|
||||
}
|
||||
|
|
|
@ -125,7 +125,8 @@ public:
|
|||
~FGJSBBase() {};
|
||||
|
||||
/// JSBSim Message structure
|
||||
typedef struct Msg {
|
||||
class Message {
|
||||
public:
|
||||
unsigned int fdmId;
|
||||
unsigned int messageId;
|
||||
string text;
|
||||
|
@ -134,7 +135,7 @@ public:
|
|||
bool bVal;
|
||||
int iVal;
|
||||
double dVal;
|
||||
} Message;
|
||||
};
|
||||
|
||||
///@name JSBSim console output highlighting terms.
|
||||
//@{
|
||||
|
@ -167,29 +168,29 @@ public:
|
|||
/** Places a Message structure on the Message queue.
|
||||
@param msg pointer to a Message structure
|
||||
@return pointer to a Message structure */
|
||||
Message* PutMessage(Message* msg);
|
||||
void PutMessage(const Message& msg);
|
||||
/** Creates a message with the given text and places it on the queue.
|
||||
@param text message text
|
||||
@return pointer to a Message structure */
|
||||
Message* PutMessage(const string& text);
|
||||
void PutMessage(const string& text);
|
||||
/** Creates a message with the given text and boolean value and places it on the queue.
|
||||
@param text message text
|
||||
@param bVal boolean value associated with the message
|
||||
@return pointer to a Message structure */
|
||||
Message* PutMessage(const string& text, bool bVal);
|
||||
void PutMessage(const string& text, bool bVal);
|
||||
/** Creates a message with the given text and integer value and places it on the queue.
|
||||
@param text message text
|
||||
@param iVal integer value associated with the message
|
||||
@return pointer to a Message structure */
|
||||
Message* PutMessage(const string& text, int iVal);
|
||||
void PutMessage(const string& text, int iVal);
|
||||
/** Creates a message with the given text and double value and places it on the queue.
|
||||
@param text message text
|
||||
@param dVal double value associated with the message
|
||||
@return pointer to a Message structure */
|
||||
Message* PutMessage(const string& text, double dVal);
|
||||
void PutMessage(const string& text, double dVal);
|
||||
/** Reads the message on the queue (but does not delete it).
|
||||
@return pointer to a Message structure (or NULL if no mesage) */
|
||||
Message* ReadMessage(void);
|
||||
@return 1 if some messages */
|
||||
int SomeMessages(void);
|
||||
/** Reads the message on the queue and removes it from the queue.
|
||||
@return pointer to a Message structure (or NULL if no mesage) */
|
||||
Message* ProcessMessage(void);
|
||||
|
@ -276,7 +277,7 @@ public:
|
|||
protected:
|
||||
static Message localMsg;
|
||||
|
||||
static std::queue <Message*> Messages;
|
||||
static std::queue <Message> Messages;
|
||||
|
||||
void Debug(int from) {};
|
||||
|
||||
|
|
|
@ -47,10 +47,6 @@ INCLUDES
|
|||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
//#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#include "FGState.h"
|
||||
|
||||
namespace JSBSim {
|
||||
|
@ -190,86 +186,6 @@ FGMatrix33& FGState::GetTb2s(void)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGState::ReportState(void)
|
||||
{
|
||||
#if 0
|
||||
#if !defined(__BORLANDCPP__)
|
||||
char out[80], flap[10], gear[12];
|
||||
|
||||
cout << endl << " JSBSim State" << endl;
|
||||
snprintf(out,80," Weight: %7.0f lbs. CG: %5.1f, %5.1f, %5.1f inches\n",
|
||||
FDMExec->GetMassBalance()->GetWeight(),
|
||||
FDMExec->GetMassBalance()->GetXYZcg(1),
|
||||
FDMExec->GetMassBalance()->GetXYZcg(2),
|
||||
FDMExec->GetMassBalance()->GetXYZcg(3));
|
||||
cout << out;
|
||||
if ( FCS->GetDfPos() <= 0.01)
|
||||
snprintf(flap,10,"Up");
|
||||
else
|
||||
snprintf(flap,10,"%2.0f",FCS->GetDfPos());
|
||||
|
||||
if (FCS->GetGearPos() < 0.01)
|
||||
snprintf(gear,12,"Up");
|
||||
else if (FCS->GetGearPos() > 0.99)
|
||||
snprintf(gear,12,"Down");
|
||||
else
|
||||
snprintf(gear,12,"In Transit");
|
||||
|
||||
snprintf(out,80, " Flaps: %3s Gear: %12s\n",flap,gear);
|
||||
cout << out;
|
||||
snprintf(out,80, " Speed: %4.0f KCAS Mach: %5.2f\n",
|
||||
Auxiliary->GetVcalibratedKTS(),
|
||||
Auxiliary->GetMach() );
|
||||
cout << out;
|
||||
snprintf(out,80, " Altitude: %7.0f ft. AGL Altitude: %7.0f ft.\n",
|
||||
Propagate->Geth(),
|
||||
Propagate->GetDistanceAGL() );
|
||||
cout << out;
|
||||
snprintf(out,80, " Angle of Attack: %6.2f deg Pitch Angle: %6.2f deg\n",
|
||||
Auxiliary->Getalpha()*radtodeg,
|
||||
Propagate->Gettht()*radtodeg );
|
||||
cout << out;
|
||||
snprintf(out,80, " Flight Path Angle: %6.2f deg Climb Rate: %5.0f ft/min\n",
|
||||
Auxiliary->GetGamma()*radtodeg,
|
||||
Propagate->Gethdot()*60 );
|
||||
cout << out;
|
||||
snprintf(out,80, " Normal Load Factor: %4.2f g's Pitch Rate: %5.2f deg/s\n",
|
||||
Aircraft->GetNlf(),
|
||||
Propagate->GetPQR(2)*radtodeg );
|
||||
cout << out;
|
||||
snprintf(out,80, " Heading: %3.0f deg true Sideslip: %5.2f deg Yaw Rate: %5.2f deg/s\n",
|
||||
Propagate->Getpsi()*radtodeg,
|
||||
Auxiliary->Getbeta()*radtodeg,
|
||||
Propagate->GetPQR(3)*radtodeg );
|
||||
cout << out;
|
||||
snprintf(out,80, " Bank Angle: %5.2f deg Roll Rate: %5.2f deg/s\n",
|
||||
Propagate->Getphi()*radtodeg,
|
||||
Propagate->GetPQR(1)*radtodeg );
|
||||
cout << out;
|
||||
snprintf(out,80, " Elevator: %5.2f deg Left Aileron: %5.2f deg Rudder: %5.2f deg\n",
|
||||
FCS->GetDePos(ofRad)*radtodeg,
|
||||
FCS->GetDaLPos(ofRad)*radtodeg,
|
||||
FCS->GetDrPos(ofRad)*radtodeg );
|
||||
cout << out;
|
||||
snprintf(out,80, " Throttle: %5.2f%c\n",
|
||||
FCS->GetThrottlePos(0)*100,'%' );
|
||||
cout << out;
|
||||
|
||||
snprintf(out,80, " Wind Components: %5.2f kts head wind, %5.2f kts cross wind\n",
|
||||
Auxiliary->GetHeadWind()*fpstokts,
|
||||
Auxiliary->GetCrossWind()*fpstokts );
|
||||
cout << out;
|
||||
|
||||
snprintf(out,80, " Ground Speed: %4.0f knots , Ground Track: %3.0f deg true\n",
|
||||
Auxiliary->GetVground()*fpstokts,
|
||||
Auxiliary->GetGroundTrack()*radtodeg );
|
||||
cout << out;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGState::bind(void)
|
||||
{
|
||||
PropertyManager->Tie("sim-time-sec", this, &FGState::Getsim_time);
|
||||
|
|
|
@ -466,7 +466,7 @@ void FGJSBsim::update( double dt )
|
|||
}
|
||||
|
||||
FGJSBBase::Message* msg;
|
||||
while (fdmex->ReadMessage()) {
|
||||
while (fdmex->SomeMessages()) {
|
||||
msg = fdmex->ProcessMessage();
|
||||
switch (msg->type) {
|
||||
case FGJSBBase::Message::eText:
|
||||
|
@ -1105,8 +1105,10 @@ void FGJSBsim::do_trim(void)
|
|||
} else {
|
||||
trimmed->setBoolValue(true);
|
||||
}
|
||||
#if 0
|
||||
if (FGJSBBase::debug_lvl > 0)
|
||||
State->ReportState();
|
||||
State->ReportState(); /* FIXME: Function not implemented */
|
||||
#endif
|
||||
|
||||
delete fgtrim;
|
||||
|
||||
|
|
|
@ -732,9 +732,6 @@ double FGInitialCondition::GetWindDirDegIC(void) const {
|
|||
bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
|
||||
{
|
||||
string resetDef;
|
||||
ifstream initialization_file;
|
||||
FGXMLParse initialization_file_parser;
|
||||
Element *document, *el;
|
||||
int n;
|
||||
|
||||
string sep = "/";
|
||||
|
@ -748,15 +745,8 @@ bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
|
|||
resetDef = rstfile;
|
||||
}
|
||||
|
||||
initialization_file.open(resetDef.c_str());
|
||||
if ( !initialization_file.is_open()) {
|
||||
cerr << "Could not open initialization file: " << resetDef << endl;
|
||||
return false;
|
||||
}
|
||||
document = LoadXMLDocument(resetDef);
|
||||
|
||||
readXML(initialization_file, initialization_file_parser);
|
||||
document = initialization_file_parser.GetDocument(); // document holds the
|
||||
// initialization description
|
||||
if (document->GetName() != string("initialize")) {
|
||||
cerr << "File: " << resetDef << " is not a reset file" << endl;
|
||||
exit(-1);
|
||||
|
@ -803,10 +793,10 @@ bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
|
|||
if (document->FindElement("vground"))
|
||||
SetVgroundKtsIC(document->FindElementValueAsNumberConvertTo("vground", "FT/SEC"));
|
||||
if (document->FindElement("running")) {
|
||||
n = document->FindElementValueAsNumber("running");
|
||||
n = int(document->FindElementValueAsNumber("running"));
|
||||
if (n != 0) {
|
||||
FGPropulsion* propulsion = fdmex->GetPropulsion();
|
||||
for(int i=0; i<propulsion->GetNumEngines(); i++) {
|
||||
for(unsigned int i=0; i<propulsion->GetNumEngines(); i++) {
|
||||
propulsion->GetEngine(i)->SetRunning(true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,6 +50,7 @@ INCLUDES
|
|||
#include <FGFDMExec.h>
|
||||
#include <FGJSBBase.h>
|
||||
#include <math/FGColumnVector3.h>
|
||||
#include <input_output/FGXMLFileRead.h>
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
|
@ -199,7 +200,7 @@ CLASS DOCUMENTATION
|
|||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class FGInitialCondition : public FGJSBBase
|
||||
class FGInitialCondition : public FGJSBBase, public FGXMLFileRead
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
|
|
|
@ -106,12 +106,34 @@ bool FGPropertyManager::HasNode (const string &path)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGPropertyManager::GetName( void ) {
|
||||
string FGPropertyManager::GetName( void )
|
||||
{
|
||||
return string( getName() );
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGPropertyManager::GetPrintableName( void )
|
||||
{
|
||||
string temp_string(getName());
|
||||
size_t initial_location=0;
|
||||
size_t found_location;
|
||||
|
||||
found_location = temp_string.rfind("/");
|
||||
if (found_location != string::npos)
|
||||
temp_string = temp_string.substr(found_location);
|
||||
|
||||
found_location = temp_string.find('_',initial_location);
|
||||
while (found_location != string::npos) {
|
||||
temp_string.replace(found_location,1," ");
|
||||
initial_location = found_location+1;
|
||||
found_location = temp_string.find('_',initial_location);
|
||||
}
|
||||
return temp_string;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGPropertyManager::GetFullyQualifiedName(void) {
|
||||
vector<string> stack;
|
||||
stack.push_back( getDisplayName(true) );
|
||||
|
|
|
@ -115,6 +115,11 @@ class FGPropertyManager : public SGPropertyNode, public FGJSBBase
|
|||
*/
|
||||
string GetName( void );
|
||||
|
||||
/**
|
||||
* Get the name of a node without underscores, etc.
|
||||
*/
|
||||
string GetPrintableName( void );
|
||||
|
||||
/**
|
||||
* Get the fully qualified name of a node
|
||||
* This function is very slow, so is probably useful for debugging only.
|
||||
|
|
|
@ -84,7 +84,7 @@ FGScript::FGScript(FGFDMExec* fgex) : FDMExec(fgex)
|
|||
|
||||
FGScript::~FGScript()
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
for (i=0; i<local_properties.size(); i++)
|
||||
PropertyManager->Untie(local_properties[i]->title);
|
||||
|
||||
|
@ -101,21 +101,16 @@ bool FGScript::LoadScript( string script )
|
|||
{
|
||||
string aircraft="", initialize="", comparison = "", prop_name="";
|
||||
string notifyPropertyName="";
|
||||
Element *document=0, *element=0, *run_element=0, *event_element=0;
|
||||
Element *element=0, *run_element=0, *event_element=0;
|
||||
Element *condition_element=0, *set_element=0, *delay_element=0;
|
||||
Element *notify_element = 0L, *notify_property_element = 0L;
|
||||
Element *property_element = 0L;
|
||||
bool result = false;
|
||||
double dt = 0.0, value = 0.0;
|
||||
FGXMLParse script_file_parser;
|
||||
struct event *newEvent;
|
||||
FGCondition *newCondition;
|
||||
ifstream script_file(script.c_str());
|
||||
|
||||
if ( !script_file ) return false;
|
||||
|
||||
readXML(script_file, script_file_parser);
|
||||
document = script_file_parser.GetDocument();
|
||||
document = LoadXMLDocument(script);
|
||||
|
||||
if (document->GetName() != string("runscript")) {
|
||||
cerr << "File: " << script << " is not a script file" << endl;
|
||||
|
@ -309,20 +304,11 @@ bool FGScript::RunScript(void)
|
|||
iEvent->Triggered = true;
|
||||
} else if (iEvent->Persistent) {
|
||||
iEvent->Triggered = false; // Reset the trigger for persistent events
|
||||
iEvent->Notified = false; // Also reset the notification flag
|
||||
}
|
||||
|
||||
if ((currentTime >= iEvent->StartTime) && iEvent->Triggered) {
|
||||
|
||||
if (iEvent->Notify && iEvent->PrevTriggered != iEvent->Triggered) {
|
||||
cout << endl << " Event " << event_ctr << " (" << iEvent->Name << ")"
|
||||
<< " executed at time: " << currentTime << endl;
|
||||
for (j=0; j<iEvent->NotifyProperties.size();j++) {
|
||||
cout << " " << iEvent->NotifyProperties[j]->GetName()
|
||||
<< " = " << iEvent->NotifyProperties[j]->getDoubleValue() << endl;
|
||||
}
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
for (i=0; i<iEvent->SetValue.size(); i++) {
|
||||
if (iEvent->Transiting[i]) {
|
||||
iEvent->TimeSpan = currentTime - iEvent->StartTime;
|
||||
|
@ -349,6 +335,19 @@ bool FGScript::RunScript(void)
|
|||
iEvent->SetParam[i]->setDoubleValue(newSetValue);
|
||||
}
|
||||
}
|
||||
|
||||
// Print notification values after setting them
|
||||
if (iEvent->Notify && !iEvent->Notified) {
|
||||
cout << endl << " Event " << event_ctr << " (" << iEvent->Name << ")"
|
||||
<< " executed at time: " << currentTime << endl;
|
||||
for (j=0; j<iEvent->NotifyProperties.size();j++) {
|
||||
cout << " " << iEvent->NotifyProperties[j]->GetName()
|
||||
<< " = " << iEvent->NotifyProperties[j]->getDoubleValue() << endl;
|
||||
}
|
||||
cout << endl;
|
||||
iEvent->Notified = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
iEvent++;
|
||||
|
|
|
@ -42,6 +42,7 @@ INCLUDES
|
|||
#include "FGFDMExec.h"
|
||||
#include <math/FGCondition.h>
|
||||
#include <vector>
|
||||
#include <input_output/FGXMLFileRead.h>
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
|
@ -162,7 +163,7 @@ CLASS DOCUMENTATION
|
|||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class FGScript : public FGJSBBase
|
||||
class FGScript : public FGJSBBase, public FGXMLFileRead
|
||||
{
|
||||
public:
|
||||
/// Default constructor
|
||||
|
@ -201,6 +202,7 @@ private:
|
|||
bool Triggered;
|
||||
bool PrevTriggered;
|
||||
bool Notify;
|
||||
bool Notified;
|
||||
double Delay;
|
||||
double StartTime;
|
||||
double TimeSpan;
|
||||
|
@ -221,7 +223,7 @@ private:
|
|||
PrevTriggered = false;
|
||||
Persistent = false;
|
||||
Delay = 0.0;
|
||||
Notify = false;
|
||||
Notify = Notified = false;
|
||||
Name = "";
|
||||
StartTime = 0.0;
|
||||
TimeSpan = 0.0;
|
||||
|
|
|
@ -292,31 +292,32 @@ string Element::FindElementValue(string el)
|
|||
double Element::FindElementValueAsNumberConvertTo(string el, string target_units)
|
||||
{
|
||||
Element* element = FindElement(el);
|
||||
double value;
|
||||
string supplied_units="";
|
||||
|
||||
if (element) {
|
||||
value = element->GetDataAsNumber();
|
||||
supplied_units = element->GetAttributeValue("unit");
|
||||
if (!supplied_units.empty()) {
|
||||
if (convert.find(supplied_units) != convert.end()) {
|
||||
if (convert[supplied_units].find(target_units) != convert[supplied_units].end()) {
|
||||
value *= convert[supplied_units][target_units];
|
||||
} else {
|
||||
cerr << endl << "Target unit: \"" << target_units << "\" does not exist (typo?). Add new unit"
|
||||
<< " conversion in FGXMLElement.cpp." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
} else {
|
||||
cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit"
|
||||
<< " conversion in FGXMLElement.cpp." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cerr << "Attempting to get get non-existent element " << el << endl;
|
||||
return 0;
|
||||
if (!element) {
|
||||
cerr << "Attempting to get non-existent element " << el << endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
string supplied_units = element->GetAttributeValue("unit");
|
||||
|
||||
if (!supplied_units.empty()) {
|
||||
if (convert.find(supplied_units) == convert.end()) {
|
||||
cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit"
|
||||
<< " conversion in FGXMLElement.cpp." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
|
||||
cerr << endl << "Supplied unit: \"" << supplied_units << "\" cannot be converted to "
|
||||
<< target_units << ". Add new unit conversion in FGXMLElement.cpp or fix typo" << endl;
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
double value = element->GetDataAsNumber();
|
||||
if (!supplied_units.empty()) {
|
||||
value *= convert[supplied_units][target_units];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -327,29 +328,30 @@ double Element::FindElementValueAsNumberConvertFromTo( string el,
|
|||
string target_units)
|
||||
{
|
||||
Element* element = FindElement(el);
|
||||
double value;
|
||||
|
||||
if (element) {
|
||||
value = element->GetDataAsNumber();
|
||||
if (!supplied_units.empty()) {
|
||||
if (convert.find(supplied_units) != convert.end()) {
|
||||
if (convert[supplied_units].find(target_units) != convert[supplied_units].end()) {
|
||||
value *= convert[supplied_units][target_units];
|
||||
} else {
|
||||
cerr << endl << "Target unit: \"" << target_units << "\" does not exist (typo?). Add new unit"
|
||||
<< " conversion in FGXMLElement.cpp." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
} else {
|
||||
cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit"
|
||||
<< " conversion in FGXMLElement.cpp." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cerr << "Attempting to get get non-existent element " << el << endl;
|
||||
return 0;
|
||||
|
||||
if (!element) {
|
||||
cerr << "Attempting to get non-existent element " << el << endl;
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if (!supplied_units.empty()) {
|
||||
if (convert.find(supplied_units) == convert.end()) {
|
||||
cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit"
|
||||
<< " conversion in FGXMLElement.cpp." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
|
||||
cerr << endl << "Supplied unit: \"" << supplied_units << "\" cannot be converted to "
|
||||
<< target_units << ". Add new unit conversion in FGXMLElement.cpp or fix typo" << endl;
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
double value = element->GetDataAsNumber();
|
||||
if (!supplied_units.empty()) {
|
||||
value *= convert[supplied_units][target_units];
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
@ -362,6 +364,19 @@ FGColumnVector3 Element::FindElementTripletConvertTo( string target_units)
|
|||
double value=0.0;
|
||||
string supplied_units = GetAttributeValue("unit");
|
||||
|
||||
if (!supplied_units.empty()) {
|
||||
if (convert.find(supplied_units) == convert.end()) {
|
||||
cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit"
|
||||
<< " conversion in FGXMLElement.cpp." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
|
||||
cerr << endl << "Supplied unit: \"" << supplied_units << "\" cannot be converted to "
|
||||
<< target_units << ". Add new unit conversion in FGXMLElement.cpp or fix typo" << endl;
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
|
||||
item = FindElement("x");
|
||||
if (!item) item = FindElement("roll");
|
||||
if (item) {
|
||||
|
|
|
@ -2,6 +2,6 @@ noinst_LIBRARIES = libInputOutput.a
|
|||
|
||||
libInputOutput_a_SOURCES = FGGroundCallback.cpp FGPropertyManager.cpp FGScript.cpp FGXMLElement.cpp FGXMLParse.cpp FGfdmSocket.cpp
|
||||
|
||||
noinst_HEADERS = FGGroundCallback.h FGPropertyManager.h FGScript.h FGXMLElement.h FGXMLParse.h FGfdmSocket.h
|
||||
noinst_HEADERS = FGGroundCallback.h FGPropertyManager.h FGScript.h FGXMLElement.h FGXMLParse.h FGfdmSocket.h FGXMLFileRead.h
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim
|
||||
|
|
|
@ -121,13 +121,6 @@ FGColumnVector3& FGColumnVector3::Normalize(void)
|
|||
return *this;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGColumnVector3 FGColumnVector3::multElementWise(const FGColumnVector3& V) const
|
||||
{
|
||||
return FGColumnVector3(Entry(1) * V(1), Entry(2) * V(2), Entry(3) * V(3));
|
||||
}
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
// The bitmasked value choices are as follows:
|
||||
// unset: In this case (the default) JSBSim would only print
|
||||
|
|
|
@ -282,9 +282,6 @@ public:
|
|||
is equal to zero it is left untouched. */
|
||||
FGColumnVector3& Normalize(void);
|
||||
|
||||
// ??? Is this something sensible ??
|
||||
FGColumnVector3 multElementWise(const FGColumnVector3& V) const;
|
||||
|
||||
// little trick here.
|
||||
struct AssignRef {
|
||||
AssignRef(FGColumnVector3& r, int i) : Ref(r), idx(i) {}
|
||||
|
|
|
@ -47,7 +47,6 @@ CLASS IMPLEMENTATION
|
|||
FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, string prefix)
|
||||
: PropertyManager(propMan), Prefix(prefix)
|
||||
{
|
||||
int i;
|
||||
Element* element;
|
||||
string operation, property_name;
|
||||
int size = el->GetNumElements();
|
||||
|
@ -92,6 +91,16 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, string prefix)
|
|||
}
|
||||
|
||||
element = el->GetElement();
|
||||
if (!element) {
|
||||
cerr << fgred << highint << endl;
|
||||
cerr << " No element was specified as an argument to the \"" << operation << "\" operation" << endl;
|
||||
cerr << " This can happen when, for instance, a cos operation is specified and a " << endl;
|
||||
cerr << " property name is given explicitly, but is not placed within a" << endl;
|
||||
cerr << " <property></property> element tag pair." << endl;
|
||||
cerr << reset;
|
||||
exit(-2);
|
||||
}
|
||||
|
||||
while (element) {
|
||||
operation = element->GetName();
|
||||
|
||||
|
@ -146,7 +155,7 @@ FGFunction::~FGFunction(void)
|
|||
PropertyManager->Untie(tmp);
|
||||
}
|
||||
|
||||
for (int i=0; i<Parameters.size(); i++) {
|
||||
for (unsigned int i=0; i<Parameters.size(); i++) {
|
||||
delete Parameters[i];
|
||||
}
|
||||
}
|
||||
|
@ -167,7 +176,7 @@ void FGFunction::cacheValue(bool cache)
|
|||
|
||||
double FGFunction::GetValue(void) const
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
|
||||
if (cached) return cachedValue;
|
||||
|
||||
|
@ -177,13 +186,19 @@ double FGFunction::GetValue(void) const
|
|||
case eTopLevel:
|
||||
break;
|
||||
case eProduct:
|
||||
for (i=1;i<Parameters.size();i++) temp *= Parameters[i]->GetValue();
|
||||
for (i=1;i<Parameters.size();i++) {
|
||||
temp *= Parameters[i]->GetValue();
|
||||
}
|
||||
break;
|
||||
case eDifference:
|
||||
for (i=1;i<Parameters.size();i++) temp -= Parameters[i]->GetValue();
|
||||
for (i=1;i<Parameters.size();i++) {
|
||||
temp -= Parameters[i]->GetValue();
|
||||
}
|
||||
break;
|
||||
case eSum:
|
||||
for (i=1;i<Parameters.size();i++) temp += Parameters[i]->GetValue();
|
||||
for (i=1;i<Parameters.size();i++) {
|
||||
temp += Parameters[i]->GetValue();
|
||||
}
|
||||
break;
|
||||
case eQuotient:
|
||||
temp /= Parameters[1]->GetValue();
|
||||
|
|
|
@ -87,8 +87,8 @@ FGTable::FGTable(const FGTable& t) : PropertyManager(t.PropertyManager)
|
|||
|
||||
Tables = t.Tables;
|
||||
Data = Allocate();
|
||||
for (int r=0; r<=nRows; r++) {
|
||||
for (int c=0; c<=nCols; c++) {
|
||||
for (unsigned int r=0; r<=nRows; r++) {
|
||||
for (unsigned int c=0; c<=nCols; c++) {
|
||||
Data[r][c] = t.Data[r][c];
|
||||
}
|
||||
}
|
||||
|
@ -101,7 +101,7 @@ FGTable::FGTable(const FGTable& t) : PropertyManager(t.PropertyManager)
|
|||
|
||||
FGTable::FGTable(FGPropertyManager* propMan, Element* el) : PropertyManager(propMan)
|
||||
{
|
||||
int i;
|
||||
unsigned int i;
|
||||
|
||||
stringstream buf;
|
||||
string property_string;
|
||||
|
@ -287,9 +287,9 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el) : PropertyManager(prop
|
|||
double** FGTable::Allocate(void)
|
||||
{
|
||||
Data = new double*[nRows+1];
|
||||
for (int r=0; r<=nRows; r++) {
|
||||
for (unsigned int r=0; r<=nRows; r++) {
|
||||
Data[r] = new double[nCols+1];
|
||||
for (int c=0; c<=nCols; c++) {
|
||||
for (unsigned int c=0; c<=nCols; c++) {
|
||||
Data[r][c] = 0.0;
|
||||
}
|
||||
}
|
||||
|
@ -306,10 +306,10 @@ FGTable::~FGTable()
|
|||
}
|
||||
|
||||
if (nTables > 0) {
|
||||
for (int i=0; i<nTables; i++) delete Tables[i];
|
||||
for (unsigned int i=0; i<nTables; i++) delete Tables[i];
|
||||
Tables.clear();
|
||||
}
|
||||
for (int r=0; r<=nRows; r++) delete[] Data[r];
|
||||
for (unsigned int r=0; r<=nRows; r++) delete[] Data[r];
|
||||
delete[] Data;
|
||||
|
||||
Debug(1);
|
||||
|
@ -317,11 +317,11 @@ FGTable::~FGTable()
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
int FGTable::FindNumColumns(string test_line)
|
||||
unsigned int FGTable::FindNumColumns(string test_line)
|
||||
{
|
||||
// determine number of data columns in table (first column is row lookup - don't count)
|
||||
int position=0;
|
||||
int nCols=0;
|
||||
size_t position=0;
|
||||
unsigned int nCols=0;
|
||||
while ((position = test_line.find_first_not_of(" \t", position)) != string::npos) {
|
||||
nCols++;
|
||||
position = test_line.find_first_of(" \t", position);
|
||||
|
@ -359,7 +359,7 @@ double FGTable::GetValue(void) const
|
|||
double FGTable::GetValue(double key) const
|
||||
{
|
||||
double Factor, Value, Span;
|
||||
int r=lastRowIndex;
|
||||
unsigned int r = lastRowIndex;
|
||||
|
||||
//if the key is off the end of the table, just return the
|
||||
//end-of-table value, do not extrapolate
|
||||
|
@ -374,14 +374,12 @@ double FGTable::GetValue(double key) const
|
|||
}
|
||||
|
||||
// the key is somewhere in the middle, search for the right breakpoint
|
||||
// assume the correct breakpoint has not changed since last frame or
|
||||
// The search is particularly efficient if
|
||||
// the correct breakpoint has not changed since last frame or
|
||||
// has only changed very little
|
||||
|
||||
if ( r > 2 && Data[r-1][0] > key ) {
|
||||
while( Data[r-1][0] > key && r > 2) { r--; }
|
||||
} else if ( Data[r][0] < key ) {
|
||||
while( Data[r][0] <= key && r <= nRows) { r++; }
|
||||
}
|
||||
while (r > 2 && Data[r-1][0] > key) { r--; }
|
||||
while (r < nRows && Data[r][0] < key) { r++; }
|
||||
|
||||
lastRowIndex=r;
|
||||
// make sure denominator below does not go to zero.
|
||||
|
@ -404,22 +402,14 @@ double FGTable::GetValue(double key) const
|
|||
double FGTable::GetValue(double rowKey, double colKey) const
|
||||
{
|
||||
double rFactor, cFactor, col1temp, col2temp, Value;
|
||||
int r=lastRowIndex;
|
||||
int c=lastColumnIndex;
|
||||
unsigned int r = lastRowIndex;
|
||||
unsigned int c = lastColumnIndex;
|
||||
|
||||
if ( r > 2 && Data[r-1][0] > rowKey ) {
|
||||
while ( Data[r-1][0] > rowKey && r > 2) { r--; }
|
||||
} else if ( Data[r][0] < rowKey ) {
|
||||
while ( r <= nRows && Data[r][0] <= rowKey ) { r++; }
|
||||
if ( r > nRows ) r = nRows;
|
||||
}
|
||||
while(r > 2 && Data[r-1][0] > rowKey) { r--; }
|
||||
while(r < nRows && Data[r] [0] < rowKey) { r++; }
|
||||
|
||||
if ( c > 2 && Data[0][c-1] > colKey ) {
|
||||
while( Data[0][c-1] > colKey && c > 2) { c--; }
|
||||
} else if ( Data[0][c] < colKey ) {
|
||||
while( Data[0][c] <= colKey && c <= nCols) { c++; }
|
||||
if ( c > nCols ) c = nCols;
|
||||
}
|
||||
while(c > 2 && Data[0][c-1] > colKey) { c--; }
|
||||
while(c < nCols && Data[0][c] < colKey) { c++; }
|
||||
|
||||
lastRowIndex=r;
|
||||
lastColumnIndex=c;
|
||||
|
@ -446,7 +436,7 @@ double FGTable::GetValue(double rowKey, double colKey) const
|
|||
double FGTable::GetValue(double rowKey, double colKey, double tableKey) const
|
||||
{
|
||||
double Factor, Value, Span;
|
||||
int r=lastRowIndex;
|
||||
unsigned int r = lastRowIndex;
|
||||
|
||||
//if the key is off the end (or before the beginning) of the table,
|
||||
// just return the boundary-table value, do not extrapolate
|
||||
|
@ -460,14 +450,12 @@ double FGTable::GetValue(double rowKey, double colKey, double tableKey) const
|
|||
}
|
||||
|
||||
// the key is somewhere in the middle, search for the right breakpoint
|
||||
// assume the correct breakpoint has not changed since last frame or
|
||||
// The search is particularly efficient if
|
||||
// the correct breakpoint has not changed since last frame or
|
||||
// has only changed very little
|
||||
|
||||
if ( r > 2 && Data[r-1][1] > tableKey ) {
|
||||
while( Data[r-1][1] > tableKey && r > 2) { r--; }
|
||||
} else if ( Data[r][1] < tableKey ) {
|
||||
while( Data[r][1] <= tableKey && r <= nRows) { r++; }
|
||||
}
|
||||
while(r > 2 && Data[r-1][1] > tableKey) { r--; }
|
||||
while(r < nRows && Data[r] [1] < tableKey) { r++; }
|
||||
|
||||
lastRowIndex=r;
|
||||
// make sure denominator below does not go to zero.
|
||||
|
@ -493,11 +481,11 @@ void FGTable::operator<<(stringstream& in_stream)
|
|||
int startRow=0;
|
||||
int startCol=0;
|
||||
|
||||
if (Type == tt1D || Type == tt3D) startRow = 1;
|
||||
if (Type == tt3D) startCol = 1;
|
||||
// In 1D table, no pseudo-row of column-headers (i.e. keys):
|
||||
if (Type == tt1D) startRow = 1;
|
||||
|
||||
for (int r=startRow; r<=nRows; r++) {
|
||||
for (int c=startCol; c<=nCols; c++) {
|
||||
for (unsigned int r=startRow; r<=nRows; r++) {
|
||||
for (unsigned int c=startCol; c<=nCols; c++) {
|
||||
if (r != 0 || c != 0) {
|
||||
in_stream >> Data[r][c];
|
||||
}
|
||||
|
@ -557,9 +545,9 @@ void FGTable::Print(void)
|
|||
break;
|
||||
}
|
||||
cout.precision(4);
|
||||
for (int r=startRow; r<=nRows; r++) {
|
||||
for (unsigned int r=startRow; r<=nRows; r++) {
|
||||
cout << " ";
|
||||
for (int c=startCol; c<=nCols; c++) {
|
||||
for (unsigned int c=startCol; c<=nCols; c++) {
|
||||
if (r == 0 && c == 0) {
|
||||
cout << " ";
|
||||
} else {
|
||||
|
|
|
@ -299,8 +299,8 @@ private:
|
|||
FGPropertyManager *lookupProperty[3];
|
||||
double** Data;
|
||||
vector <FGTable*> Tables;
|
||||
int FindNumColumns(string);
|
||||
int nRows, nCols, nTables, dimension;
|
||||
unsigned int FindNumColumns(string);
|
||||
unsigned int nRows, nCols, nTables, dimension;
|
||||
int colCounter, rowCounter, tableCounter;
|
||||
mutable int lastRowIndex, lastColumnIndex, lastTableIndex;
|
||||
double** Allocate(void);
|
||||
|
|
|
@ -5,7 +5,7 @@ libMath_a_SOURCES = FGColumnVector3.cpp FGFunction.cpp FGLocation.cpp FGMatrix33
|
|||
FGCondition.cpp
|
||||
|
||||
noinst_HEADERS = FGColumnVector3.h FGFunction.h FGLocation.h FGMatrix33.h \
|
||||
FGParameter.h FGPropertyValue.h FGQuaternion.h FGRealValue.h FGTable.h \
|
||||
FGParameter.h FGPropertyValue.h FGQuaternion.h FGRealValue.h FGTable.h \
|
||||
FGCondition.h
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim
|
||||
|
|
|
@ -353,8 +353,6 @@ void FGAerodynamics::bind(void)
|
|||
|
||||
void FGAerodynamics::unbind(void)
|
||||
{
|
||||
unsigned i,j;
|
||||
|
||||
PropertyManager->Untie("forces/fbx-aero-lbs");
|
||||
PropertyManager->Untie("forces/fby-aero-lbs");
|
||||
PropertyManager->Untie("forces/fbz-aero-lbs");
|
||||
|
@ -374,7 +372,6 @@ void FGAerodynamics::unbind(void)
|
|||
PropertyManager->Untie("aero/alpha-wing-rad");
|
||||
PropertyManager->Untie("aero/stall-hyst-norm");
|
||||
PropertyManager->Untie("systems/stall-warn-norm");
|
||||
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -94,6 +94,7 @@ FGAircraft::FGAircraft(FGFDMExec* fdmex) : FGModel(fdmex)
|
|||
lbarh = lbarv = 0.0;
|
||||
vbarh = vbarv = 0.0;
|
||||
WingIncidence = 0.0;
|
||||
HoldDown = 0;
|
||||
|
||||
bind();
|
||||
|
||||
|
@ -116,14 +117,18 @@ bool FGAircraft::Run(void)
|
|||
if (FDMExec->Holding()) return false;
|
||||
|
||||
vForces.InitMatrix();
|
||||
vForces += Aerodynamics->GetForces();
|
||||
vForces += Propulsion->GetForces();
|
||||
vForces += GroundReactions->GetForces();
|
||||
if (!HoldDown) {
|
||||
vForces += Aerodynamics->GetForces();
|
||||
vForces += Propulsion->GetForces();
|
||||
vForces += GroundReactions->GetForces();
|
||||
}
|
||||
|
||||
vMoments.InitMatrix();
|
||||
vMoments += Aerodynamics->GetMoments();
|
||||
vMoments += Propulsion->GetMoments();
|
||||
vMoments += GroundReactions->GetMoments();
|
||||
if (!HoldDown) {
|
||||
vMoments += Aerodynamics->GetMoments();
|
||||
vMoments += Propulsion->GetMoments();
|
||||
vMoments += GroundReactions->GetMoments();
|
||||
}
|
||||
|
||||
vBodyAccel = vForces/MassBalance->GetMass();
|
||||
|
||||
|
@ -212,6 +217,7 @@ void FGAircraft::bind(void)
|
|||
PropertyManager->Tie("metrics/lv-norm", this, &FGAircraft::Getlbarv);
|
||||
PropertyManager->Tie("metrics/vbarh-norm", this, &FGAircraft::Getvbarh);
|
||||
PropertyManager->Tie("metrics/vbarv-norm", this, &FGAircraft::Getvbarv);
|
||||
PropertyManager->Tie("forces/hold-down", this, &FGAircraft::GetHoldDown, &FGAircraft::SetHoldDown);
|
||||
PropertyManager->Tie("moments/l-total-lbsft", this, eL, (PMF)&FGAircraft::GetMoments);
|
||||
PropertyManager->Tie("moments/m-total-lbsft", this, eM, (PMF)&FGAircraft::GetMoments);
|
||||
PropertyManager->Tie("moments/n-total-lbsft", this, eN, (PMF)&FGAircraft::GetMoments);
|
||||
|
@ -251,6 +257,7 @@ void FGAircraft::unbind(void)
|
|||
PropertyManager->Untie("forces/fbx-total-lbs");
|
||||
PropertyManager->Untie("forces/fby-total-lbs");
|
||||
PropertyManager->Untie("forces/fbz-total-lbs");
|
||||
PropertyManager->Untie("forces/hold-down");
|
||||
PropertyManager->Untie("metrics/aero-rp-x-in");
|
||||
PropertyManager->Untie("metrics/aero-rp-y-in");
|
||||
PropertyManager->Untie("metrics/aero-rp-z-in");
|
||||
|
|
|
@ -151,6 +151,8 @@ public:
|
|||
inline double GetXYZvrp(int idx) const { return vXYZvrp(idx); }
|
||||
inline double GetXYZep(int idx) const { return vXYZep(idx); }
|
||||
inline void SetAircraftName(string name) {AircraftName = name;}
|
||||
inline void SetHoldDown(int hd) {HoldDown = hd;}
|
||||
inline int GetHoldDown(void) const {return HoldDown;}
|
||||
|
||||
void SetXYZrp(int idx, double value) {vXYZrp(idx) = value;}
|
||||
|
||||
|
@ -175,6 +177,7 @@ private:
|
|||
double WingArea, WingSpan, cbar, WingIncidence;
|
||||
double HTailArea, VTailArea, HTailArm, VTailArm;
|
||||
double lbarh,lbarv,vbarh,vbarv;
|
||||
int HoldDown;
|
||||
string AircraftName;
|
||||
|
||||
void Debug(int from);
|
||||
|
|
|
@ -101,16 +101,16 @@ FGAuxiliary::~FGAuxiliary()
|
|||
|
||||
bool FGAuxiliary::Run()
|
||||
{
|
||||
double A,B,D, hdot_Vt;
|
||||
double A,B,D;
|
||||
|
||||
if (FGModel::Run()) return true; // return true if error returned from base class
|
||||
if (FDMExec->Holding()) return false;
|
||||
|
||||
const FGColumnVector3& vPQR = Propagate->GetPQR();
|
||||
const FGColumnVector3& vUVW = Propagate->GetUVW();
|
||||
const FGColumnVector3& vUVWdot = Propagate->GetUVWdot();
|
||||
const FGColumnVector3& vVel = Propagate->GetVel();
|
||||
|
||||
if (FGModel::Run()) return true; // return true if error returned from base class
|
||||
|
||||
if (FDMExec->Holding()) return false;
|
||||
|
||||
p = Atmosphere->GetPressure();
|
||||
rhosl = Atmosphere->GetDensitySL();
|
||||
psl = Atmosphere->GetPressureSL();
|
||||
|
@ -182,18 +182,9 @@ bool FGAuxiliary::Run()
|
|||
|
||||
Vground = sqrt( vVel(eNorth)*vVel(eNorth) + vVel(eEast)*vVel(eEast) );
|
||||
|
||||
if (vVel(eNorth) == 0) psigt = 0;
|
||||
else psigt = atan2(vVel(eEast), vVel(eNorth));
|
||||
|
||||
psigt = atan2(vVel(eEast), vVel(eNorth));
|
||||
if (psigt < 0.0) psigt += 2*M_PI;
|
||||
|
||||
if (Vground == 0.0) {
|
||||
if (vVel(eDown) == 0.0) gamma = 0.0;
|
||||
else if (vVel(eDown) < 0.0) gamma = 90.0*degtorad;
|
||||
else gamma = -90.0*degtorad;
|
||||
} else {
|
||||
gamma = atan2(-vVel(eDown), Vground);
|
||||
}
|
||||
gamma = atan2(-vVel(eDown), Vground);
|
||||
|
||||
tat = sat*(1 + 0.2*Mach*Mach); // Total Temperature, isentropic flow
|
||||
tatc = RankineToCelsius(tat);
|
||||
|
|
|
@ -52,6 +52,7 @@ INCLUDES
|
|||
#include <models/flight_control/FGKinemat.h>
|
||||
#include <models/flight_control/FGFCSFunction.h>
|
||||
#include <models/flight_control/FGSensor.h>
|
||||
#include <models/flight_control/FGActuator.h>
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
|
@ -147,7 +148,9 @@ bool FGFCS::Run(void)
|
|||
|
||||
// Cycle through the sensor, autopilot, and flight control components
|
||||
for (i=0; i<sensors.size(); i++) sensors[i]->Run();
|
||||
for (i=0; i<APComponents.size(); i++) APComponents[i]->Run();
|
||||
for (i=0; i<APComponents.size(); i++) {
|
||||
APComponents[i]->Run();
|
||||
}
|
||||
for (i=0; i<FCSComponents.size(); i++) FCSComponents[i]->Run();
|
||||
|
||||
return false;
|
||||
|
@ -456,10 +459,8 @@ bool FGFCS::Load(Element* el)
|
|||
{
|
||||
string name, file, fname, interface_property_string;
|
||||
vector <FGFCSComponent*> *Components;
|
||||
Element *document, *component_element, *property_element, *sensor_element;
|
||||
Element *component_element, *property_element, *sensor_element;
|
||||
Element *channel_element;
|
||||
ifstream* controls_file = new ifstream();
|
||||
FGXMLParse controls_file_parser;
|
||||
|
||||
Components=0;
|
||||
// Determine if the FCS/Autopilot is defined inline in the aircraft configuration
|
||||
|
@ -479,10 +480,7 @@ bool FGFCS::Load(Element* el)
|
|||
cerr << "FCS/Autopilot does not appear to be defined inline nor in a file" << endl;
|
||||
return false;
|
||||
} else {
|
||||
controls_file->open(file.c_str());
|
||||
readXML(*controls_file, controls_file_parser);
|
||||
delete controls_file;
|
||||
document = controls_file_parser.GetDocument();
|
||||
document = LoadXMLDocument(file);
|
||||
}
|
||||
} else {
|
||||
document = el;
|
||||
|
@ -554,6 +552,8 @@ bool FGFCS::Load(Element* el)
|
|||
Components->push_back(new FGFCSFunction(this, component_element));
|
||||
} else if (component_element->GetName() == string("pid")) {
|
||||
Components->push_back(new FGPID(this, component_element));
|
||||
} else if (component_element->GetName() == string("actuator")) {
|
||||
Components->push_back(new FGActuator(this, component_element));
|
||||
} else {
|
||||
cerr << "Unknown FCS component: " << component_element->GetName() << endl;
|
||||
}
|
||||
|
@ -604,7 +604,9 @@ string FGFCS::GetComponentStrings(string delimeter)
|
|||
|
||||
for (comp = 0; comp < APComponents.size(); comp++)
|
||||
{
|
||||
CompStrings += delimeter;
|
||||
if (firstime) firstime = false;
|
||||
else CompStrings += delimeter;
|
||||
|
||||
CompStrings += APComponents[comp]->GetName();
|
||||
}
|
||||
|
||||
|
@ -629,7 +631,10 @@ string FGFCS::GetComponentValues(string delimeter)
|
|||
}
|
||||
|
||||
for (comp = 0; comp < APComponents.size(); comp++) {
|
||||
sprintf(buffer, "%s%9.6f", delimeter.c_str(), APComponents[comp]->GetOutput());
|
||||
if (firstime) firstime = false;
|
||||
else CompValues += delimeter;
|
||||
|
||||
sprintf(buffer, "%9.6f", APComponents[comp]->GetOutput());
|
||||
CompValues += string(buffer);
|
||||
}
|
||||
|
||||
|
@ -663,6 +668,13 @@ void FGFCS::AddGear(void)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGFCS::GetDt(void)
|
||||
{
|
||||
return FDMExec->GetDeltaT()*rate;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGFCS::bind(void)
|
||||
{
|
||||
PropertyManager->Tie("fcs/aileron-cmd-norm", this, &FGFCS::GetDaCmd, &FGFCS::SetDaCmd);
|
||||
|
|
|
@ -53,7 +53,7 @@ INCLUDES
|
|||
#include <models/flight_control/FGFCSComponent.h>
|
||||
#include <models/FGModel.h>
|
||||
#include <models/FGLGear.h>
|
||||
#include <input_output/FGXMLElement.h>
|
||||
#include <input_output/FGXMLFileRead.h>
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
|
@ -191,7 +191,8 @@ CLASS DOCUMENTATION
|
|||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class FGFCS : public FGModel {
|
||||
class FGFCS : public FGModel, public FGXMLFileRead
|
||||
{
|
||||
|
||||
public:
|
||||
/** Constructor
|
||||
|
@ -523,6 +524,7 @@ public:
|
|||
|
||||
void AddThrottle(void);
|
||||
void AddGear(void);
|
||||
double GetDt(void);
|
||||
|
||||
FGPropertyManager* GetPropertyManager(void) { return PropertyManager; }
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ FGGroundReactions::FGGroundReactions(FGFDMExec* fgex) : FGModel(fgex)
|
|||
|
||||
FGGroundReactions::~FGGroundReactions(void)
|
||||
{
|
||||
for (int i=0; i<lGear.size();i++) lGear[i].unbind();
|
||||
for (unsigned int i=0; i<lGear.size();i++) lGear[i].unbind();
|
||||
lGear.clear();
|
||||
|
||||
unbind();
|
||||
|
@ -106,7 +106,7 @@ bool FGGroundReactions::Run(void)
|
|||
bool FGGroundReactions::GetWOW(void)
|
||||
{
|
||||
bool result = false;
|
||||
for (int i=0; i<lGear.size(); i++) {
|
||||
for (unsigned int i=0; i<lGear.size(); i++) {
|
||||
if (lGear[i].IsBogey() && lGear[i].GetWOW()) {
|
||||
result = true;
|
||||
break;
|
||||
|
@ -130,7 +130,7 @@ bool FGGroundReactions::Load(Element* el)
|
|||
contact_element = el->FindNextElement("contact");
|
||||
}
|
||||
|
||||
for (int i=0; i<lGear.size();i++) lGear[i].bind();
|
||||
for (unsigned int i=0; i<lGear.size();i++) lGear[i].bind();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -149,11 +149,13 @@ string FGGroundReactions::GetGroundReactionStrings(string delimeter)
|
|||
<< name << " stroke velocity (ft/sec)" << delimeter
|
||||
<< name << " compress force (lbs)" << delimeter
|
||||
<< name << " wheel side force (lbs)" << delimeter
|
||||
<< name << " wheel velocity vec X (ft/sec)" << delimeter
|
||||
<< name << " wheel velocity vec Y (ft/sec)" << delimeter
|
||||
<< name << " wheel roll force (lbs)" << delimeter
|
||||
<< name << " body X force (lbs)" << delimeter
|
||||
<< name << " body Y force (lbs)" << delimeter
|
||||
<< name << " wheel velocity vec X (ft/sec)" << delimeter
|
||||
<< name << " wheel velocity vec Y (ft/sec)" << delimeter
|
||||
<< name << " wheel rolling velocity (ft/sec)" << delimeter
|
||||
<< name << " wheel side velocity (ft/sec)" << delimeter
|
||||
<< name << " wheel slip (deg)" << delimeter;
|
||||
}
|
||||
}
|
||||
|
@ -181,12 +183,14 @@ string FGGroundReactions::GetGroundReactionValues(string delimeter)
|
|||
<< setprecision(5) << gear.GetCompLen() << delimeter
|
||||
<< setprecision(6) << gear.GetCompVel() << delimeter
|
||||
<< setprecision(10) << gear.GetCompForce() << delimeter
|
||||
<< setprecision(6) << gear.GetWheelVel(eX) << delimeter
|
||||
<< gear.GetWheelVel(eY) << delimeter
|
||||
<< gear.GetWheelSideForce() << delimeter
|
||||
<< gear.GetWheelRollForce() << delimeter
|
||||
<< gear.GetBodyXForce() << delimeter
|
||||
<< gear.GetBodyYForce() << delimeter
|
||||
<< setprecision(6) << gear.GetWheelVel(eX) << delimeter
|
||||
<< gear.GetWheelVel(eY) << delimeter
|
||||
<< gear.GetWheelRollVel() << delimeter
|
||||
<< gear.GetWheelSideVel() << delimeter
|
||||
<< gear.GetWheelSlipAngle() << delimeter;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -206,7 +206,7 @@ bool FGInput::Load(Element* element)
|
|||
string name="", fname="";
|
||||
string property;
|
||||
|
||||
port = element->GetAttributeValueAsNumber("port");
|
||||
port = int(element->GetAttributeValueAsNumber("port"));
|
||||
if (port == 0) {
|
||||
cerr << endl << "No port assigned in input element" << endl;
|
||||
} else {
|
||||
|
|
|
@ -88,7 +88,7 @@ FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number) : Exec(fdmex),
|
|||
if (el->FindElement("max_steer"))
|
||||
maxSteerAngle = el->FindElementValueAsNumberConvertTo("max_steer", "DEG");
|
||||
if (el->FindElement("retractable"))
|
||||
isRetractable = (int)el->FindElementValueAsNumber("retractable");
|
||||
isRetractable = ((unsigned int)el->FindElementValueAsNumber("retractable"))>0.0?true:false;
|
||||
|
||||
ForceY_Table = 0;
|
||||
force_table = el->FindElement("table");
|
||||
|
@ -332,8 +332,9 @@ FGColumnVector3& FGLGear::Force(void)
|
|||
|
||||
// Compute the forces in the wheel ground plane.
|
||||
|
||||
RollingForce = (1.0 - TirePressureNorm) * 30
|
||||
+ vLocalForce(eZ) * BrakeFCoeff * (RollingWhlVel>=0?1.0:-1.0);
|
||||
RollingForce = ((1.0 - TirePressureNorm) * 30
|
||||
+ vLocalForce(eZ) * BrakeFCoeff) * (RollingWhlVel>=0?1.0:-1.0);
|
||||
|
||||
SideForce = vLocalForce(eZ) * FCoeff;
|
||||
|
||||
// Transform these forces back to the local reference frame.
|
||||
|
@ -380,7 +381,7 @@ FGColumnVector3& FGLGear::Force(void)
|
|||
if ((fabs(RollingWhlVel) <= RFRV) && RFRV > 0) vForce(eX) *= fabs(RollingWhlVel)/RFRV;
|
||||
if ((fabs(SideWhlVel) <= SFRV) && SFRV > 0) vForce(eY) *= fabs(SideWhlVel)/SFRV;
|
||||
|
||||
// End experimental section for attentuating gear jitter
|
||||
// End section for attentuating gear jitter
|
||||
|
||||
vMoment = vWhlBodyVec * vForce;
|
||||
|
||||
|
@ -426,13 +427,9 @@ void FGLGear::ComputeSlipAngle(void)
|
|||
SideWhlVel = vWhlVelVec(eY)*CosWheel - vWhlVelVec(eX)*SinWheel;
|
||||
|
||||
// Calculate tire slip angle.
|
||||
if (fabs(RollingWhlVel) < 0.02 && fabs(SideWhlVel) < 0.02) {
|
||||
WheelSlip = -SteerAngle*radtodeg;
|
||||
} else {
|
||||
WheelSlip = atan2(SideWhlVel, fabs(RollingWhlVel))*radtodeg;
|
||||
}
|
||||
|
||||
// Filter the wheel slip angle
|
||||
// Filter the wheel slip angle
|
||||
|
||||
double SlipOutput, ca, cb, denom;
|
||||
|
||||
|
|
|
@ -244,6 +244,8 @@ public:
|
|||
inline bool GetGearUnitDown(void) { return GearDown; }
|
||||
inline double GetWheelSideForce(void) { return SideForce; }
|
||||
inline double GetWheelRollForce(void) { return RollingForce; }
|
||||
inline double GetWheelSideVel(void) { return SideWhlVel; }
|
||||
inline double GetWheelRollVel(void) { return RollingWhlVel; }
|
||||
inline double GetBodyXForce(void) { return vLocalForce(eX); }
|
||||
inline double GetBodyYForce(void) { return vLocalForce(eY); }
|
||||
inline double GetWheelSlipAngle(void) { return WheelSlip; }
|
||||
|
|
|
@ -104,11 +104,11 @@ bool FGMassBalance::Load(Element* el)
|
|||
EmptyWeight = el->FindElementValueAsNumberConvertTo("emptywt", "LBS");
|
||||
|
||||
element = el->FindElement("location");
|
||||
while (element) {
|
||||
element_name = element->GetAttributeValue("name");
|
||||
if (element_name == "CG") vbaseXYZcg = element->FindElementTripletConvertTo("IN");
|
||||
element = el->FindNextElement("location");
|
||||
}
|
||||
while (element) {
|
||||
element_name = element->GetAttributeValue("name");
|
||||
if (element_name == "CG") vbaseXYZcg = element->FindElementTripletConvertTo("IN");
|
||||
element = el->FindNextElement("location");
|
||||
}
|
||||
|
||||
// Find all POINTMASS elements that descend from this METRICS branch of the
|
||||
// config file.
|
||||
|
@ -281,11 +281,11 @@ void FGMassBalance::bind(void)
|
|||
&FGMassBalance::GetMass);
|
||||
PropertyManager->Tie("inertia/weight-lbs", this,
|
||||
&FGMassBalance::GetWeight);
|
||||
PropertyManager->Tie("inertia/cg-x-ft", this,1,
|
||||
PropertyManager->Tie("inertia/cg-x-in", this,1,
|
||||
(PMF)&FGMassBalance::GetXYZcg);
|
||||
PropertyManager->Tie("inertia/cg-y-ft", this,2,
|
||||
PropertyManager->Tie("inertia/cg-y-in", this,2,
|
||||
(PMF)&FGMassBalance::GetXYZcg);
|
||||
PropertyManager->Tie("inertia/cg-z-ft", this,3,
|
||||
PropertyManager->Tie("inertia/cg-z-in", this,3,
|
||||
(PMF)&FGMassBalance::GetXYZcg);
|
||||
}
|
||||
|
||||
|
@ -295,9 +295,9 @@ void FGMassBalance::unbind(void)
|
|||
{
|
||||
PropertyManager->Untie("inertia/mass-slugs");
|
||||
PropertyManager->Untie("inertia/weight-lbs");
|
||||
PropertyManager->Untie("inertia/cg-x-ft");
|
||||
PropertyManager->Untie("inertia/cg-y-ft");
|
||||
PropertyManager->Untie("inertia/cg-z-ft");
|
||||
PropertyManager->Untie("inertia/cg-x-in");
|
||||
PropertyManager->Untie("inertia/cg-y-in");
|
||||
PropertyManager->Untie("inertia/cg-z-in");
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -335,7 +335,7 @@ void FGMassBalance::Debug(int from)
|
|||
cout << " EmptyWeight: " << EmptyWeight << " lbm" << endl;
|
||||
cout << " CG (x, y, z): " << vbaseXYZcg << endl;
|
||||
// ToDo: Need to add point mass outputs here
|
||||
for (int i=0; i<PointMasses.size(); i++) {
|
||||
for (unsigned int i=0; i<PointMasses.size(); i++) {
|
||||
cout << " Point Mass Object: " << PointMasses[i].Weight << " lbs. at "
|
||||
<< "X, Y, Z (in.): " << PointMasses[i].Location(eX) << " "
|
||||
<< PointMasses[i].Location(eY) << " "
|
||||
|
|
|
@ -145,6 +145,8 @@ void FGOutput::DelimitedOutput(string fname)
|
|||
|
||||
ostream outstream(buffer);
|
||||
|
||||
outstream.precision(10);
|
||||
|
||||
if (dFirstPass) {
|
||||
outstream << "Time";
|
||||
if (SubSystems & ssSimulation) {
|
||||
|
@ -235,7 +237,7 @@ void FGOutput::DelimitedOutput(string fname)
|
|||
}
|
||||
if (OutputProperties.size() > 0) {
|
||||
for (unsigned int i=0;i<OutputProperties.size();i++) {
|
||||
outstream << delimeter << OutputProperties[i]->GetName();
|
||||
outstream << delimeter << OutputProperties[i]->GetPrintableName();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -260,8 +262,8 @@ void FGOutput::DelimitedOutput(string fname)
|
|||
}
|
||||
if (SubSystems & ssRates) {
|
||||
outstream << delimeter;
|
||||
outstream << Propagate->GetPQR().Dump(delimeter) << delimeter;
|
||||
outstream << Propagate->GetPQRdot().Dump(delimeter);
|
||||
outstream << (radtodeg*Propagate->GetPQR()).Dump(delimeter) << delimeter;
|
||||
outstream << (radtodeg*Propagate->GetPQRdot()).Dump(delimeter);
|
||||
}
|
||||
if (SubSystems & ssVelocities) {
|
||||
outstream << delimeter;
|
||||
|
@ -297,7 +299,7 @@ void FGOutput::DelimitedOutput(string fname)
|
|||
if (SubSystems & ssPropagate) {
|
||||
outstream << delimeter;
|
||||
outstream << Propagate->Geth() << delimeter;
|
||||
outstream << Propagate->GetEuler().Dump(delimeter) << delimeter;
|
||||
outstream << (radtodeg*Propagate->GetEuler()).Dump(delimeter) << delimeter;
|
||||
outstream << Auxiliary->Getalpha(inDegrees) << delimeter;
|
||||
outstream << Auxiliary->Getbeta(inDegrees) << delimeter;
|
||||
outstream << Propagate->GetLocation().GetLatitudeDeg() << delimeter;
|
||||
|
@ -417,13 +419,13 @@ void FGOutput::SocketOutput(void)
|
|||
}
|
||||
if (SubSystems & ssPropagate) {
|
||||
socket->Append("Altitude");
|
||||
socket->Append("Phi");
|
||||
socket->Append("Tht");
|
||||
socket->Append("Psi");
|
||||
socket->Append("Alpha");
|
||||
socket->Append("Beta");
|
||||
socket->Append("Latitude (Deg)");
|
||||
socket->Append("Longitude (Deg)");
|
||||
socket->Append("Phi (deg)");
|
||||
socket->Append("Tht (deg)");
|
||||
socket->Append("Psi (deg)");
|
||||
socket->Append("Alpha (deg)");
|
||||
socket->Append("Beta (deg)");
|
||||
socket->Append("Latitude (deg)");
|
||||
socket->Append("Longitude (deg)");
|
||||
}
|
||||
if (SubSystems & ssCoefficients) {
|
||||
scratch = Aerodynamics->GetCoefficientStrings(",");
|
||||
|
@ -441,7 +443,7 @@ void FGOutput::SocketOutput(void)
|
|||
}
|
||||
if (OutputProperties.size() > 0) {
|
||||
for (unsigned int i=0;i<OutputProperties.size();i++) {
|
||||
socket->Append(OutputProperties[i]->GetName());
|
||||
socket->Append(OutputProperties[i]->GetPrintableName());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -464,12 +466,12 @@ void FGOutput::SocketOutput(void)
|
|||
socket->Append(FCS->GetDfPos());
|
||||
}
|
||||
if (SubSystems & ssRates) {
|
||||
socket->Append(Propagate->GetPQR(eP));
|
||||
socket->Append(Propagate->GetPQR(eQ));
|
||||
socket->Append(Propagate->GetPQR(eR));
|
||||
socket->Append(Propagate->GetPQRdot(eP));
|
||||
socket->Append(Propagate->GetPQRdot(eQ));
|
||||
socket->Append(Propagate->GetPQRdot(eR));
|
||||
socket->Append(radtodeg*Propagate->GetPQR(eP));
|
||||
socket->Append(radtodeg*Propagate->GetPQR(eQ));
|
||||
socket->Append(radtodeg*Propagate->GetPQR(eR));
|
||||
socket->Append(radtodeg*Propagate->GetPQRdot(eP));
|
||||
socket->Append(radtodeg*Propagate->GetPQRdot(eQ));
|
||||
socket->Append(radtodeg*Propagate->GetPQRdot(eR));
|
||||
}
|
||||
if (SubSystems & ssVelocities) {
|
||||
socket->Append(Auxiliary->Getqbar());
|
||||
|
@ -521,9 +523,9 @@ void FGOutput::SocketOutput(void)
|
|||
}
|
||||
if (SubSystems & ssPropagate) {
|
||||
socket->Append(Propagate->Geth());
|
||||
socket->Append(Propagate->GetEuler(ePhi));
|
||||
socket->Append(Propagate->GetEuler(eTht));
|
||||
socket->Append(Propagate->GetEuler(ePsi));
|
||||
socket->Append(radtodeg*Propagate->GetEuler(ePhi));
|
||||
socket->Append(radtodeg*Propagate->GetEuler(eTht));
|
||||
socket->Append(radtodeg*Propagate->GetEuler(ePsi));
|
||||
socket->Append(Auxiliary->Getalpha(inDegrees));
|
||||
socket->Append(Auxiliary->Getbeta(inDegrees));
|
||||
socket->Append(Propagate->GetLocation().GetLatitudeDeg());
|
||||
|
@ -574,9 +576,7 @@ bool FGOutput::Load(Element* element)
|
|||
int OutRate = 0;
|
||||
string property;
|
||||
unsigned int port;
|
||||
FGXMLParse output_file_parser;
|
||||
Element *document, *property_element;
|
||||
ifstream* output_file = new ifstream();
|
||||
Element *property_element;
|
||||
|
||||
string separator = "/";
|
||||
# ifdef macintosh
|
||||
|
@ -596,16 +596,7 @@ bool FGOutput::Load(Element* element)
|
|||
} else {
|
||||
output_file_name = FDMExec->GetFullAircraftPath() + separator + fname + ".xml";
|
||||
}
|
||||
output_file->open(output_file_name.c_str());
|
||||
if (output_file->is_open()) {
|
||||
readXML(*output_file, output_file_parser);
|
||||
delete output_file;
|
||||
} else {
|
||||
delete output_file;
|
||||
cerr << "Could not open directives file: " << output_file_name << endl;
|
||||
return false;
|
||||
}
|
||||
document = output_file_parser.GetDocument();
|
||||
document = LoadXMLDocument(output_file_name);
|
||||
} else {
|
||||
document = element;
|
||||
}
|
||||
|
|
|
@ -55,7 +55,7 @@ INCLUDES
|
|||
#endif
|
||||
|
||||
#include <input_output/FGfdmSocket.h>
|
||||
#include <input_output/FGXMLElement.h>
|
||||
#include <input_output/FGXMLFileRead.h>
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
|
@ -123,7 +123,7 @@ CLASS DOCUMENTATION
|
|||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class FGOutput : public FGModel
|
||||
class FGOutput : public FGModel, public FGXMLFileRead
|
||||
{
|
||||
public:
|
||||
FGOutput(FGFDMExec*);
|
||||
|
|
|
@ -98,6 +98,18 @@ FGPropagate::FGPropagate(FGFDMExec* fdmex) : FGModel(fdmex)
|
|||
Name = "FGPropagate";
|
||||
// vQtrndot.zero();
|
||||
|
||||
last2_vPQRdot.InitMatrix();
|
||||
last_vPQRdot.InitMatrix();
|
||||
vPQRdot.InitMatrix();
|
||||
|
||||
last2_vUVWdot.InitMatrix();
|
||||
last_vUVWdot.InitMatrix();
|
||||
vUVWdot.InitMatrix();
|
||||
|
||||
last2_vLocationDot.InitMatrix();
|
||||
last_vLocationDot.InitMatrix();
|
||||
vLocationDot.InitMatrix();
|
||||
|
||||
bind();
|
||||
Debug(0);
|
||||
}
|
||||
|
|
|
@ -199,11 +199,7 @@ bool FGPropulsion::ICEngineStart(void)
|
|||
bool FGPropulsion::Load(Element* el)
|
||||
{
|
||||
string type, engine_filename;
|
||||
int Feed;
|
||||
bool ThrottleAdded = false;
|
||||
Element* document;
|
||||
FGXMLParse engine_file_parser;
|
||||
ifstream* engine_file;
|
||||
|
||||
Debug(2);
|
||||
|
||||
|
@ -217,8 +213,7 @@ bool FGPropulsion::Load(Element* el)
|
|||
}
|
||||
|
||||
engine_filename = FindEngineFullPathname(engine_filename);
|
||||
readXML(engine_filename, engine_file_parser);
|
||||
document = engine_file_parser.GetDocument(); // document holds the engine description
|
||||
document = LoadXMLDocument(engine_filename);
|
||||
document->SetParent(engine_element);
|
||||
|
||||
type = document->GetName();
|
||||
|
@ -253,7 +248,7 @@ bool FGPropulsion::Load(Element* el)
|
|||
numEngines++;
|
||||
|
||||
engine_element = el->FindNextElement("engine");
|
||||
engine_file_parser.reset();
|
||||
ResetParser();
|
||||
}
|
||||
|
||||
// Process tank definitions
|
||||
|
@ -488,7 +483,7 @@ void FGPropulsion::SetCutoff(int setting)
|
|||
|
||||
void FGPropulsion::SetActiveEngine(int engine)
|
||||
{
|
||||
if (engine >= Engines.size() || engine < 0)
|
||||
if (engine >= (int)Engines.size() || engine < 0)
|
||||
ActiveEngine = -1;
|
||||
else
|
||||
ActiveEngine = engine;
|
||||
|
|
|
@ -59,7 +59,7 @@ INCLUDES
|
|||
#include <models/propulsion/FGEngine.h>
|
||||
#include <models/propulsion/FGTank.h>
|
||||
#include <math/FGMatrix33.h>
|
||||
#include <input_output/FGXMLElement.h>
|
||||
#include <input_output/FGXMLFileRead.h>
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
|
@ -97,7 +97,7 @@ CLASS DOCUMENTATION
|
|||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class FGPropulsion : public FGModel
|
||||
class FGPropulsion : public FGModel, public FGXMLFileRead
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
|
|
256
src/FDM/JSBSim/models/flight_control/FGActuator.cpp
Executable file
256
src/FDM/JSBSim/models/flight_control/FGActuator.cpp
Executable file
|
@ -0,0 +1,256 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
Module: FGActuator.cpp
|
||||
Author: Jon Berndt
|
||||
Date started: 21 February 2006
|
||||
|
||||
------------- Copyright (C) 2007 Jon S. Berndt (jsb@hal-pc.org) -------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU 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
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
HISTORY
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
COMMENTS, REFERENCES, and NOTES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGActuator.h"
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id$";
|
||||
static const char *IdHdr = ID_ACTUATOR;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS IMPLEMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
|
||||
FGActuator::FGActuator(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
|
||||
{
|
||||
double denom;
|
||||
dt = fcs->GetDt();
|
||||
|
||||
// inputs are read from the base class constructor
|
||||
|
||||
PreviousOutput = 0.0;
|
||||
PreviousHystOutput = 0.0;
|
||||
PreviousRateLimOutput = 0.0;
|
||||
PreviousLagInput = PreviousLagOutput = 0.0;
|
||||
bias = lag = hysteresis_width = deadband_width = 0.0;
|
||||
rate_limit = 0.0; // no limit
|
||||
fail_zero = fail_hardover = fail_stuck = false;
|
||||
ca = cb = 0.0;
|
||||
|
||||
if ( element->FindElement("deadband_width") ) {
|
||||
deadband_width = element->FindElementValueAsNumber("deadband_width");
|
||||
}
|
||||
if ( element->FindElement("hysteresis_width") ) {
|
||||
hysteresis_width = element->FindElementValueAsNumber("hysteresis_width");
|
||||
}
|
||||
if ( element->FindElement("rate_limit") ) {
|
||||
rate_limit = element->FindElementValueAsNumber("rate_limit");
|
||||
}
|
||||
if ( element->FindElement("bias") ) {
|
||||
bias = element->FindElementValueAsNumber("bias");
|
||||
}
|
||||
if ( element->FindElement("lag") ) {
|
||||
lag = element->FindElementValueAsNumber("lag");
|
||||
denom = 2.00 + dt*lag;
|
||||
ca = dt*lag / denom;
|
||||
cb = (2.00 - dt*lag) / denom;
|
||||
}
|
||||
|
||||
FGFCSComponent::bind();
|
||||
bind();
|
||||
|
||||
Debug(0);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGActuator::~FGActuator()
|
||||
{
|
||||
Debug(1);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGActuator::Run(void )
|
||||
{
|
||||
dt = fcs->GetDt();
|
||||
|
||||
Input = InputNodes[0]->getDoubleValue() * InputSigns[0];
|
||||
Output = Input; // perfect actuator
|
||||
|
||||
if (fail_zero) Input = 0;
|
||||
if (fail_hardover) Input = clipmax*fabs(Input)/Input;
|
||||
|
||||
if (lag != 0.0) Lag(); // models actuator lag
|
||||
if (rate_limit != 0) RateLimit(); // limit the actuator rate
|
||||
if (deadband_width != 0.0) Deadband();
|
||||
if (hysteresis_width != 0.0) Hysteresis();
|
||||
if (bias != 0.0) Bias(); // models a finite bias
|
||||
|
||||
if (fail_stuck) Output = PreviousOutput;
|
||||
PreviousOutput = Output; // previous value needed for "stuck" malfunction
|
||||
|
||||
Clip();
|
||||
if (IsOutput) SetOutput();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGActuator::Bias(void)
|
||||
{
|
||||
Output += bias;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGActuator::Lag(void)
|
||||
{
|
||||
// "Output" on the right side of the "=" is the current frame input
|
||||
// for this Lag filter
|
||||
double input = Output;
|
||||
Output = ca * (input + PreviousLagInput) + PreviousLagOutput * cb;
|
||||
PreviousLagInput = input;
|
||||
PreviousLagOutput = Output;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGActuator::Hysteresis(void)
|
||||
{
|
||||
// Note: this function acts cumulatively on the "Output" parameter. So, "Output"
|
||||
// is - for the purposes of this Hysteresis method - really the input to the
|
||||
// method.
|
||||
double input = Output;
|
||||
|
||||
if (input > PreviousHystOutput) {
|
||||
Output = max(PreviousHystOutput, input-0.5*hysteresis_width);
|
||||
} else if (input < PreviousHystOutput) {
|
||||
Output = min(PreviousHystOutput, input+0.5*hysteresis_width);
|
||||
}
|
||||
|
||||
PreviousHystOutput = Output;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGActuator::RateLimit(void)
|
||||
{
|
||||
// Note: this function acts cumulatively on the "Output" parameter. So, "Output"
|
||||
// is - for the purposes of this RateLimit method - really the input to the
|
||||
// method.
|
||||
double input = Output;
|
||||
if (dt > 0.0) {
|
||||
double rate = (input - PreviousRateLimOutput)/dt;
|
||||
if (fabs(rate) > rate_limit) {
|
||||
Output = PreviousRateLimOutput + (rate_limit*fabs(rate)/rate)*dt;
|
||||
}
|
||||
}
|
||||
PreviousRateLimOutput = Output;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGActuator::Deadband(void)
|
||||
{
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGActuator::bind(void)
|
||||
{
|
||||
string tmp = "fcs/" + PropertyManager->mkPropertyName(Name, true);
|
||||
const string tmp_zero = tmp + "/malfunction/fail_zero";
|
||||
const string tmp_hardover = tmp + "/malfunction/fail_hardover";
|
||||
const string tmp_stuck = tmp + "/malfunction/fail_stuck";
|
||||
|
||||
PropertyManager->Tie( tmp_zero, this, &FGActuator::GetFailZero, &FGActuator::SetFailZero);
|
||||
PropertyManager->Tie( tmp_hardover, this, &FGActuator::GetFailHardover, &FGActuator::SetFailHardover);
|
||||
PropertyManager->Tie( tmp_stuck, this, &FGActuator::GetFailStuck, &FGActuator::SetFailStuck);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// The bitmasked value choices are as follows:
|
||||
// unset: In this case (the default) JSBSim would only print
|
||||
// out the normally expected messages, essentially echoing
|
||||
// the config files as they are read. If the environment
|
||||
// variable is not set, debug_lvl is set to 1 internally
|
||||
// 0: This requests JSBSim not to output any messages
|
||||
// whatsoever.
|
||||
// 1: This value explicity requests the normal JSBSim
|
||||
// startup messages
|
||||
// 2: This value asks for a message to be printed out when
|
||||
// a class is instantiated
|
||||
// 4: When this value is set, a message is displayed when a
|
||||
// FGModel object executes its Run() method
|
||||
// 8: When this value is set, various runtime state variables
|
||||
// are printed out periodically
|
||||
// 16: When set various parameters are sanity checked and
|
||||
// a message is printed out when they go out of bounds
|
||||
|
||||
void FGActuator::Debug(int from)
|
||||
{
|
||||
if (debug_lvl <= 0) return;
|
||||
|
||||
if (debug_lvl & 1) { // Standard console startup message output
|
||||
if (from == 0) { // Constructor
|
||||
if (InputSigns[0] < 0)
|
||||
cout << " INPUT: -" << InputNodes[0]->getName() << endl;
|
||||
else
|
||||
cout << " INPUT: " << InputNodes[0]->getName() << endl;
|
||||
|
||||
if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
|
||||
if (bias != 0.0) cout << " Bias: " << bias << endl;
|
||||
if (rate_limit != 0) cout << " Rate limit: " << rate_limit << endl;
|
||||
if (lag != 0) cout << " Actuator lag: " << lag << endl;
|
||||
if (hysteresis_width != 0) cout << " Hysteresis width: " << hysteresis_width << endl;
|
||||
if (deadband_width != 0) cout << " Deadband width: " << deadband_width << endl;
|
||||
}
|
||||
}
|
||||
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
||||
if (from == 0) cout << "Instantiated: FGActuator" << endl;
|
||||
if (from == 1) cout << "Destroyed: FGActuator" << endl;
|
||||
}
|
||||
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
|
||||
}
|
||||
if (debug_lvl & 8 ) { // Runtime state variables
|
||||
}
|
||||
if (debug_lvl & 16) { // Sanity checking
|
||||
}
|
||||
if (debug_lvl & 64) {
|
||||
if (from == 0) { // Constructor
|
||||
cout << IdSrc << endl;
|
||||
cout << IdHdr << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
176
src/FDM/JSBSim/models/flight_control/FGActuator.h
Executable file
176
src/FDM/JSBSim/models/flight_control/FGActuator.h
Executable file
|
@ -0,0 +1,176 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
Header: FGActuator.h
|
||||
Author: Jon Berndt
|
||||
Date started: 21 February 2007
|
||||
|
||||
------------- Copyright (C) 2006 Jon S. Berndt (jsb@hal-pc.org) -------------
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU 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
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
SENTRY
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#ifndef FGACTUATOR_H
|
||||
#define FGACTUATOR_H
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGFCSComponent.h"
|
||||
#include <input_output/FGXMLElement.h>
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_ACTUATOR "$Id$"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
class FGFCS;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DOCUMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
/** Encapsulates an Actuator component for the flight control system.
|
||||
The actuator can be modeled as a "perfect actuator", with the Output
|
||||
being set directly to the input. The actuator can be made more "real"
|
||||
by specifying any/all of the following additional effects that can be
|
||||
applied to the actuator. In order of application to the input signal,
|
||||
these are:
|
||||
|
||||
-System lag (input lag, really)
|
||||
-Rate limiting
|
||||
-Deadband
|
||||
-Hysteresis (mechanical hysteresis)
|
||||
-Bias (mechanical bias)
|
||||
-Position limiting ("hard stops")
|
||||
|
||||
There are also several malfunctions that can be applied to the actuator
|
||||
by setting a property to true or false (or 1 or 0).
|
||||
|
||||
Syntax:
|
||||
|
||||
@code
|
||||
<actuator name=”name”>
|
||||
<input> {[-]property} </input>
|
||||
<lag> number </lag>
|
||||
<rate_limit> number <rate_limit>
|
||||
<bias> number </bias>
|
||||
<deadband_width> number </deadband_width>
|
||||
<hysteresis_width> number </hysteresis_width>
|
||||
[<clipto>
|
||||
<min> {property name | value} </min>
|
||||
<max> {property name | value} </max>
|
||||
</clipto>]
|
||||
[<output> {property} </output>]
|
||||
</actuator>
|
||||
@endcode
|
||||
|
||||
Example:
|
||||
|
||||
@code
|
||||
<actuator name=”fcs/gimbal_pitch_position”>
|
||||
<input> fcs/gimbal_pitch_command </input>
|
||||
<lag> 60 </lag>
|
||||
<rate_limit> 0.085 <rate_limit> <!-- 5 degrees/sec -->
|
||||
<bias> 0.002 </bias>
|
||||
<deadband_width> 0.002 </deadband_width>
|
||||
<hysteresis_width> 0.05 </hysteresis_width>
|
||||
<clipto> <!-- +/- 10 degrees -->
|
||||
<min> -0.17 </min>
|
||||
<max> 0.17 </max>
|
||||
</clipto>
|
||||
</actuator>
|
||||
@endcode
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Revision$
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class FGActuator : public FGFCSComponent
|
||||
{
|
||||
public:
|
||||
/// Constructor
|
||||
FGActuator(FGFCS* fcs, Element* element);
|
||||
/// Destructor
|
||||
~FGActuator();
|
||||
|
||||
/** This function processes the input.
|
||||
It calls private functions if needed to perform the hysteresis, lag,
|
||||
limiting, etc. functions. */
|
||||
bool Run (void);
|
||||
|
||||
// these may need to have the bool argument replaced with a double
|
||||
/** This function fails the actuator to zero. The motion to zero
|
||||
will flow through the lag, hysteresis, and rate limiting
|
||||
functions if those are activated. */
|
||||
inline void SetFailZero(bool set) {fail_zero = set;}
|
||||
inline void SetFailHardover(bool set) {fail_hardover = set;}
|
||||
inline void SetFailStuck(bool set) {fail_stuck = set;}
|
||||
|
||||
inline bool GetFailZero(void) const {return fail_zero;}
|
||||
inline bool GetFailHardover(void) const {return fail_hardover;}
|
||||
inline bool GetFailStuck(void) const {return fail_stuck;}
|
||||
|
||||
private:
|
||||
double dt;
|
||||
double span;
|
||||
double bias;
|
||||
double rate_limit;
|
||||
double hysteresis_width;
|
||||
double deadband_width;
|
||||
double lag;
|
||||
double ca; // lag filter coefficient "a"
|
||||
double cb; // lag filter coefficient "b"
|
||||
double PreviousOutput;
|
||||
double PreviousHystOutput;
|
||||
double PreviousRateLimOutput;
|
||||
double PreviousLagInput;
|
||||
double PreviousLagOutput;
|
||||
bool fail_zero;
|
||||
bool fail_hardover;
|
||||
bool fail_stuck;
|
||||
|
||||
void Hysteresis(void);
|
||||
void Lag(void);
|
||||
void RateLimit(void);
|
||||
void Deadband(void);
|
||||
void Bias(void);
|
||||
|
||||
void bind(void);
|
||||
|
||||
void Debug(int from);
|
||||
};
|
||||
}
|
||||
#endif
|
|
@ -89,6 +89,8 @@ FGFCSComponent::FGFCSComponent(FGFCS* _fcs, Element* element) : fcs(_fcs)
|
|||
Type = "PID";
|
||||
} else if (element->GetName() == string("sensor")) {
|
||||
Type = "SENSOR";
|
||||
} else if (element->GetName() == string("actuator")) {
|
||||
Type = "ACTUATOR";
|
||||
} else { // illegal component in this channel
|
||||
Type = "UNKNOWN";
|
||||
}
|
||||
|
|
|
@ -54,7 +54,12 @@ FGFCSFunction::FGFCSFunction(FGFCS* fcs, Element* element) : FGFCSComponent(fcs,
|
|||
{
|
||||
Element *function_element = element->FindElement("function");
|
||||
|
||||
function = new FGFunction(PropertyManager, function_element);
|
||||
if (function_element)
|
||||
function = new FGFunction(PropertyManager, function_element);
|
||||
else {
|
||||
cerr << "FCS Function should contain a \"function\" element" << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
FGFCSComponent::bind();
|
||||
Debug(0);
|
||||
|
|
|
@ -81,14 +81,19 @@ bool FGPID::Run(void )
|
|||
Input = InputNodes[0]->getDoubleValue() * InputSigns[0];
|
||||
|
||||
P_out = Kp * (Input - Input_prev);
|
||||
I_out = Ki * dt * Input;
|
||||
D_out = (Kd / dt) * (Input - 2*Input_prev + Input_prev2);
|
||||
|
||||
// Do not continue to integrate the input to the integrator if a wind-up
|
||||
// condition is sensed - that is, if the property pointed to by the trigger
|
||||
// element is non-zero.
|
||||
|
||||
if (Trigger != 0) {
|
||||
double test = Trigger->getDoubleValue();
|
||||
if (fabs(test) > 0.000001) {
|
||||
I_out = 0.0;
|
||||
if (fabs(test) < 0.000001) {
|
||||
I_out = Ki * dt * Input;
|
||||
}
|
||||
} else { // no anti-wind-up trigger defined
|
||||
I_out = Ki * dt * Input;
|
||||
}
|
||||
|
||||
Input_prev = Input;
|
||||
|
|
|
@ -52,12 +52,10 @@ CLASS IMPLEMENTATION
|
|||
FGSensor::FGSensor(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
|
||||
{
|
||||
double denom;
|
||||
dt = fcs->GetState()->Getdt();
|
||||
dt = fcs->GetDt();
|
||||
|
||||
// inputs are read from the base class constructor
|
||||
|
||||
dt = fcs->GetState()->Getdt();
|
||||
|
||||
bits = quantized = divisions = 0;
|
||||
PreviousInput = PreviousOutput = 0.0;
|
||||
min = max = bias = noise_variance = lag = drift_rate = drift = span = 0.0;
|
||||
|
@ -77,6 +75,7 @@ FGSensor::FGSensor(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
|
|||
if ( quantization_element->FindElement("max") ) {
|
||||
max = quantization_element->FindElementValueAsNumber("max");
|
||||
}
|
||||
quant_property = quantization_element->GetAttributeValue("name");
|
||||
span = max - min;
|
||||
granularity = span/divisions;
|
||||
}
|
||||
|
@ -214,6 +213,14 @@ void FGSensor::bind(void)
|
|||
PropertyManager->Tie( tmp_low, this, &FGSensor::GetFailLow, &FGSensor::SetFailLow);
|
||||
PropertyManager->Tie( tmp_high, this, &FGSensor::GetFailHigh, &FGSensor::SetFailHigh);
|
||||
PropertyManager->Tie( tmp_stuck, this, &FGSensor::GetFailStuck, &FGSensor::SetFailStuck);
|
||||
|
||||
if (!quant_property.empty()) {
|
||||
if (quant_property.find("/") == string::npos) { // not found
|
||||
string qprop = "fcs/" + PropertyManager->mkPropertyName(quant_property, true);
|
||||
PropertyManager->Tie(qprop, this, &FGSensor::GetQuantized);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -241,7 +248,35 @@ void FGSensor::Debug(int from)
|
|||
|
||||
if (debug_lvl & 1) { // Standard console startup message output
|
||||
if (from == 0) { // Constructor
|
||||
if (InputSigns[0] < 0)
|
||||
cout << " INPUT: -" << InputNodes[0]->getName() << endl;
|
||||
else
|
||||
cout << " INPUT: " << InputNodes[0]->getName() << endl;
|
||||
|
||||
if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
|
||||
if (bits != 0) {
|
||||
if (quant_property.empty())
|
||||
cout << " Quantized output" << endl;
|
||||
else
|
||||
cout << " Quantized output (property: " << quant_property << ")" << endl;
|
||||
|
||||
cout << " Bits: " << bits << endl;
|
||||
cout << " Min value: " << min << endl;
|
||||
cout << " Max value: " << max << endl;
|
||||
cout << " (span: " << span << ", granularity: " << granularity << ")" << endl;
|
||||
}
|
||||
if (bias != 0.0) cout << " Bias: " << bias << endl;
|
||||
if (drift_rate != 0) cout << " Sensor drift rate: " << drift_rate << endl;
|
||||
if (lag != 0) cout << " Sensor lag: " << lag << endl;
|
||||
if (noise_variance != 0) {
|
||||
if (NoiseType == eAbsolute) {
|
||||
cout << " Noise variance (absolute): " << noise_variance << endl;
|
||||
} else if (NoiseType == ePercent) {
|
||||
cout << " Noise variance (percent): " << noise_variance << endl;
|
||||
} else {
|
||||
cout << " Noise variance type is invalid" << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
||||
|
|
|
@ -63,7 +63,7 @@ CLASS DOCUMENTATION
|
|||
Syntax:
|
||||
|
||||
@code
|
||||
<sensor name=”name” rate_group=”name”>
|
||||
<sensor name=”name”>
|
||||
<input> property </input>
|
||||
<lag> number </lag>
|
||||
<noise variation=”PERCENT|ABSOLUTE”> number </noise>
|
||||
|
@ -80,7 +80,7 @@ Syntax:
|
|||
Example:
|
||||
|
||||
@code
|
||||
<sensor name=”aero/sensor/qbar” rate_group=”HFCS”>
|
||||
<sensor name=”aero/sensor/qbar”>
|
||||
<input> aero/qbar </input>
|
||||
<lag> 0.5 </lag>
|
||||
<noise variation=”PERCENT”> 2 </noise>
|
||||
|
@ -124,6 +124,7 @@ public:
|
|||
inline double GetFailLow(void) const {if (fail_low) return 1.0; else return 0.0;}
|
||||
inline double GetFailHigh(void) const {if (fail_high) return 1.0; else return 0.0;}
|
||||
inline double GetFailStuck(void) const {if (fail_stuck) return 1.0; else return 0.0;}
|
||||
inline int GetQuantized(void) const {return quantized;}
|
||||
|
||||
bool Run (void);
|
||||
|
||||
|
@ -149,6 +150,7 @@ private:
|
|||
bool fail_low;
|
||||
bool fail_high;
|
||||
bool fail_stuck;
|
||||
string quant_property;
|
||||
|
||||
void Noise(void);
|
||||
void Bias(void);
|
||||
|
|
|
@ -94,7 +94,7 @@ FGSwitch::FGSwitch(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
|
|||
else { // error
|
||||
cerr << "Unrecognized LOGIC token " << logic << " in switch component: " << Name << endl;
|
||||
}
|
||||
for (int i=0; i<test_element->GetNumDataLines(); i++)
|
||||
for (unsigned int i=0; i<test_element->GetNumDataLines(); i++)
|
||||
current_test->conditions.push_back(FGCondition(test_element->GetDataLine(i), PropertyManager));
|
||||
|
||||
condition_element = test_element->GetElement(); // retrieve condition groups
|
||||
|
|
|
@ -2,10 +2,11 @@ noinst_LIBRARIES = libFlightControl.a
|
|||
|
||||
libFlightControl_a_SOURCES = FGPID.cpp FGDeadBand.cpp FGFCSComponent.cpp \
|
||||
FGFilter.cpp FGGain.cpp FGGradient.cpp FGKinemat.cpp \
|
||||
FGSummer.cpp FGSwitch.cpp FGFCSFunction.cpp FGSensor.cpp
|
||||
FGSummer.cpp FGSwitch.cpp FGFCSFunction.cpp FGSensor.cpp \
|
||||
FGActuator.cpp
|
||||
|
||||
noinst_HEADERS = FGPID.h FGDeadBand.h FGFCSComponent.h FGFilter.h \
|
||||
FGGain.h FGGradient.h FGKinemat.h FGSummer.h FGSwitch.h FGFCSFunction.h \
|
||||
FGSensor.h
|
||||
FGSensor.h FGActuator.h
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim
|
||||
|
|
|
@ -113,7 +113,7 @@ FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number)
|
|||
else cerr << "No engine location found for this engine." << endl;
|
||||
|
||||
local_element = engine_element->GetParent()->FindElement("orient");
|
||||
if (local_element) orientation = local_element->FindElementTripletConvertTo("IN");
|
||||
if (local_element) orientation = local_element->FindElementTripletConvertTo("DEG");
|
||||
else cerr << "No engine orientation found for this engine." << endl;
|
||||
|
||||
SetPlacement(location, orientation);
|
||||
|
@ -247,12 +247,9 @@ bool FGEngine::LoadThruster(Element *thruster_element)
|
|||
{
|
||||
string token, fullpath, localpath;
|
||||
string thruster_filename, thruster_fullpathname, thrType;
|
||||
double xLoc, yLoc, zLoc, Pitch, Yaw;
|
||||
double P_Factor = 0, Sense = 0.0;
|
||||
string enginePath = FDMExec->GetEnginePath();
|
||||
string aircraftPath = FDMExec->GetFullAircraftPath();
|
||||
FGXMLParse thruster_file_parser;
|
||||
Element *document, *element;
|
||||
ifstream thruster_file;
|
||||
FGColumnVector3 location, orientation;
|
||||
string separator = "/";
|
||||
|
@ -285,8 +282,7 @@ bool FGEngine::LoadThruster(Element *thruster_element)
|
|||
return false;
|
||||
}
|
||||
|
||||
readXML(thruster_fullpathname, thruster_file_parser);
|
||||
document = thruster_file_parser.GetDocument(); // document holds the thruster description
|
||||
document = LoadXMLDocument(thruster_fullpathname);
|
||||
document->SetParent(thruster_element);
|
||||
|
||||
thrType = document->GetName();
|
||||
|
@ -336,8 +332,8 @@ void FGEngine::Debug(int from)
|
|||
cout << " X = " << Thruster->GetLocationX() << endl;
|
||||
cout << " Y = " << Thruster->GetLocationY() << endl;
|
||||
cout << " Z = " << Thruster->GetLocationZ() << endl;
|
||||
cout << " Pitch = " << Thruster->GetAnglesToBody(ePitch) << endl;
|
||||
cout << " Yaw = " << Thruster->GetAnglesToBody(eYaw) << endl;
|
||||
cout << " Pitch = " << radtodeg*Thruster->GetAnglesToBody(ePitch) << " degrees" << endl;
|
||||
cout << " Yaw = " << radtodeg*Thruster->GetAnglesToBody(eYaw) << " degrees" << endl;
|
||||
}
|
||||
}
|
||||
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
||||
|
|
|
@ -60,6 +60,7 @@ INCLUDES
|
|||
#include <FGJSBBase.h>
|
||||
#include "FGThruster.h"
|
||||
#include <input_output/FGPropertyManager.h>
|
||||
#include <input_output/FGXMLFileRead.h>
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
|
@ -102,7 +103,7 @@ CLASS DOCUMENTATION
|
|||
CLASS DECLARATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
class FGEngine : public FGJSBBase
|
||||
class FGEngine : public FGJSBBase, public FGXMLFileRead
|
||||
{
|
||||
public:
|
||||
FGEngine(FGFDMExec* exec, Element* el, int engine_number);
|
||||
|
|
|
@ -61,7 +61,6 @@ FGForce::FGForce(FGFDMExec *FDMExec) :
|
|||
mT(1,1) = 1; //identity matrix
|
||||
mT(2,2) = 1;
|
||||
mT(3,3) = 1;
|
||||
vSense.InitMatrix(1);
|
||||
|
||||
Debug(0);
|
||||
}
|
||||
|
@ -77,7 +76,7 @@ FGForce::~FGForce()
|
|||
|
||||
FGColumnVector3& FGForce::GetBodyForces(void)
|
||||
{
|
||||
vFb = Transform()*(vFn.multElementWise(vSense));
|
||||
vFb = Transform()*vFn;
|
||||
|
||||
// Find the distance from this vector's acting location to the cg; this
|
||||
// needs to be done like this to convert from structural to body coords.
|
||||
|
@ -110,29 +109,38 @@ FGMatrix33 FGForce::Transform(void)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGForce::UpdateCustomTransformMatrix(void)
|
||||
{
|
||||
double cp,sp,cr,sr,cy,sy;
|
||||
|
||||
cp=cos(vOrient(ePitch)); sp=sin(vOrient(ePitch));
|
||||
cr=cos(vOrient(eRoll)); sr=sin(vOrient(eRoll));
|
||||
cy=cos(vOrient(eYaw)); sy=sin(vOrient(eYaw));
|
||||
|
||||
mT(1,1) = cp*cy;
|
||||
mT(1,2) = cp*sy;
|
||||
mT(1,3) = -sp;
|
||||
|
||||
mT(2,1) = sr*sp*cy - cr*sy;
|
||||
mT(2,2) = sr*sp*sy + cr*cy;
|
||||
mT(2,3) = sr*cp;
|
||||
|
||||
mT(3,1) = cr*sp*cy + sr*sy;
|
||||
mT(3,2) = cr*sp*sy - sr*cy;
|
||||
mT(3,3) = cr*cp;
|
||||
mT = mT.Inverse();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGForce::SetAnglesToBody(double broll, double bpitch, double byaw)
|
||||
{
|
||||
if (ttype == tCustom) {
|
||||
double cp,sp,cr,sr,cy,sy;
|
||||
vOrient(ePitch) = bpitch;
|
||||
vOrient(eRoll) = broll;
|
||||
vOrient(eYaw) = byaw;
|
||||
|
||||
cp=cos(bpitch); sp=sin(bpitch);
|
||||
cr=cos(broll); sr=sin(broll);
|
||||
cy=cos(byaw); sy=sin(byaw);
|
||||
|
||||
mT(1,1)=cp*cy;
|
||||
mT(1,2)=cp*sy;
|
||||
mT(1,3)=-1*sp;
|
||||
|
||||
mT(2,1)=sr*sp*cy-cr*sy;
|
||||
mT(2,2)=sr*sp*sy+cr*cy;
|
||||
mT(2,3)=sr*cp;
|
||||
|
||||
mT(3,1)=cr*sp*cy+sr*sy;
|
||||
mT(3,2)=cr*sp*sy-sr*cy;
|
||||
mT(3,3)=cr*cp;
|
||||
UpdateCustomTransformMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ can now be retrieved by calling:</p>
|
|||
|
||||
<p>This method is where the bulk of the work gets done so calling it more than
|
||||
once for the same set of native forces and moments should probably be avoided.
|
||||
Note that the moment calculations are done here as well so they should not be
|
||||
Note that the moment calculations are done here as well so they should be
|
||||
retrieved after calling the GetBodyForces() method:</p>
|
||||
|
||||
<p><tt>vM=fgf.GetMoments();</tt> </p>
|
||||
|
@ -230,24 +230,7 @@ public:
|
|||
/// Destructor
|
||||
~FGForce();
|
||||
|
||||
enum TransformType { tNone, tWindBody, tLocalBody, tCustom } ttype;
|
||||
|
||||
inline void SetNativeForces(double Fnx, double Fny, double Fnz) {
|
||||
vFn(1)=Fnx;
|
||||
vFn(2)=Fny;
|
||||
vFn(3)=Fnz;
|
||||
}
|
||||
inline void SetNativeForces(FGColumnVector3 vv) { vFn = vv; };
|
||||
|
||||
inline void SetNativeMoments(double Ln,double Mn, double Nn) {
|
||||
vMn(1)=Ln;
|
||||
vMn(2)=Mn;
|
||||
vMn(3)=Nn;
|
||||
}
|
||||
inline void SetNativeMoments(FGColumnVector3 vv) { vMn = vv; }
|
||||
|
||||
inline FGColumnVector3& GetNativeForces(void) { return vFn; }
|
||||
inline FGColumnVector3& GetNativeMoments(void) { return vMn; }
|
||||
enum TransformType { tNone, tWindBody, tLocalBody, tCustom };
|
||||
|
||||
FGColumnVector3& GetBodyForces(void);
|
||||
|
||||
|
@ -305,18 +288,15 @@ public:
|
|||
SetAnglesToBody(vv(eRoll), vv(ePitch), vv(eYaw));
|
||||
}
|
||||
|
||||
void SetPitch(double pitch) {vOrient(ePitch) = pitch;}
|
||||
void SetYaw(double yaw) {vOrient(eYaw) = yaw;}
|
||||
void UpdateCustomTransformMatrix(void);
|
||||
void SetPitch(double pitch) {vOrient(ePitch) = pitch; UpdateCustomTransformMatrix();}
|
||||
void SetYaw(double yaw) {vOrient(eYaw) = yaw; UpdateCustomTransformMatrix();}
|
||||
|
||||
double GetPitch(void) const {return vOrient(ePitch);}
|
||||
double GetYaw(void) const {return vOrient(eYaw);}
|
||||
|
||||
inline void SetSense(double x, double y, double z) { vSense(eX)=x, vSense(eY)=y, vSense(eZ)=z; }
|
||||
inline void SetSense(FGColumnVector3 vv) { vSense=vv; }
|
||||
|
||||
inline FGColumnVector3& GetAnglesToBody(void) {return vOrient;}
|
||||
inline double GetAnglesToBody(int axis) {return vOrient(axis);}
|
||||
inline FGColumnVector3& GetSense(void) { return vSense; }
|
||||
|
||||
inline void SetTransformType(TransformType ii) { ttype=ii; }
|
||||
inline TransformType GetTransformType(void) { return ttype; }
|
||||
|
@ -329,14 +309,14 @@ protected:
|
|||
FGColumnVector3 vMn;
|
||||
FGColumnVector3 vH;
|
||||
FGColumnVector3 vOrient;
|
||||
TransformType ttype;
|
||||
FGColumnVector3 vXYZn;
|
||||
FGColumnVector3 vActingXYZn;
|
||||
|
||||
private:
|
||||
FGColumnVector3 vFb;
|
||||
FGColumnVector3 vM;
|
||||
FGColumnVector3 vXYZn;
|
||||
FGColumnVector3 vActingXYZn;
|
||||
FGColumnVector3 vDXYZ;
|
||||
FGColumnVector3 vSense;
|
||||
|
||||
FGMatrix33 mT;
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ FGNozzle::FGNozzle(FGFDMExec* FDMExec, Element* nozzle_element, int num)
|
|||
Type = ttNozzle;
|
||||
Area2 = (Diameter*Diameter/4.0)*M_PI;
|
||||
AreaT = Area2/ExpR;
|
||||
|
||||
|
||||
Debug(0);
|
||||
}
|
||||
|
||||
|
@ -99,7 +99,11 @@ FGNozzle::~FGNozzle()
|
|||
double FGNozzle::Calculate(double CfPc)
|
||||
{
|
||||
double pAtm = fdmex->GetAtmosphere()->GetPressure();
|
||||
Thrust = max((double)0.0, (CfPc * AreaT + (PE - pAtm)*Area2) * nzlEff);
|
||||
if (CfPc > 0)
|
||||
Thrust = max((double)0.0, (CfPc * AreaT + (PE - pAtm)*Area2) * nzlEff);
|
||||
else
|
||||
Thrust = 0.0;
|
||||
|
||||
vFn(1) = Thrust * cos(ReverserAngle);
|
||||
|
||||
ThrustCoeff = max((double)0.0, CfPc / ((pAtm - PE) * Area2));
|
||||
|
@ -120,7 +124,7 @@ string FGNozzle::GetThrusterLabels(int id, string delimeter)
|
|||
{
|
||||
std::ostringstream buf;
|
||||
|
||||
buf << Name << "_Thrust[" << id << ']';
|
||||
buf << Name << " Thrust (engine " << id << " in lbs)";
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
|
|
@ -198,7 +198,7 @@ FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number)
|
|||
}
|
||||
minMAP = MinManifoldPressure_inHg * 3386.38; // inHg to Pa
|
||||
maxMAP = MaxManifoldPressure_inHg * 3386.38;
|
||||
StarterHP = sqrt(MaxHP) * 0.2;
|
||||
StarterHP = sqrt(MaxHP) * 0.4;
|
||||
|
||||
// Set up and sanity-check the turbo/supercharging configuration based on the input values.
|
||||
if (TakeoffBoost > RatedBoost[0]) bTakeoffBoost = true;
|
||||
|
@ -580,7 +580,7 @@ void FGPiston::doEnginePower(void)
|
|||
if (RPM < 10) {
|
||||
HP = StarterHP;
|
||||
} else if (RPM < 480) {
|
||||
HP = StarterHP + ((480 - RPM) / 10.0);
|
||||
HP = StarterHP + ((480 - RPM) / 8.0);
|
||||
// This is a guess - would be nice to find a proper starter moter torque curve
|
||||
} else {
|
||||
HP = StarterHP;
|
||||
|
@ -593,7 +593,7 @@ void FGPiston::doEnginePower(void)
|
|||
HP = 0.0;
|
||||
}
|
||||
}
|
||||
//cout << "Power = " << HP << '\n';
|
||||
// cout << "Power = " << HP << " RPM = " << RPM << " Running = " << Running << " Cranking = " << Cranking << endl;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -729,10 +729,10 @@ string FGPiston::GetEngineLabels(string delimeter)
|
|||
{
|
||||
std::ostringstream buf;
|
||||
|
||||
buf << Name << "_PwrAvail[" << EngineNumber << "]" << delimeter
|
||||
<< Name << "_HP[" << EngineNumber << "]" << delimeter
|
||||
<< Name << "_equiv_ratio[" << EngineNumber << "]" << delimeter
|
||||
<< Name << "_MAP[" << EngineNumber << "]" << delimeter
|
||||
buf << Name << " Power Available (engine " << EngineNumber << " in HP)" << delimeter
|
||||
<< Name << " HP (engine " << EngineNumber << ")" << delimeter
|
||||
<< Name << " equivalent ratio (engine " << EngineNumber << ")" << delimeter
|
||||
<< Name << " MAP (engine " << EngineNumber << ")" << delimeter
|
||||
<< Thruster->GetThrusterLabels(EngineNumber, delimeter);
|
||||
|
||||
return buf.str();
|
||||
|
|
|
@ -60,7 +60,6 @@ FGPropeller::FGPropeller(FGFDMExec* exec, Element* prop_element, int num)
|
|||
: FGThruster(exec, prop_element, num)
|
||||
{
|
||||
string token;
|
||||
int rows, cols;
|
||||
Element *table_element, *local_element;
|
||||
string name="";
|
||||
FGPropertyManager* PropertyManager = exec->GetPropertyManager();
|
||||
|
@ -297,13 +296,13 @@ string FGPropeller::GetThrusterLabels(int id, string delimeter)
|
|||
{
|
||||
std::ostringstream buf;
|
||||
|
||||
buf << Name << "_Torque[" << id << "]" << delimeter
|
||||
<< Name << "_PFactor_Pitch[" << id << "]" << delimeter
|
||||
<< Name << "_PFactor_Yaw[" << id << "]" << delimeter
|
||||
<< Name << "_Thrust[" << id << "]" << delimeter;
|
||||
buf << Name << " Torque (engine " << id << ")" << delimeter
|
||||
<< Name << " PFactor Pitch (engine " << id << ")" << delimeter
|
||||
<< Name << " PFactor Yaw (engine " << id << ")" << delimeter
|
||||
<< Name << " Thrust (engine " << id << " in lbs)" << delimeter;
|
||||
if (IsVPitch())
|
||||
buf << Name << "_Pitch[" << id << "]" << delimeter;
|
||||
buf << Name << "_RPM[" << id << "]";
|
||||
buf << Name << " Pitch (engine " << id << ")" << delimeter;
|
||||
buf << Name << " RPM (engine " << id << ")";
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
|
|
@ -54,6 +54,15 @@ CLASS IMPLEMENTATION
|
|||
FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number)
|
||||
: FGEngine(exec, el, engine_number)
|
||||
{
|
||||
Element* thrust_table_element = 0;
|
||||
ThrustTable = 0L;
|
||||
BurnTime = 0.0;
|
||||
|
||||
// Defaults
|
||||
Variance = 0.0;
|
||||
MinThrottle = 0.0;
|
||||
MaxThrottle = 1.0;
|
||||
|
||||
if (el->FindElement("shr"))
|
||||
SHR = el->FindElementValueAsNumber("shr");
|
||||
if (el->FindElement("max_pc"))
|
||||
|
@ -71,6 +80,11 @@ FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number)
|
|||
if (el->FindElement("variance"))
|
||||
Variance = el->FindElementValueAsNumber("variance");
|
||||
|
||||
thrust_table_element = el->FindElement("thrust_table");
|
||||
if (thrust_table_element) {
|
||||
ThrustTable = new FGTable(PropertyManager, thrust_table_element);
|
||||
}
|
||||
|
||||
Debug(0);
|
||||
|
||||
Type = etRocket;
|
||||
|
@ -97,6 +111,18 @@ double FGRocket::Calculate(void)
|
|||
|
||||
Throttle = FCS->GetThrottlePos(EngineNumber);
|
||||
|
||||
// If there is a thrust table, it is a function of elapsed burn time. The engine
|
||||
// is started when the throttle is advanced to 1.0. After that, it burns
|
||||
// without regard to throttle setting. The table returns a value between zero
|
||||
// and one, representing the percentage of maximum vacuum thrust being applied.
|
||||
|
||||
if (ThrustTable != 0L) {
|
||||
if (Throttle == 1 || BurnTime > 0.0) {
|
||||
BurnTime += State->Getdt();
|
||||
}
|
||||
Throttle = ThrustTable->GetValue(BurnTime);
|
||||
}
|
||||
|
||||
if (Throttle < MinThrottle || Starved) {
|
||||
PctPower = Thrust = 0.0; // desired thrust
|
||||
Flameout = true;
|
||||
|
@ -122,7 +148,7 @@ string FGRocket::GetEngineLabels(string delimeter)
|
|||
{
|
||||
std::ostringstream buf;
|
||||
|
||||
buf << Name << "_ChamberPress[" << EngineNumber << "]" << delimeter
|
||||
buf << Name << " Chamber Pressure (engine " << EngineNumber << " in psf)" << delimeter
|
||||
<< Thruster->GetThrusterLabels(EngineNumber, delimeter);
|
||||
|
||||
return buf.str();
|
||||
|
|
|
@ -39,6 +39,7 @@ INCLUDES
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGEngine.h"
|
||||
#include <math/FGTable.h>
|
||||
#include <input_output/FGXMLElement.h>
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -83,6 +84,45 @@ CLASS DOCUMENTATION
|
|||
coefficient is multiplied by the chamber pressure and then passed
|
||||
to the nozzle Calculate() routine, where the thrust force is
|
||||
determined.
|
||||
|
||||
One can model the thrust of a solid rocket by providing a normalized thrust table
|
||||
as a function of time. For instance, the space shuttle solid rocket booster
|
||||
normalized thrust value looks roughly like this:
|
||||
|
||||
<pre>
|
||||
<thrust_table name="propulsion/thrust_time" type="internal">
|
||||
<tableData>
|
||||
0.0 0.00
|
||||
0.2 0.91
|
||||
8.0 0.97
|
||||
16.0 0.99
|
||||
20.0 1.00
|
||||
21.0 1.00
|
||||
24.0 0.95
|
||||
32.0 0.85
|
||||
40.0 0.78
|
||||
48.0 0.72
|
||||
50.0 0.71
|
||||
52.0 0.71
|
||||
56.0 0.73
|
||||
64.0 0.78
|
||||
72.0 0.82
|
||||
80.0 0.81
|
||||
88.0 0.73
|
||||
96.0 0.69
|
||||
104.0 0.59
|
||||
112.0 0.46
|
||||
120.0 0.09
|
||||
132.0 0.00
|
||||
</tableData>
|
||||
</thrust_table>
|
||||
</pre>
|
||||
|
||||
The left column is time, the right column is normalized thrust. Inside the
|
||||
FGRocket class code, the maximum thrust is calculated, and multiplied by this
|
||||
table. The Rocket class also tracks burn time. All that needs to be done is
|
||||
for the rocket engine to be throttle up to 1. At that time, the solid rocket
|
||||
fuel begins burning and thrust is provided.
|
||||
|
||||
@author Jon S. Berndt
|
||||
$Id$
|
||||
|
@ -133,7 +173,9 @@ private:
|
|||
double kFactor;
|
||||
double Variance;
|
||||
double PC;
|
||||
double BurnTime;
|
||||
bool Flameout;
|
||||
FGTable* ThrustTable;
|
||||
|
||||
void Debug(int from);
|
||||
};
|
||||
|
|
|
@ -58,7 +58,7 @@ FGThruster::FGThruster(FGFDMExec *FDMExec, Element *el, int num ): FGForce(FDMEx
|
|||
Type = ttDirect;
|
||||
SetTransformType(FGForce::tCustom);
|
||||
|
||||
Name = el->GetName();
|
||||
Name = el->GetAttributeValue("name");
|
||||
|
||||
GearRatio = 1.0;
|
||||
ReverserAngle = 0.0;
|
||||
|
@ -73,7 +73,7 @@ FGThruster::FGThruster(FGFDMExec *FDMExec, Element *el, int num ): FGForce(FDMEx
|
|||
else cerr << "No thruster location found." << endl;
|
||||
|
||||
element = thruster_element->FindElement("orient");
|
||||
if (element) orientation = element->FindElementTripletConvertTo("IN");
|
||||
if (element) orientation = element->FindElementTripletConvertTo("RAD");
|
||||
else cerr << "No thruster orientation found." << endl;
|
||||
|
||||
SetLocation(location);
|
||||
|
@ -122,7 +122,7 @@ string FGThruster::GetThrusterLabels(int id, string delimeter)
|
|||
{
|
||||
std::ostringstream buf;
|
||||
|
||||
buf << Name << "_Thrust[" << id << "]";
|
||||
buf << Name << " Thrust (engine " << id << " in lbs)";
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
|
|
@ -278,7 +278,7 @@ double FGTurboProp::Off(void)
|
|||
|
||||
double FGTurboProp::Run(void)
|
||||
{
|
||||
double idlethrust, milthrust, thrust = 0.0, EngPower_HP, eff_coef;
|
||||
double thrust = 0.0, EngPower_HP, eff_coef;
|
||||
Running = true; Starter = false; EngStarting = false;
|
||||
|
||||
//---
|
||||
|
|
Loading…
Reference in a new issue