1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 Module: FGPropagate.cpp
6 Purpose: Integrate the EOM to determine instantaneous position
9 ------------- Copyright (C) 1999 Jon S. Berndt (jon@jsbsim.org) -------------
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
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
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.
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.
28 FUNCTIONAL DESCRIPTION
29 --------------------------------------------------------------------------------
30 This class encapsulates the integration of rates and accelerations to get the
31 current position of the aircraft.
34 --------------------------------------------------------------------------------
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
43 [2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
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
52 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
54 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
60 #include "FGPropagate.h"
61 #include "FGFDMExec.h"
63 #include "FGAircraft.h"
64 #include "FGMassBalance.h"
65 #include "FGInertial.h"
66 #include "input_output/FGPropertyManager.h"
72 static const char *IdSrc = "$Id$";
73 static const char *IdHdr = ID_PROPAGATE;
75 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
77 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
79 FGPropagate::FGPropagate(FGFDMExec* fdmex) : FGModel(fdmex)
84 last2_vPQRdot.InitMatrix();
85 last_vPQRdot.InitMatrix();
88 last2_vQtrndot = FGQuaternion(0,0,0);
89 last_vQtrndot = FGQuaternion(0,0,0);
90 vQtrndot = FGQuaternion(0,0,0);
92 last2_vUVWdot.InitMatrix();
93 last_vUVWdot.InitMatrix();
96 last2_vLocationDot.InitMatrix();
97 last_vLocationDot.InitMatrix();
98 vLocationDot.InitMatrix();
100 vOmegaLocal.InitMatrix();
102 integrator_rotational_rate = eAdamsBashforth2;
103 integrator_translational_rate = eTrapezoidal;
104 integrator_rotational_position = eAdamsBashforth2;
105 integrator_translational_position = eTrapezoidal;
111 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113 FGPropagate::~FGPropagate(void)
118 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
120 bool FGPropagate::InitModel(void)
122 if (!FGModel::InitModel()) return false;
124 // For initialization ONLY:
125 SeaLevelRadius = LocalTerrainRadius = Inertial->GetRefRadius();
127 VState.vLocation.SetRadius( LocalTerrainRadius + 4.0 );
128 VState.vLocation.SetEllipse(Inertial->GetSemimajor(), Inertial->GetSemiminor());
129 vOmega = FGColumnVector3( 0.0, 0.0, Inertial->omega() ); // Earth rotation vector
131 last2_vPQRdot.InitMatrix();
132 last_vPQRdot.InitMatrix();
133 vPQRdot.InitMatrix();
135 last2_vQtrndot = FGQuaternion(0,0,0);
136 last_vQtrndot = FGQuaternion(0,0,0);
137 vQtrndot = FGQuaternion(0,0,0);
139 last2_vUVWdot.InitMatrix();
140 last_vUVWdot.InitMatrix();
141 vUVWdot.InitMatrix();
143 last2_vLocationDot.InitMatrix();
144 last_vLocationDot.InitMatrix();
145 vLocationDot.InitMatrix();
147 vOmegaLocal.InitMatrix();
149 integrator_rotational_rate = eAdamsBashforth2;
150 integrator_translational_rate = eTrapezoidal;
151 integrator_rotational_position = eAdamsBashforth2;
152 integrator_translational_position = eTrapezoidal;
157 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
159 void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
161 SetSeaLevelRadius(FGIC->GetSeaLevelRadiusFtIC());
162 SetTerrainElevation(FGIC->GetTerrainElevationFtIC());
164 // Set the position lat/lon/radius
165 VState.vLocation.SetPosition( FGIC->GetLongitudeRadIC(),
166 FGIC->GetLatitudeRadIC(),
167 FGIC->GetAltitudeASLFtIC() + FGIC->GetSeaLevelRadiusFtIC() );
169 VehicleRadius = GetRadius();
170 radInv = 1.0/VehicleRadius;
172 // Set the Orientation from the euler angles
173 VState.vQtrn = FGQuaternion( FGIC->GetPhiRadIC(),
174 FGIC->GetThetaRadIC(),
175 FGIC->GetPsiRadIC() );
177 // Set the velocities in the instantaneus body frame
178 VState.vUVW = FGColumnVector3( FGIC->GetUBodyFpsIC(),
179 FGIC->GetVBodyFpsIC(),
180 FGIC->GetWBodyFpsIC() );
182 // Set the angular velocities in the instantaneus body frame.
183 VState.vPQR = FGColumnVector3( FGIC->GetPRadpsIC(),
185 FGIC->GetRRadpsIC() );
187 // Compute the local frame ECEF velocity
188 vVel = GetTb2l()*VState.vUVW;
190 // Finally, make sure that the quaternion stays normalized.
191 VState.vQtrn.Normalize();
193 // Recompute the LocalTerrainRadius.
194 RecomputeLocalTerrainRadius();
196 // These local copies of the transformation matrices are for use for
197 // initial conditions only.
199 Tl2b = GetTl2b(); // local to body frame transform
200 Tb2l = Tl2b.Transposed(); // body to local frame transform
201 Tl2ec = GetTl2ec(); // local to ECEF transform
202 Tec2l = Tl2ec.Transposed(); // ECEF to local frame transform
203 Tec2b = Tl2b * Tec2l; // ECEF to body frame transform
204 Tb2ec = Tec2b.Transposed(); // body to ECEF frame tranform
205 Ti2ec = GetTi2ec(); // ECI to ECEF transform
206 Tec2i = Ti2ec.Transposed(); // ECEF to ECI frame transform
207 Ti2b = Tec2b*Ti2ec; // ECI to body frame transform
208 Tb2i = Ti2b.Transposed(); // body to ECI frame transform
211 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
213 Purpose: Called on a schedule to perform EOM integration
214 Notes: [JB] Run in standalone mode, SeaLevelRadius will be reference radius.
215 In FGFS, SeaLevelRadius is stuffed from FGJSBSim in JSBSim.cxx each pass.
217 At the top of this Run() function, see several "shortcuts" (or, aliases) being
218 set up for use later, rather than using the longer class->function() notation.
220 This propagation is done using the current state values
221 and current derivatives. Based on these values we compute an approximation to the
222 state values for (now + dt).
224 In the code below, variables named beginning with a small "v" refer to a
225 a column vector, variables named beginning with a "T" refer to a transformation
226 matrix. ECEF refers to Earth Centered Earth Fixed. ECI refers to Earth Centered
231 bool FGPropagate::Run(void)
233 if (FGModel::Run()) return true; // Fast return if we have nothing to do ...
234 if (FDMExec->Holding()) return false;
238 RecomputeLocalTerrainRadius();
240 // Calculate current aircraft radius from center of planet
242 VehicleRadius = GetRadius();
243 radInv = 1.0/VehicleRadius;
245 // These local copies of the transformation matrices are for use this
246 // pass through Run() only.
248 Tl2b = GetTl2b(); // local to body frame transform
249 Tb2l = Tl2b.Transposed(); // body to local frame transform
250 Tl2ec = GetTl2ec(); // local to ECEF transform
251 Tec2l = Tl2ec.Transposed(); // ECEF to local frame transform
252 Tec2b = Tl2b * Tec2l; // ECEF to body frame transform
253 Tb2ec = Tec2b.Transposed(); // body to ECEF frame tranform
254 Ti2ec = GetTi2ec(); // ECI to ECEF transform
255 Tec2i = Ti2ec.Transposed(); // ECEF to ECI frame transform
256 Ti2b = Tec2b*Ti2ec; // ECI to body frame transform
257 Tb2i = Ti2b.Transposed(); // body to ECI frame transform
259 // Compute vehicle velocity wrt ECEF frame, expressed in Local horizontal frame.
260 vVel = Tb2l * VState.vUVW;
262 // Inertial angular velocity measured in the body frame.
263 vPQRi = VState.vPQR + Tec2b*vOmega;
265 // Calculate state derivatives
266 CalculatePQRdot(); // Angular rate derivative
267 CalculateUVWdot(); // Translational rate derivative
268 CalculateQuatdot(); // Angular orientation derivative
269 CalculateLocationdot(); // Translational position derivative
271 // Integrate to propagate the state
273 double dt = State->Getdt()*rate; // The 'stepsize'
275 // Propagate rotational velocity
277 switch(integrator_rotational_rate) {
278 case eRectEuler: VState.vPQR += dt*vPQRdot;
280 case eTrapezoidal: VState.vPQR += 0.5*dt*(vPQRdot + last_vPQRdot);
282 case eAdamsBashforth2: VState.vPQR += dt*(1.5*vPQRdot - 0.5*last_vPQRdot);
284 case eAdamsBashforth3: VState.vPQR += (1/12.0)*dt*(23.0*vPQRdot - 16.0*last_vPQRdot + 5.0*last2_vPQRdot);
286 case eNone: // do nothing, freeze angular rate
290 // Propagate translational velocity
292 switch(integrator_translational_rate) {
293 case eRectEuler: VState.vUVW += dt*vUVWdot;
295 case eTrapezoidal: VState.vUVW += 0.5*dt*(vUVWdot + last_vUVWdot);
297 case eAdamsBashforth2: VState.vUVW += dt*(1.5*vUVWdot - 0.5*last_vUVWdot);
299 case eAdamsBashforth3: VState.vUVW += (1/12.0)*dt*(23.0*vUVWdot - 16.0*last_vUVWdot + 5.0*last2_vUVWdot);
301 case eNone: // do nothing, freeze translational rate
305 // Propagate angular position
307 switch(integrator_rotational_position) {
308 case eRectEuler: VState.vQtrn += dt*vQtrndot;
310 case eTrapezoidal: VState.vQtrn += 0.5*dt*(vQtrndot + last_vQtrndot);
312 case eAdamsBashforth2: VState.vQtrn += dt*(1.5*vQtrndot - 0.5*last_vQtrndot);
314 case eAdamsBashforth3: VState.vQtrn += (1/12.0)*dt*(23.0*vQtrndot - 16.0*last_vQtrndot + 5.0*last2_vQtrndot);
316 case eNone: // do nothing, freeze angular position
320 // Propagate translational position
322 switch(integrator_translational_position) {
323 case eRectEuler: VState.vLocation += dt*vLocationDot;
325 case eTrapezoidal: VState.vLocation += 0.5*dt*(vLocationDot + last_vLocationDot);
327 case eAdamsBashforth2: VState.vLocation += dt*(1.5*vLocationDot - 0.5*last_vLocationDot);
329 case eAdamsBashforth3: VState.vLocation += (1/12.0)*dt*(23.0*vLocationDot - 16.0*last_vLocationDot + 5.0*last2_vLocationDot);
331 case eNone: // do nothing, freeze translational position
337 last2_vPQRdot = last_vPQRdot;
338 last_vPQRdot = vPQRdot;
340 last2_vUVWdot = last_vUVWdot;
341 last_vUVWdot = vUVWdot;
343 last2_vQtrndot = last_vQtrndot;
344 last_vQtrndot = vQtrndot;
346 last2_vLocationDot = last_vLocationDot;
347 last_vLocationDot = vLocationDot;
355 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
356 // Compute body frame rotational accelerations based on the current body moments
358 // vPQRdot is the derivative of the absolute angular velocity of the vehicle
359 // (body rate with respect to the inertial frame), expressed in the body frame,
360 // where the derivative is taken in the body frame.
361 // J is the inertia matrix
362 // Jinv is the inverse inertia matrix
363 // vMoments is the moment vector in the body frame
364 // vPQRi is the total inertial angular velocity of the vehicle
365 // expressed in the body frame.
366 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
367 // Second edition (2004), eqn 1.5-16e (page 50)
369 void FGPropagate::CalculatePQRdot(void)
371 const FGColumnVector3& vMoments = Aircraft->GetMoments(); // current moments
372 const FGMatrix33& J = MassBalance->GetJ(); // inertia matrix
373 const FGMatrix33& Jinv = MassBalance->GetJinv(); // inertia matrix inverse
375 // Compute body frame rotational accelerations based on the current body
376 // moments and the total inertial angular velocity expressed in the body
379 vPQRdot = Jinv*(vMoments - vPQRi*(J*vPQRi));
382 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
383 // Compute the quaternion orientation derivative
385 // vQtrndot is the quaternion derivative.
386 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
387 // Second edition (2004), eqn 1.5-16b (page 50)
389 void FGPropagate::CalculateQuatdot(void)
391 vOmegaLocal.InitMatrix( radInv*vVel(eEast),
392 -radInv*vVel(eNorth),
393 -radInv*vVel(eEast)*VState.vLocation.GetTanLatitude() );
395 // Compute quaternion orientation derivative on current body rates
396 vQtrndot = VState.vQtrn.GetQDot( VState.vPQR - Tl2b*vOmegaLocal);
399 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
400 // This set of calculations results in the body frame accelerations being
402 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
403 // Second edition (2004), eqn 1.5-16d (page 50)
405 void FGPropagate::CalculateUVWdot(void)
407 double mass = MassBalance->GetMass(); // mass
408 const FGColumnVector3& vForces = Aircraft->GetForces(); // current forces
410 const FGColumnVector3 vGravAccel( 0.0, 0.0, Inertial->GetGAccel(VehicleRadius) );
412 // Begin to compute body frame accelerations based on the current body forces
413 vUVWdot = vForces/mass - VState.vPQR * VState.vUVW;
415 // Include Coriolis acceleration.
416 vUVWdot -= 2.0 * (Ti2b *vOmega) * VState.vUVW;
418 // Include Centrifugal acceleration.
419 if (!GroundReactions->GetWOW()) {
420 vUVWdot -= Ti2b*(vOmega*(vOmega*(Tec2i*VState.vLocation)));
423 // Include Gravitation accel
424 FGColumnVector3 gravAccel = Tl2b*vGravAccel;
425 vUVWdot += gravAccel;
428 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
430 void FGPropagate::CalculateLocationdot(void)
432 // Transform the vehicle velocity relative to the ECEF frame, expressed
433 // in the body frame, to be expressed in the ECEF frame.
434 vLocationDot = Tb2ec * VState.vUVW;
436 // Now, transform the velocity vector of the body relative to the origin (Earth
437 // center) to be expressed in the inertial frame, and add the vehicle velocity
438 // contribution due to the rotation of the planet. The above velocity is only
439 // relative to the rotating ECEF frame.
440 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
441 // Second edition (2004), eqn 1.5-16c (page 50)
443 vInertialVelocity = Tec2i * vLocationDot + (vOmega * (Tec2i * VState.vLocation));
446 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
448 void FGPropagate::RecomputeLocalTerrainRadius(void)
450 double t = State->Getsim_time();
452 // Get the LocalTerrain radius.
453 FGLocation contactloc;
455 FDMExec->GetGroundCallback()->GetAGLevel(t, VState.vLocation, contactloc, dv, dv);
456 LocalTerrainRadius = contactloc.GetRadius();
459 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
461 void FGPropagate::SetTerrainElevation(double terrainElev)
463 LocalTerrainRadius = terrainElev + SeaLevelRadius;
464 FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(LocalTerrainRadius);
467 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
469 double FGPropagate::GetTerrainElevation(void) const
471 return FDMExec->GetGroundCallback()->GetTerrainGeoCentRadius()-SeaLevelRadius;
474 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
476 const FGMatrix33& FGPropagate::GetTi2ec(void)
478 return VState.vLocation.GetTi2ec(Inertial->GetEarthPositionAngle());
481 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
483 const FGMatrix33& FGPropagate::GetTec2i(void)
485 return VState.vLocation.GetTec2i(Inertial->GetEarthPositionAngle());
488 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490 void FGPropagate::SetAltitudeASL(double altASL)
492 VState.vLocation.SetRadius( altASL + SeaLevelRadius );
495 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
497 double FGPropagate::GetLocalTerrainRadius(void) const
499 return LocalTerrainRadius;
502 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
504 double FGPropagate::GetDistanceAGL(void) const
506 return VState.vLocation.GetRadius() - LocalTerrainRadius;
509 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
511 void FGPropagate::SetDistanceAGL(double tt)
513 VState.vLocation.SetRadius( tt + LocalTerrainRadius );
516 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
518 void FGPropagate::bind(void)
520 typedef double (FGPropagate::*PMF)(int) const;
521 // typedef double (FGPropagate::*dPMF)() const;
522 PropertyManager->Tie("velocities/h-dot-fps", this, &FGPropagate::Gethdot);
524 PropertyManager->Tie("velocities/v-north-fps", this, eNorth, (PMF)&FGPropagate::GetVel);
525 PropertyManager->Tie("velocities/v-east-fps", this, eEast, (PMF)&FGPropagate::GetVel);
526 PropertyManager->Tie("velocities/v-down-fps", this, eDown, (PMF)&FGPropagate::GetVel);
528 PropertyManager->Tie("velocities/u-fps", this, eU, (PMF)&FGPropagate::GetUVW);
529 PropertyManager->Tie("velocities/v-fps", this, eV, (PMF)&FGPropagate::GetUVW);
530 PropertyManager->Tie("velocities/w-fps", this, eW, (PMF)&FGPropagate::GetUVW);
532 PropertyManager->Tie("velocities/p-rad_sec", this, eP, (PMF)&FGPropagate::GetPQR);
533 PropertyManager->Tie("velocities/q-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQR);
534 PropertyManager->Tie("velocities/r-rad_sec", this, eR, (PMF)&FGPropagate::GetPQR);
536 PropertyManager->Tie("velocities/pi-rad_sec", this, eP, (PMF)&FGPropagate::GetPQRi);
537 PropertyManager->Tie("velocities/qi-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQRi);
538 PropertyManager->Tie("velocities/ri-rad_sec", this, eR, (PMF)&FGPropagate::GetPQRi);
540 PropertyManager->Tie("velocities/eci-velocity-mag-fps", this, &FGPropagate::GetInertialVelocityMagnitude);
542 PropertyManager->Tie("accelerations/pdot-rad_sec2", this, eP, (PMF)&FGPropagate::GetPQRdot);
543 PropertyManager->Tie("accelerations/qdot-rad_sec2", this, eQ, (PMF)&FGPropagate::GetPQRdot);
544 PropertyManager->Tie("accelerations/rdot-rad_sec2", this, eR, (PMF)&FGPropagate::GetPQRdot);
546 PropertyManager->Tie("accelerations/udot-ft_sec2", this, eU, (PMF)&FGPropagate::GetUVWdot);
547 PropertyManager->Tie("accelerations/vdot-ft_sec2", this, eV, (PMF)&FGPropagate::GetUVWdot);
548 PropertyManager->Tie("accelerations/wdot-ft_sec2", this, eW, (PMF)&FGPropagate::GetUVWdot);
550 PropertyManager->Tie("position/h-sl-ft", this, &FGPropagate::GetAltitudeASL, &FGPropagate::SetAltitudeASL, true);
551 PropertyManager->Tie("position/h-sl-meters", this, &FGPropagate::GetAltitudeASLmeters, &FGPropagate::SetAltitudeASLmeters, true);
552 PropertyManager->Tie("position/lat-gc-rad", this, &FGPropagate::GetLatitude, &FGPropagate::SetLatitude);
553 PropertyManager->Tie("position/long-gc-rad", this, &FGPropagate::GetLongitude, &FGPropagate::SetLongitude);
554 PropertyManager->Tie("position/lat-gc-deg", this, &FGPropagate::GetLatitudeDeg, &FGPropagate::SetLatitudeDeg);
555 PropertyManager->Tie("position/long-gc-deg", this, &FGPropagate::GetLongitudeDeg, &FGPropagate::SetLongitudeDeg);
556 PropertyManager->Tie("position/lat-geod-rad", this, &FGPropagate::GetGeodLatitudeRad);
557 PropertyManager->Tie("position/lat-geod-deg", this, &FGPropagate::GetGeodLatitudeDeg);
558 PropertyManager->Tie("position/geod-alt-ft", this, &FGPropagate::GetGeodeticAltitude);
559 PropertyManager->Tie("position/h-agl-ft", this, &FGPropagate::GetDistanceAGL, &FGPropagate::SetDistanceAGL);
560 PropertyManager->Tie("position/radius-to-vehicle-ft", this, &FGPropagate::GetRadius);
561 PropertyManager->Tie("position/terrain-elevation-asl-ft", this,
562 &FGPropagate::GetTerrainElevation,
563 &FGPropagate::SetTerrainElevation, false);
565 PropertyManager->Tie("metrics/terrain-radius", this, &FGPropagate::GetLocalTerrainRadius);
567 PropertyManager->Tie("attitude/phi-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
568 PropertyManager->Tie("attitude/theta-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
569 PropertyManager->Tie("attitude/psi-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
571 PropertyManager->Tie("attitude/roll-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
572 PropertyManager->Tie("attitude/pitch-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
573 PropertyManager->Tie("attitude/heading-true-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
575 PropertyManager->Tie("simulation/integrator/rate/rotational", &integrator_rotational_rate);
576 PropertyManager->Tie("simulation/integrator/rate/translational", &integrator_translational_rate);
577 PropertyManager->Tie("simulation/integrator/position/rotational", &integrator_rotational_position);
578 PropertyManager->Tie("simulation/integrator/position/translational", &integrator_translational_position);
581 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
582 // The bitmasked value choices are as follows:
583 // unset: In this case (the default) JSBSim would only print
584 // out the normally expected messages, essentially echoing
585 // the config files as they are read. If the environment
586 // variable is not set, debug_lvl is set to 1 internally
587 // 0: This requests JSBSim not to output any messages
589 // 1: This value explicity requests the normal JSBSim
591 // 2: This value asks for a message to be printed out when
592 // a class is instantiated
593 // 4: When this value is set, a message is displayed when a
594 // FGModel object executes its Run() method
595 // 8: When this value is set, various runtime state variables
596 // are printed out periodically
597 // 16: When set various parameters are sanity checked and
598 // a message is printed out when they go out of bounds
600 void FGPropagate::Debug(int from)
602 if (debug_lvl <= 0) return;
604 if (debug_lvl & 1) { // Standard console startup message output
605 if (from == 0) { // Constructor
609 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
610 if (from == 0) cout << "Instantiated: FGPropagate" << endl;
611 if (from == 1) cout << "Destroyed: FGPropagate" << endl;
613 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
615 if (debug_lvl & 8 ) { // Runtime state variables
617 if (debug_lvl & 16) { // Sanity checking
618 if (from == 2) { // State sanity checking
619 if (fabs(VState.vPQR.Magnitude()) > 1000.0) {
620 cerr << endl << "Vehicle rotation rate is excessive (>1000 rad/sec): " << VState.vPQR.Magnitude() << endl;
623 if (fabs(VState.vUVW.Magnitude()) > 1.0e10) {
624 cerr << endl << "Vehicle velocity is excessive (>1e10 ft/sec): " << VState.vUVW.Magnitude() << endl;
627 if (fabs(GetDistanceAGL()) > 1e10) {
628 cerr << endl << "Vehicle altitude is excessive (>1e10 ft): " << GetDistanceAGL() << endl;
633 if (debug_lvl & 64) {
634 if (from == 0) { // Constructor
635 cout << IdSrc << endl;
636 cout << IdHdr << endl;