Sync w. JSBSim CVS (merge from PRE_OSG_PLIB_20061029 branch)
This commit is contained in:
parent
2c3dc5fca1
commit
3cda82e0a9
56 changed files with 985 additions and 503 deletions
|
@ -134,6 +134,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root)
|
||||||
modelLoaded = false;
|
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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {};
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) );
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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++;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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) {}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
|
@ -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) << " "
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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*);
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
256
src/FDM/JSBSim/models/flight_control/FGActuator.cpp
Executable file
256
src/FDM/JSBSim/models/flight_control/FGActuator.cpp
Executable file
|
@ -0,0 +1,256 @@
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
Module: FGActuator.cpp
|
||||||
|
Author: Jon Berndt
|
||||||
|
Date started: 21 February 2006
|
||||||
|
|
||||||
|
------------- Copyright (C) 2007 Jon S. Berndt (jsb@hal-pc.org) -------------
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||||
|
details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
|
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
Further information about the GNU Lesser General Public License can also be found on
|
||||||
|
the world wide web at http://www.gnu.org.
|
||||||
|
|
||||||
|
FUNCTIONAL DESCRIPTION
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
HISTORY
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
COMMENTS, REFERENCES, and NOTES
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
INCLUDES
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#include "FGActuator.h"
|
||||||
|
|
||||||
|
namespace JSBSim {
|
||||||
|
|
||||||
|
static const char *IdSrc = "$Id$";
|
||||||
|
static const char *IdHdr = ID_ACTUATOR;
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
CLASS IMPLEMENTATION
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
|
||||||
|
FGActuator::FGActuator(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
|
||||||
|
{
|
||||||
|
double denom;
|
||||||
|
dt = fcs->GetDt();
|
||||||
|
|
||||||
|
// inputs are read from the base class constructor
|
||||||
|
|
||||||
|
PreviousOutput = 0.0;
|
||||||
|
PreviousHystOutput = 0.0;
|
||||||
|
PreviousRateLimOutput = 0.0;
|
||||||
|
PreviousLagInput = PreviousLagOutput = 0.0;
|
||||||
|
bias = lag = hysteresis_width = deadband_width = 0.0;
|
||||||
|
rate_limit = 0.0; // no limit
|
||||||
|
fail_zero = fail_hardover = fail_stuck = false;
|
||||||
|
ca = cb = 0.0;
|
||||||
|
|
||||||
|
if ( element->FindElement("deadband_width") ) {
|
||||||
|
deadband_width = element->FindElementValueAsNumber("deadband_width");
|
||||||
|
}
|
||||||
|
if ( element->FindElement("hysteresis_width") ) {
|
||||||
|
hysteresis_width = element->FindElementValueAsNumber("hysteresis_width");
|
||||||
|
}
|
||||||
|
if ( element->FindElement("rate_limit") ) {
|
||||||
|
rate_limit = element->FindElementValueAsNumber("rate_limit");
|
||||||
|
}
|
||||||
|
if ( element->FindElement("bias") ) {
|
||||||
|
bias = element->FindElementValueAsNumber("bias");
|
||||||
|
}
|
||||||
|
if ( element->FindElement("lag") ) {
|
||||||
|
lag = element->FindElementValueAsNumber("lag");
|
||||||
|
denom = 2.00 + dt*lag;
|
||||||
|
ca = dt*lag / denom;
|
||||||
|
cb = (2.00 - dt*lag) / denom;
|
||||||
|
}
|
||||||
|
|
||||||
|
FGFCSComponent::bind();
|
||||||
|
bind();
|
||||||
|
|
||||||
|
Debug(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
FGActuator::~FGActuator()
|
||||||
|
{
|
||||||
|
Debug(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
bool FGActuator::Run(void )
|
||||||
|
{
|
||||||
|
dt = fcs->GetDt();
|
||||||
|
|
||||||
|
Input = InputNodes[0]->getDoubleValue() * InputSigns[0];
|
||||||
|
Output = Input; // perfect actuator
|
||||||
|
|
||||||
|
if (fail_zero) Input = 0;
|
||||||
|
if (fail_hardover) Input = clipmax*fabs(Input)/Input;
|
||||||
|
|
||||||
|
if (lag != 0.0) Lag(); // models actuator lag
|
||||||
|
if (rate_limit != 0) RateLimit(); // limit the actuator rate
|
||||||
|
if (deadband_width != 0.0) Deadband();
|
||||||
|
if (hysteresis_width != 0.0) Hysteresis();
|
||||||
|
if (bias != 0.0) Bias(); // models a finite bias
|
||||||
|
|
||||||
|
if (fail_stuck) Output = PreviousOutput;
|
||||||
|
PreviousOutput = Output; // previous value needed for "stuck" malfunction
|
||||||
|
|
||||||
|
Clip();
|
||||||
|
if (IsOutput) SetOutput();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGActuator::Bias(void)
|
||||||
|
{
|
||||||
|
Output += bias;
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGActuator::Lag(void)
|
||||||
|
{
|
||||||
|
// "Output" on the right side of the "=" is the current frame input
|
||||||
|
// for this Lag filter
|
||||||
|
double input = Output;
|
||||||
|
Output = ca * (input + PreviousLagInput) + PreviousLagOutput * cb;
|
||||||
|
PreviousLagInput = input;
|
||||||
|
PreviousLagOutput = Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGActuator::Hysteresis(void)
|
||||||
|
{
|
||||||
|
// Note: this function acts cumulatively on the "Output" parameter. So, "Output"
|
||||||
|
// is - for the purposes of this Hysteresis method - really the input to the
|
||||||
|
// method.
|
||||||
|
double input = Output;
|
||||||
|
|
||||||
|
if (input > PreviousHystOutput) {
|
||||||
|
Output = max(PreviousHystOutput, input-0.5*hysteresis_width);
|
||||||
|
} else if (input < PreviousHystOutput) {
|
||||||
|
Output = min(PreviousHystOutput, input+0.5*hysteresis_width);
|
||||||
|
}
|
||||||
|
|
||||||
|
PreviousHystOutput = Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGActuator::RateLimit(void)
|
||||||
|
{
|
||||||
|
// Note: this function acts cumulatively on the "Output" parameter. So, "Output"
|
||||||
|
// is - for the purposes of this RateLimit method - really the input to the
|
||||||
|
// method.
|
||||||
|
double input = Output;
|
||||||
|
if (dt > 0.0) {
|
||||||
|
double rate = (input - PreviousRateLimOutput)/dt;
|
||||||
|
if (fabs(rate) > rate_limit) {
|
||||||
|
Output = PreviousRateLimOutput + (rate_limit*fabs(rate)/rate)*dt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PreviousRateLimOutput = Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGActuator::Deadband(void)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGActuator::bind(void)
|
||||||
|
{
|
||||||
|
string tmp = "fcs/" + PropertyManager->mkPropertyName(Name, true);
|
||||||
|
const string tmp_zero = tmp + "/malfunction/fail_zero";
|
||||||
|
const string tmp_hardover = tmp + "/malfunction/fail_hardover";
|
||||||
|
const string tmp_stuck = tmp + "/malfunction/fail_stuck";
|
||||||
|
|
||||||
|
PropertyManager->Tie( tmp_zero, this, &FGActuator::GetFailZero, &FGActuator::SetFailZero);
|
||||||
|
PropertyManager->Tie( tmp_hardover, this, &FGActuator::GetFailHardover, &FGActuator::SetFailHardover);
|
||||||
|
PropertyManager->Tie( tmp_stuck, this, &FGActuator::GetFailStuck, &FGActuator::SetFailStuck);
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
// The bitmasked value choices are as follows:
|
||||||
|
// unset: In this case (the default) JSBSim would only print
|
||||||
|
// out the normally expected messages, essentially echoing
|
||||||
|
// the config files as they are read. If the environment
|
||||||
|
// variable is not set, debug_lvl is set to 1 internally
|
||||||
|
// 0: This requests JSBSim not to output any messages
|
||||||
|
// whatsoever.
|
||||||
|
// 1: This value explicity requests the normal JSBSim
|
||||||
|
// startup messages
|
||||||
|
// 2: This value asks for a message to be printed out when
|
||||||
|
// a class is instantiated
|
||||||
|
// 4: When this value is set, a message is displayed when a
|
||||||
|
// FGModel object executes its Run() method
|
||||||
|
// 8: When this value is set, various runtime state variables
|
||||||
|
// are printed out periodically
|
||||||
|
// 16: When set various parameters are sanity checked and
|
||||||
|
// a message is printed out when they go out of bounds
|
||||||
|
|
||||||
|
void FGActuator::Debug(int from)
|
||||||
|
{
|
||||||
|
if (debug_lvl <= 0) return;
|
||||||
|
|
||||||
|
if (debug_lvl & 1) { // Standard console startup message output
|
||||||
|
if (from == 0) { // Constructor
|
||||||
|
if (InputSigns[0] < 0)
|
||||||
|
cout << " INPUT: -" << InputNodes[0]->getName() << endl;
|
||||||
|
else
|
||||||
|
cout << " INPUT: " << InputNodes[0]->getName() << endl;
|
||||||
|
|
||||||
|
if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
|
||||||
|
if (bias != 0.0) cout << " Bias: " << bias << endl;
|
||||||
|
if (rate_limit != 0) cout << " Rate limit: " << rate_limit << endl;
|
||||||
|
if (lag != 0) cout << " Actuator lag: " << lag << endl;
|
||||||
|
if (hysteresis_width != 0) cout << " Hysteresis width: " << hysteresis_width << endl;
|
||||||
|
if (deadband_width != 0) cout << " Deadband width: " << deadband_width << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
||||||
|
if (from == 0) cout << "Instantiated: FGActuator" << endl;
|
||||||
|
if (from == 1) cout << "Destroyed: FGActuator" << endl;
|
||||||
|
}
|
||||||
|
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
|
||||||
|
}
|
||||||
|
if (debug_lvl & 8 ) { // Runtime state variables
|
||||||
|
}
|
||||||
|
if (debug_lvl & 16) { // Sanity checking
|
||||||
|
}
|
||||||
|
if (debug_lvl & 64) {
|
||||||
|
if (from == 0) { // Constructor
|
||||||
|
cout << IdSrc << endl;
|
||||||
|
cout << IdHdr << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
176
src/FDM/JSBSim/models/flight_control/FGActuator.h
Executable file
176
src/FDM/JSBSim/models/flight_control/FGActuator.h
Executable file
|
@ -0,0 +1,176 @@
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
Header: FGActuator.h
|
||||||
|
Author: Jon Berndt
|
||||||
|
Date started: 21 February 2007
|
||||||
|
|
||||||
|
------------- Copyright (C) 2006 Jon S. Berndt (jsb@hal-pc.org) -------------
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU Lesser General Public License as published by the Free Software
|
||||||
|
Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||||
|
details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
|
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
Further information about the GNU Lesser General Public License can also be found on
|
||||||
|
the world wide web at http://www.gnu.org.
|
||||||
|
|
||||||
|
HISTORY
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
SENTRY
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#ifndef FGACTUATOR_H
|
||||||
|
#define FGACTUATOR_H
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
INCLUDES
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#include "FGFCSComponent.h"
|
||||||
|
#include <input_output/FGXMLElement.h>
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
DEFINITIONS
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#define ID_ACTUATOR "$Id$"
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
FORWARD DECLARATIONS
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
namespace JSBSim {
|
||||||
|
|
||||||
|
class FGFCS;
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
CLASS DOCUMENTATION
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
/** Encapsulates an Actuator component for the flight control system.
|
||||||
|
The actuator can be modeled as a "perfect actuator", with the Output
|
||||||
|
being set directly to the input. The actuator can be made more "real"
|
||||||
|
by specifying any/all of the following additional effects that can be
|
||||||
|
applied to the actuator. In order of application to the input signal,
|
||||||
|
these are:
|
||||||
|
|
||||||
|
-System lag (input lag, really)
|
||||||
|
-Rate limiting
|
||||||
|
-Deadband
|
||||||
|
-Hysteresis (mechanical hysteresis)
|
||||||
|
-Bias (mechanical bias)
|
||||||
|
-Position limiting ("hard stops")
|
||||||
|
|
||||||
|
There are also several malfunctions that can be applied to the actuator
|
||||||
|
by setting a property to true or false (or 1 or 0).
|
||||||
|
|
||||||
|
Syntax:
|
||||||
|
|
||||||
|
@code
|
||||||
|
<actuator name=”name”>
|
||||||
|
<input> {[-]property} </input>
|
||||||
|
<lag> number </lag>
|
||||||
|
<rate_limit> number <rate_limit>
|
||||||
|
<bias> number </bias>
|
||||||
|
<deadband_width> number </deadband_width>
|
||||||
|
<hysteresis_width> number </hysteresis_width>
|
||||||
|
[<clipto>
|
||||||
|
<min> {property name | value} </min>
|
||||||
|
<max> {property name | value} </max>
|
||||||
|
</clipto>]
|
||||||
|
[<output> {property} </output>]
|
||||||
|
</actuator>
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
@code
|
||||||
|
<actuator name=”fcs/gimbal_pitch_position”>
|
||||||
|
<input> fcs/gimbal_pitch_command </input>
|
||||||
|
<lag> 60 </lag>
|
||||||
|
<rate_limit> 0.085 <rate_limit> <!-- 5 degrees/sec -->
|
||||||
|
<bias> 0.002 </bias>
|
||||||
|
<deadband_width> 0.002 </deadband_width>
|
||||||
|
<hysteresis_width> 0.05 </hysteresis_width>
|
||||||
|
<clipto> <!-- +/- 10 degrees -->
|
||||||
|
<min> -0.17 </min>
|
||||||
|
<max> 0.17 </max>
|
||||||
|
</clipto>
|
||||||
|
</actuator>
|
||||||
|
@endcode
|
||||||
|
|
||||||
|
@author Jon S. Berndt
|
||||||
|
@version $Revision$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
CLASS DECLARATION
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
class FGActuator : public FGFCSComponent
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/// Constructor
|
||||||
|
FGActuator(FGFCS* fcs, Element* element);
|
||||||
|
/// Destructor
|
||||||
|
~FGActuator();
|
||||||
|
|
||||||
|
/** This function processes the input.
|
||||||
|
It calls private functions if needed to perform the hysteresis, lag,
|
||||||
|
limiting, etc. functions. */
|
||||||
|
bool Run (void);
|
||||||
|
|
||||||
|
// these may need to have the bool argument replaced with a double
|
||||||
|
/** This function fails the actuator to zero. The motion to zero
|
||||||
|
will flow through the lag, hysteresis, and rate limiting
|
||||||
|
functions if those are activated. */
|
||||||
|
inline void SetFailZero(bool set) {fail_zero = set;}
|
||||||
|
inline void SetFailHardover(bool set) {fail_hardover = set;}
|
||||||
|
inline void SetFailStuck(bool set) {fail_stuck = set;}
|
||||||
|
|
||||||
|
inline bool GetFailZero(void) const {return fail_zero;}
|
||||||
|
inline bool GetFailHardover(void) const {return fail_hardover;}
|
||||||
|
inline bool GetFailStuck(void) const {return fail_stuck;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
double dt;
|
||||||
|
double span;
|
||||||
|
double bias;
|
||||||
|
double rate_limit;
|
||||||
|
double hysteresis_width;
|
||||||
|
double deadband_width;
|
||||||
|
double lag;
|
||||||
|
double ca; // lag filter coefficient "a"
|
||||||
|
double cb; // lag filter coefficient "b"
|
||||||
|
double PreviousOutput;
|
||||||
|
double PreviousHystOutput;
|
||||||
|
double PreviousRateLimOutput;
|
||||||
|
double PreviousLagInput;
|
||||||
|
double PreviousLagOutput;
|
||||||
|
bool fail_zero;
|
||||||
|
bool fail_hardover;
|
||||||
|
bool fail_stuck;
|
||||||
|
|
||||||
|
void Hysteresis(void);
|
||||||
|
void Lag(void);
|
||||||
|
void RateLimit(void);
|
||||||
|
void Deadband(void);
|
||||||
|
void Bias(void);
|
||||||
|
|
||||||
|
void bind(void);
|
||||||
|
|
||||||
|
void Debug(int from);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -89,6 +89,8 @@ FGFCSComponent::FGFCSComponent(FGFCS* _fcs, Element* element) : fcs(_fcs)
|
||||||
Type = "PID";
|
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";
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
//---
|
//---
|
||||||
|
|
Loading…
Reference in a new issue