]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/models/FGPropagate.cpp
2f2abc6475ccf1ab5c72db46eecddb8a6f4e4f5e
[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 #ifdef FGFS
57 #  include <simgear/compiler.h>
58 #  ifdef SG_HAVE_STD_INCLUDES
59 #    include <cmath>
60 #    include <iomanip>
61 #  else
62 #    include <math.h>
63 #    include <iomanip.h>
64 #  endif
65 #else
66 #  if defined(sgi) && !defined(__GNUC__)
67 #    include <math.h>
68 #    if (_COMPILER_VERSION < 740)
69 #      include <iomanip.h>
70 #    else
71 #      include <iomanip>
72 #    endif
73 #  else
74 #    include <cmath>
75 #    include <iomanip>
76 #  endif
77 #endif
78
79 #include "FGPropagate.h"
80 #include <FGState.h>
81 #include <FGFDMExec.h>
82 #include "FGAircraft.h"
83 #include "FGMassBalance.h"
84 #include "FGInertial.h"
85 #include <input_output/FGPropertyManager.h>
86
87 namespace JSBSim {
88
89 static const char *IdSrc = "$Id$";
90 static const char *IdHdr = ID_PROPAGATE;
91
92 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
93 CLASS IMPLEMENTATION
94 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
95
96 FGPropagate::FGPropagate(FGFDMExec* fdmex) : FGModel(fdmex)
97 {
98   Debug(0);
99   Name = "FGPropagate";
100
101   last2_vPQRdot.InitMatrix();
102   last_vPQRdot.InitMatrix();
103   vPQRdot.InitMatrix();
104   
105   last2_vUVWdot.InitMatrix();
106   last_vUVWdot.InitMatrix();
107   vUVWdot.InitMatrix();
108   
109   last2_vLocationDot.InitMatrix();
110   last_vLocationDot.InitMatrix();
111   vLocationDot.InitMatrix();
112
113   vOmegaLocal.InitMatrix();
114
115   integrator_rotational_rate = eAdamsBashforth2;
116   integrator_translational_rate = eAdamsBashforth2;
117   integrator_rotational_position = eTrapezoidal;
118   integrator_translational_position = eTrapezoidal;
119
120   bind();
121   Debug(0);
122 }
123
124 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
125
126 FGPropagate::~FGPropagate(void)
127 {
128   Debug(1);
129 }
130
131 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
132
133 bool FGPropagate::InitModel(void)
134 {
135   if (!FGModel::InitModel()) return false;
136
137   SeaLevelRadius = Inertial->GetRefRadius();          // For initialization ONLY
138   RunwayRadius   = SeaLevelRadius;
139
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
143
144   last2_vPQRdot.InitMatrix();
145   last_vPQRdot.InitMatrix();
146   vPQRdot.InitMatrix();
147   
148   last2_vUVWdot.InitMatrix();
149   last_vUVWdot.InitMatrix();
150   vUVWdot.InitMatrix();
151   
152   last2_vLocationDot.InitMatrix();
153   last_vLocationDot.InitMatrix();
154   vLocationDot.InitMatrix();
155
156   vOmegaLocal.InitMatrix();
157
158   integrator_rotational_rate = eAdamsBashforth2;
159   integrator_translational_rate = eAdamsBashforth2;
160   integrator_rotational_position = eTrapezoidal;
161   integrator_translational_position = eTrapezoidal;
162
163   return true;
164 }
165
166 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
167
168 void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
169 {
170   SeaLevelRadius = FGIC->GetSeaLevelRadiusFtIC();
171   RunwayRadius = SeaLevelRadius;
172
173   // Set the position lat/lon/radius
174   VState.vLocation.SetPosition( FGIC->GetLongitudeRadIC(),
175                           FGIC->GetLatitudeRadIC(),
176                           FGIC->GetAltitudeFtIC() + FGIC->GetSeaLevelRadiusFtIC() );
177
178   VehicleRadius = GetRadius();
179   radInv = 1.0/VehicleRadius;
180
181   // Set the Orientation from the euler angles
182   VState.vQtrn = FGQuaternion( FGIC->GetPhiRadIC(),
183                         FGIC->GetThetaRadIC(),
184                         FGIC->GetPsiRadIC() );
185
186   // Set the velocities in the instantaneus body frame
187   VState.vUVW = FGColumnVector3( FGIC->GetUBodyFpsIC(),
188                           FGIC->GetVBodyFpsIC(),
189                           FGIC->GetWBodyFpsIC() );
190
191   // Set the angular velocities in the instantaneus body frame.
192   VState.vPQR = FGColumnVector3( FGIC->GetPRadpsIC(),
193                           FGIC->GetQRadpsIC(),
194                           FGIC->GetRRadpsIC() );
195
196   // Compute the local frame ECEF velocity
197   vVel = GetTb2l()*VState.vUVW;
198
199   // Finally, make sure that the quaternion stays normalized.
200   VState.vQtrn.Normalize();
201
202   // Recompute the RunwayRadius level.
203   RecomputeRunwayRadius();
204 }
205
206 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
207 /*
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.
211
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.
214
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).
218
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
222 Inertial.
223
224 */
225
226 bool FGPropagate::Run(void)
227 {
228   if (FGModel::Run()) return true;  // Fast return if we have nothing to do ...
229   if (FDMExec->Holding()) return false;
230
231   RecomputeRunwayRadius();
232
233   // Calculate current aircraft radius from center of planet
234
235   VehicleRadius = GetRadius();
236   radInv = 1.0/VehicleRadius;
237
238   // These local copies of the transformation matrices are for use this
239   // pass through Run() only.
240
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
251
252   // Compute vehicle velocity wrt ECEF frame, expressed in Local horizontal frame.
253   vVel = Tb2l * VState.vUVW;
254
255   // Inertial angular velocity measured in the body frame.
256   vPQRi = VState.vPQR + Tec2b*vOmega;
257
258   // Calculate state derivatives
259   CalculatePQRdot();      // Angular rate derivative
260   CalculateUVWdot();      // Translational rate derivative
261   CalculateQuatdot();     // Angular orientation derivative
262   CalculateLocationdot(); // Translational position derivative
263
264   // Integrate to propagate the state
265
266   double dt = State->Getdt()*rate;  // The 'stepsize'
267
268   // Propagate rotational velocity
269
270   switch(integrator_rotational_rate) {
271   case eRectEuler:       VState.vPQR += dt*vPQRdot;
272     break;
273   case eTrapezoidal:     VState.vPQR += 0.5*dt*(vPQRdot + last_vPQRdot);
274     break;
275   case eAdamsBashforth2: VState.vPQR += dt*(1.5*vPQRdot - 0.5*last_vPQRdot);
276     break;
277   case eAdamsBashforth3: VState.vPQR += (1/12.0)*dt*(23.0*vPQRdot - 16.0*last_vPQRdot + 5.0*last2_vPQRdot);
278     break;
279   case eNone: // do nothing, freeze angular rate
280     break;
281   }
282   
283   // Propagate translational velocity
284
285   switch(integrator_translational_rate) {
286   case eRectEuler:       VState.vUVW += dt*vUVWdot;
287     break;
288   case eTrapezoidal:     VState.vUVW += 0.5*dt*(vUVWdot + last_vUVWdot);
289     break;
290   case eAdamsBashforth2: VState.vUVW += dt*(1.5*vUVWdot - 0.5*last_vUVWdot);
291     break;
292   case eAdamsBashforth3: VState.vUVW += (1/12.0)*dt*(23.0*vUVWdot - 16.0*last_vUVWdot + 5.0*last2_vUVWdot);
293     break;
294   case eNone: // do nothing, freeze translational rate
295     break;
296   }
297
298   // Propagate angular position
299
300   switch(integrator_rotational_position) {
301   case eRectEuler:       VState.vQtrn += dt*vQtrndot;
302     break;
303   case eTrapezoidal:     VState.vQtrn += 0.5*dt*(vQtrndot + last_vQtrndot);
304     break;
305   case eAdamsBashforth2: VState.vQtrn += dt*(1.5*vQtrndot - 0.5*last_vQtrndot);
306     break;
307   case eAdamsBashforth3: VState.vQtrn += (1/12.0)*dt*(23.0*vQtrndot - 16.0*last_vQtrndot + 5.0*last2_vQtrndot);
308     break;
309   case eNone: // do nothing, freeze angular position
310     break;
311   }
312
313   // Propagate translational position
314
315   switch(integrator_translational_position) {
316   case eRectEuler:       VState.vLocation += dt*vLocationDot;
317     break;
318   case eTrapezoidal:     VState.vLocation += 0.5*dt*(vLocationDot + last_vLocationDot);
319     break;
320   case eAdamsBashforth2: VState.vLocation += dt*(1.5*vLocationDot - 0.5*last_vLocationDot);
321     break;
322   case eAdamsBashforth3: VState.vLocation += (1/12.0)*dt*(23.0*vLocationDot - 16.0*last_vLocationDot + 5.0*last2_vLocationDot);
323     break;
324   case eNone: // do nothing, freeze translational position
325     break;
326   }
327   
328   // Set past values
329   
330   last2_vPQRdot = last_vPQRdot;
331   last_vPQRdot = vPQRdot;
332   
333   last2_vUVWdot = last_vUVWdot;
334   last_vUVWdot = vUVWdot;
335   
336   last2_vQtrndot = last_vQtrndot;
337   last_vQtrndot = vQtrndot;
338
339   last2_vLocationDot = last_vLocationDot;
340   last_vLocationDot = vLocationDot;
341
342   return false;
343 }
344
345 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
346 // Compute body frame rotational accelerations based on the current body moments
347 //
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)
358
359 void FGPropagate::CalculatePQRdot(void)
360 {
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
364
365   // Compute body frame rotational accelerations based on the current body
366   // moments and the total inertial angular velocity expressed in the body
367   // frame.
368
369   vPQRdot = Jinv*(vMoments - vPQRi*(J*vPQRi));
370 }
371
372 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
373 // Compute the quaternion orientation derivative
374 //
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)
378
379 void FGPropagate::CalculateQuatdot(void)
380 {
381   vOmegaLocal.InitMatrix( radInv*vVel(eEast),
382                          -radInv*vVel(eNorth),
383                          -radInv*vVel(eEast)*VState.vLocation.GetTanLatitude() );
384
385   // Compute quaternion orientation derivative on current body rates
386   vQtrndot = VState.vQtrn.GetQDot( VState.vPQR - Tl2b*vOmegaLocal);
387 }
388
389 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
390 // This set of calculations results in the body frame accelerations being
391 // computed.
392 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation", 
393 //            Second edition (2004), eqn 1.5-16d (page 50)
394
395 void FGPropagate::CalculateUVWdot(void)
396 {
397   double mass = MassBalance->GetMass();                      // mass
398   const FGColumnVector3& vForces = Aircraft->GetForces();    // current forces
399
400   const FGColumnVector3 vGravAccel( 0.0, 0.0, Inertial->GetGAccel(VehicleRadius) );
401
402   // Begin to compute body frame accelerations based on the current body forces
403   vUVWdot = vForces/mass - VState.vPQR * VState.vUVW;
404
405   // Include Coriolis acceleration.
406   vUVWdot -= 2.0 * (Ti2b *vOmega) * VState.vUVW;
407
408   // Include Centrifugal acceleration.
409   if (!GroundReactions->GetWOW()) {
410     vUVWdot -= Ti2b*(vOmega*(vOmega*(Tec2i*VState.vLocation)));
411   }
412
413   // Include Gravitation accel
414   FGColumnVector3 gravAccel = Tl2b*vGravAccel;
415   vUVWdot += gravAccel;
416 }
417
418 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
419
420 void FGPropagate::CalculateLocationdot(void)
421 {
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;
425
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)
432
433   vInertialVelocity = Tec2i * vLocationDot + (vOmega * (Tec2i * VState.vLocation));
434 }
435
436 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
437
438 void FGPropagate::RecomputeRunwayRadius(void)
439 {
440   // Get the runway radius.
441   FGLocation contactloc;
442   FGColumnVector3 dv;
443   FGGroundCallback* gcb = FDMExec->GetGroundCallback();
444   double t = State->Getsim_time();
445   gcb->GetAGLevel(t, VState.vLocation, contactloc, dv, dv);
446   RunwayRadius = contactloc.GetRadius();
447 }
448
449 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
450
451 void FGPropagate::SetTerrainElevationASL(double tt)
452 {
453   FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(tt+SeaLevelRadius);
454 }
455
456 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
457
458 double FGPropagate::GetTerrainElevationASL(void) const
459 {
460   return FDMExec->GetGroundCallback()->GetTerrainGeoCentRadius()-SeaLevelRadius;
461 }
462
463 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
464
465 const FGMatrix33& FGPropagate::GetTi2ec(void)
466 {
467   return VState.vLocation.GetTi2ec(Inertial->GetEarthPositionAngle());
468 }
469
470 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
471
472 const FGMatrix33& FGPropagate::GetTec2i(void)
473 {
474   return VState.vLocation.GetTec2i(Inertial->GetEarthPositionAngle());
475 }
476
477 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
478
479 void FGPropagate::Seth(double tt)
480 {
481   VState.vLocation.SetRadius( tt + SeaLevelRadius );
482 }
483
484 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
485
486 double FGPropagate::GetRunwayRadius(void) const
487 {
488   return RunwayRadius;
489 }
490
491 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
492
493 double FGPropagate::GetDistanceAGL(void) const
494 {
495   return VState.vLocation.GetRadius() - RunwayRadius;
496 }
497
498 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
499
500 void FGPropagate::SetDistanceAGL(double tt)
501 {
502   VState.vLocation.SetRadius( tt + RunwayRadius );
503 }
504
505 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
506
507 void FGPropagate::bind(void)
508 {
509   typedef double (FGPropagate::*PMF)(int) const;
510 //  typedef double (FGPropagate::*dPMF)() const;
511   PropertyManager->Tie("velocities/h-dot-fps", this, &FGPropagate::Gethdot);
512
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);
516
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);
520
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);
524
525   PropertyManager->Tie("velocities/eci-velocity-mag-fps", this, &FGPropagate::GetInertialVelocityMagnitude);
526
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);
530
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);
534
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);
549
550   PropertyManager->Tie("metrics/runway-radius", this, &FGPropagate::GetRunwayRadius);
551
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);
555
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);
559   
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);
564 }
565
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
573 //       whatsoever.
574 //    1: This value explicity requests the normal JSBSim
575 //       startup messages
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
584
585 void FGPropagate::Debug(int from)
586 {
587   if (debug_lvl <= 0) return;
588
589   if (debug_lvl & 1) { // Standard console startup message output
590     if (from == 0) { // Constructor
591
592     }
593   }
594   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
595     if (from == 0) cout << "Instantiated: FGPropagate" << endl;
596     if (from == 1) cout << "Destroyed:    FGPropagate" << endl;
597   }
598   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
599   }
600   if (debug_lvl & 8 ) { // Runtime state variables
601   }
602   if (debug_lvl & 16) { // Sanity checking
603   }
604   if (debug_lvl & 64) {
605     if (from == 0) { // Constructor
606       cout << IdSrc << endl;
607       cout << IdHdr << endl;
608     }
609   }
610 }
611 }