1
0
Fork 0

Sync w. JSBSim CVS (merge from PRE_OSG_PLIB_20061029 branch)

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

View file

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

View file

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

View file

@ -94,9 +94,9 @@ const double FGJSBBase::slugtolb = 32.174049;
const double FGJSBBase::lbtoslug = 1.0/slugtolb;
const string FGJSBBase::needed_cfg_version = "2.0";
const string FGJSBBase::JSBSim_version = "0.9.12 "__DATE__" "__TIME__;
const string FGJSBBase::JSBSim_version = "Pre-1.0 "__DATE__" "__TIME__;
std::queue <FGJSBBase::Message*> FGJSBBase::Messages;
std::queue <FGJSBBase::Message> FGJSBBase::Messages;
FGJSBBase::Message FGJSBBase::localMsg;
unsigned int FGJSBBase::messageId = 0;
@ -104,83 +104,75 @@ short FGJSBBase::debug_lvl = 1;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGJSBBase::Message* FGJSBBase::PutMessage(Message* msg)
void FGJSBBase::PutMessage(const Message& msg)
{
Messages.push(msg);
return msg;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGJSBBase::Message* FGJSBBase::PutMessage(const string& text)
void FGJSBBase::PutMessage(const string& text)
{
Message *msg = new Message();
msg->text = text;
msg->messageId = messageId++;
msg->subsystem = "FDM";
msg->type = Message::eText;
Message msg;
msg.text = text;
msg.messageId = messageId++;
msg.subsystem = "FDM";
msg.type = Message::eText;
Messages.push(msg);
return msg;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGJSBBase::Message* FGJSBBase::PutMessage(const string& text, bool bVal)
void FGJSBBase::PutMessage(const string& text, bool bVal)
{
Message *msg = new Message();
msg->text = text;
msg->messageId = messageId++;
msg->subsystem = "FDM";
msg->type = Message::eBool;
msg->bVal = bVal;
Message msg;
msg.text = text;
msg.messageId = messageId++;
msg.subsystem = "FDM";
msg.type = Message::eBool;
msg.bVal = bVal;
Messages.push(msg);
return msg;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGJSBBase::Message* FGJSBBase::PutMessage(const string& text, int iVal)
void FGJSBBase::PutMessage(const string& text, int iVal)
{
Message *msg = new Message();
msg->text = text;
msg->messageId = messageId++;
msg->subsystem = "FDM";
msg->type = Message::eInteger;
msg->bVal = (iVal != 0);
Message msg;
msg.text = text;
msg.messageId = messageId++;
msg.subsystem = "FDM";
msg.type = Message::eInteger;
msg.bVal = (iVal != 0);
Messages.push(msg);
return msg;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGJSBBase::Message* FGJSBBase::PutMessage(const string& text, double dVal)
void FGJSBBase::PutMessage(const string& text, double dVal)
{
Message *msg = new Message();
msg->text = text;
msg->messageId = messageId++;
msg->subsystem = "FDM";
msg->type = Message::eDouble;
msg->bVal = (dVal != 0.0);
Message msg;
msg.text = text;
msg.messageId = messageId++;
msg.subsystem = "FDM";
msg.type = Message::eDouble;
msg.bVal = (dVal != 0.0);
Messages.push(msg);
return msg;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGJSBBase::Message* FGJSBBase::ReadMessage(void)
int FGJSBBase::SomeMessages(void)
{
if (!Messages.empty()) return Messages.front();
else return NULL;
return !Messages.empty();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGJSBBase::Message* FGJSBBase::ProcessMessage(void)
{
if (!Messages.empty())
localMsg = *(Messages.front());
else
return NULL;
if (Messages.empty()) return NULL;
localMsg = Messages.front();
Messages.pop();
return &localMsg;
}

View file

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

View file

@ -47,10 +47,6 @@ INCLUDES
# endif
#endif
#ifdef _WIN32
//#define snprintf _snprintf
#endif
#include "FGState.h"
namespace JSBSim {
@ -190,86 +186,6 @@ FGMatrix33& FGState::GetTb2s(void)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGState::ReportState(void)
{
#if 0
#if !defined(__BORLANDCPP__)
char out[80], flap[10], gear[12];
cout << endl << " JSBSim State" << endl;
snprintf(out,80," Weight: %7.0f lbs. CG: %5.1f, %5.1f, %5.1f inches\n",
FDMExec->GetMassBalance()->GetWeight(),
FDMExec->GetMassBalance()->GetXYZcg(1),
FDMExec->GetMassBalance()->GetXYZcg(2),
FDMExec->GetMassBalance()->GetXYZcg(3));
cout << out;
if ( FCS->GetDfPos() <= 0.01)
snprintf(flap,10,"Up");
else
snprintf(flap,10,"%2.0f",FCS->GetDfPos());
if (FCS->GetGearPos() < 0.01)
snprintf(gear,12,"Up");
else if (FCS->GetGearPos() > 0.99)
snprintf(gear,12,"Down");
else
snprintf(gear,12,"In Transit");
snprintf(out,80, " Flaps: %3s Gear: %12s\n",flap,gear);
cout << out;
snprintf(out,80, " Speed: %4.0f KCAS Mach: %5.2f\n",
Auxiliary->GetVcalibratedKTS(),
Auxiliary->GetMach() );
cout << out;
snprintf(out,80, " Altitude: %7.0f ft. AGL Altitude: %7.0f ft.\n",
Propagate->Geth(),
Propagate->GetDistanceAGL() );
cout << out;
snprintf(out,80, " Angle of Attack: %6.2f deg Pitch Angle: %6.2f deg\n",
Auxiliary->Getalpha()*radtodeg,
Propagate->Gettht()*radtodeg );
cout << out;
snprintf(out,80, " Flight Path Angle: %6.2f deg Climb Rate: %5.0f ft/min\n",
Auxiliary->GetGamma()*radtodeg,
Propagate->Gethdot()*60 );
cout << out;
snprintf(out,80, " Normal Load Factor: %4.2f g's Pitch Rate: %5.2f deg/s\n",
Aircraft->GetNlf(),
Propagate->GetPQR(2)*radtodeg );
cout << out;
snprintf(out,80, " Heading: %3.0f deg true Sideslip: %5.2f deg Yaw Rate: %5.2f deg/s\n",
Propagate->Getpsi()*radtodeg,
Auxiliary->Getbeta()*radtodeg,
Propagate->GetPQR(3)*radtodeg );
cout << out;
snprintf(out,80, " Bank Angle: %5.2f deg Roll Rate: %5.2f deg/s\n",
Propagate->Getphi()*radtodeg,
Propagate->GetPQR(1)*radtodeg );
cout << out;
snprintf(out,80, " Elevator: %5.2f deg Left Aileron: %5.2f deg Rudder: %5.2f deg\n",
FCS->GetDePos(ofRad)*radtodeg,
FCS->GetDaLPos(ofRad)*radtodeg,
FCS->GetDrPos(ofRad)*radtodeg );
cout << out;
snprintf(out,80, " Throttle: %5.2f%c\n",
FCS->GetThrottlePos(0)*100,'%' );
cout << out;
snprintf(out,80, " Wind Components: %5.2f kts head wind, %5.2f kts cross wind\n",
Auxiliary->GetHeadWind()*fpstokts,
Auxiliary->GetCrossWind()*fpstokts );
cout << out;
snprintf(out,80, " Ground Speed: %4.0f knots , Ground Track: %3.0f deg true\n",
Auxiliary->GetVground()*fpstokts,
Auxiliary->GetGroundTrack()*radtodeg );
cout << out;
#endif
#endif
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGState::bind(void)
{
PropertyManager->Tie("sim-time-sec", this, &FGState::Getsim_time);

View file

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

View file

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

View file

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

View file

@ -106,12 +106,34 @@ bool FGPropertyManager::HasNode (const string &path)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGPropertyManager::GetName( void ) {
string FGPropertyManager::GetName( void )
{
return string( getName() );
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGPropertyManager::GetPrintableName( void )
{
string temp_string(getName());
size_t initial_location=0;
size_t found_location;
found_location = temp_string.rfind("/");
if (found_location != string::npos)
temp_string = temp_string.substr(found_location);
found_location = temp_string.find('_',initial_location);
while (found_location != string::npos) {
temp_string.replace(found_location,1," ");
initial_location = found_location+1;
found_location = temp_string.find('_',initial_location);
}
return temp_string;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGPropertyManager::GetFullyQualifiedName(void) {
vector<string> stack;
stack.push_back( getDisplayName(true) );

View file

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

View file

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

View file

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

View file

@ -292,31 +292,32 @@ string Element::FindElementValue(string el)
double Element::FindElementValueAsNumberConvertTo(string el, string target_units)
{
Element* element = FindElement(el);
double value;
string supplied_units="";
if (element) {
value = element->GetDataAsNumber();
supplied_units = element->GetAttributeValue("unit");
if (!supplied_units.empty()) {
if (convert.find(supplied_units) != convert.end()) {
if (convert[supplied_units].find(target_units) != convert[supplied_units].end()) {
value *= convert[supplied_units][target_units];
} else {
cerr << endl << "Target unit: \"" << target_units << "\" does not exist (typo?). Add new unit"
<< " conversion in FGXMLElement.cpp." << endl;
exit(-1);
if (!element) {
cerr << "Attempting to get non-existent element " << el << endl;
exit(0);
}
} else {
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);
}
} else {
cerr << "Attempting to get get non-existent element " << el << endl;
return 0;
}
double value = element->GetDataAsNumber();
if (!supplied_units.empty()) {
value *= convert[supplied_units][target_units];
}
return value;
}
@ -327,29 +328,30 @@ double Element::FindElementValueAsNumberConvertFromTo( string el,
string target_units)
{
Element* element = FindElement(el);
double value;
if (element) {
value = element->GetDataAsNumber();
if (!supplied_units.empty()) {
if (convert.find(supplied_units) != convert.end()) {
if (convert[supplied_units].find(target_units) != convert[supplied_units].end()) {
value *= convert[supplied_units][target_units];
} else {
cerr << endl << "Target unit: \"" << target_units << "\" does not exist (typo?). Add new unit"
<< " conversion in FGXMLElement.cpp." << endl;
exit(-1);
if (!element) {
cerr << "Attempting to get non-existent element " << el << endl;
exit(0);
}
} else {
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);
}
} else {
cerr << "Attempting to get get non-existent element " << el << endl;
return 0;
}
double value = element->GetDataAsNumber();
if (!supplied_units.empty()) {
value *= convert[supplied_units][target_units];
}
return value;
}
@ -362,6 +364,19 @@ FGColumnVector3 Element::FindElementTripletConvertTo( string target_units)
double value=0.0;
string supplied_units = GetAttributeValue("unit");
if (!supplied_units.empty()) {
if (convert.find(supplied_units) == convert.end()) {
cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit"
<< " conversion in FGXMLElement.cpp." << endl;
exit(-1);
}
if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) {
cerr << endl << "Supplied unit: \"" << supplied_units << "\" cannot be converted to "
<< target_units << ". Add new unit conversion in FGXMLElement.cpp or fix typo" << endl;
exit(-1);
}
}
item = FindElement("x");
if (!item) item = FindElement("roll");
if (item) {

View file

@ -2,6 +2,6 @@ noinst_LIBRARIES = libInputOutput.a
libInputOutput_a_SOURCES = FGGroundCallback.cpp FGPropertyManager.cpp FGScript.cpp FGXMLElement.cpp FGXMLParse.cpp FGfdmSocket.cpp
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

View file

@ -121,13 +121,6 @@ FGColumnVector3& FGColumnVector3::Normalize(void)
return *this;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGColumnVector3 FGColumnVector3::multElementWise(const FGColumnVector3& V) const
{
return FGColumnVector3(Entry(1) * V(1), Entry(2) * V(2), Entry(3) * V(3));
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print

View file

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

View file

@ -47,7 +47,6 @@ CLASS IMPLEMENTATION
FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, string prefix)
: PropertyManager(propMan), Prefix(prefix)
{
int i;
Element* element;
string operation, property_name;
int size = el->GetNumElements();
@ -92,6 +91,16 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, string prefix)
}
element = el->GetElement();
if (!element) {
cerr << fgred << highint << endl;
cerr << " No element was specified as an argument to the \"" << operation << "\" operation" << endl;
cerr << " This can happen when, for instance, a cos operation is specified and a " << endl;
cerr << " property name is given explicitly, but is not placed within a" << endl;
cerr << " <property></property> element tag pair." << endl;
cerr << reset;
exit(-2);
}
while (element) {
operation = element->GetName();
@ -146,7 +155,7 @@ FGFunction::~FGFunction(void)
PropertyManager->Untie(tmp);
}
for (int i=0; i<Parameters.size(); i++) {
for (unsigned int i=0; i<Parameters.size(); i++) {
delete Parameters[i];
}
}
@ -167,7 +176,7 @@ void FGFunction::cacheValue(bool cache)
double FGFunction::GetValue(void) const
{
int i;
unsigned int i;
if (cached) return cachedValue;
@ -177,13 +186,19 @@ double FGFunction::GetValue(void) const
case eTopLevel:
break;
case eProduct:
for (i=1;i<Parameters.size();i++) temp *= Parameters[i]->GetValue();
for (i=1;i<Parameters.size();i++) {
temp *= Parameters[i]->GetValue();
}
break;
case eDifference:
for (i=1;i<Parameters.size();i++) temp -= Parameters[i]->GetValue();
for (i=1;i<Parameters.size();i++) {
temp -= Parameters[i]->GetValue();
}
break;
case eSum:
for (i=1;i<Parameters.size();i++) temp += Parameters[i]->GetValue();
for (i=1;i<Parameters.size();i++) {
temp += Parameters[i]->GetValue();
}
break;
case eQuotient:
temp /= Parameters[1]->GetValue();

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -101,16 +101,16 @@ FGAuxiliary::~FGAuxiliary()
bool FGAuxiliary::Run()
{
double A,B,D, hdot_Vt;
double A,B,D;
if (FGModel::Run()) return true; // return true if error returned from base class
if (FDMExec->Holding()) return false;
const FGColumnVector3& vPQR = Propagate->GetPQR();
const FGColumnVector3& vUVW = Propagate->GetUVW();
const FGColumnVector3& vUVWdot = Propagate->GetUVWdot();
const FGColumnVector3& vVel = Propagate->GetVel();
if (FGModel::Run()) return true; // return true if error returned from base class
if (FDMExec->Holding()) return false;
p = Atmosphere->GetPressure();
rhosl = Atmosphere->GetDensitySL();
psl = Atmosphere->GetPressureSL();
@ -182,18 +182,9 @@ bool FGAuxiliary::Run()
Vground = sqrt( vVel(eNorth)*vVel(eNorth) + vVel(eEast)*vVel(eEast) );
if (vVel(eNorth) == 0) psigt = 0;
else psigt = atan2(vVel(eEast), vVel(eNorth));
psigt = atan2(vVel(eEast), vVel(eNorth));
if (psigt < 0.0) psigt += 2*M_PI;
if (Vground == 0.0) {
if (vVel(eDown) == 0.0) gamma = 0.0;
else if (vVel(eDown) < 0.0) gamma = 90.0*degtorad;
else gamma = -90.0*degtorad;
} else {
gamma = atan2(-vVel(eDown), Vground);
}
tat = sat*(1 + 0.2*Mach*Mach); // Total Temperature, isentropic flow
tatc = RankineToCelsius(tat);

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -244,6 +244,8 @@ public:
inline bool GetGearUnitDown(void) { return GearDown; }
inline double GetWheelSideForce(void) { return SideForce; }
inline double GetWheelRollForce(void) { return RollingForce; }
inline double GetWheelSideVel(void) { return SideWhlVel; }
inline double GetWheelRollVel(void) { return RollingWhlVel; }
inline double GetBodyXForce(void) { return vLocalForce(eX); }
inline double GetBodyYForce(void) { return vLocalForce(eY); }
inline double GetWheelSlipAngle(void) { return WheelSlip; }

View file

@ -281,11 +281,11 @@ void FGMassBalance::bind(void)
&FGMassBalance::GetMass);
PropertyManager->Tie("inertia/weight-lbs", this,
&FGMassBalance::GetWeight);
PropertyManager->Tie("inertia/cg-x-ft", this,1,
PropertyManager->Tie("inertia/cg-x-in", this,1,
(PMF)&FGMassBalance::GetXYZcg);
PropertyManager->Tie("inertia/cg-y-ft", this,2,
PropertyManager->Tie("inertia/cg-y-in", this,2,
(PMF)&FGMassBalance::GetXYZcg);
PropertyManager->Tie("inertia/cg-z-ft", this,3,
PropertyManager->Tie("inertia/cg-z-in", this,3,
(PMF)&FGMassBalance::GetXYZcg);
}
@ -295,9 +295,9 @@ void FGMassBalance::unbind(void)
{
PropertyManager->Untie("inertia/mass-slugs");
PropertyManager->Untie("inertia/weight-lbs");
PropertyManager->Untie("inertia/cg-x-ft");
PropertyManager->Untie("inertia/cg-y-ft");
PropertyManager->Untie("inertia/cg-z-ft");
PropertyManager->Untie("inertia/cg-x-in");
PropertyManager->Untie("inertia/cg-y-in");
PropertyManager->Untie("inertia/cg-z-in");
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -335,7 +335,7 @@ void FGMassBalance::Debug(int from)
cout << " EmptyWeight: " << EmptyWeight << " lbm" << endl;
cout << " CG (x, y, z): " << vbaseXYZcg << endl;
// ToDo: Need to add point mass outputs here
for (int i=0; i<PointMasses.size(); i++) {
for (unsigned int i=0; i<PointMasses.size(); i++) {
cout << " Point Mass Object: " << PointMasses[i].Weight << " lbs. at "
<< "X, Y, Z (in.): " << PointMasses[i].Location(eX) << " "
<< PointMasses[i].Location(eY) << " "

View file

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

View file

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

View file

@ -98,6 +98,18 @@ FGPropagate::FGPropagate(FGFDMExec* fdmex) : FGModel(fdmex)
Name = "FGPropagate";
// vQtrndot.zero();
last2_vPQRdot.InitMatrix();
last_vPQRdot.InitMatrix();
vPQRdot.InitMatrix();
last2_vUVWdot.InitMatrix();
last_vUVWdot.InitMatrix();
vUVWdot.InitMatrix();
last2_vLocationDot.InitMatrix();
last_vLocationDot.InitMatrix();
vLocationDot.InitMatrix();
bind();
Debug(0);
}

View file

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

View file

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

View file

@ -0,0 +1,256 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Module: FGActuator.cpp
Author: Jon Berndt
Date started: 21 February 2006
------------- Copyright (C) 2007 Jon S. Berndt (jsb@hal-pc.org) -------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU Lesser General Public License can also be found on
the world wide web at http://www.gnu.org.
FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------
HISTORY
--------------------------------------------------------------------------------
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
COMMENTS, REFERENCES, and NOTES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGActuator.h"
namespace JSBSim {
static const char *IdSrc = "$Id$";
static const char *IdHdr = ID_ACTUATOR;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
FGActuator::FGActuator(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
{
double denom;
dt = fcs->GetDt();
// inputs are read from the base class constructor
PreviousOutput = 0.0;
PreviousHystOutput = 0.0;
PreviousRateLimOutput = 0.0;
PreviousLagInput = PreviousLagOutput = 0.0;
bias = lag = hysteresis_width = deadband_width = 0.0;
rate_limit = 0.0; // no limit
fail_zero = fail_hardover = fail_stuck = false;
ca = cb = 0.0;
if ( element->FindElement("deadband_width") ) {
deadband_width = element->FindElementValueAsNumber("deadband_width");
}
if ( element->FindElement("hysteresis_width") ) {
hysteresis_width = element->FindElementValueAsNumber("hysteresis_width");
}
if ( element->FindElement("rate_limit") ) {
rate_limit = element->FindElementValueAsNumber("rate_limit");
}
if ( element->FindElement("bias") ) {
bias = element->FindElementValueAsNumber("bias");
}
if ( element->FindElement("lag") ) {
lag = element->FindElementValueAsNumber("lag");
denom = 2.00 + dt*lag;
ca = dt*lag / denom;
cb = (2.00 - dt*lag) / denom;
}
FGFCSComponent::bind();
bind();
Debug(0);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGActuator::~FGActuator()
{
Debug(1);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGActuator::Run(void )
{
dt = fcs->GetDt();
Input = InputNodes[0]->getDoubleValue() * InputSigns[0];
Output = Input; // perfect actuator
if (fail_zero) Input = 0;
if (fail_hardover) Input = clipmax*fabs(Input)/Input;
if (lag != 0.0) Lag(); // models actuator lag
if (rate_limit != 0) RateLimit(); // limit the actuator rate
if (deadband_width != 0.0) Deadband();
if (hysteresis_width != 0.0) Hysteresis();
if (bias != 0.0) Bias(); // models a finite bias
if (fail_stuck) Output = PreviousOutput;
PreviousOutput = Output; // previous value needed for "stuck" malfunction
Clip();
if (IsOutput) SetOutput();
return true;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGActuator::Bias(void)
{
Output += bias;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGActuator::Lag(void)
{
// "Output" on the right side of the "=" is the current frame input
// for this Lag filter
double input = Output;
Output = ca * (input + PreviousLagInput) + PreviousLagOutput * cb;
PreviousLagInput = input;
PreviousLagOutput = Output;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGActuator::Hysteresis(void)
{
// Note: this function acts cumulatively on the "Output" parameter. So, "Output"
// is - for the purposes of this Hysteresis method - really the input to the
// method.
double input = Output;
if (input > PreviousHystOutput) {
Output = max(PreviousHystOutput, input-0.5*hysteresis_width);
} else if (input < PreviousHystOutput) {
Output = min(PreviousHystOutput, input+0.5*hysteresis_width);
}
PreviousHystOutput = Output;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGActuator::RateLimit(void)
{
// Note: this function acts cumulatively on the "Output" parameter. So, "Output"
// is - for the purposes of this RateLimit method - really the input to the
// method.
double input = Output;
if (dt > 0.0) {
double rate = (input - PreviousRateLimOutput)/dt;
if (fabs(rate) > rate_limit) {
Output = PreviousRateLimOutput + (rate_limit*fabs(rate)/rate)*dt;
}
}
PreviousRateLimOutput = Output;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGActuator::Deadband(void)
{
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGActuator::bind(void)
{
string tmp = "fcs/" + PropertyManager->mkPropertyName(Name, true);
const string tmp_zero = tmp + "/malfunction/fail_zero";
const string tmp_hardover = tmp + "/malfunction/fail_hardover";
const string tmp_stuck = tmp + "/malfunction/fail_stuck";
PropertyManager->Tie( tmp_zero, this, &FGActuator::GetFailZero, &FGActuator::SetFailZero);
PropertyManager->Tie( tmp_hardover, this, &FGActuator::GetFailHardover, &FGActuator::SetFailHardover);
PropertyManager->Tie( tmp_stuck, this, &FGActuator::GetFailStuck, &FGActuator::SetFailStuck);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
// out the normally expected messages, essentially echoing
// the config files as they are read. If the environment
// variable is not set, debug_lvl is set to 1 internally
// 0: This requests JSBSim not to output any messages
// whatsoever.
// 1: This value explicity requests the normal JSBSim
// startup messages
// 2: This value asks for a message to be printed out when
// a class is instantiated
// 4: When this value is set, a message is displayed when a
// FGModel object executes its Run() method
// 8: When this value is set, various runtime state variables
// are printed out periodically
// 16: When set various parameters are sanity checked and
// a message is printed out when they go out of bounds
void FGActuator::Debug(int from)
{
if (debug_lvl <= 0) return;
if (debug_lvl & 1) { // Standard console startup message output
if (from == 0) { // Constructor
if (InputSigns[0] < 0)
cout << " INPUT: -" << InputNodes[0]->getName() << endl;
else
cout << " INPUT: " << InputNodes[0]->getName() << endl;
if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
if (bias != 0.0) cout << " Bias: " << bias << endl;
if (rate_limit != 0) cout << " Rate limit: " << rate_limit << endl;
if (lag != 0) cout << " Actuator lag: " << lag << endl;
if (hysteresis_width != 0) cout << " Hysteresis width: " << hysteresis_width << endl;
if (deadband_width != 0) cout << " Deadband width: " << deadband_width << endl;
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
if (from == 0) cout << "Instantiated: FGActuator" << endl;
if (from == 1) cout << "Destroyed: FGActuator" << endl;
}
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
}
if (debug_lvl & 8 ) { // Runtime state variables
}
if (debug_lvl & 16) { // Sanity checking
}
if (debug_lvl & 64) {
if (from == 0) { // Constructor
cout << IdSrc << endl;
cout << IdHdr << endl;
}
}
}
}

View file

@ -0,0 +1,176 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Header: FGActuator.h
Author: Jon Berndt
Date started: 21 February 2007
------------- Copyright (C) 2006 Jon S. Berndt (jsb@hal-pc.org) -------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
details.
You should have received a copy of the GNU Lesser General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU Lesser General Public License can also be found on
the world wide web at http://www.gnu.org.
HISTORY
--------------------------------------------------------------------------------
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifndef FGACTUATOR_H
#define FGACTUATOR_H
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGFCSComponent.h"
#include <input_output/FGXMLElement.h>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_ACTUATOR "$Id$"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
namespace JSBSim {
class FGFCS;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Encapsulates an Actuator component for the flight control system.
The actuator can be modeled as a "perfect actuator", with the Output
being set directly to the input. The actuator can be made more "real"
by specifying any/all of the following additional effects that can be
applied to the actuator. In order of application to the input signal,
these are:
-System lag (input lag, really)
-Rate limiting
-Deadband
-Hysteresis (mechanical hysteresis)
-Bias (mechanical bias)
-Position limiting ("hard stops")
There are also several malfunctions that can be applied to the actuator
by setting a property to true or false (or 1 or 0).
Syntax:
@code
<actuator name=name>
<input> {[-]property} </input>
<lag> number </lag>
<rate_limit> number <rate_limit>
<bias> number </bias>
<deadband_width> number </deadband_width>
<hysteresis_width> number </hysteresis_width>
[<clipto>
<min> {property name | value} </min>
<max> {property name | value} </max>
</clipto>]
[<output> {property} </output>]
</actuator>
@endcode
Example:
@code
<actuator name=fcs/gimbal_pitch_position>
<input> fcs/gimbal_pitch_command </input>
<lag> 60 </lag>
<rate_limit> 0.085 <rate_limit> <!-- 5 degrees/sec -->
<bias> 0.002 </bias>
<deadband_width> 0.002 </deadband_width>
<hysteresis_width> 0.05 </hysteresis_width>
<clipto> <!-- +/- 10 degrees -->
<min> -0.17 </min>
<max> 0.17 </max>
</clipto>
</actuator>
@endcode
@author Jon S. Berndt
@version $Revision$
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGActuator : public FGFCSComponent
{
public:
/// Constructor
FGActuator(FGFCS* fcs, Element* element);
/// Destructor
~FGActuator();
/** This function processes the input.
It calls private functions if needed to perform the hysteresis, lag,
limiting, etc. functions. */
bool Run (void);
// these may need to have the bool argument replaced with a double
/** This function fails the actuator to zero. The motion to zero
will flow through the lag, hysteresis, and rate limiting
functions if those are activated. */
inline void SetFailZero(bool set) {fail_zero = set;}
inline void SetFailHardover(bool set) {fail_hardover = set;}
inline void SetFailStuck(bool set) {fail_stuck = set;}
inline bool GetFailZero(void) const {return fail_zero;}
inline bool GetFailHardover(void) const {return fail_hardover;}
inline bool GetFailStuck(void) const {return fail_stuck;}
private:
double dt;
double span;
double bias;
double rate_limit;
double hysteresis_width;
double deadband_width;
double lag;
double ca; // lag filter coefficient "a"
double cb; // lag filter coefficient "b"
double PreviousOutput;
double PreviousHystOutput;
double PreviousRateLimOutput;
double PreviousLagInput;
double PreviousLagOutput;
bool fail_zero;
bool fail_hardover;
bool fail_stuck;
void Hysteresis(void);
void Lag(void);
void RateLimit(void);
void Deadband(void);
void Bias(void);
void bind(void);
void Debug(int from);
};
}
#endif

View file

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

View file

@ -54,7 +54,12 @@ FGFCSFunction::FGFCSFunction(FGFCS* fcs, Element* element) : FGFCSComponent(fcs,
{
Element *function_element = element->FindElement("function");
if (function_element)
function = new FGFunction(PropertyManager, function_element);
else {
cerr << "FCS Function should contain a \"function\" element" << endl;
exit(-1);
}
FGFCSComponent::bind();
Debug(0);

View file

@ -81,14 +81,19 @@ bool FGPID::Run(void )
Input = InputNodes[0]->getDoubleValue() * InputSigns[0];
P_out = Kp * (Input - Input_prev);
I_out = Ki * dt * Input;
D_out = (Kd / dt) * (Input - 2*Input_prev + Input_prev2);
// Do not continue to integrate the input to the integrator if a wind-up
// condition is sensed - that is, if the property pointed to by the trigger
// element is non-zero.
if (Trigger != 0) {
double test = Trigger->getDoubleValue();
if (fabs(test) > 0.000001) {
I_out = 0.0;
if (fabs(test) < 0.000001) {
I_out = Ki * dt * Input;
}
} else { // no anti-wind-up trigger defined
I_out = Ki * dt * Input;
}
Input_prev = Input;

View file

@ -52,12 +52,10 @@ CLASS IMPLEMENTATION
FGSensor::FGSensor(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
{
double denom;
dt = fcs->GetState()->Getdt();
dt = fcs->GetDt();
// inputs are read from the base class constructor
dt = fcs->GetState()->Getdt();
bits = quantized = divisions = 0;
PreviousInput = PreviousOutput = 0.0;
min = max = bias = noise_variance = lag = drift_rate = drift = span = 0.0;
@ -77,6 +75,7 @@ FGSensor::FGSensor(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
if ( quantization_element->FindElement("max") ) {
max = quantization_element->FindElementValueAsNumber("max");
}
quant_property = quantization_element->GetAttributeValue("name");
span = max - min;
granularity = span/divisions;
}
@ -214,6 +213,14 @@ void FGSensor::bind(void)
PropertyManager->Tie( tmp_low, this, &FGSensor::GetFailLow, &FGSensor::SetFailLow);
PropertyManager->Tie( tmp_high, this, &FGSensor::GetFailHigh, &FGSensor::SetFailHigh);
PropertyManager->Tie( tmp_stuck, this, &FGSensor::GetFailStuck, &FGSensor::SetFailStuck);
if (!quant_property.empty()) {
if (quant_property.find("/") == string::npos) { // not found
string qprop = "fcs/" + PropertyManager->mkPropertyName(quant_property, true);
PropertyManager->Tie(qprop, this, &FGSensor::GetQuantized);
}
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -241,7 +248,35 @@ void FGSensor::Debug(int from)
if (debug_lvl & 1) { // Standard console startup message output
if (from == 0) { // Constructor
if (InputSigns[0] < 0)
cout << " INPUT: -" << InputNodes[0]->getName() << endl;
else
cout << " INPUT: " << InputNodes[0]->getName() << endl;
if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
if (bits != 0) {
if (quant_property.empty())
cout << " Quantized output" << endl;
else
cout << " Quantized output (property: " << quant_property << ")" << endl;
cout << " Bits: " << bits << endl;
cout << " Min value: " << min << endl;
cout << " Max value: " << max << endl;
cout << " (span: " << span << ", granularity: " << granularity << ")" << endl;
}
if (bias != 0.0) cout << " Bias: " << bias << endl;
if (drift_rate != 0) cout << " Sensor drift rate: " << drift_rate << endl;
if (lag != 0) cout << " Sensor lag: " << lag << endl;
if (noise_variance != 0) {
if (NoiseType == eAbsolute) {
cout << " Noise variance (absolute): " << noise_variance << endl;
} else if (NoiseType == ePercent) {
cout << " Noise variance (percent): " << noise_variance << endl;
} else {
cout << " Noise variance type is invalid" << endl;
}
}
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -61,7 +61,6 @@ FGForce::FGForce(FGFDMExec *FDMExec) :
mT(1,1) = 1; //identity matrix
mT(2,2) = 1;
mT(3,3) = 1;
vSense.InitMatrix(1);
Debug(0);
}
@ -77,7 +76,7 @@ FGForce::~FGForce()
FGColumnVector3& FGForce::GetBodyForces(void)
{
vFb = Transform()*(vFn.multElementWise(vSense));
vFb = Transform()*vFn;
// Find the distance from this vector's acting location to the cg; this
// needs to be done like this to convert from structural to body coords.
@ -110,21 +109,17 @@ FGMatrix33 FGForce::Transform(void)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGForce::SetAnglesToBody(double broll, double bpitch, double byaw)
void FGForce::UpdateCustomTransformMatrix(void)
{
if (ttype == tCustom) {
double cp,sp,cr,sr,cy,sy;
vOrient(ePitch) = bpitch;
vOrient(eRoll) = broll;
vOrient(eYaw) = byaw;
cp=cos(bpitch); sp=sin(bpitch);
cr=cos(broll); sr=sin(broll);
cy=cos(byaw); sy=sin(byaw);
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)=-1*sp;
mT(1,3) = -sp;
mT(2,1) = sr*sp*cy - cr*sy;
mT(2,2) = sr*sp*sy + cr*cy;
@ -133,6 +128,19 @@ void FGForce::SetAnglesToBody(double broll, double bpitch, double byaw)
mT(3,1) = cr*sp*cy + sr*sy;
mT(3,2) = cr*sp*sy - sr*cy;
mT(3,3) = cr*cp;
mT = mT.Inverse();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGForce::SetAnglesToBody(double broll, double bpitch, double byaw)
{
if (ttype == tCustom) {
vOrient(ePitch) = bpitch;
vOrient(eRoll) = broll;
vOrient(eYaw) = byaw;
UpdateCustomTransformMatrix();
}
}

View file

@ -151,7 +151,7 @@ can now be retrieved by calling:</p>
<p>This method is where the bulk of the work gets done so calling it more than
once for the same set of native forces and moments should probably be avoided.
Note that the moment calculations are done here as well so they should not be
Note that the moment calculations are done here as well so they should be
retrieved after calling the GetBodyForces() method:</p>
<p><tt>vM=fgf.GetMoments();</tt> </p>
@ -230,24 +230,7 @@ public:
/// Destructor
~FGForce();
enum TransformType { tNone, tWindBody, tLocalBody, tCustom } ttype;
inline void SetNativeForces(double Fnx, double Fny, double Fnz) {
vFn(1)=Fnx;
vFn(2)=Fny;
vFn(3)=Fnz;
}
inline void SetNativeForces(FGColumnVector3 vv) { vFn = vv; };
inline void SetNativeMoments(double Ln,double Mn, double Nn) {
vMn(1)=Ln;
vMn(2)=Mn;
vMn(3)=Nn;
}
inline void SetNativeMoments(FGColumnVector3 vv) { vMn = vv; }
inline FGColumnVector3& GetNativeForces(void) { return vFn; }
inline FGColumnVector3& GetNativeMoments(void) { return vMn; }
enum TransformType { tNone, tWindBody, tLocalBody, tCustom };
FGColumnVector3& GetBodyForces(void);
@ -305,18 +288,15 @@ public:
SetAnglesToBody(vv(eRoll), vv(ePitch), vv(eYaw));
}
void SetPitch(double pitch) {vOrient(ePitch) = pitch;}
void SetYaw(double yaw) {vOrient(eYaw) = yaw;}
void UpdateCustomTransformMatrix(void);
void SetPitch(double pitch) {vOrient(ePitch) = pitch; UpdateCustomTransformMatrix();}
void SetYaw(double yaw) {vOrient(eYaw) = yaw; UpdateCustomTransformMatrix();}
double GetPitch(void) const {return vOrient(ePitch);}
double GetYaw(void) const {return vOrient(eYaw);}
inline void SetSense(double x, double y, double z) { vSense(eX)=x, vSense(eY)=y, vSense(eZ)=z; }
inline void SetSense(FGColumnVector3 vv) { vSense=vv; }
inline FGColumnVector3& GetAnglesToBody(void) {return vOrient;}
inline double GetAnglesToBody(int axis) {return vOrient(axis);}
inline FGColumnVector3& GetSense(void) { return vSense; }
inline void SetTransformType(TransformType ii) { ttype=ii; }
inline TransformType GetTransformType(void) { return ttype; }
@ -329,14 +309,14 @@ protected:
FGColumnVector3 vMn;
FGColumnVector3 vH;
FGColumnVector3 vOrient;
TransformType ttype;
FGColumnVector3 vXYZn;
FGColumnVector3 vActingXYZn;
private:
FGColumnVector3 vFb;
FGColumnVector3 vM;
FGColumnVector3 vXYZn;
FGColumnVector3 vActingXYZn;
FGColumnVector3 vDXYZ;
FGColumnVector3 vSense;
FGMatrix33 mT;

View file

@ -99,7 +99,11 @@ FGNozzle::~FGNozzle()
double FGNozzle::Calculate(double CfPc)
{
double pAtm = fdmex->GetAtmosphere()->GetPressure();
if (CfPc > 0)
Thrust = max((double)0.0, (CfPc * AreaT + (PE - pAtm)*Area2) * nzlEff);
else
Thrust = 0.0;
vFn(1) = Thrust * cos(ReverserAngle);
ThrustCoeff = max((double)0.0, CfPc / ((pAtm - PE) * Area2));
@ -120,7 +124,7 @@ string FGNozzle::GetThrusterLabels(int id, string delimeter)
{
std::ostringstream buf;
buf << Name << "_Thrust[" << id << ']';
buf << Name << " Thrust (engine " << id << " in lbs)";
return buf.str();
}

View file

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

View file

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

View file

@ -54,6 +54,15 @@ CLASS IMPLEMENTATION
FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number)
: FGEngine(exec, el, engine_number)
{
Element* thrust_table_element = 0;
ThrustTable = 0L;
BurnTime = 0.0;
// Defaults
Variance = 0.0;
MinThrottle = 0.0;
MaxThrottle = 1.0;
if (el->FindElement("shr"))
SHR = el->FindElementValueAsNumber("shr");
if (el->FindElement("max_pc"))
@ -71,6 +80,11 @@ FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number)
if (el->FindElement("variance"))
Variance = el->FindElementValueAsNumber("variance");
thrust_table_element = el->FindElement("thrust_table");
if (thrust_table_element) {
ThrustTable = new FGTable(PropertyManager, thrust_table_element);
}
Debug(0);
Type = etRocket;
@ -97,6 +111,18 @@ double FGRocket::Calculate(void)
Throttle = FCS->GetThrottlePos(EngineNumber);
// If there is a thrust table, it is a function of elapsed burn time. The engine
// is started when the throttle is advanced to 1.0. After that, it burns
// without regard to throttle setting. The table returns a value between zero
// and one, representing the percentage of maximum vacuum thrust being applied.
if (ThrustTable != 0L) {
if (Throttle == 1 || BurnTime > 0.0) {
BurnTime += State->Getdt();
}
Throttle = ThrustTable->GetValue(BurnTime);
}
if (Throttle < MinThrottle || Starved) {
PctPower = Thrust = 0.0; // desired thrust
Flameout = true;
@ -122,7 +148,7 @@ string FGRocket::GetEngineLabels(string delimeter)
{
std::ostringstream buf;
buf << Name << "_ChamberPress[" << EngineNumber << "]" << delimeter
buf << Name << " Chamber Pressure (engine " << EngineNumber << " in psf)" << delimeter
<< Thruster->GetThrusterLabels(EngineNumber, delimeter);
return buf.str();

View file

@ -39,6 +39,7 @@ INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGEngine.h"
#include <math/FGTable.h>
#include <input_output/FGXMLElement.h>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -84,6 +85,45 @@ CLASS DOCUMENTATION
to the nozzle Calculate() routine, where the thrust force is
determined.
One can model the thrust of a solid rocket by providing a normalized thrust table
as a function of time. For instance, the space shuttle solid rocket booster
normalized thrust value looks roughly like this:
<pre>
<thrust_table name="propulsion/thrust_time" type="internal">
<tableData>
0.0 0.00
0.2 0.91
8.0 0.97
16.0 0.99
20.0 1.00
21.0 1.00
24.0 0.95
32.0 0.85
40.0 0.78
48.0 0.72
50.0 0.71
52.0 0.71
56.0 0.73
64.0 0.78
72.0 0.82
80.0 0.81
88.0 0.73
96.0 0.69
104.0 0.59
112.0 0.46
120.0 0.09
132.0 0.00
</tableData>
</thrust_table>
</pre>
The left column is time, the right column is normalized thrust. Inside the
FGRocket class code, the maximum thrust is calculated, and multiplied by this
table. The Rocket class also tracks burn time. All that needs to be done is
for the rocket engine to be throttle up to 1. At that time, the solid rocket
fuel begins burning and thrust is provided.
@author Jon S. Berndt
$Id$
@see FGNozzle,
@ -133,7 +173,9 @@ private:
double kFactor;
double Variance;
double PC;
double BurnTime;
bool Flameout;
FGTable* ThrustTable;
void Debug(int from);
};

View file

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

View file

@ -278,7 +278,7 @@ double FGTurboProp::Off(void)
double FGTurboProp::Run(void)
{
double idlethrust, milthrust, thrust = 0.0, EngPower_HP, eff_coef;
double thrust = 0.0, EngPower_HP, eff_coef;
Running = true; Starter = false; EngStarting = false;
//---