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;
236 RecomputeLocalTerrainRadius();
238 // Calculate current aircraft radius from center of planet
240 VehicleRadius = GetRadius();
241 radInv = 1.0/VehicleRadius;
243 // These local copies of the transformation matrices are for use this
244 // pass through Run() only.
246 Tl2b = GetTl2b(); // local to body frame transform
247 Tb2l = Tl2b.Transposed(); // body to local frame transform
248 Tl2ec = GetTl2ec(); // local to ECEF transform
249 Tec2l = Tl2ec.Transposed(); // ECEF to local frame transform
250 Tec2b = Tl2b * Tec2l; // ECEF to body frame transform
251 Tb2ec = Tec2b.Transposed(); // body to ECEF frame tranform
252 Ti2ec = GetTi2ec(); // ECI to ECEF transform
253 Tec2i = Ti2ec.Transposed(); // ECEF to ECI frame transform
254 Ti2b = Tec2b*Ti2ec; // ECI to body frame transform
255 Tb2i = Ti2b.Transposed(); // body to ECI frame transform
257 // Compute vehicle velocity wrt ECEF frame, expressed in Local horizontal frame.
258 vVel = Tb2l * VState.vUVW;
260 // Inertial angular velocity measured in the body frame.
261 vPQRi = VState.vPQR + Tec2b*vOmega;
263 // Calculate state derivatives
264 CalculatePQRdot(); // Angular rate derivative
265 CalculateUVWdot(); // Translational rate derivative
266 CalculateQuatdot(); // Angular orientation derivative
267 CalculateLocationdot(); // Translational position derivative
269 // Integrate to propagate the state
271 double dt = State->Getdt()*rate; // The 'stepsize'
273 // Propagate rotational velocity
275 switch(integrator_rotational_rate) {
276 case eRectEuler: VState.vPQR += dt*vPQRdot;
278 case eTrapezoidal: VState.vPQR += 0.5*dt*(vPQRdot + last_vPQRdot);
280 case eAdamsBashforth2: VState.vPQR += dt*(1.5*vPQRdot - 0.5*last_vPQRdot);
282 case eAdamsBashforth3: VState.vPQR += (1/12.0)*dt*(23.0*vPQRdot - 16.0*last_vPQRdot + 5.0*last2_vPQRdot);
284 case eNone: // do nothing, freeze angular rate
288 // Propagate translational velocity
290 switch(integrator_translational_rate) {
291 case eRectEuler: VState.vUVW += dt*vUVWdot;
293 case eTrapezoidal: VState.vUVW += 0.5*dt*(vUVWdot + last_vUVWdot);
295 case eAdamsBashforth2: VState.vUVW += dt*(1.5*vUVWdot - 0.5*last_vUVWdot);
297 case eAdamsBashforth3: VState.vUVW += (1/12.0)*dt*(23.0*vUVWdot - 16.0*last_vUVWdot + 5.0*last2_vUVWdot);
299 case eNone: // do nothing, freeze translational rate
303 // Propagate angular position
305 switch(integrator_rotational_position) {
306 case eRectEuler: VState.vQtrn += dt*vQtrndot;
308 case eTrapezoidal: VState.vQtrn += 0.5*dt*(vQtrndot + last_vQtrndot);
310 case eAdamsBashforth2: VState.vQtrn += dt*(1.5*vQtrndot - 0.5*last_vQtrndot);
312 case eAdamsBashforth3: VState.vQtrn += (1/12.0)*dt*(23.0*vQtrndot - 16.0*last_vQtrndot + 5.0*last2_vQtrndot);
314 case eNone: // do nothing, freeze angular position
318 // Propagate translational position
320 switch(integrator_translational_position) {
321 case eRectEuler: VState.vLocation += dt*vLocationDot;
323 case eTrapezoidal: VState.vLocation += 0.5*dt*(vLocationDot + last_vLocationDot);
325 case eAdamsBashforth2: VState.vLocation += dt*(1.5*vLocationDot - 0.5*last_vLocationDot);
327 case eAdamsBashforth3: VState.vLocation += (1/12.0)*dt*(23.0*vLocationDot - 16.0*last_vLocationDot + 5.0*last2_vLocationDot);
329 case eNone: // do nothing, freeze translational position
335 last2_vPQRdot = last_vPQRdot;
336 last_vPQRdot = vPQRdot;
338 last2_vUVWdot = last_vUVWdot;
339 last_vUVWdot = vUVWdot;
341 last2_vQtrndot = last_vQtrndot;
342 last_vQtrndot = vQtrndot;
344 last2_vLocationDot = last_vLocationDot;
345 last_vLocationDot = vLocationDot;
351 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
352 // Compute body frame rotational accelerations based on the current body moments
354 // vPQRdot is the derivative of the absolute angular velocity of the vehicle
355 // (body rate with respect to the inertial frame), expressed in the body frame,
356 // where the derivative is taken in the body frame.
357 // J is the inertia matrix
358 // Jinv is the inverse inertia matrix
359 // vMoments is the moment vector in the body frame
360 // vPQRi is the total inertial angular velocity of the vehicle
361 // expressed in the body frame.
362 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
363 // Second edition (2004), eqn 1.5-16e (page 50)
365 void FGPropagate::CalculatePQRdot(void)
367 const FGColumnVector3& vMoments = Aircraft->GetMoments(); // current moments
368 const FGMatrix33& J = MassBalance->GetJ(); // inertia matrix
369 const FGMatrix33& Jinv = MassBalance->GetJinv(); // inertia matrix inverse
371 // Compute body frame rotational accelerations based on the current body
372 // moments and the total inertial angular velocity expressed in the body
375 vPQRdot = Jinv*(vMoments - vPQRi*(J*vPQRi));
378 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
379 // Compute the quaternion orientation derivative
381 // vQtrndot is the quaternion derivative.
382 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
383 // Second edition (2004), eqn 1.5-16b (page 50)
385 void FGPropagate::CalculateQuatdot(void)
387 vOmegaLocal.InitMatrix( radInv*vVel(eEast),
388 -radInv*vVel(eNorth),
389 -radInv*vVel(eEast)*VState.vLocation.GetTanLatitude() );
391 // Compute quaternion orientation derivative on current body rates
392 vQtrndot = VState.vQtrn.GetQDot( VState.vPQR - Tl2b*vOmegaLocal);
395 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
396 // This set of calculations results in the body frame accelerations being
398 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
399 // Second edition (2004), eqn 1.5-16d (page 50)
401 void FGPropagate::CalculateUVWdot(void)
403 double mass = MassBalance->GetMass(); // mass
404 const FGColumnVector3& vForces = Aircraft->GetForces(); // current forces
406 const FGColumnVector3 vGravAccel( 0.0, 0.0, Inertial->GetGAccel(VehicleRadius) );
408 // Begin to compute body frame accelerations based on the current body forces
409 vUVWdot = vForces/mass - VState.vPQR * VState.vUVW;
411 // Include Coriolis acceleration.
412 vUVWdot -= 2.0 * (Ti2b *vOmega) * VState.vUVW;
414 // Include Centrifugal acceleration.
415 if (!GroundReactions->GetWOW()) {
416 vUVWdot -= Ti2b*(vOmega*(vOmega*(Tec2i*VState.vLocation)));
419 // Include Gravitation accel
420 FGColumnVector3 gravAccel = Tl2b*vGravAccel;
421 vUVWdot += gravAccel;
424 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
426 void FGPropagate::CalculateLocationdot(void)
428 // Transform the vehicle velocity relative to the ECEF frame, expressed
429 // in the body frame, to be expressed in the ECEF frame.
430 vLocationDot = Tb2ec * VState.vUVW;
432 // Now, transform the velocity vector of the body relative to the origin (Earth
433 // center) to be expressed in the inertial frame, and add the vehicle velocity
434 // contribution due to the rotation of the planet. The above velocity is only
435 // relative to the rotating ECEF frame.
436 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
437 // Second edition (2004), eqn 1.5-16c (page 50)
439 vInertialVelocity = Tec2i * vLocationDot + (vOmega * (Tec2i * VState.vLocation));
442 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
444 void FGPropagate::RecomputeLocalTerrainRadius(void)
446 double t = State->Getsim_time();
448 // Get the LocalTerrain radius.
449 FGLocation contactloc;
451 FDMExec->GetGroundCallback()->GetAGLevel(t, VState.vLocation, contactloc, dv, dv);
452 LocalTerrainRadius = contactloc.GetRadius();
455 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
457 void FGPropagate::SetTerrainElevation(double terrainElev)
459 LocalTerrainRadius = terrainElev + SeaLevelRadius;
460 FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(LocalTerrainRadius);
463 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
465 double FGPropagate::GetTerrainElevation(void) const
467 return FDMExec->GetGroundCallback()->GetTerrainGeoCentRadius()-SeaLevelRadius;
470 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
472 const FGMatrix33& FGPropagate::GetTi2ec(void)
474 return VState.vLocation.GetTi2ec(Inertial->GetEarthPositionAngle());
477 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
479 const FGMatrix33& FGPropagate::GetTec2i(void)
481 return VState.vLocation.GetTec2i(Inertial->GetEarthPositionAngle());
484 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
486 void FGPropagate::SetAltitudeASL(double altASL)
488 VState.vLocation.SetRadius( altASL + SeaLevelRadius );
491 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
493 double FGPropagate::GetLocalTerrainRadius(void) const
495 return LocalTerrainRadius;
498 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
500 double FGPropagate::GetDistanceAGL(void) const
502 return VState.vLocation.GetRadius() - LocalTerrainRadius;
505 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
507 void FGPropagate::SetDistanceAGL(double tt)
509 VState.vLocation.SetRadius( tt + LocalTerrainRadius );
512 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
514 void FGPropagate::bind(void)
516 typedef double (FGPropagate::*PMF)(int) const;
517 // typedef double (FGPropagate::*dPMF)() const;
518 PropertyManager->Tie("velocities/h-dot-fps", this, &FGPropagate::Gethdot);
520 PropertyManager->Tie("velocities/v-north-fps", this, eNorth, (PMF)&FGPropagate::GetVel);
521 PropertyManager->Tie("velocities/v-east-fps", this, eEast, (PMF)&FGPropagate::GetVel);
522 PropertyManager->Tie("velocities/v-down-fps", this, eDown, (PMF)&FGPropagate::GetVel);
524 PropertyManager->Tie("velocities/u-fps", this, eU, (PMF)&FGPropagate::GetUVW);
525 PropertyManager->Tie("velocities/v-fps", this, eV, (PMF)&FGPropagate::GetUVW);
526 PropertyManager->Tie("velocities/w-fps", this, eW, (PMF)&FGPropagate::GetUVW);
528 PropertyManager->Tie("velocities/p-rad_sec", this, eP, (PMF)&FGPropagate::GetPQR);
529 PropertyManager->Tie("velocities/q-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQR);
530 PropertyManager->Tie("velocities/r-rad_sec", this, eR, (PMF)&FGPropagate::GetPQR);
532 PropertyManager->Tie("velocities/pi-rad_sec", this, eP, (PMF)&FGPropagate::GetPQRi);
533 PropertyManager->Tie("velocities/qi-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQRi);
534 PropertyManager->Tie("velocities/ri-rad_sec", this, eR, (PMF)&FGPropagate::GetPQRi);
536 PropertyManager->Tie("velocities/eci-velocity-mag-fps", this, &FGPropagate::GetInertialVelocityMagnitude);
538 PropertyManager->Tie("accelerations/pdot-rad_sec2", this, eP, (PMF)&FGPropagate::GetPQRdot);
539 PropertyManager->Tie("accelerations/qdot-rad_sec2", this, eQ, (PMF)&FGPropagate::GetPQRdot);
540 PropertyManager->Tie("accelerations/rdot-rad_sec2", this, eR, (PMF)&FGPropagate::GetPQRdot);
542 PropertyManager->Tie("accelerations/udot-ft_sec2", this, eU, (PMF)&FGPropagate::GetUVWdot);
543 PropertyManager->Tie("accelerations/vdot-ft_sec2", this, eV, (PMF)&FGPropagate::GetUVWdot);
544 PropertyManager->Tie("accelerations/wdot-ft_sec2", this, eW, (PMF)&FGPropagate::GetUVWdot);
546 PropertyManager->Tie("position/h-sl-ft", this, &FGPropagate::GetAltitudeASL, &FGPropagate::SetAltitudeASL, true);
547 PropertyManager->Tie("position/h-sl-meters", this, &FGPropagate::GetAltitudeASLmeters, &FGPropagate::SetAltitudeASLmeters, true);
548 PropertyManager->Tie("position/lat-gc-rad", this, &FGPropagate::GetLatitude, &FGPropagate::SetLatitude);
549 PropertyManager->Tie("position/long-gc-rad", this, &FGPropagate::GetLongitude, &FGPropagate::SetLongitude);
550 PropertyManager->Tie("position/lat-gc-deg", this, &FGPropagate::GetLatitudeDeg, &FGPropagate::SetLatitudeDeg);
551 PropertyManager->Tie("position/long-gc-deg", this, &FGPropagate::GetLongitudeDeg, &FGPropagate::SetLongitudeDeg);
552 PropertyManager->Tie("position/lat-geod-rad", this, &FGPropagate::GetGeodLatitudeRad);
553 PropertyManager->Tie("position/lat-geod-deg", this, &FGPropagate::GetGeodLatitudeDeg);
554 PropertyManager->Tie("position/geod-alt-ft", this, &FGPropagate::GetGeodeticAltitude);
555 PropertyManager->Tie("position/h-agl-ft", this, &FGPropagate::GetDistanceAGL, &FGPropagate::SetDistanceAGL);
556 PropertyManager->Tie("position/radius-to-vehicle-ft", this, &FGPropagate::GetRadius);
557 PropertyManager->Tie("position/terrain-elevation-asl-ft", this,
558 &FGPropagate::GetTerrainElevation,
559 &FGPropagate::SetTerrainElevation, false);
561 PropertyManager->Tie("metrics/terrain-radius", this, &FGPropagate::GetLocalTerrainRadius);
563 PropertyManager->Tie("attitude/phi-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
564 PropertyManager->Tie("attitude/theta-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
565 PropertyManager->Tie("attitude/psi-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
567 PropertyManager->Tie("attitude/roll-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
568 PropertyManager->Tie("attitude/pitch-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
569 PropertyManager->Tie("attitude/heading-true-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
571 PropertyManager->Tie("simulation/integrator/rate/rotational", &integrator_rotational_rate);
572 PropertyManager->Tie("simulation/integrator/rate/translational", &integrator_translational_rate);
573 PropertyManager->Tie("simulation/integrator/position/rotational", &integrator_rotational_position);
574 PropertyManager->Tie("simulation/integrator/position/translational", &integrator_translational_position);
577 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
578 // The bitmasked value choices are as follows:
579 // unset: In this case (the default) JSBSim would only print
580 // out the normally expected messages, essentially echoing
581 // the config files as they are read. If the environment
582 // variable is not set, debug_lvl is set to 1 internally
583 // 0: This requests JSBSim not to output any messages
585 // 1: This value explicity requests the normal JSBSim
587 // 2: This value asks for a message to be printed out when
588 // a class is instantiated
589 // 4: When this value is set, a message is displayed when a
590 // FGModel object executes its Run() method
591 // 8: When this value is set, various runtime state variables
592 // are printed out periodically
593 // 16: When set various parameters are sanity checked and
594 // a message is printed out when they go out of bounds
596 void FGPropagate::Debug(int from)
598 if (debug_lvl <= 0) return;
600 if (debug_lvl & 1) { // Standard console startup message output
601 if (from == 0) { // Constructor
605 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
606 if (from == 0) cout << "Instantiated: FGPropagate" << endl;
607 if (from == 1) cout << "Destroyed: FGPropagate" << endl;
609 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
611 if (debug_lvl & 8 ) { // Runtime state variables
613 if (debug_lvl & 16) { // Sanity checking
614 if (from == 2) { // State sanity checking
615 if (fabs(VState.vPQR.Magnitude()) > 1000.0) {
616 cerr << endl << "Vehicle rotation rate is excessive (>1000 rad/sec): " << VState.vPQR.Magnitude() << endl;
619 if (fabs(VState.vUVW.Magnitude()) > 1.0e10) {
620 cerr << endl << "Vehicle velocity is excessive (>1e10 ft/sec): " << VState.vUVW.Magnitude() << endl;
623 if (fabs(GetDistanceAGL()) > 1e10) {
624 cerr << endl << "Vehicle altitude is excessive (>1e10 ft): " << GetDistanceAGL() << endl;
629 if (debug_lvl & 64) {
630 if (from == 0) { // Constructor
631 cout << IdSrc << endl;
632 cout << IdHdr << endl;