1 /*******************************************************************************
3 Header: FGInitialCondition.cpp
4 Author: Tony Peden, Bertrand Coconnier
7 ------------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) -------------
9 This program is free software; you can redistribute it and/or modify it under
10 the terms of the GNU Lesser General Public License as published by the Free Software
11 Foundation; either version 2 of the License, or (at your option) any later
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
19 You should have received a copy of the GNU Lesser General Public License along with
20 this program; if not, write to the Free Software Foundation, Inc., 59 Temple
21 Place - Suite 330, Boston, MA 02111-1307, USA.
23 Further information about the GNU Lesser General Public License can also be found on
24 the world wide web at http://www.gnu.org.
28 --------------------------------------------------------------------------------
30 11/25/10 BC Complete revision - Use minimal set of variables to prevent
31 inconsistent states. Wind is correctly handled.
34 FUNCTIONAL DESCRIPTION
35 --------------------------------------------------------------------------------
37 The purpose of this class is to take a set of initial conditions and provide
38 a kinematically consistent set of body axis velocity components, euler
39 angles, and altitude. This class does not attempt to trim the model i.e.
40 the sim will most likely start in a very dynamic state (unless, of course,
41 you have chosen your IC's wisely) even after setting it up with this class.
43 ********************************************************************************
45 *******************************************************************************/
47 #include "FGInitialCondition.h"
48 #include "FGFDMExec.h"
49 #include "math/FGQuaternion.h"
50 #include "models/FGInertial.h"
51 #include "models/FGAtmosphere.h"
52 #include "models/FGPropagate.h"
53 #include "models/FGPropulsion.h"
54 #include "input_output/FGPropertyManager.h"
55 #include "input_output/string_utilities.h"
64 static const char *IdSrc = "$Id: FGInitialCondition.cpp,v 1.59 2011/04/03 13:18:51 bcoconni Exp $";
65 static const char *IdHdr = ID_INITIALCONDITION;
67 //******************************************************************************
69 FGInitialCondition::FGInitialCondition(FGFDMExec *FDMExec) : fdmex(FDMExec)
73 if(FDMExec != NULL ) {
74 PropertyManager=fdmex->GetPropertyManager();
79 cout << "FGInitialCondition: This class requires a pointer to a valid FGFDMExec object" << endl;
85 //******************************************************************************
87 FGInitialCondition::~FGInitialCondition()
92 //******************************************************************************
94 void FGInitialCondition::ResetIC(double u0, double v0, double w0,
95 double p0, double q0, double r0,
96 double alpha0, double beta0,
97 double phi0, double theta0, double psi0,
98 double latRad0, double lonRad0, double altAGLFt0,
101 double calpha = cos(alpha0), cbeta = cos(beta0);
102 double salpha = sin(alpha0), sbeta = sin(beta0);
106 p = p0; q = q0; r = r0;
107 alpha = alpha0; beta = beta0;
108 phi = phi0; theta = theta0; psi = psi0;
110 position.SetPosition(lonRad0, latRad0, altAGLFt0 + terrain_elevation + sea_level_radius);
112 FGQuaternion Quat(phi, theta, psi);
115 Tb2l = Quat.GetTInv();
117 vUVW_NED = Tb2l * FGColumnVector3(u0, v0, w0);
118 vt = vUVW_NED.Magnitude();
120 Tw2b = FGMatrix33(calpha*cbeta, -calpha*sbeta, -salpha,
122 salpha*cbeta, -salpha*sbeta, calpha);
123 Tb2w = Tw2b.Transposed();
125 SetFlightPathAngleRadIC(gamma0);
128 //******************************************************************************
130 void FGInitialCondition::InitializeIC(void)
134 terrain_elevation = 0;
135 sea_level_radius = fdmex->GetInertial()->GetRefRadius();
136 position.SetPosition(0., 0., sea_level_radius);
137 position.SetEarthPositionAngle(fdmex->GetInertial()->GetEarthPositionAngle());
138 vUVW_NED.InitMatrix();
144 Tw2b.InitMatrix(1., 0., 0., 0., 1., 0., 0., 0., 1.);
145 Tb2w.InitMatrix(1., 0., 0., 0., 1., 0., 0., 0., 1.);
146 Tl2b.InitMatrix(1., 0., 0., 0., 1., 0., 0., 0., 1.);
147 Tb2l.InitMatrix(1., 0., 0., 0., 1., 0., 0., 0., 1.);
150 //******************************************************************************
152 void FGInitialCondition::WriteStateFile(int num)
154 if (Constructing) return;
156 string filename = fdmex->GetFullAircraftPath();
158 if (filename.empty())
159 filename = "initfile.xml";
161 filename.append("/initfile.xml");
163 ofstream outfile(filename.c_str());
164 FGPropagate* Propagate = fdmex->GetPropagate();
166 if (outfile.is_open()) {
167 outfile << "<?xml version=\"1.0\"?>" << endl;
168 outfile << "<initialize name=\"reset00\">" << endl;
169 outfile << " <ubody unit=\"FT/SEC\"> " << Propagate->GetUVW(eX) << " </ubody> " << endl;
170 outfile << " <vbody unit=\"FT/SEC\"> " << Propagate->GetUVW(eY) << " </vbody> " << endl;
171 outfile << " <wbody unit=\"FT/SEC\"> " << Propagate->GetUVW(eZ) << " </wbody> " << endl;
172 outfile << " <phi unit=\"DEG\"> " << Propagate->GetEuler(ePhi) << " </phi>" << endl;
173 outfile << " <theta unit=\"DEG\"> " << Propagate->GetEuler(eTht) << " </theta>" << endl;
174 outfile << " <psi unit=\"DEG\"> " << Propagate->GetEuler(ePsi) << " </psi>" << endl;
175 outfile << " <longitude unit=\"DEG\"> " << Propagate->GetLongitudeDeg() << " </longitude>" << endl;
176 outfile << " <latitude unit=\"DEG\"> " << Propagate->GetLatitudeDeg() << " </latitude>" << endl;
177 outfile << " <altitude unit=\"FT\"> " << Propagate->GetDistanceAGL() << " </altitude>" << endl;
178 outfile << "</initialize>" << endl;
181 cerr << "Could not open and/or write the state to the initial conditions file: " << filename << endl;
185 //******************************************************************************
187 void FGInitialCondition::SetVequivalentKtsIC(double ve)
189 double altitudeASL = position.GetRadius() - sea_level_radius;
190 double rho = fdmex->GetAtmosphere()->GetDensity(altitudeASL);
191 double rhoSL = fdmex->GetAtmosphere()->GetDensitySL();
192 SetVtrueFpsIC(ve*ktstofps/sqrt(rho/rhoSL));
193 lastSpeedSet = setve;
196 //******************************************************************************
198 void FGInitialCondition::SetMachIC(double mach)
200 double altitudeASL = position.GetRadius() - sea_level_radius;
201 double temperature = fdmex->GetAtmosphere()->GetTemperature(altitudeASL);
202 double soundSpeed = sqrt(SHRatio*Reng*temperature);
203 SetVtrueFpsIC(mach*soundSpeed);
204 lastSpeedSet = setmach;
207 //******************************************************************************
209 void FGInitialCondition::SetVcalibratedKtsIC(double vcas)
211 double altitudeASL = position.GetRadius() - sea_level_radius;
212 double mach = getMachFromVcas(fabs(vcas)*ktstofps);
213 double temperature = fdmex->GetAtmosphere()->GetTemperature(altitudeASL);
214 double soundSpeed = sqrt(SHRatio*Reng*temperature);
216 SetVtrueFpsIC(mach*soundSpeed);
217 lastSpeedSet = setvc;
220 //******************************************************************************
221 // Updates alpha and beta according to the aircraft true airspeed in the local
224 void FGInitialCondition::calcAeroAngles(const FGColumnVector3& _vt_NED)
226 FGColumnVector3 _vt_BODY = Tl2b * _vt_NED;
227 double ua = _vt_BODY(eX);
228 double va = _vt_BODY(eY);
229 double wa = _vt_BODY(eZ);
230 double uwa = sqrt(ua*ua + wa*wa);
231 double calpha, cbeta;
232 double salpha, sbeta;
235 calpha = cbeta = 1.0;
236 salpha = sbeta = 0.0;
239 alpha = atan2( wa, ua );
241 // alpha cannot be constrained without updating other informations like the
242 // true speed or the Euler angles. Otherwise we might end up with an inconsistent
243 // state of the aircraft.
244 /*alpha = Constrain(fdmex->GetAerodynamics()->GetAlphaCLMin(), alpha,
245 fdmex->GetAerodynamics()->GetAlphaCLMax());*/
248 beta = atan2( va, uwa );
260 Tw2b = FGMatrix33(calpha*cbeta, -calpha*sbeta, -salpha,
262 salpha*cbeta, -salpha*sbeta, calpha);
263 Tb2w = Tw2b.Transposed();
266 //******************************************************************************
267 // Set the ground velocity. Caution it sets the vertical velocity to zero to
268 // keep backward compatibility.
270 void FGInitialCondition::SetVgroundFpsIC(double vg)
272 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
273 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
275 vUVW_NED(eU) = vg*cos(psi);
276 vUVW_NED(eV) = vg*sin(psi);
278 _vt_NED = vUVW_NED + _vWIND_NED;
279 vt = _vt_NED.Magnitude();
281 calcAeroAngles(_vt_NED);
283 lastSpeedSet = setvg;
286 //******************************************************************************
287 // Sets the true airspeed. The amplitude of the airspeed is modified but its
288 // direction is kept unchanged. If there is no wind, the same is true for the
289 // ground velocity. If there is some wind, the airspeed direction is unchanged
290 // but this may result in the ground velocity direction being altered. This is
291 // for backward compatibility.
293 void FGInitialCondition::SetVtrueFpsIC(double vtrue)
295 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
296 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
299 _vt_NED *= vtrue / vt;
301 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vtrue, 0., 0.);
304 vUVW_NED = _vt_NED - _vWIND_NED;
306 calcAeroAngles(_vt_NED);
308 lastSpeedSet = setvt;
311 //******************************************************************************
312 // When the climb rate is modified, we need to update the angles theta and beta
313 // to keep the true airspeed amplitude, the AoA and the heading unchanged.
314 // Beta will be modified if the aircraft roll angle is not null.
316 void FGInitialCondition::SetClimbRateFpsIC(double hdot)
318 if (fabs(hdot) > vt) {
319 cerr << "The climb rate cannot be higher than the true speed." << endl;
323 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
324 FGColumnVector3 _WIND_NED = _vt_NED - vUVW_NED;
325 double hdot0 = _vt_NED(eW);
327 if (fabs(hdot0) < vt) {
328 double scale = sqrt((vt*vt-hdot*hdot)/(vt*vt-hdot0*hdot0));
329 _vt_NED(eU) *= scale;
330 _vt_NED(eV) *= scale;
333 vUVW_NED = _vt_NED - _WIND_NED;
335 // The AoA is not modified here but the function SetAlphaRadIC is updating the
336 // same angles than SetClimbRateFpsIC needs to update.
337 // TODO : create a subroutine that only shares the relevant code.
338 SetAlphaRadIC(alpha);
341 //******************************************************************************
342 // When the AoA is modified, we need to update the angles theta and beta to
343 // keep the true airspeed amplitude, the climb rate and the heading unchanged.
344 // Beta will be modified if the aircraft roll angle is not null.
346 void FGInitialCondition::SetAlphaRadIC(double alfa)
348 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
350 double calpha = cos(alfa), salpha = sin(alfa);
351 double cpsi = cos(psi), spsi = sin(psi);
352 double cphi = cos(phi), sphi = sin(phi);
353 FGMatrix33 Tpsi( cpsi, spsi, 0.,
356 FGMatrix33 Tphi(1., 0., 0.,
359 FGMatrix33 Talpha( calpha, 0., salpha,
361 -salpha, 0., calpha);
363 FGColumnVector3 v0 = Tpsi * _vt_NED;
364 FGColumnVector3 n = (Talpha * Tphi).Transposed() * FGColumnVector3(0., 0., 1.);
365 FGColumnVector3 y = FGColumnVector3(0., 1., 0.);
366 FGColumnVector3 u = y - DotProduct(y, n) * n;
367 FGColumnVector3 p = y * n;
369 if (DotProduct(p, v0) < 0) p *= -1.0;
372 u *= DotProduct(v0, y) / DotProduct(u, y);
374 // There are situations where the desired alpha angle cannot be obtained. This
375 // is not a limitation of the algorithm but is due to the mathematical problem
376 // not having a solution. This can only be cured by limiting the alpha angle
377 // or by modifying an additional angle (psi ?). Since this is anticipated to
378 // be a pathological case (mainly when a high roll angle is required) this
379 // situation is not addressed below. However if there are complaints about the
380 // following error being raised too often, we might need to reconsider this
382 if (DotProduct(v0, v0) < DotProduct(u, u)) {
383 cerr << "Cannot modify angle 'alpha' from " << alpha << " to " << alfa << endl;
387 FGColumnVector3 v1 = u + sqrt(DotProduct(v0, v0) - DotProduct(u, u))*p;
389 FGColumnVector3 v0xz(v0(eU), 0., v0(eW));
390 FGColumnVector3 v1xz(v1(eU), 0., v1(eW));
393 double sinTheta = (v1xz * v0xz)(eY);
394 theta = asin(sinTheta);
396 FGQuaternion Quat(phi, theta, psi);
399 Tb2l = Quat.GetTInv();
401 FGColumnVector3 v2 = Talpha * Quat.GetT() * _vt_NED;
404 beta = atan2(v2(eV), v2(eU));
405 double cbeta=0.0, sbeta=0.0;
410 Tw2b = FGMatrix33(calpha*cbeta, -calpha*sbeta, -salpha,
412 salpha*cbeta, -salpha*sbeta, calpha);
413 Tb2w = Tw2b.Transposed();
416 //******************************************************************************
417 // When the beta angle is modified, we need to update the angles theta and psi
418 // to keep the true airspeed (amplitude and direction - including the climb rate)
419 // and the alpha angle unchanged. This may result in the aircraft heading (psi)
420 // being altered especially if there is cross wind.
422 void FGInitialCondition::SetBetaRadIC(double bta)
424 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
427 double calpha = cos(alpha), salpha = sin(alpha);
428 double cbeta = cos(beta), sbeta = sin(beta);
430 Tw2b = FGMatrix33(calpha*cbeta, -calpha*sbeta, -salpha,
432 salpha*cbeta, -salpha*sbeta, calpha);
433 Tb2w = Tw2b.Transposed();
435 FGColumnVector3 vf = FGQuaternion(eX, phi).GetTInv() * Tw2b * FGColumnVector3(vt, 0., 0.);
436 FGColumnVector3 v0xy(_vt_NED(eX), _vt_NED(eY), 0.);
437 FGColumnVector3 v1xy(sqrt(v0xy(eX)*v0xy(eX)+v0xy(eY)*v0xy(eY)-vf(eY)*vf(eY)),vf(eY),0.);
441 if (vf(eX) < 0.) v0xy(eX) *= -1.0;
443 double sinPsi = (v1xy * v0xy)(eZ);
444 double cosPsi = DotProduct(v0xy, v1xy);
445 psi = atan2(sinPsi, cosPsi);
446 FGMatrix33 Tpsi( cosPsi, sinPsi, 0.,
450 FGColumnVector3 v2xz = Tpsi * _vt_NED;
451 FGColumnVector3 vfxz = vf;
452 v2xz(eV) = vfxz(eV) = 0.0;
455 double sinTheta = (v2xz * vfxz)(eY);
456 theta = -asin(sinTheta);
458 FGQuaternion Quat(phi, theta, psi);
461 Tb2l = Quat.GetTInv();
464 //******************************************************************************
465 // Modifies the body frame orientation (roll angle phi). The true airspeed in
466 // the local NED frame is kept unchanged. Hence the true airspeed in the body
467 // frame is modified.
469 void FGInitialCondition::SetPhiRadIC(double fi)
471 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
474 FGQuaternion Quat = FGQuaternion(phi, theta, psi);
477 Tb2l = Quat.GetTInv();
479 calcAeroAngles(_vt_NED);
482 //******************************************************************************
483 // Modifies the body frame orientation (pitch angle theta). The true airspeed in
484 // the local NED frame is kept unchanged. Hence the true airspeed in the body
485 // frame is modified.
487 void FGInitialCondition::SetThetaRadIC(double teta)
489 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
492 FGQuaternion Quat = FGQuaternion(phi, theta, psi);
495 Tb2l = Quat.GetTInv();
497 calcAeroAngles(_vt_NED);
500 //******************************************************************************
501 // Modifies the body frame orientation (yaw angle psi). The true airspeed in
502 // the local NED frame is kept unchanged. Hence the true airspeed in the body
503 // frame is modified.
505 void FGInitialCondition::SetPsiRadIC(double psy)
507 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
510 FGQuaternion Quat = FGQuaternion(phi, theta, psi);
513 Tb2l = Quat.GetTInv();
515 calcAeroAngles(_vt_NED);
518 //******************************************************************************
519 // Modifies an aircraft velocity component (eU, eV or eW) in the body frame. The
520 // true airspeed is modified accordingly. If there is some wind, the airspeed
521 // direction modification may differ from the body velocity modification.
523 void FGInitialCondition::SetBodyVelFpsIC(int idx, double vel)
525 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
526 FGColumnVector3 _vUVW_BODY = Tl2b * vUVW_NED;
527 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
529 _vUVW_BODY(idx) = vel;
530 vUVW_NED = Tb2l * _vUVW_BODY;
531 _vt_NED = vUVW_NED + _vWIND_NED;
532 vt = _vt_NED.Magnitude();
534 calcAeroAngles(_vt_NED);
536 lastSpeedSet = setuvw;
539 //******************************************************************************
540 // Modifies an aircraft velocity component (eX, eY or eZ) in the local NED frame.
541 // The true airspeed is modified accordingly. If there is some wind, the airspeed
542 // direction modification may differ from the local velocity modification.
544 void FGInitialCondition::SetNEDVelFpsIC(int idx, double vel)
546 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
547 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
550 _vt_NED = vUVW_NED + _vWIND_NED;
551 vt = _vt_NED.Magnitude();
553 calcAeroAngles(_vt_NED);
555 lastSpeedSet = setned;
558 //******************************************************************************
559 // Set wind amplitude and direction in the local NED frame. The aircraft velocity
560 // with respect to the ground is not changed but the true airspeed is.
562 void FGInitialCondition::SetWindNEDFpsIC(double wN, double wE, double wD )
564 FGColumnVector3 _vt_NED = vUVW_NED + FGColumnVector3(wN, wE, wD);
565 vt = _vt_NED.Magnitude();
567 calcAeroAngles(_vt_NED);
570 //******************************************************************************
571 // Set the cross wind velocity (in knots). Here, 'cross wind' means perpendicular
572 // to the aircraft heading and parallel to the ground. The aircraft velocity
573 // with respect to the ground is not changed but the true airspeed is.
575 void FGInitialCondition::SetCrossWindKtsIC(double cross)
577 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
578 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
579 FGColumnVector3 _vCROSS(-sin(psi), cos(psi), 0.);
581 // Gram-Schmidt process is used to remove the existing cross wind component
582 _vWIND_NED -= DotProduct(_vWIND_NED, _vCROSS) * _vCROSS;
583 // which is now replaced by the new value.
584 _vWIND_NED += cross * _vCROSS;
585 _vt_NED = vUVW_NED + _vWIND_NED;
586 vt = _vt_NED.Magnitude();
588 calcAeroAngles(_vt_NED);
591 //******************************************************************************
592 // Set the head wind velocity (in knots). Here, 'head wind' means parallel
593 // to the aircraft heading and to the ground. The aircraft velocity
594 // with respect to the ground is not changed but the true airspeed is.
596 void FGInitialCondition::SetHeadWindKtsIC(double head)
598 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
599 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
600 FGColumnVector3 _vHEAD(cos(psi), sin(psi), 0.);
602 // Gram-Schmidt process is used to remove the existing cross wind component
603 _vWIND_NED -= DotProduct(_vWIND_NED, _vHEAD) * _vHEAD;
604 // which is now replaced by the new value.
605 _vWIND_NED += head * _vHEAD;
606 _vt_NED = vUVW_NED + _vWIND_NED;
607 vt = _vt_NED.Magnitude();
609 calcAeroAngles(_vt_NED);
612 //******************************************************************************
613 // Set the vertical wind velocity (in knots). The 'vertical' is taken in the
614 // local NED frame. The aircraft velocity with respect to the ground is not
615 // changed but the true airspeed is.
617 void FGInitialCondition::SetWindDownKtsIC(double wD)
619 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
621 _vt_NED(eW) = vUVW_NED(eW) + wD;
622 vt = _vt_NED.Magnitude();
624 calcAeroAngles(_vt_NED);
627 //******************************************************************************
628 // Modifies the wind velocity (in knots) while keeping its direction unchanged.
629 // The vertical component (in local NED frame) is unmodified. The aircraft
630 // velocity with respect to the ground is not changed but the true airspeed is.
632 void FGInitialCondition::SetWindMagKtsIC(double mag)
634 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
635 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
636 FGColumnVector3 _vHEAD(_vWIND_NED(eU), _vWIND_NED(eV), 0.);
637 double windMag = _vHEAD.Magnitude();
640 _vHEAD *= mag / windMag;
642 _vHEAD = FGColumnVector3(mag, 0., 0.);
644 _vWIND_NED(eU) = _vHEAD(eU);
645 _vWIND_NED(eV) = _vHEAD(eV);
646 _vt_NED = vUVW_NED + _vWIND_NED;
647 vt = _vt_NED.Magnitude();
649 calcAeroAngles(_vt_NED);
652 //******************************************************************************
653 // Modifies the wind direction while keeping its velocity unchanged. The vertical
654 // component (in local NED frame) is unmodified. The aircraft velocity with
655 // respect to the ground is not changed but the true airspeed is.
657 void FGInitialCondition::SetWindDirDegIC(double dir)
659 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
660 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
661 double mag = _vWIND_NED.Magnitude(eU, eV);
662 FGColumnVector3 _vHEAD(mag*cos(dir*degtorad), mag*sin(dir*degtorad), 0.);
664 _vWIND_NED(eU) = _vHEAD(eU);
665 _vWIND_NED(eV) = _vHEAD(eV);
666 _vt_NED = vUVW_NED + _vWIND_NED;
667 vt = _vt_NED.Magnitude();
669 calcAeroAngles(_vt_NED);
672 //******************************************************************************
673 // Set the altitude SL. If the airspeed has been previously set with parameters
674 // that are atmosphere dependent (Mach, VCAS, VEAS) then the true airspeed is
675 // modified to keep the last set speed to its previous value.
677 void FGInitialCondition::SetAltitudeASLFtIC(double alt)
679 double altitudeASL = position.GetRadius() - sea_level_radius;
680 double temperature = fdmex->GetAtmosphere()->GetTemperature(altitudeASL);
681 double soundSpeed = sqrt(SHRatio*Reng*temperature);
682 double rho = fdmex->GetAtmosphere()->GetDensity(altitudeASL);
683 double rhoSL = fdmex->GetAtmosphere()->GetDensitySL();
685 double mach0 = vt / soundSpeed;
686 double vc0 = calcVcas(mach0);
687 double ve0 = vt * sqrt(rho/rhoSL);
690 temperature = fdmex->GetAtmosphere()->GetTemperature(altitudeASL);
691 soundSpeed = sqrt(SHRatio*Reng*temperature);
692 rho = fdmex->GetAtmosphere()->GetDensity(altitudeASL);
694 switch(lastSpeedSet) {
696 mach0 = getMachFromVcas(vc0);
698 SetVtrueFpsIC(mach0 * soundSpeed);
701 SetVtrueFpsIC(ve0 * sqrt(rho/rhoSL));
703 default: // Make the compiler stop complaining about missing enums
707 position.SetRadius(alt + sea_level_radius);
710 //******************************************************************************
711 // Calculate the VCAS. Uses the Rayleigh formula for supersonic speeds
712 // (See "Introduction to Aerodynamics of a Compressible Fluid - H.W. Liepmann,
713 // A.E. Puckett - Wiley & sons (1947)" §5.4 pp 75-80)
715 double FGInitialCondition::calcVcas(double Mach) const
717 double altitudeASL = position.GetRadius() - sea_level_radius;
718 double p=fdmex->GetAtmosphere()->GetPressure(altitudeASL);
719 double psl=fdmex->GetAtmosphere()->GetPressureSL();
720 double rhosl=fdmex->GetAtmosphere()->GetDensitySL();
723 if (Mach < 0) Mach=0;
724 if (Mach < 1) //calculate total pressure assuming isentropic flow
725 pt=p*pow((1 + 0.2*Mach*Mach),3.5);
727 // shock in front of pitot tube, we'll assume its normal and use
728 // the Rayleigh Pitot Tube Formula, i.e. the ratio of total
729 // pressure behind the shock to the static pressure in front of
730 // the normal shock assumption should not be a bad one -- most supersonic
731 // aircraft place the pitot probe out front so that it is the forward
732 // most point on the aircraft. The real shock would, of course, take
733 // on something like the shape of a rounded-off cone but, here again,
734 // the assumption should be good since the opening of the pitot probe
735 // is very small and, therefore, the effects of the shock curvature
736 // should be small as well. AFAIK, this approach is fairly well accepted
737 // within the aerospace community
739 // The denominator below is zero for Mach ~ 0.38, for which
740 // we'll never be here, so we're safe
742 pt = p*166.92158*pow(Mach,7.0)/pow(7*Mach*Mach-1,2.5);
745 A = pow(((pt-p)/psl+1),0.28571);
746 vcas = sqrt(7*psl/rhosl*(A-1));
747 //cout << "calcVcas: vcas= " << vcas*fpstokts << " mach= " << Mach << " pressure: " << pt << endl;
751 //******************************************************************************
752 // Reverse the VCAS formula to obtain the corresponding Mach number. For subsonic
753 // speeds, the reversed formula has a closed form. For supersonic speeds, the
754 // formula is reversed by the Newton-Raphson algorithm.
756 double FGInitialCondition::getMachFromVcas(double vcas)
758 double altitudeASL = position.GetRadius() - sea_level_radius;
759 double p=fdmex->GetAtmosphere()->GetPressure(altitudeASL);
760 double psl=fdmex->GetAtmosphere()->GetPressureSL();
761 double rhosl=fdmex->GetAtmosphere()->GetDensitySL();
763 double pt = p + psl*(pow(1+vcas*vcas*rhosl/(7.0*psl),3.5)-1);
766 return sqrt(5.0*(pow(pt/p, 0.2857143) -1)); // Mach < 1
769 double mach = sqrt(0.77666*pt/p); // Initial guess is based on a quadratic approximation of the Rayleigh formula
771 double target = pt/(166.92158*p);
774 // Find the root with Newton-Raphson. Since the differential is never zero,
775 // the function is monotonic and has only one root with a multiplicity of one.
776 // Convergence is certain.
777 while (delta > 1E-5 && iter < 10) {
778 double m2 = mach*mach; // Mach^2
779 double m6 = m2*m2*m2; // Mach^6
780 delta = mach*m6/pow(7.0*m2-1.0,2.5) - target;
781 double diff = 7.0*m6*(2.0*m2-1)/pow(7.0*m2-1.0,3.5); // Never zero when Mach >= 1
790 //******************************************************************************
792 double FGInitialCondition::GetWindDirDegIC(void) const
794 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
795 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
797 return _vWIND_NED(eV) == 0.0 ? 0.0
798 : atan2(_vWIND_NED(eV), _vWIND_NED(eU))*radtodeg;
801 //******************************************************************************
803 double FGInitialCondition::GetNEDWindFpsIC(int idx) const
805 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
806 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
808 return _vWIND_NED(idx);
811 //******************************************************************************
813 double FGInitialCondition::GetWindFpsIC(void) const
815 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
816 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
818 return _vWIND_NED.Magnitude(eU, eV);
821 //******************************************************************************
823 double FGInitialCondition::GetBodyWindFpsIC(int idx) const
825 FGColumnVector3 _vt_BODY = Tw2b * FGColumnVector3(vt, 0., 0.);
826 FGColumnVector3 _vUVW_BODY = Tl2b * vUVW_NED;
827 FGColumnVector3 _vWIND_BODY = _vt_BODY - _vUVW_BODY;
829 return _vWIND_BODY(idx);
832 //******************************************************************************
834 double FGInitialCondition::GetVcalibratedKtsIC(void) const
836 double altitudeASL = position.GetRadius() - sea_level_radius;
837 double temperature = fdmex->GetAtmosphere()->GetTemperature(altitudeASL);
838 double soundSpeed = sqrt(SHRatio*Reng*temperature);
839 double mach = vt / soundSpeed;
840 return fpstokts * calcVcas(mach);
843 //******************************************************************************
845 double FGInitialCondition::GetVequivalentKtsIC(void) const
847 double altitudeASL = position.GetRadius() - sea_level_radius;
848 double rho = fdmex->GetAtmosphere()->GetDensity(altitudeASL);
849 double rhoSL = fdmex->GetAtmosphere()->GetDensitySL();
850 return fpstokts * vt * sqrt(rho/rhoSL);
853 //******************************************************************************
855 double FGInitialCondition::GetMachIC(void) const
857 double altitudeASL = position.GetRadius() - sea_level_radius;
858 double temperature = fdmex->GetAtmosphere()->GetTemperature(altitudeASL);
859 double soundSpeed = sqrt(SHRatio*Reng*temperature);
860 return vt / soundSpeed;
863 //******************************************************************************
865 double FGInitialCondition::GetBodyVelFpsIC(int idx) const
867 FGColumnVector3 _vUVW_BODY = Tl2b * vUVW_NED;
869 return _vUVW_BODY(idx);
872 //******************************************************************************
874 bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
877 if( useStoredPath ) {
878 init_file_name = fdmex->GetFullAircraftPath() + sep + rstfile + ".xml";
880 init_file_name = rstfile;
883 document = LoadXMLDocument(init_file_name);
885 // Make sure that the document is valid
887 cerr << "File: " << init_file_name << " could not be read." << endl;
891 if (document->GetName() != string("initialize")) {
892 cerr << "File: " << init_file_name << " is not a reset file." << endl;
896 double version = document->GetAttributeValueAsNumber("version");
899 if (version == HUGE_VAL) {
900 result = Load_v1(); // Default to the old version
901 } else if (version >= 3.0) {
902 cerr << "Only initialization file formats 1 and 2 are currently supported" << endl;
904 } else if (version >= 2.0) {
906 } else if (version >= 1.0) {
910 // Check to see if any engines are specified to be initialized in a running state
911 FGPropulsion* propulsion = fdmex->GetPropulsion();
912 Element* running_elements = document->FindElement("running");
913 while (running_elements) {
914 int n = int(running_elements->GetDataAsNumber());
916 propulsion->InitRunning(n);
917 } catch (string str) {
921 running_elements = document->FindNextElement("running");
925 fdmex->GetPropagate()->DumpState();
930 //******************************************************************************
932 bool FGInitialCondition::Load_v1(void)
936 if (document->FindElement("latitude"))
937 position.SetLatitude(document->FindElementValueAsNumberConvertTo("latitude", "RAD"));
938 if (document->FindElement("longitude"))
939 position.SetLongitude(document->FindElementValueAsNumberConvertTo("longitude", "RAD"));
940 if (document->FindElement("elevation"))
941 terrain_elevation = document->FindElementValueAsNumberConvertTo("elevation", "FT");
943 if (document->FindElement("altitude")) // This is feet above ground level
944 position.SetRadius(document->FindElementValueAsNumberConvertTo("altitude", "FT") + terrain_elevation + sea_level_radius);
945 else if (document->FindElement("altitudeAGL")) // This is feet above ground level
946 position.SetRadius(document->FindElementValueAsNumberConvertTo("altitudeAGL", "FT") + terrain_elevation + sea_level_radius);
947 else if (document->FindElement("altitudeMSL")) // This is feet above sea level
948 position.SetRadius(document->FindElementValueAsNumberConvertTo("altitudeMSL", "FT") + sea_level_radius);
950 if (document->FindElement("phi"))
951 phi = document->FindElementValueAsNumberConvertTo("phi", "RAD");
952 if (document->FindElement("theta"))
953 theta = document->FindElementValueAsNumberConvertTo("theta", "RAD");
954 if (document->FindElement("psi"))
955 psi = document->FindElementValueAsNumberConvertTo("psi", "RAD");
957 FGQuaternion Quat(phi, theta, psi);
960 Tb2l = Quat.GetTInv();
962 if (document->FindElement("ubody"))
963 SetUBodyFpsIC(document->FindElementValueAsNumberConvertTo("ubody", "FT/SEC"));
964 if (document->FindElement("vbody"))
965 SetVBodyFpsIC(document->FindElementValueAsNumberConvertTo("vbody", "FT/SEC"));
966 if (document->FindElement("wbody"))
967 SetWBodyFpsIC(document->FindElementValueAsNumberConvertTo("wbody", "FT/SEC"));
968 if (document->FindElement("vnorth"))
969 SetVNorthFpsIC(document->FindElementValueAsNumberConvertTo("vnorth", "FT/SEC"));
970 if (document->FindElement("veast"))
971 SetVEastFpsIC(document->FindElementValueAsNumberConvertTo("veast", "FT/SEC"));
972 if (document->FindElement("vdown"))
973 SetVDownFpsIC(document->FindElementValueAsNumberConvertTo("vdown", "FT/SEC"));
974 if (document->FindElement("vc"))
975 SetVcalibratedKtsIC(document->FindElementValueAsNumberConvertTo("vc", "KTS"));
976 if (document->FindElement("vt"))
977 SetVtrueKtsIC(document->FindElementValueAsNumberConvertTo("vt", "KTS"));
978 if (document->FindElement("mach"))
979 SetMachIC(document->FindElementValueAsNumber("mach"));
980 if (document->FindElement("gamma"))
981 SetFlightPathAngleDegIC(document->FindElementValueAsNumberConvertTo("gamma", "DEG"));
982 if (document->FindElement("roc"))
983 SetClimbRateFpsIC(document->FindElementValueAsNumberConvertTo("roc", "FT/SEC"));
984 if (document->FindElement("vground"))
985 SetVgroundKtsIC(document->FindElementValueAsNumberConvertTo("vground", "KTS"));
986 if (document->FindElement("alpha"))
987 SetAlphaDegIC(document->FindElementValueAsNumberConvertTo("alpha", "DEG"));
988 if (document->FindElement("beta"))
989 SetBetaDegIC(document->FindElementValueAsNumberConvertTo("beta", "DEG"));
990 if (document->FindElement("vwind"))
991 SetWindMagKtsIC(document->FindElementValueAsNumberConvertTo("vwind", "KTS"));
992 if (document->FindElement("winddir"))
993 SetWindDirDegIC(document->FindElementValueAsNumberConvertTo("winddir", "DEG"));
994 if (document->FindElement("hwind"))
995 SetHeadWindKtsIC(document->FindElementValueAsNumberConvertTo("hwind", "KTS"));
996 if (document->FindElement("xwind"))
997 SetCrossWindKtsIC(document->FindElementValueAsNumberConvertTo("xwind", "KTS"));
998 if (document->FindElement("targetNlf"))
1000 SetTargetNlfIC(document->FindElementValueAsNumber("targetNlf"));
1003 // Refer to Stevens and Lewis, 1.5-14a, pg. 49.
1004 // This is the rotation rate of the "Local" frame, expressed in the local frame.
1005 double radInv = 1.0 / position.GetRadius();
1006 FGColumnVector3 vOmegaLocal = FGColumnVector3(
1007 radInv*vUVW_NED(eEast),
1008 -radInv*vUVW_NED(eNorth),
1009 -radInv*vUVW_NED(eEast)*position.GetTanLatitude() );
1011 p = vOmegaLocal(eP);
1012 q = vOmegaLocal(eR);
1013 r = vOmegaLocal(eQ);
1018 //******************************************************************************
1020 bool FGInitialCondition::Load_v2(void)
1022 FGColumnVector3 vOrient;
1024 FGColumnVector3 vOmegaEarth = FGColumnVector3(0.0, 0.0, fdmex->GetInertial()->omega());
1026 if (document->FindElement("earth_position_angle"))
1027 position.SetEarthPositionAngle(document->FindElementValueAsNumberConvertTo("earth_position_angle", "RAD"));
1029 if (document->FindElement("elevation"))
1030 terrain_elevation = document->FindElementValueAsNumberConvertTo("elevation", "FT");
1032 // Initialize vehicle position
1034 // Allowable frames:
1035 // - ECI (Earth Centered Inertial)
1036 // - ECEF (Earth Centered, Earth Fixed)
1038 Element* position_el = document->FindElement("position");
1040 string frame = position_el->GetAttributeValue("frame");
1041 frame = to_lower(frame);
1042 if (frame == "eci") { // Need to transform vLoc to ECEF for storage and use in FGLocation.
1043 position = position.GetTi2ec() * position_el->FindElementTripletConvertTo("FT");
1044 } else if (frame == "ecef") {
1045 if (!position_el->FindElement("x") && !position_el->FindElement("y") && !position_el->FindElement("z")) {
1046 if (position_el->FindElement("radius")) {
1047 position.SetRadius(position_el->FindElementValueAsNumberConvertTo("radius", "FT"));
1048 } else if (position_el->FindElement("altitudeAGL")) {
1049 position.SetRadius(sea_level_radius + terrain_elevation + position_el->FindElementValueAsNumberConvertTo("altitudeAGL", "FT"));
1050 } else if (position_el->FindElement("altitudeMSL")) {
1051 position.SetRadius(sea_level_radius + position_el->FindElementValueAsNumberConvertTo("altitudeMSL", "FT"));
1053 cerr << endl << " No altitude or radius initial condition is given." << endl;
1056 if (position_el->FindElement("longitude"))
1057 position.SetLongitude(position_el->FindElementValueAsNumberConvertTo("longitude", "RAD"));
1058 if (position_el->FindElement("latitude"))
1059 position.SetLatitude(position_el->FindElementValueAsNumberConvertTo("latitude", "RAD"));
1061 position = position_el->FindElementTripletConvertTo("FT");
1064 cerr << endl << " Neither ECI nor ECEF frame is specified for initial position." << endl;
1068 cerr << endl << " Initial position not specified in this initialization file." << endl;
1072 // End of position initialization
1074 // Initialize vehicle orientation
1076 // - ECI (Earth Centered Inertial)
1077 // - ECEF (Earth Centered, Earth Fixed)
1080 // Need to convert the provided orientation to a local orientation, using
1081 // the given orientation and knowledge of the Earth position angle.
1082 // This could be done using matrices (where in the subscript "b/a",
1083 // it is meant "b with respect to a", and where b=body frame,
1084 // i=inertial frame, and e=ecef frame) as:
1086 // C_b/l = C_b/e * C_e/l
1088 // Using quaternions (note reverse ordering compared to matrix representation):
1090 // Q_b/l = Q_e/l * Q_b/e
1092 // Use the specific matrices as needed. The above example of course is for the whole
1093 // body to local orientation.
1094 // The new orientation angles can be extracted from the matrix or the quaternion.
1095 // ToDo: Do we need to deal with normalization of the quaternions here?
1097 Element* orientation_el = document->FindElement("orientation");
1098 FGQuaternion QuatLocal2Body;
1099 if (orientation_el) {
1100 string frame = orientation_el->GetAttributeValue("frame");
1101 frame = to_lower(frame);
1102 vOrient = orientation_el->FindElementTripletConvertTo("RAD");
1103 if (frame == "eci") {
1105 // In this case, we are supplying the Euler angles for the vehicle with
1106 // respect to the inertial system, represented by the C_b/i Matrix.
1107 // We want the body orientation with respect to the local (NED frame):
1109 // C_b/l = C_b/i * C_i/l
1111 // Or, using quaternions (note reverse ordering compared to matrix representation):
1113 // Q_b/l = Q_i/l * Q_b/i
1115 FGQuaternion QuatI2Body = FGQuaternion(vOrient);
1116 QuatI2Body.Normalize();
1117 FGQuaternion QuatLocal2I = position.GetTl2i();
1118 QuatLocal2I.Normalize();
1119 QuatLocal2Body = QuatLocal2I * QuatI2Body;
1121 } else if (frame == "ecef") {
1123 // In this case we are given the Euler angles representing the orientation of
1124 // the body with respect to the ECEF system, represented by the C_b/e Matrix.
1125 // We want the body orientation with respect to the local (NED frame):
1127 // C_b/l = C_b/e * C_e/l
1129 // Using quaternions (note reverse ordering compared to matrix representation):
1131 // Q_b/l = Q_e/l * Q_b/e
1133 FGQuaternion QuatEC2Body(vOrient); // Store relationship of Body frame wrt ECEF frame, Q_b/e
1134 QuatEC2Body.Normalize();
1135 FGQuaternion QuatLocal2EC = position.GetTl2ec(); // Get Q_e/l from matrix
1136 QuatLocal2EC.Normalize();
1137 QuatLocal2Body = QuatLocal2EC * QuatEC2Body; // Q_b/l = Q_e/l * Q_b/e
1139 } else if (frame == "local") {
1141 QuatLocal2Body = FGQuaternion(vOrient);
1145 cerr << endl << fgred << " Orientation frame type: \"" << frame
1146 << "\" is not supported!" << reset << endl << endl;
1152 QuatLocal2Body.Normalize();
1153 phi = QuatLocal2Body.GetEuler(ePhi);
1154 theta = QuatLocal2Body.GetEuler(eTht);
1155 psi = QuatLocal2Body.GetEuler(ePsi);
1156 Tl2b = QuatLocal2Body.GetT();
1157 Tb2l = QuatLocal2Body.GetTInv();
1159 // Initialize vehicle velocity
1161 // - ECI (Earth Centered Inertial)
1162 // - ECEF (Earth Centered, Earth Fixed)
1165 // The vehicle will be defaulted to (0,0,0) in the Body frame if nothing is provided.
1167 Element* velocity_el = document->FindElement("velocity");
1168 FGColumnVector3 vInitVelocity = FGColumnVector3(0.0, 0.0, 0.0);
1169 FGMatrix33 mTec2l = position.GetTec2l();
1172 string frame = velocity_el->GetAttributeValue("frame");
1173 frame = to_lower(frame);
1174 FGColumnVector3 vInitVelocity = velocity_el->FindElementTripletConvertTo("FT/SEC");
1176 if (frame == "eci") {
1177 FGColumnVector3 omega_cross_r = vOmegaEarth * (position.GetTec2i() * position);
1178 vUVW_NED = mTec2l * (vInitVelocity - omega_cross_r);
1179 } else if (frame == "ecef") {
1180 vUVW_NED = mTec2l * vInitVelocity;
1181 } else if (frame == "local") {
1182 vUVW_NED = vInitVelocity;
1183 lastSpeedSet = setned;
1184 } else if (frame == "body") {
1185 vUVW_NED = Tb2l * vInitVelocity;
1186 lastSpeedSet = setuvw;
1189 cerr << endl << fgred << " Velocity frame type: \"" << frame
1190 << "\" is not supported!" << reset << endl << endl;
1197 vUVW_NED = Tb2l * vInitVelocity;
1201 vt = vUVW_NED.Magnitude();
1203 calcAeroAngles(vUVW_NED);
1205 // Initialize vehicle body rates
1207 // - ECI (Earth Centered Inertial)
1208 // - ECEF (Earth Centered, Earth Fixed)
1211 FGColumnVector3 vLocalRate;
1212 Element* attrate_el = document->FindElement("attitude_rate");
1214 // Refer to Stevens and Lewis, 1.5-14a, pg. 49.
1215 // This is the rotation rate of the "Local" frame, expressed in the local frame.
1216 double radInv = 1.0 / position.GetRadius();
1217 FGColumnVector3 vOmegaLocal = FGColumnVector3(
1218 radInv*vUVW_NED(eEast),
1219 -radInv*vUVW_NED(eNorth),
1220 -radInv*vUVW_NED(eEast)*position.GetTanLatitude() );
1224 string frame = attrate_el->GetAttributeValue("frame");
1225 frame = to_lower(frame);
1226 FGColumnVector3 vAttRate = attrate_el->FindElementTripletConvertTo("RAD/SEC");
1228 if (frame == "eci") {
1229 vLocalRate = Tl2b * position.GetTi2l() * (vAttRate - vOmegaEarth);
1230 } else if (frame == "ecef") {
1231 vLocalRate = Tl2b * position.GetTec2l() * vAttRate;
1232 } else if (frame == "local") {
1233 vLocalRate = vAttRate + vOmegaLocal;
1234 } else if (!frame.empty()) { // misspelling of frame
1236 cerr << endl << fgred << " Attitude rate frame type: \"" << frame
1237 << "\" is not supported!" << reset << endl << endl;
1240 } else if (frame.empty()) {
1241 vLocalRate = vOmegaLocal;
1244 } else { // Body frame attitude rate assumed 0 relative to local.
1245 vLocalRate = vOmegaLocal;
1255 //******************************************************************************
1257 void FGInitialCondition::bind(void)
1259 PropertyManager->Tie("ic/vc-kts", this,
1260 &FGInitialCondition::GetVcalibratedKtsIC,
1261 &FGInitialCondition::SetVcalibratedKtsIC,
1263 PropertyManager->Tie("ic/ve-kts", this,
1264 &FGInitialCondition::GetVequivalentKtsIC,
1265 &FGInitialCondition::SetVequivalentKtsIC,
1267 PropertyManager->Tie("ic/vg-kts", this,
1268 &FGInitialCondition::GetVgroundKtsIC,
1269 &FGInitialCondition::SetVgroundKtsIC,
1271 PropertyManager->Tie("ic/vt-kts", this,
1272 &FGInitialCondition::GetVtrueKtsIC,
1273 &FGInitialCondition::SetVtrueKtsIC,
1275 PropertyManager->Tie("ic/mach", this,
1276 &FGInitialCondition::GetMachIC,
1277 &FGInitialCondition::SetMachIC,
1279 PropertyManager->Tie("ic/roc-fpm", this,
1280 &FGInitialCondition::GetClimbRateFpmIC,
1281 &FGInitialCondition::SetClimbRateFpmIC,
1283 PropertyManager->Tie("ic/gamma-deg", this,
1284 &FGInitialCondition::GetFlightPathAngleDegIC,
1285 &FGInitialCondition::SetFlightPathAngleDegIC,
1287 PropertyManager->Tie("ic/alpha-deg", this,
1288 &FGInitialCondition::GetAlphaDegIC,
1289 &FGInitialCondition::SetAlphaDegIC,
1291 PropertyManager->Tie("ic/beta-deg", this,
1292 &FGInitialCondition::GetBetaDegIC,
1293 &FGInitialCondition::SetBetaDegIC,
1295 PropertyManager->Tie("ic/theta-deg", this,
1296 &FGInitialCondition::GetThetaDegIC,
1297 &FGInitialCondition::SetThetaDegIC,
1299 PropertyManager->Tie("ic/phi-deg", this,
1300 &FGInitialCondition::GetPhiDegIC,
1301 &FGInitialCondition::SetPhiDegIC,
1303 PropertyManager->Tie("ic/psi-true-deg", this,
1304 &FGInitialCondition::GetPsiDegIC );
1305 PropertyManager->Tie("ic/lat-gc-deg", this,
1306 &FGInitialCondition::GetLatitudeDegIC,
1307 &FGInitialCondition::SetLatitudeDegIC,
1309 PropertyManager->Tie("ic/long-gc-deg", this,
1310 &FGInitialCondition::GetLongitudeDegIC,
1311 &FGInitialCondition::SetLongitudeDegIC,
1313 PropertyManager->Tie("ic/h-sl-ft", this,
1314 &FGInitialCondition::GetAltitudeASLFtIC,
1315 &FGInitialCondition::SetAltitudeASLFtIC,
1317 PropertyManager->Tie("ic/h-agl-ft", this,
1318 &FGInitialCondition::GetAltitudeAGLFtIC,
1319 &FGInitialCondition::SetAltitudeAGLFtIC,
1321 PropertyManager->Tie("ic/sea-level-radius-ft", this,
1322 &FGInitialCondition::GetSeaLevelRadiusFtIC,
1323 &FGInitialCondition::SetSeaLevelRadiusFtIC,
1325 PropertyManager->Tie("ic/terrain-elevation-ft", this,
1326 &FGInitialCondition::GetTerrainElevationFtIC,
1327 &FGInitialCondition::SetTerrainElevationFtIC,
1329 PropertyManager->Tie("ic/vg-fps", this,
1330 &FGInitialCondition::GetVgroundFpsIC,
1331 &FGInitialCondition::SetVgroundFpsIC,
1333 PropertyManager->Tie("ic/vt-fps", this,
1334 &FGInitialCondition::GetVtrueFpsIC,
1335 &FGInitialCondition::SetVtrueFpsIC,
1337 PropertyManager->Tie("ic/vw-bx-fps", this,
1338 &FGInitialCondition::GetWindUFpsIC);
1339 PropertyManager->Tie("ic/vw-by-fps", this,
1340 &FGInitialCondition::GetWindVFpsIC);
1341 PropertyManager->Tie("ic/vw-bz-fps", this,
1342 &FGInitialCondition::GetWindWFpsIC);
1343 PropertyManager->Tie("ic/vw-north-fps", this,
1344 &FGInitialCondition::GetWindNFpsIC);
1345 PropertyManager->Tie("ic/vw-east-fps", this,
1346 &FGInitialCondition::GetWindEFpsIC);
1347 PropertyManager->Tie("ic/vw-down-fps", this,
1348 &FGInitialCondition::GetWindDFpsIC);
1349 PropertyManager->Tie("ic/vw-mag-fps", this,
1350 &FGInitialCondition::GetWindFpsIC);
1351 PropertyManager->Tie("ic/vw-dir-deg", this,
1352 &FGInitialCondition::GetWindDirDegIC,
1353 &FGInitialCondition::SetWindDirDegIC,
1356 PropertyManager->Tie("ic/roc-fps", this,
1357 &FGInitialCondition::GetClimbRateFpsIC,
1358 &FGInitialCondition::SetClimbRateFpsIC,
1360 PropertyManager->Tie("ic/u-fps", this,
1361 &FGInitialCondition::GetUBodyFpsIC,
1362 &FGInitialCondition::SetUBodyFpsIC,
1364 PropertyManager->Tie("ic/v-fps", this,
1365 &FGInitialCondition::GetVBodyFpsIC,
1366 &FGInitialCondition::SetVBodyFpsIC,
1368 PropertyManager->Tie("ic/w-fps", this,
1369 &FGInitialCondition::GetWBodyFpsIC,
1370 &FGInitialCondition::SetWBodyFpsIC,
1372 PropertyManager->Tie("ic/vn-fps", this,
1373 &FGInitialCondition::GetVNorthFpsIC,
1374 &FGInitialCondition::SetVNorthFpsIC,
1376 PropertyManager->Tie("ic/ve-fps", this,
1377 &FGInitialCondition::GetVEastFpsIC,
1378 &FGInitialCondition::SetVEastFpsIC,
1380 PropertyManager->Tie("ic/vd-fps", this,
1381 &FGInitialCondition::GetVDownFpsIC,
1382 &FGInitialCondition::SetVDownFpsIC,
1384 PropertyManager->Tie("ic/gamma-rad", this,
1385 &FGInitialCondition::GetFlightPathAngleRadIC,
1386 &FGInitialCondition::SetFlightPathAngleRadIC,
1388 PropertyManager->Tie("ic/alpha-rad", this,
1389 &FGInitialCondition::GetAlphaRadIC,
1390 &FGInitialCondition::SetAlphaRadIC,
1392 PropertyManager->Tie("ic/theta-rad", this,
1393 &FGInitialCondition::GetThetaRadIC,
1394 &FGInitialCondition::SetThetaRadIC,
1396 PropertyManager->Tie("ic/beta-rad", this,
1397 &FGInitialCondition::GetBetaRadIC,
1398 &FGInitialCondition::SetBetaRadIC,
1400 PropertyManager->Tie("ic/phi-rad", this,
1401 &FGInitialCondition::GetPhiRadIC,
1402 &FGInitialCondition::SetPhiRadIC,
1404 PropertyManager->Tie("ic/psi-true-rad", this,
1405 &FGInitialCondition::GetPsiRadIC);
1406 PropertyManager->Tie("ic/lat-gc-rad", this,
1407 &FGInitialCondition::GetLatitudeRadIC,
1408 &FGInitialCondition::SetLatitudeRadIC,
1410 PropertyManager->Tie("ic/long-gc-rad", this,
1411 &FGInitialCondition::GetLongitudeRadIC,
1412 &FGInitialCondition::SetLongitudeRadIC,
1414 PropertyManager->Tie("ic/p-rad_sec", this,
1415 &FGInitialCondition::GetPRadpsIC,
1416 &FGInitialCondition::SetPRadpsIC,
1418 PropertyManager->Tie("ic/q-rad_sec", this,
1419 &FGInitialCondition::GetQRadpsIC,
1420 &FGInitialCondition::SetQRadpsIC,
1422 PropertyManager->Tie("ic/r-rad_sec", this,
1423 &FGInitialCondition::GetRRadpsIC,
1424 &FGInitialCondition::SetRRadpsIC,
1427 typedef int (FGInitialCondition::*iPMF)(void) const;
1428 PropertyManager->Tie("simulation/write-state-file",
1431 &FGInitialCondition::WriteStateFile);
1435 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1436 // The bitmasked value choices are as follows:
1437 // unset: In this case (the default) JSBSim would only print
1438 // out the normally expected messages, essentially echoing
1439 // the config files as they are read. If the environment
1440 // variable is not set, debug_lvl is set to 1 internally
1441 // 0: This requests JSBSim not to output any messages
1443 // 1: This value explicity requests the normal JSBSim
1445 // 2: This value asks for a message to be printed out when
1446 // a class is instantiated
1447 // 4: When this value is set, a message is displayed when a
1448 // FGModel object executes its Run() method
1449 // 8: When this value is set, various runtime state variables
1450 // are printed out periodically
1451 // 16: When set various parameters are sanity checked and
1452 // a message is printed out when they go out of bounds
1454 void FGInitialCondition::Debug(int from)
1456 if (debug_lvl <= 0) return;
1458 if (debug_lvl & 1) { // Standard console startup message output
1460 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
1461 if (from == 0) cout << "Instantiated: FGInitialCondition" << endl;
1462 if (from == 1) cout << "Destroyed: FGInitialCondition" << endl;
1464 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
1466 if (debug_lvl & 8 ) { // Runtime state variables
1468 if (debug_lvl & 16) { // Sanity checking
1470 if (debug_lvl & 64) {
1471 if (from == 0) { // Constructor
1472 cout << IdSrc << endl;
1473 cout << IdHdr << endl;