LCOV - code coverage report
Current view: top level - models - FGPropagate.cpp (source / functions) Hit Total Coverage
Test: JSBSim-Coverage-Statistics Lines: 236 354 66.7 %
Date: 2010-08-24 Functions: 23 30 76.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 19 83 22.9 %

           Branch data     Line data    Source code
       1                 :            : /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
       2                 :            : 
       3                 :            :  Module:       FGPropagate.cpp
       4                 :            :  Author:       Jon S. Berndt
       5                 :            :  Date started: 01/05/99
       6                 :            :  Purpose:      Integrate the EOM to determine instantaneous position
       7                 :            :  Called by:    FGFDMExec
       8                 :            : 
       9                 :            :  ------------- Copyright (C) 1999  Jon S. Berndt (jon@jsbsim.org) -------------
      10                 :            : 
      11                 :            :  This program is free software; you can redistribute it and/or modify it under
      12                 :            :  the terms of the GNU Lesser General Public License as published by the Free Software
      13                 :            :  Foundation; either version 2 of the License, or (at your option) any later
      14                 :            :  version.
      15                 :            : 
      16                 :            :  This program is distributed in the hope that it will be useful, but WITHOUT
      17                 :            :  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
      18                 :            :  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more
      19                 :            :  details.
      20                 :            : 
      21                 :            :  You should have received a copy of the GNU Lesser General Public License along with
      22                 :            :  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
      23                 :            :  Place - Suite 330, Boston, MA  02111-1307, USA.
      24                 :            : 
      25                 :            :  Further information about the GNU Lesser General Public License can also be found on
      26                 :            :  the world wide web at http://www.gnu.org.
      27                 :            : 
      28                 :            : FUNCTIONAL DESCRIPTION
      29                 :            : --------------------------------------------------------------------------------
      30                 :            : This class encapsulates the integration of rates and accelerations to get the
      31                 :            : current position of the aircraft.
      32                 :            : 
      33                 :            : HISTORY
      34                 :            : --------------------------------------------------------------------------------
      35                 :            : 01/05/99   JSB   Created
      36                 :            : 
      37                 :            : %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      38                 :            : COMMENTS, REFERENCES,  and NOTES
      39                 :            : %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      40                 :            : [1] Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
      41                 :            :     Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420  Naval Postgraduate
      42                 :            :     School, January 1994
      43                 :            : [2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
      44                 :            :     JSC 12960, July 1977
      45                 :            : [3] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
      46                 :            :     NASA-Ames", NASA CR-2497, January 1975
      47                 :            : [4] Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
      48                 :            :     Wiley & Sons, 1979 ISBN 0-471-03032-5
      49                 :            : [5] Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
      50                 :            :     1982 ISBN 0-471-08936-2
      51                 :            : [6] Erin Catto, "Iterative Dynamics with Temporal Coherence", February 22, 2005
      52                 :            : 
      53                 :            : %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      54                 :            : INCLUDES
      55                 :            : %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
      56                 :            : 
      57                 :            : #include <cmath>
      58                 :            : #include <cstdlib>
      59                 :            : #include <iostream>
      60                 :            : #include <iomanip>
      61                 :            : 
      62                 :            : #include "FGPropagate.h"
      63                 :            : #include "FGGroundReactions.h"
      64                 :            : #include "FGFDMExec.h"
      65                 :            : #include "FGAircraft.h"
      66                 :            : #include "FGMassBalance.h"
      67                 :            : #include "FGInertial.h"
      68                 :            : #include "input_output/FGPropertyManager.h"
      69                 :            : 
      70                 :            : using namespace std;
      71                 :            : 
      72                 :            : namespace JSBSim {
      73                 :            : 
      74                 :            : static const char *IdSrc = "$Id: FGPropagate.cpp,v 1.60 2010/08/12 19:11:22 andgi Exp $";
      75                 :            : static const char *IdHdr = ID_PROPAGATE;
      76                 :            : 
      77                 :            : /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
      78                 :            : CLASS IMPLEMENTATION
      79                 :            : %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
      80                 :            : 
      81                 :          1 : FGPropagate::FGPropagate(FGFDMExec* fdmex) : FGModel(fdmex)
      82                 :            : {
      83                 :          1 :   Debug(0);
      84                 :          1 :   Name = "FGPropagate";
      85                 :          1 :   gravType = gtWGS84;
      86                 :            :  
      87                 :          1 :   vPQRdot.InitMatrix();
      88                 :          1 :   vQtrndot = FGQuaternion(0,0,0);
      89                 :          1 :   vUVWdot.InitMatrix();
      90                 :          1 :   vInertialVelocity.InitMatrix();
      91                 :            : 
      92                 :          1 :   integrator_rotational_rate = eAdamsBashforth2;
      93                 :          1 :   integrator_translational_rate = eTrapezoidal;
      94                 :          1 :   integrator_rotational_position = eAdamsBashforth2;
      95                 :          1 :   integrator_translational_position = eTrapezoidal;
      96                 :            : 
      97                 :          1 :   VState.dqPQRdot.resize(4, FGColumnVector3(0.0,0.0,0.0));
      98                 :          1 :   VState.dqUVWdot.resize(4, FGColumnVector3(0.0,0.0,0.0));
      99                 :          1 :   VState.dqInertialVelocity.resize(4, FGColumnVector3(0.0,0.0,0.0));
     100                 :          1 :   VState.dqQtrndot.resize(4, FGQuaternion(0.0,0.0,0.0));
     101                 :            : 
     102                 :          1 :   bind();
     103                 :          1 :   Debug(0);
     104                 :          1 : }
     105                 :            : 
     106                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     107                 :            : 
     108                 :          1 : FGPropagate::~FGPropagate(void)
     109                 :            : {
     110                 :          1 :   Debug(1);
     111                 :          1 : }
     112                 :            : 
     113                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     114                 :            : 
     115                 :          1 : bool FGPropagate::InitModel(void)
     116                 :            : {
     117         [ -  + ]:          1 :   if (!FGModel::InitModel()) return false;
     118                 :            : 
     119                 :            :   // For initialization ONLY:
     120                 :          2 :   SeaLevelRadius = LocalTerrainRadius = Inertial->GetRefRadius();
     121                 :            : 
     122                 :          1 :   VState.vLocation.SetRadius( LocalTerrainRadius + 4.0 );
     123                 :          1 :   VState.vLocation.SetEllipse(Inertial->GetSemimajor(), Inertial->GetSemiminor());
     124                 :          2 :   vOmegaEarth = FGColumnVector3( 0.0, 0.0, Inertial->omega() ); // Earth rotation vector
     125                 :            : 
     126                 :          1 :   vPQRdot.InitMatrix();
     127                 :          1 :   vQtrndot = FGQuaternion(0,0,0);
     128                 :          1 :   vUVWdot.InitMatrix();
     129                 :          1 :   vInertialVelocity.InitMatrix();
     130                 :            : 
     131                 :          1 :   VState.dqPQRdot.resize(4, FGColumnVector3(0.0,0.0,0.0));
     132                 :          1 :   VState.dqUVWdot.resize(4, FGColumnVector3(0.0,0.0,0.0));
     133                 :          1 :   VState.dqInertialVelocity.resize(4, FGColumnVector3(0.0,0.0,0.0));
     134                 :          1 :   VState.dqQtrndot.resize(4, FGColumnVector3(0.0,0.0,0.0));
     135                 :            : 
     136                 :          1 :   integrator_rotational_rate = eAdamsBashforth2;
     137                 :          1 :   integrator_translational_rate = eTrapezoidal;
     138                 :          1 :   integrator_rotational_position = eAdamsBashforth2;
     139                 :          1 :   integrator_translational_position = eTrapezoidal;
     140                 :            : 
     141                 :          1 :   return true;
     142                 :            : }
     143                 :            : 
     144                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     145                 :            : 
     146                 :          1 : void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
     147                 :            : {
     148                 :            :   SetSeaLevelRadius(FGIC->GetSeaLevelRadiusFtIC());
     149                 :          1 :   SetTerrainElevation(FGIC->GetTerrainElevationFtIC());
     150                 :            : 
     151                 :          1 :   VehicleRadius = GetRadius();
     152                 :          1 :   radInv = 1.0/VehicleRadius;
     153                 :            : 
     154                 :            :   // Initialize the State Vector elements and the transformation matrices
     155                 :            : 
     156                 :            :   // Set the position lat/lon/radius
     157                 :            :   VState.vLocation.SetPosition( FGIC->GetLongitudeRadIC(),
     158                 :            :                                 FGIC->GetLatitudeRadIC(),
     159                 :          1 :                                 FGIC->GetAltitudeASLFtIC() + FGIC->GetSeaLevelRadiusFtIC() );
     160                 :            : 
     161                 :          2 :   VState.vLocation.SetEarthPositionAngle(Inertial->GetEarthPositionAngle());
     162                 :            : 
     163                 :          1 :   Ti2ec = GetTi2ec();         // ECI to ECEF transform
     164                 :          1 :   Tec2i = Ti2ec.Transposed(); // ECEF to ECI frame transform
     165                 :            :   
     166                 :          1 :   Tl2ec = GetTl2ec();         // local to ECEF transform
     167                 :          1 :   Tec2l = Tl2ec.Transposed(); // ECEF to local frame transform
     168                 :            : 
     169                 :          1 :   Ti2l  = GetTi2l();
     170                 :          1 :   Tl2i  = Ti2l.Transposed();
     171                 :            : 
     172                 :            :   // Set the orientation from the euler angles (is normalized within the
     173                 :            :   // constructor). The Euler angles represent the orientation of the body
     174                 :            :   // frame relative to the local frame.
     175                 :            :   VState.qAttitudeLocal = FGQuaternion( FGIC->GetPhiRadIC(),
     176                 :            :                                         FGIC->GetThetaRadIC(),
     177                 :          1 :                                         FGIC->GetPsiRadIC() );
     178                 :            : 
     179                 :          2 :   VState.qAttitudeECI = Ti2l.GetQuaternion()*VState.qAttitudeLocal;
     180                 :            : 
     181                 :          1 :   Ti2b  = GetTi2b();           // ECI to body frame transform
     182                 :          1 :   Tb2i  = Ti2b.Transposed();   // body to ECI frame transform
     183                 :            : 
     184                 :          1 :   Tl2b  = VState.qAttitudeLocal; // local to body frame transform
     185                 :          1 :   Tb2l  = Tl2b.Transposed();     // body to local frame transform
     186                 :            : 
     187                 :          1 :   Tec2b = Tl2b * Tec2l;        // ECEF to body frame transform
     188                 :          1 :   Tb2ec = Tec2b.Transposed();  // body to ECEF frame tranform
     189                 :            : 
     190                 :            :   // Set the velocities in the instantaneus body frame
     191                 :            :   VState.vUVW = FGColumnVector3( FGIC->GetUBodyFpsIC(),
     192                 :            :                                  FGIC->GetVBodyFpsIC(),
     193                 :          1 :                                  FGIC->GetWBodyFpsIC() );
     194                 :            : 
     195                 :          1 :   VState.vInertialPosition = Tec2i * VState.vLocation;
     196                 :            : 
     197                 :            :   // Compute the local frame ECEF velocity
     198                 :          1 :   vVel = Tb2l * VState.vUVW;
     199                 :            : 
     200                 :            :   // Refer to Stevens and Lewis, 1.5-14a, pg. 49.
     201                 :            :   // This is the rotation rate of the "Local" frame, expressed in the local frame.
     202                 :            : 
     203                 :            :   FGColumnVector3 vOmegaLocal = FGColumnVector3(
     204                 :            :      radInv*vVel(eEast),
     205                 :            :     -radInv*vVel(eNorth),
     206                 :          5 :     -radInv*vVel(eEast)*VState.vLocation.GetTanLatitude() );
     207                 :            : 
     208                 :            :   // Set the angular velocities of the body frame relative to the ECEF frame,
     209                 :            :   // expressed in the body frame. Effectively, this is:
     210                 :            :   //   w_b/e = w_b/l + w_l/e
     211                 :            :   VState.vPQR = FGColumnVector3( FGIC->GetPRadpsIC(),
     212                 :            :                                  FGIC->GetQRadpsIC(),
     213                 :          1 :                                  FGIC->GetRRadpsIC() ) + Tl2b*vOmegaLocal;
     214                 :            : 
     215                 :          1 :   VState.vPQRi = VState.vPQR + Ti2b * vOmegaEarth;
     216                 :            : 
     217                 :            :   // Make an initial run and set past values
     218                 :          1 :   CalculatePQRdot();           // Angular rate derivative
     219                 :          1 :   CalculateUVWdot();           // Translational rate derivative
     220                 :          1 :   ResolveFrictionForces(0.);   // Update rate derivatives with friction forces
     221                 :          1 :   CalculateQuatdot();          // Angular orientation derivative
     222                 :          1 :   CalculateInertialVelocity(); // Translational position derivative
     223                 :            : 
     224                 :            :   // Initialize past values deques
     225                 :          1 :   VState.dqPQRdot.clear();
     226                 :          1 :   VState.dqUVWdot.clear();
     227                 :          1 :   VState.dqInertialVelocity.clear();
     228                 :          1 :   VState.dqQtrndot.clear();
     229         [ +  + ]:          5 :   for (int i=0; i<4; i++) {
     230                 :          4 :     VState.dqPQRdot.push_front(vPQRdot);
     231                 :          4 :     VState.dqUVWdot.push_front(vUVWdot);
     232                 :          4 :     VState.dqInertialVelocity.push_front(VState.vInertialVelocity);
     233                 :          4 :     VState.dqQtrndot.push_front(vQtrndot);
     234                 :            :   }
     235                 :            : 
     236                 :            :   // Recompute the LocalTerrainRadius.
     237                 :          1 :   RecomputeLocalTerrainRadius();
     238                 :          1 : }
     239                 :            : 
     240                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     241                 :            : /*
     242                 :            : Purpose: Called on a schedule to perform EOM integration
     243                 :            : Notes:   [JB] Run in standalone mode, SeaLevelRadius will be reference radius.
     244                 :            :          In FGFS, SeaLevelRadius is stuffed from FGJSBSim in JSBSim.cxx each pass.
     245                 :            : 
     246                 :            : At the top of this Run() function, see several "shortcuts" (or, aliases) being
     247                 :            : set up for use later, rather than using the longer class->function() notation.
     248                 :            : 
     249                 :            : This propagation is done using the current state values
     250                 :            : and current derivatives. Based on these values we compute an approximation to the
     251                 :            : state values for (now + dt).
     252                 :            : 
     253                 :            : In the code below, variables named beginning with a small "v" refer to a 
     254                 :            : a column vector, variables named beginning with a "T" refer to a transformation
     255                 :            : matrix. ECEF refers to Earth Centered Earth Fixed. ECI refers to Earth Centered
     256                 :            : Inertial.
     257                 :            : 
     258                 :            : */
     259                 :            : 
     260                 :      54005 : bool FGPropagate::Run(void)
     261                 :            : {
     262         [ -  + ]:      54005 :   if (FGModel::Run()) return true;  // Fast return if we have nothing to do ...
     263         [ -  + ]:      54005 :   if (FDMExec->Holding()) return false;
     264                 :            : 
     265                 :     108010 :   double dt = FDMExec->GetDeltaT()*rate;  // The 'stepsize'
     266                 :            : 
     267                 :      54005 :   RunPreFunctions();
     268                 :            : 
     269                 :            :   // Calculate state derivatives
     270                 :      54005 :   CalculatePQRdot();           // Angular rate derivative
     271                 :      54005 :   CalculateUVWdot();           // Translational rate derivative
     272                 :      54005 :   ResolveFrictionForces(dt);   // Update rate derivatives with friction forces
     273                 :      54005 :   CalculateQuatdot();          // Angular orientation derivative
     274                 :      54005 :   CalculateInertialVelocity(); // Translational position derivative
     275                 :            : 
     276                 :            :   // Propagate rotational / translational velocity, angular /translational position, respectively.
     277                 :      54005 :   Integrate(VState.vPQRi,             vPQRdot,           VState.dqPQRdot,           dt, integrator_rotational_rate);
     278                 :      54005 :   Integrate(VState.vUVW,              vUVWdot,           VState.dqUVWdot,           dt, integrator_translational_rate);
     279                 :      54005 :   Integrate(VState.qAttitudeECI,      vQtrndot,          VState.dqQtrndot,          dt, integrator_rotational_position);
     280                 :      54005 :   Integrate(VState.vInertialPosition, VState.vInertialVelocity, VState.dqInertialVelocity, dt, integrator_translational_position);
     281                 :            : 
     282                 :      54005 :   VState.qAttitudeECI.Normalize(); // Normalize the ECI Attitude quaternion
     283                 :            : 
     284                 :     108010 :   VState.vLocation.SetEarthPositionAngle(Inertial->GetEarthPositionAngle()); // Update the Earth position angle (EPA)
     285                 :            : 
     286                 :            :   // Update the "Location-based" transformation matrices from the vLocation vector.
     287                 :            : 
     288                 :      54005 :   Ti2ec = GetTi2ec();          // ECI to ECEF transform
     289                 :      54005 :   Tec2i = Ti2ec.Transposed();  // ECEF to ECI frame transform
     290                 :      54005 :   Tl2ec = GetTl2ec();          // local to ECEF transform
     291                 :      54005 :   Tec2l = Tl2ec.Transposed();  // ECEF to local frame transform
     292                 :      54005 :   Ti2l  = GetTi2l();
     293                 :      54005 :   Tl2i  = Ti2l.Transposed();
     294                 :            : 
     295                 :            :   // Update the "Orientation-based" transformation matrices from the orientation quaternion
     296                 :            : 
     297                 :      54005 :   Ti2b  = GetTi2b();           // ECI to body frame transform
     298                 :      54005 :   Tb2i  = Ti2b.Transposed();   // body to ECI frame transform
     299                 :      54005 :   Tl2b  = Ti2b*Tl2i;           // local to body frame transform
     300                 :      54005 :   Tb2l  = Tl2b.Transposed();   // body to local frame transform
     301                 :      54005 :   Tec2b = Tl2b * Tec2l;        // ECEF to body frame transform
     302                 :      54005 :   Tb2ec = Tec2b.Transposed();  // body to ECEF frame tranform
     303                 :            : 
     304                 :            :   // Set auxililary state variables
     305                 :      54005 :   VState.vLocation = Ti2ec*VState.vInertialPosition;
     306                 :      54005 :   RecomputeLocalTerrainRadius();
     307                 :            : 
     308                 :      54005 :   VehicleRadius = GetRadius(); // Calculate current aircraft radius from center of planet
     309                 :      54005 :   radInv = 1.0/VehicleRadius;
     310                 :            : 
     311                 :      54005 :   VState.vPQR = VState.vPQRi - Ti2b * vOmegaEarth;
     312                 :            : 
     313                 :      54005 :   VState.qAttitudeLocal = Tl2b.GetQuaternion();
     314                 :            : 
     315                 :            :   // Compute vehicle velocity wrt ECEF frame, expressed in Local horizontal frame.
     316                 :      54005 :   vVel = Tb2l * VState.vUVW;
     317                 :            : 
     318                 :      54005 :   RunPostFunctions();
     319                 :            : 
     320                 :      54005 :   Debug(2);
     321                 :      54005 :   return false;
     322                 :            : }
     323                 :            : 
     324                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     325                 :            : // Compute body frame rotational accelerations based on the current body moments
     326                 :            : //
     327                 :            : // vPQRdot is the derivative of the absolute angular velocity of the vehicle 
     328                 :            : // (body rate with respect to the inertial frame), expressed in the body frame,
     329                 :            : // where the derivative is taken in the body frame.
     330                 :            : // J is the inertia matrix
     331                 :            : // Jinv is the inverse inertia matrix
     332                 :            : // vMoments is the moment vector in the body frame
     333                 :            : // VState.vPQRi is the total inertial angular velocity of the vehicle
     334                 :            : // expressed in the body frame.
     335                 :            : // Reference: See Stevens and Lewis, "Aircraft Control and Simulation", 
     336                 :            : //            Second edition (2004), eqn 1.5-16e (page 50)
     337                 :            : 
     338                 :      54006 : void FGPropagate::CalculatePQRdot(void)
     339                 :            : {
     340                 :     108012 :   const FGColumnVector3& vMoments = Aircraft->GetMoments(); // current moments
     341                 :     108012 :   const FGMatrix33& J = MassBalance->GetJ();                // inertia matrix
     342                 :     108012 :   const FGMatrix33& Jinv = MassBalance->GetJinv();          // inertia matrix inverse
     343                 :            : 
     344                 :            :   // Compute body frame rotational accelerations based on the current body
     345                 :            :   // moments and the total inertial angular velocity expressed in the body
     346                 :            :   // frame.
     347                 :            : 
     348                 :      54006 :   vPQRdot = Jinv*(vMoments - VState.vPQRi*(J*VState.vPQRi));
     349                 :      54006 : }
     350                 :            : 
     351                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     352                 :            : // Compute the quaternion orientation derivative
     353                 :            : //
     354                 :            : // vQtrndot is the quaternion derivative.
     355                 :            : // Reference: See Stevens and Lewis, "Aircraft Control and Simulation", 
     356                 :            : //            Second edition (2004), eqn 1.5-16b (page 50)
     357                 :            : 
     358                 :      54006 : void FGPropagate::CalculateQuatdot(void)
     359                 :            : {
     360                 :            :   // Compute quaternion orientation derivative on current body rates
     361                 :      54006 :   vQtrndot = VState.qAttitudeECI.GetQDot( VState.vPQRi);
     362                 :      54006 : }
     363                 :            : 
     364                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     365                 :            : // This set of calculations results in the body frame accelerations being
     366                 :            : // computed.
     367                 :            : // Compute body frame accelerations based on the current body forces.
     368                 :            : // Include centripetal and coriolis accelerations.
     369                 :            : // vOmegaEarth is the Earth angular rate - expressed in the inertial frame -
     370                 :            : //   so it has to be transformed to the body frame. More completely,
     371                 :            : //   vOmegaEarth is the rate of the ECEF frame relative to the Inertial
     372                 :            : //   frame (ECI), expressed in the Inertial frame.
     373                 :            : // vForces is the total force on the vehicle in the body frame.
     374                 :            : // VState.vPQR is the vehicle body rate relative to the ECEF frame, expressed
     375                 :            : //   in the body frame.
     376                 :            : // VState.vUVW is the vehicle velocity relative to the ECEF frame, expressed
     377                 :            : //   in the body frame.
     378                 :            : // Reference: See Stevens and Lewis, "Aircraft Control and Simulation", 
     379                 :            : //            Second edition (2004), eqns 1.5-13 (pg 48) and 1.5-16d (page 50)
     380                 :            : 
     381                 :      54006 : void FGPropagate::CalculateUVWdot(void)
     382                 :            : {
     383                 :     108012 :   double mass = MassBalance->GetMass();                      // mass
     384                 :     108012 :   const FGColumnVector3& vForces = Aircraft->GetForces();    // current forces
     385                 :            : 
     386                 :      54006 :   vUVWdot = vForces/mass - (VState.vPQR + 2.0*(Ti2b *vOmegaEarth)) * VState.vUVW;
     387                 :            : 
     388                 :            :   // Include Centripetal acceleration.
     389                 :      54006 :   vUVWdot -= Ti2b * (vOmegaEarth*(vOmegaEarth*VState.vInertialPosition));
     390                 :            : 
     391                 :            :   // Include Gravitation accel
     392      [ -  +  - ]:      54006 :   switch (gravType) {
     393                 :            :     case gtStandard:
     394                 :          0 :       vGravAccel = Tl2b * FGColumnVector3( 0.0, 0.0, Inertial->GetGAccel(VehicleRadius) );
     395                 :            :       break;
     396                 :            :     case gtWGS84:
     397                 :      54006 :       vGravAccel = Tec2b * Inertial->GetGravityJ2(VState.vLocation);
     398                 :            :       break;
     399                 :            :   }
     400                 :            : 
     401                 :      54006 :   vUVWdot += vGravAccel;
     402                 :      54006 : }
     403                 :            : 
     404                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     405                 :            :   // Transform the velocity vector of the body relative to the origin (Earth
     406                 :            :   // center) to be expressed in the inertial frame, and add the vehicle velocity
     407                 :            :   // contribution due to the rotation of the planet.
     408                 :            :   // Reference: See Stevens and Lewis, "Aircraft Control and Simulation", 
     409                 :            :   //            Second edition (2004), eqn 1.5-16c (page 50)
     410                 :            : 
     411                 :      54006 : void FGPropagate::CalculateInertialVelocity(void)
     412                 :            : {
     413                 :      54006 :   VState.vInertialVelocity = Tb2i * VState.vUVW + (vOmegaEarth * VState.vInertialPosition);
     414                 :      54006 : }
     415                 :            : 
     416                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     417                 :            : 
     418                 :            : void FGPropagate::Integrate( FGColumnVector3& Integrand,
     419                 :            :                              FGColumnVector3& Val,
     420                 :            :                              deque <FGColumnVector3>& ValDot,
     421                 :            :                              double dt,
     422                 :     162015 :                              eIntegrateType integration_type)
     423                 :            : {
     424                 :     162015 :   ValDot.push_front(Val);
     425                 :            :   ValDot.pop_back();
     426                 :            : 
     427   [ -  +  +  -  :     162015 :   switch(integration_type) {
                   -  - ]
     428                 :          0 :   case eRectEuler:       Integrand += dt*ValDot[0];
     429                 :            :     break;
     430                 :      54005 :   case eTrapezoidal:     Integrand += 0.5*dt*(ValDot[0] + ValDot[1]);
     431                 :            :     break;
     432                 :     108010 :   case eAdamsBashforth2: Integrand += dt*(1.5*ValDot[0] - 0.5*ValDot[1]);
     433                 :            :     break;
     434                 :          0 :   case eAdamsBashforth3: Integrand += (1/12.0)*dt*(23.0*ValDot[0] - 16.0*ValDot[1] + 5.0*ValDot[2]);
     435                 :            :     break;
     436                 :          0 :   case eAdamsBashforth4: Integrand += (1/24.0)*dt*(55.0*ValDot[0] - 59.0*ValDot[1] + 37.0*ValDot[2] - 9.0*ValDot[3]);
     437                 :            :     break;
     438                 :            :   case eNone: // do nothing, freeze translational rate
     439                 :            :     break;
     440                 :            :   }
     441                 :     162015 : }
     442                 :            : 
     443                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     444                 :            : 
     445                 :            : void FGPropagate::Integrate( FGQuaternion& Integrand,
     446                 :            :                              FGQuaternion& Val,
     447                 :            :                              deque <FGQuaternion>& ValDot,
     448                 :            :                              double dt,
     449                 :      54005 :                              eIntegrateType integration_type)
     450                 :            : {
     451                 :      54005 :   ValDot.push_front(Val);
     452                 :            :   ValDot.pop_back();
     453                 :            : 
     454   [ -  -  +  -  :      54005 :   switch(integration_type) {
                   -  - ]
     455                 :          0 :   case eRectEuler:       Integrand += dt*ValDot[0];
     456                 :            :     break;
     457                 :          0 :   case eTrapezoidal:     Integrand += 0.5*dt*(ValDot[0] + ValDot[1]);
     458                 :            :     break;
     459                 :      54005 :   case eAdamsBashforth2: Integrand += dt*(1.5*ValDot[0] - 0.5*ValDot[1]);
     460                 :            :     break;
     461                 :          0 :   case eAdamsBashforth3: Integrand += (1/12.0)*dt*(23.0*ValDot[0] - 16.0*ValDot[1] + 5.0*ValDot[2]);
     462                 :            :     break;
     463                 :          0 :   case eAdamsBashforth4: Integrand += (1/24.0)*dt*(55.0*ValDot[0] - 59.0*ValDot[1] + 37.0*ValDot[2] - 9.0*ValDot[3]);
     464                 :            :     break;
     465                 :            :   case eNone: // do nothing, freeze rotational rate
     466                 :            :     break;
     467                 :            :   }
     468                 :      54005 : }
     469                 :            : 
     470                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     471                 :            : // Resolves the contact forces just before integrating the EOM.
     472                 :            : // This routine is using Lagrange multipliers and the projected Gauss-Seidel
     473                 :            : // (PGS) method.
     474                 :            : // Reference: See Erin Catto, "Iterative Dynamics with Temporal Coherence", 
     475                 :            : //            February 22, 2005
     476                 :            : // In JSBSim there is only one rigid body (the aircraft) and there can be
     477                 :            : // multiple points of contact between the aircraft and the ground. As a
     478                 :            : // consequence our matrix J*M^-1*J^T is not sparse and the algorithm described
     479                 :            : // in Catto's paper has been adapted accordingly.
     480                 :            : 
     481                 :      54006 : void FGPropagate::ResolveFrictionForces(double dt)
     482                 :            : {
     483                 :     108012 :   const double invMass = 1.0 / MassBalance->GetMass();
     484                 :     108012 :   const FGMatrix33& Jinv = MassBalance->GetJinv();
     485                 :            :   vector <FGColumnVector3> JacF, JacM;
     486                 :      54006 :   FGColumnVector3 vdot, wdot;
     487                 :      54006 :   FGColumnVector3 Fc, Mc;
     488                 :      54006 :   int n = 0, i;
     489                 :            : 
     490                 :            :   // Compiles data from the ground reactions to build up the jacobian matrix
     491         [ -  + ]:      54006 :   for (MultiplierIterator it=MultiplierIterator(GroundReactions); *it; ++it, n++) {
     492                 :          0 :     JacF.push_back((*it)->ForceJacobian);
     493                 :          0 :     JacM.push_back((*it)->MomentJacobian);
     494                 :            :   }
     495                 :            : 
     496                 :            :   // If no gears are in contact with the ground then return
     497         [ -  + ]:     108012 :   if (!n) return;
     498                 :            : 
     499                 :          0 :   vector<double> a(n*n); // Will contain J*M^-1*J^T
     500                 :          0 :   vector<double> eta(n);
     501                 :          0 :   vector<double> lambda(n);
     502                 :          0 :   vector<double> lambdaMin(n);
     503                 :          0 :   vector<double> lambdaMax(n);
     504                 :            : 
     505                 :            :   // Initializes the Lagrange multipliers
     506                 :          0 :   i = 0;
     507         [ #  # ]:          0 :   for (MultiplierIterator it=MultiplierIterator(GroundReactions); *it; ++it, i++) {
     508                 :          0 :     lambda[i] = (*it)->value;
     509                 :          0 :     lambdaMax[i] = (*it)->Max;
     510                 :          0 :     lambdaMin[i] = (*it)->Min;
     511                 :            :   }
     512                 :            : 
     513                 :          0 :   vdot = vUVWdot;
     514                 :          0 :   wdot = vPQRdot;
     515                 :            : 
     516         [ #  # ]:          0 :   if (dt > 0.) {
     517                 :            :     // First compute the ground velocity below the aircraft center of gravity
     518                 :          0 :     FGLocation contact;
     519                 :          0 :     FGColumnVector3 normal, cvel;
     520                 :            : 
     521                 :            :     // Instruct the algorithm to zero out the relative movement between the
     522                 :            :     // aircraft and the ground.
     523                 :          0 :     vdot += (VState.vUVW - Tec2b * cvel) / dt;
     524                 :          0 :     wdot += VState.vPQR / dt;
     525                 :            :   }
     526                 :            : 
     527                 :            :   // Assemble the linear system of equations
     528         [ #  # ]:          0 :   for (i=0; i < n; i++) {
     529         [ #  # ]:          0 :     for (int j=0; j < i; j++)
     530                 :          0 :       a[i*n+j] = a[j*n+i]; // Takes advantage of the symmetry of J^T*M^-1*J
     531         [ #  # ]:          0 :     for (int j=i; j < n; j++)
     532                 :          0 :       a[i*n+j] = DotProduct(JacF[i],invMass*JacF[j])+DotProduct(JacM[i],Jinv*JacM[j]);
     533                 :            :   }
     534                 :            : 
     535                 :            :   // Prepare the linear system for the Gauss-Seidel algorithm :
     536                 :            :   // divide every line of 'a' and eta by a[i,i]. This is in order to save
     537                 :            :   // a division computation at each iteration of Gauss-Seidel.
     538         [ #  # ]:          0 :   for (i=0; i < n; i++) {
     539                 :          0 :     double d = 1.0 / a[i*n+i];
     540                 :            : 
     541                 :          0 :     eta[i] = -(DotProduct(JacF[i],vdot)+DotProduct(JacM[i],wdot))*d;
     542         [ #  # ]:          0 :     for (int j=0; j < n; j++)
     543                 :          0 :       a[i*n+j] *= d;
     544                 :            :   }
     545                 :            : 
     546                 :            :   // Resolve the Lagrange multipliers with the projected Gauss-Seidel method
     547         [ #  # ]:          0 :   for (int iter=0; iter < 50; iter++) {
     548                 :          0 :     double norm = 0.;
     549                 :            : 
     550         [ #  # ]:          0 :     for (i=0; i < n; i++) {
     551                 :          0 :       double lambda0 = lambda[i];
     552                 :          0 :       double dlambda = eta[i];
     553                 :            :       
     554         [ #  # ]:          0 :       for (int j=0; j < n; j++)
     555                 :          0 :         dlambda -= a[i*n+j]*lambda[j];
     556                 :            : 
     557                 :          0 :       lambda[i] = Constrain(lambdaMin[i], lambda0+dlambda, lambdaMax[i]);
     558                 :          0 :       dlambda = lambda[i] - lambda0;
     559                 :            : 
     560                 :          0 :       norm += fabs(dlambda);
     561                 :            :     }
     562                 :            : 
     563         [ #  # ]:          0 :     if (norm < 1E-5) break;
     564                 :            :   }
     565                 :            : 
     566                 :            :   // Calculate the total friction forces and moments
     567                 :            : 
     568                 :            :   Fc.InitMatrix();
     569                 :            :   Mc.InitMatrix();
     570                 :            : 
     571         [ #  # ]:          0 :   for (i=0; i< n; i++) {
     572                 :          0 :     Fc += lambda[i]*JacF[i];
     573                 :          0 :     Mc += lambda[i]*JacM[i];
     574                 :            :   }
     575                 :            : 
     576                 :          0 :   vUVWdot += invMass * Fc;
     577                 :          0 :   vPQRdot += Jinv * Mc;
     578                 :            : 
     579                 :            :   // Save the value of the Lagrange multipliers to accelerate the convergence
     580                 :            :   // of the Gauss-Seidel algorithm at next iteration.
     581                 :          0 :   i = 0;
     582         [ #  # ]:          0 :   for (MultiplierIterator it=MultiplierIterator(GroundReactions); *it; ++it)
     583                 :          0 :     (*it)->value = lambda[i++];
     584                 :            : 
     585                 :     108012 :   GroundReactions->UpdateForcesAndMoments();
     586                 :            : }
     587                 :            : 
     588                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     589                 :            : 
     590                 :          0 : void FGPropagate::SetInertialOrientation(FGQuaternion Qi) {
     591                 :          0 :   VState.qAttitudeECI = Qi;
     592                 :          0 : }
     593                 :            : 
     594                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     595                 :            : 
     596                 :          0 : void FGPropagate::SetInertialVelocity(FGColumnVector3 Vi) {
     597                 :          0 :   VState.vInertialVelocity = Vi;
     598                 :          0 : }
     599                 :            : 
     600                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     601                 :            : 
     602                 :      54006 : void FGPropagate::RecomputeLocalTerrainRadius(void)
     603                 :            : {
     604                 :     108012 :   double t = FDMExec->GetSimTime();
     605                 :            : 
     606                 :            :   // Get the LocalTerrain radius.
     607                 :      54006 :   FDMExec->GetGroundCallback()->GetAGLevel(t, VState.vLocation, contactloc, dv, dv);
     608                 :     108012 :   LocalTerrainRadius = contactloc.GetRadius(); 
     609                 :      54006 : }
     610                 :            : 
     611                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     612                 :            : 
     613                 :          1 : void FGPropagate::SetTerrainElevation(double terrainElev)
     614                 :            : {
     615                 :          1 :   LocalTerrainRadius = terrainElev + SeaLevelRadius;
     616                 :          1 :   FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(LocalTerrainRadius);
     617                 :          1 : }
     618                 :            : 
     619                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     620                 :            : 
     621                 :       4910 : double FGPropagate::GetTerrainElevation(void) const
     622                 :            : {
     623                 :       4910 :   return FDMExec->GetGroundCallback()->GetTerrainGeoCentRadius()-SeaLevelRadius;
     624                 :            : }
     625                 :            : 
     626                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     627                 :            : //Todo: when should this be called - when should the new EPA be used to
     628                 :            : // calculate the transformation matrix, so that the matrix is not a step
     629                 :            : // ahead of the sim and the associated calculations?
     630                 :          0 : const FGMatrix33& FGPropagate::GetTi2ec(void)
     631                 :            : {
     632                 :      54006 :   return VState.vLocation.GetTi2ec();
     633                 :            : }
     634                 :            : 
     635                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     636                 :            : 
     637                 :          0 : const FGMatrix33& FGPropagate::GetTec2i(void)
     638                 :            : {
     639                 :          0 :   return VState.vLocation.GetTec2i();
     640                 :            : }
     641                 :            : 
     642                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     643                 :            : 
     644                 :          2 : void FGPropagate::SetAltitudeASL(double altASL)
     645                 :            : {
     646                 :          2 :   VState.vLocation.SetRadius( altASL + SeaLevelRadius );
     647                 :          2 : }
     648                 :            : 
     649                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     650                 :            : 
     651                 :          1 : double FGPropagate::GetLocalTerrainRadius(void) const
     652                 :            : {
     653                 :          1 :   return LocalTerrainRadius;
     654                 :            : }
     655                 :            : 
     656                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     657                 :            : 
     658                 :     117874 : double FGPropagate::GetDistanceAGL(void) const
     659                 :            : {
     660                 :     117874 :   return VState.vLocation.GetRadius() - LocalTerrainRadius;
     661                 :            : }
     662                 :            : 
     663                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     664                 :            : 
     665                 :          0 : void FGPropagate::SetDistanceAGL(double tt)
     666                 :            : {
     667                 :          0 :   VState.vLocation.SetRadius( tt + LocalTerrainRadius );
     668                 :          0 : }
     669                 :            : 
     670                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     671                 :            : 
     672                 :          1 : void FGPropagate::bind(void)
     673                 :            : {
     674                 :            :   typedef double (FGPropagate::*PMF)(int) const;
     675                 :            : 
     676                 :          1 :   PropertyManager->Tie("velocities/h-dot-fps", this, &FGPropagate::Gethdot);
     677                 :            : 
     678                 :          1 :   PropertyManager->Tie("velocities/v-north-fps", this, eNorth, (PMF)&FGPropagate::GetVel);
     679                 :          1 :   PropertyManager->Tie("velocities/v-east-fps", this, eEast, (PMF)&FGPropagate::GetVel);
     680                 :          1 :   PropertyManager->Tie("velocities/v-down-fps", this, eDown, (PMF)&FGPropagate::GetVel);
     681                 :            : 
     682                 :          1 :   PropertyManager->Tie("velocities/u-fps", this, eU, (PMF)&FGPropagate::GetUVW);
     683                 :          1 :   PropertyManager->Tie("velocities/v-fps", this, eV, (PMF)&FGPropagate::GetUVW);
     684                 :          1 :   PropertyManager->Tie("velocities/w-fps", this, eW, (PMF)&FGPropagate::GetUVW);
     685                 :            : 
     686                 :          1 :   PropertyManager->Tie("velocities/p-rad_sec", this, eP, (PMF)&FGPropagate::GetPQR);
     687                 :          1 :   PropertyManager->Tie("velocities/q-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQR);
     688                 :          1 :   PropertyManager->Tie("velocities/r-rad_sec", this, eR, (PMF)&FGPropagate::GetPQR);
     689                 :            : 
     690                 :          1 :   PropertyManager->Tie("velocities/pi-rad_sec", this, eP, (PMF)&FGPropagate::GetPQRi);
     691                 :          1 :   PropertyManager->Tie("velocities/qi-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQRi);
     692                 :          1 :   PropertyManager->Tie("velocities/ri-rad_sec", this, eR, (PMF)&FGPropagate::GetPQRi);
     693                 :            : 
     694                 :          1 :   PropertyManager->Tie("velocities/eci-velocity-mag-fps", this, &FGPropagate::GetInertialVelocityMagnitude);
     695                 :            : 
     696                 :          1 :   PropertyManager->Tie("accelerations/pdot-rad_sec2", this, eP, (PMF)&FGPropagate::GetPQRdot);
     697                 :          1 :   PropertyManager->Tie("accelerations/qdot-rad_sec2", this, eQ, (PMF)&FGPropagate::GetPQRdot);
     698                 :          1 :   PropertyManager->Tie("accelerations/rdot-rad_sec2", this, eR, (PMF)&FGPropagate::GetPQRdot);
     699                 :            : 
     700                 :          1 :   PropertyManager->Tie("accelerations/udot-ft_sec2", this, eU, (PMF)&FGPropagate::GetUVWdot);
     701                 :          1 :   PropertyManager->Tie("accelerations/vdot-ft_sec2", this, eV, (PMF)&FGPropagate::GetUVWdot);
     702                 :          1 :   PropertyManager->Tie("accelerations/wdot-ft_sec2", this, eW, (PMF)&FGPropagate::GetUVWdot);
     703                 :            : 
     704                 :          1 :   PropertyManager->Tie("position/h-sl-ft", this, &FGPropagate::GetAltitudeASL, &FGPropagate::SetAltitudeASL, true);
     705                 :          1 :   PropertyManager->Tie("position/h-sl-meters", this, &FGPropagate::GetAltitudeASLmeters, &FGPropagate::SetAltitudeASLmeters, true);
     706                 :          1 :   PropertyManager->Tie("position/lat-gc-rad", this, &FGPropagate::GetLatitude, &FGPropagate::SetLatitude);
     707                 :          1 :   PropertyManager->Tie("position/long-gc-rad", this, &FGPropagate::GetLongitude, &FGPropagate::SetLongitude);
     708                 :          1 :   PropertyManager->Tie("position/lat-gc-deg", this, &FGPropagate::GetLatitudeDeg, &FGPropagate::SetLatitudeDeg);
     709                 :          1 :   PropertyManager->Tie("position/long-gc-deg", this, &FGPropagate::GetLongitudeDeg, &FGPropagate::SetLongitudeDeg);
     710                 :          1 :   PropertyManager->Tie("position/lat-geod-rad", this, &FGPropagate::GetGeodLatitudeRad);
     711                 :          1 :   PropertyManager->Tie("position/lat-geod-deg", this, &FGPropagate::GetGeodLatitudeDeg);
     712                 :          1 :   PropertyManager->Tie("position/geod-alt-ft", this, &FGPropagate::GetGeodeticAltitude);
     713                 :          1 :   PropertyManager->Tie("position/h-agl-ft", this,  &FGPropagate::GetDistanceAGL, &FGPropagate::SetDistanceAGL);
     714                 :          1 :   PropertyManager->Tie("position/radius-to-vehicle-ft", this, &FGPropagate::GetRadius);
     715                 :            :   PropertyManager->Tie("position/terrain-elevation-asl-ft", this,
     716                 :            :                           &FGPropagate::GetTerrainElevation,
     717                 :          1 :                           &FGPropagate::SetTerrainElevation, false);
     718                 :            : 
     719                 :          1 :   PropertyManager->Tie("metrics/terrain-radius", this, &FGPropagate::GetLocalTerrainRadius);
     720                 :            : 
     721                 :          1 :   PropertyManager->Tie("attitude/phi-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
     722                 :          1 :   PropertyManager->Tie("attitude/theta-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
     723                 :          1 :   PropertyManager->Tie("attitude/psi-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
     724                 :            : 
     725                 :          1 :   PropertyManager->Tie("attitude/roll-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
     726                 :          1 :   PropertyManager->Tie("attitude/pitch-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
     727                 :          1 :   PropertyManager->Tie("attitude/heading-true-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
     728                 :            :   
     729                 :          1 :   PropertyManager->Tie("simulation/integrator/rate/rotational", (int*)&integrator_rotational_rate);
     730                 :          1 :   PropertyManager->Tie("simulation/integrator/rate/translational", (int*)&integrator_translational_rate);
     731                 :          1 :   PropertyManager->Tie("simulation/integrator/position/rotational", (int*)&integrator_rotational_position);
     732                 :          1 :   PropertyManager->Tie("simulation/integrator/position/translational", (int*)&integrator_translational_position);
     733                 :          1 :   PropertyManager->Tie("simulation/gravity-model", &gravType);
     734                 :          1 : }
     735                 :            : 
     736                 :            : //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
     737                 :            : //    The bitmasked value choices are as follows:
     738                 :            : //    unset: In this case (the default) JSBSim would only print
     739                 :            : //       out the normally expected messages, essentially echoing
     740                 :            : //       the config files as they are read. If the environment
     741                 :            : //       variable is not set, debug_lvl is set to 1 internally
     742                 :            : //    0: This requests JSBSim not to output any messages
     743                 :            : //       whatsoever.
     744                 :            : //    1: This value explicity requests the normal JSBSim
     745                 :            : //       startup messages
     746                 :            : //    2: This value asks for a message to be printed out when
     747                 :            : //       a class is instantiated
     748                 :            : //    4: When this value is set, a message is displayed when a
     749                 :            : //       FGModel object executes its Run() method
     750                 :            : //    8: When this value is set, various runtime state variables
     751                 :            : //       are printed out periodically
     752                 :            : //    16: When set various parameters are sanity checked and
     753                 :            : //       a message is printed out when they go out of bounds
     754                 :            : 
     755                 :      54008 : void FGPropagate::Debug(int from)
     756                 :            : {
     757         [ +  - ]:      54008 :   if (debug_lvl <= 0) return;
     758                 :            : 
     759                 :      54008 :   if (debug_lvl & 1) { // Standard console startup message output
     760                 :            :     if (from == 0) { // Constructor
     761                 :            : 
     762                 :            :     }
     763                 :            :   }
     764         [ -  + ]:      54008 :   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
     765         [ #  # ]:          0 :     if (from == 0) cout << "Instantiated: FGPropagate" << endl;
     766         [ #  # ]:          0 :     if (from == 1) cout << "Destroyed:    FGPropagate" << endl;
     767                 :            :   }
     768                 :      54008 :   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
     769                 :            :   }
     770 [ -  + ][ #  # ]:      54008 :   if (debug_lvl & 8 && from == 2) { // Runtime state variables
     771                 :            :     cout << endl << fgblue << highint << left 
     772                 :            :          << "  Propagation Report (English units: ft, degrees) at simulation time " << FDMExec->GetSimTime() << " seconds"
     773                 :          0 :          << reset << endl;
     774                 :            :     cout << endl;
     775                 :            :     cout << highint << "  Earth Position Angle (deg): " << setw(8) << setprecision(3) << reset
     776                 :          0 :                     << Inertial->GetEarthPositionAngleDeg() << endl;
     777                 :            :     cout << endl;
     778                 :          0 :     cout << highint << "  Body velocity (ft/sec): " << setw(8) << setprecision(3) << reset << VState.vUVW << endl;
     779                 :          0 :     cout << highint << "  Local velocity (ft/sec): " << setw(8) << setprecision(3) << reset << vVel << endl;
     780                 :          0 :     cout << highint << "  Inertial velocity (ft/sec): " << setw(8) << setprecision(3) << reset << VState.vInertialVelocity << endl;
     781                 :          0 :     cout << highint << "  Inertial Position (ft): " << setw(10) << setprecision(3) << reset << VState.vInertialPosition << endl;
     782                 :          0 :     cout << highint << "  Latitude (deg): " << setw(8) << setprecision(3) << reset << VState.vLocation.GetLatitudeDeg() << endl;
     783                 :          0 :     cout << highint << "  Longitude (deg): " << setw(8) << setprecision(3) << reset << VState.vLocation.GetLongitudeDeg() << endl;
     784                 :          0 :     cout << highint << "  Altitude ASL (ft): " << setw(8) << setprecision(3) << reset << GetAltitudeASL() << endl;
     785                 :          0 :     cout << highint << "  Acceleration (NED, ft/sec^2): " << setw(8) << setprecision(3) << reset << Tb2l*GetUVWdot() << endl;
     786                 :            :     cout << endl;
     787                 :            :     cout << highint << "  Matrix ECEF to Body (Orientation of Body with respect to ECEF): "
     788                 :          0 :                     << reset << endl << Tec2b.Dump("\t", "    ") << endl;
     789                 :            :     cout << highint << "    Associated Euler angles (deg): " << setw(8)
     790                 :            :                     << setprecision(3) << reset << (Tec2b.GetQuaternion().GetEuler()*radtodeg)
     791                 :          0 :                     << endl << endl;
     792                 :            : 
     793                 :            :     cout << highint << "  Matrix Body to ECEF (Orientation of ECEF with respect to Body):"
     794                 :          0 :                     << reset << endl << Tb2ec.Dump("\t", "    ") << endl;
     795                 :            :     cout << highint << "    Associated Euler angles (deg): " << setw(8)
     796                 :            :                     << setprecision(3) << reset << (Tb2ec.GetQuaternion().GetEuler()*radtodeg)
     797                 :          0 :                     << endl << endl;
     798                 :            : 
     799                 :            :     cout << highint << "  Matrix Local to Body (Orientation of Body with respect to Local):"
     800                 :          0 :                     << reset << endl << Tl2b.Dump("\t", "    ") << endl;
     801                 :            :     cout << highint << "    Associated Euler angles (deg): " << setw(8)
     802                 :            :                     << setprecision(3) << reset << (Tl2b.GetQuaternion().GetEuler()*radtodeg)
     803                 :          0 :                     << endl << endl;
     804                 :            : 
     805                 :            :     cout << highint << "  Matrix Body to Local (Orientation of Local with respect to Body):"
     806                 :          0 :                     << reset << endl << Tb2l.Dump("\t", "    ") << endl;
     807                 :            :     cout << highint << "    Associated Euler angles (deg): " << setw(8)
     808                 :            :                     << setprecision(3) << reset << (Tb2l.GetQuaternion().GetEuler()*radtodeg)
     809                 :          0 :                     << endl << endl;
     810                 :            : 
     811                 :            :     cout << highint << "  Matrix Local to ECEF (Orientation of ECEF with respect to Local):"
     812                 :          0 :                     << reset << endl << Tl2ec.Dump("\t", "    ") << endl;
     813                 :            :     cout << highint << "    Associated Euler angles (deg): " << setw(8)
     814                 :            :                     << setprecision(3) << reset << (Tl2ec.GetQuaternion().GetEuler()*radtodeg)
     815                 :          0 :                     << endl << endl;
     816                 :            : 
     817                 :            :     cout << highint << "  Matrix ECEF to Local (Orientation of Local with respect to ECEF):"
     818                 :          0 :                     << reset << endl << Tec2l.Dump("\t", "    ") << endl;
     819                 :            :     cout << highint << "    Associated Euler angles (deg): " << setw(8)
     820                 :            :                     << setprecision(3) << reset << (Tec2l.GetQuaternion().GetEuler()*radtodeg)
     821                 :          0 :                     << endl << endl;
     822                 :            : 
     823                 :            :     cout << highint << "  Matrix ECEF to Inertial (Orientation of Inertial with respect to ECEF):"
     824                 :          0 :                     << reset << endl << Tec2i.Dump("\t", "    ") << endl;
     825                 :            :     cout << highint << "    Associated Euler angles (deg): " << setw(8)
     826                 :            :                     << setprecision(3) << reset << (Tec2i.GetQuaternion().GetEuler()*radtodeg)
     827                 :          0 :                     << endl << endl;
     828                 :            : 
     829                 :            :     cout << highint << "  Matrix Inertial to ECEF (Orientation of ECEF with respect to Inertial):"
     830                 :          0 :                     << reset << endl << Ti2ec.Dump("\t", "    ") << endl;
     831                 :            :     cout << highint << "    Associated Euler angles (deg): " << setw(8)
     832                 :            :                     << setprecision(3) << reset << (Ti2ec.GetQuaternion().GetEuler()*radtodeg)
     833                 :          0 :                     << endl << endl;
     834                 :            : 
     835                 :            :     cout << highint << "  Matrix Inertial to Body (Orientation of Body with respect to Inertial):"
     836                 :          0 :                     << reset << endl << Ti2b.Dump("\t", "    ") << endl;
     837                 :            :     cout << highint << "    Associated Euler angles (deg): " << setw(8)
     838                 :            :                     << setprecision(3) << reset << (Ti2b.GetQuaternion().GetEuler()*radtodeg)
     839                 :          0 :                     << endl << endl;
     840                 :            : 
     841                 :            :     cout << highint << "  Matrix Body to Inertial (Orientation of Inertial with respect to Body):"
     842                 :          0 :                     << reset << endl << Tb2i.Dump("\t", "    ") << endl;
     843                 :            :     cout << highint << "    Associated Euler angles (deg): " << setw(8)
     844                 :            :                     << setprecision(3) << reset << (Tb2i.GetQuaternion().GetEuler()*radtodeg)
     845                 :          0 :                     << endl << endl;
     846                 :            : 
     847                 :            :     cout << highint << "  Matrix Inertial to Local (Orientation of Local with respect to Inertial):"
     848                 :          0 :                     << reset << endl << Ti2l.Dump("\t", "    ") << endl;
     849                 :            :     cout << highint << "    Associated Euler angles (deg): " << setw(8)
     850                 :            :                     << setprecision(3) << reset << (Ti2l.GetQuaternion().GetEuler()*radtodeg)
     851                 :          0 :                     << endl << endl;
     852                 :            : 
     853                 :            :     cout << highint << "  Matrix Local to Inertial (Orientation of Inertial with respect to Local):"
     854                 :          0 :                     << reset << endl << Tl2i.Dump("\t", "    ") << endl;
     855                 :            :     cout << highint << "    Associated Euler angles (deg): " << setw(8)
     856                 :            :                     << setprecision(3) << reset << (Tl2i.GetQuaternion().GetEuler()*radtodeg)
     857                 :          0 :                     << endl << endl;
     858                 :            : 
     859                 :          0 :     cout << setprecision(6); // reset the output stream
     860                 :            :   }
     861         [ -  + ]:      54008 :   if (debug_lvl & 16) { // Sanity checking
     862         [ #  # ]:          0 :     if (from == 2) { // State sanity checking
     863         [ #  # ]:          0 :       if (fabs(VState.vPQR.Magnitude()) > 1000.0) {
     864                 :          0 :         cerr << endl << "Vehicle rotation rate is excessive (>1000 rad/sec): " << VState.vPQR.Magnitude() << endl;
     865                 :          0 :         exit(-1);
     866                 :            :       }
     867         [ #  # ]:          0 :       if (fabs(VState.vUVW.Magnitude()) > 1.0e10) {
     868                 :          0 :         cerr << endl << "Vehicle velocity is excessive (>1e10 ft/sec): " << VState.vUVW.Magnitude() << endl;
     869                 :          0 :         exit(-1);
     870                 :            :       }
     871         [ #  # ]:          0 :       if (fabs(GetDistanceAGL()) > 1e10) {
     872                 :          0 :         cerr << endl << "Vehicle altitude is excessive (>1e10 ft): " << GetDistanceAGL() << endl;
     873                 :          0 :         exit(-1);
     874                 :            :       }
     875                 :            :     }
     876                 :            :   }
     877         [ -  + ]:      54008 :   if (debug_lvl & 64) {
     878         [ #  # ]:          0 :     if (from == 0) { // Constructor
     879                 :          0 :       cout << IdSrc << endl;
     880                 :          0 :       cout << IdHdr << endl;
     881                 :            :     }
     882                 :            :   }
     883                 :            : }
     884 [ +  + ][ +  - ]:         12 : }

Generated by: LCOV version 1.9