]> git.mxchange.org Git - flightgear.git/blob - src/FDM/JSBSim/models/FGPropagate.cpp
a1211cd621baf494a2c3ccfd327ca9beed0c240e
[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   Name = "FGPropagate";
99 //  vQtrndot.zero();
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   bind();
114   Debug(0);
115 }
116
117 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
118
119 FGPropagate::~FGPropagate(void)
120 {
121   unbind();
122   Debug(1);
123 }
124
125 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126
127 bool FGPropagate::InitModel(void)
128 {
129   FGModel::InitModel();
130
131   SeaLevelRadius = Inertial->RefRadius();          // For initialization ONLY
132   RunwayRadius   = SeaLevelRadius;
133
134   VState.vLocation.SetRadius( SeaLevelRadius + 4.0 );
135
136   return true;
137 }
138
139 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140
141 void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
142 {
143   SeaLevelRadius = FGIC->GetSeaLevelRadiusFtIC();
144   RunwayRadius = SeaLevelRadius;
145
146   // Set the position lat/lon/radius
147   VState.vLocation = FGLocation( FGIC->GetLongitudeRadIC(),
148                           FGIC->GetLatitudeRadIC(),
149                           FGIC->GetAltitudeFtIC() + FGIC->GetSeaLevelRadiusFtIC() );
150
151   // Set the Orientation from the euler angles
152   VState.vQtrn = FGQuaternion( FGIC->GetPhiRadIC(),
153                         FGIC->GetThetaRadIC(),
154                         FGIC->GetPsiRadIC() );
155
156   // Set the velocities in the instantaneus body frame
157   VState.vUVW = FGColumnVector3( FGIC->GetUBodyFpsIC(),
158                           FGIC->GetVBodyFpsIC(),
159                           FGIC->GetWBodyFpsIC() );
160
161   // Set the angular velocities in the instantaneus body frame.
162   VState.vPQR = FGColumnVector3( FGIC->GetPRadpsIC(),
163                           FGIC->GetQRadpsIC(),
164                           FGIC->GetRRadpsIC() );
165
166   // Compute some derived values.
167   vVel = VState.vQtrn.GetTInv()*VState.vUVW;
168
169   // Finally, make sure that the quaternion stays normalized.
170   VState.vQtrn.Normalize();
171
172   // Recompute the RunwayRadius level.
173   RecomputeRunwayRadius();
174 }
175
176 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
177 /*
178 Purpose: Called on a schedule to perform EOM integration
179 Notes:   [JB] Run in standalone mode, SeaLevelRadius will be reference radius.
180          In FGFS, SeaLevelRadius is stuffed from FGJSBSim in JSBSim.cxx each pass.
181
182 At the top of this Run() function, see several "shortcuts" (or, aliases) being
183 set up for use later, rather than using the longer class->function() notation.
184
185 Here, propagation of state is done using a simple explicit Euler scheme (see the
186 bottom of the function). This propagation is done using the current state values
187 and current derivatives. Based on these values we compute an approximation to the
188 state values for (now + dt).
189
190 */
191
192 bool FGPropagate::Run(void)
193 {
194   if (FGModel::Run()) return true;  // Fast return if we have nothing to do ...
195   if (FDMExec->Holding()) return false;
196
197   RecomputeRunwayRadius();
198
199   double dt = State->Getdt()*rate;  // The 'stepsize'
200   const FGColumnVector3 omega( 0.0, 0.0, Inertial->omega() ); // earth rotation
201   const FGColumnVector3& vForces = Aircraft->GetForces();     // current forces
202   const FGColumnVector3& vMoments = Aircraft->GetMoments();   // current moments
203
204   double mass = MassBalance->GetMass();             // mass
205   const FGMatrix33& J = MassBalance->GetJ();        // inertia matrix
206   const FGMatrix33& Jinv = MassBalance->GetJinv();  // inertia matrix inverse
207   double r = GetRadius();                           // radius
208   if (r == 0.0) {cerr << "radius = 0 !" << endl; r = 1e-16;} // radius check
209   double rInv = 1.0/r;
210   FGColumnVector3 gAccel( 0.0, 0.0, Inertial->GetGAccel(r) );
211
212   // The rotation matrices:
213   const FGMatrix33& Tl2b = GetTl2b();  // local to body frame
214   const FGMatrix33& Tb2l = GetTb2l();  // body to local frame
215   const FGMatrix33& Tec2l = VState.vLocation.GetTec2l();  // earth centered to local frame
216   const FGMatrix33& Tl2ec = VState.vLocation.GetTl2ec();  // local to earth centered frame
217
218   // Inertial angular velocity measured in the body frame.
219   const FGColumnVector3 pqri = VState.vPQR + Tl2b*(Tec2l*omega);
220
221   // Compute vehicle velocity wrt EC frame, expressed in Local horizontal frame.
222   vVel = Tb2l * VState.vUVW;
223
224   // First compute the time derivatives of the vehicle state values:
225
226   // Compute body frame rotational accelerations based on the current body moments
227   vPQRdot = Jinv*(vMoments - pqri*(J*pqri));
228
229   // Compute body frame accelerations based on the current body forces
230   vUVWdot = VState.vUVW*VState.vPQR + vForces/mass;
231
232   // Coriolis acceleration.
233   FGColumnVector3 ecVel = Tl2ec*vVel;
234   FGColumnVector3 ace = 2.0*omega*ecVel;
235   vUVWdot -= Tl2b*(Tec2l*ace);
236
237   if (!GroundReactions->GetWOW()) {
238     // Centrifugal acceleration.
239     FGColumnVector3 aeec = omega*(omega*VState.vLocation);
240     vUVWdot -= Tl2b*(Tec2l*aeec);
241   }
242
243   // Gravitation accel
244   vUVWdot += Tl2b*gAccel;
245
246   // Compute vehicle velocity wrt EC frame, expressed in EC frame
247   vLocationDot = Tl2ec * vVel;
248
249   FGColumnVector3 omegaLocal( rInv*vVel(eEast),
250                               -rInv*vVel(eNorth),
251                               -rInv*vVel(eEast)*VState.vLocation.GetTanLatitude() );
252
253   // Compute quaternion orientation derivative on current body rates
254   vQtrndot = VState.vQtrn.GetQDot( VState.vPQR - Tl2b*omegaLocal );
255
256   // Integrate to propagate the state
257
258   // Propagate rotational velocity
259
260   // VState.vPQR += dt*(1.5*vPQRdot - 0.5*last_vPQRdot); // Adams-Bashforth
261   VState.vPQR += (1/12.0)*dt*(23.0*vPQRdot - 16.0*last_vPQRdot + 5.0*last2_vPQRdot); // Adams-Bashforth 3
262   // VState.vPQR += dt*vPQRdot;                          // Rectangular Euler
263   // VState.vPQR += 0.5*dt*(vPQRdot + last_vPQRdot);     // Trapezoidal
264
265   // Propagate translational velocity
266
267   // VState.vUVW += dt*(1.5*vUVWdot - 0.5*last_vUVWdot); // Adams Bashforth
268   VState.vUVW += (1/12.0)*dt*(23.0*vUVWdot - 16.0*last_vUVWdot + 5.0*last2_vUVWdot); // Adams-Bashforth 3
269   // VState.vUVW += dt*vUVWdot;                         // Rectangular Euler
270   // VState.vUVW += 0.5*dt*(vUVWdot + last_vUVWdot);    // Trapezoidal
271
272   // Propagate angular position
273
274   // VState.vQtrn += dt*(1.5*vQtrndot - 0.5*last_vQtrndot); // Adams Bashforth
275   VState.vQtrn += (1/12.0)*dt*(23.0*vQtrndot - 16.0*last_vQtrndot + 5.0*last2_vQtrndot); // Adams-Bashforth 3
276   // VState.vQtrn += dt*vQtrndot;                           // Rectangular Euler
277   // VState.vQtrn += 0.5*dt*(vQtrndot + last_vQtrndot);     // Trapezoidal
278
279   // Propagate translational position
280
281   // VState.vLocation += dt*(1.5*vLocationDot - 0.5*last_vLocationDot); // Adams Bashforth
282   VState.vLocation += (1/12.0)*dt*(23.0*vLocationDot - 16.0*last_vLocationDot + 5.0*last2_vLocationDot); // Adams-Bashforth 3
283   // VState.vLocation += dt*vLocationDot;                               // Rectangular Euler
284   // VState.vLocation += 0.5*dt*(vLocationDot + last_vLocationDot);     // Trapezoidal
285
286   // Set past values
287   
288   last2_vPQRdot = last_vPQRdot;
289   last_vPQRdot = vPQRdot;
290   
291   last2_vUVWdot = last_vUVWdot;
292   last_vUVWdot = vUVWdot;
293   
294   last2_vQtrndot = last_vQtrndot;
295   last_vQtrndot = vQtrndot;
296
297   last2_vLocationDot = last_vLocationDot;
298   last_vLocationDot = vLocationDot;
299
300   return false;
301 }
302
303 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
304
305 void FGPropagate::RecomputeRunwayRadius(void)
306 {
307   // Get the runway radius.
308   FGLocation contactloc;
309   FGColumnVector3 dv;
310   FGGroundCallback* gcb = FDMExec->GetGroundCallback();
311   double t = State->Getsim_time();
312   gcb->GetAGLevel(t, VState.vLocation, contactloc, dv, dv);
313   RunwayRadius = contactloc.GetRadius();
314 }
315
316 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
317
318 void FGPropagate::Seth(double tt)
319 {
320   VState.vLocation.SetRadius( tt + SeaLevelRadius );
321 }
322
323 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
324
325 double FGPropagate::GetRunwayRadius(void) const
326 {
327   return RunwayRadius;
328 }
329
330 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
331
332 double FGPropagate::GetDistanceAGL(void) const
333 {
334   return VState.vLocation.GetRadius() - RunwayRadius;
335 }
336
337 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
338
339 void FGPropagate::SetDistanceAGL(double tt)
340 {
341   VState.vLocation.SetRadius( tt + RunwayRadius );
342 }
343
344 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
345
346 void FGPropagate::bind(void)
347 {
348   typedef double (FGPropagate::*PMF)(int) const;
349   PropertyManager->Tie("velocities/h-dot-fps", this, &FGPropagate::Gethdot);
350
351   PropertyManager->Tie("velocities/v-north-fps", this, eNorth, (PMF)&FGPropagate::GetVel);
352   PropertyManager->Tie("velocities/v-east-fps", this, eEast, (PMF)&FGPropagate::GetVel);
353   PropertyManager->Tie("velocities/v-down-fps", this, eDown, (PMF)&FGPropagate::GetVel);
354
355   PropertyManager->Tie("velocities/u-fps", this, eU, (PMF)&FGPropagate::GetUVW);
356   PropertyManager->Tie("velocities/v-fps", this, eV, (PMF)&FGPropagate::GetUVW);
357   PropertyManager->Tie("velocities/w-fps", this, eW, (PMF)&FGPropagate::GetUVW);
358
359   PropertyManager->Tie("velocities/p-rad_sec", this, eP, (PMF)&FGPropagate::GetPQR);
360   PropertyManager->Tie("velocities/q-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQR);
361   PropertyManager->Tie("velocities/r-rad_sec", this, eR, (PMF)&FGPropagate::GetPQR);
362
363   PropertyManager->Tie("accelerations/pdot-rad_sec", this, eP, (PMF)&FGPropagate::GetPQRdot);
364   PropertyManager->Tie("accelerations/qdot-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQRdot);
365   PropertyManager->Tie("accelerations/rdot-rad_sec", this, eR, (PMF)&FGPropagate::GetPQRdot);
366
367   PropertyManager->Tie("accelerations/udot-fps", this, eU, (PMF)&FGPropagate::GetUVWdot);
368   PropertyManager->Tie("accelerations/vdot-fps", this, eV, (PMF)&FGPropagate::GetUVWdot);
369   PropertyManager->Tie("accelerations/wdot-fps", this, eW, (PMF)&FGPropagate::GetUVWdot);
370
371   PropertyManager->Tie("position/h-sl-ft", this, &FGPropagate::Geth, &FGPropagate::Seth, true);
372   PropertyManager->Tie("position/lat-gc-rad", this, &FGPropagate::GetLatitude, &FGPropagate::SetLatitude);
373   PropertyManager->Tie("position/long-gc-rad", this, &FGPropagate::GetLongitude, &FGPropagate::SetLongitude);
374   PropertyManager->Tie("position/h-agl-ft", this,  &FGPropagate::GetDistanceAGL, &FGPropagate::SetDistanceAGL);
375   PropertyManager->Tie("position/radius-to-vehicle-ft", this, &FGPropagate::GetRadius);
376
377   PropertyManager->Tie("metrics/runway-radius", this, &FGPropagate::GetRunwayRadius);
378
379   PropertyManager->Tie("attitude/phi-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
380   PropertyManager->Tie("attitude/theta-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
381   PropertyManager->Tie("attitude/psi-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
382
383   PropertyManager->Tie("attitude/roll-rad", this, (int)ePhi, (PMF)&FGPropagate::GetEuler);
384   PropertyManager->Tie("attitude/pitch-rad", this, (int)eTht, (PMF)&FGPropagate::GetEuler);
385   PropertyManager->Tie("attitude/heading-true-rad", this, (int)ePsi, (PMF)&FGPropagate::GetEuler);
386 }
387
388 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
389
390 void FGPropagate::unbind(void)
391 {
392   PropertyManager->Untie("velocities/v-north-fps");
393   PropertyManager->Untie("velocities/v-east-fps");
394   PropertyManager->Untie("velocities/v-down-fps");
395   PropertyManager->Untie("velocities/h-dot-fps");
396   PropertyManager->Untie("velocities/u-fps");
397   PropertyManager->Untie("velocities/v-fps");
398   PropertyManager->Untie("velocities/w-fps");
399   PropertyManager->Untie("velocities/p-rad_sec");
400   PropertyManager->Untie("velocities/q-rad_sec");
401   PropertyManager->Untie("velocities/r-rad_sec");
402   PropertyManager->Untie("accelerations/udot-fps");
403   PropertyManager->Untie("accelerations/vdot-fps");
404   PropertyManager->Untie("accelerations/wdot-fps");
405   PropertyManager->Untie("accelerations/pdot-rad_sec");
406   PropertyManager->Untie("accelerations/qdot-rad_sec");
407   PropertyManager->Untie("accelerations/rdot-rad_sec");
408   PropertyManager->Untie("position/h-sl-ft");
409   PropertyManager->Untie("position/lat-gc-rad");
410   PropertyManager->Untie("position/long-gc-rad");
411   PropertyManager->Untie("position/h-agl-ft");
412   PropertyManager->Untie("position/radius-to-vehicle-ft");
413   PropertyManager->Untie("metrics/runway-radius");
414   PropertyManager->Untie("attitude/phi-rad");
415   PropertyManager->Untie("attitude/theta-rad");
416   PropertyManager->Untie("attitude/psi-rad");
417   PropertyManager->Untie("attitude/roll-rad");
418   PropertyManager->Untie("attitude/pitch-rad");
419   PropertyManager->Untie("attitude/heading-true-rad");
420 }
421
422 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
423 //    The bitmasked value choices are as follows:
424 //    unset: In this case (the default) JSBSim would only print
425 //       out the normally expected messages, essentially echoing
426 //       the config files as they are read. If the environment
427 //       variable is not set, debug_lvl is set to 1 internally
428 //    0: This requests JSBSim not to output any messages
429 //       whatsoever.
430 //    1: This value explicity requests the normal JSBSim
431 //       startup messages
432 //    2: This value asks for a message to be printed out when
433 //       a class is instantiated
434 //    4: When this value is set, a message is displayed when a
435 //       FGModel object executes its Run() method
436 //    8: When this value is set, various runtime state variables
437 //       are printed out periodically
438 //    16: When set various parameters are sanity checked and
439 //       a message is printed out when they go out of bounds
440
441 void FGPropagate::Debug(int from)
442 {
443   if (debug_lvl <= 0) return;
444
445   if (debug_lvl & 1) { // Standard console startup message output
446     if (from == 0) { // Constructor
447
448     }
449   }
450   if (debug_lvl & 2 ) { // Instantiation/Destruction notification
451     if (from == 0) cout << "Instantiated: FGPropagate" << endl;
452     if (from == 1) cout << "Destroyed:    FGPropagate" << endl;
453   }
454   if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
455   }
456   if (debug_lvl & 8 ) { // Runtime state variables
457   }
458   if (debug_lvl & 16) { // Sanity checking
459   }
460   if (debug_lvl & 64) {
461     if (from == 0) { // Constructor
462       cout << IdSrc << endl;
463       cout << IdHdr << endl;
464     }
465   }
466 }
467 }