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 *******************************************************************************/
51 #include "FGInitialCondition.h"
52 #include "FGFDMExec.h"
53 #include "math/FGQuaternion.h"
54 #include "models/FGInertial.h"
55 #include "models/FGAtmosphere.h"
56 #include "models/FGPropagate.h"
57 #include "models/FGPropulsion.h"
58 #include "models/FGFCS.h"
59 #include "input_output/FGPropertyManager.h"
60 #include "input_output/string_utilities.h"
66 static const char *IdSrc = "$Id: FGInitialCondition.cpp,v 1.75 2011/10/23 15:05:32 bcoconni Exp $";
67 static const char *IdHdr = ID_INITIALCONDITION;
69 //******************************************************************************
71 FGInitialCondition::FGInitialCondition(FGFDMExec *FDMExec) : fdmex(FDMExec)
75 if(FDMExec != NULL ) {
76 PropertyManager=fdmex->GetPropertyManager();
77 Atmosphere=fdmex->GetAtmosphere();
82 cout << "FGInitialCondition: This class requires a pointer to a valid FGFDMExec object" << endl;
88 //******************************************************************************
90 FGInitialCondition::~FGInitialCondition()
95 //******************************************************************************
97 void FGInitialCondition::ResetIC(double u0, double v0, double w0,
98 double p0, double q0, double r0,
99 double alpha0, double beta0,
100 double phi0, double theta0, double psi0,
101 double latRad0, double lonRad0, double altAGLFt0,
104 double calpha = cos(alpha0), cbeta = cos(beta0);
105 double salpha = sin(alpha0), sbeta = sin(beta0);
109 vPQR_body = FGColumnVector3(p0, q0, r0);
110 alpha = alpha0; beta = beta0;
112 position.SetPosition(lonRad0, latRad0, altAGLFt0 + terrain_elevation + sea_level_radius);
114 orientation = FGQuaternion(phi0, theta0, psi0);
115 const FGMatrix33& Tb2l = orientation.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)
133 terrain_elevation = 0;
134 sea_level_radius = fdmex->GetInertial()->GetRefRadius();
135 position.SetEllipse(fdmex->GetInertial()->GetSemimajor(), fdmex->GetInertial()->GetSemiminor());
136 position.SetPosition(0., 0., sea_level_radius);
137 position.SetEarthPositionAngle(fdmex->GetPropagate()->GetEarthPositionAngle());
138 orientation = FGQuaternion(0.0, 0.0, 0.0);
139 vUVW_NED.InitMatrix();
140 vPQR_body.InitMatrix();
145 Tw2b.InitMatrix(1., 0., 0., 0., 1., 0., 0., 0., 1.);
146 Tb2w.InitMatrix(1., 0., 0., 0., 1., 0., 0., 0., 1.);
149 //******************************************************************************
151 void FGInitialCondition::WriteStateFile(int num)
153 if (Constructing) return;
155 string filename = fdmex->GetFullAircraftPath();
157 if (filename.empty())
158 filename = "initfile.xml";
160 filename.append("/initfile.xml");
162 ofstream outfile(filename.c_str());
163 FGPropagate* Propagate = fdmex->GetPropagate();
165 if (outfile.is_open()) {
166 outfile << "<?xml version=\"1.0\"?>" << endl;
167 outfile << "<initialize name=\"reset00\">" << endl;
168 outfile << " <ubody unit=\"FT/SEC\"> " << Propagate->GetUVW(eU) << " </ubody> " << endl;
169 outfile << " <vbody unit=\"FT/SEC\"> " << Propagate->GetUVW(eV) << " </vbody> " << endl;
170 outfile << " <wbody unit=\"FT/SEC\"> " << Propagate->GetUVW(eW) << " </wbody> " << endl;
171 outfile << " <phi unit=\"DEG\"> " << Propagate->GetEuler(ePhi)*radtodeg << " </phi>" << endl;
172 outfile << " <theta unit=\"DEG\"> " << Propagate->GetEuler(eTht)*radtodeg << " </theta>" << endl;
173 outfile << " <psi unit=\"DEG\"> " << Propagate->GetEuler(ePsi)*radtodeg << " </psi>" << endl;
174 outfile << " <longitude unit=\"DEG\"> " << Propagate->GetLongitudeDeg() << " </longitude>" << endl;
175 outfile << " <latitude unit=\"DEG\"> " << Propagate->GetLatitudeDeg() << " </latitude>" << endl;
176 outfile << " <altitude unit=\"FT\"> " << Propagate->GetDistanceAGL() << " </altitude>" << endl;
177 outfile << "</initialize>" << endl;
180 cerr << "Could not open and/or write the state to the initial conditions file: " << filename << endl;
184 //******************************************************************************
186 void FGInitialCondition::SetVequivalentKtsIC(double ve)
188 double altitudeASL = position.GetRadius() - sea_level_radius;
189 double rho = Atmosphere->GetDensity(altitudeASL);
190 double rhoSL = Atmosphere->GetDensitySL();
191 SetVtrueFpsIC(ve*ktstofps*sqrt(rhoSL/rho));
192 lastSpeedSet = setve;
195 //******************************************************************************
197 void FGInitialCondition::SetMachIC(double mach)
199 double altitudeASL = position.GetRadius() - sea_level_radius;
200 double temperature = Atmosphere->GetTemperature(altitudeASL);
201 double soundSpeed = sqrt(SHRatio*Reng*temperature);
202 SetVtrueFpsIC(mach*soundSpeed);
203 lastSpeedSet = setmach;
206 //******************************************************************************
208 void FGInitialCondition::SetVcalibratedKtsIC(double vcas)
210 double altitudeASL = position.GetRadius() - sea_level_radius;
211 double pressure = Atmosphere->GetPressure(altitudeASL);
212 double pressureSL = Atmosphere->GetPressureSL();
213 double rhoSL = Atmosphere->GetDensitySL();
214 double mach = MachFromVcalibrated(fabs(vcas)*ktstofps, pressure, pressureSL, rhoSL);
215 double temperature = Atmosphere->GetTemperature(altitudeASL);
216 double soundSpeed = sqrt(SHRatio*Reng*temperature);
218 SetVtrueFpsIC(mach*soundSpeed);
219 lastSpeedSet = setvc;
222 //******************************************************************************
223 // Updates alpha and beta according to the aircraft true airspeed in the local
226 void FGInitialCondition::calcAeroAngles(const FGColumnVector3& _vt_NED)
228 const FGMatrix33& Tl2b = orientation.GetT();
229 FGColumnVector3 _vt_BODY = Tl2b * _vt_NED;
230 double ua = _vt_BODY(eX);
231 double va = _vt_BODY(eY);
232 double wa = _vt_BODY(eZ);
233 double uwa = sqrt(ua*ua + wa*wa);
234 double calpha, cbeta;
235 double salpha, sbeta;
238 calpha = cbeta = 1.0;
239 salpha = sbeta = 0.0;
242 alpha = atan2( wa, ua );
244 // alpha cannot be constrained without updating other informations like the
245 // true speed or the Euler angles. Otherwise we might end up with an inconsistent
246 // state of the aircraft.
247 /*alpha = Constrain(fdmex->GetAerodynamics()->GetAlphaCLMin(), alpha,
248 fdmex->GetAerodynamics()->GetAlphaCLMax());*/
251 beta = atan2( va, uwa );
263 Tw2b = FGMatrix33(calpha*cbeta, -calpha*sbeta, -salpha,
265 salpha*cbeta, -salpha*sbeta, calpha);
266 Tb2w = Tw2b.Transposed();
269 //******************************************************************************
270 // Set the ground velocity. Caution it sets the vertical velocity to zero to
271 // keep backward compatibility.
273 void FGInitialCondition::SetVgroundFpsIC(double vg)
275 const FGMatrix33& Tb2l = orientation.GetTInv();
276 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
277 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
279 vUVW_NED(eU) = vg * orientation.GetCosEuler(ePsi);
280 vUVW_NED(eV) = vg * orientation.GetSinEuler(ePsi);
282 _vt_NED = vUVW_NED + _vWIND_NED;
283 vt = _vt_NED.Magnitude();
285 calcAeroAngles(_vt_NED);
287 lastSpeedSet = setvg;
290 //******************************************************************************
291 // Sets the true airspeed. The amplitude of the airspeed is modified but its
292 // direction is kept unchanged. If there is no wind, the same is true for the
293 // ground velocity. If there is some wind, the airspeed direction is unchanged
294 // but this may result in the ground velocity direction being altered. This is
295 // for backward compatibility.
297 void FGInitialCondition::SetVtrueFpsIC(double vtrue)
299 const FGMatrix33& Tb2l = orientation.GetTInv();
300 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
301 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
304 _vt_NED *= vtrue / vt;
306 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vtrue, 0., 0.);
309 vUVW_NED = _vt_NED - _vWIND_NED;
311 calcAeroAngles(_vt_NED);
313 lastSpeedSet = setvt;
316 //******************************************************************************
317 // When the climb rate is modified, we need to update the angles theta and beta
318 // to keep the true airspeed amplitude, the AoA and the heading unchanged.
319 // Beta will be modified if the aircraft roll angle is not null.
321 void FGInitialCondition::SetClimbRateFpsIC(double hdot)
323 if (fabs(hdot) > vt) {
324 cerr << "The climb rate cannot be higher than the true speed." << endl;
328 const FGMatrix33& Tb2l = orientation.GetTInv();
329 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
330 FGColumnVector3 _WIND_NED = _vt_NED - vUVW_NED;
331 double hdot0 = -_vt_NED(eW);
333 if (fabs(hdot0) < vt) { // Is this check really needed ?
334 double scale = sqrt((vt*vt-hdot*hdot)/(vt*vt-hdot0*hdot0));
335 _vt_NED(eU) *= scale;
336 _vt_NED(eV) *= scale;
339 vUVW_NED = _vt_NED - _WIND_NED;
341 // Updating the angles theta and beta to keep the true airspeed amplitude
342 calcThetaBeta(alpha, _vt_NED);
345 //******************************************************************************
346 // When the AoA is modified, we need to update the angles theta and beta to
347 // keep the true airspeed amplitude, the climb rate and the heading unchanged.
348 // Beta will be modified if the aircraft roll angle is not null.
350 void FGInitialCondition::SetAlphaRadIC(double alfa)
352 const FGMatrix33& Tb2l = orientation.GetTInv();
353 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
354 calcThetaBeta(alfa, _vt_NED);
357 //******************************************************************************
358 // When the AoA is modified, we need to update the angles theta and beta to
359 // keep the true airspeed amplitude, the climb rate and the heading unchanged.
360 // Beta will be modified if the aircraft roll angle is not null.
362 void FGInitialCondition::calcThetaBeta(double alfa, const FGColumnVector3& _vt_NED)
364 FGColumnVector3 vOrient = orientation.GetEuler();
365 double calpha = cos(alfa), salpha = sin(alfa);
366 double cpsi = orientation.GetCosEuler(ePsi), spsi = orientation.GetSinEuler(ePsi);
367 double cphi = orientation.GetCosEuler(ePhi), sphi = orientation.GetSinEuler(ePhi);
368 FGMatrix33 Tpsi( cpsi, spsi, 0.,
371 FGMatrix33 Tphi(1., 0., 0.,
374 FGMatrix33 Talpha( calpha, 0., salpha,
376 -salpha, 0., calpha);
378 FGColumnVector3 v0 = Tpsi * _vt_NED;
379 FGColumnVector3 n = (Talpha * Tphi).Transposed() * FGColumnVector3(0., 0., 1.);
380 FGColumnVector3 y = FGColumnVector3(0., 1., 0.);
381 FGColumnVector3 u = y - DotProduct(y, n) * n;
382 FGColumnVector3 p = y * n;
384 if (DotProduct(p, v0) < 0) p *= -1.0;
387 u *= DotProduct(v0, y) / DotProduct(u, y);
389 // There are situations where the desired alpha angle cannot be obtained. This
390 // is not a limitation of the algorithm but is due to the mathematical problem
391 // not having a solution. This can only be cured by limiting the alpha angle
392 // or by modifying an additional angle (psi ?). Since this is anticipated to
393 // be a pathological case (mainly when a high roll angle is required) this
394 // situation is not addressed below. However if there are complaints about the
395 // following error being raised too often, we might need to reconsider this
397 if (DotProduct(v0, v0) < DotProduct(u, u)) {
398 cerr << "Cannot modify angle 'alpha' from " << alpha << " to " << alfa << endl;
402 FGColumnVector3 v1 = u + sqrt(DotProduct(v0, v0) - DotProduct(u, u))*p;
404 FGColumnVector3 v0xz(v0(eU), 0., v0(eW));
405 FGColumnVector3 v1xz(v1(eU), 0., v1(eW));
408 double sinTheta = (v1xz * v0xz)(eY);
409 vOrient(eTht) = asin(sinTheta);
411 orientation = FGQuaternion(vOrient);
413 const FGMatrix33& Tl2b = orientation.GetT();
414 FGColumnVector3 v2 = Talpha * Tl2b * _vt_NED;
417 beta = atan2(v2(eV), v2(eU));
418 double cbeta=1.0, sbeta=0.0;
423 Tw2b = FGMatrix33(calpha*cbeta, -calpha*sbeta, -salpha,
425 salpha*cbeta, -salpha*sbeta, calpha);
426 Tb2w = Tw2b.Transposed();
429 //******************************************************************************
430 // When the beta angle is modified, we need to update the angles theta and psi
431 // to keep the true airspeed (amplitude and direction - including the climb rate)
432 // and the alpha angle unchanged. This may result in the aircraft heading (psi)
433 // being altered especially if there is cross wind.
435 void FGInitialCondition::SetBetaRadIC(double bta)
437 const FGMatrix33& Tb2l = orientation.GetTInv();
438 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
439 FGColumnVector3 vOrient = orientation.GetEuler();
442 double calpha = cos(alpha), salpha = sin(alpha);
443 double cbeta = cos(beta), sbeta = sin(beta);
444 double cphi = orientation.GetCosEuler(ePhi), sphi = orientation.GetSinEuler(ePhi);
445 FGMatrix33 TphiInv(1., 0., 0.,
449 Tw2b = FGMatrix33(calpha*cbeta, -calpha*sbeta, -salpha,
451 salpha*cbeta, -salpha*sbeta, calpha);
452 Tb2w = Tw2b.Transposed();
454 FGColumnVector3 vf = TphiInv * Tw2b * FGColumnVector3(vt, 0., 0.);
455 FGColumnVector3 v0xy(_vt_NED(eX), _vt_NED(eY), 0.);
456 FGColumnVector3 v1xy(sqrt(v0xy(eX)*v0xy(eX)+v0xy(eY)*v0xy(eY)-vf(eY)*vf(eY)),vf(eY),0.);
460 if (vf(eX) < 0.) v0xy(eX) *= -1.0;
462 double sinPsi = (v1xy * v0xy)(eZ);
463 double cosPsi = DotProduct(v0xy, v1xy);
464 vOrient(ePsi) = atan2(sinPsi, cosPsi);
465 FGMatrix33 Tpsi( cosPsi, sinPsi, 0.,
469 FGColumnVector3 v2xz = Tpsi * _vt_NED;
470 FGColumnVector3 vfxz = vf;
471 v2xz(eV) = vfxz(eV) = 0.0;
474 double sinTheta = (v2xz * vfxz)(eY);
475 vOrient(eTht) = -asin(sinTheta);
477 orientation = FGQuaternion(vOrient);
480 //******************************************************************************
481 // Modifies the body frame orientation.
483 void FGInitialCondition::SetEulerAngleRadIC(int idx, double angle)
485 const FGMatrix33& Tb2l = orientation.GetTInv();
486 const FGMatrix33& Tl2b = orientation.GetT();
487 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
488 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
489 FGColumnVector3 _vUVW_BODY = Tl2b * vUVW_NED;
490 FGColumnVector3 vOrient = orientation.GetEuler();
492 vOrient(idx) = angle;
493 orientation = FGQuaternion(vOrient);
495 if ((lastSpeedSet != setned) && (lastSpeedSet != setvg)) {
496 const FGMatrix33& newTb2l = orientation.GetTInv();
497 vUVW_NED = newTb2l * _vUVW_BODY;
498 _vt_NED = vUVW_NED + _vWIND_NED;
499 vt = _vt_NED.Magnitude();
502 calcAeroAngles(_vt_NED);
505 //******************************************************************************
506 // Modifies an aircraft velocity component (eU, eV or eW) in the body frame. The
507 // true airspeed is modified accordingly. If there is some wind, the airspeed
508 // direction modification may differ from the body velocity modification.
510 void FGInitialCondition::SetBodyVelFpsIC(int idx, double vel)
512 const FGMatrix33& Tb2l = orientation.GetTInv();
513 const FGMatrix33& Tl2b = orientation.GetT();
514 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
515 FGColumnVector3 _vUVW_BODY = Tl2b * vUVW_NED;
516 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
518 _vUVW_BODY(idx) = vel;
519 vUVW_NED = Tb2l * _vUVW_BODY;
520 _vt_NED = vUVW_NED + _vWIND_NED;
521 vt = _vt_NED.Magnitude();
523 calcAeroAngles(_vt_NED);
525 lastSpeedSet = setuvw;
528 //******************************************************************************
529 // Modifies an aircraft velocity component (eX, eY or eZ) in the local NED frame.
530 // The true airspeed is modified accordingly. If there is some wind, the airspeed
531 // direction modification may differ from the local velocity modification.
533 void FGInitialCondition::SetNEDVelFpsIC(int idx, double vel)
535 const FGMatrix33& Tb2l = orientation.GetTInv();
536 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
537 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
540 _vt_NED = vUVW_NED + _vWIND_NED;
541 vt = _vt_NED.Magnitude();
543 calcAeroAngles(_vt_NED);
545 lastSpeedSet = setned;
548 //******************************************************************************
549 // Set wind amplitude and direction in the local NED frame. The aircraft velocity
550 // with respect to the ground is not changed but the true airspeed is.
552 void FGInitialCondition::SetWindNEDFpsIC(double wN, double wE, double wD )
554 FGColumnVector3 _vt_NED = vUVW_NED + FGColumnVector3(wN, wE, wD);
555 vt = _vt_NED.Magnitude();
557 calcAeroAngles(_vt_NED);
560 //******************************************************************************
561 // Set the cross wind velocity (in knots). Here, 'cross wind' means perpendicular
562 // to the aircraft heading and parallel to the ground. The aircraft velocity
563 // with respect to the ground is not changed but the true airspeed is.
565 void FGInitialCondition::SetCrossWindKtsIC(double cross)
567 const FGMatrix33& Tb2l = orientation.GetTInv();
568 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
569 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
570 FGColumnVector3 _vCROSS(-orientation.GetSinEuler(ePsi), orientation.GetCosEuler(ePsi), 0.);
572 // Gram-Schmidt process is used to remove the existing cross wind component
573 _vWIND_NED -= DotProduct(_vWIND_NED, _vCROSS) * _vCROSS;
574 // Which is now replaced by the new value. The input cross wind is expected
575 // in knots, so first convert to fps, which is the internal unit used.
576 _vWIND_NED += (cross * ktstofps) * _vCROSS;
577 _vt_NED = vUVW_NED + _vWIND_NED;
578 vt = _vt_NED.Magnitude();
580 calcAeroAngles(_vt_NED);
583 //******************************************************************************
584 // Set the head wind velocity (in knots). Here, 'head wind' means parallel
585 // to the aircraft heading and to the ground. The aircraft velocity
586 // with respect to the ground is not changed but the true airspeed is.
588 void FGInitialCondition::SetHeadWindKtsIC(double head)
590 const FGMatrix33& Tb2l = orientation.GetTInv();
591 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
592 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
593 // This is a head wind, so the direction vector for the wind
594 // needs to be set opposite to the heading the aircraft
595 // is taking. So, the cos and sin of the heading (psi)
596 // are negated in the line below.
597 FGColumnVector3 _vHEAD(-orientation.GetCosEuler(ePsi), -orientation.GetSinEuler(ePsi), 0.);
599 // Gram-Schmidt process is used to remove the existing head wind component
600 _vWIND_NED -= DotProduct(_vWIND_NED, _vHEAD) * _vHEAD;
601 // Which is now replaced by the new value. The input head wind is expected
602 // in knots, so first convert to fps, which is the internal unit used.
603 _vWIND_NED += (head * ktstofps) * _vHEAD;
604 _vt_NED = vUVW_NED + _vWIND_NED;
606 vt = _vt_NED.Magnitude();
608 calcAeroAngles(_vt_NED);
611 //******************************************************************************
612 // Set the vertical wind velocity (in knots). The 'vertical' is taken in the
613 // local NED frame. The aircraft velocity with respect to the ground is not
614 // changed but the true airspeed is.
616 void FGInitialCondition::SetWindDownKtsIC(double wD)
618 const FGMatrix33& Tb2l = orientation.GetTInv();
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 const FGMatrix33& Tb2l = orientation.GetTInv();
635 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
636 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
637 FGColumnVector3 _vHEAD(_vWIND_NED(eU), _vWIND_NED(eV), 0.);
638 double windMag = _vHEAD.Magnitude();
641 _vHEAD *= (mag*ktstofps) / windMag;
643 _vHEAD = FGColumnVector3((mag*ktstofps), 0., 0.);
645 _vWIND_NED(eU) = _vHEAD(eU);
646 _vWIND_NED(eV) = _vHEAD(eV);
647 _vt_NED = vUVW_NED + _vWIND_NED;
648 vt = _vt_NED.Magnitude();
650 calcAeroAngles(_vt_NED);
653 //******************************************************************************
654 // Modifies the wind direction while keeping its velocity unchanged. The vertical
655 // component (in local NED frame) is unmodified. The aircraft velocity with
656 // respect to the ground is not changed but the true airspeed is.
658 void FGInitialCondition::SetWindDirDegIC(double dir)
660 const FGMatrix33& Tb2l = orientation.GetTInv();
661 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
662 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
663 double mag = _vWIND_NED.Magnitude(eU, eV);
664 FGColumnVector3 _vHEAD(mag*cos(dir*degtorad), mag*sin(dir*degtorad), 0.);
666 _vWIND_NED(eU) = _vHEAD(eU);
667 _vWIND_NED(eV) = _vHEAD(eV);
668 _vt_NED = vUVW_NED + _vWIND_NED;
669 vt = _vt_NED.Magnitude();
671 calcAeroAngles(_vt_NED);
674 //******************************************************************************
675 // Set the altitude SL. If the airspeed has been previously set with parameters
676 // that are atmosphere dependent (Mach, VCAS, VEAS) then the true airspeed is
677 // modified to keep the last set speed to its previous value.
679 void FGInitialCondition::SetAltitudeASLFtIC(double alt)
681 double altitudeASL = position.GetRadius() - sea_level_radius;
682 double temperature = Atmosphere->GetTemperature(altitudeASL);
683 double pressure = Atmosphere->GetPressure(altitudeASL);
684 double pressureSL = Atmosphere->GetPressureSL();
685 double soundSpeed = sqrt(SHRatio*Reng*temperature);
686 double rho = Atmosphere->GetDensity(altitudeASL);
687 double rhoSL = Atmosphere->GetDensitySL();
689 double mach0 = vt / soundSpeed;
690 double vc0 = VcalibratedFromMach(mach0, pressure, pressureSL, rhoSL);
691 double ve0 = vt * sqrt(rho/rhoSL);
694 position.SetRadius(alt + sea_level_radius);
696 temperature = Atmosphere->GetTemperature(altitudeASL);
697 soundSpeed = sqrt(SHRatio*Reng*temperature);
698 rho = Atmosphere->GetDensity(altitudeASL);
699 pressure = Atmosphere->GetPressure(altitudeASL);
701 switch(lastSpeedSet) {
703 mach0 = MachFromVcalibrated(vc0, pressure, pressureSL, rhoSL);
704 SetVtrueFpsIC(mach0 * soundSpeed);
707 SetVtrueFpsIC(mach0 * soundSpeed);
710 SetVtrueFpsIC(ve0 * sqrt(rhoSL/rho));
712 default: // Make the compiler stop complaining about missing enums
717 //******************************************************************************
719 double FGInitialCondition::GetWindDirDegIC(void) const
721 const FGMatrix33& Tb2l = orientation.GetTInv();
722 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
723 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
725 return _vWIND_NED(eV) == 0.0 ? 0.0
726 : atan2(_vWIND_NED(eV), _vWIND_NED(eU))*radtodeg;
729 //******************************************************************************
731 double FGInitialCondition::GetNEDWindFpsIC(int idx) const
733 const FGMatrix33& Tb2l = orientation.GetTInv();
734 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
735 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
737 return _vWIND_NED(idx);
740 //******************************************************************************
742 double FGInitialCondition::GetWindFpsIC(void) const
744 const FGMatrix33& Tb2l = orientation.GetTInv();
745 FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
746 FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
748 return _vWIND_NED.Magnitude(eU, eV);
751 //******************************************************************************
753 double FGInitialCondition::GetBodyWindFpsIC(int idx) const
755 const FGMatrix33& Tl2b = orientation.GetT();
756 FGColumnVector3 _vt_BODY = Tw2b * FGColumnVector3(vt, 0., 0.);
757 FGColumnVector3 _vUVW_BODY = Tl2b * vUVW_NED;
758 FGColumnVector3 _vWIND_BODY = _vt_BODY - _vUVW_BODY;
760 return _vWIND_BODY(idx);
763 //******************************************************************************
765 double FGInitialCondition::GetVcalibratedKtsIC(void) const
767 double altitudeASL = position.GetRadius() - sea_level_radius;
768 double temperature = Atmosphere->GetTemperature(altitudeASL);
769 double pressure = Atmosphere->GetPressure(altitudeASL);
770 double pressureSL = Atmosphere->GetPressureSL();
771 double rhoSL = Atmosphere->GetDensitySL();
772 double soundSpeed = sqrt(SHRatio*Reng*temperature);
773 double mach = vt / soundSpeed;
774 return fpstokts * VcalibratedFromMach(mach, pressure, pressureSL, rhoSL);
777 //******************************************************************************
779 double FGInitialCondition::GetVequivalentKtsIC(void) const
781 double altitudeASL = position.GetRadius() - sea_level_radius;
782 double rho = Atmosphere->GetDensity(altitudeASL);
783 double rhoSL = Atmosphere->GetDensitySL();
784 return fpstokts * vt * sqrt(rho/rhoSL);
787 //******************************************************************************
789 double FGInitialCondition::GetMachIC(void) const
791 double altitudeASL = position.GetRadius() - sea_level_radius;
792 double temperature = Atmosphere->GetTemperature(altitudeASL);
793 double soundSpeed = sqrt(SHRatio*Reng*temperature);
794 return vt / soundSpeed;
797 //******************************************************************************
799 double FGInitialCondition::GetBodyVelFpsIC(int idx) const
801 const FGMatrix33& Tl2b = orientation.GetT();
802 FGColumnVector3 _vUVW_BODY = Tl2b * vUVW_NED;
804 return _vUVW_BODY(idx);
807 //******************************************************************************
809 bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
812 if( useStoredPath ) {
813 init_file_name = fdmex->GetFullAircraftPath() + sep + rstfile + ".xml";
815 init_file_name = rstfile;
818 document = LoadXMLDocument(init_file_name);
820 // Make sure that the document is valid
822 cerr << "File: " << init_file_name << " could not be read." << endl;
826 if (document->GetName() != string("initialize")) {
827 cerr << "File: " << init_file_name << " is not a reset file." << endl;
831 double version = document->GetAttributeValueAsNumber("version");
834 if (version == HUGE_VAL) {
835 result = Load_v1(); // Default to the old version
836 } else if (version >= 3.0) {
837 cerr << "Only initialization file formats 1 and 2 are currently supported" << endl;
839 } else if (version >= 2.0) {
841 } else if (version >= 1.0) {
847 // Check to see if any engines are specified to be initialized in a running state
848 FGPropulsion* propulsion = fdmex->GetPropulsion();
849 Element* running_elements = document->FindElement("running");
850 while (running_elements) {
851 int n = int(running_elements->GetDataAsNumber());
853 propulsion->InitRunning(n);
854 } catch (string str) {
858 running_elements = document->FindNextElement("running");
864 //******************************************************************************
866 bool FGInitialCondition::Load_v1(void)
870 if (document->FindElement("latitude"))
871 position.SetLatitude(document->FindElementValueAsNumberConvertTo("latitude", "RAD"));
872 if (document->FindElement("longitude"))
873 position.SetLongitude(document->FindElementValueAsNumberConvertTo("longitude", "RAD"));
874 if (document->FindElement("elevation"))
875 terrain_elevation = document->FindElementValueAsNumberConvertTo("elevation", "FT");
877 if (document->FindElement("altitude")) // This is feet above ground level
878 position.SetRadius(document->FindElementValueAsNumberConvertTo("altitude", "FT") + terrain_elevation + sea_level_radius);
879 else if (document->FindElement("altitudeAGL")) // This is feet above ground level
880 position.SetRadius(document->FindElementValueAsNumberConvertTo("altitudeAGL", "FT") + terrain_elevation + sea_level_radius);
881 else if (document->FindElement("altitudeMSL")) // This is feet above sea level
882 position.SetRadius(document->FindElementValueAsNumberConvertTo("altitudeMSL", "FT") + sea_level_radius);
884 FGColumnVector3 vOrient = orientation.GetEuler();
886 if (document->FindElement("phi"))
887 vOrient(ePhi) = document->FindElementValueAsNumberConvertTo("phi", "RAD");
888 if (document->FindElement("theta"))
889 vOrient(eTht) = document->FindElementValueAsNumberConvertTo("theta", "RAD");
890 if (document->FindElement("psi"))
891 vOrient(ePsi) = document->FindElementValueAsNumberConvertTo("psi", "RAD");
893 orientation = FGQuaternion(vOrient);
895 if (document->FindElement("ubody"))
896 SetUBodyFpsIC(document->FindElementValueAsNumberConvertTo("ubody", "FT/SEC"));
897 if (document->FindElement("vbody"))
898 SetVBodyFpsIC(document->FindElementValueAsNumberConvertTo("vbody", "FT/SEC"));
899 if (document->FindElement("wbody"))
900 SetWBodyFpsIC(document->FindElementValueAsNumberConvertTo("wbody", "FT/SEC"));
901 if (document->FindElement("vnorth"))
902 SetVNorthFpsIC(document->FindElementValueAsNumberConvertTo("vnorth", "FT/SEC"));
903 if (document->FindElement("veast"))
904 SetVEastFpsIC(document->FindElementValueAsNumberConvertTo("veast", "FT/SEC"));
905 if (document->FindElement("vdown"))
906 SetVDownFpsIC(document->FindElementValueAsNumberConvertTo("vdown", "FT/SEC"));
907 if (document->FindElement("vc"))
908 SetVcalibratedKtsIC(document->FindElementValueAsNumberConvertTo("vc", "KTS"));
909 if (document->FindElement("vt"))
910 SetVtrueKtsIC(document->FindElementValueAsNumberConvertTo("vt", "KTS"));
911 if (document->FindElement("mach"))
912 SetMachIC(document->FindElementValueAsNumber("mach"));
913 if (document->FindElement("gamma"))
914 SetFlightPathAngleDegIC(document->FindElementValueAsNumberConvertTo("gamma", "DEG"));
915 if (document->FindElement("roc"))
916 SetClimbRateFpsIC(document->FindElementValueAsNumberConvertTo("roc", "FT/SEC"));
917 if (document->FindElement("vground"))
918 SetVgroundKtsIC(document->FindElementValueAsNumberConvertTo("vground", "KTS"));
919 if (document->FindElement("alpha"))
920 SetAlphaDegIC(document->FindElementValueAsNumberConvertTo("alpha", "DEG"));
921 if (document->FindElement("beta"))
922 SetBetaDegIC(document->FindElementValueAsNumberConvertTo("beta", "DEG"));
923 if (document->FindElement("vwind"))
924 SetWindMagKtsIC(document->FindElementValueAsNumberConvertTo("vwind", "KTS"));
925 if (document->FindElement("winddir"))
926 SetWindDirDegIC(document->FindElementValueAsNumberConvertTo("winddir", "DEG"));
927 if (document->FindElement("hwind"))
928 SetHeadWindKtsIC(document->FindElementValueAsNumberConvertTo("hwind", "KTS"));
929 if (document->FindElement("xwind"))
930 SetCrossWindKtsIC(document->FindElementValueAsNumberConvertTo("xwind", "KTS"));
931 if (document->FindElement("targetNlf"))
933 SetTargetNlfIC(document->FindElementValueAsNumber("targetNlf"));
936 // Refer to Stevens and Lewis, 1.5-14a, pg. 49.
937 // This is the rotation rate of the "Local" frame, expressed in the local frame.
938 double radInv = 1.0 / position.GetRadius();
939 FGColumnVector3 vOmegaLocal = FGColumnVector3(
940 radInv*vUVW_NED(eEast),
941 -radInv*vUVW_NED(eNorth),
942 -radInv*vUVW_NED(eEast)*position.GetTanLatitude() );
944 vPQR_body = vOmegaLocal;
949 //******************************************************************************
951 bool FGInitialCondition::Load_v2(void)
953 FGColumnVector3 vOrient;
955 FGColumnVector3 vOmegaEarth = fdmex->GetInertial()->GetOmegaPlanet();
957 if (document->FindElement("earth_position_angle"))
958 position.SetEarthPositionAngle(document->FindElementValueAsNumberConvertTo("earth_position_angle", "RAD"));
960 if (document->FindElement("elevation"))
961 terrain_elevation = document->FindElementValueAsNumberConvertTo("elevation", "FT");
963 // Initialize vehicle position
966 // - ECI (Earth Centered Inertial)
967 // - ECEF (Earth Centered, Earth Fixed)
969 Element* position_el = document->FindElement("position");
971 string frame = position_el->GetAttributeValue("frame");
972 frame = to_lower(frame);
973 if (frame == "eci") { // Need to transform vLoc to ECEF for storage and use in FGLocation.
974 position = position.GetTi2ec() * position_el->FindElementTripletConvertTo("FT");
975 } else if (frame == "ecef") {
976 if (!position_el->FindElement("x") && !position_el->FindElement("y") && !position_el->FindElement("z")) {
977 if (position_el->FindElement("radius")) {
978 position.SetRadius(position_el->FindElementValueAsNumberConvertTo("radius", "FT"));
979 } else if (position_el->FindElement("altitudeAGL")) {
980 position.SetRadius(sea_level_radius + terrain_elevation + position_el->FindElementValueAsNumberConvertTo("altitudeAGL", "FT"));
981 } else if (position_el->FindElement("altitudeMSL")) {
982 position.SetRadius(sea_level_radius + position_el->FindElementValueAsNumberConvertTo("altitudeMSL", "FT"));
984 cerr << endl << " No altitude or radius initial condition is given." << endl;
987 if (position_el->FindElement("longitude"))
988 position.SetLongitude(position_el->FindElementValueAsNumberConvertTo("longitude", "RAD"));
989 if (position_el->FindElement("latitude"))
990 position.SetLatitude(position_el->FindElementValueAsNumberConvertTo("latitude", "RAD"));
992 position = position_el->FindElementTripletConvertTo("FT");
995 cerr << endl << " Neither ECI nor ECEF frame is specified for initial position." << endl;
999 cerr << endl << " Initial position not specified in this initialization file." << endl;
1003 // End of position initialization
1005 // Initialize vehicle orientation
1007 // - ECI (Earth Centered Inertial)
1008 // - ECEF (Earth Centered, Earth Fixed)
1011 // Need to convert the provided orientation to a local orientation, using
1012 // the given orientation and knowledge of the Earth position angle.
1013 // This could be done using matrices (where in the subscript "b/a",
1014 // it is meant "b with respect to a", and where b=body frame,
1015 // i=inertial frame, l=local NED frame and e=ecef frame) as:
1017 // C_b/l = C_b/e * C_e/l
1019 // Using quaternions (note reverse ordering compared to matrix representation):
1021 // Q_b/l = Q_e/l * Q_b/e
1023 // Use the specific matrices as needed. The above example of course is for the whole
1024 // body to local orientation.
1025 // The new orientation angles can be extracted from the matrix or the quaternion.
1026 // ToDo: Do we need to deal with normalization of the quaternions here?
1028 Element* orientation_el = document->FindElement("orientation");
1029 if (orientation_el) {
1030 string frame = orientation_el->GetAttributeValue("frame");
1031 frame = to_lower(frame);
1032 vOrient = orientation_el->FindElementTripletConvertTo("RAD");
1033 if (frame == "eci") {
1035 // In this case, we are supplying the Euler angles for the vehicle with
1036 // respect to the inertial system, represented by the C_b/i Matrix.
1037 // We want the body orientation with respect to the local (NED frame):
1039 // C_b/l = C_b/i * C_i/l
1041 // Or, using quaternions (note reverse ordering compared to matrix representation):
1043 // Q_b/l = Q_i/l * Q_b/i
1045 FGQuaternion QuatI2Body = FGQuaternion(vOrient);
1046 QuatI2Body.Normalize();
1047 FGQuaternion QuatLocal2I = position.GetTl2i();
1048 QuatLocal2I.Normalize();
1049 orientation = QuatLocal2I * QuatI2Body;
1051 } else if (frame == "ecef") {
1053 // In this case we are given the Euler angles representing the orientation of
1054 // the body with respect to the ECEF system, represented by the C_b/e Matrix.
1055 // We want the body orientation with respect to the local (NED frame):
1057 // C_b/l = C_b/e * C_e/l
1059 // Using quaternions (note reverse ordering compared to matrix representation):
1061 // Q_b/l = Q_e/l * Q_b/e
1063 FGQuaternion QuatEC2Body(vOrient); // Store relationship of Body frame wrt ECEF frame, Q_b/e
1064 QuatEC2Body.Normalize();
1065 FGQuaternion QuatLocal2EC = position.GetTl2ec(); // Get Q_e/l from matrix
1066 QuatLocal2EC.Normalize();
1067 orientation = QuatLocal2EC * QuatEC2Body; // Q_b/l = Q_e/l * Q_b/e
1069 } else if (frame == "local") {
1071 orientation = FGQuaternion(vOrient);
1075 cerr << endl << fgred << " Orientation frame type: \"" << frame
1076 << "\" is not supported!" << reset << endl << endl;
1082 // Initialize vehicle velocity
1084 // - ECI (Earth Centered Inertial)
1085 // - ECEF (Earth Centered, Earth Fixed)
1088 // The vehicle will be defaulted to (0,0,0) in the Body frame if nothing is provided.
1090 Element* velocity_el = document->FindElement("velocity");
1091 FGColumnVector3 vInitVelocity = FGColumnVector3(0.0, 0.0, 0.0);
1092 FGMatrix33 mTec2l = position.GetTec2l();
1093 const FGMatrix33& Tb2l = orientation.GetTInv();
1097 string frame = velocity_el->GetAttributeValue("frame");
1098 frame = to_lower(frame);
1099 FGColumnVector3 vInitVelocity = velocity_el->FindElementTripletConvertTo("FT/SEC");
1101 if (frame == "eci") {
1102 FGColumnVector3 omega_cross_r = vOmegaEarth * (position.GetTec2i() * position);
1103 vUVW_NED = mTec2l * (vInitVelocity - omega_cross_r);
1104 } else if (frame == "ecef") {
1105 vUVW_NED = mTec2l * vInitVelocity;
1106 } else if (frame == "local") {
1107 vUVW_NED = vInitVelocity;
1108 lastSpeedSet = setned;
1109 } else if (frame == "body") {
1110 vUVW_NED = Tb2l * vInitVelocity;
1111 lastSpeedSet = setuvw;
1114 cerr << endl << fgred << " Velocity frame type: \"" << frame
1115 << "\" is not supported!" << reset << endl << endl;
1122 vUVW_NED = Tb2l * vInitVelocity;
1126 vt = vUVW_NED.Magnitude();
1128 calcAeroAngles(vUVW_NED);
1130 // Initialize vehicle body rates
1132 // - ECI (Earth Centered Inertial)
1133 // - ECEF (Earth Centered, Earth Fixed)
1136 Element* attrate_el = document->FindElement("attitude_rate");
1137 const FGMatrix33& Tl2b = orientation.GetT();
1139 // Refer to Stevens and Lewis, 1.5-14a, pg. 49.
1140 // This is the rotation rate of the "Local" frame, expressed in the local frame.
1141 double radInv = 1.0 / position.GetRadius();
1142 FGColumnVector3 vOmegaLocal = FGColumnVector3(
1143 radInv*vUVW_NED(eEast),
1144 -radInv*vUVW_NED(eNorth),
1145 -radInv*vUVW_NED(eEast)*position.GetTanLatitude() );
1149 string frame = attrate_el->GetAttributeValue("frame");
1150 frame = to_lower(frame);
1151 FGColumnVector3 vAttRate = attrate_el->FindElementTripletConvertTo("RAD/SEC");
1153 if (frame == "eci") {
1154 vPQR_body = Tl2b * position.GetTi2l() * (vAttRate - vOmegaEarth);
1155 } else if (frame == "ecef") {
1156 vPQR_body = Tl2b * position.GetTec2l() * vAttRate;
1157 } else if (frame == "local") {
1158 vPQR_body = vAttRate + vOmegaLocal;
1159 } else if (!frame.empty()) { // misspelling of frame
1161 cerr << endl << fgred << " Attitude rate frame type: \"" << frame
1162 << "\" is not supported!" << reset << endl << endl;
1165 } else if (frame.empty()) {
1166 vPQR_body = vOmegaLocal;
1169 } else { // Body frame attitude rate assumed 0 relative to local.
1170 vPQR_body = vOmegaLocal;
1176 //******************************************************************************
1178 void FGInitialCondition::bind(void)
1180 PropertyManager->Tie("ic/vc-kts", this,
1181 &FGInitialCondition::GetVcalibratedKtsIC,
1182 &FGInitialCondition::SetVcalibratedKtsIC,
1184 PropertyManager->Tie("ic/ve-kts", this,
1185 &FGInitialCondition::GetVequivalentKtsIC,
1186 &FGInitialCondition::SetVequivalentKtsIC,
1188 PropertyManager->Tie("ic/vg-kts", this,
1189 &FGInitialCondition::GetVgroundKtsIC,
1190 &FGInitialCondition::SetVgroundKtsIC,
1192 PropertyManager->Tie("ic/vt-kts", this,
1193 &FGInitialCondition::GetVtrueKtsIC,
1194 &FGInitialCondition::SetVtrueKtsIC,
1196 PropertyManager->Tie("ic/mach", this,
1197 &FGInitialCondition::GetMachIC,
1198 &FGInitialCondition::SetMachIC,
1200 PropertyManager->Tie("ic/roc-fpm", this,
1201 &FGInitialCondition::GetClimbRateFpmIC,
1202 &FGInitialCondition::SetClimbRateFpmIC,
1204 PropertyManager->Tie("ic/gamma-deg", this,
1205 &FGInitialCondition::GetFlightPathAngleDegIC,
1206 &FGInitialCondition::SetFlightPathAngleDegIC,
1208 PropertyManager->Tie("ic/alpha-deg", this,
1209 &FGInitialCondition::GetAlphaDegIC,
1210 &FGInitialCondition::SetAlphaDegIC,
1212 PropertyManager->Tie("ic/beta-deg", this,
1213 &FGInitialCondition::GetBetaDegIC,
1214 &FGInitialCondition::SetBetaDegIC,
1216 PropertyManager->Tie("ic/theta-deg", this,
1217 &FGInitialCondition::GetThetaDegIC,
1218 &FGInitialCondition::SetThetaDegIC,
1220 PropertyManager->Tie("ic/phi-deg", this,
1221 &FGInitialCondition::GetPhiDegIC,
1222 &FGInitialCondition::SetPhiDegIC,
1224 PropertyManager->Tie("ic/psi-true-deg", this,
1225 &FGInitialCondition::GetPsiDegIC,
1226 &FGInitialCondition::SetPsiDegIC,
1228 PropertyManager->Tie("ic/lat-gc-deg", this,
1229 &FGInitialCondition::GetLatitudeDegIC,
1230 &FGInitialCondition::SetLatitudeDegIC,
1232 PropertyManager->Tie("ic/long-gc-deg", this,
1233 &FGInitialCondition::GetLongitudeDegIC,
1234 &FGInitialCondition::SetLongitudeDegIC,
1236 PropertyManager->Tie("ic/h-sl-ft", this,
1237 &FGInitialCondition::GetAltitudeASLFtIC,
1238 &FGInitialCondition::SetAltitudeASLFtIC,
1240 PropertyManager->Tie("ic/h-agl-ft", this,
1241 &FGInitialCondition::GetAltitudeAGLFtIC,
1242 &FGInitialCondition::SetAltitudeAGLFtIC,
1244 PropertyManager->Tie("ic/terrain-elevation-ft", this,
1245 &FGInitialCondition::GetTerrainElevationFtIC,
1246 &FGInitialCondition::SetTerrainElevationFtIC,
1248 PropertyManager->Tie("ic/vg-fps", this,
1249 &FGInitialCondition::GetVgroundFpsIC,
1250 &FGInitialCondition::SetVgroundFpsIC,
1252 PropertyManager->Tie("ic/vt-fps", this,
1253 &FGInitialCondition::GetVtrueFpsIC,
1254 &FGInitialCondition::SetVtrueFpsIC,
1256 PropertyManager->Tie("ic/vw-bx-fps", this,
1257 &FGInitialCondition::GetWindUFpsIC);
1258 PropertyManager->Tie("ic/vw-by-fps", this,
1259 &FGInitialCondition::GetWindVFpsIC);
1260 PropertyManager->Tie("ic/vw-bz-fps", this,
1261 &FGInitialCondition::GetWindWFpsIC);
1262 PropertyManager->Tie("ic/vw-north-fps", this,
1263 &FGInitialCondition::GetWindNFpsIC);
1264 PropertyManager->Tie("ic/vw-east-fps", this,
1265 &FGInitialCondition::GetWindEFpsIC);
1266 PropertyManager->Tie("ic/vw-down-fps", this,
1267 &FGInitialCondition::GetWindDFpsIC);
1268 PropertyManager->Tie("ic/vw-mag-fps", this,
1269 &FGInitialCondition::GetWindFpsIC);
1270 PropertyManager->Tie("ic/vw-dir-deg", this,
1271 &FGInitialCondition::GetWindDirDegIC,
1272 &FGInitialCondition::SetWindDirDegIC,
1275 PropertyManager->Tie("ic/roc-fps", this,
1276 &FGInitialCondition::GetClimbRateFpsIC,
1277 &FGInitialCondition::SetClimbRateFpsIC,
1279 PropertyManager->Tie("ic/u-fps", this,
1280 &FGInitialCondition::GetUBodyFpsIC,
1281 &FGInitialCondition::SetUBodyFpsIC,
1283 PropertyManager->Tie("ic/v-fps", this,
1284 &FGInitialCondition::GetVBodyFpsIC,
1285 &FGInitialCondition::SetVBodyFpsIC,
1287 PropertyManager->Tie("ic/w-fps", this,
1288 &FGInitialCondition::GetWBodyFpsIC,
1289 &FGInitialCondition::SetWBodyFpsIC,
1291 PropertyManager->Tie("ic/vn-fps", this,
1292 &FGInitialCondition::GetVNorthFpsIC,
1293 &FGInitialCondition::SetVNorthFpsIC,
1295 PropertyManager->Tie("ic/ve-fps", this,
1296 &FGInitialCondition::GetVEastFpsIC,
1297 &FGInitialCondition::SetVEastFpsIC,
1299 PropertyManager->Tie("ic/vd-fps", this,
1300 &FGInitialCondition::GetVDownFpsIC,
1301 &FGInitialCondition::SetVDownFpsIC,
1303 PropertyManager->Tie("ic/gamma-rad", this,
1304 &FGInitialCondition::GetFlightPathAngleRadIC,
1305 &FGInitialCondition::SetFlightPathAngleRadIC,
1307 PropertyManager->Tie("ic/alpha-rad", this,
1308 &FGInitialCondition::GetAlphaRadIC,
1309 &FGInitialCondition::SetAlphaRadIC,
1311 PropertyManager->Tie("ic/theta-rad", this,
1312 &FGInitialCondition::GetThetaRadIC,
1313 &FGInitialCondition::SetThetaRadIC,
1315 PropertyManager->Tie("ic/beta-rad", this,
1316 &FGInitialCondition::GetBetaRadIC,
1317 &FGInitialCondition::SetBetaRadIC,
1319 PropertyManager->Tie("ic/phi-rad", this,
1320 &FGInitialCondition::GetPhiRadIC,
1321 &FGInitialCondition::SetPhiRadIC,
1323 PropertyManager->Tie("ic/psi-true-rad", this,
1324 &FGInitialCondition::GetPsiRadIC,
1325 &FGInitialCondition::SetPsiRadIC,
1327 PropertyManager->Tie("ic/lat-gc-rad", this,
1328 &FGInitialCondition::GetLatitudeRadIC,
1329 &FGInitialCondition::SetLatitudeRadIC,
1331 PropertyManager->Tie("ic/long-gc-rad", this,
1332 &FGInitialCondition::GetLongitudeRadIC,
1333 &FGInitialCondition::SetLongitudeRadIC,
1335 PropertyManager->Tie("ic/p-rad_sec", this,
1336 &FGInitialCondition::GetPRadpsIC,
1337 &FGInitialCondition::SetPRadpsIC,
1339 PropertyManager->Tie("ic/q-rad_sec", this,
1340 &FGInitialCondition::GetQRadpsIC,
1341 &FGInitialCondition::SetQRadpsIC,
1343 PropertyManager->Tie("ic/r-rad_sec", this,
1344 &FGInitialCondition::GetRRadpsIC,
1345 &FGInitialCondition::SetRRadpsIC,
1348 typedef int (FGInitialCondition::*iPMF)(void) const;
1349 PropertyManager->Tie("simulation/write-state-file",
1352 &FGInitialCondition::WriteStateFile);
1356 //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1357 // The bitmasked value choices are as follows:
1358 // unset: In this case (the default) JSBSim would only print
1359 // out the normally expected messages, essentially echoing
1360 // the config files as they are read. If the environment
1361 // variable is not set, debug_lvl is set to 1 internally
1362 // 0: This requests JSBSim not to output any messages
1364 // 1: This value explicity requests the normal JSBSim
1366 // 2: This value asks for a message to be printed out when
1367 // a class is instantiated
1368 // 4: When this value is set, a message is displayed when a
1369 // FGModel object executes its Run() method
1370 // 8: When this value is set, various runtime state variables
1371 // are printed out periodically
1372 // 16: When set various parameters are sanity checked and
1373 // a message is printed out when they go out of bounds
1375 void FGInitialCondition::Debug(int from)
1377 if (debug_lvl <= 0) return;
1379 if (debug_lvl & 1) { // Standard console startup message output
1381 if (debug_lvl & 2 ) { // Instantiation/Destruction notification
1382 if (from == 0) cout << "Instantiated: FGInitialCondition" << endl;
1383 if (from == 1) cout << "Destroyed: FGInitialCondition" << endl;
1385 if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
1387 if (debug_lvl & 8 ) { // Runtime state variables
1389 if (debug_lvl & 16) { // Sanity checking
1391 if (debug_lvl & 64) {
1392 if (from == 0) { // Constructor
1393 cout << IdSrc << endl;
1394 cout << IdHdr << endl;