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