]> git.mxchange.org Git - flightgear.git/commitdiff
Latest JSBSim updates.
authordavid <david>
Mon, 5 Aug 2002 20:13:34 +0000 (20:13 +0000)
committerdavid <david>
Mon, 5 Aug 2002 20:13:34 +0000 (20:13 +0000)
20 files changed:
src/FDM/JSBSim/FGAtmosphere.cpp
src/FDM/JSBSim/FGFCS.cpp
src/FDM/JSBSim/FGFDMExec.cpp
src/FDM/JSBSim/FGGroundReactions.cpp
src/FDM/JSBSim/FGInertial.cpp
src/FDM/JSBSim/FGInertial.h
src/FDM/JSBSim/FGInitialCondition.cpp
src/FDM/JSBSim/FGLGear.cpp
src/FDM/JSBSim/FGLGear.h
src/FDM/JSBSim/FGOutput.cpp
src/FDM/JSBSim/FGPosition.cpp
src/FDM/JSBSim/FGPosition.h
src/FDM/JSBSim/FGPropulsion.cpp
src/FDM/JSBSim/FGPropulsion.h
src/FDM/JSBSim/FGRotation.cpp
src/FDM/JSBSim/FGRotation.h
src/FDM/JSBSim/FGState.cpp
src/FDM/JSBSim/FGState.h
src/FDM/JSBSim/FGTranslation.cpp
src/FDM/JSBSim/FGTranslation.h

index e2ea8131d1aababaae5576e0a6f8ee43ea2ce97e..0e945a3cc677ab312ccb3ccd90c65cf52cf6a33e 100644 (file)
@@ -152,10 +152,10 @@ bool FGAtmosphere::Run(void)
 
     Debug(2);
 
+       return false;
   } else {                               // skip Run() execution this time
+       return true;
   }
-
-  return false;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
index 57e73bf8c0aa7411a16eb6ac214f9361351e4518..d14fbe3221b36b3efee77773abd19e8526da8444 100644 (file)
@@ -120,10 +120,11 @@ bool FGFCS::Run(void)
     for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i];
     for (i=0; i<Components.size(); i++)  Components[i]->Run();
     if (DoNormalize) Normalize();
+
+       return false;
   } else {
+       return true;
   }
-
-  return false;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
index a9cdac8e797b8e03f8dba80528a6742f1cb41af6..2b1d08973e2abd4c188af6e5bb12e7434dea0573 100644 (file)
@@ -114,9 +114,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root)
   frozen = false;
   modelLoaded = false;
   IsSlave = false;
-  
-  cout << "FGFDMExec::FGFDMExec, FDMctr: " << FDMctr << endl;
-  
+
   IdFDM = FDMctr;
   FDMctr++;
   
@@ -132,6 +130,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root)
   else            master = root;
 
   instance = master->GetNode("/fdm/jsbsim",IdFDM,true);
+  instance->SetDouble("zero",0);  
   
   Debug(0);
   
@@ -157,8 +156,7 @@ FGFDMExec::~FGFDMExec()
 
   for (unsigned int i=1; i<SlaveFDMList.size(); i++) delete SlaveFDMList[i]->exec;
   SlaveFDMList.clear();
-  cout << "FGFDMExec::~FGFDMExec, FDMctr: " << FDMctr << endl;
-  FDMctr--;
   Debug(1);
 }
 
@@ -339,9 +337,9 @@ bool FGFDMExec::Run(void)
     // Run(i)
   }
 
-  while (!model_iterator->Run()) {
+  while (model_iterator != 0L) {
+    model_iterator->Run();
     model_iterator = model_iterator->NextModel;
-    if (model_iterator == 0L) break;
   }
 
   frame = Frame++;
index c95b42edb80c9c1cc06b1bcb67ee19d17e75e8d6..6762719868d0a2f8e948cac8eaf4b0caa29a9fde 100644 (file)
@@ -134,6 +134,8 @@ string FGGroundReactions::GetGroundReactionStrings(void)
     GroundReactionStrings += (lGear[i].GetName() + "_strokeVel, ");
     GroundReactionStrings += (lGear[i].GetName() + "_CompressForce, ");
     GroundReactionStrings += (lGear[i].GetName() + "_WhlSideForce, ");
+    GroundReactionStrings += (lGear[i].GetName() + "_WhlVelVecX, ");
+    GroundReactionStrings += (lGear[i].GetName() + "_WhlVelVecY, ");
     GroundReactionStrings += (lGear[i].GetName() + "_WhlRollForce, ");
     GroundReactionStrings += (lGear[i].GetName() + "_BodyXForce, ");
     GroundReactionStrings += (lGear[i].GetName() + "_BodyYForce, ");
@@ -142,6 +144,13 @@ string FGGroundReactions::GetGroundReactionStrings(void)
     firstime = false;
   }
 
+  GroundReactionStrings += ", TotalGearForce_X, ";
+  GroundReactionStrings += "TotalGearForce_Y, ";
+  GroundReactionStrings += "TotalGearForce_Z, ";
+  GroundReactionStrings += "TotalGearMoment_L, ";
+  GroundReactionStrings += "TotalGearMoment_M, ";
+  GroundReactionStrings += "TotalGearMoment_N";
+
   return GroundReactionStrings;
 }
 
@@ -160,6 +169,8 @@ string FGGroundReactions::GetGroundReactionValues(void)
     GroundReactionValues += (string(gcvt(lGear[i].GetCompLen(),    5, buff)) + ", ");
     GroundReactionValues += (string(gcvt(lGear[i].GetCompVel(),    6, buff)) + ", ");
     GroundReactionValues += (string(gcvt(lGear[i].GetCompForce(), 10, buff)) + ", ");
+    GroundReactionValues += (string(gcvt(lGear[i].GetWheelVel(eX), 6, buff)) + ", ");
+    GroundReactionValues += (string(gcvt(lGear[i].GetWheelVel(eY), 6, buff)) + ", ");
     GroundReactionValues += (string(gcvt(lGear[i].GetWheelSideForce(), 6, buff)) + ", ");
     GroundReactionValues += (string(gcvt(lGear[i].GetWheelRollForce(), 6, buff)) + ", ");
     GroundReactionValues += (string(gcvt(lGear[i].GetBodyXForce(), 6, buff)) + ", ");
@@ -169,6 +180,13 @@ string FGGroundReactions::GetGroundReactionValues(void)
     firstime = false;
   }
 
+  GroundReactionValues += (", " + string(gcvt(vForces(eX), 6, buff)) + ", ");
+  GroundReactionValues += (string(gcvt(vForces(eY), 6, buff)) + ", ");
+  GroundReactionValues += (string(gcvt(vForces(eZ), 6, buff)) + ", ");
+  GroundReactionValues += (string(gcvt(vMoments(eX), 6, buff)) + ", ");
+  GroundReactionValues += (string(gcvt(vMoments(eY), 6, buff)) + ", ");
+  GroundReactionValues += (string(gcvt(vMoments(eZ), 6, buff)));
+
   return GroundReactionValues;
 }
 
index b3d3f598954c2d4658d48525bd44b5a5e077b94c..854ed26da897ffbab53ff19535cd56a1fe0707c4 100644 (file)
@@ -59,7 +59,10 @@ FGInertial::FGInertial(FGFDMExec* fgex) : FGModel(fgex)
   RadiusReference = 20925650.00;
   gAccelReference = GM/(RadiusReference*RadiusReference);
   gAccel          = GM/(RadiusReference*RadiusReference);
-  
+  vCoriolis.InitMatrix();
+  vCentrifugal.InitMatrix();
+  vGravity.InitMatrix();
+    
   bind();
 
   Debug(0);
@@ -77,21 +80,12 @@ FGInertial::~FGInertial(void)
 
 bool FGInertial::Run(void)
 {
-  double stht, ctht, sphi, cphi;
-
   if (!FGModel::Run()) {
 
     gAccel = GM / (Position->GetRadius()*Position->GetRadius());
 
-    stht = sin(Rotation->GetEuler(eTht));
-    ctht = cos(Rotation->GetEuler(eTht));
-    sphi = sin(Rotation->GetEuler(ePhi));
-    cphi = cos(Rotation->GetEuler(ePhi));
+    vGravity(eDown) = gAccel;
 
-    vGravity(eX) = vForces(eX) = -gravity()*stht;
-    vGravity(eY) = vForces(eY) =  gravity()*sphi*ctht;
-    vGravity(eZ) = vForces(eZ) =  gravity()*cphi*ctht;
-    
     // The following equation for vOmegaLocal terms shows the angular velocity
     // calculation _for_the_local_frame_ given the earth's rotation (first set)
     // at the current latitude, and also the component due to the aircraft
@@ -105,12 +99,17 @@ bool FGInertial::Run(void)
     vOmegaLocal(eY) += -Position->GetVn() / Position->GetRadius();
     vOmegaLocal(eZ) +=  0.00;
 
-//    vForces = State->GetTl2b()*(-2.0*vOmegaLocal * Position->GetVel());
+    // Coriolis acceleration is normally written: -2w*dr/dt, but due to the axis
+    // conventions used here the sign is reversed: 2w*dr/dt. The same is true for
+    // Centrifugal acceleration.
+
+    vCoriolis(eEast) = 2.0*omega() * (Position->GetVd()*cos(Position->GetLatitude()) +
+                                      Position->GetVn()*sin(Position->GetLatitude()));
 
-    vRadius(3) = Position->GetRadius();
-    vForces += State->GetTl2b()*(vOmegaLocal * (vOmegaLocal * vRadius));
+    vRadius(eDown) = Position->GetRadius();
+    vCentrifugal(eDown) = -vOmegaLocal.Magnitude() * vOmegaLocal.Magnitude() * vRadius(eDown);
 
-    vForces *= MassBalance->GetMass(); // IMPORTANT !!!!!!!!!!!!!!!!!!!!!!!!!!!!
+    vForces = State->GetTl2b() * MassBalance->GetMass() * (vCoriolis + vCentrifugal + vGravity);
     
     return false;
   } else {
index 569074301e507f585498cc0ef8ed8d22bc4d32f8..1e4a461e9915333d210bc6d2ed095ea23d2341cd 100644 (file)
@@ -75,6 +75,8 @@ public:
   bool Run(void);
   FGColumnVector3& GetForces(void) {return vForces;}
   FGColumnVector3& GetGravity(void) {return vGravity;}
+  FGColumnVector3& GetCoriolis(void) {return vCoriolis;}
+  FGColumnVector3& GetCentrifugal(void) {return vCentrifugal;}
   double GetForces(int n) const {return vForces(n);}
   bool LoadInertial(FGConfigFile* AC_cfg);
   double SLgravity(void) const {return gAccelReference;}
@@ -91,6 +93,8 @@ private:
   FGColumnVector3 vForces;
   FGColumnVector3 vRadius;
   FGColumnVector3 vGravity;
+  FGColumnVector3 vCoriolis;
+  FGColumnVector3 vCentrifugal;
   double gAccel;
   double gAccelReference;
   double RadiusReference;
index 16e37ca7950e5df1d522e75e4a6f99397f2759a2..58d739053263ae76f4e15bcda297c4ee8d1345b7 100644 (file)
@@ -110,7 +110,6 @@ FGInitialCondition::~FGInitialCondition()
 void FGInitialCondition::SetVcalibratedKtsIC(double tt) {
 
   if(getMachFromVcas(&mach,tt*ktstofps)) {
-
     //cout << "Mach: " << mach << endl;
     lastSpeedSet=setvc;
     vc=tt*ktstofps;
index 8f137f88bde4f0e5bd19ad376580eb8b03eaf637..52d834168a59cdc22c5d8cd8ca995a3baec26719 100644 (file)
@@ -104,7 +104,7 @@ FGLGear::FGLGear(FGConfigFile* AC_cfg, FGFDMExec* fdmex) : Exec(fdmex)
   FCS         = Exec->GetFCS();
   MassBalance = Exec->GetMassBalance();
 
-  WOW = lastWOW = false;
+  WOW = lastWOW = true; // should the value be initialized to true?
   ReportEnable = true;
   FirstContact = false;
   Reported = false;
@@ -115,7 +115,7 @@ FGLGear::FGLGear(FGConfigFile* AC_cfg, FGFDMExec* fdmex) : Exec(fdmex)
   vWhlBodyVec     = (vXYZ - MassBalance->GetXYZcg()) / 12.0;
   vWhlBodyVec(eX) = -vWhlBodyVec(eX);
   vWhlBodyVec(eZ) = -vWhlBodyVec(eZ);
-
+  
   vLocalGear = State->GetTb2l() * vWhlBodyVec;
 
   compressLength  = 0.0;
@@ -123,6 +123,13 @@ FGLGear::FGLGear(FGConfigFile* AC_cfg, FGFDMExec* fdmex) : Exec(fdmex)
   brakePct        = 0.0;
   maxCompLen      = 0.0;
 
+  WheelSlip = lastWheelSlip = 0.0;
+
+  compressLength  = 0.0;
+  compressSpeed   = 0.0;
+  brakePct        = 0.0;
+  maxCompLen      = 0.0;
+
   Debug(0);
 }
 
@@ -173,6 +180,8 @@ FGLGear::FGLGear(const FGLGear& lgear)
   isRetractable   = lgear.isRetractable;
   GearUp          = lgear.GearUp;
   GearDown        = lgear.GearDown;
+  WheelSlip       = lgear.WheelSlip;
+  lastWheelSlip   = lgear.lastWheelSlip;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -266,17 +275,17 @@ FGColumnVector3& FGLGear::Force(void)
 
       switch (eBrakeGrp) {
       case bgLeft:
-        SteerGain = -0.10;
+        SteerGain = 0.10;
         BrakeFCoeff = rollingFCoeff*(1.0 - FCS->GetBrake(bgLeft)) +
                                               staticFCoeff*FCS->GetBrake(bgLeft);
         break;
       case bgRight:
-        SteerGain = -0.10;
+        SteerGain = 0.10;
         BrakeFCoeff = rollingFCoeff*(1.0 - FCS->GetBrake(bgRight)) +
                                              staticFCoeff*FCS->GetBrake(bgRight);
         break;
       case bgCenter:
-        SteerGain = -0.10;
+        SteerGain = 0.10;
         BrakeFCoeff = rollingFCoeff*(1.0 - FCS->GetBrake(bgCenter)) +
                                              staticFCoeff*FCS->GetBrake(bgCenter);
         break;
@@ -289,7 +298,7 @@ FGColumnVector3& FGLGear::Force(void)
         BrakeFCoeff = rollingFCoeff;
         break;
       case bgNone:
-        SteerGain = -0.10;
+        SteerGain = 0.0;
         BrakeFCoeff = rollingFCoeff;
         break;
       default:
@@ -326,17 +335,31 @@ FGColumnVector3& FGLGear::Force(void)
 
       if (RollingWhlVel == 0.0 && SideWhlVel == 0.0) {
         WheelSlip = 0.0;
+      } else if (fabs(RollingWhlVel) < 0.10) {
+        WheelSlip = 0.05*radtodeg*atan2(SideWhlVel, RollingWhlVel) + 0.95*WheelSlip;
       } else {
         WheelSlip = radtodeg*atan2(SideWhlVel, RollingWhlVel);
       }
 
+      if ((WheelSlip < 0.0 && lastWheelSlip > 0.0) ||
+          (WheelSlip > 0.0 && lastWheelSlip < 0.0))
+      {
+        WheelSlip = 0.0;
+      }
+      
+      lastWheelSlip = WheelSlip;
+
 // Compute the sideforce coefficients using similar assumptions to LaRCSim for now.
 // Allow a maximum of 10 degrees tire slip angle before wheel slides.  At that point,
 // transition from static to dynamic friction.  There are more complicated formulations
 // of this that avoid the discrete jump.  Will fix this later.
 
-      if (fabs(WheelSlip) <= 10.0) {
-        FCoeff = staticFCoeff*WheelSlip/10.0;
+      if (fabs(WheelSlip) <= 20.0) {
+        FCoeff = staticFCoeff*WheelSlip/20.0;
+      } else if (fabs(WheelSlip) <= 40.0) {
+//        FCoeff = dynamicFCoeff*fabs(WheelSlip)/WheelSlip;
+        FCoeff = (dynamicFCoeff*(fabs(WheelSlip) - 20.0)/20.0 + 
+                  staticFCoeff*(40.0 - fabs(WheelSlip))/20.0)*fabs(WheelSlip)/WheelSlip;
       } else {
         FCoeff = dynamicFCoeff*fabs(WheelSlip)/WheelSlip;
       }
@@ -406,7 +429,7 @@ FGColumnVector3& FGLGear::Force(void)
     }
 
     if (lastWOW != WOW) {
-      PutMessage("GEAR_CONTACT", WOW);
+      PutMessage("GEAR_CONTACT: " + name, WOW);
     }
 
     lastWOW = WOW;
index f9e22797bfae1b794960dbd497473a5798dd924a..8bfc6e21a555521a6f29d5086be304725b1ea8f2 100644 (file)
@@ -244,6 +244,7 @@ public:
   inline double GetBodyXForce(void)        { return vLocalForce(eX); }
   inline double GetBodyYForce(void)        { return vLocalForce(eY); }
   inline double GetWheelSlipAngle(void)    { return WheelSlip;       }
+  double GetWheelVel(int axis)             { return vWhlVelVec(axis);}
   
 private:
   FGColumnVector3 vXYZ;
@@ -270,6 +271,7 @@ private:
   double SideWhlVel, RollingWhlVel;
   double RollingForce, SideForce, FCoeff;
   double WheelSlip;
+  double lastWheelSlip;
   bool WOW;
   bool lastWOW;
   bool FirstContact;
index 4d9e9491900155971430cf3833ea8d578012513c..52fa53841c59b274a4c81400cbf1cfe77471dd36 100644 (file)
@@ -98,8 +98,9 @@ bool FGOutput::Run(void)
       } else {
         // Not a valid type of output
       }
-
+         return false;
     } else {
+         return true;
     }
   }
   return false;
@@ -172,7 +173,10 @@ void FGOutput::DelimitedOutput(string fname)
       outstream << ", ";
       outstream << "Drag, Side, Lift, ";
       outstream << "L/D, ";
-      outstream << "Xforce, Yforce, Zforce";
+      outstream << "Xforce, Yforce, Zforce, ";
+      outstream << "xGravity, yGravity, zGravity, ";
+      outstream << "xCoriolis, yCoriolis, zCoriolis, ";
+      outstream << "xCentrifugal, yCentrifugal, zCentrifugal";
     }
     if (SubSystems & ssMoments) {
       outstream << ", ";
@@ -252,7 +256,10 @@ void FGOutput::DelimitedOutput(string fname)
     outstream << ", ";
     outstream << Aerodynamics->GetvFs() << ", ";
     outstream << Aerodynamics->GetLoD() << ", ";
-    outstream << Aircraft->GetForces();
+    outstream << Aircraft->GetForces() << ", ";
+    outstream << Inertial->GetGravity() << ", ";
+    outstream << Inertial->GetCoriolis() << ", ";
+    outstream << Inertial->GetCentrifugal();
   }
   if (SubSystems & ssMoments) {
     outstream << ", ";
index 01a36c649eae0d284f6142d3fd70ee7e7ed237f8..74cd727bb56134bb4e3c25a20be000043b838d74 100644 (file)
@@ -101,7 +101,13 @@ FGPosition::FGPosition(FGFDMExec* fdmex) : FGModel(fdmex)
 {
   Name = "FGPosition";
   LongitudeDot = LatitudeDot = RadiusDot = 0.0;
-  lastLongitudeDot = lastLatitudeDot = lastRadiusDot = 0.0;
+  
+  for (int i=0;i<3;i++) {
+    LatitudeDot_prev[i]  = 0.0;
+    LongitudeDot_prev[i] = 0.0;
+    RadiusDot_prev[i]    = 0.0;
+  }
+  
   Longitude = Latitude = 0.0;
   gamma = Vt = Vground = 0.0;
   hoverbmac = hoverbcg = 0.0;
@@ -143,7 +149,8 @@ Notes:   [TP] Make sure that -Vt <= hdot <= Vt, which, of course, should always
               In FGFS, SeaLevelRadius is stuffed from FGJSBSim in JSBSim.cxx each pass.
 */
 
-bool FGPosition::Run(void) {
+bool FGPosition::Run(void)
+{
   double cosLat;
   double hdot_Vt;
   FGColumnVector3 vMac;
@@ -160,22 +167,20 @@ bool FGPosition::Run(void) {
 
     cosLat = cos(Latitude);
     if (cosLat != 0) LongitudeDot = vVel(eEast) / (Radius * cosLat);
-
     LatitudeDot = vVel(eNorth) / Radius;
     RadiusDot   = -vVel(eDown);
 
-    Longitude += 0.5*dt*rate*(LongitudeDot + lastLongitudeDot);
-    Latitude  += 0.5*dt*rate*(LatitudeDot + lastLatitudeDot);
-    Radius    += 0.5*dt*rate*(RadiusDot + lastRadiusDot);
+    Longitude += State->Integrate(FGState::TRAPZ, dt*rate, LongitudeDot, LongitudeDot_prev);
+    Latitude  += State->Integrate(FGState::TRAPZ, dt*rate, LatitudeDot, LatitudeDot_prev);
+    Radius    += State->Integrate(FGState::TRAPZ, dt*rate, RadiusDot, RadiusDot_prev);
 
     h = Radius - SeaLevelRadius;           // Geocentric
 
     DistanceAGL = Radius - RunwayRadius;   // Geocentric
     
-    
     hoverbcg = DistanceAGL/b;
     
-    vMac=State->GetTb2l()*Aircraft->GetXYZrp();
+    vMac = State->GetTb2l()*Aircraft->GetXYZrp();
     
     vMac *= inchtoft;
     hoverbmac = (DistanceAGL + vMac(3))/b;
@@ -187,10 +192,6 @@ bool FGPosition::Run(void) {
       gamma = 0.0;
     }
 
-    lastLatitudeDot  = LatitudeDot;
-    lastLongitudeDot = LongitudeDot;
-    lastRadiusDot    = RadiusDot;
-
     return false;
 
   } else {
@@ -200,7 +201,8 @@ bool FGPosition::Run(void) {
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-void FGPosition::GetState(void) {
+void FGPosition::GetState(void)
+{
   dt = State->Getdt();
 
   Vt        = Translation->GetVt();
@@ -212,7 +214,8 @@ void FGPosition::GetState(void) {
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-void FGPosition::Seth(double tt) {
+void FGPosition::Seth(double tt)
+{
  h = tt;
  Radius    = h + SeaLevelRadius;
  DistanceAGL = Radius - RunwayRadius;   // Geocentric
@@ -221,7 +224,8 @@ void FGPosition::Seth(double tt) {
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-void FGPosition::SetDistanceAGL(double tt) {
+void FGPosition::SetDistanceAGL(double tt)
+{
   DistanceAGL=tt;
   Radius = RunwayRadius + DistanceAGL;
   h = Radius - SeaLevelRadius;
index 0fd024354c8cd6c454ee08fcbe26368ce750dc1d..358d5a0a08b836439cab2c0b13b23b505ca56db4 100644 (file)
@@ -79,6 +79,7 @@ public:
   /** Constructor
       @param Executive a pointer to the parent executive object */
   FGPosition(FGFDMExec*);
+
   /// Destructor
   ~FGPosition();
 
@@ -132,7 +133,7 @@ private:
   
   double Radius, h;
   double LatitudeDot, LongitudeDot, RadiusDot;
-  double lastLatitudeDot, lastLongitudeDot, lastRadiusDot;
+  double LatitudeDot_prev[3], LongitudeDot_prev[3], RadiusDot_prev[3];
   double Longitude, Latitude;
   double dt;
   double RunwayRadius;
index 0b3e2b4f2c320d4d845f299c328b1e4eaf83c5f1..1a2dba8c7d226b12450a06d9dceab085056f6a26 100644 (file)
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module:       FGPropulsion.cpp
- Author:       Jon S. Berndt
- Date started: 08/20/00
- Purpose:      Encapsulates the set of engines, tanks, and thrusters associated
-               with this aircraft
-
- ------------- Copyright (C) 2000  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 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 General Public License for more
- details.
-
- You should have received a copy of the GNU 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 General Public License can also be found on
- the world wide web at http://www.gnu.org.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-The Propulsion class is the container for the entire propulsion system, which is
-comprised of engines, tanks, and "thrusters" (the device that transforms the
-engine power into a force that acts on the aircraft, such as a nozzle or
-propeller). Once the Propulsion class gets the config file, it reads in
-information which is specific to a type of engine. Then:
-
-1) The appropriate engine type instance is created
-2) A thruster object is instantiated, and is linked to the engine
-3) At least one tank object is created, and is linked to an engine.
-
-At Run time each engines Calculate() method is called to return the excess power
-generated during that iteration. The drag from the previous iteration is sub-
-tracted to give the excess power available for thrust this pass. That quantity
-is passed to the thrusters associated with a particular engine - perhaps with a
-scaling mechanism (gearing?) to allow the engine to give its associated thrust-
-ers specific distributed portions of the excess power.
-
-HISTORY
---------------------------------------------------------------------------------
-08/20/00   JSB   Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGPropulsion.h"
-#include "FGPropertyManager.h"
-
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_PROPULSION;
-
-extern short debug_lvl;
-
-#if defined (__APPLE__)
-/* Not all systems have the gcvt function */
-inline char* gcvt (double value, int ndigits, char *buf) {
-    /* note that this is not exactly what gcvt is supposed to do! */
-    snprintf (buf, ndigits+1, "%f", value);
-    return buf;
-}
-#endif
-
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)
-{
-  Name = "FGPropulsion";
-  numSelectedFuelTanks = numSelectedOxiTanks = 0;
-  numTanks = numEngines = numThrusters = 0;
-  numOxiTanks = numFuelTanks = 0;
-  dt = 0.0;
-  bind();
-  Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGPropulsion::~FGPropulsion()
-{
-  for (unsigned int i=0; i<Engines.size(); i++) delete Engines[i];
-  Engines.clear();
-  unbind();
-  Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGPropulsion::Run(void)
-{
-  double PowerAvailable;
-  dt = State->Getdt();
-
-  vForces.InitMatrix();
-  vMoments.InitMatrix();
-
-  if (!FGModel::Run()) {
-    for (unsigned int i=0; i<numEngines; i++) {
-      Thrusters[i]->SetdeltaT(dt*rate);
-      PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());
-      Thrusters[i]->Calculate(PowerAvailable);
-      vForces  += Thrusters[i]->GetBodyForces();  // sum body frame forces
-      vMoments += Thrusters[i]->GetMoments();     // sum body frame moments
-    }
-    return false;
-  } else {
-    return true;
-  }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGPropulsion::GetSteadyState(void)
-{
-  double PowerAvailable;
-  double currentThrust = 0, lastThrust=-1;
-  dt = State->Getdt();
-  int steady_count,j=0;
-  bool steady=false;
-
-  vForces.InitMatrix();
-  vMoments.InitMatrix();
-
-  if (!FGModel::Run()) {
-    for (unsigned int i=0; i<numEngines; i++) {
-      Engines[i]->SetTrimMode(true);
-      Thrusters[i]->SetdeltaT(dt*rate);
-      steady=false;
-      steady_count=0;
-      while (!steady && j < 6000) {
-        PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());
-        lastThrust = currentThrust;
-        currentThrust = Thrusters[i]->Calculate(PowerAvailable);
-        if (fabs(lastThrust-currentThrust) < 0.0001) {
-          steady_count++;
-          if (steady_count > 120) { steady=true; }
-        } else {
-          steady_count=0;
-        }
-        j++;    
-      }
-      vForces  += Thrusters[i]->GetBodyForces();  // sum body frame forces
-      vMoments += Thrusters[i]->GetMoments();     // sum body frame moments
-      Engines[i]->SetTrimMode(false);
-    }
-
-    return false;
-  } else {
-    return true;
-  }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGPropulsion::ICEngineStart(void)
-{
-  double PowerAvailable;
-  int j;
-  dt = State->Getdt();
-
-  vForces.InitMatrix();
-  vMoments.InitMatrix();
-    
-  for (unsigned int i=0; i<numEngines; i++) {
-    Engines[i]->SetTrimMode(true);
-    Thrusters[i]->SetdeltaT(dt*rate);
-    j=0;
-    while (!Engines[i]->GetRunning() && j < 2000) {
-      PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());
-      Thrusters[i]->Calculate(PowerAvailable);
-      j++;    
-    }
-    vForces  += Thrusters[i]->GetBodyForces();  // sum body frame forces
-    vMoments += Thrusters[i]->GetMoments();     // sum body frame moments
-    Engines[i]->SetTrimMode(false);
-  }
-  return true;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGPropulsion::Load(FGConfigFile* AC_cfg)
-{
-  string token, fullpath;
-  string engineFileName, engType;
-  string thrusterFileName, thrType;
-  string parameter;
-  string enginePath = FDMExec->GetEnginePath();
-  double xLoc, yLoc, zLoc, Pitch, Yaw;
-  double P_Factor = 0, Sense = 0.0;
-  int Feed;
-  bool ThrottleAdded = false;
-
-# ifndef macintosh
-      fullpath = enginePath + "/";
-# else
-      fullpath = enginePath + ";";
-# endif
-
-  AC_cfg->GetNextConfigLine();
-
-  while ((token = AC_cfg->GetValue()) != string("/PROPULSION")) {
-
-    if (token == "AC_ENGINE") {                   // ============ READING ENGINES
-
-      engineFileName = AC_cfg->GetValue("FILE");
-
-      if (debug_lvl > 0) cout << "\n    Reading engine from file: " << fullpath
-                                                + engineFileName + ".xml"<< endl;
-      FGConfigFile Eng_cfg(fullpath + engineFileName + ".xml");
-
-      if (Eng_cfg.IsOpen()) {
-        Eng_cfg.GetNextConfigLine();
-        engType = Eng_cfg.GetValue();
-
-        FCS->AddThrottle();
-        ThrottleAdded = true;
-
-        if (engType == "FG_ROCKET") {
-          Engines.push_back(new FGRocket(FDMExec, &Eng_cfg));
-        } else if (engType == "FG_PISTON") {
-          Engines.push_back(new FGPiston(FDMExec, &Eng_cfg));
-        } else if (engType == "FG_TURBOJET") {
-          Engines.push_back(new FGTurboJet(FDMExec, &Eng_cfg));
-        } else if (engType == "FG_TURBOSHAFT") {
-          Engines.push_back(new FGTurboShaft(FDMExec, &Eng_cfg));
-        } else if (engType == "FG_TURBOPROP") {
-          Engines.push_back(new FGTurboProp(FDMExec, &Eng_cfg));
-        } else {
-          cerr << fgred << "    Unrecognized engine type: " << underon << engType
-                    << underoff << " found in config file." << fgdef << endl;
-          return false;
-        }
-
-        AC_cfg->GetNextConfigLine();
-        while ((token = AC_cfg->GetValue()) != string("/AC_ENGINE")) {
-          *AC_cfg >> token;
-          if      (token == "XLOC")  { *AC_cfg >> xLoc; }
-          else if (token == "YLOC")  { *AC_cfg >> yLoc; }
-          else if (token == "ZLOC")  { *AC_cfg >> zLoc; }
-          else if (token == "PITCH") { *AC_cfg >> Pitch;}
-          else if (token == "YAW")   { *AC_cfg >> Yaw;}
-          else if (token == "FEED")  {
-            *AC_cfg >> Feed;
-            Engines[numEngines]->AddFeedTank(Feed);
-            if (debug_lvl > 0) cout << "      Feed tank: " << Feed << endl;
-          } else cerr << "Unknown identifier: " << token << " in engine file: "
-                                                        << engineFileName << endl;
-        }
-
-        if (debug_lvl > 0)  {
-          cout << "      X = " << xLoc << endl;
-          cout << "      Y = " << yLoc << endl;
-          cout << "      Z = " << zLoc << endl;
-          cout << "      Pitch = " << Pitch << endl;
-          cout << "      Yaw = " << Yaw << endl;
-        }
-
-        Engines[numEngines]->SetPlacement(xLoc, yLoc, zLoc, Pitch, Yaw);
-        Engines[numEngines]->SetEngineNumber(numEngines);
-        numEngines++;
-
-      } else {
-
-        cerr << fgred << "\n  Could not read engine config file: " << underon <<
-                    fullpath + engineFileName + ".xml" << underoff << fgdef << endl;
-        return false;
-      }
-
-    } else if (token == "AC_TANK") {              // ============== READING TANKS
-
-      if (debug_lvl > 0) cout << "\n    Reading tank definition" << endl;
-      Tanks.push_back(new FGTank(AC_cfg));
-      switch(Tanks[numTanks]->GetType()) {
-      case FGTank::ttFUEL:
-        numSelectedFuelTanks++;
-        numFuelTanks++;
-        break;
-      case FGTank::ttOXIDIZER:
-        numSelectedOxiTanks++;
-        numOxiTanks++;
-        break;
-      }
-
-      numTanks++;
-
-    } else if (token == "AC_THRUSTER") {          // ========== READING THRUSTERS
-
-      thrusterFileName = AC_cfg->GetValue("FILE");
-
-      if (debug_lvl > 0) cout << "\n    Reading thruster from file: " <<
-                                    fullpath + thrusterFileName + ".xml" << endl;
-      FGConfigFile Thruster_cfg(fullpath + thrusterFileName + ".xml");
-
-      if (Thruster_cfg.IsOpen()) {
-        Thruster_cfg.GetNextConfigLine();
-        thrType = Thruster_cfg.GetValue();
-
-        if (thrType == "FG_PROPELLER") {
-          Thrusters.push_back(new FGPropeller(FDMExec, &Thruster_cfg));
-        } else if (thrType == "FG_NOZZLE") {
-          Thrusters.push_back(new FGNozzle(FDMExec, &Thruster_cfg));
-        }
-
-        AC_cfg->GetNextConfigLine();
-        while ((token = AC_cfg->GetValue()) != string("/AC_THRUSTER")) {
-          *AC_cfg >> token;
-          if (token == "XLOC") *AC_cfg >> xLoc;
-          else if (token == "YLOC") *AC_cfg >> yLoc;
-          else if (token == "ZLOC") *AC_cfg >> zLoc;
-          else if (token == "PITCH") *AC_cfg >> Pitch;
-          else if (token == "YAW") *AC_cfg >> Yaw;
-          else if (token == "P_FACTOR") *AC_cfg >> P_Factor;
-          else if (token == "SENSE")   *AC_cfg >> Sense;
-          else cerr << "Unknown identifier: " << token << " in engine file: "
-                                                        << engineFileName << endl;
-        }
-
-        Thrusters[numThrusters]->SetLocation(xLoc, yLoc, zLoc);
-        Thrusters[numThrusters]->SetAnglesToBody(0, Pitch, Yaw);
-        if (thrType == "FG_PROPELLER" && P_Factor > 0.001) {
-          ((FGPropeller*)Thrusters[numThrusters])->SetPFactor(P_Factor);
-          if (debug_lvl > 0) cout << "      P-Factor: " << P_Factor << endl;
-          ((FGPropeller*)Thrusters[numThrusters])->SetSense(fabs(Sense)/Sense);
-          if (debug_lvl > 0) cout << "      Sense: " << Sense <<  endl;
-        }
-        Thrusters[numThrusters]->SetdeltaT(dt*rate);
-        Thrusters[numThrusters]->SetThrusterNumber(numThrusters);
-        numThrusters++;
-
-      } else {
-        cerr << "Could not read thruster config file: " << fullpath
-                                                + thrusterFileName + ".xml" << endl;
-        return false;
-      }
-
-    }
-    AC_cfg->GetNextConfigLine();
-  }
-
-  if (!ThrottleAdded) FCS->AddThrottle(); // need to have at least one throttle
-
-  return true;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGPropulsion::GetPropulsionStrings(void)
-{
-  string PropulsionStrings = "";
-  bool firstime = true;
-  char buffer[5];
-
-  for (unsigned int i=0;i<Engines.size();i++) {
-    if (firstime)  firstime = false;
-    else           PropulsionStrings += ", ";
-
-    sprintf(buffer, "%d", i);
-
-    switch(Engines[i]->GetType()) {
-    case FGEngine::etPiston:
-      PropulsionStrings += (Engines[i]->GetName() + "_PwrAvail[" + buffer + "]");
-      break;
-    case FGEngine::etRocket:
-      PropulsionStrings += (Engines[i]->GetName() + "_ChamberPress[" + buffer + "]");
-      break;
-    case FGEngine::etTurboJet:
-    case FGEngine::etTurboProp:
-    case FGEngine::etTurboShaft:
-      break;
-    default:
-      PropulsionStrings += "INVALID ENGINE TYPE";
-      break;
-    }
-
-    PropulsionStrings += ", ";
-
-    FGPropeller* Propeller = (FGPropeller*)Thrusters[i];
-    switch(Thrusters[i]->GetType()) {
-    case FGThruster::ttNozzle:
-      PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "]");
-      break;
-    case FGThruster::ttRotor:
-      break;
-    case FGThruster::ttPropeller:
-      PropulsionStrings += (Thrusters[i]->GetName() + "_Torque[" + buffer + "], ");
-      PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Roll[" + buffer + "], ");
-      PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Pitch[" + buffer + "], ");
-      PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Yaw[" + buffer + "], ");
-      PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "], ");
-      if (Propeller->IsVPitch())
-        PropulsionStrings += (Thrusters[i]->GetName() + "_Pitch[" + buffer + "], ");
-      PropulsionStrings += (Thrusters[i]->GetName() + "_RPM[" + buffer + "]");
-      break;
-    default:
-      PropulsionStrings += "INVALID THRUSTER TYPE";
-      break;
-    }    
-  }
-
-  return PropulsionStrings;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGPropulsion::GetPropulsionValues(void)
-{
-  char buff[20];
-  string PropulsionValues = "";
-  bool firstime = true;
-
-  for (unsigned int i=0;i<Engines.size();i++) {
-    if (firstime)  firstime = false;
-    else           PropulsionValues += ", ";
-
-    switch(Engines[i]->GetType()) {
-    case FGEngine::etPiston:
-      PropulsionValues += (string(gcvt(((FGPiston*)Engines[i])->GetPowerAvailable(), 10, buff)));
-      break;
-    case FGEngine::etRocket:
-      PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetChamberPressure(), 10, buff)));
-      break;
-    case FGEngine::etTurboJet:
-    case FGEngine::etTurboProp:
-    case FGEngine::etTurboShaft:
-      break;
-    }
-
-    PropulsionValues += ", ";
-
-    switch(Thrusters[i]->GetType()) {
-    case FGThruster::ttNozzle:
-      PropulsionValues += (string(gcvt(((FGNozzle*)Thrusters[i])->GetThrust(), 10, buff)));
-      break;
-    case FGThruster::ttRotor:
-      break;
-    case FGThruster::ttPropeller:
-      FGPropeller* Propeller = (FGPropeller*)Thrusters[i];
-      FGColumnVector3 vPFactor = Propeller->GetPFactor();
-      PropulsionValues += string(gcvt(Propeller->GetTorque(), 10, buff)) + ", ";
-      PropulsionValues += string(gcvt(vPFactor(eRoll), 10, buff)) + ", ";
-      PropulsionValues += string(gcvt(vPFactor(ePitch), 10, buff)) + ", ";
-      PropulsionValues += string(gcvt(vPFactor(eYaw), 10, buff)) + ", ";
-      PropulsionValues += string(gcvt(Propeller->GetThrust(), 10, buff)) + ", ";
-      if (Propeller->IsVPitch())
-        PropulsionValues += string(gcvt(Propeller->GetPitch(), 10, buff)) + ", ";
-      PropulsionValues += string(gcvt(Propeller->GetRPM(), 10, buff));
-      break;
-    }
-  }
-
-  return PropulsionValues;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGColumnVector3& FGPropulsion::GetTanksMoment(void)
-{
-  iTank = Tanks.begin();
-  vXYZtank.InitMatrix();
-  while (iTank < Tanks.end()) {
-    vXYZtank(eX) += (*iTank)->GetX()*(*iTank)->GetContents();
-    vXYZtank(eY) += (*iTank)->GetY()*(*iTank)->GetContents();
-    vXYZtank(eZ) += (*iTank)->GetZ()*(*iTank)->GetContents();
-    iTank++;
-  }
-  return vXYZtank;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGPropulsion::GetTanksWeight(void)
-{
-  double Tw = 0.0;
-
-  iTank = Tanks.begin();
-  while (iTank < Tanks.end()) {
-    Tw += (*iTank)->GetContents();
-    iTank++;
-  }
-  return Tw;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGPropulsion::GetTanksIxx(const FGColumnVector3& vXYZcg)
-{
-  double I = 0.0;
-  iTank = Tanks.begin();
-  while (iTank < Tanks.end()) {
-    I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetX() - vXYZcg(eX)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
-    iTank++;
-  }
-  return I;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGPropulsion::GetTanksIyy(const FGColumnVector3& vXYZcg)
-{
-  double I = 0.0;
-  iTank = Tanks.begin();
-  while (iTank < Tanks.end()) {
-    I += ((*iTank)->GetY() - vXYZcg(eY))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
-    iTank++;
-  }
-  return I;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGPropulsion::GetTanksIzz(const FGColumnVector3& vXYZcg)
-{
-  double I = 0.0;
-  iTank = Tanks.begin();
-  while (iTank < Tanks.end()) {
-    I += ((*iTank)->GetZ() - vXYZcg(eZ))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
-    iTank++;
-  }
-  return I;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGPropulsion::GetTanksIxz(const FGColumnVector3& vXYZcg)
-{
-  double I = 0.0;
-  iTank = Tanks.begin();
-  while (iTank < Tanks.end()) {
-    I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
-    iTank++;
-  }
-  return I;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGPropulsion::GetTanksIxy(const FGColumnVector3& vXYZcg)
-{
-  double I = 0.0;
-  iTank = Tanks.begin();
-  while (iTank != Tanks.end()) {
-    I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());
-    iTank++;
-  }
-  return I;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropulsion::bind(void)
-{
-  typedef double (FGPropulsion::*PMF)(int) const;
-  /* PropertyManager->Tie("propulsion/num-engines", this,
-                       &FGPropulsion::GetNumEngines);
-  PropertyManager->Tie("propulsion/num-tanks", this,
-                       &FGPropulsion::GetNumTanks); */
-  PropertyManager->Tie("propulsion/num-sel-fuel-tanks", this,
-                       &FGPropulsion::GetnumSelectedFuelTanks);
-  PropertyManager->Tie("propulsion/num-sel-ox-tanks", this,
-                       &FGPropulsion::GetnumSelectedOxiTanks);
-  PropertyManager->Tie("forces/fbx-prop-lbs", this,1,
-                       (PMF)&FGPropulsion::GetForces);
-  PropertyManager->Tie("forces/fby-prop-lbs", this,2,
-                       (PMF)&FGPropulsion::GetForces);
-  PropertyManager->Tie("forces/fbz-prop-lbs", this,3,
-                       (PMF)&FGPropulsion::GetForces);
-  PropertyManager->Tie("moments/l-prop-lbsft", this,1,
-                       (PMF)&FGPropulsion::GetMoments);
-  PropertyManager->Tie("moments/m-prop-lbsft", this,2,
-                       (PMF)&FGPropulsion::GetMoments);
-  PropertyManager->Tie("moments/n-prop-lbsft", this,3,
-                       (PMF)&FGPropulsion::GetMoments);
-  //PropertyManager->Tie("propulsion/tanks-weight-lbs", this,
-  //                     &FGPropulsion::GetTanksWeight);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPropulsion::unbind(void)
-{
-  /* PropertyManager->Untie("propulsion/num-engines");
-  PropertyManager->Untie("propulsion/num-tanks"); */
-  PropertyManager->Untie("propulsion/num-sel-fuel-tanks");
-  PropertyManager->Untie("propulsion/num-sel-ox-tanks");
-  PropertyManager->Untie("forces/fbx-prop-lbs");
-  PropertyManager->Untie("forces/fby-prop-lbs");
-  PropertyManager->Untie("forces/fbz-prop-lbs");
-  PropertyManager->Untie("moments/l-prop-lbsft");
-  PropertyManager->Untie("moments/m-prop-lbsft");
-  PropertyManager->Untie("moments/n-prop-lbsft");
-  //PropertyManager->Untie("propulsion/tanks-weight-lbs");
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-//    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 FGPropulsion::Debug(int from)
-{
-  if (debug_lvl <= 0) return;
-
-  if (debug_lvl & 1) { // Standard console startup message output
-    if (from == 0) { // Constructor
-
-    }
-  }
-  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
-    if (from == 0) cout << "Instantiated: FGPropulsion" << endl;
-    if (from == 1) cout << "Destroyed:    FGPropulsion" << 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;
-    }
-  }
-}
-
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+ Module:       FGPropulsion.cpp\r
+ Author:       Jon S. Berndt\r
+ Date started: 08/20/00\r
+ Purpose:      Encapsulates the set of engines, tanks, and thrusters associated\r
+               with this aircraft\r
+\r
+ ------------- Copyright (C) 2000  Jon S. Berndt (jsb@hal-pc.org) -------------\r
+\r
+ This program is free software; you can redistribute it and/or modify it under\r
+ the terms of the GNU General Public License as published by the Free Software\r
+ Foundation; either version 2 of the License, or (at your option) any later\r
+ version.\r
+\r
+ This program is distributed in the hope that it will be useful, but WITHOUT\r
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
+ FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more\r
+ details.\r
+\r
+ You should have received a copy of the GNU General Public License along with\r
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple\r
+ Place - Suite 330, Boston, MA  02111-1307, USA.\r
+\r
+ Further information about the GNU General Public License can also be found on\r
+ the world wide web at http://www.gnu.org.\r
+\r
+FUNCTIONAL DESCRIPTION\r
+--------------------------------------------------------------------------------\r
+The Propulsion class is the container for the entire propulsion system, which is\r
+comprised of engines, tanks, and "thrusters" (the device that transforms the\r
+engine power into a force that acts on the aircraft, such as a nozzle or\r
+propeller). Once the Propulsion class gets the config file, it reads in\r
+information which is specific to a type of engine. Then:\r
+\r
+1) The appropriate engine type instance is created\r
+2) A thruster object is instantiated, and is linked to the engine\r
+3) At least one tank object is created, and is linked to an engine.\r
+\r
+At Run time each engines Calculate() method is called to return the excess power\r
+generated during that iteration. The drag from the previous iteration is sub-\r
+tracted to give the excess power available for thrust this pass. That quantity\r
+is passed to the thrusters associated with a particular engine - perhaps with a\r
+scaling mechanism (gearing?) to allow the engine to give its associated thrust-\r
+ers specific distributed portions of the excess power.\r
+\r
+HISTORY\r
+--------------------------------------------------------------------------------\r
+08/20/00   JSB   Created\r
+\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+INCLUDES\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/\r
+\r
+#include "FGPropulsion.h"\r
+#include "FGPropertyManager.h"\r
+\r
+\r
+static const char *IdSrc = "$Id$";\r
+static const char *IdHdr = ID_PROPULSION;\r
+\r
+extern short debug_lvl;\r
+\r
+#if defined (__APPLE__)\r
+/* Not all systems have the gcvt function */\r
+inline char* gcvt (double value, int ndigits, char *buf) {\r
+    /* note that this is not exactly what gcvt is supposed to do! */\r
+    snprintf (buf, ndigits+1, "%f", value);\r
+    return buf;\r
+}\r
+#endif\r
+\r
+\r
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+CLASS IMPLEMENTATION\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/\r
+\r
+FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)\r
+{\r
+  Name = "FGPropulsion";\r
+  numSelectedFuelTanks = numSelectedOxiTanks = 0;\r
+  numTanks = numEngines = numThrusters = 0;\r
+  numOxiTanks = numFuelTanks = 0;\r
+  dt = 0.0;\r
+  ActiveEngine = -1; // -1: ALL, 0: Engine 1, 1: Engine 2 ...\r
+  bind();\r
+  Debug(0);\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+FGPropulsion::~FGPropulsion()\r
+{\r
+  for (unsigned int i=0; i<Engines.size(); i++) delete Engines[i];\r
+  Engines.clear();\r
+  unbind();\r
+  Debug(1);\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+bool FGPropulsion::Run(void)\r
+{\r
+  double PowerAvailable;\r
+  dt = State->Getdt();\r
+\r
+  vForces.InitMatrix();\r
+  vMoments.InitMatrix();\r
+\r
+  if (!FGModel::Run()) {\r
+    for (unsigned int i=0; i<numEngines; i++) {\r
+      Thrusters[i]->SetdeltaT(dt*rate);\r
+      PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());\r
+      Thrusters[i]->Calculate(PowerAvailable);\r
+      vForces  += Thrusters[i]->GetBodyForces();  // sum body frame forces\r
+      vMoments += Thrusters[i]->GetMoments();     // sum body frame moments\r
+    }\r
+    return false;\r
+  } else {\r
+    return true;\r
+  }\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+bool FGPropulsion::GetSteadyState(void)\r
+{\r
+  double PowerAvailable;\r
+  double currentThrust = 0, lastThrust=-1;\r
+  dt = State->Getdt();\r
+  int steady_count,j=0;\r
+  bool steady=false;\r
+\r
+  vForces.InitMatrix();\r
+  vMoments.InitMatrix();\r
+\r
+  if (!FGModel::Run()) {\r
+    for (unsigned int i=0; i<numEngines; i++) {\r
+      Engines[i]->SetTrimMode(true);\r
+      Thrusters[i]->SetdeltaT(dt*rate);\r
+      steady=false;\r
+      steady_count=0;\r
+      while (!steady && j < 6000) {\r
+        PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());\r
+        lastThrust = currentThrust;\r
+        currentThrust = Thrusters[i]->Calculate(PowerAvailable);\r
+        if (fabs(lastThrust-currentThrust) < 0.0001) {\r
+          steady_count++;\r
+          if (steady_count > 120) { steady=true; }\r
+        } else {\r
+          steady_count=0;\r
+        }\r
+        j++;    \r
+      }\r
+      vForces  += Thrusters[i]->GetBodyForces();  // sum body frame forces\r
+      vMoments += Thrusters[i]->GetMoments();     // sum body frame moments\r
+      Engines[i]->SetTrimMode(false);\r
+    }\r
+\r
+    return false;\r
+  } else {\r
+    return true;\r
+  }\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+bool FGPropulsion::ICEngineStart(void)\r
+{\r
+  double PowerAvailable;\r
+  int j;\r
+  dt = State->Getdt();\r
+\r
+  vForces.InitMatrix();\r
+  vMoments.InitMatrix();\r
+    \r
+  for (unsigned int i=0; i<numEngines; i++) {\r
+    Engines[i]->SetTrimMode(true);\r
+    Thrusters[i]->SetdeltaT(dt*rate);\r
+    j=0;\r
+    while (!Engines[i]->GetRunning() && j < 2000) {\r
+      PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());\r
+      Thrusters[i]->Calculate(PowerAvailable);\r
+      j++;    \r
+    }\r
+    vForces  += Thrusters[i]->GetBodyForces();  // sum body frame forces\r
+    vMoments += Thrusters[i]->GetMoments();     // sum body frame moments\r
+    Engines[i]->SetTrimMode(false);\r
+  }\r
+  return true;\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+bool FGPropulsion::Load(FGConfigFile* AC_cfg)\r
+{\r
+  string token, fullpath;\r
+  string engineFileName, engType;\r
+  string thrusterFileName, thrType;\r
+  string parameter;\r
+  string enginePath = FDMExec->GetEnginePath();\r
+  double xLoc, yLoc, zLoc, Pitch, Yaw;\r
+  double P_Factor = 0, Sense = 0.0;\r
+  int Feed;\r
+  bool ThrottleAdded = false;\r
+\r
+# ifndef macintosh\r
+      fullpath = enginePath + "/";\r
+# else\r
+      fullpath = enginePath + ";";\r
+# endif\r
+\r
+  AC_cfg->GetNextConfigLine();\r
+\r
+  while ((token = AC_cfg->GetValue()) != string("/PROPULSION")) {\r
+\r
+    if (token == "AC_ENGINE") {                   // ============ READING ENGINES\r
+\r
+      engineFileName = AC_cfg->GetValue("FILE");\r
+\r
+      if (debug_lvl > 0) cout << "\n    Reading engine from file: " << fullpath\r
+                                                + engineFileName + ".xml"<< endl;\r
+      FGConfigFile Eng_cfg(fullpath + engineFileName + ".xml");\r
+\r
+      if (Eng_cfg.IsOpen()) {\r
+        Eng_cfg.GetNextConfigLine();\r
+        engType = Eng_cfg.GetValue();\r
+\r
+        FCS->AddThrottle();\r
+        ThrottleAdded = true;\r
+\r
+        if (engType == "FG_ROCKET") {\r
+          Engines.push_back(new FGRocket(FDMExec, &Eng_cfg));\r
+        } else if (engType == "FG_PISTON") {\r
+          Engines.push_back(new FGPiston(FDMExec, &Eng_cfg));\r
+        } else if (engType == "FG_TURBOJET") {\r
+          Engines.push_back(new FGTurboJet(FDMExec, &Eng_cfg));\r
+        } else if (engType == "FG_TURBOSHAFT") {\r
+          Engines.push_back(new FGTurboShaft(FDMExec, &Eng_cfg));\r
+        } else if (engType == "FG_TURBOPROP") {\r
+          Engines.push_back(new FGTurboProp(FDMExec, &Eng_cfg));\r
+        } else {\r
+          cerr << fgred << "    Unrecognized engine type: " << underon << engType\r
+                    << underoff << " found in config file." << fgdef << endl;\r
+          return false;\r
+        }\r
+\r
+        AC_cfg->GetNextConfigLine();\r
+        while ((token = AC_cfg->GetValue()) != string("/AC_ENGINE")) {\r
+          *AC_cfg >> token;\r
+          if      (token == "XLOC")  { *AC_cfg >> xLoc; }\r
+          else if (token == "YLOC")  { *AC_cfg >> yLoc; }\r
+          else if (token == "ZLOC")  { *AC_cfg >> zLoc; }\r
+          else if (token == "PITCH") { *AC_cfg >> Pitch;}\r
+          else if (token == "YAW")   { *AC_cfg >> Yaw;}\r
+          else if (token == "FEED")  {\r
+            *AC_cfg >> Feed;\r
+            Engines[numEngines]->AddFeedTank(Feed);\r
+            if (debug_lvl > 0) cout << "      Feed tank: " << Feed << endl;\r
+          } else cerr << "Unknown identifier: " << token << " in engine file: "\r
+                                                        << engineFileName << endl;\r
+        }\r
+\r
+        if (debug_lvl > 0)  {\r
+          cout << "      X = " << xLoc << endl;\r
+          cout << "      Y = " << yLoc << endl;\r
+          cout << "      Z = " << zLoc << endl;\r
+          cout << "      Pitch = " << Pitch << endl;\r
+          cout << "      Yaw = " << Yaw << endl;\r
+        }\r
+\r
+        Engines[numEngines]->SetPlacement(xLoc, yLoc, zLoc, Pitch, Yaw);\r
+        Engines[numEngines]->SetEngineNumber(numEngines);\r
+        numEngines++;\r
+\r
+      } else {\r
+\r
+        cerr << fgred << "\n  Could not read engine config file: " << underon <<\r
+                    fullpath + engineFileName + ".xml" << underoff << fgdef << endl;\r
+        return false;\r
+      }\r
+\r
+    } else if (token == "AC_TANK") {              // ============== READING TANKS\r
+\r
+      if (debug_lvl > 0) cout << "\n    Reading tank definition" << endl;\r
+      Tanks.push_back(new FGTank(AC_cfg));\r
+      switch(Tanks[numTanks]->GetType()) {\r
+      case FGTank::ttFUEL:\r
+        numSelectedFuelTanks++;\r
+        numFuelTanks++;\r
+        break;\r
+      case FGTank::ttOXIDIZER:\r
+        numSelectedOxiTanks++;\r
+        numOxiTanks++;\r
+        break;\r
+      }\r
+\r
+      numTanks++;\r
+\r
+    } else if (token == "AC_THRUSTER") {          // ========== READING THRUSTERS\r
+\r
+      thrusterFileName = AC_cfg->GetValue("FILE");\r
+\r
+      if (debug_lvl > 0) cout << "\n    Reading thruster from file: " <<\r
+                                    fullpath + thrusterFileName + ".xml" << endl;\r
+      FGConfigFile Thruster_cfg(fullpath + thrusterFileName + ".xml");\r
+\r
+      if (Thruster_cfg.IsOpen()) {\r
+        Thruster_cfg.GetNextConfigLine();\r
+        thrType = Thruster_cfg.GetValue();\r
+\r
+        if (thrType == "FG_PROPELLER") {\r
+          Thrusters.push_back(new FGPropeller(FDMExec, &Thruster_cfg));\r
+        } else if (thrType == "FG_NOZZLE") {\r
+          Thrusters.push_back(new FGNozzle(FDMExec, &Thruster_cfg));\r
+        }\r
+\r
+        AC_cfg->GetNextConfigLine();\r
+        while ((token = AC_cfg->GetValue()) != string("/AC_THRUSTER")) {\r
+          *AC_cfg >> token;\r
+          if (token == "XLOC") *AC_cfg >> xLoc;\r
+          else if (token == "YLOC") *AC_cfg >> yLoc;\r
+          else if (token == "ZLOC") *AC_cfg >> zLoc;\r
+          else if (token == "PITCH") *AC_cfg >> Pitch;\r
+          else if (token == "YAW") *AC_cfg >> Yaw;\r
+          else if (token == "P_FACTOR") *AC_cfg >> P_Factor;\r
+          else if (token == "SENSE")   *AC_cfg >> Sense;\r
+          else cerr << "Unknown identifier: " << token << " in engine file: "\r
+                                                        << engineFileName << endl;\r
+        }\r
+\r
+        Thrusters[numThrusters]->SetLocation(xLoc, yLoc, zLoc);\r
+        Thrusters[numThrusters]->SetAnglesToBody(0, Pitch, Yaw);\r
+        if (thrType == "FG_PROPELLER" && P_Factor > 0.001) {\r
+          ((FGPropeller*)Thrusters[numThrusters])->SetPFactor(P_Factor);\r
+          if (debug_lvl > 0) cout << "      P-Factor: " << P_Factor << endl;\r
+          ((FGPropeller*)Thrusters[numThrusters])->SetSense(fabs(Sense)/Sense);\r
+          if (debug_lvl > 0) cout << "      Sense: " << Sense <<  endl;\r
+        }\r
+        Thrusters[numThrusters]->SetdeltaT(dt*rate);\r
+        Thrusters[numThrusters]->SetThrusterNumber(numThrusters);\r
+        numThrusters++;\r
+\r
+      } else {\r
+        cerr << "Could not read thruster config file: " << fullpath\r
+                                                + thrusterFileName + ".xml" << endl;\r
+        return false;\r
+      }\r
+\r
+    }\r
+    AC_cfg->GetNextConfigLine();\r
+  }\r
+\r
+  if (!ThrottleAdded) FCS->AddThrottle(); // need to have at least one throttle\r
+\r
+  return true;\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+string FGPropulsion::GetPropulsionStrings(void)\r
+{\r
+  string PropulsionStrings = "";\r
+  bool firstime = true;\r
+  char buffer[5];\r
+\r
+  for (unsigned int i=0;i<Engines.size();i++) {\r
+    if (firstime)  firstime = false;\r
+    else           PropulsionStrings += ", ";\r
+\r
+    sprintf(buffer, "%d", i);\r
+\r
+    switch(Engines[i]->GetType()) {\r
+    case FGEngine::etPiston:\r
+      PropulsionStrings += (Engines[i]->GetName() + "_PwrAvail[" + buffer + "]");\r
+      break;\r
+    case FGEngine::etRocket:\r
+      PropulsionStrings += (Engines[i]->GetName() + "_ChamberPress[" + buffer + "]");\r
+      break;\r
+    case FGEngine::etTurboJet:\r
+    case FGEngine::etTurboProp:\r
+    case FGEngine::etTurboShaft:\r
+      break;\r
+    default:\r
+      PropulsionStrings += "INVALID ENGINE TYPE";\r
+      break;\r
+    }\r
+\r
+    PropulsionStrings += ", ";\r
+\r
+    FGPropeller* Propeller = (FGPropeller*)Thrusters[i];\r
+    switch(Thrusters[i]->GetType()) {\r
+    case FGThruster::ttNozzle:\r
+      PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "]");\r
+      break;\r
+    case FGThruster::ttRotor:\r
+      break;\r
+    case FGThruster::ttPropeller:\r
+      PropulsionStrings += (Thrusters[i]->GetName() + "_Torque[" + buffer + "], ");\r
+      PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Roll[" + buffer + "], ");\r
+      PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Pitch[" + buffer + "], ");\r
+      PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Yaw[" + buffer + "], ");\r
+      PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "], ");\r
+      if (Propeller->IsVPitch())\r
+        PropulsionStrings += (Thrusters[i]->GetName() + "_Pitch[" + buffer + "], ");\r
+      PropulsionStrings += (Thrusters[i]->GetName() + "_RPM[" + buffer + "]");\r
+      break;\r
+    default:\r
+      PropulsionStrings += "INVALID THRUSTER TYPE";\r
+      break;\r
+    }    \r
+  }\r
+\r
+  return PropulsionStrings;\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+string FGPropulsion::GetPropulsionValues(void)\r
+{\r
+  char buff[20];\r
+  string PropulsionValues = "";\r
+  bool firstime = true;\r
+\r
+  for (unsigned int i=0;i<Engines.size();i++) {\r
+    if (firstime)  firstime = false;\r
+    else           PropulsionValues += ", ";\r
+\r
+    switch(Engines[i]->GetType()) {\r
+    case FGEngine::etPiston:\r
+      PropulsionValues += (string(gcvt(((FGPiston*)Engines[i])->GetPowerAvailable(), 10, buff)));\r
+      break;\r
+    case FGEngine::etRocket:\r
+      PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetChamberPressure(), 10, buff)));\r
+      break;\r
+    case FGEngine::etTurboJet:\r
+    case FGEngine::etTurboProp:\r
+    case FGEngine::etTurboShaft:\r
+      break;\r
+    }\r
+\r
+    PropulsionValues += ", ";\r
+\r
+    switch(Thrusters[i]->GetType()) {\r
+    case FGThruster::ttNozzle:\r
+      PropulsionValues += (string(gcvt(((FGNozzle*)Thrusters[i])->GetThrust(), 10, buff)));\r
+      break;\r
+    case FGThruster::ttRotor:\r
+      break;\r
+    case FGThruster::ttPropeller:\r
+      FGPropeller* Propeller = (FGPropeller*)Thrusters[i];\r
+      FGColumnVector3 vPFactor = Propeller->GetPFactor();\r
+      PropulsionValues += string(gcvt(Propeller->GetTorque(), 10, buff)) + ", ";\r
+      PropulsionValues += string(gcvt(vPFactor(eRoll), 10, buff)) + ", ";\r
+      PropulsionValues += string(gcvt(vPFactor(ePitch), 10, buff)) + ", ";\r
+      PropulsionValues += string(gcvt(vPFactor(eYaw), 10, buff)) + ", ";\r
+      PropulsionValues += string(gcvt(Propeller->GetThrust(), 10, buff)) + ", ";\r
+      if (Propeller->IsVPitch())\r
+        PropulsionValues += string(gcvt(Propeller->GetPitch(), 10, buff)) + ", ";\r
+      PropulsionValues += string(gcvt(Propeller->GetRPM(), 10, buff));\r
+      break;\r
+    }\r
+  }\r
+\r
+  return PropulsionValues;\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+FGColumnVector3& FGPropulsion::GetTanksMoment(void)\r
+{\r
+  iTank = Tanks.begin();\r
+  vXYZtank.InitMatrix();\r
+  while (iTank < Tanks.end()) {\r
+    vXYZtank(eX) += (*iTank)->GetX()*(*iTank)->GetContents();\r
+    vXYZtank(eY) += (*iTank)->GetY()*(*iTank)->GetContents();\r
+    vXYZtank(eZ) += (*iTank)->GetZ()*(*iTank)->GetContents();\r
+    iTank++;\r
+  }\r
+  return vXYZtank;\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+double FGPropulsion::GetTanksWeight(void)\r
+{\r
+  double Tw = 0.0;\r
+\r
+  iTank = Tanks.begin();\r
+  while (iTank < Tanks.end()) {\r
+    Tw += (*iTank)->GetContents();\r
+    iTank++;\r
+  }\r
+  return Tw;\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+double FGPropulsion::GetTanksIxx(const FGColumnVector3& vXYZcg)\r
+{\r
+  double I = 0.0;\r
+  iTank = Tanks.begin();\r
+  while (iTank < Tanks.end()) {\r
+    I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetX() - vXYZcg(eX)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());\r
+    iTank++;\r
+  }\r
+  return I;\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+double FGPropulsion::GetTanksIyy(const FGColumnVector3& vXYZcg)\r
+{\r
+  double I = 0.0;\r
+  iTank = Tanks.begin();\r
+  while (iTank < Tanks.end()) {\r
+    I += ((*iTank)->GetY() - vXYZcg(eY))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());\r
+    iTank++;\r
+  }\r
+  return I;\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+double FGPropulsion::GetTanksIzz(const FGColumnVector3& vXYZcg)\r
+{\r
+  double I = 0.0;\r
+  iTank = Tanks.begin();\r
+  while (iTank < Tanks.end()) {\r
+    I += ((*iTank)->GetZ() - vXYZcg(eZ))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());\r
+    iTank++;\r
+  }\r
+  return I;\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+double FGPropulsion::GetTanksIxz(const FGColumnVector3& vXYZcg)\r
+{\r
+  double I = 0.0;\r
+  iTank = Tanks.begin();\r
+  while (iTank < Tanks.end()) {\r
+    I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());\r
+    iTank++;\r
+  }\r
+  return I;\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+double FGPropulsion::GetTanksIxy(const FGColumnVector3& vXYZcg)\r
+{\r
+  double I = 0.0;\r
+  iTank = Tanks.begin();\r
+  while (iTank != Tanks.end()) {\r
+    I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*Inertial->gravity());\r
+    iTank++;\r
+  }\r
+  return I;\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+void FGPropulsion::SetMagnetos(int setting)\r
+{\r
+  if (ActiveEngine == -1) {\r
+    for (unsigned i=0; i<Engines.size(); i++) {\r
+      Engines[i]->SetMagnetos(setting);\r
+    }\r
+  } else {\r
+    Engines[ActiveEngine]->SetMagnetos(setting);\r
+  }\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+void FGPropulsion::SetStarter(int setting)\r
+{\r
+  if (ActiveEngine == -1) {\r
+    for (unsigned i=0; i<Engines.size(); i++) {\r
+      Engines[i]->SetStarter(setting);\r
+    }\r
+  } else {\r
+    if (setting == 0)\r
+      Engines[ActiveEngine]->SetStarter(false);\r
+    else\r
+      Engines[ActiveEngine]->SetStarter(true);\r
+  }\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+void FGPropulsion::SetActiveEngine(int engine)\r
+{\r
+  if ( unsigned(engine) > Engines.size())\r
+    ActiveEngine = -1;\r
+  else\r
+    ActiveEngine = engine;\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+void FGPropulsion::bind(void)\r
+{\r
+  typedef double (FGPropulsion::*PMF)(int) const;\r
+  typedef int (FGPropulsion::*iPMF)(void) const;\r
+  /* PropertyManager->Tie("propulsion/num-engines", this,\r
+                       &FGPropulsion::GetNumEngines);\r
+  PropertyManager->Tie("propulsion/num-tanks", this,\r
+                       &FGPropulsion::GetNumTanks); */\r
+\r
+  PropertyManager->Tie("propulsion/magneto_cmd", this,\r
+                       (iPMF)0,\r
+                       &FGPropulsion::SetMagnetos,\r
+                       true);\r
+  PropertyManager->Tie("propulsion/starter_cmd", this,\r
+                       (iPMF)0,\r
+                       &FGPropulsion::SetStarter,\r
+                       true);\r
+  PropertyManager->Tie("propulsion/active_engine", this,\r
+                       (iPMF)0,\r
+                       &FGPropulsion::SetActiveEngine,\r
+                       true);\r
+\r
+  PropertyManager->Tie("propulsion/num-sel-fuel-tanks", this,\r
+                       &FGPropulsion::GetnumSelectedFuelTanks);\r
+  PropertyManager->Tie("propulsion/num-sel-ox-tanks", this,\r
+                       &FGPropulsion::GetnumSelectedOxiTanks);\r
+  PropertyManager->Tie("forces/fbx-prop-lbs", this,1,\r
+                       (PMF)&FGPropulsion::GetForces);\r
+  PropertyManager->Tie("forces/fby-prop-lbs", this,2,\r
+                       (PMF)&FGPropulsion::GetForces);\r
+  PropertyManager->Tie("forces/fbz-prop-lbs", this,3,\r
+                       (PMF)&FGPropulsion::GetForces);\r
+  PropertyManager->Tie("moments/l-prop-lbsft", this,1,\r
+                       (PMF)&FGPropulsion::GetMoments);\r
+  PropertyManager->Tie("moments/m-prop-lbsft", this,2,\r
+                       (PMF)&FGPropulsion::GetMoments);\r
+  PropertyManager->Tie("moments/n-prop-lbsft", this,3,\r
+                       (PMF)&FGPropulsion::GetMoments);\r
+  //PropertyManager->Tie("propulsion/tanks-weight-lbs", this,\r
+  //                     &FGPropulsion::GetTanksWeight);\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+void FGPropulsion::unbind(void)\r
+{\r
+  /* PropertyManager->Untie("propulsion/num-engines");\r
+  PropertyManager->Untie("propulsion/num-tanks"); */\r
+  PropertyManager->Untie("propulsion/num-sel-fuel-tanks");\r
+  PropertyManager->Untie("propulsion/num-sel-ox-tanks");\r
+  PropertyManager->Untie("propulsion/magneto_cmd");\r
+  PropertyManager->Untie("propulsion/starter_cmd");\r
+  PropertyManager->Untie("propulsion/active_engine");\r
+  PropertyManager->Untie("forces/fbx-prop-lbs");\r
+  PropertyManager->Untie("forces/fby-prop-lbs");\r
+  PropertyManager->Untie("forces/fbz-prop-lbs");\r
+  PropertyManager->Untie("moments/l-prop-lbsft");\r
+  PropertyManager->Untie("moments/m-prop-lbsft");\r
+  PropertyManager->Untie("moments/n-prop-lbsft");\r
+  //PropertyManager->Untie("propulsion/tanks-weight-lbs");\r
+}\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+//    The bitmasked value choices are as follows:\r
+//    unset: In this case (the default) JSBSim would only print\r
+//       out the normally expected messages, essentially echoing\r
+//       the config files as they are read. If the environment\r
+//       variable is not set, debug_lvl is set to 1 internally\r
+//    0: This requests JSBSim not to output any messages\r
+//       whatsoever.\r
+//    1: This value explicity requests the normal JSBSim\r
+//       startup messages\r
+//    2: This value asks for a message to be printed out when\r
+//       a class is instantiated\r
+//    4: When this value is set, a message is displayed when a\r
+//       FGModel object executes its Run() method\r
+//    8: When this value is set, various runtime state variables\r
+//       are printed out periodically\r
+//    16: When set various parameters are sanity checked and\r
+//       a message is printed out when they go out of bounds\r
+\r
+void FGPropulsion::Debug(int from)\r
+{\r
+  if (debug_lvl <= 0) return;\r
+\r
+  if (debug_lvl & 1) { // Standard console startup message output\r
+    if (from == 0) { // Constructor\r
+\r
+    }\r
+  }\r
+  if (debug_lvl & 2 ) { // Instantiation/Destruction notification\r
+    if (from == 0) cout << "Instantiated: FGPropulsion" << endl;\r
+    if (from == 1) cout << "Destroyed:    FGPropulsion" << endl;\r
+  }\r
+  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects\r
+  }\r
+  if (debug_lvl & 8 ) { // Runtime state variables\r
+  }\r
+  if (debug_lvl & 16) { // Sanity checking\r
+  }\r
+  if (debug_lvl & 64) {\r
+    if (from == 0) { // Constructor\r
+      cout << IdSrc << endl;\r
+      cout << IdHdr << endl;\r
+    }\r
+  }\r
+}\r
+\r
index c0a9cf636f2f6e53463e7d5886ad1183b958b71b..f5405a29fe187db347113a0a0fcedc0a4c7557e8 100644 (file)
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header:       FGPropulsion.h
- Author:       Jon S. Berndt
- Date started: 08/20/00
- ------------- Copyright (C) 1999  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 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 General Public License for more
- details.
- You should have received a copy of the GNU 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 General Public License can also be found on
- the world wide web at http://www.gnu.org.
-HISTORY
---------------------------------------------------------------------------------
-08/20/00   JSB   Created
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGPROPULSION_H
-#define FGPROPULSION_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef FGFS
-#  include <simgear/compiler.h>
-#  ifdef SG_HAVE_STD_INCLUDES
-#    include <vector>
-#    include <iterator>
-#  else
-#    include <vector.h>
-#    include <iterator.h>
-#  endif
-#else
-#  include <vector>
-#  include <iterator>
-#endif
-
-#include "FGModel.h"
-
-#include "FGRocket.h"
-#include "FGPiston.h"
-#include "FGTurboShaft.h"
-#include "FGTurboJet.h"
-#include "FGTurboProp.h"
-#include "FGTank.h"
-#include "FGPropeller.h"
-#include "FGNozzle.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_PROPULSION "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-COMMENTS, REFERENCES, and NOTES [use "class documentation" below for API docs]
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Propulsion management class.
-    FGPropulsion manages all aspects of propulsive force generation, including
-    containment of engines, tanks, and thruster class instances in STL vectors,
-    and the interaction and communication between them.
-    @author Jon S. Berndt
-    @version $Id$
-    @see FGEngine
-    @see FGTank
-    @see FGThruster
-    @see <a href="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/jsbsim/JSBSim/FGPropulsion.h?rev=HEAD&content-type=text/vnd.viewcvs-markup">
-         Header File </a>
-    @see <a href="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/jsbsim/JSBSim/FGPropulsion.cpp?rev=HEAD&content-type=text/vnd.viewcvs-markup">
-         Source File </a>
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGPropulsion : public FGModel
-{
-public:
-  /// Constructor
-  FGPropulsion(FGFDMExec*);
-  /// Destructor
-  ~FGPropulsion();
-
-  /** Executes the propulsion model.
-      The initial plan for the FGPropulsion class calls for Run() to be executed,
-      performing the following tasks:
-      <ol>
-  <li>Determine the drag - or power required - for the attached thrust effector
-      for this engine so that any feedback to the engine can be performed. This
-      is done by calling FGThruster::CalculatePReq()</li>
-  <li>Given 1, above, calculate the power available from the engine. This is
-      done by calling FGEngine::CalculatePAvail()</li>
-  <li>Next, calculate the thrust output from the thruster model given the power
-      available and the power required. This may also result in new performance
-      numbers for the thruster in the case of the propeller, at least. This
-      result is returned from a call to Calculate().</li></ol>
-
-      [Note: Should we be checking the Starved flag here?] */
-  bool Run(void);
-
-  /** Loads the propulsion system (engine[s], tank[s], thruster[s]).
-      Characteristics of the propulsion system are read in from the config file.
-      @param AC_cfg pointer to the config file instance that describes the
-             aircraft being modeled.
-      @return true if successfully loaded, otherwise false */
-  bool Load(FGConfigFile* AC_cfg);
-
-  /// Retrieves the number of engines defined for the aircraft.
-  inline unsigned int GetNumEngines(void) const {return Engines.size();}
-
-  /** Retrieves an engine object pointer from the list of engines.
-      @param index the engine index within the vector container
-      @return the address of the specific engine, or zero if no such engine is
-              available */
-  inline FGEngine* GetEngine(unsigned int index) {
-                      if (index <= Engines.size()-1) return Engines[index];
-                      else                           return 0L;      }
-
-  // Retrieves the number of tanks defined for the aircraft.
-  inline unsigned int GetNumTanks(void) const {return Tanks.size();}
-
-  /** Retrieves a tank object pointer from the list of tanks.
-      @param index the tank index within the vector container
-      @return the address of the specific tank, or zero if no such tank is
-              available */
-  inline FGTank* GetTank(unsigned int index) {
-                      if (index <= Tanks.size()-1) return Tanks[index];
-                      else                         return 0L;        }
-
-  /** Retrieves a thruster object pointer from the list of thrusters.
-      @param index the thruster index within the vector container
-      @return the address of the specific thruster, or zero if no such thruster is
-              available */
-  inline FGThruster* GetThruster(unsigned int index) {
-                      if (index <= Thrusters.size()-1) return Thrusters[index];
-                      else                             return 0L;    }
-
-  /** Returns the number of fuel tanks currently actively supplying fuel */
-  inline int GetnumSelectedFuelTanks(void) const {return numSelectedFuelTanks;}
-
-  /** Returns the number of oxidizer tanks currently actively supplying oxidizer */
-  inline int GetnumSelectedOxiTanks(void) const {return numSelectedOxiTanks;}
-
-  /** Loops the engines/thrusters until thrust output steady (used for trimming) */
-  bool GetSteadyState(void);
-  
-  /** starts the engines in IC mode (dt=0).  All engine-specific setup must
-      be done before calling this (i.e. magnetos, starter engage, etc.) */
-  bool ICEngineStart(void);
-  
-  string GetPropulsionStrings(void);
-  string GetPropulsionValues(void);
-
-  inline FGColumnVector3& GetForces(void)  {return vForces; }
-  inline double GetForces(int n) const { return vForces(n);}
-  inline FGColumnVector3& GetMoments(void) {return vMoments;}
-  inline double GetMoments(int n) const {return vMoments(n);}
-  
-  FGColumnVector3& GetTanksMoment(void);
-  double GetTanksWeight(void);
-
-  double GetTanksIxx(const FGColumnVector3& vXYZcg);
-  double GetTanksIyy(const FGColumnVector3& vXYZcg);
-  double GetTanksIzz(const FGColumnVector3& vXYZcg);
-  double GetTanksIxz(const FGColumnVector3& vXYZcg);
-  double GetTanksIxy(const FGColumnVector3& vXYZcg);
-  
-  void bind();
-  void unbind();
-   
-private:
-  vector <FGEngine*>   Engines;
-  vector <FGTank*>     Tanks;
-  vector <FGTank*>::iterator iTank;
-  vector <FGThruster*> Thrusters;
-  unsigned int numSelectedFuelTanks;
-  unsigned int numSelectedOxiTanks;
-  unsigned int numFuelTanks;
-  unsigned int numOxiTanks;
-  unsigned int numEngines;
-  unsigned int numTanks;
-  unsigned int numThrusters;
-  double dt;
-  FGColumnVector3 vForces;
-  FGColumnVector3 vMoments;
-  FGColumnVector3 vXYZtank;
-  void Debug(int from);
-};
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
-
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+\r
+ Header:       FGPropulsion.h\r
+ Author:       Jon S. Berndt\r
+ Date started: 08/20/00\r
\r
+ ------------- Copyright (C) 1999  Jon S. Berndt (jsb@hal-pc.org) -------------\r
\r
+ This program is free software; you can redistribute it and/or modify it under\r
+ the terms of the GNU General Public License as published by the Free Software\r
+ Foundation; either version 2 of the License, or (at your option) any later\r
+ version.\r
\r
+ This program is distributed in the hope that it will be useful, but WITHOUT\r
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\r
+ FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more\r
+ details.\r
\r
+ You should have received a copy of the GNU General Public License along with\r
+ this program; if not, write to the Free Software Foundation, Inc., 59 Temple\r
+ Place - Suite 330, Boston, MA  02111-1307, USA.\r
\r
+ Further information about the GNU General Public License can also be found on\r
+ the world wide web at http://www.gnu.org.\r
\r
+HISTORY\r
+--------------------------------------------------------------------------------\r
+08/20/00   JSB   Created\r
\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+SENTRY\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/\r
+\r
+#ifndef FGPROPULSION_H\r
+#define FGPROPULSION_H\r
+\r
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+INCLUDES\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/\r
+\r
+#ifdef FGFS\r
+#  include <simgear/compiler.h>\r
+#  ifdef SG_HAVE_STD_INCLUDES\r
+#    include <vector>\r
+#    include <iterator>\r
+#  else\r
+#    include <vector.h>\r
+#    include <iterator.h>\r
+#  endif\r
+#else\r
+#  include <vector>\r
+#  include <iterator>\r
+#endif\r
+\r
+#include "FGModel.h"\r
+\r
+#include "FGRocket.h"\r
+#include "FGPiston.h"\r
+#include "FGTurboShaft.h"\r
+#include "FGTurboJet.h"\r
+#include "FGTurboProp.h"\r
+#include "FGTank.h"\r
+#include "FGPropeller.h"\r
+#include "FGNozzle.h"\r
+\r
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+DEFINITIONS\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/\r
+\r
+#define ID_PROPULSION "$Id$"\r
+\r
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+FORWARD DECLARATIONS\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/\r
+\r
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+COMMENTS, REFERENCES, and NOTES [use "class documentation" below for API docs]\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/\r
+\r
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+CLASS DOCUMENTATION\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/\r
+\r
+/** Propulsion management class.\r
+    FGPropulsion manages all aspects of propulsive force generation, including\r
+    containment of engines, tanks, and thruster class instances in STL vectors,\r
+    and the interaction and communication between them.\r
+    @author Jon S. Berndt\r
+    @version $Id$\r
+    @see FGEngine\r
+    @see FGTank\r
+    @see FGThruster\r
+    @see <a href="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/jsbsim/JSBSim/FGPropulsion.h?rev=HEAD&content-type=text/vnd.viewcvs-markup">\r
+         Header File </a>\r
+    @see <a href="http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/jsbsim/JSBSim/FGPropulsion.cpp?rev=HEAD&content-type=text/vnd.viewcvs-markup">\r
+         Source File </a>\r
+*/\r
+\r
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+CLASS DECLARATION\r
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/\r
+\r
+class FGPropulsion : public FGModel\r
+{\r
+public:\r
+  /// Constructor\r
+  FGPropulsion(FGFDMExec*);\r
+  /// Destructor\r
+  ~FGPropulsion();\r
+\r
+  /** Executes the propulsion model.\r
+      The initial plan for the FGPropulsion class calls for Run() to be executed,\r
+      performing the following tasks:\r
+      <ol>\r
+  <li>Determine the drag - or power required - for the attached thrust effector\r
+      for this engine so that any feedback to the engine can be performed. This\r
+      is done by calling FGThruster::CalculatePReq()</li>\r
+  <li>Given 1, above, calculate the power available from the engine. This is\r
+      done by calling FGEngine::CalculatePAvail()</li>\r
+  <li>Next, calculate the thrust output from the thruster model given the power\r
+      available and the power required. This may also result in new performance\r
+      numbers for the thruster in the case of the propeller, at least. This\r
+      result is returned from a call to Calculate().</li></ol>\r
+\r
+      [Note: Should we be checking the Starved flag here?] */\r
+  bool Run(void);\r
+\r
+  /** Loads the propulsion system (engine[s], tank[s], thruster[s]).\r
+      Characteristics of the propulsion system are read in from the config file.\r
+      @param AC_cfg pointer to the config file instance that describes the\r
+             aircraft being modeled.\r
+      @return true if successfully loaded, otherwise false */\r
+  bool Load(FGConfigFile* AC_cfg);\r
+\r
+  /// Retrieves the number of engines defined for the aircraft.\r
+  inline unsigned int GetNumEngines(void) const {return Engines.size();}\r
+\r
+  /** Retrieves an engine object pointer from the list of engines.\r
+      @param index the engine index within the vector container\r
+      @return the address of the specific engine, or zero if no such engine is\r
+              available */\r
+  inline FGEngine* GetEngine(unsigned int index) {\r
+                      if (index <= Engines.size()-1) return Engines[index];\r
+                      else                           return 0L;      }\r
+\r
+  // Retrieves the number of tanks defined for the aircraft.\r
+  inline unsigned int GetNumTanks(void) const {return Tanks.size();}\r
+\r
+  /** Retrieves a tank object pointer from the list of tanks.\r
+      @param index the tank index within the vector container\r
+      @return the address of the specific tank, or zero if no such tank is\r
+              available */\r
+  inline FGTank* GetTank(unsigned int index) {\r
+                      if (index <= Tanks.size()-1) return Tanks[index];\r
+                      else                         return 0L;        }\r
+\r
+  /** Retrieves a thruster object pointer from the list of thrusters.\r
+      @param index the thruster index within the vector container\r
+      @return the address of the specific thruster, or zero if no such thruster is\r
+              available */\r
+  inline FGThruster* GetThruster(unsigned int index) {\r
+                      if (index <= Thrusters.size()-1) return Thrusters[index];\r
+                      else                             return 0L;    }\r
+\r
+  /** Returns the number of fuel tanks currently actively supplying fuel */\r
+  inline int GetnumSelectedFuelTanks(void) const {return numSelectedFuelTanks;}\r
+\r
+  /** Returns the number of oxidizer tanks currently actively supplying oxidizer */\r
+  inline int GetnumSelectedOxiTanks(void) const {return numSelectedOxiTanks;}\r
+\r
+  /** Loops the engines/thrusters until thrust output steady (used for trimming) */\r
+  bool GetSteadyState(void);\r
+  \r
+  /** starts the engines in IC mode (dt=0).  All engine-specific setup must\r
+      be done before calling this (i.e. magnetos, starter engage, etc.) */\r
+  bool ICEngineStart(void);\r
+  \r
+  string GetPropulsionStrings(void);\r
+  string GetPropulsionValues(void);\r
+\r
+  inline FGColumnVector3& GetForces(void)  {return vForces; }\r
+  inline double GetForces(int n) const { return vForces(n);}\r
+  inline FGColumnVector3& GetMoments(void) {return vMoments;}\r
+  inline double GetMoments(int n) const {return vMoments(n);}\r
+  \r
+  FGColumnVector3& GetTanksMoment(void);\r
+  double GetTanksWeight(void);\r
+\r
+  double GetTanksIxx(const FGColumnVector3& vXYZcg);\r
+  double GetTanksIyy(const FGColumnVector3& vXYZcg);\r
+  double GetTanksIzz(const FGColumnVector3& vXYZcg);\r
+  double GetTanksIxz(const FGColumnVector3& vXYZcg);\r
+  double GetTanksIxy(const FGColumnVector3& vXYZcg);\r
+  \r
+  void SetMagnetos(int setting);\r
+  void SetStarter(int setting);\r
+  void SetActiveEngine(int engine);\r
+  \r
+  void bind();\r
+  void unbind();\r
+   \r
+private:\r
+  vector <FGEngine*>   Engines;\r
+  vector <FGTank*>     Tanks;\r
+  vector <FGTank*>::iterator iTank;\r
+  vector <FGThruster*> Thrusters;\r
+  unsigned int numSelectedFuelTanks;\r
+  unsigned int numSelectedOxiTanks;\r
+  unsigned int numFuelTanks;\r
+  unsigned int numOxiTanks;\r
+  unsigned int numEngines;\r
+  unsigned int numTanks;\r
+  unsigned int numThrusters;\r
+  int ActiveEngine;\r
+  double dt;\r
+  FGColumnVector3 vForces;\r
+  FGColumnVector3 vMoments;\r
+  FGColumnVector3 vXYZtank;\r
+  void Debug(int from);\r
+};\r
+\r
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\r
+#endif\r
+\r
index aa48af0e121b5a80ef02899ae963caec90661683..88eeea4d9aebc9c9cdc38f20bfbb2c38d6bb450f 100644 (file)
@@ -80,9 +80,14 @@ CLASS IMPLEMENTATION
 FGRotation::FGRotation(FGFDMExec* fdmex) : FGModel(fdmex)
 {
   Name = "FGRotation";
-  cTht=cPhi=cPsi=1.0;
-  sTht=sPhi=sPsi=0.0;
-  
+  cTht = cPhi = cPsi = 1.0;
+  sTht = sPhi = sPsi = 0.0;
+
+  vPQRdot.InitMatrix();
+  vPQRdot_prev[0].InitMatrix();
+  vPQRdot_prev[1].InitMatrix();
+  vPQRdot_prev[2].InitMatrix();
+
   bind();
   
   Debug(0);
@@ -110,10 +115,12 @@ bool FGRotation::Run(void)
     N1 = vMoments(eN) - (Iyy-Ixx)*vPQR(eP)*vPQR(eQ) - Ixz*vPQR(eR)*vPQR(eQ);
 
     vPQRdot(eP) = (L2*Izz - N1*Ixz) / (Ixx*Izz - Ixz*Ixz);
-    vPQRdot(eQ) = (vMoments(eM) - (Ixx-Izz)*vPQR(eP)*vPQR(eR) - Ixz*(vPQR(eP)*vPQR(eP) - vPQR(eR)*vPQR(eR)))/Iyy;
+    vPQRdot(eQ) = (vMoments(eM) - (Ixx-Izz)*vPQR(eP)*vPQR(eR)
+                          - Ixz*(vPQR(eP)*vPQR(eP) - vPQR(eR)*vPQR(eR)))/Iyy;
     vPQRdot(eR) = (N1*Ixx + L2*Ixz) / (Ixx*Izz - Ixz*Ixz);
 
-    vPQR += dt*rate*(vlastPQRdot + vPQRdot)/2.0;
+    vPQR += State->Integrate(FGState::TRAPZ, dt*rate, vPQRdot, vPQRdot_prev);
+    
     vAeroPQR = vPQR + Atmosphere->GetTurbPQR();
 
     State->IntegrateQuat(vPQR, rate);
@@ -131,8 +138,6 @@ bool FGRotation::Run(void)
       vEulerRates(ePsi) = (vPQR(2)*sPhi + vPQR(3)*cPhi)/cTht;
     }
 
-    vlastPQRdot = vPQRdot;
-
     if (debug_lvl > 1) Debug(2);
 
     return false;
index 068b44c290dccb154d56bf5812776143a10e540a..5122535fcb4abe3c9cfceda6883a219ff65ece75 100644 (file)
@@ -121,15 +121,14 @@ public:
   void bind(void);
   void unbind(void);
 
-
 private:
   FGColumnVector3 vPQR;
   FGColumnVector3 vAeroPQR;
   FGColumnVector3 vPQRdot;
+  FGColumnVector3 vPQRdot_prev[3];
   FGColumnVector3 vMoments;
   FGColumnVector3 vEuler;
   FGColumnVector3 vEulerRates;
-  FGColumnVector3 vlastPQRdot;
   
   double cTht,sTht;
   double cPhi,sPhi;
index f76e5d027bb2cf6a9140d2bced6ed891fde5dc66..5759173d0b424eb345e35c9bfd86f55f922770a6 100644 (file)
@@ -64,13 +64,6 @@ MACROS
 CLASS IMPLEMENTATION
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-//
-// For every term registered here there must be a corresponding handler in
-// GetParameter() below that retrieves that parameter. Also, there must be an
-// entry in the enum eParam definition in FGJSBBase.h. The ID is what must be used
-// in any config file entry which references that item.
-
 FGState::FGState(FGFDMExec* fdex)
 {
   FDMExec = fdex;
@@ -78,7 +71,6 @@ FGState::FGState(FGFDMExec* fdex)
   a = 1000.0;
   sim_time = 0.0;
   dt = 1.0/120.0;
-  ActiveEngine = -1;
 
   Aircraft     = FDMExec->GetAircraft();
   Translation  = FDMExec->GetTranslation();
@@ -92,6 +84,8 @@ FGState::FGState(FGFDMExec* fdex)
   Propulsion      = FDMExec->GetPropulsion();
   PropertyManager = FDMExec->GetPropertyManager();
 
+  for(int i=0;i<3;i++) vQdot_prev[i].InitMatrix();
+
   InitPropertyMaps();
 
   bind();
@@ -159,7 +153,6 @@ bool FGState::Reset(string path, string acname, string fname)
     resetfile >> token;
   }
   
-  
   Position->SetLatitude(latitude*degtorad);
   Position->SetLongitude(longitude*degtorad);
   Position->Seth(h);
@@ -336,11 +329,10 @@ void FGState::IntegrateQuat(FGColumnVector3 vPQR, int rate)
   vQdot(2) =  0.5*(vQtrn(1)*vPQR(eP) + vQtrn(3)*vPQR(eR) - vQtrn(4)*vPQR(eQ));
   vQdot(3) =  0.5*(vQtrn(1)*vPQR(eQ) + vQtrn(4)*vPQR(eP) - vQtrn(2)*vPQR(eR));
   vQdot(4) =  0.5*(vQtrn(1)*vPQR(eR) + vQtrn(2)*vPQR(eQ) - vQtrn(3)*vPQR(eP));
-  vQtrn += 0.5*dt*rate*(vlastQdot + vQdot);
 
-  vQtrn.Normalize();
+  vQtrn += Integrate(TRAPZ, dt*rate, vQdot, vQdot_prev);
 
-  vlastQdot = vQdot;
+  vQtrn.Normalize();
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -553,17 +545,17 @@ void FGState::InitPropertyMaps(void)
   ParamNameToProp[  "FG_THROTTLE_POS" ]="fcs/throttle-pos-norm";
   ParamNameToProp[  "FG_MIXTURE_CMD" ]="fcs/mixture-cmd-norm";
   ParamNameToProp[  "FG_MIXTURE_POS" ]="fcs/mixture-pos-norm";
-  ParamNameToProp[  "FG_MAGNETO_CMD" ]="zero";
-  ParamNameToProp[  "FG_STARTER_CMD" ]="zero";
-  ParamNameToProp[  "FG_ACTIVE_ENGINE" ]="zero";
+  ParamNameToProp[  "FG_MAGNETO_CMD" ]="propulsion/magneto_cmd";
+  ParamNameToProp[  "FG_STARTER_CMD" ]="propulsion/starter_cmd";
+  ParamNameToProp[  "FG_ACTIVE_ENGINE" ]="propulsion/active_engine";
   ParamNameToProp[  "FG_HOVERB" ]="aero/h_b-mac-ft";
   ParamNameToProp[  "FG_PITCH_TRIM_CMD" ]="fcs/pitch-trim-cmd-norm";
   ParamNameToProp[  "FG_YAW_TRIM_CMD" ]="fcs/yaw-trim-cmd-norm";
   ParamNameToProp[  "FG_ROLL_TRIM_CMD" ]="fcs/roll-trim-cmd-norm";
-  ParamNameToProp[  "FG_LEFT_BRAKE_CMD" ]="zero";
-  ParamNameToProp[  "FG_CENTER_BRAKE_CMD" ]="zero";
-  ParamNameToProp[  "FG_RIGHT_BRAKE_CMD" ]="zero";
-  ParamNameToProp[  "FG_SET_LOGGING" ]="zero";
+  ParamNameToProp[  "FG_LEFT_BRAKE_CMD" ]="fcs/left_brake";
+  ParamNameToProp[  "FG_CENTER_BRAKE_CMD" ]="fcs/center_brake";
+  ParamNameToProp[  "FG_RIGHT_BRAKE_CMD" ]="fcs/right_brake";
+  ParamNameToProp[  "FG_SET_LOGGING" ]="sim/set_logging";
   ParamNameToProp[  "FG_ALPHAH" ]="aero/alpha-rad";
   ParamNameToProp[  "FG_ALPHAW" ]="aero/alpha-wing-rad";
   ParamNameToProp[  "FG_LBARH" ]="metrics/lh-norm";     
index 5d7b70dcdef868a70a7c26e946c0486862e7a9f1..681e94611f2638d0ebadef433e42e847ddd8d434 100644 (file)
@@ -229,6 +229,77 @@ public:
       @param rate the integration rate in seconds.
       */
   void IntegrateQuat(FGColumnVector3 vPQR, int rate);
+  
+  // ======================================= General Purpose INTEGRATOR
+
+  enum iType {AB4, AB3, AB2, AM3, EULER, TRAPZ};
+  
+  /** Multi-method integrator.
+      @param type Type of intergation scheme to use. Can be one of:
+             <ul>
+             <li>AB4 - Adams-Bashforth, fourth order</li>
+             <li>AB3 - Adams-Bashforth, third order</li>
+             <li>AB2 - Adams-Bashforth, second order</li>
+             <li>AM3 - Adams Moulton, third order</li>
+             <li>EULER - Euler</li>
+             <li>TRAPZ - Trapezoidal</li>
+             </ul>
+      @param delta_t the integration time step in seconds
+      @param vTDeriv a reference to the current value of the time derivative of
+             the quantity being integrated (i.e. if vUVW is being integrated
+             vTDeriv is the current value of vUVWdot)
+      @param vLastArray an array of previously calculated and saved values of 
+             the quantity being integrated (i.e. if vUVW is being integrated
+             vLastArray[0] is the past value of vUVWdot, vLastArray[1] is the value of
+             vUVWdot prior to that, etc.)
+      @return the current, incremental value of the item integrated to add to the
+              previous value. */
+  
+  template <class T> T Integrate(iType type, double delta_t, T& vTDeriv, T *vLastArray)
+  {
+    T vResult;
+
+    switch (type) {
+    case AB4:
+      vResult = (delta_t/24.0)*(  55.0 * vTDeriv
+                                - 59.0 * vLastArray[0]
+                                + 37.0 * vLastArray[1]
+                                -  9.0 * vLastArray[2] );
+      vLastArray[2] = vLastArray[1];
+      vLastArray[1] = vLastArray[0];
+      vLastArray[0] = vTDeriv;
+      break;
+    case AB3:
+      vResult = (delta_t/12.0)*(  23.0 * vTDeriv
+                                - 16.0 * vLastArray[0]
+                                +  5.0 * vLastArray[1] );
+      vLastArray[1] = vLastArray[0];
+      vLastArray[0] = vTDeriv;
+      break;
+    case AB2:
+      vResult = (delta_t/2.0)*( 3.0 * vTDeriv - vLastArray[0] );
+      vLastArray[0] = vTDeriv;
+      break;
+    case AM3:
+      vResult = (delta_t/12.0)*(  5.0 * vTDeriv
+                                + 8.0 * vLastArray[0]
+                                - 1.0 * vLastArray[1] );
+      vLastArray[1] = vLastArray[0];
+      vLastArray[0] = vTDeriv;
+      break;
+    case EULER:
+      vResult = delta_t * vTDeriv;
+      break;
+    case TRAPZ:
+      vResult = (delta_t*0.5) * (vTDeriv + vLastArray[0]);
+      vLastArray[0] = vTDeriv;
+      break;
+    }
+
+    return vResult;
+  }
+
+  // =======================================
 
   /** Calculates Euler angles from the local-to-body matrix.
       @return a reference to the vEuler column vector.
@@ -275,8 +346,6 @@ public:
   void ReportState(void);
   
   inline string GetPropertyName(string prm) { return ParamNameToProp[prm]; }
-  //inline string GetPropertyName(eParam prm) { return ParamIdxToProp[prm]; }
-  //inline eParam GetParam(string property) { return PropToParam[property]; }
   
   void bind();
   void unbind();
@@ -292,7 +361,7 @@ private:
   FGMatrix33 mTs2b;
   FGMatrix33 mTb2s;
   FGColumnVector4 vQtrn;
-  FGColumnVector4 vlastQdot;
+  FGColumnVector4 vQdot_prev[3];
   FGColumnVector4 vQdot;
   FGColumnVector3 vUVW;
   FGColumnVector3 vLocalVelNED;
@@ -313,22 +382,9 @@ private:
   FGPropulsion* Propulsion;
   FGPropertyManager* PropertyManager;
 
- /*  typedef map<string, eParam> CoeffMap;
-  CoeffMap coeffdef;
-
-  typedef map<eParam, string> ParamMap;
-  //ParamMap paramdef; */
-
-  
   typedef map<string,string> ParamNameMap;
   ParamNameMap ParamNameToProp;
   
-  typedef map<eParam,string> ParamIdxMap;
-  ParamIdxMap ParamIdxToProp;
-  //CoeffMap PropToParam;
-
-  int ActiveEngine;
-  
   void InitPropertyMaps(void);
   
   void Debug(int from);
index 8c4aa657c4a2fdd41fbc508cb0437c7501284046..9cdaf9e4ff391f5717c8085ab72c923be29ae91f 100644 (file)
@@ -88,6 +88,12 @@ FGTranslation::FGTranslation(FGFDMExec* fdmex) : FGModel(fdmex)
   Mach = 0.0;
   alpha = beta = 0.0;
   adot = bdot = 0.0;
+
+  vUVWdot.InitMatrix();
+  vUVWdot_prev[0].InitMatrix();
+  vUVWdot_prev[1].InitMatrix();
+  vUVWdot_prev[2].InitMatrix();
+
   bind();
   Debug(0);
 }
@@ -104,8 +110,6 @@ FGTranslation::~FGTranslation(void)
 
 bool FGTranslation::Run(void)
 {
-  double Tc = 0.5*State->Getdt()*rate;
-
   if (!FGModel::Run()) {
 
     mVel(1,1) =  0.0;
@@ -120,7 +124,7 @@ bool FGTranslation::Run(void)
 
     vUVWdot = mVel*Rotation->GetPQR() + Aircraft->GetBodyAccel();
 
-    vUVW += Tc*(vUVWdot + vlastUVWdot);
+    vUVW += State->Integrate(FGState::TRAPZ, State->Getdt()*rate, vUVWdot, vUVWdot_prev);
 
     vAeroUVW = vUVW + State->GetTl2b()*Atmosphere->GetWindNED();
 
@@ -155,8 +159,6 @@ bool FGTranslation::Run(void)
     qbarUV = 0.5*Atmosphere->GetDensity()*(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eV)*vAeroUVW(eV));
     Mach = Vt / State->Geta();
 
-    vlastUVWdot = vUVWdot;
-
     if (debug_lvl > 1) Debug(1);
 
     return false;
index 90fb5305014d78766908f8febeb48297938c854f..8a17e95812621adfb27d179538e14d2d2ab74fdb 100644 (file)
@@ -128,8 +128,8 @@ public:
 private:
   FGColumnVector3 vUVW;
   FGColumnVector3 vUVWdot;
-  FGColumnVector3 vlastUVWdot;
-  FGMatrix33       mVel;
+  FGColumnVector3 vUVWdot_prev[3];
+  FGMatrix33      mVel;
   FGColumnVector3 vAeroUVW;
 
   double Vt, Mach;
@@ -137,7 +137,6 @@ private:
   double dt;
   double alpha, beta;
   double adot,bdot;
-
   void Debug(int from);
 };