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 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
59 #include "FGPropagate.h"
60 #include <FGFDMExec.h>
62 #include "FGAircraft.h"
63 #include "FGMassBalance.h"
64 #include "FGInertial.h"
65 #include <input_output/FGPropertyManager.h>
69 static const char *IdSrc = "$Id$";
70 static const char *IdHdr = ID_PROPAGATE;
72 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
74 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
76 FGPropagate::FGPropagate(FGFDMExec* fdmex) : FGModel(fdmex)
81 last2_vPQRdot.InitMatrix();
82 last_vPQRdot.InitMatrix();
85 last2_vQtrndot = FGQuaternion(0,0,0);
86 last_vQtrndot = FGQuaternion(0,0,0);
87 vQtrndot = FGQuaternion(0,0,0);
89 last2_vUVWdot.InitMatrix();
90 last_vUVWdot.InitMatrix();
93 last2_vLocationDot.InitMatrix();
94 last_vLocationDot.InitMatrix();
95 vLocationDot.InitMatrix();
97 vOmegaLocal.InitMatrix();
99 integrator_rotational_rate = eAdamsBashforth2;
100 integrator_translational_rate = eTrapezoidal;
101 integrator_rotational_position = eAdamsBashforth2;
102 integrator_translational_position = eTrapezoidal;
108 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
110 FGPropagate::~FGPropagate(void)
115 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
117 bool FGPropagate::InitModel(void)
119 if (!FGModel::InitModel()) return false;
121 // For initialization ONLY:
122 SeaLevelRadius = LocalTerrainRadius = Inertial->GetRefRadius();
124 VState.vLocation.SetRadius( LocalTerrainRadius + 4.0 );
125 VState.vLocation.SetEllipse(Inertial->GetSemimajor(), Inertial->GetSemiminor());
126 vOmega = FGColumnVector3( 0.0, 0.0, Inertial->omega() ); // Earth rotation vector
128 last2_vPQRdot.InitMatrix();
129 last_vPQRdot.InitMatrix();
130 vPQRdot.InitMatrix();
132 last2_vQtrndot = FGQuaternion(0,0,0);
133 last_vQtrndot = FGQuaternion(0,0,0);
134 vQtrndot = FGQuaternion(0,0,0);
136 last2_vUVWdot.InitMatrix();
137 last_vUVWdot.InitMatrix();
138 vUVWdot.InitMatrix();
140 last2_vLocationDot.InitMatrix();
141 last_vLocationDot.InitMatrix();
142 vLocationDot.InitMatrix();
144 vOmegaLocal.InitMatrix();
146 integrator_rotational_rate = eAdamsBashforth2;
147 integrator_translational_rate = eTrapezoidal;
148 integrator_rotational_position = eAdamsBashforth2;
149 integrator_translational_position = eTrapezoidal;
154 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
156 void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
158 SetSeaLevelRadius(FGIC->GetSeaLevelRadiusFtIC());
159 SetTerrainElevation(FGIC->GetTerrainElevationFtIC());
161 // Set the position lat/lon/radius
162 VState.vLocation.SetPosition( FGIC->GetLongitudeRadIC(),
163 FGIC->GetLatitudeRadIC(),
164 FGIC->GetAltitudeASLFtIC() + FGIC->GetSeaLevelRadiusFtIC() );
166 VehicleRadius = GetRadius();
167 radInv = 1.0/VehicleRadius;
169 // Set the Orientation from the euler angles
170 VState.vQtrn = FGQuaternion( FGIC->GetPhiRadIC(),
171 FGIC->GetThetaRadIC(),
172 FGIC->GetPsiRadIC() );
174 // Set the velocities in the instantaneus body frame
175 VState.vUVW = FGColumnVector3( FGIC->GetUBodyFpsIC(),
176 FGIC->GetVBodyFpsIC(),
177 FGIC->GetWBodyFpsIC() );
179 // Set the angular velocities in the instantaneus body frame.
180 VState.vPQR = FGColumnVector3( FGIC->GetPRadpsIC(),
182 FGIC->GetRRadpsIC() );
184 // Compute the local frame ECEF velocity
185 vVel = GetTb2l()*VState.vUVW;
187 // Finally, make sure that the quaternion stays normalized.
188 VState.vQtrn.Normalize();
190 // Recompute the LocalTerrainRadius.
191 RecomputeLocalTerrainRadius();
194 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
196 Purpose: Called on a schedule to perform EOM integration
197 Notes: [JB] Run in standalone mode, SeaLevelRadius will be reference radius.
198 In FGFS, SeaLevelRadius is stuffed from FGJSBSim in JSBSim.cxx each pass.
200 At the top of this Run() function, see several "shortcuts" (or, aliases) being
201 set up for use later, rather than using the longer class->function() notation.
203 This propagation is done using the current state values
204 and current derivatives. Based on these values we compute an approximation to the
205 state values for (now + dt).
207 In the code below, variables named beginning with a small "v" refer to a
208 a column vector, variables named beginning with a "T" refer to a transformation
209 matrix. ECEF refers to Earth Centered Earth Fixed. ECI refers to Earth Centered
214 bool FGPropagate::Run(void)
216 if (FGModel::Run()) return true; // Fast return if we have nothing to do ...
217 if (FDMExec->Holding()) return false;
219 RecomputeLocalTerrainRadius();
221 // Calculate current aircraft radius from center of planet
223 VehicleRadius = GetRadius();
224 radInv = 1.0/VehicleRadius;
226 // These local copies of the transformation matrices are for use this
227 // pass through Run() only.
229 Tl2b = GetTl2b(); // local to body frame transform
230 Tb2l = Tl2b.Transposed(); // body to local frame transform
231 Tl2ec = GetTl2ec(); // local to ECEF transform
232 Tec2l = Tl2ec.Transposed(); // ECEF to local frame transform
233 Tec2b = Tl2b * Tec2l; // ECEF to body frame transform
234 Tb2ec = Tec2b.Transposed(); // body to ECEF frame tranform
235 Ti2ec = GetTi2ec(); // ECI to ECEF transform
236 Tec2i = Ti2ec.Transposed(); // ECEF to ECI frame transform
237 Ti2b = Tec2b*Ti2ec; // ECI to body frame transform
238 Tb2i = Ti2b.Transposed(); // body to ECI frame transform
240 // Compute vehicle velocity wrt ECEF frame, expressed in Local horizontal frame.
241 vVel = Tb2l * VState.vUVW;
243 // Inertial angular velocity measured in the body frame.
244 vPQRi = VState.vPQR + Tec2b*vOmega;
246 // Calculate state derivatives
247 CalculatePQRdot(); // Angular rate derivative
248 CalculateUVWdot(); // Translational rate derivative
249 CalculateQuatdot(); // Angular orientation derivative
250 CalculateLocationdot(); // Translational position derivative
252 // Integrate to propagate the state
254 double dt = State->Getdt()*rate; // The 'stepsize'
256 // Propagate rotational velocity
258 switch(integrator_rotational_rate) {
259 case eRectEuler: VState.vPQR += dt*vPQRdot;
261 case eTrapezoidal: VState.vPQR += 0.5*dt*(vPQRdot + last_vPQRdot);
263 case eAdamsBashforth2: VState.vPQR += dt*(1.5*vPQRdot - 0.5*last_vPQRdot);
265 case eAdamsBashforth3: VState.vPQR += (1/12.0)*dt*(23.0*vPQRdot - 16.0*last_vPQRdot + 5.0*last2_vPQRdot);
267 case eNone: // do nothing, freeze angular rate
271 // Propagate translational velocity
273 switch(integrator_translational_rate) {
274 case eRectEuler: VState.vUVW += dt*vUVWdot;
276 case eTrapezoidal: VState.vUVW += 0.5*dt*(vUVWdot + last_vUVWdot);
278 case eAdamsBashforth2: VState.vUVW += dt*(1.5*vUVWdot - 0.5*last_vUVWdot);
280 case eAdamsBashforth3: VState.vUVW += (1/12.0)*dt*(23.0*vUVWdot - 16.0*last_vUVWdot + 5.0*last2_vUVWdot);
282 case eNone: // do nothing, freeze translational rate
286 // Propagate angular position
288 switch(integrator_rotational_position) {
289 case eRectEuler: VState.vQtrn += dt*vQtrndot;
291 case eTrapezoidal: VState.vQtrn += 0.5*dt*(vQtrndot + last_vQtrndot);
293 case eAdamsBashforth2: VState.vQtrn += dt*(1.5*vQtrndot - 0.5*last_vQtrndot);
295 case eAdamsBashforth3: VState.vQtrn += (1/12.0)*dt*(23.0*vQtrndot - 16.0*last_vQtrndot + 5.0*last2_vQtrndot);
297 case eNone: // do nothing, freeze angular position
301 // Propagate translational position
303 switch(integrator_translational_position) {
304 case eRectEuler: VState.vLocation += dt*vLocationDot;
306 case eTrapezoidal: VState.vLocation += 0.5*dt*(vLocationDot + last_vLocationDot);
308 case eAdamsBashforth2: VState.vLocation += dt*(1.5*vLocationDot - 0.5*last_vLocationDot);
310 case eAdamsBashforth3: VState.vLocation += (1/12.0)*dt*(23.0*vLocationDot - 16.0*last_vLocationDot + 5.0*last2_vLocationDot);
312 case eNone: // do nothing, freeze translational position
318 last2_vPQRdot = last_vPQRdot;
319 last_vPQRdot = vPQRdot;
321 last2_vUVWdot = last_vUVWdot;
322 last_vUVWdot = vUVWdot;
324 last2_vQtrndot = last_vQtrndot;
325 last_vQtrndot = vQtrndot;
327 last2_vLocationDot = last_vLocationDot;
328 last_vLocationDot = vLocationDot;
334 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
335 // Compute body frame rotational accelerations based on the current body moments
337 // vPQRdot is the derivative of the absolute angular velocity of the vehicle
338 // (body rate with respect to the inertial frame), expressed in the body frame,
339 // where the derivative is taken in the body frame.
340 // J is the inertia matrix
341 // Jinv is the inverse inertia matrix
342 // vMoments is the moment vector in the body frame
343 // vPQRi is the total inertial angular velocity of the vehicle
344 // expressed in the body frame.
345 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
346 // Second edition (2004), eqn 1.5-16e (page 50)
348 void FGPropagate::CalculatePQRdot(void)
350 const FGColumnVector3& vMoments = Aircraft->GetMoments(); // current moments
351 const FGMatrix33& J = MassBalance->GetJ(); // inertia matrix
352 const FGMatrix33& Jinv = MassBalance->GetJinv(); // inertia matrix inverse
354 // Compute body frame rotational accelerations based on the current body
355 // moments and the total inertial angular velocity expressed in the body
358 vPQRdot = Jinv*(vMoments - vPQRi*(J*vPQRi));
361 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362 // Compute the quaternion orientation derivative
364 // vQtrndot is the quaternion derivative.
365 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
366 // Second edition (2004), eqn 1.5-16b (page 50)
368 void FGPropagate::CalculateQuatdot(void)
370 vOmegaLocal.InitMatrix( radInv*vVel(eEast),
371 -radInv*vVel(eNorth),
372 -radInv*vVel(eEast)*VState.vLocation.GetTanLatitude() );
374 // Compute quaternion orientation derivative on current body rates
375 vQtrndot = VState.vQtrn.GetQDot( VState.vPQR - Tl2b*vOmegaLocal);
378 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
379 // This set of calculations results in the body frame accelerations being
381 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
382 // Second edition (2004), eqn 1.5-16d (page 50)
384 void FGPropagate::CalculateUVWdot(void)
386 double mass = MassBalance->GetMass(); // mass
387 const FGColumnVector3& vForces = Aircraft->GetForces(); // current forces
389 const FGColumnVector3 vGravAccel( 0.0, 0.0, Inertial->GetGAccel(VehicleRadius) );
391 // Begin to compute body frame accelerations based on the current body forces
392 vUVWdot = vForces/mass - VState.vPQR * VState.vUVW;
394 // Include Coriolis acceleration.
395 vUVWdot -= 2.0 * (Ti2b *vOmega) * VState.vUVW;
397 // Include Centrifugal acceleration.
398 if (!GroundReactions->GetWOW()) {
399 vUVWdot -= Ti2b*(vOmega*(vOmega*(Tec2i*VState.vLocation)));
402 // Include Gravitation accel
403 FGColumnVector3 gravAccel = Tl2b*vGravAccel;
404 vUVWdot += gravAccel;
407 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
409 void FGPropagate::CalculateLocationdot(void)
411 // Transform the vehicle velocity relative to the ECEF frame, expressed
412 // in the body frame, to be expressed in the ECEF frame.
413 vLocationDot = Tb2ec * VState.vUVW;
415 // Now, transform the velocity vector of the body relative to the origin (Earth
416 // center) to be expressed in the inertial frame, and add the vehicle velocity
417 // contribution due to the rotation of the planet. The above velocity is only
418 // relative to the rotating ECEF frame.
419 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
420 // Second edition (2004), eqn 1.5-16c (page 50)
422 vInertialVelocity = Tec2i * vLocationDot + (vOmega * (Tec2i * VState.vLocation));
425 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
427 void FGPropagate::RecomputeLocalTerrainRadius(void)
429 double t = State->Getsim_time();
431 // Get the LocalTerrain radius.
432 FGLocation contactloc;
434 FDMExec->GetGroundCallback()->GetAGLevel(t, VState.vLocation, contactloc, dv, dv);
435 LocalTerrainRadius = contactloc.GetRadius();
438 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
440 void FGPropagate::SetTerrainElevation(double terrainElev)
442 LocalTerrainRadius = terrainElev + SeaLevelRadius;
443 FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(LocalTerrainRadius);
446 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
448 double FGPropagate::GetTerrainElevation(void) const
450 return FDMExec->GetGroundCallback()->GetTerrainGeoCentRadius()-SeaLevelRadius;
453 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
455 const FGMatrix33& FGPropagate::GetTi2ec(void)
457 return VState.vLocation.GetTi2ec(Inertial->GetEarthPositionAngle());
460 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
462 const FGMatrix33& FGPropagate::GetTec2i(void)
464 return VState.vLocation.GetTec2i(Inertial->GetEarthPositionAngle());
467 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
469 void FGPropagate::SetAltitudeASL(double altASL)
471 VState.vLocation.SetRadius( altASL + SeaLevelRadius );
474 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
476 double FGPropagate::GetLocalTerrainRadius(void) const
478 return LocalTerrainRadius;
481 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
483 double FGPropagate::GetDistanceAGL(void) const
485 return VState.vLocation.GetRadius() - LocalTerrainRadius;
488 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
490 void FGPropagate::SetDistanceAGL(double tt)
492 VState.vLocation.SetRadius( tt + LocalTerrainRadius );
495 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
497 void FGPropagate::bind(void)
499 typedef double (FGPropagate::*PMF)(int) const;
500 // typedef double (FGPropagate::*dPMF)() const;
501 PropertyManager->Tie("velocities/h-dot-fps", this, &FGPropagate::Gethdot);
503 PropertyManager->Tie("velocities/v-north-fps", this, eNorth, (PMF)&FGPropagate::GetVel);
504 PropertyManager->Tie("velocities/v-east-fps", this, eEast, (PMF)&FGPropagate::GetVel);
505 PropertyManager->Tie("velocities/v-down-fps", this, eDown, (PMF)&FGPropagate::GetVel);
507 PropertyManager->Tie("velocities/u-fps", this, eU, (PMF)&FGPropagate::GetUVW);
508 PropertyManager->Tie("velocities/v-fps", this, eV, (PMF)&FGPropagate::GetUVW);
509 PropertyManager->Tie("velocities/w-fps", this, eW, (PMF)&FGPropagate::GetUVW);
511 PropertyManager->Tie("velocities/p-rad_sec", this, eP, (PMF)&FGPropagate::GetPQR);
512 PropertyManager->Tie("velocities/q-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQR);
513 PropertyManager->Tie("velocities/r-rad_sec", this, eR, (PMF)&FGPropagate::GetPQR);
515 PropertyManager->Tie("velocities/pi-rad_sec", this, eP, (PMF)&FGPropagate::GetPQRi);
516 PropertyManager->Tie("velocities/qi-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQRi);
517 PropertyManager->Tie("velocities/ri-rad_sec", this, eR, (PMF)&FGPropagate::GetPQRi);
519 PropertyManager->Tie("velocities/eci-velocity-mag-fps", this, &FGPropagate::GetInertialVelocityMagnitude);
521 PropertyManager->Tie("accelerations/pdot-rad_sec2", this, eP, (PMF)&FGPropagate::GetPQRdot);
522 PropertyManager->Tie("accelerations/qdot-rad_sec2", this, eQ, (PMF)&FGPropagate::GetPQRdot);
523 PropertyManager->Tie("accelerations/rdot-rad_sec2", this, eR, (PMF)&FGPropagate::GetPQRdot);
525 PropertyManager->Tie("accelerations/udot-ft_sec2", this, eU, (PMF)&FGPropagate::GetUVWdot);
526 PropertyManager->Tie("accelerations/vdot-ft_sec2", this, eV, (PMF)&FGPropagate::GetUVWdot);
527 PropertyManager->Tie("accelerations/wdot-ft_sec2", this, eW, (PMF)&FGPropagate::GetUVWdot);
529 PropertyManager->Tie("position/h-sl-ft", this, &FGPropagate::GetAltitudeASL, &FGPropagate::SetAltitudeASL, true);
530 PropertyManager->Tie("position/h-sl-meters", this, &FGPropagate::GetAltitudeASLmeters, &FGPropagate::SetAltitudeASLmeters, true);
531 PropertyManager->Tie("position/lat-gc-rad", this, &FGPropagate::GetLatitude, &FGPropagate::SetLatitude);
532 PropertyManager->Tie("position/long-gc-rad", this, &FGPropagate::GetLongitude, &FGPropagate::SetLongitude);
533 PropertyManager->Tie("position/lat-gc-deg", this, &FGPropagate::GetLatitudeDeg, &FGPropagate::SetLatitudeDeg);
534 PropertyManager->Tie("position/long-gc-deg", this, &FGPropagate::GetLongitudeDeg, &FGPropagate::SetLongitudeDeg);
535 PropertyManager->Tie("position/lat-geod-rad", this, &FGPropagate::GetGeodLatitudeRad);
536 PropertyManager->Tie("position/lat-geod-deg", this, &FGPropagate::GetGeodLatitudeDeg);
537 PropertyManager->Tie("position/geod-alt-ft", this, &FGPropagate::GetGeodeticAltitude);
538 PropertyManager->Tie("position/h-agl-ft", this, &FGPropagate::GetDistanceAGL, &FGPropagate::SetDistanceAGL);
539 PropertyManager->Tie("position/radius-to-vehicle-ft", this, &FGPropagate::GetRadius);
540 PropertyManager->Tie("position/terrain-elevation-asl-ft", this,
541 &FGPropagate::GetTerrainElevation,
542 &FGPropagate::SetTerrainElevation, false);
544 PropertyManager->Tie("metrics/terrain-radius", this, &FGPropagate::GetLocalTerrainRadius);
546 PropertyManager->Tie("attitude/phi-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
547 PropertyManager->Tie("attitude/theta-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
548 PropertyManager->Tie("attitude/psi-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
550 PropertyManager->Tie("attitude/roll-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
551 PropertyManager->Tie("attitude/pitch-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
552 PropertyManager->Tie("attitude/heading-true-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
554 PropertyManager->Tie("simulation/integrator/rate/rotational", &integrator_rotational_rate);
555 PropertyManager->Tie("simulation/integrator/rate/translational", &integrator_translational_rate);
556 PropertyManager->Tie("simulation/integrator/position/rotational", &integrator_rotational_position);
557 PropertyManager->Tie("simulation/integrator/position/translational", &integrator_translational_position);
560 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
561 // The bitmasked value choices are as follows:
562 // unset: In this case (the default) JSBSim would only print
563 // out the normally expected messages, essentially echoing
564 // the config files as they are read. If the environment
565 // variable is not set, debug_lvl is set to 1 internally
566 // 0: This requests JSBSim not to output any messages
568 // 1: This value explicity requests the normal JSBSim
570 // 2: This value asks for a message to be printed out when
571 // a class is instantiated
572 // 4: When this value is set, a message is displayed when a
573 // FGModel object executes its Run() method
574 // 8: When this value is set, various runtime state variables
575 // are printed out periodically
576 // 16: When set various parameters are sanity checked and
577 // a message is printed out when they go out of bounds
579 void FGPropagate::Debug(int from)
581 if (debug_lvl <= 0) return;
583 if (debug_lvl & 1) { // Standard console startup message output
584 if (from == 0) { // Constructor
588 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
589 if (from == 0) cout << "Instantiated: FGPropagate" << endl;
590 if (from == 1) cout << "Destroyed: FGPropagate" << endl;
592 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
594 if (debug_lvl & 8 ) { // Runtime state variables
596 if (debug_lvl & 16) { // Sanity checking
597 if (from == 2) { // State sanity checking
598 if (fabs(VState.vPQR.Magnitude()) > 1000.0) {
599 cerr << endl << "Vehicle rotation rate is excessive (>1000 rad/sec): " << VState.vPQR.Magnitude() << endl;
602 if (fabs(VState.vUVW.Magnitude()) > 1.0e10) {
603 cerr << endl << "Vehicle velocity is excessive (>1e10 ft/sec): " << VState.vUVW.Magnitude() << endl;
606 if (fabs(GetDistanceAGL()) > 1e10) {
607 cerr << endl << "Vehicle altitude is excessive (>1e10 ft): " << GetDistanceAGL() << endl;
612 if (debug_lvl & 64) {
613 if (from == 0) { // Constructor
614 cout << IdSrc << endl;
615 cout << IdHdr << endl;