JSBSim Flight Dynamics Model  1.0 (02 March 2017)
An Open Source Flight Dynamics and Control Software Library in C++
FGInitialCondition.cpp
1 /*******************************************************************************
2 
3  Header: FGInitialCondition.cpp
4  Author: Tony Peden, Bertrand Coconnier
5  Date started: 7/1/99
6 
7  ------------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) -------------
8 
9  This program is free software; you can redistribute it and/or modify it under
10  the terms of the GNU Lesser General Public License as published by the Free Software
11  Foundation; either version 2 of the License, or (at your option) any later
12  version.
13 
14  This program is distributed in the hope that it will be useful, but WITHOUT
15  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
16  FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
17  details.
18 
19  You should have received a copy of the GNU Lesser General Public License along with
20  this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21  Place - Suite 330, Boston, MA 02111-1307, USA.
22 
23  Further information about the GNU Lesser General Public License can also be found on
24  the world wide web at http://www.gnu.org.
25 
26 
27  HISTORY
28 --------------------------------------------------------------------------------
29 7/1/99 TP Created
30 11/25/10 BC Complete revision - Use minimal set of variables to prevent
31  inconsistent states. Wind is correctly handled.
32 
33 
34 FUNCTIONAL DESCRIPTION
35 --------------------------------------------------------------------------------
36 
37 The purpose of this class is to take a set of initial conditions and provide
38 a kinematically consistent set of body axis velocity components, euler
39 angles, and altitude. This class does not attempt to trim the model i.e.
40 the sim will most likely start in a very dynamic state (unless, of course,
41 you have chosen your IC's wisely) even after setting it up with this class.
42 
43 ********************************************************************************
44 INCLUDES
45 *******************************************************************************/
46 
47 #include <cstdlib>
48 
49 #include "FGInitialCondition.h"
50 #include "FGFDMExec.h"
51 #include "models/FGInertial.h"
52 #include "models/FGAtmosphere.h"
53 #include "models/FGAircraft.h"
54 #include "models/FGAccelerations.h"
55 #include "input_output/FGXMLFileRead.h"
56 
57 using namespace std;
58 
59 namespace JSBSim {
60 
61 IDENT(IdSrc,"$Id: FGInitialCondition.cpp,v 1.114 2017/02/25 14:23:18 bcoconni Exp $");
62 IDENT(IdHdr,ID_INITIALCONDITION);
63 
64 //******************************************************************************
65 
66 FGInitialCondition::FGInitialCondition(FGFDMExec *FDMExec) : fdmex(FDMExec)
67 {
68  InitializeIC();
69 
70  if(FDMExec != NULL ) {
71  Atmosphere=fdmex->GetAtmosphere();
72  Aircraft=fdmex->GetAircraft();
73  } else {
74  cout << "FGInitialCondition: This class requires a pointer to a valid FGFDMExec object" << endl;
75  }
76 
77  Debug(0);
78 }
79 
80 //******************************************************************************
81 
83 {
84  Debug(1);
85 }
86 
87 //******************************************************************************
88 
89 void FGInitialCondition::ResetIC(double u0, double v0, double w0,
90  double p0, double q0, double r0,
91  double alpha0, double beta0,
92  double phi0, double theta0, double psi0,
93  double latRad0, double lonRad0, double altAGLFt0,
94  double gamma0)
95 {
96  double calpha = cos(alpha0), cbeta = cos(beta0);
97  double salpha = sin(alpha0), sbeta = sin(beta0);
98 
99  InitializeIC();
100 
101  vPQR_body = FGColumnVector3(p0, q0, r0);
102  alpha = alpha0; beta = beta0;
103 
104  position.SetLongitude(lonRad0);
105  position.SetLatitude(latRad0);
106  position.SetAltitudeAGL(altAGLFt0);
107  lastLatitudeSet = setgeoc;
108  lastAltitudeSet = setagl;
109 
110  orientation = FGQuaternion(phi0, theta0, psi0);
111  const FGMatrix33& Tb2l = orientation.GetTInv();
112 
113  vUVW_NED = Tb2l * FGColumnVector3(u0, v0, w0);
114  vt = vUVW_NED.Magnitude();
115  lastSpeedSet = setuvw;
116 
117  Tw2b = FGMatrix33(calpha*cbeta, -calpha*sbeta, -salpha,
118  sbeta, cbeta, 0.0,
119  salpha*cbeta, -salpha*sbeta, calpha);
120  Tb2w = Tw2b.Transposed();
121 
122  SetFlightPathAngleRadIC(gamma0);
123 }
124 
125 //******************************************************************************
126 
127 void FGInitialCondition::InitializeIC(void)
128 {
129  alpha=beta=0;
130  a = fdmex->GetInertial()->GetSemimajor();
131  double b = fdmex->GetInertial()->GetSemiminor();
132  double ec = b/a;
133  e2 = 1.0 - ec*ec;
134 
135  position.SetEllipse(a, b);
136 
137  position.SetPositionGeodetic(0.0, 0.0, 0.0);
138  position.SetEarthPositionAngle(fdmex->GetPropagate()->GetEarthPositionAngle());
139 
140  orientation = FGQuaternion(0.0, 0.0, 0.0);
141  vUVW_NED.InitMatrix();
142  vPQR_body.InitMatrix();
143  vt=0;
144 
145  targetNlfIC = 1.0;
146 
147  Tw2b.InitMatrix(1., 0., 0., 0., 1., 0., 0., 0., 1.);
148  Tb2w.InitMatrix(1., 0., 0., 0., 1., 0., 0., 0., 1.);
149 
150  lastSpeedSet = setvt;
151  lastAltitudeSet = setasl;
152  lastLatitudeSet = setgeoc;
153  enginesRunning = 0;
154  needTrim = 0;
155 }
156 
157 //******************************************************************************
158 
160 {
161  double altitudeASL = position.GetAltitudeASL();
162  double rho = Atmosphere->GetDensity(altitudeASL);
163  double rhoSL = Atmosphere->GetDensitySL();
164  SetVtrueFpsIC(ve*ktstofps*sqrt(rhoSL/rho));
165  lastSpeedSet = setve;
166 }
167 
168 //******************************************************************************
169 
171 {
172  double altitudeASL = position.GetAltitudeASL();
173  double soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
174  SetVtrueFpsIC(mach*soundSpeed);
175  lastSpeedSet = setmach;
176 }
177 
178 //******************************************************************************
179 
181 {
182  double altitudeASL = position.GetAltitudeASL();
183  double pressure = Atmosphere->GetPressure(altitudeASL);
184  double pressureSL = Atmosphere->GetPressureSL();
185  double rhoSL = Atmosphere->GetDensitySL();
186  double mach = MachFromVcalibrated(fabs(vcas)*ktstofps, pressure, pressureSL, rhoSL);
187  double soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
188  double PitotAngle = Aircraft->GetPitotAngle();
189 
190  SetVtrueFpsIC(mach * soundSpeed / (cos(alpha+PitotAngle) * cos(beta)));
191  lastSpeedSet = setvc;
192 }
193 
194 //******************************************************************************
195 // Updates alpha and beta according to the aircraft true airspeed in the local
196 // NED frame.
197 
198 void FGInitialCondition::calcAeroAngles(const FGColumnVector3& _vt_NED)
199 {
200  const FGMatrix33& Tl2b = orientation.GetT();
201  FGColumnVector3 _vt_BODY = Tl2b * _vt_NED;
202  double ua = _vt_BODY(eX);
203  double va = _vt_BODY(eY);
204  double wa = _vt_BODY(eZ);
205  double uwa = sqrt(ua*ua + wa*wa);
206  double calpha, cbeta;
207  double salpha, sbeta;
208 
209  alpha = beta = 0.0;
210  calpha = cbeta = 1.0;
211  salpha = sbeta = 0.0;
212 
213  if( wa != 0 )
214  alpha = atan2( wa, ua );
215 
216  // alpha cannot be constrained without updating other informations like the
217  // true speed or the Euler angles. Otherwise we might end up with an
218  // inconsistent state of the aircraft.
219  /*alpha = Constrain(fdmex->GetAerodynamics()->GetAlphaCLMin(), alpha,
220  fdmex->GetAerodynamics()->GetAlphaCLMax());*/
221 
222  if( va != 0 )
223  beta = atan2( va, uwa );
224 
225  if (uwa != 0) {
226  calpha = ua / uwa;
227  salpha = wa / uwa;
228  }
229 
230  if (vt != 0) {
231  cbeta = uwa / vt;
232  sbeta = va / vt;
233  }
234 
235  Tw2b = FGMatrix33(calpha*cbeta, -calpha*sbeta, -salpha,
236  sbeta, cbeta, 0.0,
237  salpha*cbeta, -salpha*sbeta, calpha);
238  Tb2w = Tw2b.Transposed();
239 }
240 
241 //******************************************************************************
242 // Set the ground velocity. Caution it sets the vertical velocity to zero to
243 // keep backward compatibility.
244 
246 {
247  const FGMatrix33& Tb2l = orientation.GetTInv();
248  FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
249  FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
250 
251  vUVW_NED(eU) = vg * orientation.GetCosEuler(ePsi);
252  vUVW_NED(eV) = vg * orientation.GetSinEuler(ePsi);
253  vUVW_NED(eW) = 0.;
254  _vt_NED = vUVW_NED + _vWIND_NED;
255  vt = _vt_NED.Magnitude();
256 
257  calcAeroAngles(_vt_NED);
258 
259  lastSpeedSet = setvg;
260 }
261 
262 //******************************************************************************
263 // Sets the true airspeed. The amplitude of the airspeed is modified but its
264 // direction is kept unchanged. If there is no wind, the same is true for the
265 // ground velocity. If there is some wind, the airspeed direction is unchanged
266 // but this may result in the ground velocity direction being altered. This is
267 // for backward compatibility.
268 
270 {
271  const FGMatrix33& Tb2l = orientation.GetTInv();
272  FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
273  FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
274 
275  if (vt > 0.1)
276  _vt_NED *= vtrue / vt;
277  else
278  _vt_NED = Tb2l * Tw2b * FGColumnVector3(vtrue, 0., 0.);
279 
280  vt = vtrue;
281  vUVW_NED = _vt_NED - _vWIND_NED;
282 
283  calcAeroAngles(_vt_NED);
284 
285  lastSpeedSet = setvt;
286 }
287 
288 //******************************************************************************
289 // When the climb rate is modified, we need to update the angles theta and beta
290 // to keep the true airspeed amplitude, the AoA and the heading unchanged.
291 // Beta will be modified if the aircraft roll angle is not null.
292 
294 {
295  if (fabs(hdot) > vt) {
296  cerr << "The climb rate cannot be higher than the true speed." << endl;
297  return;
298  }
299 
300  const FGMatrix33& Tb2l = orientation.GetTInv();
301  FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
302  FGColumnVector3 _WIND_NED = _vt_NED - vUVW_NED;
303  double hdot0 = -_vt_NED(eW);
304 
305  if (fabs(hdot0) < vt) { // Is this check really needed ?
306  double scale = sqrt((vt*vt-hdot*hdot)/(vt*vt-hdot0*hdot0));
307  _vt_NED(eU) *= scale;
308  _vt_NED(eV) *= scale;
309  }
310  _vt_NED(eW) = -hdot;
311  vUVW_NED = _vt_NED - _WIND_NED;
312 
313  // Updating the angles theta and beta to keep the true airspeed amplitude
314  calcThetaBeta(alpha, _vt_NED);
315 }
316 
317 //******************************************************************************
318 // When the AoA is modified, we need to update the angles theta and beta to
319 // keep the true airspeed amplitude, the climb rate and the heading unchanged.
320 // Beta will be modified if the aircraft roll angle is not null.
321 
323 {
324  const FGMatrix33& Tb2l = orientation.GetTInv();
325  FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
326  calcThetaBeta(alfa, _vt_NED);
327 }
328 
329 //******************************************************************************
330 // When the AoA is modified, we need to update the angles theta and beta to
331 // keep the true airspeed amplitude, the climb rate and the heading unchanged.
332 // Beta will be modified if the aircraft roll angle is not null.
333 
334 void FGInitialCondition::calcThetaBeta(double alfa, const FGColumnVector3& _vt_NED)
335 {
336  FGColumnVector3 vOrient = orientation.GetEuler();
337  double calpha = cos(alfa), salpha = sin(alfa);
338  double cpsi = orientation.GetCosEuler(ePsi), spsi = orientation.GetSinEuler(ePsi);
339  double cphi = orientation.GetCosEuler(ePhi), sphi = orientation.GetSinEuler(ePhi);
340  FGMatrix33 Tpsi( cpsi, spsi, 0.,
341  -spsi, cpsi, 0.,
342  0., 0., 1.);
343  FGMatrix33 Tphi(1., 0., 0.,
344  0., cphi, sphi,
345  0.,-sphi, cphi);
346  FGMatrix33 Talpha( calpha, 0., salpha,
347  0., 1., 0.,
348  -salpha, 0., calpha);
349 
350  FGColumnVector3 v0 = Tpsi * _vt_NED;
351  FGColumnVector3 n = (Talpha * Tphi).Transposed() * FGColumnVector3(0., 0., 1.);
352  FGColumnVector3 y = FGColumnVector3(0., 1., 0.);
353  FGColumnVector3 u = y - DotProduct(y, n) * n;
354  FGColumnVector3 p = y * n;
355 
356  if (DotProduct(p, v0) < 0) p *= -1.0;
357  p.Normalize();
358 
359  u *= DotProduct(v0, y) / DotProduct(u, y);
360 
361  // There are situations where the desired alpha angle cannot be obtained. This
362  // is not a limitation of the algorithm but is due to the mathematical problem
363  // not having a solution. This can only be cured by limiting the alpha angle
364  // or by modifying an additional angle (psi ?). Since this is anticipated to
365  // be a pathological case (mainly when a high roll angle is required) this
366  // situation is not addressed below. However if there are complaints about the
367  // following error being raised too often, we might need to reconsider this
368  // position.
369  if (DotProduct(v0, v0) < DotProduct(u, u)) {
370  cerr << "Cannot modify angle 'alpha' from " << alpha << " to " << alfa << endl;
371  return;
372  }
373 
374  FGColumnVector3 v1 = u + sqrt(DotProduct(v0, v0) - DotProduct(u, u))*p;
375 
376  FGColumnVector3 v0xz(v0(eU), 0., v0(eW));
377  FGColumnVector3 v1xz(v1(eU), 0., v1(eW));
378  v0xz.Normalize();
379  v1xz.Normalize();
380  double sinTheta = (v1xz * v0xz)(eY);
381  vOrient(eTht) = asin(sinTheta);
382 
383  orientation = FGQuaternion(vOrient);
384 
385  const FGMatrix33& Tl2b = orientation.GetT();
386  FGColumnVector3 v2 = Talpha * Tl2b * _vt_NED;
387 
388  alpha = alfa;
389  beta = atan2(v2(eV), v2(eU));
390  double cbeta=1.0, sbeta=0.0;
391  if (vt != 0.0) {
392  cbeta = v2(eU) / vt;
393  sbeta = v2(eV) / vt;
394  }
395  Tw2b = FGMatrix33(calpha*cbeta, -calpha*sbeta, -salpha,
396  sbeta, cbeta, 0.0,
397  salpha*cbeta, -salpha*sbeta, calpha);
398  Tb2w = Tw2b.Transposed();
399 }
400 
401 //******************************************************************************
402 // When the beta angle is modified, we need to update the angles theta and psi
403 // to keep the true airspeed (amplitude and direction - including the climb rate)
404 // and the alpha angle unchanged. This may result in the aircraft heading (psi)
405 // being altered especially if there is cross wind.
406 
408 {
409  const FGMatrix33& Tb2l = orientation.GetTInv();
410  FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
411  FGColumnVector3 vOrient = orientation.GetEuler();
412 
413  beta = bta;
414  double calpha = cos(alpha), salpha = sin(alpha);
415  double cbeta = cos(beta), sbeta = sin(beta);
416  double cphi = orientation.GetCosEuler(ePhi), sphi = orientation.GetSinEuler(ePhi);
417  FGMatrix33 TphiInv(1., 0., 0.,
418  0., cphi,-sphi,
419  0., sphi, cphi);
420 
421  Tw2b = FGMatrix33(calpha*cbeta, -calpha*sbeta, -salpha,
422  sbeta, cbeta, 0.0,
423  salpha*cbeta, -salpha*sbeta, calpha);
424  Tb2w = Tw2b.Transposed();
425 
426  FGColumnVector3 vf = TphiInv * Tw2b * FGColumnVector3(vt, 0., 0.);
427  FGColumnVector3 v0xy(_vt_NED(eX), _vt_NED(eY), 0.);
428  FGColumnVector3 v1xy(sqrt(v0xy(eX)*v0xy(eX)+v0xy(eY)*v0xy(eY)-vf(eY)*vf(eY)),vf(eY),0.);
429  v0xy.Normalize();
430  v1xy.Normalize();
431 
432  if (vf(eX) < 0.) v0xy(eX) *= -1.0;
433 
434  double sinPsi = (v1xy * v0xy)(eZ);
435  double cosPsi = DotProduct(v0xy, v1xy);
436  vOrient(ePsi) = atan2(sinPsi, cosPsi);
437  FGMatrix33 Tpsi( cosPsi, sinPsi, 0.,
438  -sinPsi, cosPsi, 0.,
439  0., 0., 1.);
440 
441  FGColumnVector3 v2xz = Tpsi * _vt_NED;
442  FGColumnVector3 vfxz = vf;
443  v2xz(eV) = vfxz(eV) = 0.0;
444  v2xz.Normalize();
445  vfxz.Normalize();
446  double sinTheta = (v2xz * vfxz)(eY);
447  vOrient(eTht) = -asin(sinTheta);
448 
449  orientation = FGQuaternion(vOrient);
450 }
451 
452 //******************************************************************************
453 // Modifies the body frame orientation.
454 
455 void FGInitialCondition::SetEulerAngleRadIC(int idx, double angle)
456 {
457  const FGMatrix33& Tb2l = orientation.GetTInv();
458  const FGMatrix33& Tl2b = orientation.GetT();
459  FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
460  FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
461  FGColumnVector3 _vUVW_BODY = Tl2b * vUVW_NED;
462  FGColumnVector3 vOrient = orientation.GetEuler();
463 
464  vOrient(idx) = angle;
465  orientation = FGQuaternion(vOrient);
466 
467  if ((lastSpeedSet != setned) && (lastSpeedSet != setvg)) {
468  const FGMatrix33& newTb2l = orientation.GetTInv();
469  vUVW_NED = newTb2l * _vUVW_BODY;
470  _vt_NED = vUVW_NED + _vWIND_NED;
471  vt = _vt_NED.Magnitude();
472  }
473 
474  calcAeroAngles(_vt_NED);
475 }
476 
477 //******************************************************************************
478 // Modifies an aircraft velocity component (eU, eV or eW) in the body frame. The
479 // true airspeed is modified accordingly. If there is some wind, the airspeed
480 // direction modification may differ from the body velocity modification.
481 
482 void FGInitialCondition::SetBodyVelFpsIC(int idx, double vel)
483 {
484  const FGMatrix33& Tb2l = orientation.GetTInv();
485  const FGMatrix33& Tl2b = orientation.GetT();
486  FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
487  FGColumnVector3 _vUVW_BODY = Tl2b * vUVW_NED;
488  FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
489 
490  _vUVW_BODY(idx) = vel;
491  vUVW_NED = Tb2l * _vUVW_BODY;
492  _vt_NED = vUVW_NED + _vWIND_NED;
493  vt = _vt_NED.Magnitude();
494 
495  calcAeroAngles(_vt_NED);
496 
497  lastSpeedSet = setuvw;
498 }
499 
500 //******************************************************************************
501 // Modifies an aircraft velocity component (eX, eY or eZ) in the local NED frame.
502 // The true airspeed is modified accordingly. If there is some wind, the airspeed
503 // direction modification may differ from the local velocity modification.
504 
505 void FGInitialCondition::SetNEDVelFpsIC(int idx, double vel)
506 {
507  const FGMatrix33& Tb2l = orientation.GetTInv();
508  FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
509  FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
510 
511  vUVW_NED(idx) = vel;
512  _vt_NED = vUVW_NED + _vWIND_NED;
513  vt = _vt_NED.Magnitude();
514 
515  calcAeroAngles(_vt_NED);
516 
517  lastSpeedSet = setned;
518 }
519 
520 //******************************************************************************
521 // Set wind amplitude and direction in the local NED frame. The aircraft velocity
522 // with respect to the ground is not changed but the true airspeed is.
523 
524 void FGInitialCondition::SetWindNEDFpsIC(double wN, double wE, double wD )
525 {
526  FGColumnVector3 _vt_NED = vUVW_NED + FGColumnVector3(wN, wE, wD);
527  vt = _vt_NED.Magnitude();
528 
529  calcAeroAngles(_vt_NED);
530 }
531 
532 //******************************************************************************
533 // Set the cross wind velocity (in knots). Here, 'cross wind' means perpendicular
534 // to the aircraft heading and parallel to the ground. The aircraft velocity
535 // with respect to the ground is not changed but the true airspeed is.
536 
538 {
539  const FGMatrix33& Tb2l = orientation.GetTInv();
540  FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
541  FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
542  FGColumnVector3 _vCROSS(-orientation.GetSinEuler(ePsi), orientation.GetCosEuler(ePsi), 0.);
543 
544  // Gram-Schmidt process is used to remove the existing cross wind component
545  _vWIND_NED -= DotProduct(_vWIND_NED, _vCROSS) * _vCROSS;
546  // Which is now replaced by the new value. The input cross wind is expected
547  // in knots, so first convert to fps, which is the internal unit used.
548  _vWIND_NED += (cross * ktstofps) * _vCROSS;
549  _vt_NED = vUVW_NED + _vWIND_NED;
550  vt = _vt_NED.Magnitude();
551 
552  calcAeroAngles(_vt_NED);
553 }
554 
555 //******************************************************************************
556 // Set the head wind velocity (in knots). Here, 'head wind' means parallel
557 // to the aircraft heading and to the ground. The aircraft velocity
558 // with respect to the ground is not changed but the true airspeed is.
559 
561 {
562  const FGMatrix33& Tb2l = orientation.GetTInv();
563  FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
564  FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
565  // This is a head wind, so the direction vector for the wind
566  // needs to be set opposite to the heading the aircraft
567  // is taking. So, the cos and sin of the heading (psi)
568  // are negated in the line below.
569  FGColumnVector3 _vHEAD(-orientation.GetCosEuler(ePsi), -orientation.GetSinEuler(ePsi), 0.);
570 
571  // Gram-Schmidt process is used to remove the existing head wind component
572  _vWIND_NED -= DotProduct(_vWIND_NED, _vHEAD) * _vHEAD;
573  // Which is now replaced by the new value. The input head wind is expected
574  // in knots, so first convert to fps, which is the internal unit used.
575  _vWIND_NED += (head * ktstofps) * _vHEAD;
576  _vt_NED = vUVW_NED + _vWIND_NED;
577 
578  vt = _vt_NED.Magnitude();
579 
580  calcAeroAngles(_vt_NED);
581 }
582 
583 //******************************************************************************
584 // Set the vertical wind velocity (in knots). The 'vertical' is taken in the
585 // local NED frame. The aircraft velocity with respect to the ground is not
586 // changed but the true airspeed is.
587 
589 {
590  const FGMatrix33& Tb2l = orientation.GetTInv();
591  FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
592 
593  _vt_NED(eW) = vUVW_NED(eW) + wD;
594  vt = _vt_NED.Magnitude();
595 
596  calcAeroAngles(_vt_NED);
597 }
598 
599 //******************************************************************************
600 // Modifies the wind velocity (in knots) while keeping its direction unchanged.
601 // The vertical component (in local NED frame) is unmodified. The aircraft
602 // velocity with respect to the ground is not changed but the true airspeed is.
603 
605 {
606  const FGMatrix33& Tb2l = orientation.GetTInv();
607  FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
608  FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
609  FGColumnVector3 _vHEAD(_vWIND_NED(eU), _vWIND_NED(eV), 0.);
610  double windMag = _vHEAD.Magnitude();
611 
612  if (windMag > 0.001)
613  _vHEAD *= (mag*ktstofps) / windMag;
614  else
615  _vHEAD = FGColumnVector3((mag*ktstofps), 0., 0.);
616 
617  _vWIND_NED(eU) = _vHEAD(eU);
618  _vWIND_NED(eV) = _vHEAD(eV);
619  _vt_NED = vUVW_NED + _vWIND_NED;
620  vt = _vt_NED.Magnitude();
621 
622  calcAeroAngles(_vt_NED);
623 }
624 
625 //******************************************************************************
626 // Modifies the wind direction while keeping its velocity unchanged. The vertical
627 // component (in local NED frame) is unmodified. The aircraft velocity with
628 // respect to the ground is not changed but the true airspeed is.
629 
631 {
632  const FGMatrix33& Tb2l = orientation.GetTInv();
633  FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
634  FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
635  double mag = _vWIND_NED.Magnitude(eU, eV);
636  FGColumnVector3 _vHEAD(mag*cos(dir*degtorad), mag*sin(dir*degtorad), 0.);
637 
638  _vWIND_NED(eU) = _vHEAD(eU);
639  _vWIND_NED(eV) = _vHEAD(eV);
640  _vt_NED = vUVW_NED + _vWIND_NED;
641  vt = _vt_NED.Magnitude();
642 
643  calcAeroAngles(_vt_NED);
644 }
645 
646 //******************************************************************************
647 
649 {
650  fdmex->GetGroundCallback()->SetSeaLevelRadius(slr);
651 }
652 
653 //******************************************************************************
654 
656 {
657  double agl = GetAltitudeAGLFtIC();
658 
659  fdmex->GetGroundCallback()->SetTerrainGeoCentRadius(elev + position.GetSeaLevelRadius());
660 
661  if (lastAltitudeSet == setagl)
662  SetAltitudeAGLFtIC(agl);
663 }
664 
665 //******************************************************************************
666 
668 {
669  return position.GetAltitudeAGL();
670 }
671 
672 //******************************************************************************
673 
675 {
676  return position.GetTerrainRadius() - position.GetSeaLevelRadius();
677 }
678 
679 //******************************************************************************
680 
682 {
683  double terrainElevation = position.GetTerrainRadius()
684  - position.GetSeaLevelRadius();
685  SetAltitudeASLFtIC(agl + terrainElevation);
686  lastAltitudeSet = setagl;
687 }
688 
689 //******************************************************************************
690 // Set the altitude SL. If the airspeed has been previously set with parameters
691 // that are atmosphere dependent (Mach, VCAS, VEAS) then the true airspeed is
692 // modified to keep the last set speed to its previous value.
693 
695 {
696  double altitudeASL = position.GetAltitudeASL();
697  double pressure = Atmosphere->GetPressure(altitudeASL);
698  double pressureSL = Atmosphere->GetPressureSL();
699  double soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
700  double rho = Atmosphere->GetDensity(altitudeASL);
701  double rhoSL = Atmosphere->GetDensitySL();
702 
703  double mach0 = vt / soundSpeed;
704  double vc0 = VcalibratedFromMach(mach0, pressure, pressureSL, rhoSL);
705  double ve0 = vt * sqrt(rho/rhoSL);
706  double PitotAngle = Aircraft->GetPitotAngle();
707 
708  double geodLatitude = position.GetGeodLatitudeRad();
709  altitudeASL=alt;
710  position.SetAltitudeASL(alt);
711 
712  // The call to SetAltitudeASL has most likely modified the geodetic latitude
713  // so we need to restore it to its initial value.
714  if (lastLatitudeSet == setgeod)
715  SetGeodLatitudeRadIC(geodLatitude);
716 
717  soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
718  rho = Atmosphere->GetDensity(altitudeASL);
719  pressure = Atmosphere->GetPressure(altitudeASL);
720 
721  switch(lastSpeedSet) {
722  case setvc:
723  mach0 = MachFromVcalibrated(vc0 * cos(alpha+PitotAngle) * cos(beta),
724  pressure, pressureSL, rhoSL);
725  SetVtrueFpsIC(mach0 * soundSpeed / (cos(alpha+PitotAngle) * cos(beta)));
726  break;
727  case setmach:
728  SetVtrueFpsIC(mach0 * soundSpeed);
729  break;
730  case setve:
731  SetVtrueFpsIC(ve0 * sqrt(rhoSL/rho));
732  break;
733  default: // Make the compiler stop complaining about missing enums
734  break;
735  }
736 
737  lastAltitudeSet = setasl;
738 }
739 
740 //******************************************************************************
741 
743 {
744  double h = ComputeGeodAltitude(geodLatitude);
745  double lon = position.GetLongitude();
746 
747  position.SetPositionGeodetic(lon, geodLatitude, h);
748  lastLatitudeSet = setgeod;
749 }
750 
751 //******************************************************************************
752 
754 {
755  double altitude;
756 
757  lastLatitudeSet = setgeoc;
758 
759  switch(lastAltitudeSet) {
760  case setagl:
761  altitude = GetAltitudeAGLFtIC();
762  position.SetLatitude(lat);
763  SetAltitudeAGLFtIC(altitude);
764  break;
765  default:
766  position.SetLatitude(lat);
767  break;
768  }
769 }
770 
771 //******************************************************************************
772 
774 {
775  double altitude;
776 
777  switch(lastAltitudeSet) {
778  case setagl:
779  altitude = GetAltitudeAGLFtIC();
780  position.SetLongitude(lon);
781  SetAltitudeAGLFtIC(altitude);
782  break;
783  default:
784  altitude = position.GetAltitudeASL();
785  position.SetLongitude(lon);
786  position.SetAltitudeASL(altitude);
787  break;
788  }
789 }
790 
791 //******************************************************************************
792 
794 {
795  const FGMatrix33& Tb2l = orientation.GetTInv();
796  FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
797  FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
798 
799  return _vWIND_NED(eV) == 0.0 ? 0.0
800  : atan2(_vWIND_NED(eV), _vWIND_NED(eU))*radtodeg;
801 }
802 
803 //******************************************************************************
804 
805 double FGInitialCondition::GetNEDWindFpsIC(int idx) const
806 {
807  const FGMatrix33& Tb2l = orientation.GetTInv();
808  FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
809  FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
810 
811  return _vWIND_NED(idx);
812 }
813 
814 //******************************************************************************
815 
817 {
818  const FGMatrix33& Tb2l = orientation.GetTInv();
819  FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
820  FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
821 
822  return _vWIND_NED.Magnitude(eU, eV);
823 }
824 
825 //******************************************************************************
826 
827 double FGInitialCondition::GetBodyWindFpsIC(int idx) const
828 {
829  const FGMatrix33& Tl2b = orientation.GetT();
830  FGColumnVector3 _vt_BODY = Tw2b * FGColumnVector3(vt, 0., 0.);
831  FGColumnVector3 _vUVW_BODY = Tl2b * vUVW_NED;
832  FGColumnVector3 _vWIND_BODY = _vt_BODY - _vUVW_BODY;
833 
834  return _vWIND_BODY(idx);
835 }
836 
837 //******************************************************************************
838 
840 {
841  double altitudeASL = position.GetAltitudeASL();
842  double pressure = Atmosphere->GetPressure(altitudeASL);
843  double pressureSL = Atmosphere->GetPressureSL();
844  double rhoSL = Atmosphere->GetDensitySL();
845  double soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
846  double PitotAngle = Aircraft->GetPitotAngle();
847  double mach = vt * cos(alpha+PitotAngle) * cos(beta) / soundSpeed;
848 
849  return fpstokts * VcalibratedFromMach(mach, pressure, pressureSL, rhoSL);
850 }
851 
852 //******************************************************************************
853 
855 {
856  double altitudeASL = position.GetAltitudeASL();
857  double rho = Atmosphere->GetDensity(altitudeASL);
858  double rhoSL = Atmosphere->GetDensitySL();
859  return fpstokts * vt * sqrt(rho/rhoSL);
860 }
861 
862 //******************************************************************************
863 
865 {
866  double altitudeASL = position.GetAltitudeASL();
867  double soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
868  return vt / soundSpeed;
869 }
870 
871 //******************************************************************************
872 
873 double FGInitialCondition::GetBodyVelFpsIC(int idx) const
874 {
875  const FGMatrix33& Tl2b = orientation.GetT();
876  FGColumnVector3 _vUVW_BODY = Tl2b * vUVW_NED;
877 
878  return _vUVW_BODY(idx);
879 }
880 
881 //******************************************************************************
882 
883 bool FGInitialCondition::Load(const SGPath& rstfile, bool useStoredPath)
884 {
885  SGPath init_file_name;
886  if(useStoredPath && rstfile.isRelative()) {
887  init_file_name = fdmex->GetFullAircraftPath()/rstfile.utf8Str();
888  } else {
889  init_file_name = rstfile;
890  }
891 
892  FGXMLFileRead XMLFileRead;
893  Element* document = XMLFileRead.LoadXMLDocument(init_file_name);
894 
895  // Make sure that the document is valid
896  if (!document) {
897  cerr << "File: " << init_file_name << " could not be read." << endl;
898  exit(-1);
899  }
900 
901  if (document->GetName() != string("initialize")) {
902  cerr << "File: " << init_file_name << " is not a reset file." << endl;
903  exit(-1);
904  }
905 
906  double version = HUGE_VAL;
907  bool result = false;
908 
909  if (document->HasAttribute("version"))
910  version = document->GetAttributeValueAsNumber("version");
911 
912  if (version == HUGE_VAL) {
913  result = Load_v1(document); // Default to the old version
914  } else if (version >= 3.0) {
915  cerr << "Only initialization file formats 1 and 2 are currently supported" << endl;
916  exit (-1);
917  } else if (version >= 2.0) {
918  result = Load_v2(document);
919  } else if (version >= 1.0) {
920  result = Load_v1(document);
921  }
922 
923  // Check to see if any engines are specified to be initialized in a running state
924  Element* running_elements = document->FindElement("running");
925  while (running_elements) {
926  enginesRunning |= 1 << int(running_elements->GetDataAsNumber());
927  running_elements = document->FindNextElement("running");
928  }
929 
930  return result;
931 }
932 
933 //******************************************************************************
934 // Given an altitude above the mean sea level (or a position radius which is the
935 // same) and a geodetic latitude, compute the geodetic altitude.
936 //
937 // TODO: extend the routine to the case where lastAltitudeSet is equal to
938 // setagl.
939 
940 double FGInitialCondition::ComputeGeodAltitude(double geodLatitude)
941 {
942  double R = position.GetRadius();
943  double slat = sin(geodLatitude);
944  double RN = a / sqrt(1.0 - e2*slat*slat);
945  double p1 = e2*RN*slat*slat;
946  double p2 = e2*e2*RN*RN*slat*slat-R*R;
947  return p1 + sqrt(p1*p1-p2) - RN;
948 }
949 
950 //******************************************************************************
951 
952 bool FGInitialCondition::LoadLatitude(Element* position_el)
953 {
954  Element* latitude_el = position_el->FindElement("latitude");
955 
956  if (latitude_el) {
957  double latitude = position_el->FindElementValueAsNumberConvertTo("latitude", "RAD");
958 
959  if (fabs(latitude) > 0.5*M_PI) {
960  string unit_type = latitude_el->GetAttributeValue("unit");
961  if (unit_type.empty()) unit_type="RAD";
962 
963  cerr << latitude_el->ReadFrom() << "The latitude value "
964  << latitude_el->GetDataAsNumber() << " " << unit_type
965  << " is outside the range [";
966  if (unit_type == "DEG")
967  cerr << "-90 DEG ; +90 DEG]" << endl;
968  else
969  cerr << "-PI/2 RAD; +PI/2 RAD]" << endl;
970 
971  return false;
972  }
973 
974  string lat_type = latitude_el->GetAttributeValue("type");
975 
976  if (lat_type == "geod" || lat_type == "geodetic")
977  SetGeodLatitudeRadIC(latitude);
978  else {
979  position.SetLatitude(latitude);
980  lastLatitudeSet = setgeoc;
981  }
982  }
983 
984  return true;
985 }
986 
987 //******************************************************************************
988 
989 bool FGInitialCondition::Load_v1(Element* document)
990 {
991  bool result = true;
992 
993  if (document->FindElement("longitude"))
994  SetLongitudeRadIC(document->FindElementValueAsNumberConvertTo("longitude", "RAD"));
995  if (document->FindElement("elevation"))
996  SetTerrainElevationFtIC(document->FindElementValueAsNumberConvertTo("elevation", "FT"));
997 
998  if (document->FindElement("altitude")) // This is feet above ground level
999  SetAltitudeAGLFtIC(document->FindElementValueAsNumberConvertTo("altitude", "FT"));
1000  else if (document->FindElement("altitudeAGL")) // This is feet above ground level
1001  SetAltitudeAGLFtIC(document->FindElementValueAsNumberConvertTo("altitudeAGL", "FT"));
1002  else if (document->FindElement("altitudeMSL")) // This is feet above sea level
1003  SetAltitudeASLFtIC(document->FindElementValueAsNumberConvertTo("altitudeMSL", "FT"));
1004 
1005  result = LoadLatitude(document);
1006 
1007  FGColumnVector3 vOrient = orientation.GetEuler();
1008 
1009  if (document->FindElement("phi"))
1010  vOrient(ePhi) = document->FindElementValueAsNumberConvertTo("phi", "RAD");
1011  if (document->FindElement("theta"))
1012  vOrient(eTht) = document->FindElementValueAsNumberConvertTo("theta", "RAD");
1013  if (document->FindElement("psi"))
1014  vOrient(ePsi) = document->FindElementValueAsNumberConvertTo("psi", "RAD");
1015 
1016  orientation = FGQuaternion(vOrient);
1017 
1018  if (document->FindElement("ubody"))
1019  SetUBodyFpsIC(document->FindElementValueAsNumberConvertTo("ubody", "FT/SEC"));
1020  if (document->FindElement("vbody"))
1021  SetVBodyFpsIC(document->FindElementValueAsNumberConvertTo("vbody", "FT/SEC"));
1022  if (document->FindElement("wbody"))
1023  SetWBodyFpsIC(document->FindElementValueAsNumberConvertTo("wbody", "FT/SEC"));
1024  if (document->FindElement("vnorth"))
1025  SetVNorthFpsIC(document->FindElementValueAsNumberConvertTo("vnorth", "FT/SEC"));
1026  if (document->FindElement("veast"))
1027  SetVEastFpsIC(document->FindElementValueAsNumberConvertTo("veast", "FT/SEC"));
1028  if (document->FindElement("vdown"))
1029  SetVDownFpsIC(document->FindElementValueAsNumberConvertTo("vdown", "FT/SEC"));
1030  if (document->FindElement("vc"))
1032  if (document->FindElement("vt"))
1033  SetVtrueKtsIC(document->FindElementValueAsNumberConvertTo("vt", "KTS"));
1034  if (document->FindElement("mach"))
1035  SetMachIC(document->FindElementValueAsNumber("mach"));
1036  if (document->FindElement("gamma"))
1038  if (document->FindElement("roc"))
1039  SetClimbRateFpsIC(document->FindElementValueAsNumberConvertTo("roc", "FT/SEC"));
1040  if (document->FindElement("vground"))
1041  SetVgroundKtsIC(document->FindElementValueAsNumberConvertTo("vground", "KTS"));
1042  if (document->FindElement("alpha"))
1043  SetAlphaDegIC(document->FindElementValueAsNumberConvertTo("alpha", "DEG"));
1044  if (document->FindElement("beta"))
1045  SetBetaDegIC(document->FindElementValueAsNumberConvertTo("beta", "DEG"));
1046  if (document->FindElement("vwind"))
1047  SetWindMagKtsIC(document->FindElementValueAsNumberConvertTo("vwind", "KTS"));
1048  if (document->FindElement("winddir"))
1049  SetWindDirDegIC(document->FindElementValueAsNumberConvertTo("winddir", "DEG"));
1050  if (document->FindElement("hwind"))
1051  SetHeadWindKtsIC(document->FindElementValueAsNumberConvertTo("hwind", "KTS"));
1052  if (document->FindElement("xwind"))
1053  SetCrossWindKtsIC(document->FindElementValueAsNumberConvertTo("xwind", "KTS"));
1054  if (document->FindElement("targetNlf"))
1055  SetTargetNlfIC(document->FindElementValueAsNumber("targetNlf"));
1056  if (document->FindElement("trim"))
1057  needTrim = document->FindElementValueAsNumber("trim");
1058 
1059  // Refer to Stevens and Lewis, 1.5-14a, pg. 49.
1060  // This is the rotation rate of the "Local" frame, expressed in the local frame.
1061  const FGMatrix33& Tl2b = orientation.GetT();
1062  double radInv = 1.0 / position.GetRadius();
1063  FGColumnVector3 vOmegaLocal = FGColumnVector3(
1064  radInv*vUVW_NED(eEast),
1065  -radInv*vUVW_NED(eNorth),
1066  -radInv*vUVW_NED(eEast)*position.GetTanLatitude() );
1067 
1068  vPQR_body = Tl2b * vOmegaLocal;
1069 
1070  return result;
1071 }
1072 
1073 //******************************************************************************
1074 
1075 bool FGInitialCondition::Load_v2(Element* document)
1076 {
1077  FGColumnVector3 vOrient;
1078  bool result = true;
1079 
1080  // support both earth_position_angle and planet_position_angle, for now.
1081  if (document->FindElement("earth_position_angle"))
1082  position.SetEarthPositionAngle(document->FindElementValueAsNumberConvertTo("earth_position_angle", "RAD"));
1083  if (document->FindElement("planet_position_angle"))
1084  position.SetEarthPositionAngle(document->FindElementValueAsNumberConvertTo("planet_position_angle", "RAD"));
1085 
1086  if (document->FindElement("planet_rotation_rate")) {
1087  fdmex->GetInertial()->SetOmegaPlanet(document->FindElementValueAsNumberConvertTo("planet_rotation_rate", "RAD"));
1088  fdmex->GetPropagate()->in.vOmegaPlanet = fdmex->GetInertial()->GetOmegaPlanet();
1089  fdmex->GetAccelerations()->in.vOmegaPlanet = fdmex->GetInertial()->GetOmegaPlanet();
1090  }
1091  FGColumnVector3 vOmegaEarth = fdmex->GetInertial()->GetOmegaPlanet();
1092 
1093  if (document->FindElement("elevation"))
1094  fdmex->GetGroundCallback()->SetTerrainGeoCentRadius(document->FindElementValueAsNumberConvertTo("elevation", "FT")+position.GetSeaLevelRadius());
1095 
1096  // Initialize vehicle position
1097  //
1098  // Allowable frames:
1099  // - ECI (Earth Centered Inertial)
1100  // - ECEF (Earth Centered, Earth Fixed)
1101 
1102  Element* position_el = document->FindElement("position");
1103  if (position_el) {
1104  string frame = position_el->GetAttributeValue("frame");
1105  frame = to_lower(frame);
1106  if (frame == "eci") { // Need to transform vLoc to ECEF for storage and use in FGLocation.
1107  position = position.GetTi2ec() * position_el->FindElementTripletConvertTo("FT");
1108  } else if (frame == "ecef") {
1109  if (!position_el->FindElement("x") && !position_el->FindElement("y") && !position_el->FindElement("z")) {
1110  if (position_el->FindElement("longitude"))
1111  position.SetLongitude(position_el->FindElementValueAsNumberConvertTo("longitude", "RAD"));
1112 
1113  if (position_el->FindElement("radius")) {
1114  position.SetRadius(position_el->FindElementValueAsNumberConvertTo("radius", "FT"));
1115  } else if (position_el->FindElement("altitudeAGL")) {
1116  position.SetAltitudeAGL(position_el->FindElementValueAsNumberConvertTo("altitudeAGL", "FT"));
1117  } else if (position_el->FindElement("altitudeMSL")) {
1118  position.SetAltitudeASL(position_el->FindElementValueAsNumberConvertTo("altitudeMSL", "FT"));
1119  } else {
1120  cerr << endl << " No altitude or radius initial condition is given." << endl;
1121  result = false;
1122  }
1123 
1124  result = LoadLatitude(position_el);
1125 
1126  } else {
1127  position = position_el->FindElementTripletConvertTo("FT");
1128  }
1129  } else {
1130  cerr << endl << " Neither ECI nor ECEF frame is specified for initial position." << endl;
1131  result = false;
1132  }
1133  } else {
1134  cerr << endl << " Initial position not specified in this initialization file." << endl;
1135  result = false;
1136  }
1137 
1138  // End of position initialization
1139 
1140  // Initialize vehicle orientation
1141  // Allowable frames
1142  // - ECI (Earth Centered Inertial)
1143  // - ECEF (Earth Centered, Earth Fixed)
1144  // - Local
1145  //
1146  // Need to convert the provided orientation to a local orientation, using
1147  // the given orientation and knowledge of the Earth position angle.
1148  // This could be done using matrices (where in the subscript "b/a",
1149  // it is meant "b with respect to a", and where b=body frame,
1150  // i=inertial frame, l=local NED frame and e=ecef frame) as:
1151  //
1152  // C_b/l = C_b/e * C_e/l
1153  //
1154  // Using quaternions (note reverse ordering compared to matrix representation):
1155  //
1156  // Q_b/l = Q_e/l * Q_b/e
1157  //
1158  // Use the specific matrices as needed. The above example of course is for the whole
1159  // body to local orientation.
1160  // The new orientation angles can be extracted from the matrix or the quaternion.
1161  // ToDo: Do we need to deal with normalization of the quaternions here?
1162 
1163  Element* orientation_el = document->FindElement("orientation");
1164  if (orientation_el) {
1165  string frame = orientation_el->GetAttributeValue("frame");
1166  frame = to_lower(frame);
1167  vOrient = orientation_el->FindElementTripletConvertTo("RAD");
1168  if (frame == "eci") {
1169 
1170  // In this case, we are supplying the Euler angles for the vehicle with
1171  // respect to the inertial system, represented by the C_b/i Matrix.
1172  // We want the body orientation with respect to the local (NED frame):
1173  //
1174  // C_b/l = C_b/i * C_i/l
1175  //
1176  // Or, using quaternions (note reverse ordering compared to matrix representation):
1177  //
1178  // Q_b/l = Q_i/l * Q_b/i
1179 
1180  FGQuaternion QuatI2Body = FGQuaternion(vOrient);
1181  QuatI2Body.Normalize();
1182  FGQuaternion QuatLocal2I = position.GetTl2i();
1183  QuatLocal2I.Normalize();
1184  orientation = QuatLocal2I * QuatI2Body;
1185 
1186  } else if (frame == "ecef") {
1187 
1188  // In this case we are given the Euler angles representing the orientation of
1189  // the body with respect to the ECEF system, represented by the C_b/e Matrix.
1190  // We want the body orientation with respect to the local (NED frame):
1191  //
1192  // C_b/l = C_b/e * C_e/l
1193  //
1194  // Using quaternions (note reverse ordering compared to matrix representation):
1195  //
1196  // Q_b/l = Q_e/l * Q_b/e
1197 
1198  FGQuaternion QuatEC2Body(vOrient); // Store relationship of Body frame wrt ECEF frame, Q_b/e
1199  QuatEC2Body.Normalize();
1200  FGQuaternion QuatLocal2EC = position.GetTl2ec(); // Get Q_e/l from matrix
1201  QuatLocal2EC.Normalize();
1202  orientation = QuatLocal2EC * QuatEC2Body; // Q_b/l = Q_e/l * Q_b/e
1203 
1204  } else if (frame == "local") {
1205 
1206  orientation = FGQuaternion(vOrient);
1207 
1208  } else {
1209 
1210  cerr << endl << fgred << " Orientation frame type: \"" << frame
1211  << "\" is not supported!" << reset << endl << endl;
1212  result = false;
1213 
1214  }
1215  }
1216 
1217  // Initialize vehicle velocity
1218  // Allowable frames
1219  // - ECI (Earth Centered Inertial)
1220  // - ECEF (Earth Centered, Earth Fixed)
1221  // - Local
1222  // - Body
1223  // The vehicle will be defaulted to (0,0,0) in the Body frame if nothing is provided.
1224 
1225  Element* velocity_el = document->FindElement("velocity");
1226  FGColumnVector3 vInitVelocity = FGColumnVector3(0.0, 0.0, 0.0);
1227  FGMatrix33 mTec2l = position.GetTec2l();
1228  const FGMatrix33& Tb2l = orientation.GetTInv();
1229 
1230  if (velocity_el) {
1231 
1232  string frame = velocity_el->GetAttributeValue("frame");
1233  frame = to_lower(frame);
1234  FGColumnVector3 vInitVelocity = velocity_el->FindElementTripletConvertTo("FT/SEC");
1235 
1236  if (frame == "eci") {
1237  FGColumnVector3 omega_cross_r = vOmegaEarth * (position.GetTec2i() * position);
1238  vUVW_NED = mTec2l * (vInitVelocity - omega_cross_r);
1239  lastSpeedSet = setned;
1240  } else if (frame == "ecef") {
1241  vUVW_NED = mTec2l * vInitVelocity;
1242  lastSpeedSet = setned;
1243  } else if (frame == "local") {
1244  vUVW_NED = vInitVelocity;
1245  lastSpeedSet = setned;
1246  } else if (frame == "body") {
1247  vUVW_NED = Tb2l * vInitVelocity;
1248  lastSpeedSet = setuvw;
1249  } else {
1250 
1251  cerr << endl << fgred << " Velocity frame type: \"" << frame
1252  << "\" is not supported!" << reset << endl << endl;
1253  result = false;
1254 
1255  }
1256 
1257  } else {
1258 
1259  vUVW_NED = Tb2l * vInitVelocity;
1260 
1261  }
1262 
1263  vt = vUVW_NED.Magnitude();
1264 
1265  calcAeroAngles(vUVW_NED);
1266 
1267  // Initialize vehicle body rates
1268  // Allowable frames
1269  // - ECI (Earth Centered Inertial)
1270  // - ECEF (Earth Centered, Earth Fixed)
1271  // - Body
1272 
1273  Element* attrate_el = document->FindElement("attitude_rate");
1274  const FGMatrix33& Tl2b = orientation.GetT();
1275 
1276  // Refer to Stevens and Lewis, 1.5-14a, pg. 49.
1277  // This is the rotation rate of the "Local" frame, expressed in the local frame.
1278  double radInv = 1.0 / position.GetRadius();
1279  FGColumnVector3 vOmegaLocal = FGColumnVector3(
1280  radInv*vUVW_NED(eEast),
1281  -radInv*vUVW_NED(eNorth),
1282  -radInv*vUVW_NED(eEast)*position.GetTanLatitude() );
1283 
1284  if (attrate_el) {
1285 
1286  string frame = attrate_el->GetAttributeValue("frame");
1287  frame = to_lower(frame);
1288  FGColumnVector3 vAttRate = attrate_el->FindElementTripletConvertTo("RAD/SEC");
1289 
1290  if (frame == "eci") {
1291  vPQR_body = Tl2b * position.GetTi2l() * (vAttRate - vOmegaEarth);
1292  } else if (frame == "ecef") {
1293  vPQR_body = Tl2b * position.GetTec2l() * vAttRate;
1294  } else if (frame == "local") {
1295  vPQR_body = Tl2b * (vAttRate + vOmegaLocal);
1296  } else if (frame == "body") {
1297  vPQR_body = vAttRate;
1298  } else if (!frame.empty()) { // misspelling of frame
1299 
1300  cerr << endl << fgred << " Attitude rate frame type: \"" << frame
1301  << "\" is not supported!" << reset << endl << endl;
1302  result = false;
1303 
1304  } else if (frame.empty()) {
1305  vPQR_body = Tl2b * vOmegaLocal;
1306  }
1307 
1308  } else { // Body frame attitude rate assumed 0 relative to local.
1309  vPQR_body = Tl2b * vOmegaLocal;
1310  }
1311 
1312  return result;
1313 }
1314 
1315 //******************************************************************************
1316 
1317 void FGInitialCondition::bind(FGPropertyManager* PropertyManager)
1318 {
1319  PropertyManager->Tie("ic/vc-kts", this,
1322  true);
1323  PropertyManager->Tie("ic/ve-kts", this,
1326  true);
1327  PropertyManager->Tie("ic/vg-kts", this,
1330  true);
1331  PropertyManager->Tie("ic/vt-kts", this,
1334  true);
1335  PropertyManager->Tie("ic/mach", this,
1338  true);
1339  PropertyManager->Tie("ic/roc-fpm", this,
1342  true);
1343  PropertyManager->Tie("ic/gamma-deg", this,
1346  true);
1347  PropertyManager->Tie("ic/alpha-deg", this,
1350  true);
1351  PropertyManager->Tie("ic/beta-deg", this,
1354  true);
1355  PropertyManager->Tie("ic/theta-deg", this,
1358  true);
1359  PropertyManager->Tie("ic/phi-deg", this,
1362  true);
1363  PropertyManager->Tie("ic/psi-true-deg", this,
1366  true);
1367  PropertyManager->Tie("ic/lat-gc-deg", this,
1370  true);
1371  PropertyManager->Tie("ic/long-gc-deg", this,
1374  true);
1375  PropertyManager->Tie("ic/h-sl-ft", this,
1378  true);
1379  PropertyManager->Tie("ic/h-agl-ft", this,
1382  true);
1383  PropertyManager->Tie("ic/terrain-elevation-ft", this,
1386  true);
1387  PropertyManager->Tie("ic/vg-fps", this,
1390  true);
1391  PropertyManager->Tie("ic/vt-fps", this,
1394  true);
1395  PropertyManager->Tie("ic/vw-bx-fps", this,
1397  PropertyManager->Tie("ic/vw-by-fps", this,
1399  PropertyManager->Tie("ic/vw-bz-fps", this,
1401  PropertyManager->Tie("ic/vw-north-fps", this,
1403  PropertyManager->Tie("ic/vw-east-fps", this,
1405  PropertyManager->Tie("ic/vw-down-fps", this,
1407  PropertyManager->Tie("ic/vw-mag-fps", this,
1409  PropertyManager->Tie("ic/vw-dir-deg", this,
1412  true);
1413 
1414  PropertyManager->Tie("ic/roc-fps", this,
1417  true);
1418  PropertyManager->Tie("ic/u-fps", this,
1421  true);
1422  PropertyManager->Tie("ic/v-fps", this,
1425  true);
1426  PropertyManager->Tie("ic/w-fps", this,
1429  true);
1430  PropertyManager->Tie("ic/vn-fps", this,
1433  true);
1434  PropertyManager->Tie("ic/ve-fps", this,
1437  true);
1438  PropertyManager->Tie("ic/vd-fps", this,
1441  true);
1442  PropertyManager->Tie("ic/gamma-rad", this,
1445  true);
1446  PropertyManager->Tie("ic/alpha-rad", this,
1449  true);
1450  PropertyManager->Tie("ic/theta-rad", this,
1453  true);
1454  PropertyManager->Tie("ic/beta-rad", this,
1457  true);
1458  PropertyManager->Tie("ic/phi-rad", this,
1461  true);
1462  PropertyManager->Tie("ic/psi-true-rad", this,
1465  true);
1466  PropertyManager->Tie("ic/lat-gc-rad", this,
1469  true);
1470  PropertyManager->Tie("ic/long-gc-rad", this,
1473  true);
1474  PropertyManager->Tie("ic/p-rad_sec", this,
1477  true);
1478  PropertyManager->Tie("ic/q-rad_sec", this,
1481  true);
1482  PropertyManager->Tie("ic/r-rad_sec", this,
1485  true);
1486  PropertyManager->Tie("ic/lat-geod-rad", this,
1489  true);
1490  PropertyManager->Tie("ic/lat-geod-deg", this,
1493  true);
1494  PropertyManager->Tie("ic/geod-alt-ft", &position,
1496 }
1497 
1498 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1499 // The bitmasked value choices are as follows:
1500 // unset: In this case (the default) JSBSim would only print
1501 // out the normally expected messages, essentially echoing
1502 // the config files as they are read. If the environment
1503 // variable is not set, debug_lvl is set to 1 internally
1504 // 0: This requests JSBSim not to output any messages
1505 // whatsoever.
1506 // 1: This value explicity requests the normal JSBSim
1507 // startup messages
1508 // 2: This value asks for a message to be printed out when
1509 // a class is instantiated
1510 // 4: When this value is set, a message is displayed when a
1511 // FGModel object executes its Run() method
1512 // 8: When this value is set, various runtime state variables
1513 // are printed out periodically
1514 // 16: When set various parameters are sanity checked and
1515 // a message is printed out when they go out of bounds
1516 
1517 void FGInitialCondition::Debug(int from)
1518 {
1519  if (debug_lvl <= 0) return;
1520 
1521  if (debug_lvl & 1) { // Standard console startup message output
1522  }
1523  if (debug_lvl & 2 ) { // Instantiation/Destruction notification
1524  if (from == 0) cout << "Instantiated: FGInitialCondition" << endl;
1525  if (from == 1) cout << "Destroyed: FGInitialCondition" << endl;
1526  }
1527  if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
1528  }
1529  if (debug_lvl & 8 ) { // Runtime state variables
1530  }
1531  if (debug_lvl & 16) { // Sanity checking
1532  }
1533  if (debug_lvl & 64) {
1534  if (from == 0) { // Constructor
1535  cout << IdSrc << endl;
1536  cout << IdHdr << endl;
1537  }
1538  }
1539 }
1540 }
double GetAlphaDegIC(void) const
Gets the initial angle of attack.
double GetLatitudeRadIC(void) const
Gets the initial latitude.
void SetThetaDegIC(double theta)
Sets pitch angle initial condition in degrees.
FGAccelerations * GetAccelerations(void)
Returns the FGAccelerations pointer.
Definition: FGFDMExec.h:347
void SetThetaRadIC(double theta)
Sets the initial pitch angle.
void SetVEastFpsIC(double ve)
Sets the initial local axis east velocity.
double GetThetaDegIC(void) const
Gets the initial pitch angle.
Models the Quaternion representation of rotations.
Definition: FGQuaternion.h:92
double GetGeodLatitudeRadIC(void) const
Gets the initial geodetic latitude.
double GetVgroundFpsIC(void) const
Gets the initial ground velocity.
double GetBetaRadIC(void) const
Gets the initial angle of sideslip.
double GetVtrueFpsIC(void) const
Gets the initial true velocity.
FGInertial * GetInertial(void)
Returns the FGInertial pointer.
Definition: FGFDMExec.h:359
double GetFlightPathAngleRadIC(void) const
Gets the initial flight path angle.
double GetVDownFpsIC(void) const
Gets the initial local frame Z (Down) velocity.
void SetVtrueFpsIC(double vt)
Sets the initial true airspeed.
const FGMatrix33 & GetT(void) const
Transformation matrix.
Definition: FGQuaternion.h:194
void SetLongitude(double longitude)
Set the longitude.
Definition: FGLocation.cpp:197
void SetLatitudeRadIC(double lat)
Sets the initial latitude.
double GetLongitudeDegIC(void) const
Gets the initial longitude.
double GetSeaLevelRadius(void) const
Get the local sea level radius.
Definition: FGLocation.h:347
std::string GetAttributeValue(const std::string &key)
Retrieves an attribute.
double GetVtrueKtsIC(void) const
Gets the initial true velocity.
void SetVNorthFpsIC(double vn)
Sets the initial local axis north velocity.
double GetBetaDegIC(void) const
Gets the initial sideslip angle.
void SetLatitude(double latitude)
Set the latitude.
Definition: FGLocation.cpp:217
double GetRRadpsIC() const
Gets the initial body axis yaw rate.
double GetSinEuler(int i) const
Retrieves sine of the given euler angle.
Definition: FGQuaternion.h:243
void SetSeaLevelRadiusFtIC(double slr)
Sets the initial sea level radius from planet center.
double GetAltitudeASL(void) const
Get the altitude above sea level.
Definition: FGLocation.h:359
double GetTerrainElevationFtIC(void) const
Gets the initial terrain elevation.
void SetAltitudeAGL(double altitudeAGL)
Set the altitude above ground level.
Definition: FGLocation.h:341
double GetVequivalentKtsIC(void) const
Gets the initial equivalent airspeed.
void SetRadius(double radius)
Set the distance from the center of the earth.
Definition: FGLocation.cpp:241
double GetGeodAltitude(void) const
Gets the geodetic altitude in feet.
Definition: FGLocation.h:293
double GetAltitudeAGLFtIC(void) const
Gets the initial altitude above ground level.
void SetPhiRadIC(double phi)
Sets the initial roll angle.
bool HasAttribute(const std::string &key)
Determines if an element has the supplied attribute.
Definition: FGXMLElement.h:162
void SetBetaDegIC(double b)
Sets angle of sideslip initial condition in degrees.
double GetPhiRadIC(void) const
Gets the initial roll angle.
double FindElementValueAsNumberConvertTo(const std::string &el, const std::string &target_units)
Searches for the named element and converts and returns the data belonging to it. ...
const SGPath & GetFullAircraftPath(void)
Retrieves the full aircraft path name.
Definition: FGFDMExec.h:397
double GetUBodyFpsIC(void) const
Gets the initial body axis X velocity.
double GetVgroundKtsIC(void) const
Gets the initial ground speed.
void SetClimbRateFpsIC(double roc)
Sets the initial climb rate.
const FGMatrix33 & GetTInv(void) const
Backward transformation matrix.
Definition: FGQuaternion.h:199
static char reset[5]
resets text properties
Definition: FGJSBBase.h:131
void SetClimbRateFpmIC(double roc)
Sets the climb rate initial condition in feet/minute.
void SetWindDownKtsIC(double wD)
Sets the initial wind downward speed.
STL namespace.
virtual void SetSeaLevelRadius(double radius)
Set the sea level radius.
double GetQRadpsIC() const
Gets the initial body axis pitch rate.
double GetVBodyFpsIC(void) const
Gets the initial body axis Y velocity.
void SetQRadpsIC(double Q)
Sets the initial body axis pitch rate.
FGColumnVector3 & Normalize(void)
Normalize.
virtual double GetPressure(void) const
Returns the pressure in psf.
Definition: FGAtmosphere.h:152
Element * FindElement(const std::string &el="")
Searches for a specified element.
double FindElementValueAsNumber(const std::string &el="")
Searches for the named element and returns the data belonging to it as a number.
void SetFlightPathAngleDegIC(double gamma)
Sets the flight path angle initial condition in degrees.
void ResetIC(double u0, double v0, double w0, double p0, double q0, double r0, double alpha0, double beta0, double phi0, double theta0, double psi0, double latitudeRad0, double longitudeRad0, double altitudeAGL0, double gamma0)
Resets the IC data structure to new values.
void SetUBodyFpsIC(double ubody)
Sets the initial body axis X velocity.
void SetWindDirDegIC(double dir)
Sets the initial wind direction.
void SetVequivalentKtsIC(double ve)
Set equivalent airspeed initial condition in knots.
void SetGeodLatitudeRadIC(double glat)
Sets the initial geodetic latitude.
void SetWindNEDFpsIC(double wN, double wE, double wD)
Sets the initial wind velocity.
double GetLongitudeRadIC(void) const
Gets the initial longitude.
void SetPositionGeodetic(double lon, double lat, double height)
Sets the longitude, latitude and the distance above the reference ellipsoid.
Definition: FGLocation.cpp:270
void SetTerrainElevationFtIC(double elev)
Sets the initial terrain elevation.
FGColumnVector3 vOmegaPlanet
Earth rotating vector (expressed in the ECI frame).
void SetEarthPositionAngle(double EPA)
Sets the Earth position angle.
Definition: FGLocation.h:241
void SetFlightPathAngleRadIC(double gamma)
Sets the initial flight path angle.
void SetGeodLatitudeDegIC(double glat)
Sets the initial geodetic latitude.
double GetWindNFpsIC(void) const
Gets the initial wind velocity in local frame.
double GetPRadpsIC() const
Gets the initial body axis roll rate.
double GetRadius() const
Get the distance from the center of the earth.
Definition: FGLocation.h:323
void SetEllipse(double semimajor, double semiminor)
Sets the semimajor and semiminor axis lengths for this planet.
Definition: FGLocation.cpp:285
static char fgred[6]
red text
Definition: FGJSBBase.h:141
void SetWindMagKtsIC(double mag)
Sets the initial total wind speed.
double GetVcalibratedKtsIC(void) const
Gets the initial calibrated airspeed.
static double VcalibratedFromMach(double mach, double p, double psl, double rhosl)
Calculate the calibrated airspeed from the Mach number.
Definition: FGJSBBase.cpp:305
const FGMatrix33 & GetTi2ec(void) const
Transform matrix from inertial to earth centered frame.
Definition: FGLocation.h:421
void SetHeadWindKtsIC(double head)
Sets the initial headwind velocity.
double GetLongitude() const
Get the longitude.
Definition: FGLocation.h:254
void Tie(const std::string &name, bool *pointer, bool useDefault=true)
Tie a property to an external bool variable.
void SetRRadpsIC(double R)
Sets the initial body axis yaw rate.
static double MachFromVcalibrated(double vcas, double p, double psl, double rhosl)
Calculate the Mach number from the calibrated airspeed.
Definition: FGJSBBase.cpp:315
void SetAltitudeASL(double altitudeASL)
Set the altitude above sea level.
Definition: FGLocation.h:335
double GetWindDirDegIC(void) const
Gets the initial wind direction.
void SetVgroundFpsIC(double vg)
Sets the initial ground speed.
void SetLatitudeDegIC(double lat)
Sets the initial latitude.
double GetFlightPathAngleDegIC(void) const
Gets the initial flight path angle.
double GetTanLatitude() const
Get the cosine of Latitude.
Definition: FGLocation.h:302
double GetGeodLatitudeDegIC(void) const
Gets the initial geodetic latitude.
double GetDataAsNumber(void)
Converts the element data to a number.
virtual double GetDensitySL(void) const
Returns the sea level density in slugs/ft^3.
Definition: FGAtmosphere.h:181
void SetVBodyFpsIC(double vbody)
Sets the initial body axis Y velocity.
double GetPsiDegIC(void) const
Gets the initial heading angle.
void SetVgroundKtsIC(double vg)
Set ground speed initial condition in knots.
void SetTargetNlfIC(double nlf)
Sets the target normal load factor.
FGAircraft * GetAircraft(void)
Returns the FGAircraft pointer.
Definition: FGFDMExec.h:367
double GetAttributeValueAsNumber(const std::string &key)
Retrieves an attribute value as a double precision real number.
virtual double GetSoundSpeed(void) const
Returns the speed of sound in ft/sec.
Definition: FGAtmosphere.h:191
const std::string & GetName(void) const
Retrieves the element name.
Definition: FGXMLElement.h:186
double GetWindEFpsIC(void) const
Gets the initial wind velocity in local frame.
double GetPsiRadIC(void) const
Gets the initial heading angle.
void SetVcalibratedKtsIC(double vc)
Set calibrated airspeed initial condition in knots.
void SetVtrueKtsIC(double vtrue)
Set true airspeed initial condition in knots.
double GetVEastFpsIC(void) const
Gets the initial local frame Y (East) velocity.
double GetWindUFpsIC(void) const
Gets the initial body axis X wind velocity.
void SetLongitudeDegIC(double lon)
Sets the initial longitude.
double GetTerrainRadius(void) const
Get the local terrain radius.
Definition: FGLocation.h:353
bool Load(const SGPath &rstname, bool useStoredPath=true)
Loads the initial conditions.
double GetPhiDegIC(void) const
Gets the initial roll angle.
const FGMatrix33 & GetTl2i(void) const
Transform matrix from local horizontal to inertial frame.
Definition: FGLocation.h:442
FGGroundCallback * GetGroundCallback(void)
Get a pointer to the ground callback currently used.
Definition: FGFDMExec.h:381
void SetAltitudeAGLFtIC(double agl)
Sets the initial Altitude above ground level.
void SetPhiDegIC(double phi)
Sets the roll angle initial condition in degrees.
This class implements a 3 element column vector.
void SetAlphaDegIC(double a)
Sets angle of attack initial condition in degrees.
virtual double GetDensity(void) const
Returns the density in slugs/ft^3.
Definition: FGAtmosphere.h:175
void SetVDownFpsIC(double vd)
Sets the initial local axis down velocity.
void SetCrossWindKtsIC(double cross)
Sets the initial crosswind speed.
double GetGeodLatitudeRad(void) const
Get the geodetic latitude.
Definition: FGLocation.h:278
double GetWindDFpsIC(void) const
Gets the initial wind velocity in local frame.
std::string ReadFrom(void) const
Return a string that contains a description of the location where the current XML element was read fr...
void SetAlphaRadIC(double alpha)
Sets the initial angle of attack.
const FGMatrix33 & GetTec2l(void) const
Transform matrix from the earth centered to local horizontal frame.
Definition: FGLocation.h:414
void SetPsiDegIC(double psi)
Sets the heading angle initial condition in degrees.
double GetVNorthFpsIC(void) const
Gets the initial local frame X (North) velocity.
Element * FindNextElement(const std::string &el="")
Searches for the next element as specified.
double GetAlphaRadIC(void) const
Gets the initial angle of attack.
double GetLatitudeDegIC(void) const
Gets the initial latitude.
double GetCosEuler(int i) const
Retrieves cosine of the given euler angle.
Definition: FGQuaternion.h:251
Handles matrix math operations.
Definition: FGMatrix33.h:92
FGMatrix33 Transposed(void) const
Transposed matrix.
Definition: FGMatrix33.h:243
double GetWindVFpsIC(void) const
Gets the initial body axis Y wind velocity.
double Magnitude(void) const
Length of the vector.
void InitMatrix(void)
Initialize the matrix.
Definition: FGMatrix33.cpp:257
void Normalize(void)
Normalize.
const FGColumnVector3 & GetEuler(void) const
Retrieves the Euler angles.
Definition: FGQuaternion.h:205
double GetWindWFpsIC(void) const
Gets the initial body axis Z wind velocity.
double GetMachIC(void) const
Gets the initial mach.
void SetPRadpsIC(double P)
Sets the initial body axis roll rate.
void SetWBodyFpsIC(double wbody)
Sets the initial body axis Z velocity.
void SetLongitudeRadIC(double lon)
Sets the initial longitude.
double GetClimbRateFpmIC(void) const
Gets the initial climb rate.
const FGMatrix33 & GetTec2i(void) const
Transform matrix from the earth centered to inertial frame.
Definition: FGLocation.h:428
double GetThetaRadIC(void) const
Gets the initial pitch angle.
const FGMatrix33 & GetTl2ec(void) const
Transform matrix from local horizontal to earth centered frame.
Definition: FGLocation.h:409
double GetWBodyFpsIC(void) const
Gets the initial body axis Z velocity.
Encapsulates the JSBSim simulation executive.
Definition: FGFDMExec.h:189
const FGMatrix33 & GetTi2l(void) const
Transform matrix from the inertial to local horizontal frame.
Definition: FGLocation.h:435
void SetBetaRadIC(double beta)
Sets the initial sideslip angle.
double GetWindFpsIC(void) const
Gets the initial total wind velocity in feet/sec.
void SetMachIC(double mach)
Set mach initial condition.
void SetAltitudeASLFtIC(double altitudeASL)
Sets the altitude above sea level initial condition in feet.
void SetPsiRadIC(double psi)
Sets the initial heading angle.
FGColumnVector3 FindElementTripletConvertTo(const std::string &target_units)
Composes a 3-element column vector for the supplied location or orientation.
double GetAltitudeASLFtIC(void) const
Gets the initial altitude above sea level.
double GetClimbRateFpsIC(void) const
Gets the initial climb rate.
FGPropagate * GetPropagate(void)
Returns the FGPropagate pointer.
Definition: FGFDMExec.h:369
double GetAltitudeAGL(void) const
Get the altitude above ground level.
Definition: FGLocation.h:365
virtual void SetTerrainGeoCentRadius(double radius)
Set the local terrain radius.