1
0
Fork 0

Sync w. JSBSim CVS (merge from PRE_OSG_PLIB_20061029 branch)

This commit is contained in:
mfranz 2007-06-03 09:37:02 +00:00
parent 2c3dc5fca1
commit 3cda82e0a9
56 changed files with 985 additions and 503 deletions

View file

@ -134,6 +134,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root)
modelLoaded = false; modelLoaded = false;
IsSlave = false; IsSlave = false;
holding = false; holding = false;
Terminate = false;
// Multiple FDM's are stopped for now. We need to ensure that // Multiple FDM's are stopped for now. We need to ensure that
// the "user" instance always gets the zeroeth instance number, // the "user" instance always gets the zeroeth instance number,
@ -168,6 +169,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root)
Constructing = true; Constructing = true;
typedef int (FGFDMExec::*iPMF)(void) const; typedef int (FGFDMExec::*iPMF)(void) const;
instance->Tie("simulation/do_trim", this, (iPMF)0, &FGFDMExec::DoTrim); instance->Tie("simulation/do_trim", this, (iPMF)0, &FGFDMExec::DoTrim);
instance->Tie("simulation/terminate", (int *)&Terminate);
Constructing = false; Constructing = false;
} }
@ -176,6 +178,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root)
FGFDMExec::~FGFDMExec() FGFDMExec::~FGFDMExec()
{ {
instance->Untie("simulation/do_trim"); instance->Untie("simulation/do_trim");
instance->Untie("simulation/terminate");
try { try {
DeAllocate(); DeAllocate();
@ -354,7 +357,7 @@ int FGFDMExec::Schedule(FGModel* model, int rate)
bool FGFDMExec::Run(void) bool FGFDMExec::Run(void)
{ {
bool success = false; bool success=false;
FGModel* model_iterator; FGModel* model_iterator;
model_iterator = FirstModel; model_iterator = FirstModel;
@ -376,6 +379,7 @@ bool FGFDMExec::Run(void)
Frame++; Frame++;
if (!Holding()) State->IncrTime(); if (!Holding()) State->IncrTime();
if (Terminate) success = false;
return (success); return (success);
} }
@ -459,6 +463,9 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath)
string token; string token;
string aircraftCfgFileName; string aircraftCfgFileName;
string separator = "/"; string separator = "/";
Element* element = 0L;
modelName = model; // Set the class modelName attribute
# ifdef macintosh # ifdef macintosh
separator = ";"; separator = ";";
@ -474,27 +481,12 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath)
if (addModelToPath) FullAircraftPath += separator + model; if (addModelToPath) FullAircraftPath += separator + model;
aircraftCfgFileName = FullAircraftPath + separator + model + ".xml"; 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) { if (modelLoaded) {
DeAllocate(); DeAllocate();
Allocate(); Allocate();
} }
document = LoadXMLDocument(aircraftCfgFileName); // "document" is a class member
ReadPrologue(document); ReadPrologue(document);
element = document->GetElement(); element = document->GetElement();
@ -553,7 +545,7 @@ void FGFDMExec::BuildPropertyCatalog(struct PropertyCatalogStructure* pcs)
int node_idx = 0; int node_idx = 0;
char int_buf[10]; 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(); pcsNew->base_string = pcs->base_string + "/" + pcs->node->getChild(i)->getName();
node_idx = pcs->node->getChild(i)->getIndex(); node_idx = pcs->node->getChild(i)->getIndex();
sprintf(int_buf, "[%d]", node_idx); sprintf(int_buf, "[%d]", node_idx);

View file

@ -48,8 +48,8 @@ INCLUDES
#include <initialization/FGInitialCondition.h> #include <initialization/FGInitialCondition.h>
#include <FGJSBBase.h> #include <FGJSBBase.h>
#include <input_output/FGPropertyManager.h> #include <input_output/FGPropertyManager.h>
#include <input_output/FGXMLParse.h>
#include <input_output/FGGroundCallback.h> #include <input_output/FGGroundCallback.h>
#include <input_output/FGXMLFileRead.h>
#include <models/FGPropagate.h> #include <models/FGPropagate.h>
#include <vector> #include <vector>
@ -173,7 +173,7 @@ CLASS DOCUMENTATION
CLASS DECLARATION CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGFDMExec : public FGJSBBase class FGFDMExec : public FGJSBBase, public FGXMLFileRead
{ {
public: public:
@ -414,6 +414,7 @@ private:
int Error; int Error;
unsigned int Frame; unsigned int Frame;
unsigned int IdFDM; unsigned int IdFDM;
unsigned short Terminate;
bool holding; bool holding;
bool Constructing; bool Constructing;
bool modelLoaded; bool modelLoaded;

View file

@ -94,9 +94,9 @@ const double FGJSBBase::slugtolb = 32.174049;
const double FGJSBBase::lbtoslug = 1.0/slugtolb; const double FGJSBBase::lbtoslug = 1.0/slugtolb;
const string FGJSBBase::needed_cfg_version = "2.0"; 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; FGJSBBase::Message FGJSBBase::localMsg;
unsigned int FGJSBBase::messageId = 0; 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); Messages.push(msg);
return msg;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGJSBBase::Message* FGJSBBase::PutMessage(const string& text) void FGJSBBase::PutMessage(const string& text)
{ {
Message *msg = new Message(); Message msg;
msg->text = text; msg.text = text;
msg->messageId = messageId++; msg.messageId = messageId++;
msg->subsystem = "FDM"; msg.subsystem = "FDM";
msg->type = Message::eText; msg.type = Message::eText;
Messages.push(msg); 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(); Message msg;
msg->text = text; msg.text = text;
msg->messageId = messageId++; msg.messageId = messageId++;
msg->subsystem = "FDM"; msg.subsystem = "FDM";
msg->type = Message::eBool; msg.type = Message::eBool;
msg->bVal = bVal; msg.bVal = bVal;
Messages.push(msg); 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(); Message msg;
msg->text = text; msg.text = text;
msg->messageId = messageId++; msg.messageId = messageId++;
msg->subsystem = "FDM"; msg.subsystem = "FDM";
msg->type = Message::eInteger; msg.type = Message::eInteger;
msg->bVal = (iVal != 0); msg.bVal = (iVal != 0);
Messages.push(msg); 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(); Message msg;
msg->text = text; msg.text = text;
msg->messageId = messageId++; msg.messageId = messageId++;
msg->subsystem = "FDM"; msg.subsystem = "FDM";
msg->type = Message::eDouble; msg.type = Message::eDouble;
msg->bVal = (dVal != 0.0); msg.bVal = (dVal != 0.0);
Messages.push(msg); Messages.push(msg);
return msg;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGJSBBase::Message* FGJSBBase::ReadMessage(void) int FGJSBBase::SomeMessages(void)
{ {
if (!Messages.empty()) return Messages.front(); return !Messages.empty();
else return NULL;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGJSBBase::Message* FGJSBBase::ProcessMessage(void) FGJSBBase::Message* FGJSBBase::ProcessMessage(void)
{ {
if (!Messages.empty()) if (Messages.empty()) return NULL;
localMsg = *(Messages.front()); localMsg = Messages.front();
else
return NULL;
Messages.pop(); Messages.pop();
return &localMsg; return &localMsg;
} }

View file

@ -125,7 +125,8 @@ public:
~FGJSBBase() {}; ~FGJSBBase() {};
/// JSBSim Message structure /// JSBSim Message structure
typedef struct Msg { class Message {
public:
unsigned int fdmId; unsigned int fdmId;
unsigned int messageId; unsigned int messageId;
string text; string text;
@ -134,7 +135,7 @@ public:
bool bVal; bool bVal;
int iVal; int iVal;
double dVal; double dVal;
} Message; };
///@name JSBSim console output highlighting terms. ///@name JSBSim console output highlighting terms.
//@{ //@{
@ -167,29 +168,29 @@ public:
/** Places a Message structure on the Message queue. /** Places a Message structure on the Message queue.
@param msg pointer to a Message structure @param msg pointer to a Message structure
@return 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. /** Creates a message with the given text and places it on the queue.
@param text message text @param text message text
@return pointer to a Message structure */ @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. /** Creates a message with the given text and boolean value and places it on the queue.
@param text message text @param text message text
@param bVal boolean value associated with the message @param bVal boolean value associated with the message
@return pointer to a Message structure */ @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. /** Creates a message with the given text and integer value and places it on the queue.
@param text message text @param text message text
@param iVal integer value associated with the message @param iVal integer value associated with the message
@return pointer to a Message structure */ @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. /** Creates a message with the given text and double value and places it on the queue.
@param text message text @param text message text
@param dVal double value associated with the message @param dVal double value associated with the message
@return pointer to a Message structure */ @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). /** Reads the message on the queue (but does not delete it).
@return pointer to a Message structure (or NULL if no mesage) */ @return 1 if some messages */
Message* ReadMessage(void); int SomeMessages(void);
/** Reads the message on the queue and removes it from the queue. /** Reads the message on the queue and removes it from the queue.
@return pointer to a Message structure (or NULL if no mesage) */ @return pointer to a Message structure (or NULL if no mesage) */
Message* ProcessMessage(void); Message* ProcessMessage(void);
@ -276,7 +277,7 @@ public:
protected: protected:
static Message localMsg; static Message localMsg;
static std::queue <Message*> Messages; static std::queue <Message> Messages;
void Debug(int from) {}; void Debug(int from) {};

View file

@ -47,10 +47,6 @@ INCLUDES
# endif # endif
#endif #endif
#ifdef _WIN32
//#define snprintf _snprintf
#endif
#include "FGState.h" #include "FGState.h"
namespace JSBSim { 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) void FGState::bind(void)
{ {
PropertyManager->Tie("sim-time-sec", this, &FGState::Getsim_time); PropertyManager->Tie("sim-time-sec", this, &FGState::Getsim_time);

View file

@ -466,7 +466,7 @@ void FGJSBsim::update( double dt )
} }
FGJSBBase::Message* msg; FGJSBBase::Message* msg;
while (fdmex->ReadMessage()) { while (fdmex->SomeMessages()) {
msg = fdmex->ProcessMessage(); msg = fdmex->ProcessMessage();
switch (msg->type) { switch (msg->type) {
case FGJSBBase::Message::eText: case FGJSBBase::Message::eText:
@ -1105,8 +1105,10 @@ void FGJSBsim::do_trim(void)
} else { } else {
trimmed->setBoolValue(true); trimmed->setBoolValue(true);
} }
#if 0
if (FGJSBBase::debug_lvl > 0) if (FGJSBBase::debug_lvl > 0)
State->ReportState(); State->ReportState(); /* FIXME: Function not implemented */
#endif
delete fgtrim; delete fgtrim;

View file

@ -732,9 +732,6 @@ double FGInitialCondition::GetWindDirDegIC(void) const {
bool FGInitialCondition::Load(string rstfile, bool useStoredPath) bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
{ {
string resetDef; string resetDef;
ifstream initialization_file;
FGXMLParse initialization_file_parser;
Element *document, *el;
int n; int n;
string sep = "/"; string sep = "/";
@ -748,15 +745,8 @@ bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
resetDef = rstfile; resetDef = rstfile;
} }
initialization_file.open(resetDef.c_str()); document = LoadXMLDocument(resetDef);
if ( !initialization_file.is_open()) {
cerr << "Could not open initialization file: " << resetDef << endl;
return false;
}
readXML(initialization_file, initialization_file_parser);
document = initialization_file_parser.GetDocument(); // document holds the
// initialization description
if (document->GetName() != string("initialize")) { if (document->GetName() != string("initialize")) {
cerr << "File: " << resetDef << " is not a reset file" << endl; cerr << "File: " << resetDef << " is not a reset file" << endl;
exit(-1); exit(-1);
@ -803,10 +793,10 @@ bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
if (document->FindElement("vground")) if (document->FindElement("vground"))
SetVgroundKtsIC(document->FindElementValueAsNumberConvertTo("vground", "FT/SEC")); SetVgroundKtsIC(document->FindElementValueAsNumberConvertTo("vground", "FT/SEC"));
if (document->FindElement("running")) { if (document->FindElement("running")) {
n = document->FindElementValueAsNumber("running"); n = int(document->FindElementValueAsNumber("running"));
if (n != 0) { if (n != 0) {
FGPropulsion* propulsion = fdmex->GetPropulsion(); 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); propulsion->GetEngine(i)->SetRunning(true);
} }
} }

View file

@ -50,6 +50,7 @@ INCLUDES
#include <FGFDMExec.h> #include <FGFDMExec.h>
#include <FGJSBBase.h> #include <FGJSBBase.h>
#include <math/FGColumnVector3.h> #include <math/FGColumnVector3.h>
#include <input_output/FGXMLFileRead.h>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS DEFINITIONS
@ -199,7 +200,7 @@ CLASS DOCUMENTATION
CLASS DECLARATION CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGInitialCondition : public FGJSBBase class FGInitialCondition : public FGJSBBase, public FGXMLFileRead
{ {
public: public:
/// Constructor /// Constructor

View file

@ -106,12 +106,34 @@ bool FGPropertyManager::HasNode (const string &path)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGPropertyManager::GetName( void ) { string FGPropertyManager::GetName( void )
{
return string( getName() ); 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) { string FGPropertyManager::GetFullyQualifiedName(void) {
vector<string> stack; vector<string> stack;
stack.push_back( getDisplayName(true) ); stack.push_back( getDisplayName(true) );

View file

@ -115,6 +115,11 @@ class FGPropertyManager : public SGPropertyNode, public FGJSBBase
*/ */
string GetName( void ); string GetName( void );
/**
* Get the name of a node without underscores, etc.
*/
string GetPrintableName( void );
/** /**
* Get the fully qualified name of a node * Get the fully qualified name of a node
* This function is very slow, so is probably useful for debugging only. * This function is very slow, so is probably useful for debugging only.

View file

@ -84,7 +84,7 @@ FGScript::FGScript(FGFDMExec* fgex) : FDMExec(fgex)
FGScript::~FGScript() FGScript::~FGScript()
{ {
int i; unsigned int i;
for (i=0; i<local_properties.size(); i++) for (i=0; i<local_properties.size(); i++)
PropertyManager->Untie(local_properties[i]->title); PropertyManager->Untie(local_properties[i]->title);
@ -101,21 +101,16 @@ bool FGScript::LoadScript( string script )
{ {
string aircraft="", initialize="", comparison = "", prop_name=""; string aircraft="", initialize="", comparison = "", prop_name="";
string notifyPropertyName=""; 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 *condition_element=0, *set_element=0, *delay_element=0;
Element *notify_element = 0L, *notify_property_element = 0L; Element *notify_element = 0L, *notify_property_element = 0L;
Element *property_element = 0L; Element *property_element = 0L;
bool result = false; bool result = false;
double dt = 0.0, value = 0.0; double dt = 0.0, value = 0.0;
FGXMLParse script_file_parser;
struct event *newEvent; struct event *newEvent;
FGCondition *newCondition; FGCondition *newCondition;
ifstream script_file(script.c_str());
if ( !script_file ) return false; document = LoadXMLDocument(script);
readXML(script_file, script_file_parser);
document = script_file_parser.GetDocument();
if (document->GetName() != string("runscript")) { if (document->GetName() != string("runscript")) {
cerr << "File: " << script << " is not a script file" << endl; cerr << "File: " << script << " is not a script file" << endl;
@ -309,20 +304,11 @@ bool FGScript::RunScript(void)
iEvent->Triggered = true; iEvent->Triggered = true;
} else if (iEvent->Persistent) { } else if (iEvent->Persistent) {
iEvent->Triggered = false; // Reset the trigger for persistent events iEvent->Triggered = false; // Reset the trigger for persistent events
iEvent->Notified = false; // Also reset the notification flag
} }
if ((currentTime >= iEvent->StartTime) && iEvent->Triggered) { 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++) { for (i=0; i<iEvent->SetValue.size(); i++) {
if (iEvent->Transiting[i]) { if (iEvent->Transiting[i]) {
iEvent->TimeSpan = currentTime - iEvent->StartTime; iEvent->TimeSpan = currentTime - iEvent->StartTime;
@ -349,6 +335,19 @@ bool FGScript::RunScript(void)
iEvent->SetParam[i]->setDoubleValue(newSetValue); 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++; iEvent++;

View file

@ -42,6 +42,7 @@ INCLUDES
#include "FGFDMExec.h" #include "FGFDMExec.h"
#include <math/FGCondition.h> #include <math/FGCondition.h>
#include <vector> #include <vector>
#include <input_output/FGXMLFileRead.h>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS DEFINITIONS
@ -162,7 +163,7 @@ CLASS DOCUMENTATION
CLASS DECLARATION CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGScript : public FGJSBBase class FGScript : public FGJSBBase, public FGXMLFileRead
{ {
public: public:
/// Default constructor /// Default constructor
@ -201,6 +202,7 @@ private:
bool Triggered; bool Triggered;
bool PrevTriggered; bool PrevTriggered;
bool Notify; bool Notify;
bool Notified;
double Delay; double Delay;
double StartTime; double StartTime;
double TimeSpan; double TimeSpan;
@ -221,7 +223,7 @@ private:
PrevTriggered = false; PrevTriggered = false;
Persistent = false; Persistent = false;
Delay = 0.0; Delay = 0.0;
Notify = false; Notify = Notified = false;
Name = ""; Name = "";
StartTime = 0.0; StartTime = 0.0;
TimeSpan = 0.0; TimeSpan = 0.0;

View file

@ -292,31 +292,32 @@ string Element::FindElementValue(string el)
double Element::FindElementValueAsNumberConvertTo(string el, string target_units) double Element::FindElementValueAsNumberConvertTo(string el, string target_units)
{ {
Element* element = FindElement(el); Element* element = FindElement(el);
double value;
string supplied_units="";
if (element) { if (!element) {
value = element->GetDataAsNumber(); cerr << "Attempting to get non-existent element " << el << endl;
supplied_units = element->GetAttributeValue("unit"); exit(0);
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;
} }
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; return value;
} }
@ -327,29 +328,30 @@ double Element::FindElementValueAsNumberConvertFromTo( string el,
string target_units) string target_units)
{ {
Element* element = FindElement(el); Element* element = FindElement(el);
double value;
if (!element) {
if (element) { cerr << "Attempting to get non-existent element " << el << endl;
value = element->GetDataAsNumber(); exit(0);
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 (!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; return value;
} }
@ -362,6 +364,19 @@ FGColumnVector3 Element::FindElementTripletConvertTo( string target_units)
double value=0.0; double value=0.0;
string supplied_units = GetAttributeValue("unit"); 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"); item = FindElement("x");
if (!item) item = FindElement("roll"); if (!item) item = FindElement("roll");
if (item) { if (item) {

View file

@ -2,6 +2,6 @@ noinst_LIBRARIES = libInputOutput.a
libInputOutput_a_SOURCES = FGGroundCallback.cpp FGPropertyManager.cpp FGScript.cpp FGXMLElement.cpp FGXMLParse.cpp FGfdmSocket.cpp 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 INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim

View file

@ -121,13 +121,6 @@ FGColumnVector3& FGColumnVector3::Normalize(void)
return *this; 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: // The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print // unset: In this case (the default) JSBSim would only print

View file

@ -282,9 +282,6 @@ public:
is equal to zero it is left untouched. */ is equal to zero it is left untouched. */
FGColumnVector3& Normalize(void); FGColumnVector3& Normalize(void);
// ??? Is this something sensible ??
FGColumnVector3 multElementWise(const FGColumnVector3& V) const;
// little trick here. // little trick here.
struct AssignRef { struct AssignRef {
AssignRef(FGColumnVector3& r, int i) : Ref(r), idx(i) {} AssignRef(FGColumnVector3& r, int i) : Ref(r), idx(i) {}

View file

@ -47,7 +47,6 @@ CLASS IMPLEMENTATION
FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, string prefix) FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, string prefix)
: PropertyManager(propMan), Prefix(prefix) : PropertyManager(propMan), Prefix(prefix)
{ {
int i;
Element* element; Element* element;
string operation, property_name; string operation, property_name;
int size = el->GetNumElements(); int size = el->GetNumElements();
@ -92,6 +91,16 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, string prefix)
} }
element = el->GetElement(); 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) { while (element) {
operation = element->GetName(); operation = element->GetName();
@ -146,7 +155,7 @@ FGFunction::~FGFunction(void)
PropertyManager->Untie(tmp); PropertyManager->Untie(tmp);
} }
for (int i=0; i<Parameters.size(); i++) { for (unsigned int i=0; i<Parameters.size(); i++) {
delete Parameters[i]; delete Parameters[i];
} }
} }
@ -167,7 +176,7 @@ void FGFunction::cacheValue(bool cache)
double FGFunction::GetValue(void) const double FGFunction::GetValue(void) const
{ {
int i; unsigned int i;
if (cached) return cachedValue; if (cached) return cachedValue;
@ -177,13 +186,19 @@ double FGFunction::GetValue(void) const
case eTopLevel: case eTopLevel:
break; break;
case eProduct: 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; break;
case eDifference: 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; break;
case eSum: 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; break;
case eQuotient: case eQuotient:
temp /= Parameters[1]->GetValue(); temp /= Parameters[1]->GetValue();

View file

@ -87,8 +87,8 @@ FGTable::FGTable(const FGTable& t) : PropertyManager(t.PropertyManager)
Tables = t.Tables; Tables = t.Tables;
Data = Allocate(); Data = Allocate();
for (int r=0; r<=nRows; r++) { for (unsigned int r=0; r<=nRows; r++) {
for (int c=0; c<=nCols; c++) { for (unsigned int c=0; c<=nCols; c++) {
Data[r][c] = t.Data[r][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) FGTable::FGTable(FGPropertyManager* propMan, Element* el) : PropertyManager(propMan)
{ {
int i; unsigned int i;
stringstream buf; stringstream buf;
string property_string; string property_string;
@ -287,9 +287,9 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el) : PropertyManager(prop
double** FGTable::Allocate(void) double** FGTable::Allocate(void)
{ {
Data = new double*[nRows+1]; 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]; 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; Data[r][c] = 0.0;
} }
} }
@ -306,10 +306,10 @@ FGTable::~FGTable()
} }
if (nTables > 0) { 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(); 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; delete[] Data;
Debug(1); 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) // determine number of data columns in table (first column is row lookup - don't count)
int position=0; size_t position=0;
int nCols=0; unsigned int nCols=0;
while ((position = test_line.find_first_not_of(" \t", position)) != string::npos) { while ((position = test_line.find_first_not_of(" \t", position)) != string::npos) {
nCols++; nCols++;
position = test_line.find_first_of(" \t", position); position = test_line.find_first_of(" \t", position);
@ -359,7 +359,7 @@ double FGTable::GetValue(void) const
double FGTable::GetValue(double key) const double FGTable::GetValue(double key) const
{ {
double Factor, Value, Span; double Factor, Value, Span;
int r=lastRowIndex; unsigned int r = lastRowIndex;
//if the key is off the end of the table, just return the //if the key is off the end of the table, just return the
//end-of-table value, do not extrapolate //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 // 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 // has only changed very little
if ( r > 2 && Data[r-1][0] > key ) { while (r > 2 && Data[r-1][0] > key) { r--; }
while( Data[r-1][0] > key && r > 2) { r--; } while (r < nRows && Data[r][0] < key) { r++; }
} else if ( Data[r][0] < key ) {
while( Data[r][0] <= key && r <= nRows) { r++; }
}
lastRowIndex=r; lastRowIndex=r;
// make sure denominator below does not go to zero. // 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 FGTable::GetValue(double rowKey, double colKey) const
{ {
double rFactor, cFactor, col1temp, col2temp, Value; double rFactor, cFactor, col1temp, col2temp, Value;
int r=lastRowIndex; unsigned int r = lastRowIndex;
int c=lastColumnIndex; unsigned int c = lastColumnIndex;
if ( r > 2 && Data[r-1][0] > rowKey ) { while(r > 2 && Data[r-1][0] > rowKey) { r--; }
while ( Data[r-1][0] > rowKey && r > 2) { r--; } while(r < nRows && Data[r] [0] < rowKey) { r++; }
} else if ( Data[r][0] < rowKey ) {
while ( r <= nRows && Data[r][0] <= rowKey ) { r++; }
if ( r > nRows ) r = nRows;
}
if ( c > 2 && Data[0][c-1] > colKey ) { while(c > 2 && Data[0][c-1] > colKey) { c--; }
while( Data[0][c-1] > colKey && c > 2) { c--; } while(c < nCols && Data[0][c] < colKey) { c++; }
} else if ( Data[0][c] < colKey ) {
while( Data[0][c] <= colKey && c <= nCols) { c++; }
if ( c > nCols ) c = nCols;
}
lastRowIndex=r; lastRowIndex=r;
lastColumnIndex=c; 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 FGTable::GetValue(double rowKey, double colKey, double tableKey) const
{ {
double Factor, Value, Span; 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, //if the key is off the end (or before the beginning) of the table,
// just return the boundary-table value, do not extrapolate // 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 // 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 // has only changed very little
if ( r > 2 && Data[r-1][1] > tableKey ) { while(r > 2 && Data[r-1][1] > tableKey) { r--; }
while( Data[r-1][1] > tableKey && r > 2) { r--; } while(r < nRows && Data[r] [1] < tableKey) { r++; }
} else if ( Data[r][1] < tableKey ) {
while( Data[r][1] <= tableKey && r <= nRows) { r++; }
}
lastRowIndex=r; lastRowIndex=r;
// make sure denominator below does not go to zero. // make sure denominator below does not go to zero.
@ -493,11 +481,11 @@ void FGTable::operator<<(stringstream& in_stream)
int startRow=0; int startRow=0;
int startCol=0; int startCol=0;
if (Type == tt1D || Type == tt3D) startRow = 1; // In 1D table, no pseudo-row of column-headers (i.e. keys):
if (Type == tt3D) startCol = 1; if (Type == tt1D) startRow = 1;
for (int r=startRow; r<=nRows; r++) { for (unsigned int r=startRow; r<=nRows; r++) {
for (int c=startCol; c<=nCols; c++) { for (unsigned int c=startCol; c<=nCols; c++) {
if (r != 0 || c != 0) { if (r != 0 || c != 0) {
in_stream >> Data[r][c]; in_stream >> Data[r][c];
} }
@ -557,9 +545,9 @@ void FGTable::Print(void)
break; break;
} }
cout.precision(4); cout.precision(4);
for (int r=startRow; r<=nRows; r++) { for (unsigned int r=startRow; r<=nRows; r++) {
cout << " "; cout << " ";
for (int c=startCol; c<=nCols; c++) { for (unsigned int c=startCol; c<=nCols; c++) {
if (r == 0 && c == 0) { if (r == 0 && c == 0) {
cout << " "; cout << " ";
} else { } else {

View file

@ -299,8 +299,8 @@ private:
FGPropertyManager *lookupProperty[3]; FGPropertyManager *lookupProperty[3];
double** Data; double** Data;
vector <FGTable*> Tables; vector <FGTable*> Tables;
int FindNumColumns(string); unsigned int FindNumColumns(string);
int nRows, nCols, nTables, dimension; unsigned int nRows, nCols, nTables, dimension;
int colCounter, rowCounter, tableCounter; int colCounter, rowCounter, tableCounter;
mutable int lastRowIndex, lastColumnIndex, lastTableIndex; mutable int lastRowIndex, lastColumnIndex, lastTableIndex;
double** Allocate(void); double** Allocate(void);

View file

@ -5,7 +5,7 @@ libMath_a_SOURCES = FGColumnVector3.cpp FGFunction.cpp FGLocation.cpp FGMatrix33
FGCondition.cpp FGCondition.cpp
noinst_HEADERS = FGColumnVector3.h FGFunction.h FGLocation.h FGMatrix33.h \ 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 FGCondition.h
INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim

View file

@ -353,8 +353,6 @@ void FGAerodynamics::bind(void)
void FGAerodynamics::unbind(void) void FGAerodynamics::unbind(void)
{ {
unsigned i,j;
PropertyManager->Untie("forces/fbx-aero-lbs"); PropertyManager->Untie("forces/fbx-aero-lbs");
PropertyManager->Untie("forces/fby-aero-lbs"); PropertyManager->Untie("forces/fby-aero-lbs");
PropertyManager->Untie("forces/fbz-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/alpha-wing-rad");
PropertyManager->Untie("aero/stall-hyst-norm"); PropertyManager->Untie("aero/stall-hyst-norm");
PropertyManager->Untie("systems/stall-warn-norm"); PropertyManager->Untie("systems/stall-warn-norm");
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View file

@ -94,6 +94,7 @@ FGAircraft::FGAircraft(FGFDMExec* fdmex) : FGModel(fdmex)
lbarh = lbarv = 0.0; lbarh = lbarv = 0.0;
vbarh = vbarv = 0.0; vbarh = vbarv = 0.0;
WingIncidence = 0.0; WingIncidence = 0.0;
HoldDown = 0;
bind(); bind();
@ -116,14 +117,18 @@ bool FGAircraft::Run(void)
if (FDMExec->Holding()) return false; if (FDMExec->Holding()) return false;
vForces.InitMatrix(); vForces.InitMatrix();
vForces += Aerodynamics->GetForces(); if (!HoldDown) {
vForces += Propulsion->GetForces(); vForces += Aerodynamics->GetForces();
vForces += GroundReactions->GetForces(); vForces += Propulsion->GetForces();
vForces += GroundReactions->GetForces();
}
vMoments.InitMatrix(); vMoments.InitMatrix();
vMoments += Aerodynamics->GetMoments(); if (!HoldDown) {
vMoments += Propulsion->GetMoments(); vMoments += Aerodynamics->GetMoments();
vMoments += GroundReactions->GetMoments(); vMoments += Propulsion->GetMoments();
vMoments += GroundReactions->GetMoments();
}
vBodyAccel = vForces/MassBalance->GetMass(); vBodyAccel = vForces/MassBalance->GetMass();
@ -212,6 +217,7 @@ void FGAircraft::bind(void)
PropertyManager->Tie("metrics/lv-norm", this, &FGAircraft::Getlbarv); PropertyManager->Tie("metrics/lv-norm", this, &FGAircraft::Getlbarv);
PropertyManager->Tie("metrics/vbarh-norm", this, &FGAircraft::Getvbarh); PropertyManager->Tie("metrics/vbarh-norm", this, &FGAircraft::Getvbarh);
PropertyManager->Tie("metrics/vbarv-norm", this, &FGAircraft::Getvbarv); 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/l-total-lbsft", this, eL, (PMF)&FGAircraft::GetMoments);
PropertyManager->Tie("moments/m-total-lbsft", this, eM, (PMF)&FGAircraft::GetMoments); PropertyManager->Tie("moments/m-total-lbsft", this, eM, (PMF)&FGAircraft::GetMoments);
PropertyManager->Tie("moments/n-total-lbsft", this, eN, (PMF)&FGAircraft::GetMoments); PropertyManager->Tie("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/fbx-total-lbs");
PropertyManager->Untie("forces/fby-total-lbs"); PropertyManager->Untie("forces/fby-total-lbs");
PropertyManager->Untie("forces/fbz-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-x-in");
PropertyManager->Untie("metrics/aero-rp-y-in"); PropertyManager->Untie("metrics/aero-rp-y-in");
PropertyManager->Untie("metrics/aero-rp-z-in"); PropertyManager->Untie("metrics/aero-rp-z-in");

View file

@ -151,6 +151,8 @@ public:
inline double GetXYZvrp(int idx) const { return vXYZvrp(idx); } inline double GetXYZvrp(int idx) const { return vXYZvrp(idx); }
inline double GetXYZep(int idx) const { return vXYZep(idx); } inline double GetXYZep(int idx) const { return vXYZep(idx); }
inline void SetAircraftName(string name) {AircraftName = name;} 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;} void SetXYZrp(int idx, double value) {vXYZrp(idx) = value;}
@ -175,6 +177,7 @@ private:
double WingArea, WingSpan, cbar, WingIncidence; double WingArea, WingSpan, cbar, WingIncidence;
double HTailArea, VTailArea, HTailArm, VTailArm; double HTailArea, VTailArea, HTailArm, VTailArm;
double lbarh,lbarv,vbarh,vbarv; double lbarh,lbarv,vbarh,vbarv;
int HoldDown;
string AircraftName; string AircraftName;
void Debug(int from); void Debug(int from);

View file

@ -101,16 +101,16 @@ FGAuxiliary::~FGAuxiliary()
bool FGAuxiliary::Run() 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& vPQR = Propagate->GetPQR();
const FGColumnVector3& vUVW = Propagate->GetUVW(); const FGColumnVector3& vUVW = Propagate->GetUVW();
const FGColumnVector3& vUVWdot = Propagate->GetUVWdot(); const FGColumnVector3& vUVWdot = Propagate->GetUVWdot();
const FGColumnVector3& vVel = Propagate->GetVel(); 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(); p = Atmosphere->GetPressure();
rhosl = Atmosphere->GetDensitySL(); rhosl = Atmosphere->GetDensitySL();
psl = Atmosphere->GetPressureSL(); psl = Atmosphere->GetPressureSL();
@ -182,18 +182,9 @@ bool FGAuxiliary::Run()
Vground = sqrt( vVel(eNorth)*vVel(eNorth) + vVel(eEast)*vVel(eEast) ); Vground = sqrt( vVel(eNorth)*vVel(eNorth) + vVel(eEast)*vVel(eEast) );
if (vVel(eNorth) == 0) psigt = 0; psigt = atan2(vVel(eEast), vVel(eNorth));
else psigt = atan2(vVel(eEast), vVel(eNorth));
if (psigt < 0.0) psigt += 2*M_PI; if (psigt < 0.0) psigt += 2*M_PI;
gamma = atan2(-vVel(eDown), Vground);
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);
}
tat = sat*(1 + 0.2*Mach*Mach); // Total Temperature, isentropic flow tat = sat*(1 + 0.2*Mach*Mach); // Total Temperature, isentropic flow
tatc = RankineToCelsius(tat); tatc = RankineToCelsius(tat);

View file

@ -52,6 +52,7 @@ INCLUDES
#include <models/flight_control/FGKinemat.h> #include <models/flight_control/FGKinemat.h>
#include <models/flight_control/FGFCSFunction.h> #include <models/flight_control/FGFCSFunction.h>
#include <models/flight_control/FGSensor.h> #include <models/flight_control/FGSensor.h>
#include <models/flight_control/FGActuator.h>
namespace JSBSim { namespace JSBSim {
@ -147,7 +148,9 @@ bool FGFCS::Run(void)
// Cycle through the sensor, autopilot, and flight control components // Cycle through the sensor, autopilot, and flight control components
for (i=0; i<sensors.size(); i++) sensors[i]->Run(); 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(); for (i=0; i<FCSComponents.size(); i++) FCSComponents[i]->Run();
return false; return false;
@ -456,10 +459,8 @@ bool FGFCS::Load(Element* el)
{ {
string name, file, fname, interface_property_string; string name, file, fname, interface_property_string;
vector <FGFCSComponent*> *Components; vector <FGFCSComponent*> *Components;
Element *document, *component_element, *property_element, *sensor_element; Element *component_element, *property_element, *sensor_element;
Element *channel_element; Element *channel_element;
ifstream* controls_file = new ifstream();
FGXMLParse controls_file_parser;
Components=0; Components=0;
// Determine if the FCS/Autopilot is defined inline in the aircraft configuration // 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; cerr << "FCS/Autopilot does not appear to be defined inline nor in a file" << endl;
return false; return false;
} else { } else {
controls_file->open(file.c_str()); document = LoadXMLDocument(file);
readXML(*controls_file, controls_file_parser);
delete controls_file;
document = controls_file_parser.GetDocument();
} }
} else { } else {
document = el; document = el;
@ -554,6 +552,8 @@ bool FGFCS::Load(Element* el)
Components->push_back(new FGFCSFunction(this, component_element)); Components->push_back(new FGFCSFunction(this, component_element));
} else if (component_element->GetName() == string("pid")) { } else if (component_element->GetName() == string("pid")) {
Components->push_back(new FGPID(this, component_element)); Components->push_back(new FGPID(this, component_element));
} else if (component_element->GetName() == string("actuator")) {
Components->push_back(new FGActuator(this, component_element));
} else { } else {
cerr << "Unknown FCS component: " << component_element->GetName() << endl; cerr << "Unknown FCS component: " << component_element->GetName() << endl;
} }
@ -604,7 +604,9 @@ string FGFCS::GetComponentStrings(string delimeter)
for (comp = 0; comp < APComponents.size(); comp++) for (comp = 0; comp < APComponents.size(); comp++)
{ {
CompStrings += delimeter; if (firstime) firstime = false;
else CompStrings += delimeter;
CompStrings += APComponents[comp]->GetName(); CompStrings += APComponents[comp]->GetName();
} }
@ -629,7 +631,10 @@ string FGFCS::GetComponentValues(string delimeter)
} }
for (comp = 0; comp < APComponents.size(); comp++) { 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); CompValues += string(buffer);
} }
@ -663,6 +668,13 @@ void FGFCS::AddGear(void)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGFCS::GetDt(void)
{
return FDMExec->GetDeltaT()*rate;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGFCS::bind(void) void FGFCS::bind(void)
{ {
PropertyManager->Tie("fcs/aileron-cmd-norm", this, &FGFCS::GetDaCmd, &FGFCS::SetDaCmd); PropertyManager->Tie("fcs/aileron-cmd-norm", this, &FGFCS::GetDaCmd, &FGFCS::SetDaCmd);

View file

@ -53,7 +53,7 @@ INCLUDES
#include <models/flight_control/FGFCSComponent.h> #include <models/flight_control/FGFCSComponent.h>
#include <models/FGModel.h> #include <models/FGModel.h>
#include <models/FGLGear.h> #include <models/FGLGear.h>
#include <input_output/FGXMLElement.h> #include <input_output/FGXMLFileRead.h>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS DEFINITIONS
@ -191,7 +191,8 @@ CLASS DOCUMENTATION
CLASS DECLARATION CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGFCS : public FGModel { class FGFCS : public FGModel, public FGXMLFileRead
{
public: public:
/** Constructor /** Constructor
@ -523,6 +524,7 @@ public:
void AddThrottle(void); void AddThrottle(void);
void AddGear(void); void AddGear(void);
double GetDt(void);
FGPropertyManager* GetPropertyManager(void) { return PropertyManager; } FGPropertyManager* GetPropertyManager(void) { return PropertyManager; }

View file

@ -64,7 +64,7 @@ FGGroundReactions::FGGroundReactions(FGFDMExec* fgex) : FGModel(fgex)
FGGroundReactions::~FGGroundReactions(void) 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(); lGear.clear();
unbind(); unbind();
@ -106,7 +106,7 @@ bool FGGroundReactions::Run(void)
bool FGGroundReactions::GetWOW(void) bool FGGroundReactions::GetWOW(void)
{ {
bool result = false; 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()) { if (lGear[i].IsBogey() && lGear[i].GetWOW()) {
result = true; result = true;
break; break;
@ -130,7 +130,7 @@ bool FGGroundReactions::Load(Element* el)
contact_element = el->FindNextElement("contact"); 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; return true;
} }
@ -149,11 +149,13 @@ string FGGroundReactions::GetGroundReactionStrings(string delimeter)
<< name << " stroke velocity (ft/sec)" << delimeter << name << " stroke velocity (ft/sec)" << delimeter
<< name << " compress force (lbs)" << delimeter << name << " compress force (lbs)" << delimeter
<< name << " wheel side 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 << " wheel roll force (lbs)" << delimeter
<< name << " body X force (lbs)" << delimeter << name << " body X force (lbs)" << delimeter
<< name << " body Y 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; << name << " wheel slip (deg)" << delimeter;
} }
} }
@ -181,12 +183,14 @@ string FGGroundReactions::GetGroundReactionValues(string delimeter)
<< setprecision(5) << gear.GetCompLen() << delimeter << setprecision(5) << gear.GetCompLen() << delimeter
<< setprecision(6) << gear.GetCompVel() << delimeter << setprecision(6) << gear.GetCompVel() << delimeter
<< setprecision(10) << gear.GetCompForce() << delimeter << setprecision(10) << gear.GetCompForce() << delimeter
<< setprecision(6) << gear.GetWheelVel(eX) << delimeter
<< gear.GetWheelVel(eY) << delimeter
<< gear.GetWheelSideForce() << delimeter << gear.GetWheelSideForce() << delimeter
<< gear.GetWheelRollForce() << delimeter << gear.GetWheelRollForce() << delimeter
<< gear.GetBodyXForce() << delimeter << gear.GetBodyXForce() << delimeter
<< gear.GetBodyYForce() << delimeter << gear.GetBodyYForce() << delimeter
<< setprecision(6) << gear.GetWheelVel(eX) << delimeter
<< gear.GetWheelVel(eY) << delimeter
<< gear.GetWheelRollVel() << delimeter
<< gear.GetWheelSideVel() << delimeter
<< gear.GetWheelSlipAngle() << delimeter; << gear.GetWheelSlipAngle() << delimeter;
} }
} }

View file

@ -206,7 +206,7 @@ bool FGInput::Load(Element* element)
string name="", fname=""; string name="", fname="";
string property; string property;
port = element->GetAttributeValueAsNumber("port"); port = int(element->GetAttributeValueAsNumber("port"));
if (port == 0) { if (port == 0) {
cerr << endl << "No port assigned in input element" << endl; cerr << endl << "No port assigned in input element" << endl;
} else { } else {

View file

@ -88,7 +88,7 @@ FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number) : Exec(fdmex),
if (el->FindElement("max_steer")) if (el->FindElement("max_steer"))
maxSteerAngle = el->FindElementValueAsNumberConvertTo("max_steer", "DEG"); maxSteerAngle = el->FindElementValueAsNumberConvertTo("max_steer", "DEG");
if (el->FindElement("retractable")) if (el->FindElement("retractable"))
isRetractable = (int)el->FindElementValueAsNumber("retractable"); isRetractable = ((unsigned int)el->FindElementValueAsNumber("retractable"))>0.0?true:false;
ForceY_Table = 0; ForceY_Table = 0;
force_table = el->FindElement("table"); force_table = el->FindElement("table");
@ -332,8 +332,9 @@ FGColumnVector3& FGLGear::Force(void)
// Compute the forces in the wheel ground plane. // Compute the forces in the wheel ground plane.
RollingForce = (1.0 - TirePressureNorm) * 30 RollingForce = ((1.0 - TirePressureNorm) * 30
+ vLocalForce(eZ) * BrakeFCoeff * (RollingWhlVel>=0?1.0:-1.0); + vLocalForce(eZ) * BrakeFCoeff) * (RollingWhlVel>=0?1.0:-1.0);
SideForce = vLocalForce(eZ) * FCoeff; SideForce = vLocalForce(eZ) * FCoeff;
// Transform these forces back to the local reference frame. // 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(RollingWhlVel) <= RFRV) && RFRV > 0) vForce(eX) *= fabs(RollingWhlVel)/RFRV;
if ((fabs(SideWhlVel) <= SFRV) && SFRV > 0) vForce(eY) *= fabs(SideWhlVel)/SFRV; 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; vMoment = vWhlBodyVec * vForce;
@ -426,13 +427,9 @@ void FGLGear::ComputeSlipAngle(void)
SideWhlVel = vWhlVelVec(eY)*CosWheel - vWhlVelVec(eX)*SinWheel; SideWhlVel = vWhlVelVec(eY)*CosWheel - vWhlVelVec(eX)*SinWheel;
// Calculate tire slip angle. // Calculate tire slip angle.
if (fabs(RollingWhlVel) < 0.02 && fabs(SideWhlVel) < 0.02) {
WheelSlip = -SteerAngle*radtodeg;
} else {
WheelSlip = atan2(SideWhlVel, fabs(RollingWhlVel))*radtodeg; WheelSlip = atan2(SideWhlVel, fabs(RollingWhlVel))*radtodeg;
}
// Filter the wheel slip angle // Filter the wheel slip angle
double SlipOutput, ca, cb, denom; double SlipOutput, ca, cb, denom;

View file

@ -244,6 +244,8 @@ public:
inline bool GetGearUnitDown(void) { return GearDown; } inline bool GetGearUnitDown(void) { return GearDown; }
inline double GetWheelSideForce(void) { return SideForce; } inline double GetWheelSideForce(void) { return SideForce; }
inline double GetWheelRollForce(void) { return RollingForce; } 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 GetBodyXForce(void) { return vLocalForce(eX); }
inline double GetBodyYForce(void) { return vLocalForce(eY); } inline double GetBodyYForce(void) { return vLocalForce(eY); }
inline double GetWheelSlipAngle(void) { return WheelSlip; } inline double GetWheelSlipAngle(void) { return WheelSlip; }

View file

@ -104,11 +104,11 @@ bool FGMassBalance::Load(Element* el)
EmptyWeight = el->FindElementValueAsNumberConvertTo("emptywt", "LBS"); EmptyWeight = el->FindElementValueAsNumberConvertTo("emptywt", "LBS");
element = el->FindElement("location"); element = el->FindElement("location");
while (element) { while (element) {
element_name = element->GetAttributeValue("name"); element_name = element->GetAttributeValue("name");
if (element_name == "CG") vbaseXYZcg = element->FindElementTripletConvertTo("IN"); if (element_name == "CG") vbaseXYZcg = element->FindElementTripletConvertTo("IN");
element = el->FindNextElement("location"); element = el->FindNextElement("location");
} }
// Find all POINTMASS elements that descend from this METRICS branch of the // Find all POINTMASS elements that descend from this METRICS branch of the
// config file. // config file.
@ -281,11 +281,11 @@ void FGMassBalance::bind(void)
&FGMassBalance::GetMass); &FGMassBalance::GetMass);
PropertyManager->Tie("inertia/weight-lbs", this, PropertyManager->Tie("inertia/weight-lbs", this,
&FGMassBalance::GetWeight); &FGMassBalance::GetWeight);
PropertyManager->Tie("inertia/cg-x-ft", this,1, PropertyManager->Tie("inertia/cg-x-in", this,1,
(PMF)&FGMassBalance::GetXYZcg); (PMF)&FGMassBalance::GetXYZcg);
PropertyManager->Tie("inertia/cg-y-ft", this,2, PropertyManager->Tie("inertia/cg-y-in", this,2,
(PMF)&FGMassBalance::GetXYZcg); (PMF)&FGMassBalance::GetXYZcg);
PropertyManager->Tie("inertia/cg-z-ft", this,3, PropertyManager->Tie("inertia/cg-z-in", this,3,
(PMF)&FGMassBalance::GetXYZcg); (PMF)&FGMassBalance::GetXYZcg);
} }
@ -295,9 +295,9 @@ void FGMassBalance::unbind(void)
{ {
PropertyManager->Untie("inertia/mass-slugs"); PropertyManager->Untie("inertia/mass-slugs");
PropertyManager->Untie("inertia/weight-lbs"); PropertyManager->Untie("inertia/weight-lbs");
PropertyManager->Untie("inertia/cg-x-ft"); PropertyManager->Untie("inertia/cg-x-in");
PropertyManager->Untie("inertia/cg-y-ft"); PropertyManager->Untie("inertia/cg-y-in");
PropertyManager->Untie("inertia/cg-z-ft"); PropertyManager->Untie("inertia/cg-z-in");
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -335,7 +335,7 @@ void FGMassBalance::Debug(int from)
cout << " EmptyWeight: " << EmptyWeight << " lbm" << endl; cout << " EmptyWeight: " << EmptyWeight << " lbm" << endl;
cout << " CG (x, y, z): " << vbaseXYZcg << endl; cout << " CG (x, y, z): " << vbaseXYZcg << endl;
// ToDo: Need to add point mass outputs here // 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 " cout << " Point Mass Object: " << PointMasses[i].Weight << " lbs. at "
<< "X, Y, Z (in.): " << PointMasses[i].Location(eX) << " " << "X, Y, Z (in.): " << PointMasses[i].Location(eX) << " "
<< PointMasses[i].Location(eY) << " " << PointMasses[i].Location(eY) << " "

View file

@ -145,6 +145,8 @@ void FGOutput::DelimitedOutput(string fname)
ostream outstream(buffer); ostream outstream(buffer);
outstream.precision(10);
if (dFirstPass) { if (dFirstPass) {
outstream << "Time"; outstream << "Time";
if (SubSystems & ssSimulation) { if (SubSystems & ssSimulation) {
@ -235,7 +237,7 @@ void FGOutput::DelimitedOutput(string fname)
} }
if (OutputProperties.size() > 0) { if (OutputProperties.size() > 0) {
for (unsigned int i=0;i<OutputProperties.size();i++) { 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) { if (SubSystems & ssRates) {
outstream << delimeter; outstream << delimeter;
outstream << Propagate->GetPQR().Dump(delimeter) << delimeter; outstream << (radtodeg*Propagate->GetPQR()).Dump(delimeter) << delimeter;
outstream << Propagate->GetPQRdot().Dump(delimeter); outstream << (radtodeg*Propagate->GetPQRdot()).Dump(delimeter);
} }
if (SubSystems & ssVelocities) { if (SubSystems & ssVelocities) {
outstream << delimeter; outstream << delimeter;
@ -297,7 +299,7 @@ void FGOutput::DelimitedOutput(string fname)
if (SubSystems & ssPropagate) { if (SubSystems & ssPropagate) {
outstream << delimeter; outstream << delimeter;
outstream << Propagate->Geth() << 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->Getalpha(inDegrees) << delimeter;
outstream << Auxiliary->Getbeta(inDegrees) << delimeter; outstream << Auxiliary->Getbeta(inDegrees) << delimeter;
outstream << Propagate->GetLocation().GetLatitudeDeg() << delimeter; outstream << Propagate->GetLocation().GetLatitudeDeg() << delimeter;
@ -417,13 +419,13 @@ void FGOutput::SocketOutput(void)
} }
if (SubSystems & ssPropagate) { if (SubSystems & ssPropagate) {
socket->Append("Altitude"); socket->Append("Altitude");
socket->Append("Phi"); socket->Append("Phi (deg)");
socket->Append("Tht"); socket->Append("Tht (deg)");
socket->Append("Psi"); socket->Append("Psi (deg)");
socket->Append("Alpha"); socket->Append("Alpha (deg)");
socket->Append("Beta"); socket->Append("Beta (deg)");
socket->Append("Latitude (Deg)"); socket->Append("Latitude (deg)");
socket->Append("Longitude (Deg)"); socket->Append("Longitude (deg)");
} }
if (SubSystems & ssCoefficients) { if (SubSystems & ssCoefficients) {
scratch = Aerodynamics->GetCoefficientStrings(","); scratch = Aerodynamics->GetCoefficientStrings(",");
@ -441,7 +443,7 @@ void FGOutput::SocketOutput(void)
} }
if (OutputProperties.size() > 0) { if (OutputProperties.size() > 0) {
for (unsigned int i=0;i<OutputProperties.size();i++) { 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()); socket->Append(FCS->GetDfPos());
} }
if (SubSystems & ssRates) { if (SubSystems & ssRates) {
socket->Append(Propagate->GetPQR(eP)); socket->Append(radtodeg*Propagate->GetPQR(eP));
socket->Append(Propagate->GetPQR(eQ)); socket->Append(radtodeg*Propagate->GetPQR(eQ));
socket->Append(Propagate->GetPQR(eR)); socket->Append(radtodeg*Propagate->GetPQR(eR));
socket->Append(Propagate->GetPQRdot(eP)); socket->Append(radtodeg*Propagate->GetPQRdot(eP));
socket->Append(Propagate->GetPQRdot(eQ)); socket->Append(radtodeg*Propagate->GetPQRdot(eQ));
socket->Append(Propagate->GetPQRdot(eR)); socket->Append(radtodeg*Propagate->GetPQRdot(eR));
} }
if (SubSystems & ssVelocities) { if (SubSystems & ssVelocities) {
socket->Append(Auxiliary->Getqbar()); socket->Append(Auxiliary->Getqbar());
@ -521,9 +523,9 @@ void FGOutput::SocketOutput(void)
} }
if (SubSystems & ssPropagate) { if (SubSystems & ssPropagate) {
socket->Append(Propagate->Geth()); socket->Append(Propagate->Geth());
socket->Append(Propagate->GetEuler(ePhi)); socket->Append(radtodeg*Propagate->GetEuler(ePhi));
socket->Append(Propagate->GetEuler(eTht)); socket->Append(radtodeg*Propagate->GetEuler(eTht));
socket->Append(Propagate->GetEuler(ePsi)); socket->Append(radtodeg*Propagate->GetEuler(ePsi));
socket->Append(Auxiliary->Getalpha(inDegrees)); socket->Append(Auxiliary->Getalpha(inDegrees));
socket->Append(Auxiliary->Getbeta(inDegrees)); socket->Append(Auxiliary->Getbeta(inDegrees));
socket->Append(Propagate->GetLocation().GetLatitudeDeg()); socket->Append(Propagate->GetLocation().GetLatitudeDeg());
@ -574,9 +576,7 @@ bool FGOutput::Load(Element* element)
int OutRate = 0; int OutRate = 0;
string property; string property;
unsigned int port; unsigned int port;
FGXMLParse output_file_parser; Element *property_element;
Element *document, *property_element;
ifstream* output_file = new ifstream();
string separator = "/"; string separator = "/";
# ifdef macintosh # ifdef macintosh
@ -596,16 +596,7 @@ bool FGOutput::Load(Element* element)
} else { } else {
output_file_name = FDMExec->GetFullAircraftPath() + separator + fname + ".xml"; output_file_name = FDMExec->GetFullAircraftPath() + separator + fname + ".xml";
} }
output_file->open(output_file_name.c_str()); document = LoadXMLDocument(output_file_name);
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();
} else { } else {
document = element; document = element;
} }

View file

@ -55,7 +55,7 @@ INCLUDES
#endif #endif
#include <input_output/FGfdmSocket.h> #include <input_output/FGfdmSocket.h>
#include <input_output/FGXMLElement.h> #include <input_output/FGXMLFileRead.h>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS DEFINITIONS
@ -123,7 +123,7 @@ CLASS DOCUMENTATION
CLASS DECLARATION CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGOutput : public FGModel class FGOutput : public FGModel, public FGXMLFileRead
{ {
public: public:
FGOutput(FGFDMExec*); FGOutput(FGFDMExec*);

View file

@ -98,6 +98,18 @@ FGPropagate::FGPropagate(FGFDMExec* fdmex) : FGModel(fdmex)
Name = "FGPropagate"; Name = "FGPropagate";
// vQtrndot.zero(); // 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(); bind();
Debug(0); Debug(0);
} }

View file

@ -199,11 +199,7 @@ bool FGPropulsion::ICEngineStart(void)
bool FGPropulsion::Load(Element* el) bool FGPropulsion::Load(Element* el)
{ {
string type, engine_filename; string type, engine_filename;
int Feed;
bool ThrottleAdded = false; bool ThrottleAdded = false;
Element* document;
FGXMLParse engine_file_parser;
ifstream* engine_file;
Debug(2); Debug(2);
@ -217,8 +213,7 @@ bool FGPropulsion::Load(Element* el)
} }
engine_filename = FindEngineFullPathname(engine_filename); engine_filename = FindEngineFullPathname(engine_filename);
readXML(engine_filename, engine_file_parser); document = LoadXMLDocument(engine_filename);
document = engine_file_parser.GetDocument(); // document holds the engine description
document->SetParent(engine_element); document->SetParent(engine_element);
type = document->GetName(); type = document->GetName();
@ -253,7 +248,7 @@ bool FGPropulsion::Load(Element* el)
numEngines++; numEngines++;
engine_element = el->FindNextElement("engine"); engine_element = el->FindNextElement("engine");
engine_file_parser.reset(); ResetParser();
} }
// Process tank definitions // Process tank definitions
@ -488,7 +483,7 @@ void FGPropulsion::SetCutoff(int setting)
void FGPropulsion::SetActiveEngine(int engine) void FGPropulsion::SetActiveEngine(int engine)
{ {
if (engine >= Engines.size() || engine < 0) if (engine >= (int)Engines.size() || engine < 0)
ActiveEngine = -1; ActiveEngine = -1;
else else
ActiveEngine = engine; ActiveEngine = engine;

View file

@ -59,7 +59,7 @@ INCLUDES
#include <models/propulsion/FGEngine.h> #include <models/propulsion/FGEngine.h>
#include <models/propulsion/FGTank.h> #include <models/propulsion/FGTank.h>
#include <math/FGMatrix33.h> #include <math/FGMatrix33.h>
#include <input_output/FGXMLElement.h> #include <input_output/FGXMLFileRead.h>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS DEFINITIONS
@ -97,7 +97,7 @@ CLASS DOCUMENTATION
CLASS DECLARATION CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGPropulsion : public FGModel class FGPropulsion : public FGModel, public FGXMLFileRead
{ {
public: public:
/// Constructor /// Constructor

View 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;
}
}
}
}

View 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

View file

@ -89,6 +89,8 @@ FGFCSComponent::FGFCSComponent(FGFCS* _fcs, Element* element) : fcs(_fcs)
Type = "PID"; Type = "PID";
} else if (element->GetName() == string("sensor")) { } else if (element->GetName() == string("sensor")) {
Type = "SENSOR"; Type = "SENSOR";
} else if (element->GetName() == string("actuator")) {
Type = "ACTUATOR";
} else { // illegal component in this channel } else { // illegal component in this channel
Type = "UNKNOWN"; Type = "UNKNOWN";
} }

View file

@ -54,7 +54,12 @@ FGFCSFunction::FGFCSFunction(FGFCS* fcs, Element* element) : FGFCSComponent(fcs,
{ {
Element *function_element = element->FindElement("function"); 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(); FGFCSComponent::bind();
Debug(0); Debug(0);

View file

@ -81,14 +81,19 @@ bool FGPID::Run(void )
Input = InputNodes[0]->getDoubleValue() * InputSigns[0]; Input = InputNodes[0]->getDoubleValue() * InputSigns[0];
P_out = Kp * (Input - Input_prev); P_out = Kp * (Input - Input_prev);
I_out = Ki * dt * Input;
D_out = (Kd / dt) * (Input - 2*Input_prev + Input_prev2); 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) { if (Trigger != 0) {
double test = Trigger->getDoubleValue(); double test = Trigger->getDoubleValue();
if (fabs(test) > 0.000001) { if (fabs(test) < 0.000001) {
I_out = 0.0; I_out = Ki * dt * Input;
} }
} else { // no anti-wind-up trigger defined
I_out = Ki * dt * Input;
} }
Input_prev = Input; Input_prev = Input;

View file

@ -52,12 +52,10 @@ CLASS IMPLEMENTATION
FGSensor::FGSensor(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element) FGSensor::FGSensor(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
{ {
double denom; double denom;
dt = fcs->GetState()->Getdt(); dt = fcs->GetDt();
// inputs are read from the base class constructor // inputs are read from the base class constructor
dt = fcs->GetState()->Getdt();
bits = quantized = divisions = 0; bits = quantized = divisions = 0;
PreviousInput = PreviousOutput = 0.0; PreviousInput = PreviousOutput = 0.0;
min = max = bias = noise_variance = lag = drift_rate = drift = span = 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") ) { if ( quantization_element->FindElement("max") ) {
max = quantization_element->FindElementValueAsNumber("max"); max = quantization_element->FindElementValueAsNumber("max");
} }
quant_property = quantization_element->GetAttributeValue("name");
span = max - min; span = max - min;
granularity = span/divisions; granularity = span/divisions;
} }
@ -214,6 +213,14 @@ void FGSensor::bind(void)
PropertyManager->Tie( tmp_low, this, &FGSensor::GetFailLow, &FGSensor::SetFailLow); PropertyManager->Tie( tmp_low, this, &FGSensor::GetFailLow, &FGSensor::SetFailLow);
PropertyManager->Tie( tmp_high, this, &FGSensor::GetFailHigh, &FGSensor::SetFailHigh); PropertyManager->Tie( tmp_high, this, &FGSensor::GetFailHigh, &FGSensor::SetFailHigh);
PropertyManager->Tie( tmp_stuck, this, &FGSensor::GetFailStuck, &FGSensor::SetFailStuck); 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 (debug_lvl & 1) { // Standard console startup message output
if (from == 0) { // Constructor 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 if (debug_lvl & 2 ) { // Instantiation/Destruction notification

View file

@ -63,7 +63,7 @@ CLASS DOCUMENTATION
Syntax: Syntax:
@code @code
<sensor name=name rate_group=name> <sensor name=name>
<input> property </input> <input> property </input>
<lag> number </lag> <lag> number </lag>
<noise variation=PERCENT|ABSOLUTE> number </noise> <noise variation=PERCENT|ABSOLUTE> number </noise>
@ -80,7 +80,7 @@ Syntax:
Example: Example:
@code @code
<sensor name=aero/sensor/qbar rate_group=HFCS> <sensor name=aero/sensor/qbar>
<input> aero/qbar </input> <input> aero/qbar </input>
<lag> 0.5 </lag> <lag> 0.5 </lag>
<noise variation=PERCENT> 2 </noise> <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 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 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 double GetFailStuck(void) const {if (fail_stuck) return 1.0; else return 0.0;}
inline int GetQuantized(void) const {return quantized;}
bool Run (void); bool Run (void);
@ -149,6 +150,7 @@ private:
bool fail_low; bool fail_low;
bool fail_high; bool fail_high;
bool fail_stuck; bool fail_stuck;
string quant_property;
void Noise(void); void Noise(void);
void Bias(void); void Bias(void);

View file

@ -94,7 +94,7 @@ FGSwitch::FGSwitch(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
else { // error else { // error
cerr << "Unrecognized LOGIC token " << logic << " in switch component: " << Name << endl; 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)); current_test->conditions.push_back(FGCondition(test_element->GetDataLine(i), PropertyManager));
condition_element = test_element->GetElement(); // retrieve condition groups condition_element = test_element->GetElement(); // retrieve condition groups

View file

@ -2,10 +2,11 @@ noinst_LIBRARIES = libFlightControl.a
libFlightControl_a_SOURCES = FGPID.cpp FGDeadBand.cpp FGFCSComponent.cpp \ libFlightControl_a_SOURCES = FGPID.cpp FGDeadBand.cpp FGFCSComponent.cpp \
FGFilter.cpp FGGain.cpp FGGradient.cpp FGKinemat.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 \ noinst_HEADERS = FGPID.h FGDeadBand.h FGFCSComponent.h FGFilter.h \
FGGain.h FGGradient.h FGKinemat.h FGSummer.h FGSwitch.h FGFCSFunction.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 INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim

View file

@ -113,7 +113,7 @@ FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number)
else cerr << "No engine location found for this engine." << endl; else cerr << "No engine location found for this engine." << endl;
local_element = engine_element->GetParent()->FindElement("orient"); 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; else cerr << "No engine orientation found for this engine." << endl;
SetPlacement(location, orientation); SetPlacement(location, orientation);
@ -247,12 +247,9 @@ bool FGEngine::LoadThruster(Element *thruster_element)
{ {
string token, fullpath, localpath; string token, fullpath, localpath;
string thruster_filename, thruster_fullpathname, thrType; string thruster_filename, thruster_fullpathname, thrType;
double xLoc, yLoc, zLoc, Pitch, Yaw;
double P_Factor = 0, Sense = 0.0; double P_Factor = 0, Sense = 0.0;
string enginePath = FDMExec->GetEnginePath(); string enginePath = FDMExec->GetEnginePath();
string aircraftPath = FDMExec->GetFullAircraftPath(); string aircraftPath = FDMExec->GetFullAircraftPath();
FGXMLParse thruster_file_parser;
Element *document, *element;
ifstream thruster_file; ifstream thruster_file;
FGColumnVector3 location, orientation; FGColumnVector3 location, orientation;
string separator = "/"; string separator = "/";
@ -285,8 +282,7 @@ bool FGEngine::LoadThruster(Element *thruster_element)
return false; return false;
} }
readXML(thruster_fullpathname, thruster_file_parser); document = LoadXMLDocument(thruster_fullpathname);
document = thruster_file_parser.GetDocument(); // document holds the thruster description
document->SetParent(thruster_element); document->SetParent(thruster_element);
thrType = document->GetName(); thrType = document->GetName();
@ -336,8 +332,8 @@ void FGEngine::Debug(int from)
cout << " X = " << Thruster->GetLocationX() << endl; cout << " X = " << Thruster->GetLocationX() << endl;
cout << " Y = " << Thruster->GetLocationY() << endl; cout << " Y = " << Thruster->GetLocationY() << endl;
cout << " Z = " << Thruster->GetLocationZ() << endl; cout << " Z = " << Thruster->GetLocationZ() << endl;
cout << " Pitch = " << Thruster->GetAnglesToBody(ePitch) << endl; cout << " Pitch = " << radtodeg*Thruster->GetAnglesToBody(ePitch) << " degrees" << endl;
cout << " Yaw = " << Thruster->GetAnglesToBody(eYaw) << endl; cout << " Yaw = " << radtodeg*Thruster->GetAnglesToBody(eYaw) << " degrees" << endl;
} }
} }
if (debug_lvl & 2 ) { // Instantiation/Destruction notification if (debug_lvl & 2 ) { // Instantiation/Destruction notification

View file

@ -60,6 +60,7 @@ INCLUDES
#include <FGJSBBase.h> #include <FGJSBBase.h>
#include "FGThruster.h" #include "FGThruster.h"
#include <input_output/FGPropertyManager.h> #include <input_output/FGPropertyManager.h>
#include <input_output/FGXMLFileRead.h>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS DEFINITIONS
@ -102,7 +103,7 @@ CLASS DOCUMENTATION
CLASS DECLARATION CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGEngine : public FGJSBBase class FGEngine : public FGJSBBase, public FGXMLFileRead
{ {
public: public:
FGEngine(FGFDMExec* exec, Element* el, int engine_number); FGEngine(FGFDMExec* exec, Element* el, int engine_number);

View file

@ -61,7 +61,6 @@ FGForce::FGForce(FGFDMExec *FDMExec) :
mT(1,1) = 1; //identity matrix mT(1,1) = 1; //identity matrix
mT(2,2) = 1; mT(2,2) = 1;
mT(3,3) = 1; mT(3,3) = 1;
vSense.InitMatrix(1);
Debug(0); Debug(0);
} }
@ -77,7 +76,7 @@ FGForce::~FGForce()
FGColumnVector3& FGForce::GetBodyForces(void) 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 // 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. // 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) void FGForce::SetAnglesToBody(double broll, double bpitch, double byaw)
{ {
if (ttype == tCustom) { if (ttype == tCustom) {
double cp,sp,cr,sr,cy,sy;
vOrient(ePitch) = bpitch; vOrient(ePitch) = bpitch;
vOrient(eRoll) = broll; vOrient(eRoll) = broll;
vOrient(eYaw) = byaw; vOrient(eYaw) = byaw;
cp=cos(bpitch); sp=sin(bpitch); UpdateCustomTransformMatrix();
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;
} }
} }

View file

@ -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 <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. 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> retrieved after calling the GetBodyForces() method:</p>
<p><tt>vM=fgf.GetMoments();</tt> </p> <p><tt>vM=fgf.GetMoments();</tt> </p>
@ -230,24 +230,7 @@ public:
/// Destructor /// Destructor
~FGForce(); ~FGForce();
enum TransformType { tNone, tWindBody, tLocalBody, tCustom } ttype; enum TransformType { tNone, tWindBody, tLocalBody, tCustom };
inline void SetNativeForces(double Fnx, double Fny, double Fnz) {
vFn(1)=Fnx;
vFn(2)=Fny;
vFn(3)=Fnz;
}
inline void SetNativeForces(FGColumnVector3 vv) { vFn = vv; };
inline void SetNativeMoments(double Ln,double Mn, double Nn) {
vMn(1)=Ln;
vMn(2)=Mn;
vMn(3)=Nn;
}
inline void SetNativeMoments(FGColumnVector3 vv) { vMn = vv; }
inline FGColumnVector3& GetNativeForces(void) { return vFn; }
inline FGColumnVector3& GetNativeMoments(void) { return vMn; }
FGColumnVector3& GetBodyForces(void); FGColumnVector3& GetBodyForces(void);
@ -305,18 +288,15 @@ public:
SetAnglesToBody(vv(eRoll), vv(ePitch), vv(eYaw)); SetAnglesToBody(vv(eRoll), vv(ePitch), vv(eYaw));
} }
void SetPitch(double pitch) {vOrient(ePitch) = pitch;} void UpdateCustomTransformMatrix(void);
void SetYaw(double yaw) {vOrient(eYaw) = yaw;} void SetPitch(double pitch) {vOrient(ePitch) = pitch; UpdateCustomTransformMatrix();}
void SetYaw(double yaw) {vOrient(eYaw) = yaw; UpdateCustomTransformMatrix();}
double GetPitch(void) const {return vOrient(ePitch);} double GetPitch(void) const {return vOrient(ePitch);}
double GetYaw(void) const {return vOrient(eYaw);} 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 FGColumnVector3& GetAnglesToBody(void) {return vOrient;}
inline double GetAnglesToBody(int axis) {return vOrient(axis);} inline double GetAnglesToBody(int axis) {return vOrient(axis);}
inline FGColumnVector3& GetSense(void) { return vSense; }
inline void SetTransformType(TransformType ii) { ttype=ii; } inline void SetTransformType(TransformType ii) { ttype=ii; }
inline TransformType GetTransformType(void) { return ttype; } inline TransformType GetTransformType(void) { return ttype; }
@ -329,14 +309,14 @@ protected:
FGColumnVector3 vMn; FGColumnVector3 vMn;
FGColumnVector3 vH; FGColumnVector3 vH;
FGColumnVector3 vOrient; FGColumnVector3 vOrient;
TransformType ttype;
FGColumnVector3 vXYZn;
FGColumnVector3 vActingXYZn;
private: private:
FGColumnVector3 vFb; FGColumnVector3 vFb;
FGColumnVector3 vM; FGColumnVector3 vM;
FGColumnVector3 vXYZn;
FGColumnVector3 vActingXYZn;
FGColumnVector3 vDXYZ; FGColumnVector3 vDXYZ;
FGColumnVector3 vSense;
FGMatrix33 mT; FGMatrix33 mT;

View file

@ -83,7 +83,7 @@ FGNozzle::FGNozzle(FGFDMExec* FDMExec, Element* nozzle_element, int num)
Type = ttNozzle; Type = ttNozzle;
Area2 = (Diameter*Diameter/4.0)*M_PI; Area2 = (Diameter*Diameter/4.0)*M_PI;
AreaT = Area2/ExpR; AreaT = Area2/ExpR;
Debug(0); Debug(0);
} }
@ -99,7 +99,11 @@ FGNozzle::~FGNozzle()
double FGNozzle::Calculate(double CfPc) double FGNozzle::Calculate(double CfPc)
{ {
double pAtm = fdmex->GetAtmosphere()->GetPressure(); 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); vFn(1) = Thrust * cos(ReverserAngle);
ThrustCoeff = max((double)0.0, CfPc / ((pAtm - PE) * Area2)); ThrustCoeff = max((double)0.0, CfPc / ((pAtm - PE) * Area2));
@ -120,7 +124,7 @@ string FGNozzle::GetThrusterLabels(int id, string delimeter)
{ {
std::ostringstream buf; std::ostringstream buf;
buf << Name << "_Thrust[" << id << ']'; buf << Name << " Thrust (engine " << id << " in lbs)";
return buf.str(); return buf.str();
} }

View file

@ -198,7 +198,7 @@ FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number)
} }
minMAP = MinManifoldPressure_inHg * 3386.38; // inHg to Pa minMAP = MinManifoldPressure_inHg * 3386.38; // inHg to Pa
maxMAP = MaxManifoldPressure_inHg * 3386.38; 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. // Set up and sanity-check the turbo/supercharging configuration based on the input values.
if (TakeoffBoost > RatedBoost[0]) bTakeoffBoost = true; if (TakeoffBoost > RatedBoost[0]) bTakeoffBoost = true;
@ -580,7 +580,7 @@ void FGPiston::doEnginePower(void)
if (RPM < 10) { if (RPM < 10) {
HP = StarterHP; HP = StarterHP;
} else if (RPM < 480) { } 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 // This is a guess - would be nice to find a proper starter moter torque curve
} else { } else {
HP = StarterHP; HP = StarterHP;
@ -593,7 +593,7 @@ void FGPiston::doEnginePower(void)
HP = 0.0; 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; std::ostringstream buf;
buf << Name << "_PwrAvail[" << EngineNumber << "]" << delimeter buf << Name << " Power Available (engine " << EngineNumber << " in HP)" << delimeter
<< Name << "_HP[" << EngineNumber << "]" << delimeter << Name << " HP (engine " << EngineNumber << ")" << delimeter
<< Name << "_equiv_ratio[" << EngineNumber << "]" << delimeter << Name << " equivalent ratio (engine " << EngineNumber << ")" << delimeter
<< Name << "_MAP[" << EngineNumber << "]" << delimeter << Name << " MAP (engine " << EngineNumber << ")" << delimeter
<< Thruster->GetThrusterLabels(EngineNumber, delimeter); << Thruster->GetThrusterLabels(EngineNumber, delimeter);
return buf.str(); return buf.str();

View file

@ -60,7 +60,6 @@ FGPropeller::FGPropeller(FGFDMExec* exec, Element* prop_element, int num)
: FGThruster(exec, prop_element, num) : FGThruster(exec, prop_element, num)
{ {
string token; string token;
int rows, cols;
Element *table_element, *local_element; Element *table_element, *local_element;
string name=""; string name="";
FGPropertyManager* PropertyManager = exec->GetPropertyManager(); FGPropertyManager* PropertyManager = exec->GetPropertyManager();
@ -297,13 +296,13 @@ string FGPropeller::GetThrusterLabels(int id, string delimeter)
{ {
std::ostringstream buf; std::ostringstream buf;
buf << Name << "_Torque[" << id << "]" << delimeter buf << Name << " Torque (engine " << id << ")" << delimeter
<< Name << "_PFactor_Pitch[" << id << "]" << delimeter << Name << " PFactor Pitch (engine " << id << ")" << delimeter
<< Name << "_PFactor_Yaw[" << id << "]" << delimeter << Name << " PFactor Yaw (engine " << id << ")" << delimeter
<< Name << "_Thrust[" << id << "]" << delimeter; << Name << " Thrust (engine " << id << " in lbs)" << delimeter;
if (IsVPitch()) if (IsVPitch())
buf << Name << "_Pitch[" << id << "]" << delimeter; buf << Name << " Pitch (engine " << id << ")" << delimeter;
buf << Name << "_RPM[" << id << "]"; buf << Name << " RPM (engine " << id << ")";
return buf.str(); return buf.str();
} }

View file

@ -54,6 +54,15 @@ CLASS IMPLEMENTATION
FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number) FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number)
: FGEngine(exec, el, 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")) if (el->FindElement("shr"))
SHR = el->FindElementValueAsNumber("shr"); SHR = el->FindElementValueAsNumber("shr");
if (el->FindElement("max_pc")) if (el->FindElement("max_pc"))
@ -71,6 +80,11 @@ FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number)
if (el->FindElement("variance")) if (el->FindElement("variance"))
Variance = el->FindElementValueAsNumber("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); Debug(0);
Type = etRocket; Type = etRocket;
@ -97,6 +111,18 @@ double FGRocket::Calculate(void)
Throttle = FCS->GetThrottlePos(EngineNumber); 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) { if (Throttle < MinThrottle || Starved) {
PctPower = Thrust = 0.0; // desired thrust PctPower = Thrust = 0.0; // desired thrust
Flameout = true; Flameout = true;
@ -122,7 +148,7 @@ string FGRocket::GetEngineLabels(string delimeter)
{ {
std::ostringstream buf; std::ostringstream buf;
buf << Name << "_ChamberPress[" << EngineNumber << "]" << delimeter buf << Name << " Chamber Pressure (engine " << EngineNumber << " in psf)" << delimeter
<< Thruster->GetThrusterLabels(EngineNumber, delimeter); << Thruster->GetThrusterLabels(EngineNumber, delimeter);
return buf.str(); return buf.str();

View file

@ -39,6 +39,7 @@ INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGEngine.h" #include "FGEngine.h"
#include <math/FGTable.h>
#include <input_output/FGXMLElement.h> #include <input_output/FGXMLElement.h>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -83,6 +84,45 @@ CLASS DOCUMENTATION
coefficient is multiplied by the chamber pressure and then passed coefficient is multiplied by the chamber pressure and then passed
to the nozzle Calculate() routine, where the thrust force is to the nozzle Calculate() routine, where the thrust force is
determined. 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 @author Jon S. Berndt
$Id$ $Id$
@ -133,7 +173,9 @@ private:
double kFactor; double kFactor;
double Variance; double Variance;
double PC; double PC;
double BurnTime;
bool Flameout; bool Flameout;
FGTable* ThrustTable;
void Debug(int from); void Debug(int from);
}; };

View file

@ -58,7 +58,7 @@ FGThruster::FGThruster(FGFDMExec *FDMExec, Element *el, int num ): FGForce(FDMEx
Type = ttDirect; Type = ttDirect;
SetTransformType(FGForce::tCustom); SetTransformType(FGForce::tCustom);
Name = el->GetName(); Name = el->GetAttributeValue("name");
GearRatio = 1.0; GearRatio = 1.0;
ReverserAngle = 0.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; else cerr << "No thruster location found." << endl;
element = thruster_element->FindElement("orient"); element = thruster_element->FindElement("orient");
if (element) orientation = element->FindElementTripletConvertTo("IN"); if (element) orientation = element->FindElementTripletConvertTo("RAD");
else cerr << "No thruster orientation found." << endl; else cerr << "No thruster orientation found." << endl;
SetLocation(location); SetLocation(location);
@ -122,7 +122,7 @@ string FGThruster::GetThrusterLabels(int id, string delimeter)
{ {
std::ostringstream buf; std::ostringstream buf;
buf << Name << "_Thrust[" << id << "]"; buf << Name << " Thrust (engine " << id << " in lbs)";
return buf.str(); return buf.str();
} }

View file

@ -278,7 +278,7 @@ double FGTurboProp::Off(void)
double FGTurboProp::Run(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; Running = true; Starter = false; EngStarting = false;
//--- //---