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