]> git.mxchange.org Git - flightgear.git/blobdiff - src/FDM/JSBSim/initialization/FGInitialCondition.cpp
Merge branch 'next' of gitorious.org:fg/flightgear into next
[flightgear.git] / src / FDM / JSBSim / initialization / FGInitialCondition.cpp
index 5975a048a035c964456d04159d82c1defc32cdc8..2d8f8a67393192c06d109c72541be98852a91c57 100644 (file)
@@ -42,36 +42,27 @@ you have chosen your IC's wisely) even after setting it up with this class.
 INCLUDES
 *******************************************************************************/
 
-#ifdef FGFS
-#  include <simgear/compiler.h>
-#  ifdef SG_HAVE_STD_INCLUDES
-#    include <fstream>
-#  else
-#    include <fstream.h>
-#  endif
-#else
-#  if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
-#    include <fstream.h>
-#  else
-#    include <fstream>
-#  endif
-#endif
-
 #include "FGInitialCondition.h"
-#include <FGFDMExec.h>
-#include <models/FGInertial.h>
-#include <models/FGAtmosphere.h>
-#include <models/FGAerodynamics.h>
-#include <models/FGPropagate.h>
-#include <input_output/FGPropertyManager.h>
-#include <models/FGPropulsion.h>
-#include <input_output/FGXMLParse.h>
-
-#include <math/FGQuaternion.h>
+#include "FGFDMExec.h"
+#include "models/FGInertial.h"
+#include "models/FGAtmosphere.h"
+#include "models/FGAerodynamics.h"
+#include "models/FGPropagate.h"
+#include "input_output/FGPropertyManager.h"
+#include "input_output/FGXMLElement.h"
+#include "models/FGPropulsion.h"
+#include "input_output/FGXMLParse.h"
+#include "math/FGQuaternion.h"
+#include <iostream>
+#include <fstream>
+#include <cstdlib>
+#include "input_output/string_utilities.h"
+
+using namespace std;
 
 namespace JSBSim {
 
-static const char *IdSrc = "$Id$";
+static const char *IdSrc = "$Id: FGInitialCondition.cpp,v 1.40 2010/06/02 04:05:13 jberndt Exp $";
 static const char *IdHdr = ID_INITIALCONDITION;
 
 //******************************************************************************
@@ -81,10 +72,12 @@ FGInitialCondition::FGInitialCondition(FGFDMExec *FDMExec) : fdmex(FDMExec)
   InitializeIC();
 
   if(FDMExec != NULL ) {
-    fdmex->GetPropagate()->Seth(altitude);
+    fdmex->GetPropagate()->SetAltitudeASL(altitudeASL);
     fdmex->GetAtmosphere()->Run();
     PropertyManager=fdmex->GetPropertyManager();
+    Constructing = true;
     bind();
+    Constructing = false;
   } else {
     cout << "FGInitialCondition: This class requires a pointer to a valid FGFDMExec object" << endl;
   }
@@ -133,7 +126,7 @@ void FGInitialCondition::ResetIC(double u0, double v0, double w0,
   FGColumnVector3 _vUVW_BODY(u,v,w);
   FGColumnVector3 _vUVW_NED = _Tb2l * _vUVW_BODY;
   FGColumnVector3 _vWIND_NED(wnorth,weast,wdown);
-  FGColumnVector3 _vUVWAero = _Tl2b * ( _vUVW_NED + _vWIND_NED );
+//  FGColumnVector3 _vUVWAero = _Tl2b * ( _vUVW_NED + _vWIND_NED );
 
   uw=_vWIND_NED(1); vw=_vWIND_NED(2); ww=_vWIND_NED(3);
 
@@ -147,7 +140,7 @@ void FGInitialCondition::InitializeIC(void)
   mach=0;
   alpha=beta=gamma=0;
   theta=phi=psi=0;
-  altitude=hdot=0;
+  altitudeASL=hdot=0;
   latitude=longitude=0;
   u=v=w=0;
   p=q=r=0;
@@ -159,7 +152,7 @@ void FGInitialCondition::InitializeIC(void)
   lastSpeedSet=setvt;
   lastWindSet=setwned;
   radius_to_vehicle = sea_level_radius = fdmex->GetInertial()->GetRefRadius();
-  terrain_altitude = 0;
+  terrain_elevation = 0;
 
   targetNlfIC = 1.0;
 
@@ -171,7 +164,15 @@ void FGInitialCondition::InitializeIC(void)
 
 void FGInitialCondition::WriteStateFile(int num)
 {
-  string filename = fdmex->GetFullAircraftPath() + "/" + "initfile.xml";
+  if (Constructing) return;
+
+  string filename = fdmex->GetFullAircraftPath();
+
+  if (filename.empty())
+    filename = "initfile.xml";
+  else
+    filename.append("/initfile.xml");
+  
   ofstream outfile(filename.c_str());
   FGPropagate* Propagate = fdmex->GetPropagate();
   
@@ -186,13 +187,12 @@ void FGInitialCondition::WriteStateFile(int num)
     outfile << "  <psi unit=\"DEG\"> " << Propagate->GetEuler(ePsi) << " </psi>" << endl;
     outfile << "  <longitude unit=\"DEG\"> " << Propagate->GetLongitudeDeg() << " </longitude>" << endl;
     outfile << "  <latitude unit=\"DEG\"> " << Propagate->GetLatitudeDeg() << " </latitude>" << endl;
-    outfile << "  <altitude unit=\"FT\"> " << Propagate->Geth() << " </altitude>" << endl;
+    outfile << "  <altitude unit=\"FT\"> " << Propagate->GetAltitudeASL() << " </altitude>" << endl;
     outfile << "</initialize>" << endl;
+    outfile.close();
   } else {
-    cerr << "Could not open and/or write the state to the initial conditions file." << endl;
+    cerr << "Could not open and/or write the state to the initial conditions file: " << filename << endl;
   }
-
-  outfile.close();
 }
 
 //******************************************************************************
@@ -544,9 +544,10 @@ void FGInitialCondition::calcWindUVW(void) {
 
 //******************************************************************************
 
-void FGInitialCondition::SetAltitudeFtIC(double tt) {
-  altitude=tt;
-  fdmex->GetPropagate()->Seth(altitude);
+void FGInitialCondition::SetAltitudeASLFtIC(double tt)
+{
+  altitudeASL=tt;
+  fdmex->GetPropagate()->SetAltitudeASL(altitudeASL);
   fdmex->GetAtmosphere()->Run();
   //lets try to make sure the user gets what they intended
 
@@ -573,25 +574,29 @@ void FGInitialCondition::SetAltitudeFtIC(double tt) {
 
 //******************************************************************************
 
-void FGInitialCondition::SetAltitudeAGLFtIC(double tt) {
-  SetAltitudeFtIC(terrain_altitude + tt);
+void FGInitialCondition::SetAltitudeAGLFtIC(double tt)
+{
+  SetAltitudeASLFtIC(terrain_elevation + tt);
 }
 
 //******************************************************************************
 
-void FGInitialCondition::SetSeaLevelRadiusFtIC(double tt) {
+void FGInitialCondition::SetSeaLevelRadiusFtIC(double tt)
+{
   sea_level_radius = tt;
 }
 
 //******************************************************************************
 
-void FGInitialCondition::SetTerrainAltitudeFtIC(double tt) {
-  terrain_altitude=tt;
+void FGInitialCondition::SetTerrainElevationFtIC(double tt)
+{
+  terrain_elevation=tt;
 }
 
 //******************************************************************************
 
-void FGInitialCondition::calcUVWfromNED(void) {
+void FGInitialCondition::calcUVWfromNED(void)
+{
   u=vnorth*ctheta*cpsi +
      veast*ctheta*spsi -
      vdown*stheta;
@@ -700,23 +705,22 @@ double FGInitialCondition::calcVcas(double Mach) {
   double psl=fdmex->GetAtmosphere()->GetPressureSL();
   double rhosl=fdmex->GetAtmosphere()->GetDensitySL();
   double pt,A,B,D,vcas;
-  if(Mach < 0) Mach=0;
-  if(Mach < 1)    //calculate total pressure assuming isentropic flow
+
+  if (Mach < 0) Mach=0;
+  if (Mach < 1)    //calculate total pressure assuming isentropic flow
     pt=p*pow((1 + 0.2*Mach*Mach),3.5);
   else {
     // shock in front of pitot tube, we'll assume its normal and use
     // the Rayleigh Pitot Tube Formula, i.e. the ratio of total
-    // pressure behind the shock to the static pressure in front
-
-
-    //the normal shock assumption should not be a bad one -- most supersonic
-    //aircraft place the pitot probe out front so that it is the forward
-    //most point on the aircraft.  The real shock would, of course, take
-    //on something like the shape of a rounded-off cone but, here again,
-    //the assumption should be good since the opening of the pitot probe
-    //is very small and, therefore, the effects of the shock curvature
-    //should be small as well. AFAIK, this approach is fairly well accepted
-    //within the aerospace community
+    // pressure behind the shock to the static pressure in front of
+    // the normal shock assumption should not be a bad one -- most supersonic
+    // aircraft place the pitot probe out front so that it is the forward
+    // most point on the aircraft.  The real shock would, of course, take
+    // on something like the shape of a rounded-off cone but, here again,
+    // the assumption should be good since the opening of the pitot probe
+    // is very small and, therefore, the effects of the shock curvature
+    // should be small as well. AFAIK, this approach is fairly well accepted
+    // within the aerospace community
 
     B = 5.76*Mach*Mach/(5.6*Mach*Mach - 0.8);
 
@@ -838,13 +842,7 @@ double FGInitialCondition::GetWindDirDegIC(void) const {
 
 bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
 {
-  int n;
-
   string sep = "/";
-# ifdef macintosh
-   sep = ";";
-# endif
-
   if( useStoredPath ) {
     init_file_name = fdmex->GetFullAircraftPath() + sep + rstfile + ".xml";
   } else {
@@ -864,12 +862,40 @@ bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
     exit(-1);
   }
 
+  double version = document->GetAttributeValueAsNumber("version");
+  if (version == HUGE_VAL) {
+    return Load_v1(); // Default to the old version
+  } else if (version >= 3.0) {
+    cerr << "Only initialization file formats 1 and 2 are currently supported" << endl;
+    exit (-1);
+  } else if (version >= 2.0) {
+    return Load_v2();
+  } else if (version >= 1.0) {
+    return Load_v1();
+  } 
+
+}
+
+//******************************************************************************
+
+bool FGInitialCondition::Load_v1(void)
+{
+  int n;
+
   if (document->FindElement("latitude"))
     SetLatitudeDegIC(document->FindElementValueAsNumberConvertTo("latitude", "DEG"));
   if (document->FindElement("longitude"))
     SetLongitudeDegIC(document->FindElementValueAsNumberConvertTo("longitude", "DEG"));
-  if (document->FindElement("altitude"))
-    SetAltitudeFtIC(document->FindElementValueAsNumberConvertTo("altitude", "FT"));
+  if (document->FindElement("elevation"))
+    SetTerrainElevationFtIC(document->FindElementValueAsNumberConvertTo("elevation", "FT"));
+
+  if (document->FindElement("altitude")) // This is feet above ground level
+    SetAltitudeAGLFtIC(document->FindElementValueAsNumberConvertTo("altitude", "FT"));
+  else if (document->FindElement("altitudeAGL")) // This is feet above ground level
+    SetAltitudeAGLFtIC(document->FindElementValueAsNumberConvertTo("altitudeAGL", "FT"));
+  else if (document->FindElement("altitudeMSL")) // This is feet above sea level
+    SetAltitudeASLFtIC(document->FindElementValueAsNumberConvertTo("altitudeMSL", "FT"));
+
   if (document->FindElement("ubody"))
     SetUBodyFpsIC(document->FindElementValueAsNumberConvertTo("ubody", "FT/SEC"));
   if (document->FindElement("vbody"))
@@ -933,6 +959,249 @@ bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
 
 //******************************************************************************
 
+bool FGInitialCondition::Load_v2(void)
+{
+  int n;
+  FGColumnVector3 vLoc, vOrient;
+  bool result = true;
+  FGInertial* Inertial = fdmex->GetInertial();
+  FGPropagate* Propagate = fdmex->GetPropagate();
+
+  if (document->FindElement("earth_position_angle")) {
+    double epa = document->FindElementValueAsNumberConvertTo("earth_position_angle", "RAD");
+    Inertial->SetEarthPositionAngle(epa);
+  }
+
+  // Initialize vehicle position
+  //
+  // Allowable frames:
+  // - ECI (Earth Centered Inertial)
+  // - ECEF (Earth Centered, Earth Fixed)
+
+  Element* position = document->FindElement("position");
+  if (position) {
+    vLoc = position->FindElementTripletConvertTo("FT");
+    string frame = position->GetAttributeValue("frame");
+    frame = to_lower(frame);
+    if (frame == "eci") {
+      // Need to transform vLoc to ECEF for storage and use in FGLocation.
+      vLoc = Propagate->GetTi2ec()*vLoc;
+    } else if (frame == "ecef") {
+      // Move vLoc query until after lat/lon/alt query to eliminate spurious warning msgs.
+      if (vLoc.Magnitude() == 0.0) {
+        Propagate->SetLatitudeDeg(position->FindElementValueAsNumberConvertTo("latitude", "DEG"));
+        Propagate->SetLongitudeDeg(position->FindElementValueAsNumberConvertTo("longitude", "DEG"));
+        if (position->FindElement("radius")) {
+          radius_to_vehicle = position->FindElementValueAsNumberConvertTo("radius", "FT");
+          SetAltitudeASLFtIC(radius_to_vehicle - sea_level_radius);
+        } else if (position->FindElement("altitudeAGL")) {
+          SetAltitudeAGLFtIC(position->FindElementValueAsNumberConvertTo("altitudeAGL", "FT"));
+        } else if (position->FindElement("altitudeMSL")) {
+          SetAltitudeASLFtIC(position->FindElementValueAsNumberConvertTo("altitudeMSL", "FT"));
+        } else {
+          cerr << endl << "  No altitude or radius initial condition is given." << endl;
+          result = false;
+        }
+      }
+    } else {
+      cerr << endl << "  Neither ECI nor ECEF frame is specified for initial position." << endl;
+      result = false;
+    }
+  } else {
+    cerr << endl << "  Initial position not specified in this initialization file." << endl;
+    result = false;
+  }
+
+  // End of position initialization
+
+  // Initialize vehicle orientation
+  // Allowable frames
+  // - ECI (Earth Centered Inertial)
+  // - ECEF (Earth Centered, Earth Fixed)
+  // - Local
+  //
+  // Need to convert the provided orientation to an ECI orientation, using 
+  // the given orientation and knowledge of the Earth position angle.
+  // This could be done using matrices (where in the subscript "b/a",
+  // it is meant "b with respect to a", and where b=body frame, 
+  // i=inertial frame, and e=ecef frame) as:
+  //
+  // C_b/i =  C_b/e * C_e/i
+  //
+  // Using quaternions (note reverse ordering compared to matrix representation):
+  //
+  // Q_b/i = Q_e/i * Q_b/e
+  //
+  // Use the specific matrices as needed. The above example of course is for the whole
+  // body to inertial orientation.
+  // The new orientation angles can be extracted from the matrix or the quaternion.
+  // ToDo: Do we need to deal with normalization of the quaternions here?
+
+  Element* orientation_el = document->FindElement("orientation");
+  if (orientation_el) {
+    string frame = orientation_el->GetAttributeValue("frame");
+    frame = to_lower(frame);
+    vOrient = orientation_el->FindElementTripletConvertTo("RAD");
+    FGQuaternion QuatI2Body;
+    if (frame == "eci") {
+
+      QuatI2Body = FGQuaternion(vOrient);
+
+    } else if (frame == "ecef") {
+
+      // In this case we are given the Euler angles representing the orientation of
+      // the body with respect to the ECEF system, represented by the C_b/e Matrix.
+      // We want the body orientation with respect to the inertial system:
+      //
+      // C_b/i =  C_b/e * C_e/i
+      //
+      // Using quaternions (note reverse ordering compared to matrix representation):
+      //
+      // Q_b/i = Q_e/i * Q_b/e
+
+      FGQuaternion QuatEC2Body(vOrient); // Store relationship of Body frame wrt ECEF frame, Q_b/e
+      FGQuaternion QuatI2EC = Propagate->GetTi2ec(); // Get Q_e/i from matrix
+      QuatI2Body = QuatI2EC * QuatEC2Body; // Q_b/i = Q_e/i * Q_b/e 
+
+    } else if (frame == "local") {
+
+      // In this case, we are supplying the Euler angles for the vehicle with
+      // respect to the local (NED frame), also called the navigation frame.
+      // This is the most common way of initializing the orientation of
+      // aircraft. The matrix representation is:
+      //
+      // C_b/i = C_b/n * C_n/e * C_e/i
+      //
+      // Or, using quaternions (note reverse ordering compared to matrix representation):
+      //
+      // Q_b/i = Q_e/i * Q_n/e * Q_b/n
+
+      FGQuaternion QuatLocal2Body = FGQuaternion(vOrient); // Store relationship of Body frame wrt local (NED) frame, Q_b/n
+      FGQuaternion QuatEC2Local = Propagate->GetTec2l();   // Get Q_n/e from matrix
+      FGQuaternion QuatI2EC = Propagate->GetTi2ec(); // Get Q_e/i from matrix
+      QuatI2Body = QuatI2EC * QuatEC2Local * QuatLocal2Body; // Q_b/i = Q_e/i * Q_n/e * Q_b/n
+
+    } else {
+
+      cerr << endl << fgred << "  Orientation frame type: \"" << frame
+           << "\" is not supported!" << reset << endl << endl;
+      result = false;
+
+    }
+
+    Propagate->SetInertialOrientation(QuatI2Body);
+  }
+
+  // Initialize vehicle velocity
+  // Allowable frames
+  // - ECI (Earth Centered Inertial)
+  // - ECEF (Earth Centered, Earth Fixed)
+  // - Local
+  // - Body
+  // The vehicle will be defaulted to (0,0,0) in the Body frame if nothing is provided.
+  
+  Element* velocity_el = document->FindElement("velocity");
+  FGColumnVector3 vInertialVelocity;
+  FGColumnVector3 vInitVelocity = FGColumnVector3(0.0, 0.0, 0.0);
+  if (velocity_el) {
+
+    string frame = velocity_el->GetAttributeValue("frame");
+    frame = to_lower(frame);
+    FGColumnVector3 vInitVelocity = velocity_el->FindElementTripletConvertTo("FT/SEC");
+    FGColumnVector3 omega_cross_r = Inertial->omega() * Propagate->GetInertialPosition();
+
+    if (frame == "eci") {
+      vInertialVelocity = vInitVelocity;
+    } else if (frame == "ecef") {
+      FGMatrix33 mTec2i = Propagate->GetTec2i(); // Get C_i/e
+      vInertialVelocity = mTec2i * vInitVelocity + omega_cross_r;
+    } else if (frame == "local") {
+      FGMatrix33 mTl2i = Propagate->GetTl2i();
+      vInertialVelocity = mTl2i * vInitVelocity + omega_cross_r;
+    } else if (frame == "body") {
+      FGMatrix33 mTb2i = Propagate->GetTb2i();
+      vInertialVelocity = mTb2i * vInitVelocity + omega_cross_r;
+    } else {
+
+      cerr << endl << fgred << "  Velocity frame type: \"" << frame
+           << "\" is not supported!" << reset << endl << endl;
+      result = false;
+
+    }
+
+  } else {
+
+    FGMatrix33 mTb2i = Propagate->GetTb2i();
+    vInertialVelocity = mTb2i * vInitVelocity + (Inertial->omega() * Propagate->GetInertialPosition());
+
+  }
+
+  Propagate->SetInertialVelocity(vInertialVelocity);
+
+  // Allowable frames
+  // - ECI (Earth Centered Inertial)
+  // - ECEF (Earth Centered, Earth Fixed)
+  // - Body
+  
+  FGColumnVector3 vInertialRate;
+  Element* attrate_el = document->FindElement("attitude_rate");
+  if (attrate_el) {
+
+    string frame = attrate_el->GetAttributeValue("frame");
+    frame = to_lower(frame);
+    FGColumnVector3 vAttRate = attrate_el->FindElementTripletConvertTo("RAD/SEC");
+
+    if (frame == "eci") {
+      vInertialRate = vAttRate;
+    } else if (frame == "ecef") {
+//      vInertialRate = vAttRate + Inertial->omega(); 
+    } else if (frame == "body") {
+    //Todo: determine local frame rate
+      FGMatrix33 mTb2l = Propagate->GetTb2l();
+//      vInertialRate = mTb2l*vAttRate + Inertial->omega();
+    } else if (!frame.empty()) { // misspelling of frame
+      
+      cerr << endl << fgred << "  Attitude rate frame type: \"" << frame
+           << "\" is not supported!" << reset << endl << endl;
+      result = false;
+
+    } else if (frame.empty()) {
+    
+    }
+    
+  } else { // Body frame attitude rate assumed 0 relative to local.
+/*
+    //Todo: determine local frame rate
+
+    FGMatrix33 mTi2l = Propagate->GetTi2l();
+    vVel = mTi2l * vInertialVelocity;
+
+    // Compute the local frame ECEF velocity
+    vVel = Tb2l * VState.vUVW;
+
+    FGColumnVector3 vOmegaLocal = FGColumnVector3(
+       radInv*vVel(eEast),
+      -radInv*vVel(eNorth),
+      -radInv*vVel(eEast)*VState.vLocation.GetTanLatitude() );
+*/  
+  }
+
+  // Check to see if any engines are specified to be initialized in a running state
+  FGPropulsion* propulsion = fdmex->GetPropulsion();
+  Element* running_elements = document->FindElement("running");
+  while (running_elements) {
+    n = int(running_elements->GetDataAsNumber());
+    propulsion->InitRunning(n);
+    running_elements = document->FindNextElement("running");
+  }
+
+  // fdmex->RunIC();
+
+  return result;
+}
+
+//******************************************************************************
+
 void FGInitialCondition::bind(void){
   PropertyManager->Tie("ic/vc-kts", this,
                        &FGInitialCondition::GetVcalibratedKtsIC,
@@ -989,8 +1258,8 @@ void FGInitialCondition::bind(void){
                        &FGInitialCondition::SetLongitudeDegIC,
                        true);
   PropertyManager->Tie("ic/h-sl-ft", this,
-                       &FGInitialCondition::GetAltitudeFtIC,
-                       &FGInitialCondition::SetAltitudeFtIC,
+                       &FGInitialCondition::GetAltitudeASLFtIC,
+                       &FGInitialCondition::SetAltitudeASLFtIC,
                        true);
   PropertyManager->Tie("ic/h-agl-ft", this,
                        &FGInitialCondition::GetAltitudeAGLFtIC,
@@ -1000,9 +1269,9 @@ void FGInitialCondition::bind(void){
                        &FGInitialCondition::GetSeaLevelRadiusFtIC,
                        &FGInitialCondition::SetSeaLevelRadiusFtIC,
                        true);
-  PropertyManager->Tie("ic/terrain-altitude-ft", this,
-                       &FGInitialCondition::GetTerrainAltitudeFtIC,
-                       &FGInitialCondition::SetTerrainAltitudeFtIC,
+  PropertyManager->Tie("ic/terrain-elevation-ft", this,
+                       &FGInitialCondition::GetTerrainElevationFtIC,
+                       &FGInitialCondition::SetTerrainElevationFtIC,
                        true);
   PropertyManager->Tie("ic/vg-fps", this,
                        &FGInitialCondition::GetVgroundFpsIC,