68 #include "FGPropagate.h"
69 #include "initialization/FGInitialCondition.h"
70 #include "FGFDMExec.h"
71 #include "simgear/io/iostreams/sgstream.hxx"
72 #include "FGInertial.h"
93 integrator_rotational_rate = eRectEuler;
94 integrator_translational_rate = eAdamsBashforth2;
95 integrator_rotational_position = eRectEuler;
96 integrator_translational_position = eAdamsBashforth3;
120 if (!FGModel::InitModel())
return false;
131 integrator_rotational_rate = eRectEuler;
132 integrator_translational_rate = eAdamsBashforth2;
133 integrator_rotational_position = eRectEuler;
134 integrator_translational_position = eAdamsBashforth3;
151 Ti2ec = { cos(epa), sin(epa), 0.0,
152 -sin(epa), cos(epa), 0.0,
156 VState.vInertialPosition = Tec2i * VState.
vLocation;
158 UpdateLocationMatrices();
166 UpdateBodyMatrices();
172 vVel = Tb2l * VState.
vUVW;
175 RecomputeLocalTerrainVelocity();
181 VState.
vPQRi = VState.
vPQR + Ti2b * in.vOmegaPlanet;
183 CalculateInertialVelocity();
190 void FGPropagate::InitializeDerivatives()
192 VState.dqPQRidot.assign(5, in.vPQRidot);
193 VState.dqUVWidot.assign(5, in.vUVWidot);
194 VState.dqInertialVelocity.assign(5, VState.vInertialVelocity);
195 VState.dqQtrndot.assign(5, VState.vQtrndot);
221 if (Holding)
return false;
223 double dt = in.DeltaT * rate;
228 Integrate(VState.
qAttitudeECI, VState.vQtrndot, VState.dqQtrndot, dt, integrator_rotational_position);
229 Integrate(VState.
vPQRi, in.vPQRidot, VState.dqPQRidot, dt, integrator_rotational_rate);
230 Integrate(VState.vInertialPosition, VState.vInertialVelocity, VState.dqInertialVelocity, dt, integrator_translational_position);
231 Integrate(VState.vInertialVelocity, in.vUVWidot, VState.dqUVWidot, dt, integrator_translational_rate);
239 epa += in.vOmegaPlanet(eZ)*dt;
242 double cos_epa = cos(epa);
243 double sin_epa = sin(epa);
244 Ti2ec = { cos_epa, sin_epa, 0.0,
245 -sin_epa, cos_epa, 0.0,
250 VState.
vLocation = Ti2ec*VState.vInertialPosition;
254 UpdateLocationMatrices();
258 UpdateBodyMatrices();
265 RecomputeLocalTerrainVelocity();
267 VState.
vPQR = VState.
vPQRi - Ti2b * in.vOmegaPlanet;
276 vVel = Tb2l * VState.
vUVW;
287 VState.
vUVW.InitMatrix();
288 CalculateInertialVelocity();
289 VState.
vPQR.InitMatrix();
290 VState.
vPQRi = Ti2b * in.vOmegaPlanet;
292 InitializeDerivatives();
303 void FGPropagate::CalculateQuatdot(
void)
316 void FGPropagate::CalculateInertialVelocity(
void)
318 VState.vInertialVelocity = Tb2i * VState.
vUVW + (in.vOmegaPlanet * VState.vInertialPosition);
326 void FGPropagate::CalculateUVW(
void)
328 VState.
vUVW = Ti2b * (VState.vInertialVelocity - (in.vOmegaPlanet * VState.vInertialPosition));
333 void FGPropagate::Integrate( FGColumnVector3& Integrand,
334 FGColumnVector3& Val,
335 deque <FGColumnVector3>& ValDot,
337 eIntegrateType integration_type)
339 ValDot.push_front(Val);
342 switch(integration_type) {
343 case eRectEuler: Integrand += dt*ValDot[0];
345 case eTrapezoidal: Integrand += 0.5*dt*(ValDot[0] + ValDot[1]);
347 case eAdamsBashforth2: Integrand += dt*(1.5*ValDot[0] - 0.5*ValDot[1]);
349 case eAdamsBashforth3: Integrand += (1/12.0)*dt*(23.0*ValDot[0] - 16.0*ValDot[1] + 5.0*ValDot[2]);
351 case eAdamsBashforth4: Integrand += (1/24.0)*dt*(55.0*ValDot[0] - 59.0*ValDot[1] + 37.0*ValDot[2] - 9.0*ValDot[3]);
353 case eAdamsBashforth5: Integrand += dt*((1901./720.)*ValDot[0] - (1387./360.)*ValDot[1] + (109./30.)*ValDot[2] - (637./360.)*ValDot[3] + (251./720.)*ValDot[4]);
359 case eLocalLinearization:
360 throw(
"Can only use Buss (1 & 2) or local linearization integration methods in for rotational position!");
368 void FGPropagate::Integrate( FGQuaternion& Integrand,
370 deque <FGQuaternion>& ValDot,
372 eIntegrateType integration_type)
374 ValDot.push_front(Val);
377 switch(integration_type) {
378 case eRectEuler: Integrand += dt*ValDot[0];
380 case eTrapezoidal: Integrand += 0.5*dt*(ValDot[0] + ValDot[1]);
382 case eAdamsBashforth2: Integrand += dt*(1.5*ValDot[0] - 0.5*ValDot[1]);
384 case eAdamsBashforth3: Integrand += (1/12.0)*dt*(23.0*ValDot[0] - 16.0*ValDot[1] + 5.0*ValDot[2]);
386 case eAdamsBashforth4: Integrand += (1/24.0)*dt*(55.0*ValDot[0] - 59.0*ValDot[1] + 37.0*ValDot[2] - 9.0*ValDot[3]);
388 case eAdamsBashforth5: Integrand += dt*((1901./720.)*ValDot[0] - (1387./360.)*ValDot[1] + (109./30.)*ValDot[2] - (637./360.)*ValDot[3] + (251./720.)*ValDot[4]);
396 Integrand = Integrand * QExp(0.5 * dt * VState.
vPQRi);
404 FGColumnVector3 wi = VState.
vPQRi;
405 FGColumnVector3 wdoti = in.vPQRidot;
406 FGColumnVector3 omega = wi + 0.5*dt*wdoti + dt*dt/12.*wdoti*wi;
407 Integrand = Integrand * QExp(0.5 * dt * omega);
410 case eLocalLinearization:
416 FGColumnVector3 wi = 0.5 * VState.
vPQRi;
417 FGColumnVector3 wdoti = 0.5 * in.vPQRidot;
418 double omegak2 = DotProduct(VState.
vPQRi, VState.
vPQRi);
419 double omegak = omegak2 > 1E-6 ? sqrt(omegak2) : 1E-6;
420 double rhok = 0.5 * dt * omegak;
421 double C1 = cos(rhok);
422 double C2 = 2.0 * sin(rhok) / omegak;
423 double C3 = 4.0 * (1.0 - C1) / (omegak*omegak);
424 double C4 = 4.0 * (dt - C2) / (omegak*omegak);
425 FGColumnVector3 Omega = C2*wi + C3*wdoti + C4*wi*wdoti;
428 q(1) = C1 - C4*DotProduct(wi, wdoti);
433 Integrand = Integrand * q;
467 Integrand.Normalize();
472 void FGPropagate::UpdateLocationMatrices(
void)
476 Ti2l = Tec2l * Ti2ec;
482 void FGPropagate::UpdateBodyMatrices(
void)
488 Tec2b = Ti2b * Tec2i;
496 void FGPropagate::SetInertialOrientation(
const FGQuaternion& Qi)
500 UpdateBodyMatrices();
507 void FGPropagate::SetInertialVelocity(
const FGColumnVector3& Vi) {
508 VState.vInertialVelocity = Vi;
510 vVel = Tb2l * VState.
vUVW;
515 void FGPropagate::SetInertialRates(
const FGColumnVector3& vRates) {
516 VState.
vPQRi = Ti2b * vRates;
517 VState.
vPQR = VState.
vPQRi - Ti2b * in.vOmegaPlanet;
530 void FGPropagate::SetAltitudeASL(
double altASL)
534 UpdateVehicleState();
539 void FGPropagate::RecomputeLocalTerrainVelocity()
542 FGColumnVector3 normal;
544 LocalTerrainVelocity, LocalTerrainAngularVelocity);
549 double FGPropagate::GetTerrainElevation(
void)
const
551 FGColumnVector3 vDummy;
553 contact.SetEllipse(in.SemiMajor, in.SemiMinor);
555 return contact.GetGeodAltitude();
560 void FGPropagate::SetTerrainElevation(
double terrainElev)
577 double FGPropagate::GetDistanceAGL(
void)
const
584 double FGPropagate::GetDistanceAGLKm(
void)
const
586 return GetDistanceAGL()*0.0003048;
591 void FGPropagate::SetDistanceAGL(
double tt)
594 UpdateVehicleState();
599 void FGPropagate::SetDistanceAGLKm(
double tt)
601 SetDistanceAGL(tt*3280.8399);
606 void FGPropagate::SetVState(
const VehicleState& vstate)
610 UpdateLocationMatrices();
611 SetInertialOrientation(vstate.qAttitudeECI);
612 RecomputeLocalTerrainVelocity();
613 VState.
vUVW = vstate.vUVW;
614 vVel = Tb2l * VState.
vUVW;
615 VState.
vPQR = vstate.vPQR;
616 VState.
vPQRi = VState.
vPQR + Ti2b * in.vOmegaPlanet;
617 VState.vInertialPosition = vstate.vInertialPosition;
623 void FGPropagate::UpdateVehicleState(
void)
625 RecomputeLocalTerrainVelocity();
626 VState.vInertialPosition = Tec2i * VState.
vLocation;
627 UpdateLocationMatrices();
628 UpdateBodyMatrices();
629 vVel = Tb2l * VState.
vUVW;
635 void FGPropagate::SetLocation(
const FGLocation& l)
638 UpdateVehicleState();
650 void FGPropagate::DumpState(
void)
654 <<
"------------------------------------------------------------------" <<
reset << endl;
656 <<
"State Report at sim time: " << FDMExec->
GetSimTime() <<
" seconds" <<
reset << endl;
659 cout <<
" ECI: " << VState.vInertialPosition.
Dump(
", ") <<
" (x,y,z, in ft)" << endl;
660 cout <<
" ECEF: " << VState.
vLocation <<
" (x,y,z, in ft)" << endl;
663 <<
", " <<
GetAltitudeASL() <<
" (geodetic lat, lon, alt ASL in deg and ft)" << endl;
666 <<
"Orientation" <<
underoff << endl;
672 cout <<
" ECI: " << VState.vInertialVelocity.
Dump(
", ") <<
" (x,y,z in ft/s)" << endl;
673 cout <<
" ECEF: " << (Tb2ec * VState.
vUVW).Dump(
", ") <<
" (x,y,z in ft/s)" << endl;
674 cout <<
" Local: " <<
GetVel() <<
" (n,e,d in ft/sec)" << endl;
675 cout <<
" Body: " <<
GetUVW() <<
" (u,v,w in ft/sec)" << endl;
678 <<
"Body Rates (relative to given frame, expressed in body frame)" <<
underoff << endl;
679 cout <<
" ECI: " << (VState.
vPQRi*radtodeg).Dump(
", ") <<
" (p,q,r in deg/s)" << endl;
680 cout <<
" ECEF: " << (VState.
vPQR*radtodeg).Dump(
", ") <<
" (p,q,r in deg/s)" << endl;
685 void FGPropagate::WriteStateFile(
int num)
689 if (num == 0)
return;
693 if (path.isNull()) path = SGPath(
"initfile.");
694 else path.append(
"initfile.");
697 path.concat(to_string((
double)FDMExec->
GetSimTime())+
".xml");
702 if (outfile.is_open()) {
703 outfile <<
"<?xml version=\"1.0\"?>" << endl;
704 outfile <<
"<initialize name=\"reset00\">" << endl;
705 outfile <<
" <ubody unit=\"FT/SEC\"> " << VState.
vUVW(eU) <<
" </ubody> " << endl;
706 outfile <<
" <vbody unit=\"FT/SEC\"> " << VState.
vUVW(eV) <<
" </vbody> " << endl;
707 outfile <<
" <wbody unit=\"FT/SEC\"> " << VState.
vUVW(eW) <<
" </wbody> " << endl;
709 outfile <<
" <theta unit=\"DEG\"> " << VState.
qAttitudeLocal.
GetEuler(eTht)*radtodeg <<
" </theta>" << endl;
713 outfile <<
" <altitude unit=\"FT\"> " << GetDistanceAGL() <<
" </altitude>" << endl;
714 outfile <<
"</initialize>" << endl;
717 cerr <<
"Could not open and/or write the state to the initial conditions file: "
723 if (outfile.is_open()) {
724 outfile <<
"<?xml version=\"1.0\"?>" << endl;
725 outfile <<
"<initialize name=\"IC File\" version=\"2.0\">" << endl;
726 outfile <<
"" << endl;
727 outfile <<
" <position frame=\"ECEF\">" << endl;
730 outfile <<
" <altitudeMSL unit=\"FT\"> " <<
GetAltitudeASL() <<
" </altitudeMSL>" << endl;
731 outfile <<
" </position>" << endl;
732 outfile <<
"" << endl;
733 outfile <<
" <orientation unit=\"DEG\" frame=\"LOCAL\">" << endl;
737 outfile <<
" </orientation>" << endl;
738 outfile <<
"" << endl;
739 outfile <<
" <velocity unit=\"FT/SEC\" frame=\"LOCAL\">" << endl;
740 outfile <<
" <x> " <<
GetVel(eNorth) <<
" </x>" << endl;
741 outfile <<
" <y> " <<
GetVel(eEast) <<
" </y>" << endl;
742 outfile <<
" <z> " <<
GetVel(eDown) <<
" </z>" << endl;
743 outfile <<
" </velocity>" << endl;
744 outfile <<
"" << endl;
745 outfile <<
" <attitude_rate unit=\"DEG/SEC\" frame=\"BODY\">" << endl;
746 outfile <<
" <roll> " << (VState.
vPQR*radtodeg)(eRoll) <<
" </roll>" << endl;
747 outfile <<
" <pitch> " << (VState.
vPQR*radtodeg)(ePitch) <<
" </pitch>" << endl;
748 outfile <<
" <yaw> " << (VState.
vPQR*radtodeg)(eYaw) <<
" </yaw>" << endl;
749 outfile <<
" </attitude_rate>" << endl;
750 outfile <<
"" << endl;
751 outfile <<
"</initialize>" << endl;
754 cerr <<
"Could not open and/or write the state to the initial conditions file: "
759 cerr <<
"When writing a state file, the supplied value must be 1 or 2 for the version number of the resulting IC file" << endl;
765 void FGPropagate::bind(
void)
797 PropertyManager->
Tie(
"position/lat-gc-rad",
this, &FGPropagate::GetLatitude, &FGPropagate::SetLatitude);
798 PropertyManager->
Tie(
"position/long-gc-rad",
this, &FGPropagate::GetLongitude, &FGPropagate::SetLongitude);
799 PropertyManager->
Tie(
"position/lat-gc-deg",
this, &FGPropagate::GetLatitudeDeg, &FGPropagate::SetLatitudeDeg);
800 PropertyManager->
Tie(
"position/long-gc-deg",
this, &FGPropagate::GetLongitudeDeg, &FGPropagate::SetLongitudeDeg);
801 PropertyManager->
Tie(
"position/lat-geod-rad",
this, &FGPropagate::GetGeodLatitudeRad);
802 PropertyManager->
Tie(
"position/lat-geod-deg",
this, &FGPropagate::GetGeodLatitudeDeg);
803 PropertyManager->
Tie(
"position/geod-alt-ft",
this, &FGPropagate::GetGeodeticAltitude);
804 PropertyManager->
Tie(
"position/h-agl-ft",
this, &FGPropagate::GetDistanceAGL, &FGPropagate::SetDistanceAGL);
805 PropertyManager->
Tie(
"position/geod-alt-km",
this, &FGPropagate::GetGeodeticAltitudeKm);
806 PropertyManager->
Tie(
"position/h-agl-km",
this, &FGPropagate::GetDistanceAGLKm, &FGPropagate::SetDistanceAGLKm);
807 PropertyManager->
Tie(
"position/radius-to-vehicle-ft",
this, &FGPropagate::GetRadius);
808 PropertyManager->
Tie(
"position/terrain-elevation-asl-ft",
this,
809 &FGPropagate::GetTerrainElevation,
810 &FGPropagate::SetTerrainElevation);
816 PropertyManager->
Tie(
"position/ecef-x-ft",
this, eX, (PMF)&FGPropagate::GetLocation);
817 PropertyManager->
Tie(
"position/ecef-y-ft",
this, eY, (PMF)&FGPropagate::GetLocation);
818 PropertyManager->
Tie(
"position/ecef-z-ft",
this, eZ, (PMF)&FGPropagate::GetLocation);
835 PropertyManager->
Tie(
"simulation/integrator/rate/rotational", (
int*)&integrator_rotational_rate);
836 PropertyManager->
Tie(
"simulation/integrator/rate/translational", (
int*)&integrator_translational_rate);
837 PropertyManager->
Tie(
"simulation/integrator/position/rotational", (
int*)&integrator_rotational_position);
838 PropertyManager->
Tie(
"simulation/integrator/position/translational", (
int*)&integrator_translational_position);
840 PropertyManager->
Tie(
"simulation/write-state-file",
this, (iPMF)0, &FGPropagate::WriteStateFile);
862 void FGPropagate::Debug(
int from)
864 if (debug_lvl <= 0)
return;
871 if (debug_lvl & 2 ) {
872 if (from == 0) cout <<
"Instantiated: FGPropagate" << endl;
873 if (from == 1) cout <<
"Destroyed: FGPropagate" << endl;
875 if (debug_lvl & 4 ) {
877 if (debug_lvl & 8 && from == 2) {
879 <<
" Propagation Report (English units: ft, degrees) at simulation time " << FDMExec->
GetSimTime() <<
" seconds"
882 cout <<
highint <<
" Earth Position Angle (deg): " << setw(8) << setprecision(3) <<
reset
885 cout <<
highint <<
" Body velocity (ft/sec): " << setw(8) << setprecision(3) <<
reset << VState.
vUVW << endl;
886 cout <<
highint <<
" Local velocity (ft/sec): " << setw(8) << setprecision(3) <<
reset << vVel << endl;
887 cout <<
highint <<
" Inertial velocity (ft/sec): " << setw(8) << setprecision(3) <<
reset << VState.vInertialVelocity << endl;
888 cout <<
highint <<
" Inertial Position (ft): " << setw(10) << setprecision(3) <<
reset << VState.vInertialPosition << endl;
894 cout <<
highint <<
" Matrix ECEF to Body (Orientation of Body with respect to ECEF): "
895 <<
reset << endl << Tec2b.
Dump(
"\t",
" ") << endl;
896 cout <<
highint <<
" Associated Euler angles (deg): " << setw(8)
900 cout <<
highint <<
" Matrix Body to ECEF (Orientation of ECEF with respect to Body):"
901 <<
reset << endl << Tb2ec.
Dump(
"\t",
" ") << endl;
902 cout <<
highint <<
" Associated Euler angles (deg): " << setw(8)
906 cout <<
highint <<
" Matrix Local to Body (Orientation of Body with respect to Local):"
907 <<
reset << endl << Tl2b.
Dump(
"\t",
" ") << endl;
908 cout <<
highint <<
" Associated Euler angles (deg): " << setw(8)
912 cout <<
highint <<
" Matrix Body to Local (Orientation of Local with respect to Body):"
913 <<
reset << endl << Tb2l.
Dump(
"\t",
" ") << endl;
914 cout <<
highint <<
" Associated Euler angles (deg): " << setw(8)
918 cout <<
highint <<
" Matrix Local to ECEF (Orientation of ECEF with respect to Local):"
919 <<
reset << endl << Tl2ec.
Dump(
"\t",
" ") << endl;
920 cout <<
highint <<
" Associated Euler angles (deg): " << setw(8)
924 cout <<
highint <<
" Matrix ECEF to Local (Orientation of Local with respect to ECEF):"
925 <<
reset << endl << Tec2l.
Dump(
"\t",
" ") << endl;
926 cout <<
highint <<
" Associated Euler angles (deg): " << setw(8)
930 cout <<
highint <<
" Matrix ECEF to Inertial (Orientation of Inertial with respect to ECEF):"
931 <<
reset << endl << Tec2i.Dump(
"\t",
" ") << endl;
932 cout <<
highint <<
" Associated Euler angles (deg): " << setw(8)
933 << setprecision(3) <<
reset << (Tec2i.GetQuaternion().GetEuler()*radtodeg)
936 cout <<
highint <<
" Matrix Inertial to ECEF (Orientation of ECEF with respect to Inertial):"
937 <<
reset << endl << Ti2ec.Dump(
"\t",
" ") << endl;
938 cout <<
highint <<
" Associated Euler angles (deg): " << setw(8)
939 << setprecision(3) <<
reset << (Ti2ec.GetQuaternion().GetEuler()*radtodeg)
942 cout <<
highint <<
" Matrix Inertial to Body (Orientation of Body with respect to Inertial):"
943 <<
reset << endl << Ti2b.
Dump(
"\t",
" ") << endl;
944 cout <<
highint <<
" Associated Euler angles (deg): " << setw(8)
948 cout <<
highint <<
" Matrix Body to Inertial (Orientation of Inertial with respect to Body):"
949 <<
reset << endl << Tb2i.
Dump(
"\t",
" ") << endl;
950 cout <<
highint <<
" Associated Euler angles (deg): " << setw(8)
954 cout <<
highint <<
" Matrix Inertial to Local (Orientation of Local with respect to Inertial):"
955 <<
reset << endl << Ti2l.
Dump(
"\t",
" ") << endl;
956 cout <<
highint <<
" Associated Euler angles (deg): " << setw(8)
960 cout <<
highint <<
" Matrix Local to Inertial (Orientation of Inertial with respect to Local):"
961 <<
reset << endl << Tl2i.Dump(
"\t",
" ") << endl;
962 cout <<
highint <<
" Associated Euler angles (deg): " << setw(8)
963 << setprecision(3) <<
reset << (Tl2i.GetQuaternion().GetEuler()*radtodeg)
966 cout << setprecision(6);
968 if (debug_lvl & 16) {
972 s <<
"Vehicle rotation rate is excessive (>1000 rad/sec): " << VState.
vPQR.
Magnitude();
973 cerr << endl << s.str() << endl;
974 throw BaseException(s.str());
978 s <<
"Vehicle velocity is excessive (>1e10 ft/sec): " << VState.
vUVW.
Magnitude();
979 cerr << endl << s.str() << endl;
980 throw BaseException(s.str());
982 if (fabs(GetDistanceAGL()) > 1e10) {
984 s <<
"Vehicle altitude is excessive (>1e10 ft): " << GetDistanceAGL();
985 cerr << endl << s.str() << endl;
986 throw BaseException(s.str());
990 if (debug_lvl & 64) {