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
51 [6] Erin Catto, "Iterative Dynamics with Temporal Coherence", February 22, 2005
53 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
55 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
62 #include "FGPropagate.h"
63 #include "FGGroundReactions.h"
64 #include "FGFDMExec.h"
65 #include "input_output/FGPropertyManager.h"
71 static const char *IdSrc = "$Id: FGPropagate.cpp,v 1.98 2011/10/22 15:11:24 bcoconni Exp $";
72 static const char *IdHdr = ID_PROPAGATE;
74 /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
76 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
78 FGPropagate::FGPropagate(FGFDMExec* fdmex)
85 vInertialVelocity.InitMatrix();
87 /// These define the indices use to select the various integrators.
88 // eNone = 0, eRectEuler, eTrapezoidal, eAdamsBashforth2, eAdamsBashforth3, eAdamsBashforth4};
90 integrator_rotational_rate = eRectEuler;
91 integrator_translational_rate = eAdamsBashforth2;
92 integrator_rotational_position = eRectEuler;
93 integrator_translational_position = eAdamsBashforth3;
95 VState.dqPQRidot.resize(4, FGColumnVector3(0.0,0.0,0.0));
96 VState.dqUVWidot.resize(4, FGColumnVector3(0.0,0.0,0.0));
97 VState.dqInertialVelocity.resize(4, FGColumnVector3(0.0,0.0,0.0));
98 VState.dqQtrndot.resize(4, FGQuaternion(0.0,0.0,0.0));
104 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
106 FGPropagate::~FGPropagate(void)
111 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
113 bool FGPropagate::InitModel(void)
115 // For initialization ONLY:
116 VState.vLocation.SetRadius( FDMExec->GetGroundCallback()->
117 GetTerrainGeoCentRadius(0.0,VState.vLocation) + 4.0 );
119 VState.vLocation.SetEllipse(in.SemiMajor, in.SemiMinor);
121 vInertialVelocity.InitMatrix();
123 VState.dqPQRidot.resize(4, FGColumnVector3(0.0,0.0,0.0));
124 VState.dqUVWidot.resize(4, FGColumnVector3(0.0,0.0,0.0));
125 VState.dqInertialVelocity.resize(4, FGColumnVector3(0.0,0.0,0.0));
126 VState.dqQtrndot.resize(4, FGColumnVector3(0.0,0.0,0.0));
128 integrator_rotational_rate = eRectEuler;
129 integrator_translational_rate = eAdamsBashforth2;
130 integrator_rotational_position = eRectEuler;
131 integrator_translational_position = eAdamsBashforth3;
136 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
138 void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
140 SetTerrainElevation(FGIC->GetTerrainElevationFtIC());
142 // Initialize the State Vector elements and the transformation matrices
144 // Set the position lat/lon/radius
145 VState.vLocation = FGIC->GetPosition();
147 Ti2ec = VState.vLocation.GetTi2ec(); // ECI to ECEF transform
148 Tec2i = Ti2ec.Transposed(); // ECEF to ECI frame transform
150 VState.vInertialPosition = Tec2i * VState.vLocation;
152 UpdateLocationMatrices();
154 // Set the orientation from the euler angles (is normalized within the
155 // constructor). The Euler angles represent the orientation of the body
156 // frame relative to the local frame.
157 VState.qAttitudeLocal = FGIC->GetOrientation();
159 VState.qAttitudeECI = Ti2l.GetQuaternion()*VState.qAttitudeLocal;
160 UpdateBodyMatrices();
162 // Set the velocities in the instantaneus body frame
163 VState.vUVW = FGIC->GetUVWFpsIC();
165 // Compute the local frame ECEF velocity
166 vVel = Tb2l * VState.vUVW;
168 // Compute local terrain velocity
169 RecomputeLocalTerrainVelocity();
170 VehicleRadius = GetRadius();
172 // Set the angular velocities of the body frame relative to the ECEF frame,
173 // expressed in the body frame.
174 VState.vPQR = FGIC->GetPQRRadpsIC();
176 VState.vPQRi = VState.vPQR + Ti2b * in.vOmegaPlanet;
178 CalculateInertialVelocity(); // Translational position derivative
181 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
182 // Initialize the past value deques
184 void FGPropagate::InitializeDerivatives()
186 for (int i=0; i<4; i++) {
187 VState.dqPQRidot[i] = in.vPQRidot;
188 VState.dqUVWidot[i] = in.vUVWidot;
189 VState.dqInertialVelocity[i] = VState.vInertialVelocity;
190 VState.dqQtrndot[i] = in.vQtrndot;
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(bool Holding)
216 if (FGModel::Run(Holding)) return true; // Fast return if we have nothing to do ...
217 if (Holding) return false;
219 double dt = in.DeltaT * rate; // The 'stepsize'
223 // Propagate rotational / translational velocity, angular /translational position, respectively.
225 Integrate(VState.vPQRi, in.vPQRidot, VState.dqPQRidot, dt, integrator_rotational_rate);
226 Integrate(VState.qAttitudeECI, in.vQtrndot, VState.dqQtrndot, dt, integrator_rotational_position);
227 Integrate(VState.vInertialPosition, VState.vInertialVelocity, VState.dqInertialVelocity, dt, integrator_translational_position);
228 Integrate(VState.vInertialVelocity, in.vUVWidot, VState.dqUVWidot, dt, integrator_translational_rate);
230 // CAUTION : the order of the operations below is very important to get transformation
231 // matrices that are consistent with the new state of the vehicle
233 // 1. Update the Earth position angle (EPA)
234 VState.vLocation.IncrementEarthPositionAngle(in.vOmegaPlanet(eZ)*(in.DeltaT*rate));
236 // 2. Update the Ti2ec and Tec2i transforms from the updated EPA
237 Ti2ec = VState.vLocation.GetTi2ec(); // ECI to ECEF transform
238 Tec2i = Ti2ec.Transposed(); // ECEF to ECI frame transform
240 // 3. Update the location from the updated Ti2ec and inertial position
241 VState.vLocation = Ti2ec*VState.vInertialPosition;
243 // 4. Update the other "Location-based" transformation matrices from the updated
245 UpdateLocationMatrices();
247 // 5. Normalize the ECI Attitude quaternion
248 VState.qAttitudeECI.Normalize();
250 // 6. Update the "Orientation-based" transformation matrices from the updated
251 // orientation quaternion and vLocation vector.
252 UpdateBodyMatrices();
254 // Translational position derivative (velocities are integrated in the inertial frame)
257 // Set auxilliary state variables
258 RecomputeLocalTerrainVelocity();
259 VehicleRadius = GetRadius(); // Calculate current aircraft radius from center of planet
261 VState.vPQR = VState.vPQRi - Ti2b * in.vOmegaPlanet;
263 VState.qAttitudeLocal = Tl2b.GetQuaternion();
265 // Compute vehicle velocity wrt ECEF frame, expressed in Local horizontal frame.
266 vVel = Tb2l * VState.vUVW;
274 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
275 // Transform the velocity vector of the body relative to the origin (Earth
276 // center) to be expressed in the inertial frame, and add the vehicle velocity
277 // contribution due to the rotation of the planet.
278 // Reference: See Stevens and Lewis, "Aircraft Control and Simulation",
279 // Second edition (2004), eqn 1.5-16c (page 50)
281 void FGPropagate::CalculateInertialVelocity(void)
283 VState.vInertialVelocity = Tb2i * VState.vUVW + (in.vOmegaPlanet * VState.vInertialPosition);
286 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
287 // Transform the velocity vector of the inertial frame to be expressed in the
288 // body frame relative to the origin (Earth center), and substract the vehicle
289 // velocity contribution due to the rotation of the planet.
291 void FGPropagate::CalculateUVW(void)
293 VState.vUVW = Ti2b * (VState.vInertialVelocity - (in.vOmegaPlanet * VState.vInertialPosition));
296 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
298 void FGPropagate::Integrate( FGColumnVector3& Integrand,
299 FGColumnVector3& Val,
300 deque <FGColumnVector3>& ValDot,
302 eIntegrateType integration_type)
304 ValDot.push_front(Val);
307 switch(integration_type) {
308 case eRectEuler: Integrand += dt*ValDot[0];
310 case eTrapezoidal: Integrand += 0.5*dt*(ValDot[0] + ValDot[1]);
312 case eAdamsBashforth2: Integrand += dt*(1.5*ValDot[0] - 0.5*ValDot[1]);
314 case eAdamsBashforth3: Integrand += (1/12.0)*dt*(23.0*ValDot[0] - 16.0*ValDot[1] + 5.0*ValDot[2]);
316 case eAdamsBashforth4: Integrand += (1/24.0)*dt*(55.0*ValDot[0] - 59.0*ValDot[1] + 37.0*ValDot[2] - 9.0*ValDot[3]);
318 case eNone: // do nothing, freeze translational rate
323 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
325 void FGPropagate::Integrate( FGQuaternion& Integrand,
327 deque <FGQuaternion>& ValDot,
329 eIntegrateType integration_type)
331 ValDot.push_front(Val);
334 switch(integration_type) {
335 case eRectEuler: Integrand += dt*ValDot[0];
337 case eTrapezoidal: Integrand += 0.5*dt*(ValDot[0] + ValDot[1]);
339 case eAdamsBashforth2: Integrand += dt*(1.5*ValDot[0] - 0.5*ValDot[1]);
341 case eAdamsBashforth3: Integrand += (1/12.0)*dt*(23.0*ValDot[0] - 16.0*ValDot[1] + 5.0*ValDot[2]);
343 case eAdamsBashforth4: Integrand += (1/24.0)*dt*(55.0*ValDot[0] - 59.0*ValDot[1] + 37.0*ValDot[2] - 9.0*ValDot[3]);
345 case eNone: // do nothing, freeze rotational rate
350 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
352 void FGPropagate::UpdateLocationMatrices(void)
354 Tl2ec = VState.vLocation.GetTl2ec(); // local to ECEF transform
355 Tec2l = Tl2ec.Transposed(); // ECEF to local frame transform
356 Ti2l = VState.vLocation.GetTi2l(); // ECI to local frame transform
357 Tl2i = Ti2l.Transposed(); // local to ECI transform
360 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
362 void FGPropagate::UpdateBodyMatrices(void)
364 Ti2b = VState.qAttitudeECI.GetT(); // ECI to body frame transform
365 Tb2i = Ti2b.Transposed(); // body to ECI frame transform
366 Tl2b = Ti2b * Tl2i; // local to body frame transform
367 Tb2l = Tl2b.Transposed(); // body to local frame transform
368 Tec2b = Ti2b * Tec2i; // ECEF to body frame transform
369 Tb2ec = Tec2b.Transposed(); // body to ECEF frame tranform
372 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
374 void FGPropagate::SetInertialOrientation(FGQuaternion Qi) {
375 VState.qAttitudeECI = Qi;
376 VState.qAttitudeECI.Normalize();
377 UpdateBodyMatrices();
378 VState.qAttitudeLocal = Tl2b.GetQuaternion();
381 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
383 void FGPropagate::SetInertialVelocity(FGColumnVector3 Vi) {
384 VState.vInertialVelocity = Vi;
386 vVel = Tb2l * VState.vUVW;
389 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
391 void FGPropagate::SetInertialRates(FGColumnVector3 vRates) {
392 VState.vPQRi = Ti2b * vRates;
393 VState.vPQR = VState.vPQRi - Ti2b * in.vOmegaPlanet;
396 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
398 void FGPropagate::RecomputeLocalTerrainVelocity()
401 FGColumnVector3 normal;
402 FDMExec->GetGroundCallback()->GetAGLevel(FDMExec->GetSimTime(),
405 LocalTerrainVelocity,
406 LocalTerrainAngularVelocity);
409 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
411 void FGPropagate::SetTerrainElevation(double terrainElev)
413 double radius = terrainElev + FDMExec->GetGroundCallback()->GetSeaLevelRadius(VState.vLocation);
414 FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(radius);
417 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
419 void FGPropagate::SetSeaLevelRadius(double tt)
421 FDMExec->GetGroundCallback()->SetSeaLevelRadius(tt);
424 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
426 double FGPropagate::GetLocalTerrainRadius(void) const
428 return FDMExec->GetGroundCallback()->GetTerrainGeoCentRadius(FDMExec->GetSimTime(),
432 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
434 double FGPropagate::GetTerrainElevation(void) const
436 return GetLocalTerrainRadius()
437 - FDMExec->GetGroundCallback()->GetSeaLevelRadius(VState.vLocation);
440 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
442 double FGPropagate::GetDistanceAGL(void) const
444 FGColumnVector3 dummy;
446 double t = FDMExec->GetSimTime();
447 return FDMExec->GetGroundCallback()->GetAGLevel(t, VState.vLocation, dummyloc,
448 dummy, dummy, dummy);
451 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
453 void FGPropagate::SetAltitudeASL(double altASL)
455 SetRadius(altASL + FDMExec->GetGroundCallback()->GetSeaLevelRadius(VState.vLocation));
458 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
460 double FGPropagate::GetAltitudeASL(void) const
462 return VState.vLocation.GetRadius()
463 - FDMExec->GetGroundCallback()->GetSeaLevelRadius(VState.vLocation);
466 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
468 void FGPropagate::SetDistanceAGL(double tt)
470 SetAltitudeASL(tt + GetTerrainElevation());
473 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
475 void FGPropagate::SetVState(const VehicleState& vstate)
477 //ToDo: Shouldn't all of these be set from the vstate vector passed in?
478 VState.vLocation = vstate.vLocation;
479 VState.vLocation.SetEarthPositionAngle(vstate.vLocation.GetEPA());
480 Ti2ec = VState.vLocation.GetTi2ec(); // useless ?
481 Tec2i = Ti2ec.Transposed();
482 UpdateLocationMatrices();
483 SetInertialOrientation(vstate.qAttitudeECI);
484 RecomputeLocalTerrainVelocity();
485 VehicleRadius = GetRadius();
486 VState.vUVW = vstate.vUVW;
487 vVel = Tb2l * VState.vUVW;
488 VState.vPQR = vstate.vPQR;
489 VState.vPQRi = VState.vPQR + Ti2b * in.vOmegaPlanet;
490 VState.vInertialPosition = vstate.vInertialPosition;
493 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
495 void FGPropagate::UpdateVehicleState(void)
497 RecomputeLocalTerrainVelocity();
498 VehicleRadius = GetRadius();
499 VState.vInertialPosition = Tec2i * VState.vLocation;
500 UpdateLocationMatrices();
501 UpdateBodyMatrices();
502 vVel = Tb2l * VState.vUVW;
503 VState.qAttitudeLocal = Tl2b.GetQuaternion();
506 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
508 void FGPropagate::SetLocation(const FGLocation& l)
510 VState.vLocation = l;
511 VState.vLocation.SetEarthPositionAngle(l.GetEPA());
512 Ti2ec = VState.vLocation.GetTi2ec(); // useless ?
513 Tec2i = Ti2ec.Transposed();
514 UpdateVehicleState();
517 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
519 void FGPropagate::DumpState(void)
523 << "------------------------------------------------------------------" << reset << endl;
525 << "State Report at sim time: " << FDMExec->GetSimTime() << " seconds" << reset << endl;
526 cout << " " << underon
527 << "Position" << underoff << endl;
528 cout << " ECI: " << VState.vInertialPosition.Dump(", ") << " (x,y,z, in ft)" << endl;
529 cout << " ECEF: " << VState.vLocation << " (x,y,z, in ft)" << endl;
530 cout << " Local: " << VState.vLocation.GetLatitudeDeg()
531 << ", " << VState.vLocation.GetLongitudeDeg()
532 << ", " << GetAltitudeASL() << " (lat, lon, alt in deg and ft)" << endl;
534 cout << endl << " " << underon
535 << "Orientation" << underoff << endl;
536 cout << " ECI: " << VState.qAttitudeECI.GetEulerDeg().Dump(", ") << " (phi, theta, psi in deg)" << endl;
537 cout << " Local: " << VState.qAttitudeLocal.GetEulerDeg().Dump(", ") << " (phi, theta, psi in deg)" << endl;
539 cout << endl << " " << underon
540 << "Velocity" << underoff << endl;
541 cout << " ECI: " << VState.vInertialVelocity.Dump(", ") << " (x,y,z in ft/s)" << endl;
542 cout << " ECEF: " << (Tb2ec * VState.vUVW).Dump(", ") << " (x,y,z in ft/s)" << endl;
543 cout << " Local: " << GetVel() << " (n,e,d in ft/sec)" << endl;
544 cout << " Body: " << GetUVW() << " (u,v,w in ft/sec)" << endl;
546 cout << endl << " " << underon
547 << "Body Rates (relative to given frame, expressed in body frame)" << underoff << endl;
548 cout << " ECI: " << (VState.vPQRi*radtodeg).Dump(", ") << " (p,q,r in deg/s)" << endl;
549 cout << " ECEF: " << (VState.vPQR*radtodeg).Dump(", ") << " (p,q,r in deg/s)" << endl;
552 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
554 void FGPropagate::bind(void)
556 typedef double (FGPropagate::*PMF)(int) const;
558 PropertyManager->Tie("velocities/h-dot-fps", this, &FGPropagate::Gethdot);
560 PropertyManager->Tie("velocities/v-north-fps", this, eNorth, (PMF)&FGPropagate::GetVel);
561 PropertyManager->Tie("velocities/v-east-fps", this, eEast, (PMF)&FGPropagate::GetVel);
562 PropertyManager->Tie("velocities/v-down-fps", this, eDown, (PMF)&FGPropagate::GetVel);
564 PropertyManager->Tie("velocities/u-fps", this, eU, (PMF)&FGPropagate::GetUVW);
565 PropertyManager->Tie("velocities/v-fps", this, eV, (PMF)&FGPropagate::GetUVW);
566 PropertyManager->Tie("velocities/w-fps", this, eW, (PMF)&FGPropagate::GetUVW);
568 PropertyManager->Tie("velocities/p-rad_sec", this, eP, (PMF)&FGPropagate::GetPQR);
569 PropertyManager->Tie("velocities/q-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQR);
570 PropertyManager->Tie("velocities/r-rad_sec", this, eR, (PMF)&FGPropagate::GetPQR);
572 PropertyManager->Tie("velocities/pi-rad_sec", this, eP, (PMF)&FGPropagate::GetPQRi);
573 PropertyManager->Tie("velocities/qi-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQRi);
574 PropertyManager->Tie("velocities/ri-rad_sec", this, eR, (PMF)&FGPropagate::GetPQRi);
576 PropertyManager->Tie("velocities/eci-velocity-mag-fps", this, &FGPropagate::GetInertialVelocityMagnitude);
578 PropertyManager->Tie("position/h-sl-ft", this, &FGPropagate::GetAltitudeASL, &FGPropagate::SetAltitudeASL, true);
579 PropertyManager->Tie("position/h-sl-meters", this, &FGPropagate::GetAltitudeASLmeters, &FGPropagate::SetAltitudeASLmeters, true);
580 PropertyManager->Tie("position/lat-gc-rad", this, &FGPropagate::GetLatitude, &FGPropagate::SetLatitude, false);
581 PropertyManager->Tie("position/long-gc-rad", this, &FGPropagate::GetLongitude, &FGPropagate::SetLongitude, false);
582 PropertyManager->Tie("position/lat-gc-deg", this, &FGPropagate::GetLatitudeDeg, &FGPropagate::SetLatitudeDeg, false);
583 PropertyManager->Tie("position/long-gc-deg", this, &FGPropagate::GetLongitudeDeg, &FGPropagate::SetLongitudeDeg, false);
584 PropertyManager->Tie("position/lat-geod-rad", this, &FGPropagate::GetGeodLatitudeRad);
585 PropertyManager->Tie("position/lat-geod-deg", this, &FGPropagate::GetGeodLatitudeDeg);
586 PropertyManager->Tie("position/geod-alt-ft", this, &FGPropagate::GetGeodeticAltitude);
587 PropertyManager->Tie("position/h-agl-ft", this, &FGPropagate::GetDistanceAGL, &FGPropagate::SetDistanceAGL);
588 PropertyManager->Tie("position/radius-to-vehicle-ft", this, &FGPropagate::GetRadius);
589 PropertyManager->Tie("position/terrain-elevation-asl-ft", this,
590 &FGPropagate::GetTerrainElevation,
591 &FGPropagate::SetTerrainElevation, false);
593 PropertyManager->Tie("position/epa-rad", this, &FGPropagate::GetEarthPositionAngle);
594 PropertyManager->Tie("metrics/terrain-radius", this, &FGPropagate::GetLocalTerrainRadius);
596 PropertyManager->Tie("attitude/phi-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
597 PropertyManager->Tie("attitude/theta-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
598 PropertyManager->Tie("attitude/psi-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
600 PropertyManager->Tie("attitude/roll-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
601 PropertyManager->Tie("attitude/pitch-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
602 PropertyManager->Tie("attitude/heading-true-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
604 PropertyManager->Tie("simulation/integrator/rate/rotational", (int*)&integrator_rotational_rate);
605 PropertyManager->Tie("simulation/integrator/rate/translational", (int*)&integrator_translational_rate);
606 PropertyManager->Tie("simulation/integrator/position/rotational", (int*)&integrator_rotational_position);
607 PropertyManager->Tie("simulation/integrator/position/translational", (int*)&integrator_translational_position);
610 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
611 // The bitmasked value choices are as follows:
612 // unset: In this case (the default) JSBSim would only print
613 // out the normally expected messages, essentially echoing
614 // the config files as they are read. If the environment
615 // variable is not set, debug_lvl is set to 1 internally
616 // 0: This requests JSBSim not to output any messages
618 // 1: This value explicity requests the normal JSBSim
620 // 2: This value asks for a message to be printed out when
621 // a class is instantiated
622 // 4: When this value is set, a message is displayed when a
623 // FGModel object executes its Run() method
624 // 8: When this value is set, various runtime state variables
625 // are printed out periodically
626 // 16: When set various parameters are sanity checked and
627 // a message is printed out when they go out of bounds
629 void FGPropagate::Debug(int from)
631 if (debug_lvl <= 0) return;
633 if (debug_lvl & 1) { // Standard console startup message output
634 if (from == 0) { // Constructor
638 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
639 if (from == 0) cout << "Instantiated: FGPropagate" << endl;
640 if (from == 1) cout << "Destroyed: FGPropagate" << endl;
642 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
644 if (debug_lvl & 8 && from == 2) { // Runtime state variables
645 cout << endl << fgblue << highint << left
646 << " Propagation Report (English units: ft, degrees) at simulation time " << FDMExec->GetSimTime() << " seconds"
649 cout << highint << " Earth Position Angle (deg): " << setw(8) << setprecision(3) << reset
650 << GetEarthPositionAngleDeg() << endl;
652 cout << highint << " Body velocity (ft/sec): " << setw(8) << setprecision(3) << reset << VState.vUVW << endl;
653 cout << highint << " Local velocity (ft/sec): " << setw(8) << setprecision(3) << reset << vVel << endl;
654 cout << highint << " Inertial velocity (ft/sec): " << setw(8) << setprecision(3) << reset << VState.vInertialVelocity << endl;
655 cout << highint << " Inertial Position (ft): " << setw(10) << setprecision(3) << reset << VState.vInertialPosition << endl;
656 cout << highint << " Latitude (deg): " << setw(8) << setprecision(3) << reset << VState.vLocation.GetLatitudeDeg() << endl;
657 cout << highint << " Longitude (deg): " << setw(8) << setprecision(3) << reset << VState.vLocation.GetLongitudeDeg() << endl;
658 cout << highint << " Altitude ASL (ft): " << setw(8) << setprecision(3) << reset << GetAltitudeASL() << endl;
659 // cout << highint << " Acceleration (NED, ft/sec^2): " << setw(8) << setprecision(3) << reset << Tb2l*GetUVWdot() << endl;
661 cout << highint << " Matrix ECEF to Body (Orientation of Body with respect to ECEF): "
662 << reset << endl << Tec2b.Dump("\t", " ") << endl;
663 cout << highint << " Associated Euler angles (deg): " << setw(8)
664 << setprecision(3) << reset << (Tec2b.GetQuaternion().GetEuler()*radtodeg)
667 cout << highint << " Matrix Body to ECEF (Orientation of ECEF with respect to Body):"
668 << reset << endl << Tb2ec.Dump("\t", " ") << endl;
669 cout << highint << " Associated Euler angles (deg): " << setw(8)
670 << setprecision(3) << reset << (Tb2ec.GetQuaternion().GetEuler()*radtodeg)
673 cout << highint << " Matrix Local to Body (Orientation of Body with respect to Local):"
674 << reset << endl << Tl2b.Dump("\t", " ") << endl;
675 cout << highint << " Associated Euler angles (deg): " << setw(8)
676 << setprecision(3) << reset << (Tl2b.GetQuaternion().GetEuler()*radtodeg)
679 cout << highint << " Matrix Body to Local (Orientation of Local with respect to Body):"
680 << reset << endl << Tb2l.Dump("\t", " ") << endl;
681 cout << highint << " Associated Euler angles (deg): " << setw(8)
682 << setprecision(3) << reset << (Tb2l.GetQuaternion().GetEuler()*radtodeg)
685 cout << highint << " Matrix Local to ECEF (Orientation of ECEF with respect to Local):"
686 << reset << endl << Tl2ec.Dump("\t", " ") << endl;
687 cout << highint << " Associated Euler angles (deg): " << setw(8)
688 << setprecision(3) << reset << (Tl2ec.GetQuaternion().GetEuler()*radtodeg)
691 cout << highint << " Matrix ECEF to Local (Orientation of Local with respect to ECEF):"
692 << reset << endl << Tec2l.Dump("\t", " ") << endl;
693 cout << highint << " Associated Euler angles (deg): " << setw(8)
694 << setprecision(3) << reset << (Tec2l.GetQuaternion().GetEuler()*radtodeg)
697 cout << highint << " Matrix ECEF to Inertial (Orientation of Inertial with respect to ECEF):"
698 << reset << endl << Tec2i.Dump("\t", " ") << endl;
699 cout << highint << " Associated Euler angles (deg): " << setw(8)
700 << setprecision(3) << reset << (Tec2i.GetQuaternion().GetEuler()*radtodeg)
703 cout << highint << " Matrix Inertial to ECEF (Orientation of ECEF with respect to Inertial):"
704 << reset << endl << Ti2ec.Dump("\t", " ") << endl;
705 cout << highint << " Associated Euler angles (deg): " << setw(8)
706 << setprecision(3) << reset << (Ti2ec.GetQuaternion().GetEuler()*radtodeg)
709 cout << highint << " Matrix Inertial to Body (Orientation of Body with respect to Inertial):"
710 << reset << endl << Ti2b.Dump("\t", " ") << endl;
711 cout << highint << " Associated Euler angles (deg): " << setw(8)
712 << setprecision(3) << reset << (Ti2b.GetQuaternion().GetEuler()*radtodeg)
715 cout << highint << " Matrix Body to Inertial (Orientation of Inertial with respect to Body):"
716 << reset << endl << Tb2i.Dump("\t", " ") << endl;
717 cout << highint << " Associated Euler angles (deg): " << setw(8)
718 << setprecision(3) << reset << (Tb2i.GetQuaternion().GetEuler()*radtodeg)
721 cout << highint << " Matrix Inertial to Local (Orientation of Local with respect to Inertial):"
722 << reset << endl << Ti2l.Dump("\t", " ") << endl;
723 cout << highint << " Associated Euler angles (deg): " << setw(8)
724 << setprecision(3) << reset << (Ti2l.GetQuaternion().GetEuler()*radtodeg)
727 cout << highint << " Matrix Local to Inertial (Orientation of Inertial with respect to Local):"
728 << reset << endl << Tl2i.Dump("\t", " ") << endl;
729 cout << highint << " Associated Euler angles (deg): " << setw(8)
730 << setprecision(3) << reset << (Tl2i.GetQuaternion().GetEuler()*radtodeg)
733 cout << setprecision(6); // reset the output stream
735 if (debug_lvl & 16) { // Sanity checking
736 if (from == 2) { // State sanity checking
737 if (fabs(VState.vPQR.Magnitude()) > 1000.0) {
738 cerr << endl << "Vehicle rotation rate is excessive (>1000 rad/sec): " << VState.vPQR.Magnitude() << endl;
741 if (fabs(VState.vUVW.Magnitude()) > 1.0e10) {
742 cerr << endl << "Vehicle velocity is excessive (>1e10 ft/sec): " << VState.vUVW.Magnitude() << endl;
745 if (fabs(GetDistanceAGL()) > 1e10) {
746 cerr << endl << "Vehicle altitude is excessive (>1e10 ft): " << GetDistanceAGL() << endl;
751 if (debug_lvl & 64) {
752 if (from == 0) { // Constructor
753 cout << IdSrc << endl;
754 cout << IdHdr << endl;