]> git.mxchange.org Git - flightgear.git/commitdiff
Sync w. JSBSim CVS (merge from PRE_OSG_PLIB_20061029 branch)
authormfranz <mfranz>
Sun, 3 Jun 2007 09:37:02 +0000 (09:37 +0000)
committermfranz <mfranz>
Sun, 3 Jun 2007 09:37:02 +0000 (09:37 +0000)
56 files changed:
src/FDM/JSBSim/FGFDMExec.cpp
src/FDM/JSBSim/FGFDMExec.h
src/FDM/JSBSim/FGJSBBase.cpp
src/FDM/JSBSim/FGJSBBase.h
src/FDM/JSBSim/FGState.cpp
src/FDM/JSBSim/JSBSim.cxx
src/FDM/JSBSim/initialization/FGInitialCondition.cpp
src/FDM/JSBSim/initialization/FGInitialCondition.h
src/FDM/JSBSim/input_output/FGPropertyManager.cpp
src/FDM/JSBSim/input_output/FGPropertyManager.h
src/FDM/JSBSim/input_output/FGScript.cpp
src/FDM/JSBSim/input_output/FGScript.h
src/FDM/JSBSim/input_output/FGXMLElement.cpp
src/FDM/JSBSim/input_output/Makefile.am
src/FDM/JSBSim/math/FGColumnVector3.cpp
src/FDM/JSBSim/math/FGColumnVector3.h
src/FDM/JSBSim/math/FGFunction.cpp
src/FDM/JSBSim/math/FGTable.cpp
src/FDM/JSBSim/math/FGTable.h
src/FDM/JSBSim/math/Makefile.am
src/FDM/JSBSim/models/FGAerodynamics.cpp
src/FDM/JSBSim/models/FGAircraft.cpp
src/FDM/JSBSim/models/FGAircraft.h
src/FDM/JSBSim/models/FGAuxiliary.cpp
src/FDM/JSBSim/models/FGFCS.cpp
src/FDM/JSBSim/models/FGFCS.h
src/FDM/JSBSim/models/FGGroundReactions.cpp
src/FDM/JSBSim/models/FGInput.cpp
src/FDM/JSBSim/models/FGLGear.cpp
src/FDM/JSBSim/models/FGLGear.h
src/FDM/JSBSim/models/FGMassBalance.cpp
src/FDM/JSBSim/models/FGOutput.cpp
src/FDM/JSBSim/models/FGOutput.h
src/FDM/JSBSim/models/FGPropagate.cpp
src/FDM/JSBSim/models/FGPropulsion.cpp
src/FDM/JSBSim/models/FGPropulsion.h
src/FDM/JSBSim/models/flight_control/FGActuator.cpp [new file with mode: 0755]
src/FDM/JSBSim/models/flight_control/FGActuator.h [new file with mode: 0755]
src/FDM/JSBSim/models/flight_control/FGFCSComponent.cpp
src/FDM/JSBSim/models/flight_control/FGFCSFunction.cpp
src/FDM/JSBSim/models/flight_control/FGPID.cpp
src/FDM/JSBSim/models/flight_control/FGSensor.cpp
src/FDM/JSBSim/models/flight_control/FGSensor.h
src/FDM/JSBSim/models/flight_control/FGSwitch.cpp
src/FDM/JSBSim/models/flight_control/Makefile.am
src/FDM/JSBSim/models/propulsion/FGEngine.cpp
src/FDM/JSBSim/models/propulsion/FGEngine.h
src/FDM/JSBSim/models/propulsion/FGForce.cpp
src/FDM/JSBSim/models/propulsion/FGForce.h
src/FDM/JSBSim/models/propulsion/FGNozzle.cpp
src/FDM/JSBSim/models/propulsion/FGPiston.cpp
src/FDM/JSBSim/models/propulsion/FGPropeller.cpp
src/FDM/JSBSim/models/propulsion/FGRocket.cpp
src/FDM/JSBSim/models/propulsion/FGRocket.h
src/FDM/JSBSim/models/propulsion/FGThruster.cpp
src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp

index 890342316e244070033f97a6e1520c33e47c0739..94088579a2e21b4c13c58eb25cf685e08aa1dc5f 100644 (file)
@@ -134,6 +134,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root)
   modelLoaded = false;
   IsSlave = false;
   holding = false;
+  Terminate = false;
 
   // Multiple FDM's are stopped for now.  We need to ensure that
   // the "user" instance always gets the zeroeth instance number,
@@ -168,6 +169,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root)
   Constructing = true;
   typedef int (FGFDMExec::*iPMF)(void) const;
   instance->Tie("simulation/do_trim", this, (iPMF)0, &FGFDMExec::DoTrim);
+  instance->Tie("simulation/terminate", (int *)&Terminate);
   Constructing = false;
 }
 
@@ -176,6 +178,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) : Root(root)
 FGFDMExec::~FGFDMExec()
 {
   instance->Untie("simulation/do_trim");
+  instance->Untie("simulation/terminate");
 
   try {
     DeAllocate();
@@ -354,7 +357,7 @@ int FGFDMExec::Schedule(FGModel* model, int rate)
 
 bool FGFDMExec::Run(void)
 {
-  bool success = false;
+  bool success=false;
   FGModel* model_iterator;
 
   model_iterator = FirstModel;
@@ -376,6 +379,7 @@ bool FGFDMExec::Run(void)
 
   Frame++;
   if (!Holding()) State->IncrTime();
+  if (Terminate) success = false;
   return (success);
 }
 
@@ -459,6 +463,9 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath)
   string token;
   string aircraftCfgFileName;
   string separator = "/";
+  Element* element = 0L;
+
+  modelName = model; // Set the class modelName attribute
 
 # ifdef macintosh
     separator = ";";
@@ -474,27 +481,12 @@ bool FGFDMExec::LoadModel(string model, bool addModelToPath)
   if (addModelToPath) FullAircraftPath += separator + model;
   aircraftCfgFileName = FullAircraftPath + separator + model + ".xml";
 
-  FGXMLParse *XMLParse = new FGXMLParse();
-  Element* element = 0L;
-  Element* document;
-
-  ifstream input_file(aircraftCfgFileName.c_str());
-
-  if (!input_file.is_open()) { // file open failed
-    cerr << "Could not open file " << aircraftCfgFileName.c_str() << endl;
-    return false;
-  }
-
-  readXML(input_file, *XMLParse);
-  document = XMLParse->GetDocument();
-
-  modelName = model;
-
   if (modelLoaded) {
     DeAllocate();
     Allocate();
   }
 
+  document = LoadXMLDocument(aircraftCfgFileName); // "document" is a class member
   ReadPrologue(document);
   element = document->GetElement();
 
@@ -553,7 +545,7 @@ void FGFDMExec::BuildPropertyCatalog(struct PropertyCatalogStructure* pcs)
   int node_idx = 0;
   char int_buf[10];
 
-  for (int i=0; i<pcs->node->nChildren(); i++) {
+  for (unsigned int i=0; i<pcs->node->nChildren(); i++) {
     pcsNew->base_string = pcs->base_string + "/" + pcs->node->getChild(i)->getName();
     node_idx = pcs->node->getChild(i)->getIndex();
     sprintf(int_buf, "[%d]", node_idx);
index 6ae678cfd9a66811f0ef0f3d96b581cca7857cfa..b286fab9c18b0656962d6365003c6b6a2c2527e1 100644 (file)
@@ -48,8 +48,8 @@ INCLUDES
 #include <initialization/FGInitialCondition.h>
 #include <FGJSBBase.h>
 #include <input_output/FGPropertyManager.h>
-#include <input_output/FGXMLParse.h>
 #include <input_output/FGGroundCallback.h>
+#include <input_output/FGXMLFileRead.h>
 #include <models/FGPropagate.h>
 
 #include <vector>
@@ -173,7 +173,7 @@ CLASS DOCUMENTATION
 CLASS DECLARATION
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
-class FGFDMExec : public FGJSBBase
+class FGFDMExec : public FGJSBBase, public FGXMLFileRead
 {
 public:
 
@@ -414,6 +414,7 @@ private:
   int Error;
   unsigned int Frame;
   unsigned int IdFDM;
+  unsigned short Terminate;
   bool holding;
   bool Constructing;
   bool modelLoaded;
index a9912cb69120de55bd60cd46311bbb1193d3a373..259220dbb343b1016c06b187be7d6646ef3bb53a 100644 (file)
@@ -94,9 +94,9 @@ const double FGJSBBase::slugtolb = 32.174049;
 const double FGJSBBase::lbtoslug = 1.0/slugtolb;
 
 const string FGJSBBase::needed_cfg_version = "2.0";
-const string FGJSBBase::JSBSim_version = "0.9.12 "__DATE__" "__TIME__;
+const string FGJSBBase::JSBSim_version = "Pre-1.0 "__DATE__" "__TIME__;
 
-std::queue <FGJSBBase::Message*> FGJSBBase::Messages;
+std::queue <FGJSBBase::Message> FGJSBBase::Messages;
 FGJSBBase::Message FGJSBBase::localMsg;
 unsigned int FGJSBBase::messageId = 0;
 
@@ -104,83 +104,75 @@ short FGJSBBase::debug_lvl  = 1;
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-FGJSBBase::Message* FGJSBBase::PutMessage(Message* msg)
+void FGJSBBase::PutMessage(const Message& msg)
 {
   Messages.push(msg);
-  return msg;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-FGJSBBase::Message* FGJSBBase::PutMessage(const string& text)
+void FGJSBBase::PutMessage(const string& text)
 {
-  Message *msg = new Message();
-  msg->text = text;
-  msg->messageId = messageId++;
-  msg->subsystem = "FDM";
-  msg->type = Message::eText;
+  Message msg;
+  msg.text = text;
+  msg.messageId = messageId++;
+  msg.subsystem = "FDM";
+  msg.type = Message::eText;
   Messages.push(msg);
-  return msg;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-FGJSBBase::Message* FGJSBBase::PutMessage(const string& text, bool bVal)
+void FGJSBBase::PutMessage(const string& text, bool bVal)
 {
-  Message *msg = new Message();
-  msg->text = text;
-  msg->messageId = messageId++;
-  msg->subsystem = "FDM";
-  msg->type = Message::eBool;
-  msg->bVal = bVal;
+  Message msg;
+  msg.text = text;
+  msg.messageId = messageId++;
+  msg.subsystem = "FDM";
+  msg.type = Message::eBool;
+  msg.bVal = bVal;
   Messages.push(msg);
-  return msg;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-FGJSBBase::Message* FGJSBBase::PutMessage(const string& text, int iVal)
+void FGJSBBase::PutMessage(const string& text, int iVal)
 {
-  Message *msg = new Message();
-  msg->text = text;
-  msg->messageId = messageId++;
-  msg->subsystem = "FDM";
-  msg->type = Message::eInteger;
-  msg->bVal = (iVal != 0);
+  Message msg;
+  msg.text = text;
+  msg.messageId = messageId++;
+  msg.subsystem = "FDM";
+  msg.type = Message::eInteger;
+  msg.bVal = (iVal != 0);
   Messages.push(msg);
-  return msg;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-FGJSBBase::Message* FGJSBBase::PutMessage(const string& text, double dVal)
+void FGJSBBase::PutMessage(const string& text, double dVal)
 {
-  Message *msg = new Message();
-  msg->text = text;
-  msg->messageId = messageId++;
-  msg->subsystem = "FDM";
-  msg->type = Message::eDouble;
-  msg->bVal = (dVal != 0.0);
+  Message msg;
+  msg.text = text;
+  msg.messageId = messageId++;
+  msg.subsystem = "FDM";
+  msg.type = Message::eDouble;
+  msg.bVal = (dVal != 0.0);
   Messages.push(msg);
-  return msg;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-FGJSBBase::Message* FGJSBBase::ReadMessage(void)
+int FGJSBBase::SomeMessages(void)
 {
-  if (!Messages.empty()) return Messages.front();
-  else                   return NULL;
+  return !Messages.empty();
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
 FGJSBBase::Message* FGJSBBase::ProcessMessage(void)
 {
-  if (!Messages.empty())
-    localMsg = *(Messages.front());
-  else
-    return NULL;
+  if (Messages.empty()) return NULL;
+  localMsg = Messages.front();
   Messages.pop();
   return &localMsg;
 }
index 6147248e68aba3a66f49a75d8dcaea580fb2f562..2dd3637389cc29d78ee4e132a31ea1009e2b6e15 100644 (file)
@@ -125,7 +125,8 @@ public:
   ~FGJSBBase() {};
 
   /// JSBSim Message structure
-  typedef struct Msg {
+  class Message {
+  public:
     unsigned int fdmId;
     unsigned int messageId;
     string text;
@@ -134,7 +135,7 @@ public:
     bool bVal;
     int  iVal;
     double dVal;
-  } Message;
+  };
 
   ///@name JSBSim console output highlighting terms.
   //@{
@@ -167,29 +168,29 @@ public:
   /** Places a Message structure on the Message queue.
       @param msg pointer to a Message structure
       @return pointer to a Message structure */
-  Message* PutMessage(Message* msg);
+void PutMessage(const Message& msg);
   /** Creates a message with the given text and places it on the queue.
       @param text message text
       @return pointer to a Message structure */
-  Message* PutMessage(const string& text);
+  void PutMessage(const string& text);
   /** Creates a message with the given text and boolean value and places it on the queue.
       @param text message text
       @param bVal boolean value associated with the message
       @return pointer to a Message structure */
-  Message* PutMessage(const string& text, bool bVal);
+void PutMessage(const string& text, bool bVal);
   /** Creates a message with the given text and integer value and places it on the queue.
       @param text message text
       @param iVal integer value associated with the message
       @return pointer to a Message structure */
-  Message* PutMessage(const string& text, int iVal);
+void PutMessage(const string& text, int iVal);
   /** Creates a message with the given text and double value and places it on the queue.
       @param text message text
       @param dVal double value associated with the message
       @return pointer to a Message structure */
-  Message* PutMessage(const string& text, double dVal);
+void PutMessage(const string& text, double dVal);
   /** Reads the message on the queue (but does not delete it).
-      @return pointer to a Message structure (or NULL if no mesage) */
-  Message* ReadMessage(void);
+      @return 1 if some messages */
+  int SomeMessages(void);
   /** Reads the message on the queue and removes it from the queue.
       @return pointer to a Message structure (or NULL if no mesage) */
   Message* ProcessMessage(void);
@@ -276,7 +277,7 @@ public:
 protected:
   static Message localMsg;
 
-  static std::queue <Message*> Messages;
+  static std::queue <Message> Messages;
 
   void Debug(int from) {};
 
index 8945abdd47a1aba23678565a23899afaee87c55d..29c174132afc8e231d5e036ca88b3e5bebd8ec42 100644 (file)
@@ -47,10 +47,6 @@ INCLUDES
 #  endif
 #endif
 
-#ifdef _WIN32
-//#define snprintf _snprintf
-#endif
-
 #include "FGState.h"
 
 namespace JSBSim {
@@ -190,86 +186,6 @@ FGMatrix33& FGState::GetTb2s(void)
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-void FGState::ReportState(void)
-{
-#if 0
-#if !defined(__BORLANDCPP__)
-  char out[80], flap[10], gear[12];
-
-  cout << endl << "  JSBSim State" << endl;
-  snprintf(out,80,"    Weight: %7.0f lbs.  CG: %5.1f, %5.1f, %5.1f inches\n",
-                   FDMExec->GetMassBalance()->GetWeight(),
-                   FDMExec->GetMassBalance()->GetXYZcg(1),
-                   FDMExec->GetMassBalance()->GetXYZcg(2),
-                   FDMExec->GetMassBalance()->GetXYZcg(3));
-  cout << out;
-  if ( FCS->GetDfPos() <= 0.01)
-    snprintf(flap,10,"Up");
-  else
-    snprintf(flap,10,"%2.0f",FCS->GetDfPos());
-
-  if (FCS->GetGearPos() < 0.01)
-    snprintf(gear,12,"Up");
-  else if (FCS->GetGearPos() > 0.99)
-    snprintf(gear,12,"Down");
-  else
-    snprintf(gear,12,"In Transit");
-
-  snprintf(out,80, "    Flaps: %3s  Gear: %12s\n",flap,gear);
-  cout << out;
-  snprintf(out,80, "    Speed: %4.0f KCAS  Mach: %5.2f\n",
-                    Auxiliary->GetVcalibratedKTS(),
-                    Auxiliary->GetMach() );
-  cout << out;
-  snprintf(out,80, "    Altitude: %7.0f ft.  AGL Altitude: %7.0f ft.\n",
-                    Propagate->Geth(),
-                    Propagate->GetDistanceAGL() );
-  cout << out;
-  snprintf(out,80, "    Angle of Attack: %6.2f deg  Pitch Angle: %6.2f deg\n",
-                    Auxiliary->Getalpha()*radtodeg,
-                    Propagate->Gettht()*radtodeg );
-  cout << out;
-  snprintf(out,80, "    Flight Path Angle: %6.2f deg  Climb Rate: %5.0f ft/min\n",
-                    Auxiliary->GetGamma()*radtodeg,
-                    Propagate->Gethdot()*60 );
-  cout << out;
-  snprintf(out,80, "    Normal Load Factor: %4.2f g's  Pitch Rate: %5.2f deg/s\n",
-                    Aircraft->GetNlf(),
-                    Propagate->GetPQR(2)*radtodeg );
-  cout << out;
-  snprintf(out,80, "    Heading: %3.0f deg true  Sideslip: %5.2f deg  Yaw Rate: %5.2f deg/s\n",
-                    Propagate->Getpsi()*radtodeg,
-                    Auxiliary->Getbeta()*radtodeg,
-                    Propagate->GetPQR(3)*radtodeg  );
-  cout << out;
-  snprintf(out,80, "    Bank Angle: %5.2f deg  Roll Rate: %5.2f deg/s\n",
-                    Propagate->Getphi()*radtodeg,
-                    Propagate->GetPQR(1)*radtodeg );
-  cout << out;
-  snprintf(out,80, "    Elevator: %5.2f deg  Left Aileron: %5.2f deg  Rudder: %5.2f deg\n",
-                    FCS->GetDePos(ofRad)*radtodeg,
-                    FCS->GetDaLPos(ofRad)*radtodeg,
-                    FCS->GetDrPos(ofRad)*radtodeg );
-  cout << out;
-  snprintf(out,80, "    Throttle: %5.2f%c\n",
-                    FCS->GetThrottlePos(0)*100,'%' );
-  cout << out;
-
-  snprintf(out,80, "    Wind Components: %5.2f kts head wind, %5.2f kts cross wind\n",
-                    Auxiliary->GetHeadWind()*fpstokts,
-                    Auxiliary->GetCrossWind()*fpstokts );
-  cout << out;
-
-  snprintf(out,80, "    Ground Speed: %4.0f knots , Ground Track: %3.0f deg true\n",
-                    Auxiliary->GetVground()*fpstokts,
-                    Auxiliary->GetGroundTrack()*radtodeg );
-  cout << out;
-#endif
-#endif
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
 void FGState::bind(void)
 {
   PropertyManager->Tie("sim-time-sec", this, &FGState::Getsim_time);
index e8e48984635f3b44551cab1a20082f04f0d8b7a1..2b59f324091ae2ddbcaa9c4cb7691aa655b0fee1 100644 (file)
@@ -466,7 +466,7 @@ void FGJSBsim::update( double dt )
     }
 
     FGJSBBase::Message* msg;
-    while (fdmex->ReadMessage()) {
+    while (fdmex->SomeMessages()) {
       msg = fdmex->ProcessMessage();
       switch (msg->type) {
       case FGJSBBase::Message::eText:
@@ -1105,8 +1105,10 @@ void FGJSBsim::do_trim(void)
   } else {
     trimmed->setBoolValue(true);
   }
+#if 0
   if (FGJSBBase::debug_lvl > 0)
-      State->ReportState();
+      State->ReportState();    /* FIXME: Function not implemented */
+#endif
 
   delete fgtrim;
 
index 9ee9d094edc640c1439107a13d0af520d5d39841..7c2dc3dfcaf6f0b84592e89aef5df0714ccf160b 100644 (file)
@@ -732,9 +732,6 @@ double FGInitialCondition::GetWindDirDegIC(void) const {
 bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
 {
   string resetDef;
-  ifstream initialization_file;
-  FGXMLParse initialization_file_parser;
-  Element *document, *el;
   int n;
 
   string sep = "/";
@@ -748,15 +745,8 @@ bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
     resetDef = rstfile;
   }
 
-  initialization_file.open(resetDef.c_str());
-  if ( !initialization_file.is_open()) {
-    cerr << "Could not open initialization file: " << resetDef << endl;
-    return false;
-  }
+  document = LoadXMLDocument(resetDef);
 
-  readXML(initialization_file, initialization_file_parser);
-  document = initialization_file_parser.GetDocument(); // document holds the
-                                                       // initialization description
   if (document->GetName() != string("initialize")) {
     cerr << "File: " << resetDef << " is not a reset file" << endl;
     exit(-1);
@@ -803,10 +793,10 @@ bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
   if (document->FindElement("vground"))
     SetVgroundKtsIC(document->FindElementValueAsNumberConvertTo("vground", "FT/SEC"));
   if (document->FindElement("running")) {
-    n = document->FindElementValueAsNumber("running");
+    n = int(document->FindElementValueAsNumber("running"));
     if (n != 0) {
       FGPropulsion* propulsion = fdmex->GetPropulsion();
-      for(int i=0; i<propulsion->GetNumEngines(); i++) {
+      for(unsigned int i=0; i<propulsion->GetNumEngines(); i++) {
          propulsion->GetEngine(i)->SetRunning(true);
       }
     }
index 077f001f7e15c8f02a396437a6ec9544371f898e..105297c1a6e0c807511f327f110dd313694f5403 100644 (file)
@@ -50,6 +50,7 @@ INCLUDES
 #include <FGFDMExec.h>
 #include <FGJSBBase.h>
 #include <math/FGColumnVector3.h>
+#include <input_output/FGXMLFileRead.h>
 
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 DEFINITIONS
@@ -199,7 +200,7 @@ CLASS DOCUMENTATION
 CLASS DECLARATION
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
-class FGInitialCondition : public FGJSBBase
+class FGInitialCondition : public FGJSBBase, public FGXMLFileRead
 {
 public:
   /// Constructor
index f8b857368f149b37458e236274c767159a7efed1..1f6f6d2e29eaedc4dda6921da195554cdbaae480 100755 (executable)
@@ -106,12 +106,34 @@ bool FGPropertyManager::HasNode (const string &path)
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-string FGPropertyManager::GetName( void ) {
+string FGPropertyManager::GetName( void )
+{
   return string( getName() );
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
+string FGPropertyManager::GetPrintableName( void )
+{
+  string temp_string(getName());
+  size_t initial_location=0;
+  size_t found_location;
+
+  found_location = temp_string.rfind("/");
+  if (found_location != string::npos)
+  temp_string = temp_string.substr(found_location);
+
+  found_location = temp_string.find('_',initial_location);
+  while (found_location != string::npos) {
+    temp_string.replace(found_location,1," ");
+    initial_location = found_location+1;
+    found_location = temp_string.find('_',initial_location);
+  }
+  return temp_string;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
 string FGPropertyManager::GetFullyQualifiedName(void) {
     vector<string> stack;
     stack.push_back( getDisplayName(true) );
index ce71615240b62b49bc4f2e2894464f347197372f..3c50322269755a17f36acb917e4feed0e5bcf136 100644 (file)
@@ -115,6 +115,11 @@ class FGPropertyManager : public SGPropertyNode, public FGJSBBase
      */
     string GetName( void );
 
+    /**
+     * Get the name of a node without underscores, etc.
+     */
+    string GetPrintableName( void );
+
     /**
      * Get the fully qualified name of a node
      * This function is very slow, so is probably useful for debugging only.
index 797a5bf497c3028a23f70150fe89cdfec042f86d..7e542fbe9a130f52b5253f9561518f9a5e947ff4 100755 (executable)
@@ -84,7 +84,7 @@ FGScript::FGScript(FGFDMExec* fgex) : FDMExec(fgex)
 
 FGScript::~FGScript()
 {
-  int i;
+  unsigned int i;
   for (i=0; i<local_properties.size(); i++)
     PropertyManager->Untie(local_properties[i]->title);
   
@@ -101,21 +101,16 @@ bool FGScript::LoadScript( string script )
 {
   string aircraft="", initialize="", comparison = "", prop_name="";
   string notifyPropertyName="";
-  Element *document=0, *element=0, *run_element=0, *event_element=0;
+  Element *element=0, *run_element=0, *event_element=0;
   Element *condition_element=0, *set_element=0, *delay_element=0;
   Element *notify_element = 0L, *notify_property_element = 0L;
   Element *property_element = 0L;
   bool result = false;
   double dt = 0.0, value = 0.0;
-  FGXMLParse script_file_parser;
   struct event *newEvent;
   FGCondition *newCondition;
-  ifstream script_file(script.c_str());
 
-  if ( !script_file ) return false;
-
-  readXML(script_file, script_file_parser);
-  document = script_file_parser.GetDocument();
+  document = LoadXMLDocument(script);
 
   if (document->GetName() != string("runscript")) {
     cerr << "File: " << script << " is not a script file" << endl;
@@ -309,20 +304,11 @@ bool FGScript::RunScript(void)
       iEvent->Triggered = true;
     } else if (iEvent->Persistent) {
       iEvent->Triggered = false; // Reset the trigger for persistent events
+      iEvent->Notified = false;  // Also reset the notification flag
     }
 
     if ((currentTime >= iEvent->StartTime) && iEvent->Triggered) {
 
-      if (iEvent->Notify && iEvent->PrevTriggered != iEvent->Triggered) {
-        cout << endl << "  Event " << event_ctr << " (" << iEvent->Name << ")"
-             << " executed at time: " << currentTime << endl;
-        for (j=0; j<iEvent->NotifyProperties.size();j++) {
-          cout << "    " << iEvent->NotifyProperties[j]->GetName()
-               << " = " << iEvent->NotifyProperties[j]->getDoubleValue() << endl;
-        }
-        cout << endl;
-      }
-
       for (i=0; i<iEvent->SetValue.size(); i++) {
         if (iEvent->Transiting[i]) {
           iEvent->TimeSpan = currentTime - iEvent->StartTime;
@@ -349,6 +335,19 @@ bool FGScript::RunScript(void)
           iEvent->SetParam[i]->setDoubleValue(newSetValue);
         }
       }
+
+      // Print notification values after setting them
+      if (iEvent->Notify && !iEvent->Notified) {
+        cout << endl << "  Event " << event_ctr << " (" << iEvent->Name << ")"
+             << " executed at time: " << currentTime << endl;
+        for (j=0; j<iEvent->NotifyProperties.size();j++) {
+          cout << "    " << iEvent->NotifyProperties[j]->GetName()
+               << " = " << iEvent->NotifyProperties[j]->getDoubleValue() << endl;
+        }
+        cout << endl;
+        iEvent->Notified = true;
+      }
+
     }
 
     iEvent++;
index 903057a1de69d41b8366f2e3b6b8c2b8388097d6..4915404756fa7638da0b99e8c0ab458b7258f25d 100644 (file)
@@ -42,6 +42,7 @@ INCLUDES
 #include "FGFDMExec.h"
 #include <math/FGCondition.h>
 #include <vector>
+#include <input_output/FGXMLFileRead.h>
 
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 DEFINITIONS
@@ -162,7 +163,7 @@ CLASS DOCUMENTATION
 CLASS DECLARATION
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
-class FGScript : public FGJSBBase
+class FGScript : public FGJSBBase, public FGXMLFileRead
 {
 public:
   /// Default constructor
@@ -201,6 +202,7 @@ private:
     bool             Triggered;
     bool             PrevTriggered;
     bool             Notify;
+    bool             Notified;
     double           Delay;
     double           StartTime;
     double           TimeSpan;
@@ -221,7 +223,7 @@ private:
       PrevTriggered = false;
       Persistent = false;
       Delay = 0.0;
-      Notify = false;
+      Notify = Notified = false;
       Name = "";
       StartTime = 0.0;
       TimeSpan = 0.0;
index 64d2a38ed6938a0ecd931304c3b25cb87c392484..741a806095ac292e16d1a59b25ebc55ab65e480c 100755 (executable)
@@ -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) {
index 6fff1d27a175b2b60f5fceb8f518782ea5efb5c3..5c53240a68b8dead0eb054582c5e19f6c09c02bd 100644 (file)
@@ -2,6 +2,6 @@ noinst_LIBRARIES = libInputOutput.a
 
 libInputOutput_a_SOURCES = FGGroundCallback.cpp FGPropertyManager.cpp FGScript.cpp FGXMLElement.cpp FGXMLParse.cpp FGfdmSocket.cpp
 
-noinst_HEADERS = FGGroundCallback.h FGPropertyManager.h FGScript.h FGXMLElement.h FGXMLParse.h FGfdmSocket.h 
+noinst_HEADERS = FGGroundCallback.h FGPropertyManager.h FGScript.h FGXMLElement.h FGXMLParse.h FGfdmSocket.h FGXMLFileRead.h
 
 INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim
index dfbbca6e014b851b891c29a483b266f1eaaa1a82..f34afe5923420592ecadda642b44f2bbca6df0a2 100644 (file)
@@ -121,13 +121,6 @@ FGColumnVector3& FGColumnVector3::Normalize(void)
   return *this;
 }
 
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGColumnVector3 FGColumnVector3::multElementWise(const FGColumnVector3& V) const
-{
-  return FGColumnVector3(Entry(1) * V(1), Entry(2) * V(2), Entry(3) * V(3));
-}
-
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 //    The bitmasked value choices are as follows:
 //    unset: In this case (the default) JSBSim would only print
index a17c53561d1cd5fdb83d00f4731213cbe42664e5..85e6bab227304a11ce6dec3df00ede9b7cca63f1 100644 (file)
@@ -282,9 +282,6 @@ public:
       is equal to zero it is left untouched.   */
   FGColumnVector3& Normalize(void);
 
-  // ??? Is this something sensible ??
-  FGColumnVector3 multElementWise(const FGColumnVector3& V) const;
-
   // little trick here.
   struct AssignRef {
     AssignRef(FGColumnVector3& r, int i) : Ref(r), idx(i) {}
index 0625d4d6bd3fcec66c359b67f4f28d52b4a99d26..f040e2a65f59711a4daa52bb205b51f5b2fb7c2e 100755 (executable)
@@ -47,7 +47,6 @@ CLASS IMPLEMENTATION
 FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, string prefix)
                                       : PropertyManager(propMan), Prefix(prefix)
 {
-  int i;
   Element* element;
   string operation, property_name;
   int size = el->GetNumElements();
@@ -92,6 +91,16 @@ FGFunction::FGFunction(FGPropertyManager* propMan, Element* el, string prefix)
   }
 
   element = el->GetElement();
+  if (!element) {
+    cerr << fgred << highint << endl;
+    cerr << "  No element was specified as an argument to the \"" << operation << "\" operation" << endl;
+    cerr << "  This can happen when, for instance, a cos operation is specified and a " << endl;
+    cerr << "  property name is given explicitly, but is not placed within a" << endl;
+    cerr << "  <property></property> element tag pair." << endl;
+    cerr << reset;
+    exit(-2);
+  }
+  
   while (element) {
     operation = element->GetName();
 
@@ -146,7 +155,7 @@ FGFunction::~FGFunction(void)
     PropertyManager->Untie(tmp);
   }
 
-  for (int i=0; i<Parameters.size(); i++) {
+  for (unsigned int i=0; i<Parameters.size(); i++) {
     delete Parameters[i];
   }
 }
@@ -167,7 +176,7 @@ void FGFunction::cacheValue(bool cache)
 
 double FGFunction::GetValue(void) const
 {
-  int i;
+  unsigned int i;
 
   if (cached) return cachedValue;
 
@@ -177,13 +186,19 @@ double FGFunction::GetValue(void) const
   case eTopLevel:
     break;
   case eProduct:
-    for (i=1;i<Parameters.size();i++) temp *= Parameters[i]->GetValue();
+    for (i=1;i<Parameters.size();i++) {
+      temp *= Parameters[i]->GetValue();
+    }
     break;
   case eDifference:
-    for (i=1;i<Parameters.size();i++) temp -= Parameters[i]->GetValue();
+    for (i=1;i<Parameters.size();i++) {
+      temp -= Parameters[i]->GetValue();
+    }
     break;
   case eSum:
-    for (i=1;i<Parameters.size();i++) temp += Parameters[i]->GetValue();
+    for (i=1;i<Parameters.size();i++) {
+      temp += Parameters[i]->GetValue();
+    }
     break;
   case eQuotient:
     temp /= Parameters[1]->GetValue();
index 5d57628b0ed5d29183e5d851f97b2c56702a3bf5..100d5d784d1e9f5d0cd07075ef52cdd1e073ddfe 100644 (file)
@@ -87,8 +87,8 @@ FGTable::FGTable(const FGTable& t) : PropertyManager(t.PropertyManager)
 
   Tables = t.Tables;
   Data = Allocate();
-  for (int r=0; r<=nRows; r++) {
-    for (int c=0; c<=nCols; c++) {
+  for (unsigned int r=0; r<=nRows; r++) {
+    for (unsigned int c=0; c<=nCols; c++) {
       Data[r][c] = t.Data[r][c];
     }
   }
@@ -101,7 +101,7 @@ FGTable::FGTable(const FGTable& t) : PropertyManager(t.PropertyManager)
 
 FGTable::FGTable(FGPropertyManager* propMan, Element* el) : PropertyManager(propMan)
 {
-  int i;
+  unsigned int i;
 
   stringstream buf;
   string property_string;
@@ -287,9 +287,9 @@ FGTable::FGTable(FGPropertyManager* propMan, Element* el) : PropertyManager(prop
 double** FGTable::Allocate(void)
 {
   Data = new double*[nRows+1];
-  for (int r=0; r<=nRows; r++) {
+  for (unsigned int r=0; r<=nRows; r++) {
     Data[r] = new double[nCols+1];
-    for (int c=0; c<=nCols; c++) {
+    for (unsigned int c=0; c<=nCols; c++) {
       Data[r][c] = 0.0;
     }
   }
@@ -306,10 +306,10 @@ FGTable::~FGTable()
   }
 
   if (nTables > 0) {
-    for (int i=0; i<nTables; i++) delete Tables[i];
+    for (unsigned int i=0; i<nTables; i++) delete Tables[i];
     Tables.clear();
   }
-  for (int r=0; r<=nRows; r++) delete[] Data[r];
+  for (unsigned int r=0; r<=nRows; r++) delete[] Data[r];
   delete[] Data;
 
   Debug(1);
@@ -317,11 +317,11 @@ FGTable::~FGTable()
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-int FGTable::FindNumColumns(string test_line)
+unsigned int FGTable::FindNumColumns(string test_line)
 {
   // determine number of data columns in table (first column is row lookup - don't count)
-  int position=0;
-  int nCols=0;
+  size_t position=0;
+  unsigned int nCols=0;
   while ((position = test_line.find_first_not_of(" \t", position)) != string::npos) {
     nCols++;
     position = test_line.find_first_of(" \t", position);
@@ -359,7 +359,7 @@ double FGTable::GetValue(void) const
 double FGTable::GetValue(double key) const
 {
   double Factor, Value, Span;
-  int r=lastRowIndex;
+  unsigned int r = lastRowIndex;
 
   //if the key is off the end of the table, just return the
   //end-of-table value, do not extrapolate
@@ -374,14 +374,12 @@ double FGTable::GetValue(double key) const
   }
 
   // the key is somewhere in the middle, search for the right breakpoint
-  // assume the correct breakpoint has not changed since last frame or
+  // The search is particularly efficient if 
+  // the correct breakpoint has not changed since last frame or
   // has only changed very little
 
-  if ( r > 2 && Data[r-1][0] > key ) {
-    while( Data[r-1][0] > key && r > 2) { r--; }
-  } else if ( Data[r][0] < key ) {
-    while( Data[r][0] <= key && r <= nRows) { r++; }
-  }
+  while (r > 2     && Data[r-1][0] > key) { r--; }
+  while (r < nRows && Data[r][0]   < key) { r++; }
 
   lastRowIndex=r;
   // make sure denominator below does not go to zero.
@@ -404,22 +402,14 @@ double FGTable::GetValue(double key) const
 double FGTable::GetValue(double rowKey, double colKey) const
 {
   double rFactor, cFactor, col1temp, col2temp, Value;
-  int r=lastRowIndex;
-  int c=lastColumnIndex;
-
-  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 {
index e70684095d49d9cae05928ac373e0c03a8ec7906..e3bafc3222ba3e9c1a37116e452a56e71c0508fb 100644 (file)
@@ -299,8 +299,8 @@ private:
   FGPropertyManager *lookupProperty[3];
   double** Data;
   vector <FGTable*> Tables;
-  int  FindNumColumns(string);
-  int nRows, nCols, nTables, dimension;
+  unsigned int FindNumColumns(string);
+  unsigned int nRows, nCols, nTables, dimension;
   int colCounter, rowCounter, tableCounter;
   mutable int lastRowIndex, lastColumnIndex, lastTableIndex;
   double** Allocate(void);
index afcedd6cc11a19e62464190aba7fe8e4efd82d93..ce92ff6eb5a32f729ffdaa1194c09562e7881ade 100644 (file)
@@ -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
index 8e75ce0588b4bf9fc1e07c7a74eaa1c3bf418cd1..9d7d31dcbc5c6bb590c8e55a2a416e8bf5963e80 100644 (file)
@@ -353,8 +353,6 @@ void FGAerodynamics::bind(void)
 
 void FGAerodynamics::unbind(void)
 {
-  unsigned i,j;
-
   PropertyManager->Untie("forces/fbx-aero-lbs");
   PropertyManager->Untie("forces/fby-aero-lbs");
   PropertyManager->Untie("forces/fbz-aero-lbs");
@@ -374,7 +372,6 @@ void FGAerodynamics::unbind(void)
   PropertyManager->Untie("aero/alpha-wing-rad");
   PropertyManager->Untie("aero/stall-hyst-norm");
   PropertyManager->Untie("systems/stall-warn-norm");
-
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
index 4e4b6536089f2541f2cda8c164069bd16176258c..edce3e0a3fbcb5b3ea15d9f452fdda8087557f68 100644 (file)
@@ -94,6 +94,7 @@ FGAircraft::FGAircraft(FGFDMExec* fdmex) : FGModel(fdmex)
   lbarh = lbarv = 0.0;
   vbarh = vbarv = 0.0;
   WingIncidence = 0.0;
+  HoldDown = 0;
 
   bind();
 
@@ -116,14 +117,18 @@ bool FGAircraft::Run(void)
   if (FDMExec->Holding()) return false;
 
   vForces.InitMatrix();
-  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");
index 6a882e11a5e91cfe4a5f31bd345dd6f9552c8207..f62ef276a5c56ba306c1ae110ccab040b94268b0 100644 (file)
@@ -151,6 +151,8 @@ public:
   inline double GetXYZvrp(int idx) const { return vXYZvrp(idx); }
   inline double GetXYZep(int idx) const { return vXYZep(idx); }
   inline void SetAircraftName(string name) {AircraftName = name;}
+  inline void SetHoldDown(int hd) {HoldDown = hd;}
+  inline int GetHoldDown(void) const {return HoldDown;}
 
   void SetXYZrp(int idx, double value) {vXYZrp(idx) = value;}
 
@@ -175,6 +177,7 @@ private:
   double WingArea, WingSpan, cbar, WingIncidence;
   double HTailArea, VTailArea, HTailArm, VTailArm;
   double lbarh,lbarv,vbarh,vbarv;
+  int HoldDown;
   string AircraftName;
 
   void Debug(int from);
index 86d1cbdc53f7e6323e760eb2c49d56ac59d2bb59..bc684ce9cabc2c6388f2203712239b34fe4ea6bc 100755 (executable)
@@ -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);
index faf95af847659ec67c8d965d097153ae4ab81d15..cf41c57555baf6a7ed3365ece6449323cf530df4 100644 (file)
@@ -52,6 +52,7 @@ INCLUDES
 #include <models/flight_control/FGKinemat.h>
 #include <models/flight_control/FGFCSFunction.h>
 #include <models/flight_control/FGSensor.h>
+#include <models/flight_control/FGActuator.h>
 
 namespace JSBSim {
 
@@ -147,7 +148,9 @@ bool FGFCS::Run(void)
 
   // Cycle through the sensor, autopilot, and flight control components
   for (i=0; i<sensors.size(); i++) sensors[i]->Run();
-  for (i=0; i<APComponents.size(); i++) APComponents[i]->Run();
+  for (i=0; i<APComponents.size(); i++) {
+    APComponents[i]->Run();
+  }
   for (i=0; i<FCSComponents.size(); i++) FCSComponents[i]->Run();
 
   return false;
@@ -456,10 +459,8 @@ bool FGFCS::Load(Element* el)
 {
   string name, file, fname, interface_property_string;
   vector <FGFCSComponent*> *Components;
-  Element *document, *component_element, *property_element, *sensor_element;
+  Element *component_element, *property_element, *sensor_element;
   Element *channel_element;
-  ifstream* controls_file = new ifstream();
-  FGXMLParse controls_file_parser;
 
   Components=0;
   // Determine if the FCS/Autopilot is defined inline in the aircraft configuration
@@ -479,10 +480,7 @@ bool FGFCS::Load(Element* el)
       cerr << "FCS/Autopilot does not appear to be defined inline nor in a file" << endl;
       return false;
     } else {
-      controls_file->open(file.c_str());
-      readXML(*controls_file, controls_file_parser);
-      delete controls_file;
-      document = controls_file_parser.GetDocument();
+      document = LoadXMLDocument(file);
     }
   } else {
     document = el;
@@ -554,6 +552,8 @@ bool FGFCS::Load(Element* el)
           Components->push_back(new FGFCSFunction(this, component_element));
         } else if (component_element->GetName() == string("pid")) {
           Components->push_back(new FGPID(this, component_element));
+        } else if (component_element->GetName() == string("actuator")) {
+          Components->push_back(new FGActuator(this, component_element));
         } else {
           cerr << "Unknown FCS component: " << component_element->GetName() << endl;
         }
@@ -604,7 +604,9 @@ string FGFCS::GetComponentStrings(string delimeter)
 
   for (comp = 0; comp < APComponents.size(); comp++)
   {
-    CompStrings += delimeter;
+    if (firstime) firstime = false;
+    else          CompStrings += delimeter;
+
     CompStrings += APComponents[comp]->GetName();
   }
 
@@ -629,7 +631,10 @@ string FGFCS::GetComponentValues(string delimeter)
   }
 
   for (comp = 0; comp < APComponents.size(); comp++) {
-    sprintf(buffer, "%s%9.6f", delimeter.c_str(), APComponents[comp]->GetOutput());
+    if (firstime) firstime = false;
+    else          CompValues += delimeter;
+
+    sprintf(buffer, "%9.6f", APComponents[comp]->GetOutput());
     CompValues += string(buffer);
   }
 
@@ -663,6 +668,13 @@ void FGFCS::AddGear(void)
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
+double FGFCS::GetDt(void)
+{
+  return FDMExec->GetDeltaT()*rate;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
 void FGFCS::bind(void)
 {
   PropertyManager->Tie("fcs/aileron-cmd-norm", this, &FGFCS::GetDaCmd, &FGFCS::SetDaCmd);
index 10c582d1032705495fd2fbc70b63ce227718f011..b07800fb71345ead5b440dbaa7464c02544343d4 100644 (file)
@@ -53,7 +53,7 @@ INCLUDES
 #include <models/flight_control/FGFCSComponent.h>
 #include <models/FGModel.h>
 #include <models/FGLGear.h>
-#include <input_output/FGXMLElement.h>
+#include <input_output/FGXMLFileRead.h>
 
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 DEFINITIONS
@@ -191,7 +191,8 @@ CLASS DOCUMENTATION
 CLASS DECLARATION
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
-class FGFCS : public FGModel {
+class FGFCS : public FGModel, public FGXMLFileRead
+{
 
 public:
   /** Constructor
@@ -523,6 +524,7 @@ public:
 
   void AddThrottle(void);
   void AddGear(void);
+  double GetDt(void);
 
   FGPropertyManager* GetPropertyManager(void) { return PropertyManager; }
 
index a82a281a124372aefceb2ae368fae26d893d769f..c8bf6ab9e589ab85d0b19411692eda4ba0cf595b 100644 (file)
@@ -64,7 +64,7 @@ FGGroundReactions::FGGroundReactions(FGFDMExec* fgex) : FGModel(fgex)
 
 FGGroundReactions::~FGGroundReactions(void)
 {
-  for (int i=0; i<lGear.size();i++) lGear[i].unbind();
+  for (unsigned int i=0; i<lGear.size();i++) lGear[i].unbind();
   lGear.clear();
 
   unbind();
@@ -106,7 +106,7 @@ bool FGGroundReactions::Run(void)
 bool FGGroundReactions::GetWOW(void)
 {
   bool result = false;
-  for (int i=0; i<lGear.size(); i++) {
+  for (unsigned int i=0; i<lGear.size(); i++) {
     if (lGear[i].IsBogey() && lGear[i].GetWOW()) {
       result = true;
       break;
@@ -130,7 +130,7 @@ bool FGGroundReactions::Load(Element* el)
     contact_element = el->FindNextElement("contact");
   }
 
-  for (int i=0; i<lGear.size();i++) lGear[i].bind();
+  for (unsigned int i=0; i<lGear.size();i++) lGear[i].bind();
 
   return true;
 }
@@ -149,11 +149,13 @@ string FGGroundReactions::GetGroundReactionStrings(string delimeter)
           << name << " stroke velocity (ft/sec)" << delimeter
           << name << " compress force (lbs)" << delimeter
           << name << " wheel side force (lbs)" << delimeter
-          << name << " wheel velocity vec X (ft/sec)" << delimeter
-          << name << " wheel velocity vec Y (ft/sec)" << delimeter
           << name << " wheel roll force (lbs)" << delimeter
           << name << " body X force (lbs)" << delimeter
           << name << " body Y force (lbs)" << delimeter
+          << name << " wheel velocity vec X (ft/sec)" << delimeter
+          << name << " wheel velocity vec Y (ft/sec)" << delimeter
+          << name << " wheel rolling velocity (ft/sec)" << delimeter
+          << name << " wheel side velocity (ft/sec)" << delimeter
           << name << " wheel slip (deg)" << delimeter;
     }
   }
@@ -181,12 +183,14 @@ string FGGroundReactions::GetGroundReactionValues(string delimeter)
           << setprecision(5) << gear.GetCompLen() << delimeter
           << setprecision(6) << gear.GetCompVel() << delimeter
           << setprecision(10) << gear.GetCompForce() << delimeter
-          << setprecision(6) << gear.GetWheelVel(eX) << delimeter
-          << gear.GetWheelVel(eY) << delimeter
           << gear.GetWheelSideForce() << delimeter
           << gear.GetWheelRollForce() << delimeter
           << gear.GetBodyXForce() << delimeter
           << gear.GetBodyYForce() << delimeter
+          << setprecision(6) << gear.GetWheelVel(eX) << delimeter
+          << gear.GetWheelVel(eY) << delimeter
+          << gear.GetWheelRollVel() << delimeter
+          << gear.GetWheelSideVel() << delimeter
           << gear.GetWheelSlipAngle() << delimeter;
     }
   }
index 9f20531a303cf247478c0317b106a9b07235432e..412dd7c27b798846d32179532c3acbc50ad236a4 100755 (executable)
@@ -206,7 +206,7 @@ bool FGInput::Load(Element* element)
   string name="", fname="";
   string property;
 
-  port = element->GetAttributeValueAsNumber("port");
+  port = int(element->GetAttributeValueAsNumber("port"));
   if (port == 0) {
     cerr << endl << "No port assigned in input element" << endl;
   } else {
index 201d0ed85d0a10a5104719b85fbe09cf02b81fe9..b11041c9a4a542b9118705026a0863406c2699eb 100644 (file)
@@ -88,7 +88,7 @@ FGLGear::FGLGear(Element* el, FGFDMExec* fdmex, int number) : Exec(fdmex),
   if (el->FindElement("max_steer"))
     maxSteerAngle = el->FindElementValueAsNumberConvertTo("max_steer", "DEG");
   if (el->FindElement("retractable"))
-    isRetractable = (int)el->FindElementValueAsNumber("retractable");
+    isRetractable = ((unsigned int)el->FindElementValueAsNumber("retractable"))>0.0?true:false;
 
   ForceY_Table = 0;
   force_table = el->FindElement("table");
@@ -332,8 +332,9 @@ FGColumnVector3& FGLGear::Force(void)
 
     // Compute the forces in the wheel ground plane.
 
-    RollingForce = (1.0 - TirePressureNorm) * 30
-                   + vLocalForce(eZ) * BrakeFCoeff * (RollingWhlVel>=0?1.0:-1.0);
+    RollingForce = ((1.0 - TirePressureNorm) * 30
+                   + vLocalForce(eZ) * BrakeFCoeff) * (RollingWhlVel>=0?1.0:-1.0);
+
     SideForce    = vLocalForce(eZ) * FCoeff;
 
     // Transform these forces back to the local reference frame.
@@ -380,7 +381,7 @@ FGColumnVector3& FGLGear::Force(void)
     if ((fabs(RollingWhlVel) <= RFRV) && RFRV > 0) vForce(eX) *= fabs(RollingWhlVel)/RFRV;
     if ((fabs(SideWhlVel) <= SFRV) && SFRV > 0) vForce(eY) *= fabs(SideWhlVel)/SFRV;
 
-// End experimental section for attentuating gear jitter
+// End section for attentuating gear jitter
 
     vMoment = vWhlBodyVec * vForce;
 
@@ -426,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;
 
index e35d2b7c40fc78bdba0fe656b8bf7c5fe986d008..fdfa809c9d7b7590bc7091ff2bcf17bae229b17c 100644 (file)
@@ -244,6 +244,8 @@ public:
   inline bool GetGearUnitDown(void)        { return GearDown;        }
   inline double GetWheelSideForce(void)    { return SideForce;       }
   inline double GetWheelRollForce(void)    { return RollingForce;    }
+  inline double GetWheelSideVel(void)      { return SideWhlVel;      }
+  inline double GetWheelRollVel(void)      { return RollingWhlVel;   }
   inline double GetBodyXForce(void)        { return vLocalForce(eX); }
   inline double GetBodyYForce(void)        { return vLocalForce(eY); }
   inline double GetWheelSlipAngle(void)    { return WheelSlip;       }
index e5a868f8320d8737c11e476b6c8fb38c1a92025a..f39e97a65cb1eef8839af06a097973d6525ab9eb 100644 (file)
@@ -104,11 +104,11 @@ bool FGMassBalance::Load(Element* el)
   EmptyWeight = el->FindElementValueAsNumberConvertTo("emptywt", "LBS");
 
   element = el->FindElement("location");
-   while (element) {
-     element_name = element->GetAttributeValue("name");
-     if (element_name == "CG") vbaseXYZcg = element->FindElementTripletConvertTo("IN");
-     element = el->FindNextElement("location");
-   }
+  while (element) {
+    element_name = element->GetAttributeValue("name");
+    if (element_name == "CG") vbaseXYZcg = element->FindElementTripletConvertTo("IN");
+    element = el->FindNextElement("location");
+  }
 
 // Find all POINTMASS elements that descend from this METRICS branch of the
 // config file.
@@ -281,11 +281,11 @@ void FGMassBalance::bind(void)
                        &FGMassBalance::GetMass);
   PropertyManager->Tie("inertia/weight-lbs", this,
                        &FGMassBalance::GetWeight);
-  PropertyManager->Tie("inertia/cg-x-ft", this,1,
+  PropertyManager->Tie("inertia/cg-x-in", this,1,
                        (PMF)&FGMassBalance::GetXYZcg);
-  PropertyManager->Tie("inertia/cg-y-ft", this,2,
+  PropertyManager->Tie("inertia/cg-y-in", this,2,
                        (PMF)&FGMassBalance::GetXYZcg);
-  PropertyManager->Tie("inertia/cg-z-ft", this,3,
+  PropertyManager->Tie("inertia/cg-z-in", this,3,
                        (PMF)&FGMassBalance::GetXYZcg);
 }
 
@@ -295,9 +295,9 @@ void FGMassBalance::unbind(void)
 {
   PropertyManager->Untie("inertia/mass-slugs");
   PropertyManager->Untie("inertia/weight-lbs");
-  PropertyManager->Untie("inertia/cg-x-ft");
-  PropertyManager->Untie("inertia/cg-y-ft");
-  PropertyManager->Untie("inertia/cg-z-ft");
+  PropertyManager->Untie("inertia/cg-x-in");
+  PropertyManager->Untie("inertia/cg-y-in");
+  PropertyManager->Untie("inertia/cg-z-in");
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -335,7 +335,7 @@ void FGMassBalance::Debug(int from)
       cout << "    EmptyWeight: " << EmptyWeight << " lbm" << endl;
       cout << "    CG (x, y, z): " << vbaseXYZcg << endl;
       // ToDo: Need to add point mass outputs here
-      for (int i=0; i<PointMasses.size(); i++) {
+      for (unsigned int i=0; i<PointMasses.size(); i++) {
         cout << "    Point Mass Object: " << PointMasses[i].Weight << " lbs. at "
                    << "X, Y, Z (in.): " << PointMasses[i].Location(eX) << "  "
                    << PointMasses[i].Location(eY) << "  "
index 39be607d5b62ca47ca7e3eeaa5789c29a15387cd..64aaf018f0195d888615fb1d8142933049594317 100644 (file)
@@ -145,6 +145,8 @@ void FGOutput::DelimitedOutput(string fname)
 
   ostream outstream(buffer);
 
+  outstream.precision(10);
+
   if (dFirstPass) {
     outstream << "Time";
     if (SubSystems & ssSimulation) {
@@ -235,7 +237,7 @@ void FGOutput::DelimitedOutput(string fname)
     }
     if (OutputProperties.size() > 0) {
       for (unsigned int i=0;i<OutputProperties.size();i++) {
-        outstream << delimeter << OutputProperties[i]->GetName();
+        outstream << delimeter << OutputProperties[i]->GetPrintableName();
       }
     }
 
@@ -260,8 +262,8 @@ void FGOutput::DelimitedOutput(string fname)
   }
   if (SubSystems & ssRates) {
     outstream << delimeter;
-    outstream << Propagate->GetPQR().Dump(delimeter) << delimeter;
-    outstream << Propagate->GetPQRdot().Dump(delimeter);
+    outstream << (radtodeg*Propagate->GetPQR()).Dump(delimeter) << delimeter;
+    outstream << (radtodeg*Propagate->GetPQRdot()).Dump(delimeter);
   }
   if (SubSystems & ssVelocities) {
     outstream << delimeter;
@@ -297,7 +299,7 @@ void FGOutput::DelimitedOutput(string fname)
   if (SubSystems & ssPropagate) {
     outstream << delimeter;
     outstream << Propagate->Geth() << delimeter;
-    outstream << Propagate->GetEuler().Dump(delimeter) << delimeter;
+    outstream << (radtodeg*Propagate->GetEuler()).Dump(delimeter) << delimeter;
     outstream << Auxiliary->Getalpha(inDegrees) << delimeter;
     outstream << Auxiliary->Getbeta(inDegrees) << delimeter;
     outstream << Propagate->GetLocation().GetLatitudeDeg() << delimeter;
@@ -417,13 +419,13 @@ void FGOutput::SocketOutput(void)
     }
     if (SubSystems & ssPropagate) {
         socket->Append("Altitude");
-        socket->Append("Phi");
-        socket->Append("Tht");
-        socket->Append("Psi");
-        socket->Append("Alpha");
-        socket->Append("Beta");
-        socket->Append("Latitude (Deg)");
-        socket->Append("Longitude (Deg)");
+        socket->Append("Phi (deg)");
+        socket->Append("Tht (deg)");
+        socket->Append("Psi (deg)");
+        socket->Append("Alpha (deg)");
+        socket->Append("Beta (deg)");
+        socket->Append("Latitude (deg)");
+        socket->Append("Longitude (deg)");
     }
     if (SubSystems & ssCoefficients) {
       scratch = Aerodynamics->GetCoefficientStrings(",");
@@ -441,7 +443,7 @@ void FGOutput::SocketOutput(void)
     }
     if (OutputProperties.size() > 0) {
       for (unsigned int i=0;i<OutputProperties.size();i++) {
-        socket->Append(OutputProperties[i]->GetName());
+        socket->Append(OutputProperties[i]->GetPrintableName());
       }
     }
 
@@ -464,12 +466,12 @@ void FGOutput::SocketOutput(void)
     socket->Append(FCS->GetDfPos());
   }
   if (SubSystems & ssRates) {
-    socket->Append(Propagate->GetPQR(eP));
-    socket->Append(Propagate->GetPQR(eQ));
-    socket->Append(Propagate->GetPQR(eR));
-    socket->Append(Propagate->GetPQRdot(eP));
-    socket->Append(Propagate->GetPQRdot(eQ));
-    socket->Append(Propagate->GetPQRdot(eR));
+    socket->Append(radtodeg*Propagate->GetPQR(eP));
+    socket->Append(radtodeg*Propagate->GetPQR(eQ));
+    socket->Append(radtodeg*Propagate->GetPQR(eR));
+    socket->Append(radtodeg*Propagate->GetPQRdot(eP));
+    socket->Append(radtodeg*Propagate->GetPQRdot(eQ));
+    socket->Append(radtodeg*Propagate->GetPQRdot(eR));
   }
   if (SubSystems & ssVelocities) {
     socket->Append(Auxiliary->Getqbar());
@@ -521,9 +523,9 @@ void FGOutput::SocketOutput(void)
   }
   if (SubSystems & ssPropagate) {
     socket->Append(Propagate->Geth());
-    socket->Append(Propagate->GetEuler(ePhi));
-    socket->Append(Propagate->GetEuler(eTht));
-    socket->Append(Propagate->GetEuler(ePsi));
+    socket->Append(radtodeg*Propagate->GetEuler(ePhi));
+    socket->Append(radtodeg*Propagate->GetEuler(eTht));
+    socket->Append(radtodeg*Propagate->GetEuler(ePsi));
     socket->Append(Auxiliary->Getalpha(inDegrees));
     socket->Append(Auxiliary->Getbeta(inDegrees));
     socket->Append(Propagate->GetLocation().GetLatitudeDeg());
@@ -574,9 +576,7 @@ bool FGOutput::Load(Element* element)
   int OutRate = 0;
   string property;
   unsigned int port;
-  FGXMLParse output_file_parser;
-  Element *document, *property_element;
-  ifstream* output_file = new ifstream();
+  Element *property_element;
 
   string separator = "/";
 # ifdef macintosh
@@ -596,16 +596,7 @@ bool FGOutput::Load(Element* element)
     } else {
       output_file_name = FDMExec->GetFullAircraftPath() + separator + fname + ".xml";
     }
-    output_file->open(output_file_name.c_str());
-    if (output_file->is_open()) {
-      readXML(*output_file, output_file_parser);
-      delete output_file;
-    } else {
-      delete output_file;
-      cerr << "Could not open directives file: " << output_file_name << endl;
-      return false;
-    }
-    document = output_file_parser.GetDocument();
+    document = LoadXMLDocument(output_file_name);
   } else {
     document = element;
   }
index 7126624a24ba5e9fc84c75b024bd444e56d7126e..8d3f00b9ed44aec2ac682c547840aa095cd7b60e 100644 (file)
@@ -55,7 +55,7 @@ INCLUDES
 #endif
 
 #include <input_output/FGfdmSocket.h>
-#include <input_output/FGXMLElement.h>
+#include <input_output/FGXMLFileRead.h>
 
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 DEFINITIONS
@@ -123,7 +123,7 @@ CLASS DOCUMENTATION
 CLASS DECLARATION
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
-class FGOutput : public FGModel
+class FGOutput : public FGModel, public FGXMLFileRead
 {
 public:
   FGOutput(FGFDMExec*);
index db2ff3f92589bf7c7424dd4325edf80eb57fa07e..a1211cd621baf494a2c3ccfd327ca9beed0c240e 100644 (file)
@@ -98,6 +98,18 @@ FGPropagate::FGPropagate(FGFDMExec* fdmex) : FGModel(fdmex)
   Name = "FGPropagate";
 //  vQtrndot.zero();
 
+  last2_vPQRdot.InitMatrix();
+  last_vPQRdot.InitMatrix();
+  vPQRdot.InitMatrix();
+  
+  last2_vUVWdot.InitMatrix();
+  last_vUVWdot.InitMatrix();
+  vUVWdot.InitMatrix();
+  
+  last2_vLocationDot.InitMatrix();
+  last_vLocationDot.InitMatrix();
+  vLocationDot.InitMatrix();
+
   bind();
   Debug(0);
 }
index 35f420a5bc38632fabb030ba44e32b9b186db615..a6f45021fb8a3d2972cc66a5ee9ef389dff78fa4 100644 (file)
@@ -199,11 +199,7 @@ bool FGPropulsion::ICEngineStart(void)
 bool FGPropulsion::Load(Element* el)
 {
   string type, engine_filename;
-  int Feed;
   bool ThrottleAdded = false;
-  Element* document;
-  FGXMLParse engine_file_parser;
-  ifstream* engine_file;
 
   Debug(2);
 
@@ -217,8 +213,7 @@ bool FGPropulsion::Load(Element* el)
     }
 
     engine_filename = FindEngineFullPathname(engine_filename);
-    readXML(engine_filename, engine_file_parser);
-    document = engine_file_parser.GetDocument(); // document holds the engine description
+    document = LoadXMLDocument(engine_filename);
     document->SetParent(engine_element);
 
     type = document->GetName();
@@ -253,7 +248,7 @@ bool FGPropulsion::Load(Element* el)
     numEngines++;
 
     engine_element = el->FindNextElement("engine");
-    engine_file_parser.reset();
+    ResetParser();
   }
 
   // Process tank definitions
@@ -488,7 +483,7 @@ void FGPropulsion::SetCutoff(int setting)
 
 void FGPropulsion::SetActiveEngine(int engine)
 {
-  if (engine >= Engines.size() || engine < 0)
+  if (engine >= (int)Engines.size() || engine < 0)
     ActiveEngine = -1;
   else
     ActiveEngine = engine;
index e25f46fd13b503d2164b1984b895dd9cfc32e132..9884f61c34ead2be26452f3f89e05cd500248d25 100644 (file)
@@ -59,7 +59,7 @@ INCLUDES
 #include <models/propulsion/FGEngine.h>
 #include <models/propulsion/FGTank.h>
 #include <math/FGMatrix33.h>
-#include <input_output/FGXMLElement.h>
+#include <input_output/FGXMLFileRead.h>
 
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 DEFINITIONS
@@ -97,7 +97,7 @@ CLASS DOCUMENTATION
 CLASS DECLARATION
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
-class FGPropulsion : public FGModel
+class FGPropulsion : public FGModel, public FGXMLFileRead
 {
 public:
   /// Constructor
diff --git a/src/FDM/JSBSim/models/flight_control/FGActuator.cpp b/src/FDM/JSBSim/models/flight_control/FGActuator.cpp
new file mode 100755 (executable)
index 0000000..3a06e89
--- /dev/null
@@ -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 (executable)
index 0000000..a420cbe
--- /dev/null
@@ -0,0 +1,176 @@
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header:       FGActuator.h
+ Author:       Jon Berndt
+ Date started: 21 February 2007
+
+ ------------- Copyright (C) 2006 Jon S. Berndt (jsb@hal-pc.org) -------------
+
+ This program is free software; you can redistribute it and/or modify it under
+ the terms of the GNU Lesser General Public License as published by the Free Software
+ Foundation; either version 2 of the License, or (at your option) any later
+ version.
+
+ This program is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
+ details.
+
+ You should have received a copy of the GNU Lesser General Public License along with
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ Place - Suite 330, Boston, MA  02111-1307, USA.
+
+ Further information about the GNU Lesser General Public License can also be found on
+ the world wide web at http://www.gnu.org.
+
+HISTORY
+--------------------------------------------------------------------------------
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGACTUATOR_H
+#define FGACTUATOR_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGFCSComponent.h"
+#include <input_output/FGXMLElement.h>
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_ACTUATOR "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+class FGFCS;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Encapsulates an Actuator component for the flight control system.
+    The actuator can be modeled as a "perfect actuator", with the Output
+    being set directly to the input. The actuator can be made more "real"
+    by specifying any/all of the following additional effects that can be
+    applied to the actuator. In order of application to the input signal,
+    these are:
+    
+    -System lag (input lag, really)
+    -Rate limiting
+    -Deadband
+    -Hysteresis (mechanical hysteresis)
+    -Bias (mechanical bias)
+    -Position limiting ("hard stops")
+    
+    There are also several malfunctions that can be applied to the actuator
+    by setting a property to true or false (or 1 or 0).
+
+Syntax:
+
+@code
+<actuator name=\94name\94>
+  <input> {[-]property} </input>
+  <lag> number </lag>
+  <rate_limit> number <rate_limit>
+  <bias> number </bias>
+  <deadband_width> number </deadband_width>
+  <hysteresis_width> number </hysteresis_width>
+  [<clipto>
+    <min> {property name | value} </min>
+    <max> {property name | value} </max>
+   </clipto>]
+  [<output> {property} </output>]
+</actuator>
+@endcode
+
+Example:
+
+@code
+<actuator name=\94fcs/gimbal_pitch_position\94>
+  <input> fcs/gimbal_pitch_command </input>
+  <lag> 60 </lag>
+  <rate_limit> 0.085 <rate_limit> <!-- 5 degrees/sec -->
+  <bias> 0.002 </bias>
+  <deadband_width> 0.002 </deadband_width>
+  <hysteresis_width> 0.05 </hysteresis_width>
+  <clipto> <!-- +/- 10 degrees -->
+    <min> -0.17 </min>
+    <max>  0.17 </max>
+   </clipto>
+</actuator>
+@endcode
+
+@author Jon S. Berndt
+@version $Revision$
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGActuator  : public FGFCSComponent
+{
+public:
+  /// Constructor
+  FGActuator(FGFCS* fcs, Element* element);
+  /// Destructor
+  ~FGActuator();
+
+  /** This function processes the input.
+      It calls private functions if needed to perform the hysteresis, lag,
+      limiting, etc. functions. */
+  bool Run (void);
+
+  // these may need to have the bool argument replaced with a double
+  /** This function fails the actuator to zero. The motion to zero
+      will flow through the lag, hysteresis, and rate limiting
+      functions if those are activated. */
+  inline void SetFailZero(bool set) {fail_zero = set;}
+  inline void SetFailHardover(bool set) {fail_hardover = set;}
+  inline void SetFailStuck(bool set) {fail_stuck = set;}
+
+  inline bool GetFailZero(void) const {return fail_zero;}
+  inline bool GetFailHardover(void) const {return fail_hardover;}
+  inline bool GetFailStuck(void) const {return fail_stuck;}
+  
+private:
+  double dt;
+  double span;
+  double bias;
+  double rate_limit;
+  double hysteresis_width;
+  double deadband_width;
+  double lag;
+  double ca; // lag filter coefficient "a"
+  double cb; // lag filter coefficient "b"
+  double PreviousOutput;
+  double PreviousHystOutput;
+  double PreviousRateLimOutput;
+  double PreviousLagInput;
+  double PreviousLagOutput;
+  bool fail_zero;
+  bool fail_hardover;
+  bool fail_stuck;
+
+  void Hysteresis(void);
+  void Lag(void);
+  void RateLimit(void);
+  void Deadband(void);
+  void Bias(void);
+
+  void bind(void);
+
+  void Debug(int from);
+};
+}
+#endif
index 177055becc379d49b0ddb3387853f0225346fb92..b7f31b6d39c26ac2d0579e8b8429994b832ee205 100644 (file)
@@ -89,6 +89,8 @@ FGFCSComponent::FGFCSComponent(FGFCS* _fcs, Element* element) : fcs(_fcs)
     Type = "PID";
   } else if (element->GetName() == string("sensor")) {
     Type = "SENSOR";
+  } else if (element->GetName() == string("actuator")) {
+    Type = "ACTUATOR";
   } else { // illegal component in this channel
     Type = "UNKNOWN";
   }
index cd6559b089bb1d48cecd0bc71e17d47c268371b1..b47aed33302b4dd7b04986ba8db1c1e219225f34 100755 (executable)
@@ -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);
index 3b60b1a748b5bf06ebd768c023bdf266fb460aa5..7917d1fedd74c6ad7e06f4c8417b87891f22ffb4 100755 (executable)
@@ -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;
index f0055616cdb8e97fe8b999759ca298ef65b47d29..72278f05901c3bd08b60da8521ef5184057281d0 100755 (executable)
@@ -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
index 267258336554dc1ccd2e9d27be50bade954c76ba..4789996b7819374519446600aa7a3daf03b133a4 100755 (executable)
@@ -63,7 +63,7 @@ CLASS DOCUMENTATION
 Syntax:
 
 @code
-<sensor name=\94name\94 rate_group=\94name\94>
+<sensor name=\94name\94>
   <input> property </input>
   <lag> number </lag>
   <noise variation=\94PERCENT|ABSOLUTE\94> number </noise>
@@ -80,7 +80,7 @@ Syntax:
 Example:
 
 @code
-<sensor name=\94aero/sensor/qbar\94 rate_group=\94HFCS\94>
+<sensor name=\94aero/sensor/qbar\94>
   <input> aero/qbar </input>
   <lag> 0.5 </lag>
   <noise variation=\94PERCENT\94> 2 </noise>
@@ -124,6 +124,7 @@ public:
   inline double GetFailLow(void) const {if (fail_low) return 1.0; else return 0.0;}
   inline double GetFailHigh(void) const {if (fail_high) return 1.0; else return 0.0;}
   inline double GetFailStuck(void) const {if (fail_stuck) return 1.0; else return 0.0;}
+  inline int    GetQuantized(void) const {return quantized;}
 
   bool Run (void);
 
@@ -149,6 +150,7 @@ private:
   bool fail_low;
   bool fail_high;
   bool fail_stuck;
+  string quant_property;
 
   void Noise(void);
   void Bias(void);
index a28aeddddd8a9dcfdd56d112a56a9baf5ad72d6b..782cc0eec830dddd270f0cca1b740ad1345993ba 100644 (file)
@@ -94,7 +94,7 @@ FGSwitch::FGSwitch(FGFCS* fcs, Element* element) : FGFCSComponent(fcs, element)
       else { // error
         cerr << "Unrecognized LOGIC token " << logic << " in switch component: " << Name << endl;
       }
-      for (int i=0; i<test_element->GetNumDataLines(); i++)
+      for (unsigned int i=0; i<test_element->GetNumDataLines(); i++)
         current_test->conditions.push_back(FGCondition(test_element->GetDataLine(i), PropertyManager));
 
       condition_element = test_element->GetElement(); // retrieve condition groups
index e81ce1480cd2a04bab6613f7a3bfd0261b67ee21..5ccfe5cae63226d3da7183e1de433b489731f522 100644 (file)
@@ -2,10 +2,11 @@ noinst_LIBRARIES = libFlightControl.a
 
 libFlightControl_a_SOURCES = FGPID.cpp FGDeadBand.cpp FGFCSComponent.cpp \
                             FGFilter.cpp FGGain.cpp FGGradient.cpp FGKinemat.cpp \
-                            FGSummer.cpp FGSwitch.cpp FGFCSFunction.cpp FGSensor.cpp
+                            FGSummer.cpp FGSwitch.cpp FGFCSFunction.cpp FGSensor.cpp \
+                            FGActuator.cpp
 
 noinst_HEADERS = FGPID.h FGDeadBand.h FGFCSComponent.h FGFilter.h \
                  FGGain.h FGGradient.h FGKinemat.h FGSummer.h FGSwitch.h FGFCSFunction.h \
-                 FGSensor.h
+                 FGSensor.h FGActuator.h
 
 INCLUDES = -I$(top_srcdir)/src/FDM/JSBSim
index ac55b0aed123bb697f98f5b93b4d9aac695e8860..b40cdb3490a0d36e8cfe6e9980c6fe387dd6d713 100644 (file)
@@ -113,7 +113,7 @@ FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number)
   else      cerr << "No engine location found for this engine." << endl;
 
   local_element = engine_element->GetParent()->FindElement("orient");
-  if (local_element)  orientation = local_element->FindElementTripletConvertTo("IN");
+  if (local_element)  orientation = local_element->FindElementTripletConvertTo("DEG");
   else          cerr << "No engine orientation found for this engine." << endl;
 
   SetPlacement(location, orientation);
@@ -247,12 +247,9 @@ bool FGEngine::LoadThruster(Element *thruster_element)
 {
   string token, fullpath, localpath;
   string thruster_filename, thruster_fullpathname, thrType;
-  double xLoc, yLoc, zLoc, Pitch, Yaw;
   double P_Factor = 0, Sense = 0.0;
   string enginePath = FDMExec->GetEnginePath();
   string aircraftPath = FDMExec->GetFullAircraftPath();
-  FGXMLParse thruster_file_parser;
-  Element *document, *element;
   ifstream thruster_file;
   FGColumnVector3 location, orientation;
   string separator = "/";
@@ -285,8 +282,7 @@ bool FGEngine::LoadThruster(Element *thruster_element)
     return false;
   }
 
-  readXML(thruster_fullpathname, thruster_file_parser);
-  document = thruster_file_parser.GetDocument(); // document holds the thruster description
+  document = LoadXMLDocument(thruster_fullpathname);
   document->SetParent(thruster_element);
 
   thrType = document->GetName();
@@ -336,8 +332,8 @@ void FGEngine::Debug(int from)
       cout << "      X = " << Thruster->GetLocationX() << endl;
       cout << "      Y = " << Thruster->GetLocationY() << endl;
       cout << "      Z = " << Thruster->GetLocationZ() << endl;
-      cout << "      Pitch = " << Thruster->GetAnglesToBody(ePitch) << endl;
-      cout << "      Yaw = " << Thruster->GetAnglesToBody(eYaw) << endl;
+      cout << "      Pitch = " << radtodeg*Thruster->GetAnglesToBody(ePitch) << " degrees" << endl;
+      cout << "      Yaw = " << radtodeg*Thruster->GetAnglesToBody(eYaw) << " degrees" << endl;
     }
   }
   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
index 07c4c60e1a0201e438375f62207432fb420b349c..f60db357d163eaba546442e4bc4c8727045f3106 100644 (file)
@@ -60,6 +60,7 @@ INCLUDES
 #include <FGJSBBase.h>
 #include "FGThruster.h"
 #include <input_output/FGPropertyManager.h>
+#include <input_output/FGXMLFileRead.h>
 
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 DEFINITIONS
@@ -102,7 +103,7 @@ CLASS DOCUMENTATION
 CLASS DECLARATION
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
-class FGEngine : public FGJSBBase
+class FGEngine : public FGJSBBase, public FGXMLFileRead
 {
 public:
   FGEngine(FGFDMExec* exec, Element* el, int engine_number);
index 1dffff82d0b1698f62ca24fb0446e8134bb9c9fc..fec3686d9bd8db7f44dba2515661b69218c01eae 100644 (file)
@@ -61,7 +61,6 @@ FGForce::FGForce(FGFDMExec *FDMExec) :
   mT(1,1) = 1; //identity matrix
   mT(2,2) = 1;
   mT(3,3) = 1;
-  vSense.InitMatrix(1);
 
   Debug(0);
 }
@@ -77,7 +76,7 @@ FGForce::~FGForce()
 
 FGColumnVector3& FGForce::GetBodyForces(void)
 {
-  vFb = Transform()*(vFn.multElementWise(vSense));
+  vFb = Transform()*vFn;
 
   // Find the distance from this vector's acting location to the cg; this
   // needs to be done like this to convert from structural to body coords.
@@ -110,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();
   }
 }
 
index 767e269417b968f04ff91f1456f56bde4464eade..ce62f239b5ff12fff59da21e54bb00ff5abe2424 100644 (file)
@@ -151,7 +151,7 @@ can now be retrieved by calling:</p>
 
 <p>This method is where the bulk of the work gets done so calling it more than
 once for the same set of native forces and moments should probably be avoided.
-Note that the moment calculations are done here as well so they should not be
+Note that the moment calculations are done here as well so they should be
 retrieved after calling the GetBodyForces() method:</p>
 
 <p><tt>vM=fgf.GetMoments();</tt> </p>
@@ -230,24 +230,7 @@ public:
   /// Destructor
   ~FGForce();
 
-  enum TransformType { tNone, tWindBody, tLocalBody, tCustom } ttype;
-
-  inline void SetNativeForces(double Fnx, double Fny, double Fnz) {
-    vFn(1)=Fnx;
-    vFn(2)=Fny;
-    vFn(3)=Fnz;
-  }
-  inline void SetNativeForces(FGColumnVector3 vv) { vFn = vv; };
-
-  inline void SetNativeMoments(double Ln,double Mn, double Nn) {
-    vMn(1)=Ln;
-    vMn(2)=Mn;
-    vMn(3)=Nn;
-  }
-  inline void SetNativeMoments(FGColumnVector3 vv) { vMn = vv; }
-
-  inline FGColumnVector3& GetNativeForces(void) { return vFn; }
-  inline FGColumnVector3& GetNativeMoments(void) { return vMn; }
+  enum TransformType { tNone, tWindBody, tLocalBody, tCustom };
 
   FGColumnVector3& GetBodyForces(void);
 
@@ -305,18 +288,15 @@ public:
     SetAnglesToBody(vv(eRoll), vv(ePitch), vv(eYaw));
   }
 
-  void SetPitch(double pitch) {vOrient(ePitch) = pitch;}
-  void SetYaw(double yaw) {vOrient(eYaw) = yaw;}
+  void UpdateCustomTransformMatrix(void);
+  void SetPitch(double pitch) {vOrient(ePitch) = pitch; UpdateCustomTransformMatrix();}
+  void SetYaw(double yaw) {vOrient(eYaw) = yaw; UpdateCustomTransformMatrix();}
 
   double GetPitch(void) const {return vOrient(ePitch);}
   double GetYaw(void) const {return vOrient(eYaw);}
 
-  inline void SetSense(double x, double y, double z) { vSense(eX)=x, vSense(eY)=y, vSense(eZ)=z; }
-  inline void SetSense(FGColumnVector3 vv) { vSense=vv; }
-
   inline FGColumnVector3& GetAnglesToBody(void) {return vOrient;}
   inline double GetAnglesToBody(int axis) {return vOrient(axis);}
-  inline FGColumnVector3& GetSense(void) { return vSense; }
 
   inline void SetTransformType(TransformType ii) { ttype=ii; }
   inline TransformType GetTransformType(void) { return ttype; }
@@ -329,14 +309,14 @@ protected:
   FGColumnVector3 vMn;
   FGColumnVector3 vH;
   FGColumnVector3 vOrient;
+  TransformType ttype;
+  FGColumnVector3 vXYZn;
+  FGColumnVector3 vActingXYZn;
 
 private:
   FGColumnVector3 vFb;
   FGColumnVector3 vM;
-  FGColumnVector3 vXYZn;
-  FGColumnVector3 vActingXYZn;
   FGColumnVector3 vDXYZ;
-  FGColumnVector3 vSense;
 
   FGMatrix33 mT;
 
index 5b0b58a20d29fcf8a3e8b7c814d1929e236b19d5..476f4a988884487f2200c35491cadac83344c46d 100644 (file)
@@ -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();
 }
index 94b54c35d6ce6b24495a6560fd773a5ac4a3476f..3526b6d7d8c163597a0fe7dcfa769e96d52bc43c 100644 (file)
@@ -198,7 +198,7 @@ FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number)
   }
   minMAP = MinManifoldPressure_inHg * 3386.38;  // inHg to Pa
   maxMAP = MaxManifoldPressure_inHg * 3386.38;
-  StarterHP = sqrt(MaxHP) * 0.2;
+  StarterHP = sqrt(MaxHP) * 0.4;
 
   // Set up and sanity-check the turbo/supercharging configuration based on the input values.
   if (TakeoffBoost > RatedBoost[0]) bTakeoffBoost = true;
@@ -580,7 +580,7 @@ void FGPiston::doEnginePower(void)
       if (RPM < 10) {
         HP = StarterHP;
       } else if (RPM < 480) {
-        HP = StarterHP + ((480 - RPM) / 10.0);
+        HP = StarterHP + ((480 - RPM) / 8.0);
         // This is a guess - would be nice to find a proper starter moter torque curve
       } else {
         HP = StarterHP;
@@ -593,7 +593,7 @@ void FGPiston::doEnginePower(void)
         HP = 0.0;
     }
   }
-  //cout << "Power = " << HP << '\n';
+//  cout << "Power = " << HP << "  RPM = " << RPM << "  Running = " << Running << "  Cranking = " << Cranking << endl;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -729,10 +729,10 @@ string FGPiston::GetEngineLabels(string delimeter)
 {
   std::ostringstream buf;
 
-  buf << Name << "_PwrAvail[" << EngineNumber << "]" << delimeter
-      << Name << "_HP[" << EngineNumber << "]" << delimeter
-      << Name << "_equiv_ratio[" << EngineNumber << "]" << delimeter
-      << Name << "_MAP[" << EngineNumber << "]" << delimeter
+  buf << Name << " Power Available (engine " << EngineNumber << " in HP)" << delimeter
+      << Name << " HP (engine " << EngineNumber << ")" << delimeter
+      << Name << " equivalent ratio (engine " << EngineNumber << ")" << delimeter
+      << Name << " MAP (engine " << EngineNumber << ")" << delimeter
       << Thruster->GetThrusterLabels(EngineNumber, delimeter);
 
   return buf.str();
index ea5ad91b209d6fd60489fc175b594763adc99534..4925d5a0509a3501a84c12240fefce89a6526ca4 100644 (file)
@@ -60,7 +60,6 @@ FGPropeller::FGPropeller(FGFDMExec* exec, Element* prop_element, int num)
                        : FGThruster(exec, prop_element, num)
 {
   string token;
-  int rows, cols;
   Element *table_element, *local_element;
   string name="";
   FGPropertyManager* PropertyManager = exec->GetPropertyManager();
@@ -297,13 +296,13 @@ string FGPropeller::GetThrusterLabels(int id, string delimeter)
 {
   std::ostringstream buf;
 
-  buf << Name << "_Torque[" << id << "]" << delimeter
-      << Name << "_PFactor_Pitch[" << id << "]" << delimeter
-      << Name << "_PFactor_Yaw[" << id << "]" << delimeter
-      << Name << "_Thrust[" << id << "]" << delimeter;
+  buf << Name << " Torque (engine " << id << ")" << delimeter
+      << Name << " PFactor Pitch (engine " << id << ")" << delimeter
+      << Name << " PFactor Yaw (engine " << id << ")" << delimeter
+      << Name << " Thrust (engine " << id << " in lbs)" << delimeter;
   if (IsVPitch())
-    buf << Name << "_Pitch[" << id << "]" << delimeter;
-  buf << Name << "_RPM[" << id << "]";
+    buf << Name << " Pitch (engine " << id << ")" << delimeter;
+  buf << Name << " RPM (engine " << id << ")";
 
   return buf.str();
 }
index d4c0fa0e13fc4f8f6766351f5d63a8448f8babbc..ada946f9df24c2c1175518a7a6e10e48e553f75f 100644 (file)
@@ -54,6 +54,15 @@ CLASS IMPLEMENTATION
 FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number)
   : FGEngine(exec, el, engine_number)
 {
+  Element* thrust_table_element = 0;
+  ThrustTable = 0L;
+  BurnTime = 0.0;
+
+  // Defaults
+   Variance = 0.0;
+   MinThrottle = 0.0;
+   MaxThrottle = 1.0;
+
   if (el->FindElement("shr"))
     SHR = el->FindElementValueAsNumber("shr");
   if (el->FindElement("max_pc"))
@@ -71,6 +80,11 @@ FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number)
   if (el->FindElement("variance"))
     Variance = el->FindElementValueAsNumber("variance");
 
+  thrust_table_element = el->FindElement("thrust_table");
+  if (thrust_table_element) {
+    ThrustTable = new FGTable(PropertyManager, thrust_table_element);
+  }
+
   Debug(0);
 
   Type = etRocket;
@@ -97,6 +111,18 @@ double FGRocket::Calculate(void)
 
   Throttle = FCS->GetThrottlePos(EngineNumber);
 
+  // If there is a thrust table, it is a function of elapsed burn time. The engine
+  // is started when the throttle is advanced to 1.0. After that, it burns
+  // without regard to throttle setting. The table returns a value between zero
+  // and one, representing the percentage of maximum vacuum thrust being applied.
+
+  if (ThrustTable != 0L) {
+    if (Throttle == 1 || BurnTime > 0.0) {
+      BurnTime += State->Getdt();
+    }
+    Throttle = ThrustTable->GetValue(BurnTime);
+  }
+
   if (Throttle < MinThrottle || Starved) {
     PctPower = Thrust = 0.0; // desired thrust
     Flameout = true;
@@ -122,7 +148,7 @@ string FGRocket::GetEngineLabels(string delimeter)
 {
   std::ostringstream buf;
 
-  buf << Name << "_ChamberPress[" << EngineNumber << "]" << delimeter
+  buf << Name << " Chamber Pressure (engine " << EngineNumber << " in psf)" << delimeter
       << Thruster->GetThrusterLabels(EngineNumber, delimeter);
 
   return buf.str();
index eac74251c3b077bec252226377a52c34aeb23674..42436cc335bc32714c1ad65959884e14281c3d6d 100644 (file)
@@ -39,6 +39,7 @@ INCLUDES
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
 #include "FGEngine.h"
+#include <math/FGTable.h>
 #include <input_output/FGXMLElement.h>
 
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -83,6 +84,45 @@ CLASS DOCUMENTATION
     coefficient is multiplied by the chamber pressure and then passed
     to the nozzle Calculate() routine, where the thrust force is
     determined.
+    
+    One can model the thrust of a solid rocket by providing a normalized thrust table
+    as a function of time. For instance, the space shuttle solid rocket booster
+    normalized thrust value looks roughly like this:
+
+<pre>    
+  <thrust_table name="propulsion/thrust_time" type="internal">
+    <tableData>
+      0.0   0.00
+      0.2   0.91
+      8.0   0.97
+     16.0   0.99
+     20.0   1.00
+     21.0   1.00
+     24.0   0.95
+     32.0   0.85
+     40.0   0.78
+     48.0   0.72
+     50.0   0.71
+     52.0   0.71
+     56.0   0.73
+     64.0   0.78
+     72.0   0.82
+     80.0   0.81
+     88.0   0.73
+     96.0   0.69
+    104.0   0.59
+    112.0   0.46
+    120.0   0.09
+    132.0   0.00
+    </tableData>
+  </thrust_table>
+</pre>
+
+The left column is time, the right column is normalized thrust. Inside the
+FGRocket class code, the maximum thrust is calculated, and multiplied by this
+table. The Rocket class also tracks burn time. All that needs to be done is
+for the rocket engine to be throttle up to 1. At that time, the solid rocket
+fuel begins burning and thrust is provided.
 
     @author Jon S. Berndt
     $Id$
@@ -133,7 +173,9 @@ private:
   double kFactor;
   double Variance;
   double PC;
+  double BurnTime;
   bool Flameout;
+  FGTable* ThrustTable;
 
   void Debug(int from);
 };
index 8cf4bf894c09951d798e2e49cd2ce89a6d42c7d0..02875b2a1de08da56f5a56ab5d57675062bbbec8 100644 (file)
@@ -58,7 +58,7 @@ FGThruster::FGThruster(FGFDMExec *FDMExec, Element *el, int num ): FGForce(FDMEx
   Type = ttDirect;
   SetTransformType(FGForce::tCustom);
 
-  Name = el->GetName();
+  Name = el->GetAttributeValue("name");
 
   GearRatio = 1.0;
   ReverserAngle = 0.0;
@@ -73,7 +73,7 @@ FGThruster::FGThruster(FGFDMExec *FDMExec, Element *el, int num ): FGForce(FDMEx
   else          cerr << "No thruster location found." << endl;
 
   element = thruster_element->FindElement("orient");
-  if (element)  orientation = element->FindElementTripletConvertTo("IN");
+  if (element)  orientation = element->FindElementTripletConvertTo("RAD");
   else          cerr << "No thruster orientation found." << endl;
 
   SetLocation(location);
@@ -122,7 +122,7 @@ string FGThruster::GetThrusterLabels(int id, string delimeter)
 {
   std::ostringstream buf;
 
-  buf << Name << "_Thrust[" << id << "]";
+  buf << Name << " Thrust (engine " << id << " in lbs)";
 
   return buf.str();
 }
index 057d961f009dc7428e8db251fd6e255c63ba1983..6191e21492f80d535287117469c1ba8d020c3aab 100755 (executable)
@@ -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;
 
 //---