]> git.mxchange.org Git - flightgear.git/blobdiff - src/FDM/JSBSim/models/FGPropagate.cpp
Better fix for a compilation problem with MSVC 2012
[flightgear.git] / src / FDM / JSBSim / models / FGPropagate.cpp
index 93d6d4749e89f14dc7d80ce6195d21547a4bec79..3c77bca282af8e5df2c38680b08efdd9924d064a 100644 (file)
@@ -48,58 +48,63 @@ COMMENTS, REFERENCES,  and NOTES
     Wiley & Sons, 1979 ISBN 0-471-03032-5
 [5] Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
     1982 ISBN 0-471-08936-2
+[6] S. Buss, "Accurate and Efficient Simulation of Rigid Body Rotations",
+    Technical Report, Department of Mathematics, University of California,
+    San Diego, 1999
+[7] Barker L.E., Bowles R.L. and Williams L.H., "Development and Application of
+    a Local Linearization Algorithm for the Integration of Quaternion Rate
+    Equations in Real-Time Flight Simulation Problems", NASA TN D-7347,
+    December 1973
+[8] Phillips W.F, Hailey C.E and Gebert G.A, "Review of Attitude Representations
+    Used for Aircraft Kinematics", Journal Of Aircraft Vol. 38, No. 4,
+    July-August 2001
 
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 INCLUDES
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
 #include <cmath>
+#include <cstdlib>
+#include <iostream>
 #include <iomanip>
 
 #include "FGPropagate.h"
-#include <FGFDMExec.h>
-#include <FGState.h>
-#include "FGAircraft.h"
-#include "FGMassBalance.h"
-#include "FGInertial.h"
-#include <input_output/FGPropertyManager.h>
+#include "FGGroundReactions.h"
+#include "FGFDMExec.h"
+#include "input_output/FGPropertyManager.h"
+
+using namespace std;
 
 namespace JSBSim {
 
-static const char *IdSrc = "$Id$";
+static const char *IdSrc = "$Id: FGPropagate.cpp,v 1.105 2012/03/26 21:26:11 bcoconni Exp $";
 static const char *IdHdr = ID_PROPAGATE;
 
 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 CLASS IMPLEMENTATION
 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
 
-FGPropagate::FGPropagate(FGFDMExec* fdmex) : FGModel(fdmex)
+FGPropagate::FGPropagate(FGFDMExec* fdmex)
+  : FGModel(fdmex),
+    VehicleRadius(0)
 {
   Debug(0);
   Name = "FGPropagate";
 
-  last2_vPQRdot.InitMatrix();
-  last_vPQRdot.InitMatrix();
-  vPQRdot.InitMatrix();
-  
-  last2_vQtrndot = FGQuaternion(0,0,0);
-  last_vQtrndot = FGQuaternion(0,0,0);
-  vQtrndot = FGQuaternion(0,0,0);
-
-  last2_vUVWdot.InitMatrix();
-  last_vUVWdot.InitMatrix();
-  vUVWdot.InitMatrix();
-  
-  last2_vLocationDot.InitMatrix();
-  last_vLocationDot.InitMatrix();
-  vLocationDot.InitMatrix();
-
-  vOmegaLocal.InitMatrix();
-
-  integrator_rotational_rate = eAdamsBashforth2;
-  integrator_translational_rate = eTrapezoidal;
-  integrator_rotational_position = eAdamsBashforth2;
-  integrator_translational_position = eTrapezoidal;
+  vInertialVelocity.InitMatrix();
+
+  /// These define the indices use to select the various integrators.
+  // eNone = 0, eRectEuler, eTrapezoidal, eAdamsBashforth2, eAdamsBashforth3, eAdamsBashforth4};
+
+  integrator_rotational_rate = eRectEuler;
+  integrator_translational_rate = eAdamsBashforth2;
+  integrator_rotational_position = eRectEuler;
+  integrator_translational_position = eAdamsBashforth3;
+
+  VState.dqPQRidot.resize(4, FGColumnVector3(0.0,0.0,0.0));
+  VState.dqUVWidot.resize(4, FGColumnVector3(0.0,0.0,0.0));
+  VState.dqInertialVelocity.resize(4, FGColumnVector3(0.0,0.0,0.0));
+  VState.dqQtrndot.resize(4, FGQuaternion(0.0,0.0,0.0));
 
   bind();
   Debug(0);
@@ -116,37 +121,21 @@ FGPropagate::~FGPropagate(void)
 
 bool FGPropagate::InitModel(void)
 {
-  if (!FGModel::InitModel()) return false;
-
   // For initialization ONLY:
-  SeaLevelRadius = LocalTerrainRadius = Inertial->GetRefRadius();
-
-  VState.vLocation.SetRadius( LocalTerrainRadius + 4.0 );
-  VState.vLocation.SetEllipse(Inertial->GetSemimajor(), Inertial->GetSemiminor());
-  vOmega = FGColumnVector3( 0.0, 0.0, Inertial->omega() ); // Earth rotation vector
-
-  last2_vPQRdot.InitMatrix();
-  last_vPQRdot.InitMatrix();
-  vPQRdot.InitMatrix();
-  
-  last2_vQtrndot = FGQuaternion(0,0,0);
-  last_vQtrndot = FGQuaternion(0,0,0);
-  vQtrndot = FGQuaternion(0,0,0);
-
-  last2_vUVWdot.InitMatrix();
-  last_vUVWdot.InitMatrix();
-  vUVWdot.InitMatrix();
-  
-  last2_vLocationDot.InitMatrix();
-  last_vLocationDot.InitMatrix();
-  vLocationDot.InitMatrix();
-
-  vOmegaLocal.InitMatrix();
-
-  integrator_rotational_rate = eAdamsBashforth2;
-  integrator_translational_rate = eTrapezoidal;
-  integrator_rotational_position = eAdamsBashforth2;
-  integrator_translational_position = eTrapezoidal;
+  VState.vLocation.SetEllipse(in.SemiMajor, in.SemiMinor);
+  VState.vLocation.SetAltitudeAGL(4.0, FDMExec->GetSimTime());
+
+  vInertialVelocity.InitMatrix();
+
+  VState.dqPQRidot.resize(4, FGColumnVector3(0.0,0.0,0.0));
+  VState.dqUVWidot.resize(4, FGColumnVector3(0.0,0.0,0.0));
+  VState.dqInertialVelocity.resize(4, FGColumnVector3(0.0,0.0,0.0));
+  VState.dqQtrndot.resize(4, FGColumnVector3(0.0,0.0,0.0));
+
+  integrator_rotational_rate = eRectEuler;
+  integrator_translational_rate = eAdamsBashforth2;
+  integrator_rotational_position = eRectEuler;
+  integrator_translational_position = eAdamsBashforth3;
 
   return true;
 }
@@ -155,54 +144,56 @@ bool FGPropagate::InitModel(void)
 
 void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
 {
-  SetSeaLevelRadius(FGIC->GetSeaLevelRadiusFtIC());
-  SetTerrainElevation(FGIC->GetTerrainElevationFtIC());
+  // Initialize the State Vector elements and the transformation matrices
 
   // Set the position lat/lon/radius
-  VState.vLocation.SetPosition( FGIC->GetLongitudeRadIC(),
-                          FGIC->GetLatitudeRadIC(),
-                          FGIC->GetAltitudeASLFtIC() + FGIC->GetSeaLevelRadiusFtIC() );
+  VState.vLocation = FGIC->GetPosition();
 
-  VehicleRadius = GetRadius();
-  radInv = 1.0/VehicleRadius;
+  Ti2ec = VState.vLocation.GetTi2ec(); // ECI to ECEF transform
+  Tec2i = Ti2ec.Transposed();          // ECEF to ECI frame transform
 
-  // Set the Orientation from the euler angles
-  VState.vQtrn = FGQuaternion( FGIC->GetPhiRadIC(),
-                        FGIC->GetThetaRadIC(),
-                        FGIC->GetPsiRadIC() );
+  VState.vInertialPosition = Tec2i * VState.vLocation;
 
-  // Set the velocities in the instantaneus body frame
-  VState.vUVW = FGColumnVector3( FGIC->GetUBodyFpsIC(),
-                          FGIC->GetVBodyFpsIC(),
-                          FGIC->GetWBodyFpsIC() );
+  UpdateLocationMatrices();
+
+  // Set the orientation from the euler angles (is normalized within the
+  // constructor). The Euler angles represent the orientation of the body
+  // frame relative to the local frame.
+  VState.qAttitudeLocal = FGIC->GetOrientation();
 
-  // Set the angular velocities in the instantaneus body frame.
-  VState.vPQR = FGColumnVector3( FGIC->GetPRadpsIC(),
-                          FGIC->GetQRadpsIC(),
-                          FGIC->GetRRadpsIC() );
+  VState.qAttitudeECI = Ti2l.GetQuaternion()*VState.qAttitudeLocal;
+  UpdateBodyMatrices();
+
+  // Set the velocities in the instantaneus body frame
+  VState.vUVW = FGIC->GetUVWFpsIC();
 
   // Compute the local frame ECEF velocity
-  vVel = GetTb2l()*VState.vUVW;
-
-  // Finally, make sure that the quaternion stays normalized.
-  VState.vQtrn.Normalize();
-
-  // Recompute the LocalTerrainRadius.
-  RecomputeLocalTerrainRadius();
-
-  // These local copies of the transformation matrices are for use for
-  // initial conditions only.
-
-  Tl2b = GetTl2b();           // local to body frame transform
-  Tb2l = Tl2b.Transposed();   // body to local frame transform
-  Tl2ec = GetTl2ec();         // local to ECEF transform
-  Tec2l = Tl2ec.Transposed(); // ECEF to local frame transform
-  Tec2b = Tl2b * Tec2l;       // ECEF to body frame transform
-  Tb2ec = Tec2b.Transposed(); // body to ECEF frame tranform
-  Ti2ec = GetTi2ec();         // ECI to ECEF transform
-  Tec2i = Ti2ec.Transposed(); // ECEF to ECI frame transform
-  Ti2b  = Tec2b*Ti2ec;        // ECI to body frame transform
-  Tb2i  = Ti2b.Transposed();  // body to ECI frame transform
+  vVel = Tb2l * VState.vUVW;
+
+  // Compute local terrain velocity
+  RecomputeLocalTerrainVelocity();
+  VehicleRadius = GetRadius();
+
+  // Set the angular velocities of the body frame relative to the ECEF frame,
+  // expressed in the body frame.
+  VState.vPQR = FGIC->GetPQRRadpsIC();
+
+  VState.vPQRi = VState.vPQR + Ti2b * in.vOmegaPlanet;
+
+  CalculateInertialVelocity(); // Translational position derivative
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// Initialize the past value deques
+
+void FGPropagate::InitializeDerivatives()
+{
+  for (int i=0; i<4; i++) {
+    VState.dqPQRidot[i] = in.vPQRidot;
+    VState.dqUVWidot[i] = in.vUVWidot;
+    VState.dqInertialVelocity[i] = VState.vInertialVelocity;
+    VState.dqQtrndot[i] = in.vQtrndot;
+  }
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -218,292 +209,388 @@ This propagation is done using the current state values
 and current derivatives. Based on these values we compute an approximation to the
 state values for (now + dt).
 
-In the code below, variables named beginning with a small "v" refer to a 
+In the code below, variables named beginning with a small "v" refer to a
 a column vector, variables named beginning with a "T" refer to a transformation
 matrix. ECEF refers to Earth Centered Earth Fixed. ECI refers to Earth Centered
 Inertial.
 
 */
 
-bool FGPropagate::Run(void)
+bool FGPropagate::Run(bool Holding)
 {
-  if (FGModel::Run()) return true;  // Fast return if we have nothing to do ...
-  if (FDMExec->Holding()) return false;
+  if (FGModel::Run(Holding)) return true;  // Fast return if we have nothing to do ...
+  if (Holding) return false;
 
-  RecomputeLocalTerrainRadius();
+  double dt = in.DeltaT * rate;  // The 'stepsize'
 
-  // Calculate current aircraft radius from center of planet
+  // Propagate rotational / translational velocity, angular /translational position, respectively.
 
-  VehicleRadius = GetRadius();
-  radInv = 1.0/VehicleRadius;
-
-  // These local copies of the transformation matrices are for use this
-  // pass through Run() only.
-
-  Tl2b = GetTl2b();           // local to body frame transform
-  Tb2l = Tl2b.Transposed();   // body to local frame transform
-  Tl2ec = GetTl2ec();         // local to ECEF transform
-  Tec2l = Tl2ec.Transposed(); // ECEF to local frame transform
-  Tec2b = Tl2b * Tec2l;       // ECEF to body frame transform
-  Tb2ec = Tec2b.Transposed(); // body to ECEF frame tranform
-  Ti2ec = GetTi2ec();         // ECI to ECEF transform
-  Tec2i = Ti2ec.Transposed(); // ECEF to ECI frame transform
-  Ti2b  = Tec2b*Ti2ec;        // ECI to body frame transform
-  Tb2i  = Ti2b.Transposed();  // body to ECI frame transform
+  Integrate(VState.qAttitudeECI,      in.vQtrndot,          VState.dqQtrndot,          dt, integrator_rotational_position);
+  Integrate(VState.vPQRi,             in.vPQRidot,          VState.dqPQRidot,          dt, integrator_rotational_rate);
+  Integrate(VState.vInertialPosition, VState.vInertialVelocity, VState.dqInertialVelocity, dt, integrator_translational_position);
+  Integrate(VState.vInertialVelocity, in.vUVWidot,          VState.dqUVWidot,          dt, integrator_translational_rate);
+
+  // CAUTION : the order of the operations below is very important to get transformation
+  // matrices that are consistent with the new state of the vehicle
+
+  // 1. Update the Earth position angle (EPA)
+  VState.vLocation.IncrementEarthPositionAngle(in.vOmegaPlanet(eZ)*(in.DeltaT*rate));
+
+  // 2. Update the Ti2ec and Tec2i transforms from the updated EPA
+  Ti2ec = VState.vLocation.GetTi2ec(); // ECI to ECEF transform
+  Tec2i = Ti2ec.Transposed();          // ECEF to ECI frame transform
+
+  // 3. Update the location from the updated Ti2ec and inertial position
+  VState.vLocation = Ti2ec*VState.vInertialPosition;
+
+  // 4. Update the other "Location-based" transformation matrices from the updated
+  //    vLocation vector.
+  UpdateLocationMatrices();
+
+  // 5. Update the "Orientation-based" transformation matrices from the updated
+  //    orientation quaternion and vLocation vector.
+  UpdateBodyMatrices();
+
+  // Translational position derivative (velocities are integrated in the inertial frame)
+  CalculateUVW();
+
+  // Set auxilliary state variables
+  RecomputeLocalTerrainVelocity();
+  VehicleRadius = GetRadius(); // Calculate current aircraft radius from center of planet
+
+  VState.vPQR = VState.vPQRi - Ti2b * in.vOmegaPlanet;
+
+  VState.qAttitudeLocal = Tl2b.GetQuaternion();
 
   // Compute vehicle velocity wrt ECEF frame, expressed in Local horizontal frame.
   vVel = Tb2l * VState.vUVW;
 
-  // Inertial angular velocity measured in the body frame.
-  vPQRi = VState.vPQR + Tec2b*vOmega;
+  Debug(2);
+  return false;
+}
 
-  // Calculate state derivatives
-  CalculatePQRdot();      // Angular rate derivative
-  CalculateUVWdot();      // Translational rate derivative
-  CalculateQuatdot();     // Angular orientation derivative
-  CalculateLocationdot(); // Translational position derivative
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  // Transform the velocity vector of the body relative to the origin (Earth
+  // center) to be expressed in the inertial frame, and add the vehicle velocity
+  // contribution due to the rotation of the planet.
+  // Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
+  //            Second edition (2004), eqn 1.5-16c (page 50)
 
-  // Integrate to propagate the state
+void FGPropagate::CalculateInertialVelocity(void)
+{
+  VState.vInertialVelocity = Tb2i * VState.vUVW + (in.vOmegaPlanet * VState.vInertialPosition);
+}
 
-  double dt = State->Getdt()*rate;  // The 'stepsize'
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+  // Transform the velocity vector of the inertial frame to be expressed in the
+  // body frame relative to the origin (Earth center), and substract the vehicle
+  // velocity contribution due to the rotation of the planet.
 
-  // Propagate rotational velocity
+void FGPropagate::CalculateUVW(void)
+{
+  VState.vUVW = Ti2b * (VState.vInertialVelocity - (in.vOmegaPlanet * VState.vInertialPosition));
+}
 
-  switch(integrator_rotational_rate) {
-  case eRectEuler:       VState.vPQR += dt*vPQRdot;
-    break;
-  case eTrapezoidal:     VState.vPQR += 0.5*dt*(vPQRdot + last_vPQRdot);
-    break;
-  case eAdamsBashforth2: VState.vPQR += dt*(1.5*vPQRdot - 0.5*last_vPQRdot);
-    break;
-  case eAdamsBashforth3: VState.vPQR += (1/12.0)*dt*(23.0*vPQRdot - 16.0*last_vPQRdot + 5.0*last2_vPQRdot);
-    break;
-  case eNone: // do nothing, freeze angular rate
-    break;
-  }
-  
-  // Propagate translational velocity
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-  switch(integrator_translational_rate) {
-  case eRectEuler:       VState.vUVW += dt*vUVWdot;
+void FGPropagate::Integrate( FGColumnVector3& Integrand,
+                             FGColumnVector3& Val,
+                             deque <FGColumnVector3>& ValDot,
+                             double dt,
+                             eIntegrateType integration_type)
+{
+  ValDot.push_front(Val);
+  ValDot.pop_back();
+
+  switch(integration_type) {
+  case eRectEuler:       Integrand += dt*ValDot[0];
     break;
-  case eTrapezoidal:     VState.vUVW += 0.5*dt*(vUVWdot + last_vUVWdot);
+  case eTrapezoidal:     Integrand += 0.5*dt*(ValDot[0] + ValDot[1]);
     break;
-  case eAdamsBashforth2: VState.vUVW += dt*(1.5*vUVWdot - 0.5*last_vUVWdot);
+  case eAdamsBashforth2: Integrand += dt*(1.5*ValDot[0] - 0.5*ValDot[1]);
     break;
-  case eAdamsBashforth3: VState.vUVW += (1/12.0)*dt*(23.0*vUVWdot - 16.0*last_vUVWdot + 5.0*last2_vUVWdot);
+  case eAdamsBashforth3: Integrand += (1/12.0)*dt*(23.0*ValDot[0] - 16.0*ValDot[1] + 5.0*ValDot[2]);
+    break;
+  case eAdamsBashforth4: Integrand += (1/24.0)*dt*(55.0*ValDot[0] - 59.0*ValDot[1] + 37.0*ValDot[2] - 9.0*ValDot[3]);
     break;
   case eNone: // do nothing, freeze translational rate
     break;
+  default:
+    break;
   }
+}
 
-  // Propagate angular position
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-  switch(integrator_rotational_position) {
-  case eRectEuler:       VState.vQtrn += dt*vQtrndot;
-    break;
-  case eTrapezoidal:     VState.vQtrn += 0.5*dt*(vQtrndot + last_vQtrndot);
-    break;
-  case eAdamsBashforth2: VState.vQtrn += dt*(1.5*vQtrndot - 0.5*last_vQtrndot);
-    break;
-  case eAdamsBashforth3: VState.vQtrn += (1/12.0)*dt*(23.0*vQtrndot - 16.0*last_vQtrndot + 5.0*last2_vQtrndot);
+void FGPropagate::Integrate( FGQuaternion& Integrand,
+                             FGQuaternion& Val,
+                             deque <FGQuaternion>& ValDot,
+                             double dt,
+                             eIntegrateType integration_type)
+{
+  ValDot.push_front(Val);
+  ValDot.pop_back();
+
+  switch(integration_type) {
+  case eRectEuler:       Integrand += dt*ValDot[0];
     break;
-  case eNone: // do nothing, freeze angular position
+  case eTrapezoidal:     Integrand += 0.5*dt*(ValDot[0] + ValDot[1]);
     break;
-  }
-
-  // Propagate translational position
-
-  switch(integrator_translational_position) {
-  case eRectEuler:       VState.vLocation += dt*vLocationDot;
+  case eAdamsBashforth2: Integrand += dt*(1.5*ValDot[0] - 0.5*ValDot[1]);
     break;
-  case eTrapezoidal:     VState.vLocation += 0.5*dt*(vLocationDot + last_vLocationDot);
+  case eAdamsBashforth3: Integrand += (1/12.0)*dt*(23.0*ValDot[0] - 16.0*ValDot[1] + 5.0*ValDot[2]);
     break;
-  case eAdamsBashforth2: VState.vLocation += dt*(1.5*vLocationDot - 0.5*last_vLocationDot);
+  case eAdamsBashforth4: Integrand += (1/24.0)*dt*(55.0*ValDot[0] - 59.0*ValDot[1] + 37.0*ValDot[2] - 9.0*ValDot[3]);
     break;
-  case eAdamsBashforth3: VState.vLocation += (1/12.0)*dt*(23.0*vLocationDot - 16.0*last_vLocationDot + 5.0*last2_vLocationDot);
+  case eBuss1:
+    {
+      // This is the first order method as described in Samuel R. Buss paper[6].
+      // The formula from Buss' paper is transposed below to quaternions and is
+      // actually the exact solution of the quaternion differential equation
+      // qdot = 1/2*w*q when w is constant.
+      Integrand = Integrand * QExp(0.5 * dt * VState.vPQRi);
+    }
+    return; // No need to normalize since the quaternion exponential is always normal
+  case eBuss2:
+    {
+      // This is the 'augmented second-order method' from S.R. Buss paper [6].
+      // Unlike Runge-Kutta or Adams-Bashforth, it is a one-pass second-order
+      // method (see reference [6]).
+      FGColumnVector3 wi = VState.vPQRi;
+      FGColumnVector3 wdoti = in.vPQRidot;
+      FGColumnVector3 omega = wi + 0.5*dt*wdoti + dt*dt/12.*wdoti*wi;
+      Integrand = Integrand * QExp(0.5 * dt * omega);
+    }
+    return; // No need to normalize since the quaternion exponential is always normal
+  case eLocalLinearization:
+    {
+      // This is the local linearization algorithm of Barker et al. (see ref. [7])
+      // It is also a one-pass second-order method. The code below is based on the
+      // more compact formulation issued from equation (107) of ref. [8]. The
+      // constants C1, C2, C3 and C4 have the same value than those in ref. [7] pp. 11
+      FGColumnVector3 wi = 0.5 * VState.vPQRi;
+      FGColumnVector3 wdoti = 0.5 * in.vPQRidot;
+      double omegak2 = DotProduct(VState.vPQRi, VState.vPQRi);
+      double omegak = omegak2 > 1E-6 ? sqrt(omegak2) : 1E-6;
+      double rhok = 0.5 * dt * omegak;
+      double C1 = cos(rhok);
+      double C2 = 2.0 * sin(rhok) / omegak;
+      double C3 = 4.0 * (1.0 - C1) / (omegak*omegak);
+      double C4 = 4.0 * (dt - C2) / (omegak*omegak);
+      FGColumnVector3 Omega = C2*wi + C3*wdoti + C4*wi*wdoti;
+      FGQuaternion q;
+
+      q(1) = C1 - C4*DotProduct(wi, wdoti);
+      q(2) = Omega(eP);
+      q(3) = Omega(eQ);
+      q(4) = Omega(eR);
+
+      Integrand = Integrand * q;
+
+      /* Cross check with ref. [7] pp.11-12 formulas and code pp. 20
+      double pk = VState.vPQRi(eP);
+      double qk = VState.vPQRi(eQ);
+      double rk = VState.vPQRi(eR);
+      double pdotk = in.vPQRidot(eP);
+      double qdotk = in.vPQRidot(eQ);
+      double rdotk = in.vPQRidot(eR);
+      double Ap = -0.25 * (pk*pdotk + qk*qdotk + rk*rdotk);
+      double Bp = 0.25 * (pk*qdotk - qk*pdotk);
+      double Cp = 0.25 * (pdotk*rk - pk*rdotk);
+      double Dp = 0.25 * (qk*rdotk - qdotk*rk);
+      double C2p = sin(rhok) / omegak;
+      double C3p = 2.0 * (1.0 - cos(rhok)) / (omegak*omegak);
+      double H = C1 + C4 * Ap;
+      double G = -C2p*rk - C3p*rdotk + C4*Bp;
+      double J = C2p*qk + C3p*qdotk - C4*Cp;
+      double K = C2p*pk + C3p*pdotk - C4*Dp;
+
+      cout << "q:       " << q << endl;
+
+      // Warning! In the paper of Barker et al. the quaternion components are not
+      // ordered the same way as in JSBSim (see equations (2) and (3) of ref. [7]
+      // as well as the comment just below equation (3))
+      cout << "FORTRAN: " << H << " , " << K << " , " << J << " , " << -G << endl;*/
+    }
+    break; // The quaternion q is not normal so the normalization needs to be done.
+  case eNone: // do nothing, freeze rotational rate
     break;
-  case eNone: // do nothing, freeze translational position
+  default:
     break;
   }
-  
-  // Set past values
-  
-  last2_vPQRdot = last_vPQRdot;
-  last_vPQRdot = vPQRdot;
-  
-  last2_vUVWdot = last_vUVWdot;
-  last_vUVWdot = vUVWdot;
-  
-  last2_vQtrndot = last_vQtrndot;
-  last_vQtrndot = vQtrndot;
-
-  last2_vLocationDot = last_vLocationDot;
-  last_vLocationDot = vLocationDot;
 
-  Debug(2);
-  return false;
+  Integrand.Normalize();
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// Compute body frame rotational accelerations based on the current body moments
-//
-// vPQRdot is the derivative of the absolute angular velocity of the vehicle 
-// (body rate with respect to the inertial frame), expressed in the body frame,
-// where the derivative is taken in the body frame.
-// J is the inertia matrix
-// Jinv is the inverse inertia matrix
-// vMoments is the moment vector in the body frame
-// vPQRi is the total inertial angular velocity of the vehicle
-// expressed in the body frame.
-// Reference: See Stevens and Lewis, "Aircraft Control and Simulation", 
-//            Second edition (2004), eqn 1.5-16e (page 50)
-
-void FGPropagate::CalculatePQRdot(void)
-{
-  const FGColumnVector3& vMoments = Aircraft->GetMoments(); // current moments
-  const FGMatrix33& J = MassBalance->GetJ();                // inertia matrix
-  const FGMatrix33& Jinv = MassBalance->GetJinv();          // inertia matrix inverse
-
-  // Compute body frame rotational accelerations based on the current body
-  // moments and the total inertial angular velocity expressed in the body
-  // frame.
 
-  vPQRdot = Jinv*(vMoments - vPQRi*(J*vPQRi));
+void FGPropagate::UpdateLocationMatrices(void)
+{
+  Tl2ec = VState.vLocation.GetTl2ec(); // local to ECEF transform
+  Tec2l = Tl2ec.Transposed();          // ECEF to local frame transform
+  Ti2l  = VState.vLocation.GetTi2l();  // ECI to local frame transform
+  Tl2i  = Ti2l.Transposed();           // local to ECI transform
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// Compute the quaternion orientation derivative
-//
-// vQtrndot is the quaternion derivative.
-// Reference: See Stevens and Lewis, "Aircraft Control and Simulation", 
-//            Second edition (2004), eqn 1.5-16b (page 50)
 
-void FGPropagate::CalculateQuatdot(void)
+void FGPropagate::UpdateBodyMatrices(void)
 {
-  vOmegaLocal.InitMatrix( radInv*vVel(eEast),
-                         -radInv*vVel(eNorth),
-                         -radInv*vVel(eEast)*VState.vLocation.GetTanLatitude() );
-
-  // Compute quaternion orientation derivative on current body rates
-  vQtrndot = VState.vQtrn.GetQDot( VState.vPQR - Tl2b*vOmegaLocal);
+  Ti2b  = VState.qAttitudeECI.GetT(); // ECI to body frame transform
+  Tb2i  = Ti2b.Transposed();          // body to ECI frame transform
+  Tl2b  = Ti2b * Tl2i;                // local to body frame transform
+  Tb2l  = Tl2b.Transposed();          // body to local frame transform
+  Tec2b = Ti2b * Tec2i;               // ECEF to body frame transform
+  Tb2ec = Tec2b.Transposed();         // body to ECEF frame tranform
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// This set of calculations results in the body frame accelerations being
-// computed.
-// Reference: See Stevens and Lewis, "Aircraft Control and Simulation", 
-//            Second edition (2004), eqn 1.5-16d (page 50)
-
-void FGPropagate::CalculateUVWdot(void)
-{
-  double mass = MassBalance->GetMass();                      // mass
-  const FGColumnVector3& vForces = Aircraft->GetForces();    // current forces
 
-  const FGColumnVector3 vGravAccel( 0.0, 0.0, Inertial->GetGAccel(VehicleRadius) );
+void FGPropagate::SetInertialOrientation(const FGQuaternion& Qi) {
+  VState.qAttitudeECI = Qi;
+  VState.qAttitudeECI.Normalize();
+  UpdateBodyMatrices();
+  VState.qAttitudeLocal = Tl2b.GetQuaternion();
+}
 
-  // Begin to compute body frame accelerations based on the current body forces
-  vUVWdot = vForces/mass - VState.vPQR * VState.vUVW;
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-  // Include Coriolis acceleration.
-  vUVWdot -= 2.0 * (Ti2b *vOmega) * VState.vUVW;
+void FGPropagate::SetInertialVelocity(const FGColumnVector3& Vi) {
+  VState.vInertialVelocity = Vi;
+  CalculateUVW();
+  vVel = Tb2l * VState.vUVW;
+}
 
-  // Include Centrifugal acceleration.
-  if (!GroundReactions->GetWOW()) {
-    vUVWdot -= Ti2b*(vOmega*(vOmega*(Tec2i*VState.vLocation)));
-  }
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-  // Include Gravitation accel
-  FGColumnVector3 gravAccel = Tl2b*vGravAccel;
-  vUVWdot += gravAccel;
+void FGPropagate::SetInertialRates(const FGColumnVector3& vRates) {
+  VState.vPQRi = Ti2b * vRates;
+  VState.vPQR = VState.vPQRi - Ti2b * in.vOmegaPlanet;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-void FGPropagate::CalculateLocationdot(void)
+void FGPropagate::RecomputeLocalTerrainVelocity()
 {
-  // Transform the vehicle velocity relative to the ECEF frame, expressed
-  // in the body frame, to be expressed in the ECEF frame.
-  vLocationDot = Tb2ec * VState.vUVW;
-
-  // Now, transform the velocity vector of the body relative to the origin (Earth
-  // center) to be expressed in the inertial frame, and add the vehicle velocity
-  // contribution due to the rotation of the planet. The above velocity is only
-  // relative to the rotating ECEF frame.
-  // Reference: See Stevens and Lewis, "Aircraft Control and Simulation", 
-  //            Second edition (2004), eqn 1.5-16c (page 50)
-
-  vInertialVelocity = Tec2i * vLocationDot + (vOmega * (Tec2i * VState.vLocation));
+  FGLocation contact;
+  FGColumnVector3 normal;
+  VState.vLocation.GetContactPoint(FDMExec->GetSimTime(), contact, normal,
+                                   LocalTerrainVelocity, LocalTerrainAngularVelocity);
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-void FGPropagate::RecomputeLocalTerrainRadius(void)
+void FGPropagate::SetTerrainElevation(double terrainElev)
 {
-  double t = State->Getsim_time();
-
-  // Get the LocalTerrain radius.
-  FGLocation contactloc;
-  FGColumnVector3 dv;
-  FDMExec->GetGroundCallback()->GetAGLevel(t, VState.vLocation, contactloc, dv, dv);
-  LocalTerrainRadius = contactloc.GetRadius();
+  double radius = terrainElev + VState.vLocation.GetSeaLevelRadius();
+  FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(radius);
 }
 
+
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-void FGPropagate::SetTerrainElevation(double terrainElev)
+void FGPropagate::SetSeaLevelRadius(double tt)
 {
-  LocalTerrainRadius = terrainElev + SeaLevelRadius;
-  FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(LocalTerrainRadius);
+  FDMExec->GetGroundCallback()->SetSeaLevelRadius(tt);
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-double FGPropagate::GetTerrainElevation(void) const
+double FGPropagate::GetLocalTerrainRadius(void) const
 {
-  return FDMExec->GetGroundCallback()->GetTerrainGeoCentRadius()-SeaLevelRadius;
+  return VState.vLocation.GetTerrainRadius(FDMExec->GetSimTime());
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-const FGMatrix33& FGPropagate::GetTi2ec(void)
+double FGPropagate::GetDistanceAGL(void) const
 {
-  return VState.vLocation.GetTi2ec(Inertial->GetEarthPositionAngle());
+  return VState.vLocation.GetAltitudeAGL(FDMExec->GetSimTime());
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-const FGMatrix33& FGPropagate::GetTec2i(void)
+void FGPropagate::SetDistanceAGL(double tt)
 {
-  return VState.vLocation.GetTec2i(Inertial->GetEarthPositionAngle());
+  VState.vLocation.SetAltitudeAGL(tt, FDMExec->GetSimTime());
+  UpdateVehicleState();
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-void FGPropagate::SetAltitudeASL(double altASL)
+void FGPropagate::SetVState(const VehicleState& vstate)
 {
-  VState.vLocation.SetRadius( altASL + SeaLevelRadius );
+  //ToDo: Shouldn't all of these be set from the vstate vector passed in?
+  VState.vLocation = vstate.vLocation;
+  Ti2ec = VState.vLocation.GetTi2ec(); // useless ?
+  Tec2i = Ti2ec.Transposed();
+  UpdateLocationMatrices();
+  SetInertialOrientation(vstate.qAttitudeECI);
+  RecomputeLocalTerrainVelocity();
+  VehicleRadius = GetRadius();
+  VState.vUVW = vstate.vUVW;
+  vVel = Tb2l * VState.vUVW;
+  VState.vPQR = vstate.vPQR;
+  VState.vPQRi = VState.vPQR + Ti2b * in.vOmegaPlanet;
+  VState.vInertialPosition = vstate.vInertialPosition;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-double FGPropagate::GetLocalTerrainRadius(void) const
+void FGPropagate::UpdateVehicleState(void)
 {
-  return LocalTerrainRadius;
+  RecomputeLocalTerrainVelocity();
+  VehicleRadius = GetRadius();
+  VState.vInertialPosition = Tec2i * VState.vLocation;
+  UpdateLocationMatrices();
+  UpdateBodyMatrices();
+  vVel = Tb2l * VState.vUVW;
+  VState.qAttitudeLocal = Tl2b.GetQuaternion();
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-double FGPropagate::GetDistanceAGL(void) const
+void FGPropagate::SetLocation(const FGLocation& l)
 {
-  return VState.vLocation.GetRadius() - LocalTerrainRadius;
+  VState.vLocation = l;
+  Ti2ec = VState.vLocation.GetTi2ec(); // useless ?
+  Tec2i = Ti2ec.Transposed();
+  UpdateVehicleState();
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 
-void FGPropagate::SetDistanceAGL(double tt)
+void FGPropagate::DumpState(void)
 {
-  VState.vLocation.SetRadius( tt + LocalTerrainRadius );
+  cout << endl;
+  cout << fgblue
+       << "------------------------------------------------------------------" << reset << endl;
+  cout << highint
+       << "State Report at sim time: " << FDMExec->GetSimTime() << " seconds" << reset << endl;
+  cout << "  " << underon
+       <<   "Position" << underoff << endl;
+  cout << "    ECI:   " << VState.vInertialPosition.Dump(", ") << " (x,y,z, in ft)" << endl;
+  cout << "    ECEF:  " << VState.vLocation << " (x,y,z, in ft)"  << endl;
+  cout << "    Local: " << VState.vLocation.GetLatitudeDeg()
+                        << ", " << VState.vLocation.GetLongitudeDeg()
+                        << ", " << GetAltitudeASL() << " (lat, lon, alt in deg and ft)" << endl;
+
+  cout << endl << "  " << underon
+       <<   "Orientation" << underoff << endl;
+  cout << "    ECI:   " << VState.qAttitudeECI.GetEulerDeg().Dump(", ") << " (phi, theta, psi in deg)" << endl;
+  cout << "    Local: " << VState.qAttitudeLocal.GetEulerDeg().Dump(", ") << " (phi, theta, psi in deg)" << endl;
+
+  cout << endl << "  " << underon
+       <<   "Velocity" << underoff << endl;
+  cout << "    ECI:   " << VState.vInertialVelocity.Dump(", ") << " (x,y,z in ft/s)" << endl;
+  cout << "    ECEF:  " << (Tb2ec * VState.vUVW).Dump(", ")  << " (x,y,z in ft/s)"  << endl;
+  cout << "    Local: " << GetVel() << " (n,e,d in ft/sec)" << endl;
+  cout << "    Body:  " << GetUVW() << " (u,v,w in ft/sec)" << endl;
+
+  cout << endl << "  " << underon
+       <<   "Body Rates (relative to given frame, expressed in body frame)" << underoff << endl;
+  cout << "    ECI:   " << (VState.vPQRi*radtodeg).Dump(", ") << " (p,q,r in deg/s)" << endl;
+  cout << "    ECEF:  " << (VState.vPQR*radtodeg).Dump(", ") << " (p,q,r in deg/s)" << endl;
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -511,7 +598,7 @@ void FGPropagate::SetDistanceAGL(double tt)
 void FGPropagate::bind(void)
 {
   typedef double (FGPropagate::*PMF)(int) const;
-//  typedef double (FGPropagate::*dPMF)() const;
+
   PropertyManager->Tie("velocities/h-dot-fps", this, &FGPropagate::Gethdot);
 
   PropertyManager->Tie("velocities/v-north-fps", this, eNorth, (PMF)&FGPropagate::GetVel);
@@ -532,20 +619,12 @@ void FGPropagate::bind(void)
 
   PropertyManager->Tie("velocities/eci-velocity-mag-fps", this, &FGPropagate::GetInertialVelocityMagnitude);
 
-  PropertyManager->Tie("accelerations/pdot-rad_sec2", this, eP, (PMF)&FGPropagate::GetPQRdot);
-  PropertyManager->Tie("accelerations/qdot-rad_sec2", this, eQ, (PMF)&FGPropagate::GetPQRdot);
-  PropertyManager->Tie("accelerations/rdot-rad_sec2", this, eR, (PMF)&FGPropagate::GetPQRdot);
-
-  PropertyManager->Tie("accelerations/udot-ft_sec2", this, eU, (PMF)&FGPropagate::GetUVWdot);
-  PropertyManager->Tie("accelerations/vdot-ft_sec2", this, eV, (PMF)&FGPropagate::GetUVWdot);
-  PropertyManager->Tie("accelerations/wdot-ft_sec2", this, eW, (PMF)&FGPropagate::GetUVWdot);
-
   PropertyManager->Tie("position/h-sl-ft", this, &FGPropagate::GetAltitudeASL, &FGPropagate::SetAltitudeASL, true);
   PropertyManager->Tie("position/h-sl-meters", this, &FGPropagate::GetAltitudeASLmeters, &FGPropagate::SetAltitudeASLmeters, true);
-  PropertyManager->Tie("position/lat-gc-rad", this, &FGPropagate::GetLatitude, &FGPropagate::SetLatitude);
-  PropertyManager->Tie("position/long-gc-rad", this, &FGPropagate::GetLongitude, &FGPropagate::SetLongitude);
-  PropertyManager->Tie("position/lat-gc-deg", this, &FGPropagate::GetLatitudeDeg, &FGPropagate::SetLatitudeDeg);
-  PropertyManager->Tie("position/long-gc-deg", this, &FGPropagate::GetLongitudeDeg, &FGPropagate::SetLongitudeDeg);
+  PropertyManager->Tie("position/lat-gc-rad", this, &FGPropagate::GetLatitude, &FGPropagate::SetLatitude, false);
+  PropertyManager->Tie("position/long-gc-rad", this, &FGPropagate::GetLongitude, &FGPropagate::SetLongitude, false);
+  PropertyManager->Tie("position/lat-gc-deg", this, &FGPropagate::GetLatitudeDeg, &FGPropagate::SetLatitudeDeg, false);
+  PropertyManager->Tie("position/long-gc-deg", this, &FGPropagate::GetLongitudeDeg, &FGPropagate::SetLongitudeDeg, false);
   PropertyManager->Tie("position/lat-geod-rad", this, &FGPropagate::GetGeodLatitudeRad);
   PropertyManager->Tie("position/lat-geod-deg", this, &FGPropagate::GetGeodLatitudeDeg);
   PropertyManager->Tie("position/geod-alt-ft", this, &FGPropagate::GetGeodeticAltitude);
@@ -555,6 +634,7 @@ void FGPropagate::bind(void)
                           &FGPropagate::GetTerrainElevation,
                           &FGPropagate::SetTerrainElevation, false);
 
+  PropertyManager->Tie("position/epa-rad", this, &FGPropagate::GetEarthPositionAngle);
   PropertyManager->Tie("metrics/terrain-radius", this, &FGPropagate::GetLocalTerrainRadius);
 
   PropertyManager->Tie("attitude/phi-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
@@ -564,11 +644,11 @@ void FGPropagate::bind(void)
   PropertyManager->Tie("attitude/roll-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
   PropertyManager->Tie("attitude/pitch-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
   PropertyManager->Tie("attitude/heading-true-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
-  
-  PropertyManager->Tie("simulation/integrator/rate/rotational", &integrator_rotational_rate);
-  PropertyManager->Tie("simulation/integrator/rate/translational", &integrator_translational_rate);
-  PropertyManager->Tie("simulation/integrator/position/rotational", &integrator_rotational_position);
-  PropertyManager->Tie("simulation/integrator/position/translational", &integrator_translational_position);
+
+  PropertyManager->Tie("simulation/integrator/rate/rotational", (int*)&integrator_rotational_rate);
+  PropertyManager->Tie("simulation/integrator/rate/translational", (int*)&integrator_translational_rate);
+  PropertyManager->Tie("simulation/integrator/position/rotational", (int*)&integrator_rotational_position);
+  PropertyManager->Tie("simulation/integrator/position/translational", (int*)&integrator_translational_position);
 }
 
 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -605,7 +685,96 @@ void FGPropagate::Debug(int from)
   }
   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
   }
-  if (debug_lvl & 8 ) { // Runtime state variables
+  if (debug_lvl & 8 && from == 2) { // Runtime state variables
+    cout << endl << fgblue << highint << left
+         << "  Propagation Report (English units: ft, degrees) at simulation time " << FDMExec->GetSimTime() << " seconds"
+         << reset << endl;
+    cout << endl;
+    cout << highint << "  Earth Position Angle (deg): " << setw(8) << setprecision(3) << reset
+         << GetEarthPositionAngleDeg() << endl;
+    cout << endl;
+    cout << highint << "  Body velocity (ft/sec): " << setw(8) << setprecision(3) << reset << VState.vUVW << endl;
+    cout << highint << "  Local velocity (ft/sec): " << setw(8) << setprecision(3) << reset << vVel << endl;
+    cout << highint << "  Inertial velocity (ft/sec): " << setw(8) << setprecision(3) << reset << VState.vInertialVelocity << endl;
+    cout << highint << "  Inertial Position (ft): " << setw(10) << setprecision(3) << reset << VState.vInertialPosition << endl;
+    cout << highint << "  Latitude (deg): " << setw(8) << setprecision(3) << reset << VState.vLocation.GetLatitudeDeg() << endl;
+    cout << highint << "  Longitude (deg): " << setw(8) << setprecision(3) << reset << VState.vLocation.GetLongitudeDeg() << endl;
+    cout << highint << "  Altitude ASL (ft): " << setw(8) << setprecision(3) << reset << GetAltitudeASL() << endl;
+//    cout << highint << "  Acceleration (NED, ft/sec^2): " << setw(8) << setprecision(3) << reset << Tb2l*GetUVWdot() << endl;
+    cout << endl;
+    cout << highint << "  Matrix ECEF to Body (Orientation of Body with respect to ECEF): "
+                    << reset << endl << Tec2b.Dump("\t", "    ") << endl;
+    cout << highint << "    Associated Euler angles (deg): " << setw(8)
+                    << setprecision(3) << reset << (Tec2b.GetQuaternion().GetEuler()*radtodeg)
+                    << endl << endl;
+
+    cout << highint << "  Matrix Body to ECEF (Orientation of ECEF with respect to Body):"
+                    << reset << endl << Tb2ec.Dump("\t", "    ") << endl;
+    cout << highint << "    Associated Euler angles (deg): " << setw(8)
+                    << setprecision(3) << reset << (Tb2ec.GetQuaternion().GetEuler()*radtodeg)
+                    << endl << endl;
+
+    cout << highint << "  Matrix Local to Body (Orientation of Body with respect to Local):"
+                    << reset << endl << Tl2b.Dump("\t", "    ") << endl;
+    cout << highint << "    Associated Euler angles (deg): " << setw(8)
+                    << setprecision(3) << reset << (Tl2b.GetQuaternion().GetEuler()*radtodeg)
+                    << endl << endl;
+
+    cout << highint << "  Matrix Body to Local (Orientation of Local with respect to Body):"
+                    << reset << endl << Tb2l.Dump("\t", "    ") << endl;
+    cout << highint << "    Associated Euler angles (deg): " << setw(8)
+                    << setprecision(3) << reset << (Tb2l.GetQuaternion().GetEuler()*radtodeg)
+                    << endl << endl;
+
+    cout << highint << "  Matrix Local to ECEF (Orientation of ECEF with respect to Local):"
+                    << reset << endl << Tl2ec.Dump("\t", "    ") << endl;
+    cout << highint << "    Associated Euler angles (deg): " << setw(8)
+                    << setprecision(3) << reset << (Tl2ec.GetQuaternion().GetEuler()*radtodeg)
+                    << endl << endl;
+
+    cout << highint << "  Matrix ECEF to Local (Orientation of Local with respect to ECEF):"
+                    << reset << endl << Tec2l.Dump("\t", "    ") << endl;
+    cout << highint << "    Associated Euler angles (deg): " << setw(8)
+                    << setprecision(3) << reset << (Tec2l.GetQuaternion().GetEuler()*radtodeg)
+                    << endl << endl;
+
+    cout << highint << "  Matrix ECEF to Inertial (Orientation of Inertial with respect to ECEF):"
+                    << reset << endl << Tec2i.Dump("\t", "    ") << endl;
+    cout << highint << "    Associated Euler angles (deg): " << setw(8)
+                    << setprecision(3) << reset << (Tec2i.GetQuaternion().GetEuler()*radtodeg)
+                    << endl << endl;
+
+    cout << highint << "  Matrix Inertial to ECEF (Orientation of ECEF with respect to Inertial):"
+                    << reset << endl << Ti2ec.Dump("\t", "    ") << endl;
+    cout << highint << "    Associated Euler angles (deg): " << setw(8)
+                    << setprecision(3) << reset << (Ti2ec.GetQuaternion().GetEuler()*radtodeg)
+                    << endl << endl;
+
+    cout << highint << "  Matrix Inertial to Body (Orientation of Body with respect to Inertial):"
+                    << reset << endl << Ti2b.Dump("\t", "    ") << endl;
+    cout << highint << "    Associated Euler angles (deg): " << setw(8)
+                    << setprecision(3) << reset << (Ti2b.GetQuaternion().GetEuler()*radtodeg)
+                    << endl << endl;
+
+    cout << highint << "  Matrix Body to Inertial (Orientation of Inertial with respect to Body):"
+                    << reset << endl << Tb2i.Dump("\t", "    ") << endl;
+    cout << highint << "    Associated Euler angles (deg): " << setw(8)
+                    << setprecision(3) << reset << (Tb2i.GetQuaternion().GetEuler()*radtodeg)
+                    << endl << endl;
+
+    cout << highint << "  Matrix Inertial to Local (Orientation of Local with respect to Inertial):"
+                    << reset << endl << Ti2l.Dump("\t", "    ") << endl;
+    cout << highint << "    Associated Euler angles (deg): " << setw(8)
+                    << setprecision(3) << reset << (Ti2l.GetQuaternion().GetEuler()*radtodeg)
+                    << endl << endl;
+
+    cout << highint << "  Matrix Local to Inertial (Orientation of Inertial with respect to Local):"
+                    << reset << endl << Tl2i.Dump("\t", "    ") << endl;
+    cout << highint << "    Associated Euler angles (deg): " << setw(8)
+                    << setprecision(3) << reset << (Tl2i.GetQuaternion().GetEuler()*radtodeg)
+                    << endl << endl;
+
+    cout << setprecision(6); // reset the output stream
   }
   if (debug_lvl & 16) { // Sanity checking
     if (from == 2) { // State sanity checking