1 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3 Module: FGPropagate.cpp
6 Purpose: Integrate the EOM to determine instantaneous position
9 ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.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 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
57 # include <simgear/compiler.h>
58 # ifdef SG_HAVE_STD_INCLUDES
66 # if defined(sgi) && !defined(__GNUC__)
68 # if (_COMPILER_VERSION < 740)
79 #include "FGPropagate.h"
81 #include <FGFDMExec.h>
82 #include "FGAircraft.h"
83 #include "FGMassBalance.h"
84 #include "FGInertial.h"
85 #include <input_output/FGPropertyManager.h>
89 static const char *IdSrc = "$Id$";
90 static const char *IdHdr = ID_PROPAGATE;
92 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
94 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
96 FGPropagate::FGPropagate(FGFDMExec* fdmex) : FGModel(fdmex)
101 last2_vPQRdot.InitMatrix();
102 last_vPQRdot.InitMatrix();
103 vPQRdot.InitMatrix();
105 last2_vUVWdot.InitMatrix();
106 last_vUVWdot.InitMatrix();
107 vUVWdot.InitMatrix();
109 last2_vLocationDot.InitMatrix();
110 last_vLocationDot.InitMatrix();
111 vLocationDot.InitMatrix();
113 vOmegaLocal.InitMatrix();
115 integrator_rotational_rate = eAdamsBashforth2;
116 integrator_translational_rate = eAdamsBashforth2;
117 integrator_rotational_position = eTrapezoidal;
118 integrator_translational_position = eTrapezoidal;
124 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126 FGPropagate::~FGPropagate(void)
131 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
133 bool FGPropagate::InitModel(void)
135 if (!FGModel::InitModel()) return false;
137 SeaLevelRadius = Inertial->GetRefRadius(); // For initialization ONLY
138 RunwayRadius = SeaLevelRadius;
140 VState.vLocation.SetRadius( SeaLevelRadius + 4.0 ); // Todo Add terrain elevation?
141 VState.vLocation.SetEllipse(Inertial->GetSemimajor(), Inertial->GetSemiminor());
142 vOmega = FGColumnVector3( 0.0, 0.0, Inertial->omega() ); // Earth rotation vector
144 last2_vPQRdot.InitMatrix();
145 last_vPQRdot.InitMatrix();
146 vPQRdot.InitMatrix();
148 last2_vUVWdot.InitMatrix();
149 last_vUVWdot.InitMatrix();
150 vUVWdot.InitMatrix();
152 last2_vLocationDot.InitMatrix();
153 last_vLocationDot.InitMatrix();
154 vLocationDot.InitMatrix();
156 vOmegaLocal.InitMatrix();
158 integrator_rotational_rate = eAdamsBashforth2;
159 integrator_translational_rate = eAdamsBashforth2;
160 integrator_rotational_position = eTrapezoidal;
161 integrator_translational_position = eTrapezoidal;
166 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
168 void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
170 SeaLevelRadius = FGIC->GetSeaLevelRadiusFtIC();
171 RunwayRadius = SeaLevelRadius;
173 // Set the position lat/lon/radius
174 VState.vLocation.SetPosition( FGIC->GetLongitudeRadIC(),
175 FGIC->GetLatitudeRadIC(),
176 FGIC->GetAltitudeFtIC() + FGIC->GetSeaLevelRadiusFtIC() );
178 VehicleRadius = GetRadius();
179 radInv = 1.0/VehicleRadius;
181 // Set the Orientation from the euler angles
182 VState.vQtrn = FGQuaternion( FGIC->GetPhiRadIC(),
183 FGIC->GetThetaRadIC(),
184 FGIC->GetPsiRadIC() );
186 // Set the velocities in the instantaneus body frame
187 VState.vUVW = FGColumnVector3( FGIC->GetUBodyFpsIC(),
188 FGIC->GetVBodyFpsIC(),
189 FGIC->GetWBodyFpsIC() );
191 // Set the angular velocities in the instantaneus body frame.
192 VState.vPQR = FGColumnVector3( FGIC->GetPRadpsIC(),
194 FGIC->GetRRadpsIC() );
196 // Compute the local frame ECEF velocity
197 vVel = GetTb2l()*VState.vUVW;
199 // Finally, make sure that the quaternion stays normalized.
200 VState.vQtrn.Normalize();
202 // Recompute the RunwayRadius level.
203 RecomputeRunwayRadius();
206 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
208 Purpose: Called on a schedule to perform EOM integration
209 Notes: [JB] Run in standalone mode, SeaLevelRadius will be reference radius.
210 In FGFS, SeaLevelRadius is stuffed from FGJSBSim in JSBSim.cxx each pass.
212 At the top of this Run() function, see several "shortcuts" (or, aliases) being
213 set up for use later, rather than using the longer class->function() notation.
215 This propagation is done using the current state values
216 and current derivatives. Based on these values we compute an approximation to the
217 state values for (now + dt).
219 In the code below, variables named beginning with a small "v" refer to a
220 a column vector, variables named beginning with a "T" refer to a transformation
221 matrix. ECEF refers to Earth Centered Earth Fixed. ECI refers to Earth Centered
226 bool FGPropagate::Run(void)
228 if (FGModel::Run()) return true; // Fast return if we have nothing to do ...
229 if (FDMExec->Holding()) return false;
231 RecomputeRunwayRadius();
233 // Calculate current aircraft radius from center of planet
235 VehicleRadius = GetRadius();
236 radInv = 1.0/VehicleRadius;
238 // These local copies of the transformation matrices are for use this
239 // pass through Run() only.
241 Tl2b = GetTl2b(); // local to body frame transform
242 Tb2l = Tl2b.Transposed(); // body to local frame transform
243 Tl2ec = GetTl2ec(); // local to ECEF transform
244 Tec2l = Tl2ec.Transposed(); // ECEF to local frame transform
245 Tec2b = Tl2b * Tec2l; // ECEF to body frame transform
246 Tb2ec = Tec2b.Transposed(); // body to ECEF frame tranform
247 Ti2ec = GetTi2ec(); // ECI to ECEF transform
248 Tec2i = Ti2ec.Transposed(); // ECEF to ECI frame transform
249 Ti2b = Tec2b*Ti2ec; // ECI to body frame transform
250 Tb2i = Ti2b.Transposed(); // body to ECI frame transform
252 // Compute vehicle velocity wrt ECEF frame, expressed in Local horizontal frame.
253 vVel = Tb2l * VState.vUVW;
255 // Inertial angular velocity measured in the body frame.
256 vPQRi = VState.vPQR + Tec2b*vOmega;
258 // Calculate state derivatives
259 CalculatePQRdot(); // Angular rate derivative
260 CalculateUVWdot(); // Translational rate derivative
261 CalculateQuatdot(); // Angular orientation derivative
262 CalculateLocationdot(); // Translational position derivative
264 // Integrate to propagate the state
266 double dt = State->Getdt()*rate; // The 'stepsize'
268 // Propagate rotational velocity
270 switch(integrator_rotational_rate) {
271 case eRectEuler: VState.vPQR += dt*vPQRdot;
273 case eTrapezoidal: VState.vPQR += 0.5*dt*(vPQRdot + last_vPQRdot);
275 case eAdamsBashforth2: VState.vPQR += dt*(1.5*vPQRdot - 0.5*last_vPQRdot);
277 case eAdamsBashforth3: VState.vPQR += (1/12.0)*dt*(23.0*vPQRdot - 16.0*last_vPQRdot + 5.0*last2_vPQRdot);
279 case eNone: // do nothing, freeze angular rate
283 // Propagate translational velocity
285 switch(integrator_translational_rate) {
286 case eRectEuler: VState.vUVW += dt*vUVWdot;
288 case eTrapezoidal: VState.vUVW += 0.5*dt*(vUVWdot + last_vUVWdot);
290 case eAdamsBashforth2: VState.vUVW += dt*(1.5*vUVWdot - 0.5*last_vUVWdot);
292 case eAdamsBashforth3: VState.vUVW += (1/12.0)*dt*(23.0*vUVWdot - 16.0*last_vUVWdot + 5.0*last2_vUVWdot);
294 case eNone: // do nothing, freeze translational rate
298 // Propagate angular position
300 switch(integrator_rotational_position) {
301 case eRectEuler: VState.vQtrn += dt*vQtrndot;
303 case eTrapezoidal: VState.vQtrn += 0.5*dt*(vQtrndot + last_vQtrndot);
305 case eAdamsBashforth2: VState.vQtrn += dt*(1.5*vQtrndot - 0.5*last_vQtrndot);
307 case eAdamsBashforth3: VState.vQtrn += (1/12.0)*dt*(23.0*vQtrndot - 16.0*last_vQtrndot + 5.0*last2_vQtrndot);
309 case eNone: // do nothing, freeze angular position
313 // Propagate translational position
315 switch(integrator_translational_position) {
316 case eRectEuler: VState.vLocation += dt*vLocationDot;
318 case eTrapezoidal: VState.vLocation += 0.5*dt*(vLocationDot + last_vLocationDot);
320 case eAdamsBashforth2: VState.vLocation += dt*(1.5*vLocationDot - 0.5*last_vLocationDot);
322 case eAdamsBashforth3: VState.vLocation += (1/12.0)*dt*(23.0*vLocationDot - 16.0*last_vLocationDot + 5.0*last2_vLocationDot);
324 case eNone: // do nothing, freeze translational position
330 last2_vPQRdot = last_vPQRdot;
331 last_vPQRdot = vPQRdot;
333 last2_vUVWdot = last_vUVWdot;
334 last_vUVWdot = vUVWdot;
336 last2_vQtrndot = last_vQtrndot;
337 last_vQtrndot = vQtrndot;
339 last2_vLocationDot = last_vLocationDot;
340 last_vLocationDot = vLocationDot;
345 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346 // Compute body frame rotational accelerations based on the current body moments
348 // vPQRdot is the derivative of the absolute angular velocity of the vehicle
349 // (body rate with respect to the inertial frame), expressed in the body frame,
350 // where the derivative is taken in the body frame.
351 // J is the inertia matrix
352 // Jinv is the inverse inertia matrix
353 // vMoments is the moment vector in the body frame
354 // vPQRi is the total inertial angular velocity of the vehicle
355 // expressed in the body frame.
356 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
357 // Second edition (2004), eqn 1.5-16e (page 50)
359 void FGPropagate::CalculatePQRdot(void)
361 const FGColumnVector3& vMoments = Aircraft->GetMoments(); // current moments
362 const FGMatrix33& J = MassBalance->GetJ(); // inertia matrix
363 const FGMatrix33& Jinv = MassBalance->GetJinv(); // inertia matrix inverse
365 // Compute body frame rotational accelerations based on the current body
366 // moments and the total inertial angular velocity expressed in the body
369 vPQRdot = Jinv*(vMoments - vPQRi*(J*vPQRi));
372 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
373 // Compute the quaternion orientation derivative
375 // vQtrndot is the quaternion derivative.
376 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
377 // Second edition (2004), eqn 1.5-16b (page 50)
379 void FGPropagate::CalculateQuatdot(void)
381 vOmegaLocal.InitMatrix( radInv*vVel(eEast),
382 -radInv*vVel(eNorth),
383 -radInv*vVel(eEast)*VState.vLocation.GetTanLatitude() );
385 // Compute quaternion orientation derivative on current body rates
386 vQtrndot = VState.vQtrn.GetQDot( VState.vPQR - Tl2b*vOmegaLocal);
389 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
390 // This set of calculations results in the body frame accelerations being
392 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
393 // Second edition (2004), eqn 1.5-16d (page 50)
395 void FGPropagate::CalculateUVWdot(void)
397 double mass = MassBalance->GetMass(); // mass
398 const FGColumnVector3& vForces = Aircraft->GetForces(); // current forces
400 const FGColumnVector3 vGravAccel( 0.0, 0.0, Inertial->GetGAccel(VehicleRadius) );
402 // Begin to compute body frame accelerations based on the current body forces
403 vUVWdot = vForces/mass - VState.vPQR * VState.vUVW;
405 // Include Coriolis acceleration.
406 vUVWdot -= 2.0 * (Ti2b *vOmega) * VState.vUVW;
408 // Include Centrifugal acceleration.
409 if (!GroundReactions->GetWOW()) {
410 vUVWdot -= Ti2b*(vOmega*(vOmega*(Tec2i*VState.vLocation)));
413 // Include Gravitation accel
414 FGColumnVector3 gravAccel = Tl2b*vGravAccel;
415 vUVWdot += gravAccel;
418 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
420 void FGPropagate::CalculateLocationdot(void)
422 // Transform the vehicle velocity relative to the ECEF frame, expressed
423 // in the body frame, to be expressed in the ECEF frame.
424 vLocationDot = Tb2ec * VState.vUVW;
426 // Now, transform the velocity vector of the body relative to the origin (Earth
427 // center) to be expressed in the inertial frame, and add the vehicle velocity
428 // contribution due to the rotation of the planet. The above velocity is only
429 // relative to the rotating ECEF frame.
430 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
431 // Second edition (2004), eqn 1.5-16c (page 50)
433 vInertialVelocity = Tec2i * vLocationDot + (vOmega * (Tec2i * VState.vLocation));
436 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
438 void FGPropagate::RecomputeRunwayRadius(void)
440 // Get the runway radius.
441 FGLocation contactloc;
443 FGGroundCallback* gcb = FDMExec->GetGroundCallback();
444 double t = State->Getsim_time();
445 gcb->GetAGLevel(t, VState.vLocation, contactloc, dv, dv);
446 RunwayRadius = contactloc.GetRadius();
449 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
451 void FGPropagate::SetTerrainElevationASL(double tt)
453 FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(tt+SeaLevelRadius);
456 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
458 double FGPropagate::GetTerrainElevationASL(void) const
460 return FDMExec->GetGroundCallback()->GetTerrainGeoCentRadius()-SeaLevelRadius;
463 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
465 const FGMatrix33& FGPropagate::GetTi2ec(void)
467 return VState.vLocation.GetTi2ec(Inertial->GetEarthPositionAngle());
470 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
472 const FGMatrix33& FGPropagate::GetTec2i(void)
474 return VState.vLocation.GetTec2i(Inertial->GetEarthPositionAngle());
477 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
479 void FGPropagate::Seth(double tt)
481 VState.vLocation.SetRadius( tt + SeaLevelRadius );
484 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
486 double FGPropagate::GetRunwayRadius(void) const
491 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
493 double FGPropagate::GetDistanceAGL(void) const
495 return VState.vLocation.GetRadius() - RunwayRadius;
498 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
500 void FGPropagate::SetDistanceAGL(double tt)
502 VState.vLocation.SetRadius( tt + RunwayRadius );
505 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
507 void FGPropagate::bind(void)
509 typedef double (FGPropagate::*PMF)(int) const;
510 // typedef double (FGPropagate::*dPMF)() const;
511 PropertyManager->Tie("velocities/h-dot-fps", this, &FGPropagate::Gethdot);
513 PropertyManager->Tie("velocities/v-north-fps", this, eNorth, (PMF)&FGPropagate::GetVel);
514 PropertyManager->Tie("velocities/v-east-fps", this, eEast, (PMF)&FGPropagate::GetVel);
515 PropertyManager->Tie("velocities/v-down-fps", this, eDown, (PMF)&FGPropagate::GetVel);
517 PropertyManager->Tie("velocities/u-fps", this, eU, (PMF)&FGPropagate::GetUVW);
518 PropertyManager->Tie("velocities/v-fps", this, eV, (PMF)&FGPropagate::GetUVW);
519 PropertyManager->Tie("velocities/w-fps", this, eW, (PMF)&FGPropagate::GetUVW);
521 PropertyManager->Tie("velocities/p-rad_sec", this, eP, (PMF)&FGPropagate::GetPQR);
522 PropertyManager->Tie("velocities/q-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQR);
523 PropertyManager->Tie("velocities/r-rad_sec", this, eR, (PMF)&FGPropagate::GetPQR);
525 PropertyManager->Tie("velocities/eci-velocity-mag-fps", this, &FGPropagate::GetInertialVelocityMagnitude);
527 PropertyManager->Tie("accelerations/pdot-rad_sec2", this, eP, (PMF)&FGPropagate::GetPQRdot);
528 PropertyManager->Tie("accelerations/qdot-rad_sec2", this, eQ, (PMF)&FGPropagate::GetPQRdot);
529 PropertyManager->Tie("accelerations/rdot-rad_sec2", this, eR, (PMF)&FGPropagate::GetPQRdot);
531 PropertyManager->Tie("accelerations/udot-ft_sec2", this, eU, (PMF)&FGPropagate::GetUVWdot);
532 PropertyManager->Tie("accelerations/vdot-ft_sec2", this, eV, (PMF)&FGPropagate::GetUVWdot);
533 PropertyManager->Tie("accelerations/wdot-ft_sec2", this, eW, (PMF)&FGPropagate::GetUVWdot);
535 PropertyManager->Tie("position/h-sl-ft", this, &FGPropagate::Geth, &FGPropagate::Seth, true);
536 PropertyManager->Tie("position/h-sl-meters", this, &FGPropagate::Gethmeters, &FGPropagate::Sethmeters, true);
537 PropertyManager->Tie("position/lat-gc-rad", this, &FGPropagate::GetLatitude, &FGPropagate::SetLatitude);
538 PropertyManager->Tie("position/long-gc-rad", this, &FGPropagate::GetLongitude, &FGPropagate::SetLongitude);
539 PropertyManager->Tie("position/lat-gc-deg", this, &FGPropagate::GetLatitudeDeg, &FGPropagate::SetLatitudeDeg);
540 PropertyManager->Tie("position/long-gc-deg", this, &FGPropagate::GetLongitudeDeg, &FGPropagate::SetLongitudeDeg);
541 PropertyManager->Tie("position/lat-geod-rad", this, &FGPropagate::GetGeodLatitudeRad);
542 PropertyManager->Tie("position/lat-geod-deg", this, &FGPropagate::GetGeodLatitudeDeg);
543 PropertyManager->Tie("position/geod-alt-ft", this, &FGPropagate::GetGeodeticAltitude);
544 PropertyManager->Tie("position/h-agl-ft", this, &FGPropagate::GetDistanceAGL, &FGPropagate::SetDistanceAGL);
545 PropertyManager->Tie("position/radius-to-vehicle-ft", this, &FGPropagate::GetRadius);
546 PropertyManager->Tie("position/terrain-elevation-asl-ft", this,
547 &FGPropagate::GetTerrainElevationASL,
548 &FGPropagate::SetTerrainElevationASL, false);
550 PropertyManager->Tie("metrics/runway-radius", this, &FGPropagate::GetRunwayRadius);
552 PropertyManager->Tie("attitude/phi-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
553 PropertyManager->Tie("attitude/theta-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
554 PropertyManager->Tie("attitude/psi-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
556 PropertyManager->Tie("attitude/roll-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
557 PropertyManager->Tie("attitude/pitch-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
558 PropertyManager->Tie("attitude/heading-true-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
560 PropertyManager->Tie("simulation/integrator/rate/rotational", &integrator_rotational_rate);
561 PropertyManager->Tie("simulation/integrator/rate/translational", &integrator_translational_rate);
562 PropertyManager->Tie("simulation/integrator/position/rotational", &integrator_rotational_position);
563 PropertyManager->Tie("simulation/integrator/position/translational", &integrator_translational_position);
566 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
567 // The bitmasked value choices are as follows:
568 // unset: In this case (the default) JSBSim would only print
569 // out the normally expected messages, essentially echoing
570 // the config files as they are read. If the environment
571 // variable is not set, debug_lvl is set to 1 internally
572 // 0: This requests JSBSim not to output any messages
574 // 1: This value explicity requests the normal JSBSim
576 // 2: This value asks for a message to be printed out when
577 // a class is instantiated
578 // 4: When this value is set, a message is displayed when a
579 // FGModel object executes its Run() method
580 // 8: When this value is set, various runtime state variables
581 // are printed out periodically
582 // 16: When set various parameters are sanity checked and
583 // a message is printed out when they go out of bounds
585 void FGPropagate::Debug(int from)
587 if (debug_lvl <= 0) return;
589 if (debug_lvl & 1) { // Standard console startup message output
590 if (from == 0) { // Constructor
594 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
595 if (from == 0) cout << "Instantiated: FGPropagate" << endl;
596 if (from == 1) cout << "Destroyed: FGPropagate" << endl;
598 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
600 if (debug_lvl & 8 ) { // Runtime state variables
602 if (debug_lvl & 16) { // Sanity checking
604 if (debug_lvl & 64) {
605 if (from == 0) { // Constructor
606 cout << IdSrc << endl;
607 cout << IdHdr << endl;