From 3cda82e0a9b3ff5eb6d21408328c5f864be31e0d Mon Sep 17 00:00:00 2001 From: mfranz Date: Sun, 3 Jun 2007 09:37:02 +0000 Subject: [PATCH] Sync w. JSBSim CVS (merge from PRE_OSG_PLIB_20061029 branch) --- src/FDM/JSBSim/FGFDMExec.cpp | 28 +- src/FDM/JSBSim/FGFDMExec.h | 5 +- src/FDM/JSBSim/FGJSBBase.cpp | 76 +++--- src/FDM/JSBSim/FGJSBBase.h | 21 +- src/FDM/JSBSim/FGState.cpp | 84 ------ src/FDM/JSBSim/JSBSim.cxx | 6 +- .../initialization/FGInitialCondition.cpp | 16 +- .../initialization/FGInitialCondition.h | 3 +- .../JSBSim/input_output/FGPropertyManager.cpp | 24 +- .../JSBSim/input_output/FGPropertyManager.h | 5 + src/FDM/JSBSim/input_output/FGScript.cpp | 35 ++- src/FDM/JSBSim/input_output/FGScript.h | 6 +- src/FDM/JSBSim/input_output/FGXMLElement.cpp | 103 ++++--- src/FDM/JSBSim/input_output/Makefile.am | 2 +- src/FDM/JSBSim/math/FGColumnVector3.cpp | 7 - src/FDM/JSBSim/math/FGColumnVector3.h | 3 - src/FDM/JSBSim/math/FGFunction.cpp | 27 +- src/FDM/JSBSim/math/FGTable.cpp | 78 +++--- src/FDM/JSBSim/math/FGTable.h | 4 +- src/FDM/JSBSim/math/Makefile.am | 2 +- src/FDM/JSBSim/models/FGAerodynamics.cpp | 3 - src/FDM/JSBSim/models/FGAircraft.cpp | 19 +- src/FDM/JSBSim/models/FGAircraft.h | 3 + src/FDM/JSBSim/models/FGAuxiliary.cpp | 23 +- src/FDM/JSBSim/models/FGFCS.cpp | 32 ++- src/FDM/JSBSim/models/FGFCS.h | 6 +- src/FDM/JSBSim/models/FGGroundReactions.cpp | 18 +- src/FDM/JSBSim/models/FGInput.cpp | 2 +- src/FDM/JSBSim/models/FGLGear.cpp | 15 +- src/FDM/JSBSim/models/FGLGear.h | 2 + src/FDM/JSBSim/models/FGMassBalance.cpp | 24 +- src/FDM/JSBSim/models/FGOutput.cpp | 59 ++-- src/FDM/JSBSim/models/FGOutput.h | 4 +- src/FDM/JSBSim/models/FGPropagate.cpp | 12 + src/FDM/JSBSim/models/FGPropulsion.cpp | 11 +- src/FDM/JSBSim/models/FGPropulsion.h | 4 +- .../models/flight_control/FGActuator.cpp | 256 ++++++++++++++++++ .../JSBSim/models/flight_control/FGActuator.h | 176 ++++++++++++ .../models/flight_control/FGFCSComponent.cpp | 2 + .../models/flight_control/FGFCSFunction.cpp | 7 +- .../JSBSim/models/flight_control/FGPID.cpp | 11 +- .../JSBSim/models/flight_control/FGSensor.cpp | 43 ++- .../JSBSim/models/flight_control/FGSensor.h | 6 +- .../JSBSim/models/flight_control/FGSwitch.cpp | 2 +- .../JSBSim/models/flight_control/Makefile.am | 5 +- src/FDM/JSBSim/models/propulsion/FGEngine.cpp | 12 +- src/FDM/JSBSim/models/propulsion/FGEngine.h | 3 +- src/FDM/JSBSim/models/propulsion/FGForce.cpp | 44 +-- src/FDM/JSBSim/models/propulsion/FGForce.h | 36 +-- src/FDM/JSBSim/models/propulsion/FGNozzle.cpp | 10 +- src/FDM/JSBSim/models/propulsion/FGPiston.cpp | 14 +- .../JSBSim/models/propulsion/FGPropeller.cpp | 13 +- src/FDM/JSBSim/models/propulsion/FGRocket.cpp | 28 +- src/FDM/JSBSim/models/propulsion/FGRocket.h | 42 +++ .../JSBSim/models/propulsion/FGThruster.cpp | 6 +- .../JSBSim/models/propulsion/FGTurboProp.cpp | 2 +- 56 files changed, 986 insertions(+), 504 deletions(-) create mode 100755 src/FDM/JSBSim/models/flight_control/FGActuator.cpp create mode 100755 src/FDM/JSBSim/models/flight_control/FGActuator.h diff --git a/src/FDM/JSBSim/FGFDMExec.cpp b/src/FDM/JSBSim/FGFDMExec.cpp index 890342316..94088579a 100644 --- a/src/FDM/JSBSim/FGFDMExec.cpp +++ b/src/FDM/JSBSim/FGFDMExec.cpp @@ -134,6 +134,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root) modelLoaded = false; IsSlave = false; holding = false; + Terminate = false; // Multiple FDM's are stopped for now. We need to ensure that // the "user" instance always gets the zeroeth instance number, @@ -168,6 +169,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root) Constructing = true; typedef int (FGFDMExec::*iPMF)(void) const; instance->Tie("simulation/do_trim", this, (iPMF)0, &FGFDMExec::DoTrim); + instance->Tie("simulation/terminate", (int *)&Terminate); Constructing = false; } @@ -176,6 +178,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root) FGFDMExec::~FGFDMExec() { instance->Untie("simulation/do_trim"); + instance->Untie("simulation/terminate"); try { DeAllocate(); @@ -354,7 +357,7 @@ int FGFDMExec::Schedule(FGModel* model, int rate) bool FGFDMExec::Run(void) { - bool success = false; + bool success=false; FGModel* model_iterator; model_iterator = FirstModel; @@ -376,6 +379,7 @@ bool FGFDMExec::Run(void) Frame++; if (!Holding()) State->IncrTime(); + if (Terminate) success = false; return (success); } @@ -459,6 +463,9 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) string token; string aircraftCfgFileName; string separator = "/"; + Element* element = 0L; + + modelName = model; // Set the class modelName attribute # ifdef macintosh separator = ";"; @@ -474,27 +481,12 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath) if (addModelToPath) FullAircraftPath += separator + model; aircraftCfgFileName = FullAircraftPath + separator + model + ".xml"; - FGXMLParse *XMLParse = new FGXMLParse(); - Element* element = 0L; - Element* document; - - ifstream input_file(aircraftCfgFileName.c_str()); - - if (!input_file.is_open()) { // file open failed - cerr << "Could not open file " << aircraftCfgFileName.c_str() << endl; - return false; - } - - readXML(input_file, *XMLParse); - document = XMLParse->GetDocument(); - - modelName = model; - if (modelLoaded) { DeAllocate(); Allocate(); } + document = LoadXMLDocument(aircraftCfgFileName); // "document" is a class member ReadPrologue(document); element = document->GetElement(); @@ -553,7 +545,7 @@ void FGFDMExec::BuildPropertyCatalog(struct PropertyCatalogStructure* pcs) int node_idx = 0; char int_buf[10]; - for (int i=0; inode->nChildren(); i++) { + for (unsigned int i=0; inode->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); diff --git a/src/FDM/JSBSim/FGFDMExec.h b/src/FDM/JSBSim/FGFDMExec.h index 6ae678cfd..b286fab9c 100644 --- a/src/FDM/JSBSim/FGFDMExec.h +++ b/src/FDM/JSBSim/FGFDMExec.h @@ -48,8 +48,8 @@ INCLUDES #include #include #include -#include #include +#include #include #include @@ -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; diff --git a/src/FDM/JSBSim/FGJSBBase.cpp b/src/FDM/JSBSim/FGJSBBase.cpp index a9912cb69..259220dbb 100644 --- a/src/FDM/JSBSim/FGJSBBase.cpp +++ b/src/FDM/JSBSim/FGJSBBase.cpp @@ -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::Messages; +std::queue 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; } diff --git a/src/FDM/JSBSim/FGJSBBase.h b/src/FDM/JSBSim/FGJSBBase.h index 6147248e6..2dd363738 100644 --- a/src/FDM/JSBSim/FGJSBBase.h +++ b/src/FDM/JSBSim/FGJSBBase.h @@ -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 Messages; + static std::queue Messages; void Debug(int from) {}; diff --git a/src/FDM/JSBSim/FGState.cpp b/src/FDM/JSBSim/FGState.cpp index 8945abdd4..29c174132 100644 --- a/src/FDM/JSBSim/FGState.cpp +++ b/src/FDM/JSBSim/FGState.cpp @@ -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); diff --git a/src/FDM/JSBSim/JSBSim.cxx b/src/FDM/JSBSim/JSBSim.cxx index e8e489846..2b59f3240 100644 --- a/src/FDM/JSBSim/JSBSim.cxx +++ b/src/FDM/JSBSim/JSBSim.cxx @@ -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; diff --git a/src/FDM/JSBSim/initialization/FGInitialCondition.cpp b/src/FDM/JSBSim/initialization/FGInitialCondition.cpp index 9ee9d094e..7c2dc3dfc 100644 --- a/src/FDM/JSBSim/initialization/FGInitialCondition.cpp +++ b/src/FDM/JSBSim/initialization/FGInitialCondition.cpp @@ -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; iGetNumEngines(); i++) { + for(unsigned int i=0; iGetNumEngines(); i++) { propulsion->GetEngine(i)->SetRunning(true); } } diff --git a/src/FDM/JSBSim/initialization/FGInitialCondition.h b/src/FDM/JSBSim/initialization/FGInitialCondition.h index 077f001f7..105297c1a 100644 --- a/src/FDM/JSBSim/initialization/FGInitialCondition.h +++ b/src/FDM/JSBSim/initialization/FGInitialCondition.h @@ -50,6 +50,7 @@ INCLUDES #include #include #include +#include /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% DEFINITIONS @@ -199,7 +200,7 @@ CLASS DOCUMENTATION CLASS DECLARATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ -class FGInitialCondition : public FGJSBBase +class FGInitialCondition : public FGJSBBase, public FGXMLFileRead { public: /// Constructor diff --git a/src/FDM/JSBSim/input_output/FGPropertyManager.cpp b/src/FDM/JSBSim/input_output/FGPropertyManager.cpp index f8b857368..1f6f6d2e2 100755 --- a/src/FDM/JSBSim/input_output/FGPropertyManager.cpp +++ b/src/FDM/JSBSim/input_output/FGPropertyManager.cpp @@ -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 stack; stack.push_back( getDisplayName(true) ); diff --git a/src/FDM/JSBSim/input_output/FGPropertyManager.h b/src/FDM/JSBSim/input_output/FGPropertyManager.h index ce7161524..3c5032226 100644 --- a/src/FDM/JSBSim/input_output/FGPropertyManager.h +++ b/src/FDM/JSBSim/input_output/FGPropertyManager.h @@ -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. diff --git a/src/FDM/JSBSim/input_output/FGScript.cpp b/src/FDM/JSBSim/input_output/FGScript.cpp index 797a5bf49..7e542fbe9 100755 --- a/src/FDM/JSBSim/input_output/FGScript.cpp +++ b/src/FDM/JSBSim/input_output/FGScript.cpp @@ -84,7 +84,7 @@ FGScript::FGScript(FGFDMExec* fgex) : FDMExec(fgex) FGScript::~FGScript() { - int i; + unsigned int i; for (i=0; iUntie(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; jNotifyProperties.size();j++) { - cout << " " << iEvent->NotifyProperties[j]->GetName() - << " = " << iEvent->NotifyProperties[j]->getDoubleValue() << endl; - } - cout << endl; - } - for (i=0; iSetValue.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; jNotifyProperties.size();j++) { + cout << " " << iEvent->NotifyProperties[j]->GetName() + << " = " << iEvent->NotifyProperties[j]->getDoubleValue() << endl; + } + cout << endl; + iEvent->Notified = true; + } + } iEvent++; diff --git a/src/FDM/JSBSim/input_output/FGScript.h b/src/FDM/JSBSim/input_output/FGScript.h index 903057a1d..491540475 100644 --- a/src/FDM/JSBSim/input_output/FGScript.h +++ b/src/FDM/JSBSim/input_output/FGScript.h @@ -42,6 +42,7 @@ INCLUDES #include "FGFDMExec.h" #include #include +#include /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 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; diff --git a/src/FDM/JSBSim/input_output/FGXMLElement.cpp b/src/FDM/JSBSim/input_output/FGXMLElement.cpp index 64d2a38ed..741a80609 100755 --- a/src/FDM/JSBSim/input_output/FGXMLElement.cpp +++ b/src/FDM/JSBSim/input_output/FGXMLElement.cpp @@ -292,31 +292,32 @@ string Element::FindElementValue(string el) double Element::FindElementValueAsNumberConvertTo(string el, string target_units) { Element* element = FindElement(el); - double value; - string supplied_units=""; - if (element) { - value = element->GetDataAsNumber(); - supplied_units = element->GetAttributeValue("unit"); - if (!supplied_units.empty()) { - if (convert.find(supplied_units) != convert.end()) { - if (convert[supplied_units].find(target_units) != convert[supplied_units].end()) { - value *= convert[supplied_units][target_units]; - } else { - cerr << endl << "Target unit: \"" << target_units << "\" does not exist (typo?). Add new unit" - << " conversion in FGXMLElement.cpp." << endl; - exit(-1); - } - } else { - cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit" - << " conversion in FGXMLElement.cpp." << endl; - exit(-1); - } - } - } else { - cerr << "Attempting to get get non-existent element " << el << endl; - return 0; + if (!element) { + cerr << "Attempting to get non-existent element " << el << endl; + exit(0); + } + + string supplied_units = element->GetAttributeValue("unit"); + + if (!supplied_units.empty()) { + if (convert.find(supplied_units) == convert.end()) { + cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit" + << " conversion in FGXMLElement.cpp." << endl; + exit(-1); + } + if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) { + cerr << endl << "Supplied unit: \"" << supplied_units << "\" cannot be converted to " + << target_units << ". Add new unit conversion in FGXMLElement.cpp or fix typo" << endl; + exit(-1); + } + } + + double value = element->GetDataAsNumber(); + if (!supplied_units.empty()) { + value *= convert[supplied_units][target_units]; } + return value; } @@ -327,29 +328,30 @@ double Element::FindElementValueAsNumberConvertFromTo( string el, string target_units) { Element* element = FindElement(el); - double value; + + if (!element) { + cerr << "Attempting to get non-existent element " << el << endl; + exit(0); + } + + if (!supplied_units.empty()) { + if (convert.find(supplied_units) == convert.end()) { + cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit" + << " conversion in FGXMLElement.cpp." << endl; + exit(-1); + } + if (convert[supplied_units].find(target_units) == convert[supplied_units].end()) { + cerr << endl << "Supplied unit: \"" << supplied_units << "\" cannot be converted to " + << target_units << ". Add new unit conversion in FGXMLElement.cpp or fix typo" << endl; + exit(-1); + } + } - if (element) { - value = element->GetDataAsNumber(); - if (!supplied_units.empty()) { - if (convert.find(supplied_units) != convert.end()) { - if (convert[supplied_units].find(target_units) != convert[supplied_units].end()) { - value *= convert[supplied_units][target_units]; - } else { - cerr << endl << "Target unit: \"" << target_units << "\" does not exist (typo?). Add new unit" - << " conversion in FGXMLElement.cpp." << endl; - exit(-1); - } - } else { - cerr << endl << "Supplied unit: \"" << supplied_units << "\" does not exist (typo?). Add new unit" - << " conversion in FGXMLElement.cpp." << endl; - exit(-1); - } - } - } else { - cerr << "Attempting to get get non-existent element " << el << endl; - return 0; + 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) { diff --git a/src/FDM/JSBSim/input_output/Makefile.am b/src/FDM/JSBSim/input_output/Makefile.am index 6fff1d27a..5c53240a6 100644 --- a/src/FDM/JSBSim/input_output/Makefile.am +++ b/src/FDM/JSBSim/input_output/Makefile.am @@ -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 diff --git a/src/FDM/JSBSim/math/FGColumnVector3.cpp b/src/FDM/JSBSim/math/FGColumnVector3.cpp index dfbbca6e0..f34afe592 100644 --- a/src/FDM/JSBSim/math/FGColumnVector3.cpp +++ b/src/FDM/JSBSim/math/FGColumnVector3.cpp @@ -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 diff --git a/src/FDM/JSBSim/math/FGColumnVector3.h b/src/FDM/JSBSim/math/FGColumnVector3.h index a17c53561..85e6bab22 100644 --- a/src/FDM/JSBSim/math/FGColumnVector3.h +++ b/src/FDM/JSBSim/math/FGColumnVector3.h @@ -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) {} diff --git a/src/FDM/JSBSim/math/FGFunction.cpp b/src/FDM/JSBSim/math/FGFunction.cpp index 0625d4d6b..f040e2a65 100755 --- a/src/FDM/JSBSim/math/FGFunction.cpp +++ b/src/FDM/JSBSim/math/FGFunction.cpp @@ -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 << " 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; iGetValue(); + for (i=1;iGetValue(); + } break; case eDifference: - for (i=1;iGetValue(); + for (i=1;iGetValue(); + } break; case eSum: - for (i=1;iGetValue(); + for (i=1;iGetValue(); + } break; case eQuotient: temp /= Parameters[1]->GetValue(); diff --git a/src/FDM/JSBSim/math/FGTable.cpp b/src/FDM/JSBSim/math/FGTable.cpp index 5d57628b0..100d5d784 100644 --- a/src/FDM/JSBSim/math/FGTable.cpp +++ b/src/FDM/JSBSim/math/FGTable.cpp @@ -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 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; - - 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; - } + unsigned int r = lastRowIndex; + unsigned int c = lastColumnIndex; - 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(r > 2 && Data[r-1][0] > rowKey) { r--; } + while(r < nRows && Data[r] [0] < rowKey) { r++; } + + 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 { diff --git a/src/FDM/JSBSim/math/FGTable.h b/src/FDM/JSBSim/math/FGTable.h index e70684095..e3bafc322 100644 --- a/src/FDM/JSBSim/math/FGTable.h +++ b/src/FDM/JSBSim/math/FGTable.h @@ -299,8 +299,8 @@ private: FGPropertyManager *lookupProperty[3]; double** Data; vector 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); diff --git a/src/FDM/JSBSim/math/Makefile.am b/src/FDM/JSBSim/math/Makefile.am index afcedd6cc..ce92ff6eb 100644 --- a/src/FDM/JSBSim/math/Makefile.am +++ b/src/FDM/JSBSim/math/Makefile.am @@ -5,7 +5,7 @@ libMath_a_SOURCES = FGColumnVector3.cpp FGFunction.cpp FGLocation.cpp FGMatrix33 FGCondition.cpp noinst_HEADERS = FGColumnVector3.h FGFunction.h FGLocation.h FGMatrix33.h \ - FGParameter.h FGPropertyValue.h FGQuaternion.h FGRealValue.h FGTable.h \ + FGParameter.h FGPropertyValue.h FGQuaternion.h FGRealValue.h FGTable.h \ FGCondition.h INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim diff --git a/src/FDM/JSBSim/models/FGAerodynamics.cpp b/src/FDM/JSBSim/models/FGAerodynamics.cpp index 8e75ce058..9d7d31dcb 100644 --- a/src/FDM/JSBSim/models/FGAerodynamics.cpp +++ b/src/FDM/JSBSim/models/FGAerodynamics.cpp @@ -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"); - } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/FDM/JSBSim/models/FGAircraft.cpp b/src/FDM/JSBSim/models/FGAircraft.cpp index 4e4b65360..edce3e0a3 100644 --- a/src/FDM/JSBSim/models/FGAircraft.cpp +++ b/src/FDM/JSBSim/models/FGAircraft.cpp @@ -94,6 +94,7 @@ FGAircraft::FGAircraft(FGFDMExec* fdmex) : FGModel(fdmex) lbarh = lbarv = 0.0; vbarh = vbarv = 0.0; WingIncidence = 0.0; + HoldDown = 0; bind(); @@ -116,14 +117,18 @@ bool FGAircraft::Run(void) if (FDMExec->Holding()) return false; vForces.InitMatrix(); - vForces += Aerodynamics->GetForces(); - vForces += Propulsion->GetForces(); - vForces += GroundReactions->GetForces(); + if (!HoldDown) { + vForces += Aerodynamics->GetForces(); + vForces += Propulsion->GetForces(); + vForces += GroundReactions->GetForces(); + } vMoments.InitMatrix(); - vMoments += Aerodynamics->GetMoments(); - vMoments += Propulsion->GetMoments(); - vMoments += GroundReactions->GetMoments(); + if (!HoldDown) { + vMoments += Aerodynamics->GetMoments(); + vMoments += Propulsion->GetMoments(); + vMoments += GroundReactions->GetMoments(); + } vBodyAccel = vForces/MassBalance->GetMass(); @@ -212,6 +217,7 @@ void FGAircraft::bind(void) PropertyManager->Tie("metrics/lv-norm", this, &FGAircraft::Getlbarv); PropertyManager->Tie("metrics/vbarh-norm", this, &FGAircraft::Getvbarh); PropertyManager->Tie("metrics/vbarv-norm", this, &FGAircraft::Getvbarv); + PropertyManager->Tie("forces/hold-down", this, &FGAircraft::GetHoldDown, &FGAircraft::SetHoldDown); PropertyManager->Tie("moments/l-total-lbsft", this, eL, (PMF)&FGAircraft::GetMoments); PropertyManager->Tie("moments/m-total-lbsft", this, eM, (PMF)&FGAircraft::GetMoments); PropertyManager->Tie("moments/n-total-lbsft", this, eN, (PMF)&FGAircraft::GetMoments); @@ -251,6 +257,7 @@ void FGAircraft::unbind(void) PropertyManager->Untie("forces/fbx-total-lbs"); PropertyManager->Untie("forces/fby-total-lbs"); PropertyManager->Untie("forces/fbz-total-lbs"); + PropertyManager->Untie("forces/hold-down"); PropertyManager->Untie("metrics/aero-rp-x-in"); PropertyManager->Untie("metrics/aero-rp-y-in"); PropertyManager->Untie("metrics/aero-rp-z-in"); diff --git a/src/FDM/JSBSim/models/FGAircraft.h b/src/FDM/JSBSim/models/FGAircraft.h index 6a882e11a..f62ef276a 100644 --- a/src/FDM/JSBSim/models/FGAircraft.h +++ b/src/FDM/JSBSim/models/FGAircraft.h @@ -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); diff --git a/src/FDM/JSBSim/models/FGAuxiliary.cpp b/src/FDM/JSBSim/models/FGAuxiliary.cpp index 86d1cbdc5..bc684ce9c 100755 --- a/src/FDM/JSBSim/models/FGAuxiliary.cpp +++ b/src/FDM/JSBSim/models/FGAuxiliary.cpp @@ -101,16 +101,16 @@ FGAuxiliary::~FGAuxiliary() bool FGAuxiliary::Run() { - double A,B,D, hdot_Vt; + double A,B,D; + + if (FGModel::Run()) return true; // return true if error returned from base class + if (FDMExec->Holding()) return false; + const FGColumnVector3& vPQR = Propagate->GetPQR(); const FGColumnVector3& vUVW = Propagate->GetUVW(); const FGColumnVector3& vUVWdot = Propagate->GetUVWdot(); const FGColumnVector3& vVel = Propagate->GetVel(); - if (FGModel::Run()) return true; // return true if error returned from base class - - if (FDMExec->Holding()) return false; - p = Atmosphere->GetPressure(); rhosl = Atmosphere->GetDensitySL(); psl = Atmosphere->GetPressureSL(); @@ -182,18 +182,9 @@ bool FGAuxiliary::Run() Vground = sqrt( vVel(eNorth)*vVel(eNorth) + vVel(eEast)*vVel(eEast) ); - if (vVel(eNorth) == 0) psigt = 0; - else psigt = atan2(vVel(eEast), vVel(eNorth)); - + psigt = atan2(vVel(eEast), vVel(eNorth)); if (psigt < 0.0) psigt += 2*M_PI; - - if (Vground == 0.0) { - if (vVel(eDown) == 0.0) gamma = 0.0; - else if (vVel(eDown) < 0.0) gamma = 90.0*degtorad; - else gamma = -90.0*degtorad; - } else { - gamma = atan2(-vVel(eDown), Vground); - } + gamma = atan2(-vVel(eDown), Vground); tat = sat*(1 + 0.2*Mach*Mach); // Total Temperature, isentropic flow tatc = RankineToCelsius(tat); diff --git a/src/FDM/JSBSim/models/FGFCS.cpp b/src/FDM/JSBSim/models/FGFCS.cpp index faf95af84..cf41c5755 100644 --- a/src/FDM/JSBSim/models/FGFCS.cpp +++ b/src/FDM/JSBSim/models/FGFCS.cpp @@ -52,6 +52,7 @@ INCLUDES #include #include #include +#include namespace JSBSim { @@ -147,7 +148,9 @@ bool FGFCS::Run(void) // Cycle through the sensor, autopilot, and flight control components for (i=0; iRun(); - for (i=0; iRun(); + for (i=0; iRun(); + } for (i=0; iRun(); return false; @@ -456,10 +459,8 @@ bool FGFCS::Load(Element* el) { string name, file, fname, interface_property_string; vector *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); diff --git a/src/FDM/JSBSim/models/FGFCS.h b/src/FDM/JSBSim/models/FGFCS.h index 10c582d10..b07800fb7 100644 --- a/src/FDM/JSBSim/models/FGFCS.h +++ b/src/FDM/JSBSim/models/FGFCS.h @@ -53,7 +53,7 @@ INCLUDES #include #include #include -#include +#include /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 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; } diff --git a/src/FDM/JSBSim/models/FGGroundReactions.cpp b/src/FDM/JSBSim/models/FGGroundReactions.cpp index a82a281a1..c8bf6ab9e 100644 --- a/src/FDM/JSBSim/models/FGGroundReactions.cpp +++ b/src/FDM/JSBSim/models/FGGroundReactions.cpp @@ -64,7 +64,7 @@ FGGroundReactions::FGGroundReactions(FGFDMExec* fgex) : FGModel(fgex) FGGroundReactions::~FGGroundReactions(void) { - for (int i=0; iFindNextElement("contact"); } - for (int i=0; iGetAttributeValueAsNumber("port"); + port = int(element->GetAttributeValueAsNumber("port")); if (port == 0) { cerr << endl << "No port assigned in input element" << endl; } else { diff --git a/src/FDM/JSBSim/models/FGLGear.cpp b/src/FDM/JSBSim/models/FGLGear.cpp index 201d0ed85..b11041c9a 100644 --- a/src/FDM/JSBSim/models/FGLGear.cpp +++ b/src/FDM/JSBSim/models/FGLGear.cpp @@ -88,7 +88,7 @@ FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number) : Exec(fdmex), if (el->FindElement("max_steer")) maxSteerAngle = el->FindElementValueAsNumberConvertTo("max_steer", "DEG"); if (el->FindElement("retractable")) - isRetractable = (int)el->FindElementValueAsNumber("retractable"); + isRetractable = ((unsigned int)el->FindElementValueAsNumber("retractable"))>0.0?true:false; ForceY_Table = 0; force_table = el->FindElement("table"); @@ -332,8 +332,9 @@ FGColumnVector3& FGLGear::Force(void) // Compute the forces in the wheel ground plane. - RollingForce = (1.0 - TirePressureNorm) * 30 - + vLocalForce(eZ) * BrakeFCoeff * (RollingWhlVel>=0?1.0:-1.0); + RollingForce = ((1.0 - TirePressureNorm) * 30 + + vLocalForce(eZ) * BrakeFCoeff) * (RollingWhlVel>=0?1.0:-1.0); + SideForce = vLocalForce(eZ) * FCoeff; // Transform these forces back to the local reference frame. @@ -380,7 +381,7 @@ FGColumnVector3& FGLGear::Force(void) if ((fabs(RollingWhlVel) <= RFRV) && RFRV > 0) vForce(eX) *= fabs(RollingWhlVel)/RFRV; if ((fabs(SideWhlVel) <= SFRV) && SFRV > 0) vForce(eY) *= fabs(SideWhlVel)/SFRV; -// End experimental section for attentuating gear jitter +// End section for attentuating gear jitter vMoment = vWhlBodyVec * vForce; @@ -426,13 +427,9 @@ void FGLGear::ComputeSlipAngle(void) SideWhlVel = vWhlVelVec(eY)*CosWheel - vWhlVelVec(eX)*SinWheel; // Calculate tire slip angle. - if (fabs(RollingWhlVel) < 0.02 && fabs(SideWhlVel) < 0.02) { - WheelSlip = -SteerAngle*radtodeg; - } else { WheelSlip = atan2(SideWhlVel, fabs(RollingWhlVel))*radtodeg; - } -// Filter the wheel slip angle + // Filter the wheel slip angle double SlipOutput, ca, cb, denom; diff --git a/src/FDM/JSBSim/models/FGLGear.h b/src/FDM/JSBSim/models/FGLGear.h index e35d2b7c4..fdfa809c9 100644 --- a/src/FDM/JSBSim/models/FGLGear.h +++ b/src/FDM/JSBSim/models/FGLGear.h @@ -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; } diff --git a/src/FDM/JSBSim/models/FGMassBalance.cpp b/src/FDM/JSBSim/models/FGMassBalance.cpp index e5a868f83..f39e97a65 100644 --- a/src/FDM/JSBSim/models/FGMassBalance.cpp +++ b/src/FDM/JSBSim/models/FGMassBalance.cpp @@ -104,11 +104,11 @@ bool FGMassBalance::Load(Element* el) EmptyWeight = el->FindElementValueAsNumberConvertTo("emptywt", "LBS"); element = el->FindElement("location"); - while (element) { - element_name = element->GetAttributeValue("name"); - if (element_name == "CG") vbaseXYZcg = element->FindElementTripletConvertTo("IN"); - element = el->FindNextElement("location"); - } + while (element) { + element_name = element->GetAttributeValue("name"); + if (element_name == "CG") vbaseXYZcg = element->FindElementTripletConvertTo("IN"); + element = el->FindNextElement("location"); + } // Find all POINTMASS elements that descend from this METRICS branch of the // config file. @@ -281,11 +281,11 @@ void FGMassBalance::bind(void) &FGMassBalance::GetMass); PropertyManager->Tie("inertia/weight-lbs", this, &FGMassBalance::GetWeight); - PropertyManager->Tie("inertia/cg-x-ft", this,1, + PropertyManager->Tie("inertia/cg-x-in", this,1, (PMF)&FGMassBalance::GetXYZcg); - PropertyManager->Tie("inertia/cg-y-ft", this,2, + PropertyManager->Tie("inertia/cg-y-in", this,2, (PMF)&FGMassBalance::GetXYZcg); - PropertyManager->Tie("inertia/cg-z-ft", this,3, + PropertyManager->Tie("inertia/cg-z-in", this,3, (PMF)&FGMassBalance::GetXYZcg); } @@ -295,9 +295,9 @@ void FGMassBalance::unbind(void) { PropertyManager->Untie("inertia/mass-slugs"); PropertyManager->Untie("inertia/weight-lbs"); - PropertyManager->Untie("inertia/cg-x-ft"); - PropertyManager->Untie("inertia/cg-y-ft"); - PropertyManager->Untie("inertia/cg-z-ft"); + PropertyManager->Untie("inertia/cg-x-in"); + PropertyManager->Untie("inertia/cg-y-in"); + PropertyManager->Untie("inertia/cg-z-in"); } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -335,7 +335,7 @@ void FGMassBalance::Debug(int from) cout << " EmptyWeight: " << EmptyWeight << " lbm" << endl; cout << " CG (x, y, z): " << vbaseXYZcg << endl; // ToDo: Need to add point mass outputs here - for (int i=0; i 0) { for (unsigned int i=0;iGetName(); + 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;iAppend(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; } diff --git a/src/FDM/JSBSim/models/FGOutput.h b/src/FDM/JSBSim/models/FGOutput.h index 7126624a2..8d3f00b9e 100644 --- a/src/FDM/JSBSim/models/FGOutput.h +++ b/src/FDM/JSBSim/models/FGOutput.h @@ -55,7 +55,7 @@ INCLUDES #endif #include -#include +#include /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% DEFINITIONS @@ -123,7 +123,7 @@ CLASS DOCUMENTATION CLASS DECLARATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ -class FGOutput : public FGModel +class FGOutput : public FGModel, public FGXMLFileRead { public: FGOutput(FGFDMExec*); diff --git a/src/FDM/JSBSim/models/FGPropagate.cpp b/src/FDM/JSBSim/models/FGPropagate.cpp index db2ff3f92..a1211cd62 100644 --- a/src/FDM/JSBSim/models/FGPropagate.cpp +++ b/src/FDM/JSBSim/models/FGPropagate.cpp @@ -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); } diff --git a/src/FDM/JSBSim/models/FGPropulsion.cpp b/src/FDM/JSBSim/models/FGPropulsion.cpp index 35f420a5b..a6f45021f 100644 --- a/src/FDM/JSBSim/models/FGPropulsion.cpp +++ b/src/FDM/JSBSim/models/FGPropulsion.cpp @@ -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; diff --git a/src/FDM/JSBSim/models/FGPropulsion.h b/src/FDM/JSBSim/models/FGPropulsion.h index e25f46fd1..9884f61c3 100644 --- a/src/FDM/JSBSim/models/FGPropulsion.h +++ b/src/FDM/JSBSim/models/FGPropulsion.h @@ -59,7 +59,7 @@ INCLUDES #include #include #include -#include +#include /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% DEFINITIONS @@ -97,7 +97,7 @@ CLASS DOCUMENTATION CLASS DECLARATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ -class FGPropulsion : public FGModel +class FGPropulsion : public FGModel, public FGXMLFileRead { public: /// Constructor diff --git a/src/FDM/JSBSim/models/flight_control/FGActuator.cpp b/src/FDM/JSBSim/models/flight_control/FGActuator.cpp new file mode 100755 index 000000000..3a06e89b3 --- /dev/null +++ b/src/FDM/JSBSim/models/flight_control/FGActuator.cpp @@ -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; + } + } +} +} diff --git a/src/FDM/JSBSim/models/flight_control/FGActuator.h b/src/FDM/JSBSim/models/flight_control/FGActuator.h new file mode 100755 index 000000000..a420cbec9 --- /dev/null +++ b/src/FDM/JSBSim/models/flight_control/FGActuator.h @@ -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 + +/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +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 + + + number + number + number + number + number + [ + {property name | value} + {property name | value} + ] + [ {property} ] + +@endcode + +Example: + +@code + + + 60 + 0.085 + 0.002 + 0.002 + 0.05 + + -0.17 + 0.17 + + +@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 diff --git a/src/FDM/JSBSim/models/flight_control/FGFCSComponent.cpp b/src/FDM/JSBSim/models/flight_control/FGFCSComponent.cpp index 177055bec..b7f31b6d3 100644 --- a/src/FDM/JSBSim/models/flight_control/FGFCSComponent.cpp +++ b/src/FDM/JSBSim/models/flight_control/FGFCSComponent.cpp @@ -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"; } diff --git a/src/FDM/JSBSim/models/flight_control/FGFCSFunction.cpp b/src/FDM/JSBSim/models/flight_control/FGFCSFunction.cpp index cd6559b08..b47aed333 100755 --- a/src/FDM/JSBSim/models/flight_control/FGFCSFunction.cpp +++ b/src/FDM/JSBSim/models/flight_control/FGFCSFunction.cpp @@ -54,7 +54,12 @@ FGFCSFunction::FGFCSFunction(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, { Element *function_element = element->FindElement("function"); - function = new FGFunction(PropertyManager, function_element); + if (function_element) + function = new FGFunction(PropertyManager, function_element); + else { + cerr << "FCS Function should contain a \"function\" element" << endl; + exit(-1); + } FGFCSComponent::bind(); Debug(0); diff --git a/src/FDM/JSBSim/models/flight_control/FGPID.cpp b/src/FDM/JSBSim/models/flight_control/FGPID.cpp index 3b60b1a74..7917d1fed 100755 --- a/src/FDM/JSBSim/models/flight_control/FGPID.cpp +++ b/src/FDM/JSBSim/models/flight_control/FGPID.cpp @@ -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; diff --git a/src/FDM/JSBSim/models/flight_control/FGSensor.cpp b/src/FDM/JSBSim/models/flight_control/FGSensor.cpp index f0055616c..72278f059 100755 --- a/src/FDM/JSBSim/models/flight_control/FGSensor.cpp +++ b/src/FDM/JSBSim/models/flight_control/FGSensor.cpp @@ -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 diff --git a/src/FDM/JSBSim/models/flight_control/FGSensor.h b/src/FDM/JSBSim/models/flight_control/FGSensor.h index 267258336..4789996b7 100755 --- a/src/FDM/JSBSim/models/flight_control/FGSensor.h +++ b/src/FDM/JSBSim/models/flight_control/FGSensor.h @@ -63,7 +63,7 @@ CLASS DOCUMENTATION Syntax: @code - + number number @@ -80,7 +80,7 @@ Syntax: Example: @code - + 0.5 2 @@ -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); diff --git a/src/FDM/JSBSim/models/flight_control/FGSwitch.cpp b/src/FDM/JSBSim/models/flight_control/FGSwitch.cpp index a28aedddd..782cc0eec 100644 --- a/src/FDM/JSBSim/models/flight_control/FGSwitch.cpp +++ b/src/FDM/JSBSim/models/flight_control/FGSwitch.cpp @@ -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; iGetNumDataLines(); i++) + for (unsigned int i=0; iGetNumDataLines(); i++) current_test->conditions.push_back(FGCondition(test_element->GetDataLine(i), PropertyManager)); condition_element = test_element->GetElement(); // retrieve condition groups diff --git a/src/FDM/JSBSim/models/flight_control/Makefile.am b/src/FDM/JSBSim/models/flight_control/Makefile.am index e81ce1480..5ccfe5cae 100644 --- a/src/FDM/JSBSim/models/flight_control/Makefile.am +++ b/src/FDM/JSBSim/models/flight_control/Makefile.am @@ -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 diff --git a/src/FDM/JSBSim/models/propulsion/FGEngine.cpp b/src/FDM/JSBSim/models/propulsion/FGEngine.cpp index ac55b0aed..b40cdb349 100644 --- a/src/FDM/JSBSim/models/propulsion/FGEngine.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGEngine.cpp @@ -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 diff --git a/src/FDM/JSBSim/models/propulsion/FGEngine.h b/src/FDM/JSBSim/models/propulsion/FGEngine.h index 07c4c60e1..f60db357d 100644 --- a/src/FDM/JSBSim/models/propulsion/FGEngine.h +++ b/src/FDM/JSBSim/models/propulsion/FGEngine.h @@ -60,6 +60,7 @@ INCLUDES #include #include "FGThruster.h" #include +#include /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 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); diff --git a/src/FDM/JSBSim/models/propulsion/FGForce.cpp b/src/FDM/JSBSim/models/propulsion/FGForce.cpp index 1dffff82d..fec3686d9 100644 --- a/src/FDM/JSBSim/models/propulsion/FGForce.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGForce.cpp @@ -61,7 +61,6 @@ FGForce::FGForce(FGFDMExec *FDMExec) : mT(1,1) = 1; //identity matrix mT(2,2) = 1; mT(3,3) = 1; - vSense.InitMatrix(1); Debug(0); } @@ -77,7 +76,7 @@ FGForce::~FGForce() FGColumnVector3& FGForce::GetBodyForces(void) { - vFb = Transform()*(vFn.multElementWise(vSense)); + vFb = Transform()*vFn; // Find the distance from this vector's acting location to the cg; this // needs to be done like this to convert from structural to body coords. @@ -110,29 +109,38 @@ FGMatrix33 FGForce::Transform(void) //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +void FGForce::UpdateCustomTransformMatrix(void) +{ + double cp,sp,cr,sr,cy,sy; + + cp=cos(vOrient(ePitch)); sp=sin(vOrient(ePitch)); + cr=cos(vOrient(eRoll)); sr=sin(vOrient(eRoll)); + cy=cos(vOrient(eYaw)); sy=sin(vOrient(eYaw)); + + mT(1,1) = cp*cy; + mT(1,2) = cp*sy; + mT(1,3) = -sp; + + mT(2,1) = sr*sp*cy - cr*sy; + mT(2,2) = sr*sp*sy + cr*cy; + mT(2,3) = sr*cp; + + mT(3,1) = cr*sp*cy + sr*sy; + mT(3,2) = cr*sp*sy - sr*cy; + mT(3,3) = cr*cp; + mT = mT.Inverse(); +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + void FGForce::SetAnglesToBody(double broll, double bpitch, double byaw) { if (ttype == tCustom) { - double cp,sp,cr,sr,cy,sy; vOrient(ePitch) = bpitch; vOrient(eRoll) = broll; vOrient(eYaw) = byaw; - cp=cos(bpitch); sp=sin(bpitch); - cr=cos(broll); sr=sin(broll); - cy=cos(byaw); sy=sin(byaw); - - mT(1,1)=cp*cy; - mT(1,2)=cp*sy; - mT(1,3)=-1*sp; - - mT(2,1)=sr*sp*cy-cr*sy; - mT(2,2)=sr*sp*sy+cr*cy; - mT(2,3)=sr*cp; - - mT(3,1)=cr*sp*cy+sr*sy; - mT(3,2)=cr*sp*sy-sr*cy; - mT(3,3)=cr*cp; + UpdateCustomTransformMatrix(); } } diff --git a/src/FDM/JSBSim/models/propulsion/FGForce.h b/src/FDM/JSBSim/models/propulsion/FGForce.h index 767e26941..ce62f239b 100644 --- a/src/FDM/JSBSim/models/propulsion/FGForce.h +++ b/src/FDM/JSBSim/models/propulsion/FGForce.h @@ -151,7 +151,7 @@ can now be retrieved by calling:

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:

vM=fgf.GetMoments();

@@ -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; diff --git a/src/FDM/JSBSim/models/propulsion/FGNozzle.cpp b/src/FDM/JSBSim/models/propulsion/FGNozzle.cpp index 5b0b58a20..476f4a988 100644 --- a/src/FDM/JSBSim/models/propulsion/FGNozzle.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGNozzle.cpp @@ -83,7 +83,7 @@ FGNozzle::FGNozzle(FGFDMExec* FDMExec, Element* nozzle_element, int num) Type = ttNozzle; Area2 = (Diameter*Diameter/4.0)*M_PI; AreaT = Area2/ExpR; - + Debug(0); } @@ -99,7 +99,11 @@ FGNozzle::~FGNozzle() double FGNozzle::Calculate(double CfPc) { double pAtm = fdmex->GetAtmosphere()->GetPressure(); - Thrust = max((double)0.0, (CfPc * AreaT + (PE - pAtm)*Area2) * nzlEff); + if (CfPc > 0) + Thrust = max((double)0.0, (CfPc * AreaT + (PE - pAtm)*Area2) * nzlEff); + else + Thrust = 0.0; + vFn(1) = Thrust * cos(ReverserAngle); ThrustCoeff = max((double)0.0, CfPc / ((pAtm - PE) * Area2)); @@ -120,7 +124,7 @@ string FGNozzle::GetThrusterLabels(int id, string delimeter) { std::ostringstream buf; - buf << Name << "_Thrust[" << id << ']'; + buf << Name << " Thrust (engine " << id << " in lbs)"; return buf.str(); } diff --git a/src/FDM/JSBSim/models/propulsion/FGPiston.cpp b/src/FDM/JSBSim/models/propulsion/FGPiston.cpp index 94b54c35d..3526b6d7d 100644 --- a/src/FDM/JSBSim/models/propulsion/FGPiston.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGPiston.cpp @@ -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(); diff --git a/src/FDM/JSBSim/models/propulsion/FGPropeller.cpp b/src/FDM/JSBSim/models/propulsion/FGPropeller.cpp index ea5ad91b2..4925d5a05 100644 --- a/src/FDM/JSBSim/models/propulsion/FGPropeller.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGPropeller.cpp @@ -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(); } diff --git a/src/FDM/JSBSim/models/propulsion/FGRocket.cpp b/src/FDM/JSBSim/models/propulsion/FGRocket.cpp index d4c0fa0e1..ada946f9d 100644 --- a/src/FDM/JSBSim/models/propulsion/FGRocket.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGRocket.cpp @@ -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(); diff --git a/src/FDM/JSBSim/models/propulsion/FGRocket.h b/src/FDM/JSBSim/models/propulsion/FGRocket.h index eac74251c..42436cc33 100644 --- a/src/FDM/JSBSim/models/propulsion/FGRocket.h +++ b/src/FDM/JSBSim/models/propulsion/FGRocket.h @@ -39,6 +39,7 @@ INCLUDES %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ #include "FGEngine.h" +#include #include /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -83,6 +84,45 @@ CLASS DOCUMENTATION coefficient is multiplied by the chamber pressure and then passed to the nozzle Calculate() routine, where the thrust force is determined. + + One can model the thrust of a solid rocket by providing a normalized thrust table + as a function of time. For instance, the space shuttle solid rocket booster + normalized thrust value looks roughly like this: + +
    
+  
+    
+      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
+    
+  
+
+ +The left column is time, the right column is normalized thrust. Inside the +FGRocket class code, the maximum thrust is calculated, and multiplied by this +table. The Rocket class also tracks burn time. All that needs to be done is +for the rocket engine to be throttle up to 1. At that time, the solid rocket +fuel begins burning and thrust is provided. @author Jon S. Berndt $Id$ @@ -133,7 +173,9 @@ private: double kFactor; double Variance; double PC; + double BurnTime; bool Flameout; + FGTable* ThrustTable; void Debug(int from); }; diff --git a/src/FDM/JSBSim/models/propulsion/FGThruster.cpp b/src/FDM/JSBSim/models/propulsion/FGThruster.cpp index 8cf4bf894..02875b2a1 100644 --- a/src/FDM/JSBSim/models/propulsion/FGThruster.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGThruster.cpp @@ -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(); } diff --git a/src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp b/src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp index 057d961f0..6191e2149 100755 --- a/src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp +++ b/src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp @@ -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; //--- -- 2.39.5