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