]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/models/FGPropagate.cpp
943d0b2fa04f91dc760ac592dbe8d190af8c773d
[flightgear.git] / src / FDM / JSBSim / models / FGPropagate.cpp
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 (jsb@hal-pc.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
52 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
53 INCLUDES
54 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
55
56 #include <cmath>
57 #include <iomanip>
58
59 #include "FGPropagate.h"
60 #include <FGState.h>
61 #include <FGFDMExec.h>
62 #include "FGAircraft.h"
63 #include "FGMassBalance.h"
64 #include "FGInertial.h"
65 #include <input_output/FGPropertyManager.h>
66
67 namespace JSBSim {
68
69 static const char *IdSrc = "$Id$";
70 static const char *IdHdr = ID_PROPAGATE;
71
72 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
73 CLASS IMPLEMENTATION
74 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
75
76 FGPropagate::FGPropagate(FGFDMExec* fdmex) : FGModel(fdmex)
77 {
78   Debug(0);
79   Name = "FGPropagate";
80
81   last2_vPQRdot.InitMatrix();
82   last_vPQRdot.InitMatrix();
83   vPQRdot.InitMatrix();
84   
85   last2_vUVWdot.InitMatrix();
86   last_vUVWdot.InitMatrix();
87   vUVWdot.InitMatrix();
88   
89   last2_vLocationDot.InitMatrix();
90   last_vLocationDot.InitMatrix();
91   vLocationDot.InitMatrix();
92
93   vOmegaLocal.InitMatrix();
94
95   integrator_rotational_rate = eAdamsBashforth2;
96   integrator_translational_rate = eAdamsBashforth2;
97   integrator_rotational_position = eTrapezoidal;
98   integrator_translational_position = eTrapezoidal;
99
100   bind();
101   Debug(0);
102 }
103
104 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
105
106 FGPropagate::~FGPropagate(void)
107 {
108   Debug(1);
109 }
110
111 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
112
113 bool FGPropagate::InitModel(void)
114 {
115   if (!FGModel::InitModel()) return false;
116
117   SeaLevelRadius = Inertial->GetRefRadius();          // For initialization ONLY
118   RunwayRadius   = SeaLevelRadius;
119
120   VState.vLocation.SetRadius( SeaLevelRadius + 4.0 ); // Todo Add terrain elevation?
121   VState.vLocation.SetEllipse(Inertial->GetSemimajor(), Inertial->GetSemiminor());
122   vOmega = FGColumnVector3( 0.0, 0.0, Inertial->omega() ); // Earth rotation vector
123
124   last2_vPQRdot.InitMatrix();
125   last_vPQRdot.InitMatrix();
126   vPQRdot.InitMatrix();
127   
128   last2_vUVWdot.InitMatrix();
129   last_vUVWdot.InitMatrix();
130   vUVWdot.InitMatrix();
131   
132   last2_vLocationDot.InitMatrix();
133   last_vLocationDot.InitMatrix();
134   vLocationDot.InitMatrix();
135
136   vOmegaLocal.InitMatrix();
137
138   integrator_rotational_rate = eAdamsBashforth2;
139   integrator_translational_rate = eAdamsBashforth2;
140   integrator_rotational_position = eTrapezoidal;
141   integrator_translational_position = eTrapezoidal;
142
143   return true;
144 }
145
146 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
147
148 void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
149 {
150   SeaLevelRadius = FGIC->GetSeaLevelRadiusFtIC();
151   RunwayRadius = SeaLevelRadius;
152
153   // Set the position lat/lon/radius
154   VState.vLocation.SetPosition( FGIC->GetLongitudeRadIC(),
155                           FGIC->GetLatitudeRadIC(),
156                           FGIC->GetAltitudeFtIC() + FGIC->GetSeaLevelRadiusFtIC() );
157
158   VehicleRadius = GetRadius();
159   radInv = 1.0/VehicleRadius;
160
161   // Set the Orientation from the euler angles
162   VState.vQtrn = FGQuaternion( FGIC->GetPhiRadIC(),
163                         FGIC->GetThetaRadIC(),
164                         FGIC->GetPsiRadIC() );
165
166   // Set the velocities in the instantaneus body frame
167   VState.vUVW = FGColumnVector3( FGIC->GetUBodyFpsIC(),
168                           FGIC->GetVBodyFpsIC(),
169                           FGIC->GetWBodyFpsIC() );
170
171   // Set the angular velocities in the instantaneus body frame.
172   VState.vPQR = FGColumnVector3( FGIC->GetPRadpsIC(),
173                           FGIC->GetQRadpsIC(),
174                           FGIC->GetRRadpsIC() );
175
176   // Compute the local frame ECEF velocity
177   vVel = GetTb2l()*VState.vUVW;
178
179   // Finally, make sure that the quaternion stays normalized.
180   VState.vQtrn.Normalize();
181
182   // Recompute the RunwayRadius level.
183   RecomputeRunwayRadius();
184 }
185
186 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
187 /*
188 Purpose: Called on a schedule to perform EOM integration
189 Notes:   [JB] Run in standalone mode, SeaLevelRadius will be reference radius.
190          In FGFS, SeaLevelRadius is stuffed from FGJSBSim in JSBSim.cxx each pass.
191
192 At the top of this Run() function, see several "shortcuts" (or, aliases) being
193 set up for use later, rather than using the longer class->function() notation.
194
195 This propagation is done using the current state values
196 and current derivatives. Based on these values we compute an approximation to the
197 state values for (now + dt).
198
199 In the code below, variables named beginning with a small "v" refer to a 
200 a column vector, variables named beginning with a "T" refer to a transformation
201 matrix. ECEF refers to Earth Centered Earth Fixed. ECI refers to Earth Centered
202 Inertial.
203
204 */
205
206 bool FGPropagate::Run(void)
207 {
208   if (FGModel::Run()) return true;  // Fast return if we have nothing to do ...
209   if (FDMExec->Holding()) return false;
210
211   RecomputeRunwayRadius();
212
213   // Calculate current aircraft radius from center of planet
214
215   VehicleRadius = GetRadius();
216   radInv = 1.0/VehicleRadius;
217
218   // These local copies of the transformation matrices are for use this
219   // pass through Run() only.
220
221   Tl2b = GetTl2b();           // local to body frame transform
222   Tb2l = Tl2b.Transposed();   // body to local frame transform
223   Tl2ec = GetTl2ec();         // local to ECEF transform
224   Tec2l = Tl2ec.Transposed(); // ECEF to local frame transform
225   Tec2b = Tl2b * Tec2l;       // ECEF to body frame transform
226   Tb2ec = Tec2b.Transposed(); // body to ECEF frame tranform
227   Ti2ec = GetTi2ec();         // ECI to ECEF transform
228   Tec2i = Ti2ec.Transposed(); // ECEF to ECI frame transform
229   Ti2b  = Tec2b*Ti2ec;        // ECI to body frame transform
230   Tb2i  = Ti2b.Transposed();  // body to ECI frame transform
231
232   // Compute vehicle velocity wrt ECEF frame, expressed in Local horizontal frame.
233   vVel = Tb2l * VState.vUVW;
234
235   // Inertial angular velocity measured in the body frame.
236   vPQRi = VState.vPQR + Tec2b*vOmega;
237
238   // Calculate state derivatives
239   CalculatePQRdot();      // Angular rate derivative
240   CalculateUVWdot();      // Translational rate derivative
241   CalculateQuatdot();     // Angular orientation derivative
242   CalculateLocationdot(); // Translational position derivative
243
244   // Integrate to propagate the state
245
246   double dt = State->Getdt()*rate;  // The 'stepsize'
247
248   // Propagate rotational velocity
249
250   switch(integrator_rotational_rate) {
251   case eRectEuler:       VState.vPQR += dt*vPQRdot;
252     break;
253   case eTrapezoidal:     VState.vPQR += 0.5*dt*(vPQRdot + last_vPQRdot);
254     break;
255   case eAdamsBashforth2: VState.vPQR += dt*(1.5*vPQRdot - 0.5*last_vPQRdot);
256     break;
257   case eAdamsBashforth3: VState.vPQR += (1/12.0)*dt*(23.0*vPQRdot - 16.0*last_vPQRdot + 5.0*last2_vPQRdot);
258     break;
259   case eNone: // do nothing, freeze angular rate
260     break;
261   }
262   
263   // Propagate translational velocity
264
265   switch(integrator_translational_rate) {
266   case eRectEuler:       VState.vUVW += dt*vUVWdot;
267     break;
268   case eTrapezoidal:     VState.vUVW += 0.5*dt*(vUVWdot + last_vUVWdot);
269     break;
270   case eAdamsBashforth2: VState.vUVW += dt*(1.5*vUVWdot - 0.5*last_vUVWdot);
271     break;
272   case eAdamsBashforth3: VState.vUVW += (1/12.0)*dt*(23.0*vUVWdot - 16.0*last_vUVWdot + 5.0*last2_vUVWdot);
273     break;
274   case eNone: // do nothing, freeze translational rate
275     break;
276   }
277
278   // Propagate angular position
279
280   switch(integrator_rotational_position) {
281   case eRectEuler:       VState.vQtrn += dt*vQtrndot;
282     break;
283   case eTrapezoidal:     VState.vQtrn += 0.5*dt*(vQtrndot + last_vQtrndot);
284     break;
285   case eAdamsBashforth2: VState.vQtrn += dt*(1.5*vQtrndot - 0.5*last_vQtrndot);
286     break;
287   case eAdamsBashforth3: VState.vQtrn += (1/12.0)*dt*(23.0*vQtrndot - 16.0*last_vQtrndot + 5.0*last2_vQtrndot);
288     break;
289   case eNone: // do nothing, freeze angular position
290     break;
291   }
292
293   // Propagate translational position
294
295   switch(integrator_translational_position) {
296   case eRectEuler:       VState.vLocation += dt*vLocationDot;
297     break;
298   case eTrapezoidal:     VState.vLocation += 0.5*dt*(vLocationDot + last_vLocationDot);
299     break;
300   case eAdamsBashforth2: VState.vLocation += dt*(1.5*vLocationDot - 0.5*last_vLocationDot);
301     break;
302   case eAdamsBashforth3: VState.vLocation += (1/12.0)*dt*(23.0*vLocationDot - 16.0*last_vLocationDot + 5.0*last2_vLocationDot);
303     break;
304   case eNone: // do nothing, freeze translational position
305     break;
306   }
307   
308   // Set past values
309   
310   last2_vPQRdot = last_vPQRdot;
311   last_vPQRdot = vPQRdot;
312   
313   last2_vUVWdot = last_vUVWdot;
314   last_vUVWdot = vUVWdot;
315   
316   last2_vQtrndot = last_vQtrndot;
317   last_vQtrndot = vQtrndot;
318
319   last2_vLocationDot = last_vLocationDot;
320   last_vLocationDot = vLocationDot;
321
322   return false;
323 }
324
325 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
326 // Compute body frame rotational accelerations based on the current body moments
327 //
328 // vPQRdot is the derivative of the absolute angular velocity of the vehicle 
329 // (body rate with respect to the inertial frame), expressed in the body frame,
330 // where the derivative is taken in the body frame.
331 // J is the inertia matrix
332 // Jinv is the inverse inertia matrix
333 // vMoments is the moment vector in the body frame
334 // vPQRi is the total inertial angular velocity of the vehicle
335 // expressed in the body frame.
336 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation", 
337 //            Second edition (2004), eqn 1.5-16e (page 50)
338
339 void FGPropagate::CalculatePQRdot(void)
340 {
341   const FGColumnVector3& vMoments = Aircraft->GetMoments(); // current moments
342   const FGMatrix33& J = MassBalance->GetJ();                // inertia matrix
343   const FGMatrix33& Jinv = MassBalance->GetJinv();          // inertia matrix inverse
344
345   // Compute body frame rotational accelerations based on the current body
346   // moments and the total inertial angular velocity expressed in the body
347   // frame.
348
349   vPQRdot = Jinv*(vMoments - vPQRi*(J*vPQRi));
350 }
351
352 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
353 // Compute the quaternion orientation derivative
354 //
355 // vQtrndot is the quaternion derivative.
356 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation", 
357 //            Second edition (2004), eqn 1.5-16b (page 50)
358
359 void FGPropagate::CalculateQuatdot(void)
360 {
361   vOmegaLocal.InitMatrix( radInv*vVel(eEast),
362                          -radInv*vVel(eNorth),
363                          -radInv*vVel(eEast)*VState.vLocation.GetTanLatitude() );
364
365   // Compute quaternion orientation derivative on current body rates
366   vQtrndot = VState.vQtrn.GetQDot( VState.vPQR - Tl2b*vOmegaLocal);
367 }
368
369 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
370 // This set of calculations results in the body frame accelerations being
371 // computed.
372 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation", 
373 //            Second edition (2004), eqn 1.5-16d (page 50)
374
375 void FGPropagate::CalculateUVWdot(void)
376 {
377   double mass = MassBalance->GetMass();                      // mass
378   const FGColumnVector3& vForces = Aircraft->GetForces();    // current forces
379
380   const FGColumnVector3 vGravAccel( 0.0, 0.0, Inertial->GetGAccel(VehicleRadius) );
381
382   // Begin to compute body frame accelerations based on the current body forces
383   vUVWdot = vForces/mass - VState.vPQR * VState.vUVW;
384
385   // Include Coriolis acceleration.
386   vUVWdot -= 2.0 * (Ti2b *vOmega) * VState.vUVW;
387
388   // Include Centrifugal acceleration.
389   if (!GroundReactions->GetWOW()) {
390     vUVWdot -= Ti2b*(vOmega*(vOmega*(Tec2i*VState.vLocation)));
391   }
392
393   // Include Gravitation accel
394   FGColumnVector3 gravAccel = Tl2b*vGravAccel;
395   vUVWdot += gravAccel;
396 }
397
398 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
399
400 void FGPropagate::CalculateLocationdot(void)
401 {
402   // Transform the vehicle velocity relative to the ECEF frame, expressed
403   // in the body frame, to be expressed in the ECEF frame.
404   vLocationDot = Tb2ec * VState.vUVW;
405
406   // Now, transform the velocity vector of the body relative to the origin (Earth
407   // center) to be expressed in the inertial frame, and add the vehicle velocity
408   // contribution due to the rotation of the planet. The above velocity is only
409   // relative to the rotating ECEF frame.
410   // Reference: See Stevens and Lewis, "Aircraft Control and Simulation", 
411   //            Second edition (2004), eqn 1.5-16c (page 50)
412
413   vInertialVelocity = Tec2i * vLocationDot + (vOmega * (Tec2i * VState.vLocation));
414 }
415
416 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
417
418 void FGPropagate::RecomputeRunwayRadius(void)
419 {
420   // Get the runway radius.
421   FGLocation contactloc;
422   FGColumnVector3 dv;
423   FGGroundCallback* gcb = FDMExec->GetGroundCallback();
424   double t = State->Getsim_time();
425   gcb->GetAGLevel(t, VState.vLocation, contactloc, dv, dv);
426   RunwayRadius = contactloc.GetRadius();
427 }
428
429 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
430
431 void FGPropagate::SetTerrainElevationASL(double tt)
432 {
433   FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(tt+SeaLevelRadius);
434 }
435
436 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
437
438 double FGPropagate::GetTerrainElevationASL(void) const
439 {
440   return FDMExec->GetGroundCallback()->GetTerrainGeoCentRadius()-SeaLevelRadius;
441 }
442
443 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
444
445 const FGMatrix33& FGPropagate::GetTi2ec(void)
446 {
447   return VState.vLocation.GetTi2ec(Inertial->GetEarthPositionAngle());
448 }
449
450 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
451
452 const FGMatrix33& FGPropagate::GetTec2i(void)
453 {
454   return VState.vLocation.GetTec2i(Inertial->GetEarthPositionAngle());
455 }
456
457 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
458
459 void FGPropagate::Seth(double tt)
460 {
461   VState.vLocation.SetRadius( tt + SeaLevelRadius );
462 }
463
464 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
465
466 double FGPropagate::GetRunwayRadius(void) const
467 {
468   return RunwayRadius;
469 }
470
471 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
472
473 double FGPropagate::GetDistanceAGL(void) const
474 {
475   return VState.vLocation.GetRadius() - RunwayRadius;
476 }
477
478 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
479
480 void FGPropagate::SetDistanceAGL(double tt)
481 {
482   VState.vLocation.SetRadius( tt + RunwayRadius );
483 }
484
485 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
486
487 void FGPropagate::bind(void)
488 {
489   typedef double (FGPropagate::*PMF)(int) const;
490 //  typedef double (FGPropagate::*dPMF)() const;
491   PropertyManager->Tie("velocities/h-dot-fps", this, &FGPropagate::Gethdot);
492
493   PropertyManager->Tie("velocities/v-north-fps", this, eNorth, (PMF)&FGPropagate::GetVel);
494   PropertyManager->Tie("velocities/v-east-fps", this, eEast, (PMF)&FGPropagate::GetVel);
495   PropertyManager->Tie("velocities/v-down-fps", this, eDown, (PMF)&FGPropagate::GetVel);
496
497   PropertyManager->Tie("velocities/u-fps", this, eU, (PMF)&FGPropagate::GetUVW);
498   PropertyManager->Tie("velocities/v-fps", this, eV, (PMF)&FGPropagate::GetUVW);
499   PropertyManager->Tie("velocities/w-fps", this, eW, (PMF)&FGPropagate::GetUVW);
500
501   PropertyManager->Tie("velocities/p-rad_sec", this, eP, (PMF)&FGPropagate::GetPQR);
502   PropertyManager->Tie("velocities/q-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQR);
503   PropertyManager->Tie("velocities/r-rad_sec", this, eR, (PMF)&FGPropagate::GetPQR);
504
505   PropertyManager->Tie("velocities/eci-velocity-mag-fps", this, &FGPropagate::GetInertialVelocityMagnitude);
506
507   PropertyManager->Tie("accelerations/pdot-rad_sec2", this, eP, (PMF)&FGPropagate::GetPQRdot);
508   PropertyManager->Tie("accelerations/qdot-rad_sec2", this, eQ, (PMF)&FGPropagate::GetPQRdot);
509   PropertyManager->Tie("accelerations/rdot-rad_sec2", this, eR, (PMF)&FGPropagate::GetPQRdot);
510
511   PropertyManager->Tie("accelerations/udot-ft_sec2", this, eU, (PMF)&FGPropagate::GetUVWdot);
512   PropertyManager->Tie("accelerations/vdot-ft_sec2", this, eV, (PMF)&FGPropagate::GetUVWdot);
513   PropertyManager->Tie("accelerations/wdot-ft_sec2", this, eW, (PMF)&FGPropagate::GetUVWdot);
514
515   PropertyManager->Tie("position/h-sl-ft", this, &FGPropagate::Geth, &FGPropagate::Seth, true);
516   PropertyManager->Tie("position/h-sl-meters", this, &FGPropagate::Gethmeters, &FGPropagate::Sethmeters, true);
517   PropertyManager->Tie("position/lat-gc-rad", this, &FGPropagate::GetLatitude, &FGPropagate::SetLatitude);
518   PropertyManager->Tie("position/long-gc-rad", this, &FGPropagate::GetLongitude, &FGPropagate::SetLongitude);
519   PropertyManager->Tie("position/lat-gc-deg", this, &FGPropagate::GetLatitudeDeg, &FGPropagate::SetLatitudeDeg);
520   PropertyManager->Tie("position/long-gc-deg", this, &FGPropagate::GetLongitudeDeg, &FGPropagate::SetLongitudeDeg);
521   PropertyManager->Tie("position/lat-geod-rad", this, &FGPropagate::GetGeodLatitudeRad);
522   PropertyManager->Tie("position/lat-geod-deg", this, &FGPropagate::GetGeodLatitudeDeg);
523   PropertyManager->Tie("position/geod-alt-ft", this, &FGPropagate::GetGeodeticAltitude);
524   PropertyManager->Tie("position/h-agl-ft", this,  &FGPropagate::GetDistanceAGL, &FGPropagate::SetDistanceAGL);
525   PropertyManager->Tie("position/radius-to-vehicle-ft", this, &FGPropagate::GetRadius);
526   PropertyManager->Tie("position/terrain-elevation-asl-ft", this,
527                           &FGPropagate::GetTerrainElevationASL,
528                           &FGPropagate::SetTerrainElevationASL, false);
529
530   PropertyManager->Tie("metrics/runway-radius", this, &FGPropagate::GetRunwayRadius);
531
532   PropertyManager->Tie("attitude/phi-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
533   PropertyManager->Tie("attitude/theta-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
534   PropertyManager->Tie("attitude/psi-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
535
536   PropertyManager->Tie("attitude/roll-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
537   PropertyManager->Tie("attitude/pitch-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
538   PropertyManager->Tie("attitude/heading-true-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
539   
540   PropertyManager->Tie("simulation/integrator/rate/rotational", &integrator_rotational_rate);
541   PropertyManager->Tie("simulation/integrator/rate/translational", &integrator_translational_rate);
542   PropertyManager->Tie("simulation/integrator/position/rotational", &integrator_rotational_position);
543   PropertyManager->Tie("simulation/integrator/position/translational", &integrator_translational_position);
544 }
545
546 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
547 //    The bitmasked value choices are as follows:
548 //    unset: In this case (the default) JSBSim would only print
549 //       out the normally expected messages, essentially echoing
550 //       the config files as they are read. If the environment
551 //       variable is not set, debug_lvl is set to 1 internally
552 //    0: This requests JSBSim not to output any messages
553 //       whatsoever.
554 //    1: This value explicity requests the normal JSBSim
555 //       startup messages
556 //    2: This value asks for a message to be printed out when
557 //       a class is instantiated
558 //    4: When this value is set, a message is displayed when a
559 //       FGModel object executes its Run() method
560 //    8: When this value is set, various runtime state variables
561 //       are printed out periodically
562 //    16: When set various parameters are sanity checked and
563 //       a message is printed out when they go out of bounds
564
565 void FGPropagate::Debug(int from)
566 {
567   if (debug_lvl <= 0) return;
568
569   if (debug_lvl & 1) { // Standard console startup message output
570     if (from == 0) { // Constructor
571
572     }
573   }
574   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
575     if (from == 0) cout << "Instantiated: FGPropagate" << endl;
576     if (from == 1) cout << "Destroyed:    FGPropagate" << endl;
577   }
578   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
579   }
580   if (debug_lvl & 8 ) { // Runtime state variables
581   }
582   if (debug_lvl & 16) { // Sanity checking
583   }
584   if (debug_lvl & 64) {
585     if (from == 0) { // Constructor
586       cout << IdSrc << endl;
587       cout << IdHdr << endl;
588     }
589   }
590 }
591 }