diff --git a/src/FDM/JSBSim/FGAtmosphere.cpp b/src/FDM/JSBSim/FGAtmosphere.cpp index e2ea8131d..0e945a3cc 100644 --- a/src/FDM/JSBSim/FGAtmosphere.cpp +++ b/src/FDM/JSBSim/FGAtmosphere.cpp @@ -152,10 +152,10 @@ bool FGAtmosphere::Run(void) Debug(2); + return false; } else { // skip Run() execution this time + return true; } - - return false; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/FDM/JSBSim/FGFCS.cpp b/src/FDM/JSBSim/FGFCS.cpp index 57e73bf8c..d14fbe322 100644 --- a/src/FDM/JSBSim/FGFCS.cpp +++ b/src/FDM/JSBSim/FGFCS.cpp @@ -120,10 +120,11 @@ bool FGFCS::Run(void) for (i=0; iRun(); if (DoNormalize) Normalize(); - } else { - } - return false; + return false; + } else { + return true; + } } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/src/FDM/JSBSim/FGFDMExec.cpp b/src/FDM/JSBSim/FGFDMExec.cpp index a9cdac8e7..2b1d08973 100644 --- a/src/FDM/JSBSim/FGFDMExec.cpp +++ b/src/FDM/JSBSim/FGFDMExec.cpp @@ -114,9 +114,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) frozen = false; modelLoaded = false; IsSlave = false; - - cout << "FGFDMExec::FGFDMExec, FDMctr: " << FDMctr << endl; - + IdFDM = FDMctr; FDMctr++; @@ -132,6 +130,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root) else master = root; instance = master->GetNode("/fdm/jsbsim",IdFDM,true); + instance->SetDouble("zero",0); Debug(0); @@ -157,8 +156,7 @@ FGFDMExec::~FGFDMExec() for (unsigned int i=1; iexec; SlaveFDMList.clear(); - cout << "FGFDMExec::~FGFDMExec, FDMctr: " << FDMctr << endl; - FDMctr--; + Debug(1); } @@ -339,9 +337,9 @@ bool FGFDMExec::Run(void) // Run(i) } - while (!model_iterator->Run()) { + while (model_iterator != 0L) { + model_iterator->Run(); model_iterator = model_iterator->NextModel; - if (model_iterator == 0L) break; } frame = Frame++; diff --git a/src/FDM/JSBSim/FGGroundReactions.cpp b/src/FDM/JSBSim/FGGroundReactions.cpp index c95b42edb..676271986 100644 --- a/src/FDM/JSBSim/FGGroundReactions.cpp +++ b/src/FDM/JSBSim/FGGroundReactions.cpp @@ -134,6 +134,8 @@ string FGGroundReactions::GetGroundReactionStrings(void) GroundReactionStrings += (lGear[i].GetName() + "_strokeVel, "); GroundReactionStrings += (lGear[i].GetName() + "_CompressForce, "); GroundReactionStrings += (lGear[i].GetName() + "_WhlSideForce, "); + GroundReactionStrings += (lGear[i].GetName() + "_WhlVelVecX, "); + GroundReactionStrings += (lGear[i].GetName() + "_WhlVelVecY, "); GroundReactionStrings += (lGear[i].GetName() + "_WhlRollForce, "); GroundReactionStrings += (lGear[i].GetName() + "_BodyXForce, "); GroundReactionStrings += (lGear[i].GetName() + "_BodyYForce, "); @@ -142,6 +144,13 @@ string FGGroundReactions::GetGroundReactionStrings(void) firstime = false; } + GroundReactionStrings += ", TotalGearForce_X, "; + GroundReactionStrings += "TotalGearForce_Y, "; + GroundReactionStrings += "TotalGearForce_Z, "; + GroundReactionStrings += "TotalGearMoment_L, "; + GroundReactionStrings += "TotalGearMoment_M, "; + GroundReactionStrings += "TotalGearMoment_N"; + return GroundReactionStrings; } @@ -160,6 +169,8 @@ string FGGroundReactions::GetGroundReactionValues(void) GroundReactionValues += (string(gcvt(lGear[i].GetCompLen(), 5, buff)) + ", "); GroundReactionValues += (string(gcvt(lGear[i].GetCompVel(), 6, buff)) + ", "); GroundReactionValues += (string(gcvt(lGear[i].GetCompForce(), 10, buff)) + ", "); + GroundReactionValues += (string(gcvt(lGear[i].GetWheelVel(eX), 6, buff)) + ", "); + GroundReactionValues += (string(gcvt(lGear[i].GetWheelVel(eY), 6, buff)) + ", "); GroundReactionValues += (string(gcvt(lGear[i].GetWheelSideForce(), 6, buff)) + ", "); GroundReactionValues += (string(gcvt(lGear[i].GetWheelRollForce(), 6, buff)) + ", "); GroundReactionValues += (string(gcvt(lGear[i].GetBodyXForce(), 6, buff)) + ", "); @@ -169,6 +180,13 @@ string FGGroundReactions::GetGroundReactionValues(void) firstime = false; } + GroundReactionValues += (", " + string(gcvt(vForces(eX), 6, buff)) + ", "); + GroundReactionValues += (string(gcvt(vForces(eY), 6, buff)) + ", "); + GroundReactionValues += (string(gcvt(vForces(eZ), 6, buff)) + ", "); + GroundReactionValues += (string(gcvt(vMoments(eX), 6, buff)) + ", "); + GroundReactionValues += (string(gcvt(vMoments(eY), 6, buff)) + ", "); + GroundReactionValues += (string(gcvt(vMoments(eZ), 6, buff))); + return GroundReactionValues; } diff --git a/src/FDM/JSBSim/FGInertial.cpp b/src/FDM/JSBSim/FGInertial.cpp index b3d3f5989..854ed26da 100644 --- a/src/FDM/JSBSim/FGInertial.cpp +++ b/src/FDM/JSBSim/FGInertial.cpp @@ -59,7 +59,10 @@ FGInertial::FGInertial(FGFDMExec* fgex) : FGModel(fgex) RadiusReference = 20925650.00; gAccelReference = GM/(RadiusReference*RadiusReference); gAccel = GM/(RadiusReference*RadiusReference); - + vCoriolis.InitMatrix(); + vCentrifugal.InitMatrix(); + vGravity.InitMatrix(); + bind(); Debug(0); @@ -77,21 +80,12 @@ FGInertial::~FGInertial(void) bool FGInertial::Run(void) { - double stht, ctht, sphi, cphi; - if (!FGModel::Run()) { gAccel = GM / (Position->GetRadius()*Position->GetRadius()); - stht = sin(Rotation->GetEuler(eTht)); - ctht = cos(Rotation->GetEuler(eTht)); - sphi = sin(Rotation->GetEuler(ePhi)); - cphi = cos(Rotation->GetEuler(ePhi)); + vGravity(eDown) = gAccel; - vGravity(eX) = vForces(eX) = -gravity()*stht; - vGravity(eY) = vForces(eY) = gravity()*sphi*ctht; - vGravity(eZ) = vForces(eZ) = gravity()*cphi*ctht; - // The following equation for vOmegaLocal terms shows the angular velocity // calculation _for_the_local_frame_ given the earth's rotation (first set) // at the current latitude, and also the component due to the aircraft @@ -105,12 +99,17 @@ bool FGInertial::Run(void) vOmegaLocal(eY) += -Position->GetVn() / Position->GetRadius(); vOmegaLocal(eZ) += 0.00; -// vForces = State->GetTl2b()*(-2.0*vOmegaLocal * Position->GetVel()); + // Coriolis acceleration is normally written: -2w*dr/dt, but due to the axis + // conventions used here the sign is reversed: 2w*dr/dt. The same is true for + // Centrifugal acceleration. - vRadius(3) = Position->GetRadius(); - vForces += State->GetTl2b()*(vOmegaLocal * (vOmegaLocal * vRadius)); + vCoriolis(eEast) = 2.0*omega() * (Position->GetVd()*cos(Position->GetLatitude()) + + Position->GetVn()*sin(Position->GetLatitude())); - vForces *= MassBalance->GetMass(); // IMPORTANT !!!!!!!!!!!!!!!!!!!!!!!!!!!! + vRadius(eDown) = Position->GetRadius(); + vCentrifugal(eDown) = -vOmegaLocal.Magnitude() * vOmegaLocal.Magnitude() * vRadius(eDown); + + vForces = State->GetTl2b() * MassBalance->GetMass() * (vCoriolis + vCentrifugal + vGravity); return false; } else { diff --git a/src/FDM/JSBSim/FGInertial.h b/src/FDM/JSBSim/FGInertial.h index 569074301..1e4a461e9 100644 --- a/src/FDM/JSBSim/FGInertial.h +++ b/src/FDM/JSBSim/FGInertial.h @@ -75,6 +75,8 @@ public: bool Run(void); FGColumnVector3& GetForces(void) {return vForces;} FGColumnVector3& GetGravity(void) {return vGravity;} + FGColumnVector3& GetCoriolis(void) {return vCoriolis;} + FGColumnVector3& GetCentrifugal(void) {return vCentrifugal;} double GetForces(int n) const {return vForces(n);} bool LoadInertial(FGConfigFile* AC_cfg); double SLgravity(void) const {return gAccelReference;} @@ -91,6 +93,8 @@ private: FGColumnVector3 vForces; FGColumnVector3 vRadius; FGColumnVector3 vGravity; + FGColumnVector3 vCoriolis; + FGColumnVector3 vCentrifugal; double gAccel; double gAccelReference; double RadiusReference; diff --git a/src/FDM/JSBSim/FGInitialCondition.cpp b/src/FDM/JSBSim/FGInitialCondition.cpp index 16e37ca79..58d739053 100644 --- a/src/FDM/JSBSim/FGInitialCondition.cpp +++ b/src/FDM/JSBSim/FGInitialCondition.cpp @@ -110,7 +110,6 @@ FGInitialCondition::~FGInitialCondition() void FGInitialCondition::SetVcalibratedKtsIC(double tt) { if(getMachFromVcas(&mach,tt*ktstofps)) { - //cout << "Mach: " << mach << endl; lastSpeedSet=setvc; vc=tt*ktstofps; diff --git a/src/FDM/JSBSim/FGLGear.cpp b/src/FDM/JSBSim/FGLGear.cpp index 8f137f88b..52d834168 100644 --- a/src/FDM/JSBSim/FGLGear.cpp +++ b/src/FDM/JSBSim/FGLGear.cpp @@ -104,7 +104,7 @@ FGLGear::FGLGear(FGConfigFile* AC_cfg, FGFDMExec* fdmex) : Exec(fdmex) FCS = Exec->GetFCS(); MassBalance = Exec->GetMassBalance(); - WOW = lastWOW = false; + WOW = lastWOW = true; // should the value be initialized to true? ReportEnable = true; FirstContact = false; Reported = false; @@ -115,7 +115,7 @@ FGLGear::FGLGear(FGConfigFile* AC_cfg, FGFDMExec* fdmex) : Exec(fdmex) vWhlBodyVec = (vXYZ - MassBalance->GetXYZcg()) / 12.0; vWhlBodyVec(eX) = -vWhlBodyVec(eX); vWhlBodyVec(eZ) = -vWhlBodyVec(eZ); - + vLocalGear = State->GetTb2l() * vWhlBodyVec; compressLength = 0.0; @@ -123,6 +123,13 @@ FGLGear::FGLGear(FGConfigFile* AC_cfg, FGFDMExec* fdmex) : Exec(fdmex) brakePct = 0.0; maxCompLen = 0.0; + WheelSlip = lastWheelSlip = 0.0; + + compressLength = 0.0; + compressSpeed = 0.0; + brakePct = 0.0; + maxCompLen = 0.0; + Debug(0); } @@ -173,6 +180,8 @@ FGLGear::FGLGear(const FGLGear& lgear) isRetractable = lgear.isRetractable; GearUp = lgear.GearUp; GearDown = lgear.GearDown; + WheelSlip = lgear.WheelSlip; + lastWheelSlip = lgear.lastWheelSlip; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -266,17 +275,17 @@ FGColumnVector3& FGLGear::Force(void) switch (eBrakeGrp) { case bgLeft: - SteerGain = -0.10; + SteerGain = 0.10; BrakeFCoeff = rollingFCoeff*(1.0 - FCS->GetBrake(bgLeft)) + staticFCoeff*FCS->GetBrake(bgLeft); break; case bgRight: - SteerGain = -0.10; + SteerGain = 0.10; BrakeFCoeff = rollingFCoeff*(1.0 - FCS->GetBrake(bgRight)) + staticFCoeff*FCS->GetBrake(bgRight); break; case bgCenter: - SteerGain = -0.10; + SteerGain = 0.10; BrakeFCoeff = rollingFCoeff*(1.0 - FCS->GetBrake(bgCenter)) + staticFCoeff*FCS->GetBrake(bgCenter); break; @@ -289,7 +298,7 @@ FGColumnVector3& FGLGear::Force(void) BrakeFCoeff = rollingFCoeff; break; case bgNone: - SteerGain = -0.10; + SteerGain = 0.0; BrakeFCoeff = rollingFCoeff; break; default: @@ -326,17 +335,31 @@ FGColumnVector3& FGLGear::Force(void) if (RollingWhlVel == 0.0 && SideWhlVel == 0.0) { WheelSlip = 0.0; + } else if (fabs(RollingWhlVel) < 0.10) { + WheelSlip = 0.05*radtodeg*atan2(SideWhlVel, RollingWhlVel) + 0.95*WheelSlip; } else { WheelSlip = radtodeg*atan2(SideWhlVel, RollingWhlVel); } + if ((WheelSlip < 0.0 && lastWheelSlip > 0.0) || + (WheelSlip > 0.0 && lastWheelSlip < 0.0)) + { + WheelSlip = 0.0; + } + + lastWheelSlip = WheelSlip; + // Compute the sideforce coefficients using similar assumptions to LaRCSim for now. // Allow a maximum of 10 degrees tire slip angle before wheel slides. At that point, // transition from static to dynamic friction. There are more complicated formulations // of this that avoid the discrete jump. Will fix this later. - if (fabs(WheelSlip) <= 10.0) { - FCoeff = staticFCoeff*WheelSlip/10.0; + if (fabs(WheelSlip) <= 20.0) { + FCoeff = staticFCoeff*WheelSlip/20.0; + } else if (fabs(WheelSlip) <= 40.0) { +// FCoeff = dynamicFCoeff*fabs(WheelSlip)/WheelSlip; + FCoeff = (dynamicFCoeff*(fabs(WheelSlip) - 20.0)/20.0 + + staticFCoeff*(40.0 - fabs(WheelSlip))/20.0)*fabs(WheelSlip)/WheelSlip; } else { FCoeff = dynamicFCoeff*fabs(WheelSlip)/WheelSlip; } @@ -406,7 +429,7 @@ FGColumnVector3& FGLGear::Force(void) } if (lastWOW != WOW) { - PutMessage("GEAR_CONTACT", WOW); + PutMessage("GEAR_CONTACT: " + name, WOW); } lastWOW = WOW; diff --git a/src/FDM/JSBSim/FGLGear.h b/src/FDM/JSBSim/FGLGear.h index f9e22797b..8bfc6e21a 100644 --- a/src/FDM/JSBSim/FGLGear.h +++ b/src/FDM/JSBSim/FGLGear.h @@ -244,6 +244,7 @@ public: inline double GetBodyXForce(void) { return vLocalForce(eX); } inline double GetBodyYForce(void) { return vLocalForce(eY); } inline double GetWheelSlipAngle(void) { return WheelSlip; } + double GetWheelVel(int axis) { return vWhlVelVec(axis);} private: FGColumnVector3 vXYZ; @@ -270,6 +271,7 @@ private: double SideWhlVel, RollingWhlVel; double RollingForce, SideForce, FCoeff; double WheelSlip; + double lastWheelSlip; bool WOW; bool lastWOW; bool FirstContact; diff --git a/src/FDM/JSBSim/FGOutput.cpp b/src/FDM/JSBSim/FGOutput.cpp index 4d9e94919..52fa53841 100644 --- a/src/FDM/JSBSim/FGOutput.cpp +++ b/src/FDM/JSBSim/FGOutput.cpp @@ -98,8 +98,9 @@ bool FGOutput::Run(void) } else { // Not a valid type of output } - + return false; } else { + return true; } } return false; @@ -172,7 +173,10 @@ void FGOutput::DelimitedOutput(string fname) outstream << ", "; outstream << "Drag, Side, Lift, "; outstream << "L/D, "; - outstream << "Xforce, Yforce, Zforce"; + outstream << "Xforce, Yforce, Zforce, "; + outstream << "xGravity, yGravity, zGravity, "; + outstream << "xCoriolis, yCoriolis, zCoriolis, "; + outstream << "xCentrifugal, yCentrifugal, zCentrifugal"; } if (SubSystems & ssMoments) { outstream << ", "; @@ -252,7 +256,10 @@ void FGOutput::DelimitedOutput(string fname) outstream << ", "; outstream << Aerodynamics->GetvFs() << ", "; outstream << Aerodynamics->GetLoD() << ", "; - outstream << Aircraft->GetForces(); + outstream << Aircraft->GetForces() << ", "; + outstream << Inertial->GetGravity() << ", "; + outstream << Inertial->GetCoriolis() << ", "; + outstream << Inertial->GetCentrifugal(); } if (SubSystems & ssMoments) { outstream << ", "; diff --git a/src/FDM/JSBSim/FGPosition.cpp b/src/FDM/JSBSim/FGPosition.cpp index 01a36c649..74cd727bb 100644 --- a/src/FDM/JSBSim/FGPosition.cpp +++ b/src/FDM/JSBSim/FGPosition.cpp @@ -101,7 +101,13 @@ FGPosition::FGPosition(FGFDMExec* fdmex) : FGModel(fdmex) { Name = "FGPosition"; LongitudeDot = LatitudeDot = RadiusDot = 0.0; - lastLongitudeDot = lastLatitudeDot = lastRadiusDot = 0.0; + + for (int i=0;i<3;i++) { + LatitudeDot_prev[i] = 0.0; + LongitudeDot_prev[i] = 0.0; + RadiusDot_prev[i] = 0.0; + } + Longitude = Latitude = 0.0; gamma = Vt = Vground = 0.0; hoverbmac = hoverbcg = 0.0; @@ -143,7 +149,8 @@ Notes: [TP] Make sure that -Vt <= hdot <= Vt, which, of course, should always In FGFS, SeaLevelRadius is stuffed from FGJSBSim in JSBSim.cxx each pass. */ -bool FGPosition::Run(void) { +bool FGPosition::Run(void) +{ double cosLat; double hdot_Vt; FGColumnVector3 vMac; @@ -160,22 +167,20 @@ bool FGPosition::Run(void) { cosLat = cos(Latitude); if (cosLat != 0) LongitudeDot = vVel(eEast) / (Radius * cosLat); - LatitudeDot = vVel(eNorth) / Radius; RadiusDot = -vVel(eDown); - Longitude += 0.5*dt*rate*(LongitudeDot + lastLongitudeDot); - Latitude += 0.5*dt*rate*(LatitudeDot + lastLatitudeDot); - Radius += 0.5*dt*rate*(RadiusDot + lastRadiusDot); + Longitude += State->Integrate(FGState::TRAPZ, dt*rate, LongitudeDot, LongitudeDot_prev); + Latitude += State->Integrate(FGState::TRAPZ, dt*rate, LatitudeDot, LatitudeDot_prev); + Radius += State->Integrate(FGState::TRAPZ, dt*rate, RadiusDot, RadiusDot_prev); h = Radius - SeaLevelRadius; // Geocentric DistanceAGL = Radius - RunwayRadius; // Geocentric - hoverbcg = DistanceAGL/b; - vMac=State->GetTb2l()*Aircraft->GetXYZrp(); + vMac = State->GetTb2l()*Aircraft->GetXYZrp(); vMac *= inchtoft; hoverbmac = (DistanceAGL + vMac(3))/b; @@ -187,10 +192,6 @@ bool FGPosition::Run(void) { gamma = 0.0; } - lastLatitudeDot = LatitudeDot; - lastLongitudeDot = LongitudeDot; - lastRadiusDot = RadiusDot; - return false; } else { @@ -200,7 +201,8 @@ bool FGPosition::Run(void) { //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void FGPosition::GetState(void) { +void FGPosition::GetState(void) +{ dt = State->Getdt(); Vt = Translation->GetVt(); @@ -212,7 +214,8 @@ void FGPosition::GetState(void) { //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void FGPosition::Seth(double tt) { +void FGPosition::Seth(double tt) +{ h = tt; Radius = h + SeaLevelRadius; DistanceAGL = Radius - RunwayRadius; // Geocentric @@ -221,7 +224,8 @@ void FGPosition::Seth(double tt) { //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -void FGPosition::SetDistanceAGL(double tt) { +void FGPosition::SetDistanceAGL(double tt) +{ DistanceAGL=tt; Radius = RunwayRadius + DistanceAGL; h = Radius - SeaLevelRadius; diff --git a/src/FDM/JSBSim/FGPosition.h b/src/FDM/JSBSim/FGPosition.h index 0fd024354..358d5a0a0 100644 --- a/src/FDM/JSBSim/FGPosition.h +++ b/src/FDM/JSBSim/FGPosition.h @@ -79,6 +79,7 @@ public: /** Constructor @param Executive a pointer to the parent executive object */ FGPosition(FGFDMExec*); + /// Destructor ~FGPosition(); @@ -132,7 +133,7 @@ private: double Radius, h; double LatitudeDot, LongitudeDot, RadiusDot; - double lastLatitudeDot, lastLongitudeDot, lastRadiusDot; + double LatitudeDot_prev[3], LongitudeDot_prev[3], RadiusDot_prev[3]; double Longitude, Latitude; double dt; double RunwayRadius; diff --git a/src/FDM/JSBSim/FGPropulsion.cpp b/src/FDM/JSBSim/FGPropulsion.cpp index 0b3e2b4f2..1a2dba8c7 100644 --- a/src/FDM/JSBSim/FGPropulsion.cpp +++ b/src/FDM/JSBSim/FGPropulsion.cpp @@ -1,652 +1,710 @@ -/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - Module: FGPropulsion.cpp - Author: Jon S. Berndt - Date started: 08/20/00 - Purpose: Encapsulates the set of engines, tanks, and thrusters associated - with this aircraft - - ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) ------------- - - This program is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free Software - Foundation; either version 2 of the License, or (at your option) any later - version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 Temple - Place - Suite 330, Boston, MA 02111-1307, USA. - - Further information about the GNU General Public License can also be found on - the world wide web at http://www.gnu.org. - -FUNCTIONAL DESCRIPTION --------------------------------------------------------------------------------- -The Propulsion class is the container for the entire propulsion system, which is -comprised of engines, tanks, and "thrusters" (the device that transforms the -engine power into a force that acts on the aircraft, such as a nozzle or -propeller). Once the Propulsion class gets the config file, it reads in -information which is specific to a type of engine. Then: - -1) The appropriate engine type instance is created -2) A thruster object is instantiated, and is linked to the engine -3) At least one tank object is created, and is linked to an engine. - -At Run time each engines Calculate() method is called to return the excess power -generated during that iteration. The drag from the previous iteration is sub- -tracted to give the excess power available for thrust this pass. That quantity -is passed to the thrusters associated with a particular engine - perhaps with a -scaling mechanism (gearing?) to allow the engine to give its associated thrust- -ers specific distributed portions of the excess power. - -HISTORY --------------------------------------------------------------------------------- -08/20/00 JSB Created - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -INCLUDES -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ - -#include "FGPropulsion.h" -#include "FGPropertyManager.h" - - -static const char *IdSrc = "$Id$"; -static const char *IdHdr = ID_PROPULSION; - -extern short debug_lvl; - -#if defined (__APPLE__) -/* Not all systems have the gcvt function */ -inline char* gcvt (double value, int ndigits, char *buf) { - /* note that this is not exactly what gcvt is supposed to do! */ - snprintf (buf, ndigits+1, "%f", value); - return buf; -} -#endif - - -/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -CLASS IMPLEMENTATION -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ - -FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec) -{ - Name = "FGPropulsion"; - numSelectedFuelTanks = numSelectedOxiTanks = 0; - numTanks = numEngines = numThrusters = 0; - numOxiTanks = numFuelTanks = 0; - dt = 0.0; - bind(); - Debug(0); -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -FGPropulsion::~FGPropulsion() -{ - for (unsigned int i=0; iGetdt(); - - vForces.InitMatrix(); - vMoments.InitMatrix(); - - if (!FGModel::Run()) { - for (unsigned int i=0; iSetdeltaT(dt*rate); - PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired()); - Thrusters[i]->Calculate(PowerAvailable); - vForces += Thrusters[i]->GetBodyForces(); // sum body frame forces - vMoments += Thrusters[i]->GetMoments(); // sum body frame moments - } - return false; - } else { - return true; - } -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -bool FGPropulsion::GetSteadyState(void) -{ - double PowerAvailable; - double currentThrust = 0, lastThrust=-1; - dt = State->Getdt(); - int steady_count,j=0; - bool steady=false; - - vForces.InitMatrix(); - vMoments.InitMatrix(); - - if (!FGModel::Run()) { - for (unsigned int i=0; iSetTrimMode(true); - Thrusters[i]->SetdeltaT(dt*rate); - steady=false; - steady_count=0; - while (!steady && j < 6000) { - PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired()); - lastThrust = currentThrust; - currentThrust = Thrusters[i]->Calculate(PowerAvailable); - if (fabs(lastThrust-currentThrust) < 0.0001) { - steady_count++; - if (steady_count > 120) { steady=true; } - } else { - steady_count=0; - } - j++; - } - vForces += Thrusters[i]->GetBodyForces(); // sum body frame forces - vMoments += Thrusters[i]->GetMoments(); // sum body frame moments - Engines[i]->SetTrimMode(false); - } - - return false; - } else { - return true; - } -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -bool FGPropulsion::ICEngineStart(void) -{ - double PowerAvailable; - int j; - dt = State->Getdt(); - - vForces.InitMatrix(); - vMoments.InitMatrix(); - - for (unsigned int i=0; iSetTrimMode(true); - Thrusters[i]->SetdeltaT(dt*rate); - j=0; - while (!Engines[i]->GetRunning() && j < 2000) { - PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired()); - Thrusters[i]->Calculate(PowerAvailable); - j++; - } - vForces += Thrusters[i]->GetBodyForces(); // sum body frame forces - vMoments += Thrusters[i]->GetMoments(); // sum body frame moments - Engines[i]->SetTrimMode(false); - } - return true; -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -bool FGPropulsion::Load(FGConfigFile* AC_cfg) -{ - string token, fullpath; - string engineFileName, engType; - string thrusterFileName, thrType; - string parameter; - string enginePath = FDMExec->GetEnginePath(); - double xLoc, yLoc, zLoc, Pitch, Yaw; - double P_Factor = 0, Sense = 0.0; - int Feed; - bool ThrottleAdded = false; - -# ifndef macintosh - fullpath = enginePath + "/"; -# else - fullpath = enginePath + ";"; -# endif - - AC_cfg->GetNextConfigLine(); - - while ((token = AC_cfg->GetValue()) != string("/PROPULSION")) { - - if (token == "AC_ENGINE") { // ============ READING ENGINES - - engineFileName = AC_cfg->GetValue("FILE"); - - if (debug_lvl > 0) cout << "\n Reading engine from file: " << fullpath - + engineFileName + ".xml"<< endl; - FGConfigFile Eng_cfg(fullpath + engineFileName + ".xml"); - - if (Eng_cfg.IsOpen()) { - Eng_cfg.GetNextConfigLine(); - engType = Eng_cfg.GetValue(); - - FCS->AddThrottle(); - ThrottleAdded = true; - - if (engType == "FG_ROCKET") { - Engines.push_back(new FGRocket(FDMExec, &Eng_cfg)); - } else if (engType == "FG_PISTON") { - Engines.push_back(new FGPiston(FDMExec, &Eng_cfg)); - } else if (engType == "FG_TURBOJET") { - Engines.push_back(new FGTurboJet(FDMExec, &Eng_cfg)); - } else if (engType == "FG_TURBOSHAFT") { - Engines.push_back(new FGTurboShaft(FDMExec, &Eng_cfg)); - } else if (engType == "FG_TURBOPROP") { - Engines.push_back(new FGTurboProp(FDMExec, &Eng_cfg)); - } else { - cerr << fgred << " Unrecognized engine type: " << underon << engType - << underoff << " found in config file." << fgdef << endl; - return false; - } - - AC_cfg->GetNextConfigLine(); - while ((token = AC_cfg->GetValue()) != string("/AC_ENGINE")) { - *AC_cfg >> token; - if (token == "XLOC") { *AC_cfg >> xLoc; } - else if (token == "YLOC") { *AC_cfg >> yLoc; } - else if (token == "ZLOC") { *AC_cfg >> zLoc; } - else if (token == "PITCH") { *AC_cfg >> Pitch;} - else if (token == "YAW") { *AC_cfg >> Yaw;} - else if (token == "FEED") { - *AC_cfg >> Feed; - Engines[numEngines]->AddFeedTank(Feed); - if (debug_lvl > 0) cout << " Feed tank: " << Feed << endl; - } else cerr << "Unknown identifier: " << token << " in engine file: " - << engineFileName << endl; - } - - if (debug_lvl > 0) { - cout << " X = " << xLoc << endl; - cout << " Y = " << yLoc << endl; - cout << " Z = " << zLoc << endl; - cout << " Pitch = " << Pitch << endl; - cout << " Yaw = " << Yaw << endl; - } - - Engines[numEngines]->SetPlacement(xLoc, yLoc, zLoc, Pitch, Yaw); - Engines[numEngines]->SetEngineNumber(numEngines); - numEngines++; - - } else { - - cerr << fgred << "\n Could not read engine config file: " << underon << - fullpath + engineFileName + ".xml" << underoff << fgdef << endl; - return false; - } - - } else if (token == "AC_TANK") { // ============== READING TANKS - - if (debug_lvl > 0) cout << "\n Reading tank definition" << endl; - Tanks.push_back(new FGTank(AC_cfg)); - switch(Tanks[numTanks]->GetType()) { - case FGTank::ttFUEL: - numSelectedFuelTanks++; - numFuelTanks++; - break; - case FGTank::ttOXIDIZER: - numSelectedOxiTanks++; - numOxiTanks++; - break; - } - - numTanks++; - - } else if (token == "AC_THRUSTER") { // ========== READING THRUSTERS - - thrusterFileName = AC_cfg->GetValue("FILE"); - - if (debug_lvl > 0) cout << "\n Reading thruster from file: " << - fullpath + thrusterFileName + ".xml" << endl; - FGConfigFile Thruster_cfg(fullpath + thrusterFileName + ".xml"); - - if (Thruster_cfg.IsOpen()) { - Thruster_cfg.GetNextConfigLine(); - thrType = Thruster_cfg.GetValue(); - - if (thrType == "FG_PROPELLER") { - Thrusters.push_back(new FGPropeller(FDMExec, &Thruster_cfg)); - } else if (thrType == "FG_NOZZLE") { - Thrusters.push_back(new FGNozzle(FDMExec, &Thruster_cfg)); - } - - AC_cfg->GetNextConfigLine(); - while ((token = AC_cfg->GetValue()) != string("/AC_THRUSTER")) { - *AC_cfg >> token; - if (token == "XLOC") *AC_cfg >> xLoc; - else if (token == "YLOC") *AC_cfg >> yLoc; - else if (token == "ZLOC") *AC_cfg >> zLoc; - else if (token == "PITCH") *AC_cfg >> Pitch; - else if (token == "YAW") *AC_cfg >> Yaw; - else if (token == "P_FACTOR") *AC_cfg >> P_Factor; - else if (token == "SENSE") *AC_cfg >> Sense; - else cerr << "Unknown identifier: " << token << " in engine file: " - << engineFileName << endl; - } - - Thrusters[numThrusters]->SetLocation(xLoc, yLoc, zLoc); - Thrusters[numThrusters]->SetAnglesToBody(0, Pitch, Yaw); - if (thrType == "FG_PROPELLER" && P_Factor > 0.001) { - ((FGPropeller*)Thrusters[numThrusters])->SetPFactor(P_Factor); - if (debug_lvl > 0) cout << " P-Factor: " << P_Factor << endl; - ((FGPropeller*)Thrusters[numThrusters])->SetSense(fabs(Sense)/Sense); - if (debug_lvl > 0) cout << " Sense: " << Sense << endl; - } - Thrusters[numThrusters]->SetdeltaT(dt*rate); - Thrusters[numThrusters]->SetThrusterNumber(numThrusters); - numThrusters++; - - } else { - cerr << "Could not read thruster config file: " << fullpath - + thrusterFileName + ".xml" << endl; - return false; - } - - } - AC_cfg->GetNextConfigLine(); - } - - if (!ThrottleAdded) FCS->AddThrottle(); // need to have at least one throttle - - return true; -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -string FGPropulsion::GetPropulsionStrings(void) -{ - string PropulsionStrings = ""; - bool firstime = true; - char buffer[5]; - - for (unsigned int i=0;iGetType()) { - case FGEngine::etPiston: - PropulsionStrings += (Engines[i]->GetName() + "_PwrAvail[" + buffer + "]"); - break; - case FGEngine::etRocket: - PropulsionStrings += (Engines[i]->GetName() + "_ChamberPress[" + buffer + "]"); - break; - case FGEngine::etTurboJet: - case FGEngine::etTurboProp: - case FGEngine::etTurboShaft: - break; - default: - PropulsionStrings += "INVALID ENGINE TYPE"; - break; - } - - PropulsionStrings += ", "; - - FGPropeller* Propeller = (FGPropeller*)Thrusters[i]; - switch(Thrusters[i]->GetType()) { - case FGThruster::ttNozzle: - PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "]"); - break; - case FGThruster::ttRotor: - break; - case FGThruster::ttPropeller: - PropulsionStrings += (Thrusters[i]->GetName() + "_Torque[" + buffer + "], "); - PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Roll[" + buffer + "], "); - PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Pitch[" + buffer + "], "); - PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Yaw[" + buffer + "], "); - PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "], "); - if (Propeller->IsVPitch()) - PropulsionStrings += (Thrusters[i]->GetName() + "_Pitch[" + buffer + "], "); - PropulsionStrings += (Thrusters[i]->GetName() + "_RPM[" + buffer + "]"); - break; - default: - PropulsionStrings += "INVALID THRUSTER TYPE"; - break; - } - } - - return PropulsionStrings; -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -string FGPropulsion::GetPropulsionValues(void) -{ - char buff[20]; - string PropulsionValues = ""; - bool firstime = true; - - for (unsigned int i=0;iGetType()) { - case FGEngine::etPiston: - PropulsionValues += (string(gcvt(((FGPiston*)Engines[i])->GetPowerAvailable(), 10, buff))); - break; - case FGEngine::etRocket: - PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetChamberPressure(), 10, buff))); - break; - case FGEngine::etTurboJet: - case FGEngine::etTurboProp: - case FGEngine::etTurboShaft: - break; - } - - PropulsionValues += ", "; - - switch(Thrusters[i]->GetType()) { - case FGThruster::ttNozzle: - PropulsionValues += (string(gcvt(((FGNozzle*)Thrusters[i])->GetThrust(), 10, buff))); - break; - case FGThruster::ttRotor: - break; - case FGThruster::ttPropeller: - FGPropeller* Propeller = (FGPropeller*)Thrusters[i]; - FGColumnVector3 vPFactor = Propeller->GetPFactor(); - PropulsionValues += string(gcvt(Propeller->GetTorque(), 10, buff)) + ", "; - PropulsionValues += string(gcvt(vPFactor(eRoll), 10, buff)) + ", "; - PropulsionValues += string(gcvt(vPFactor(ePitch), 10, buff)) + ", "; - PropulsionValues += string(gcvt(vPFactor(eYaw), 10, buff)) + ", "; - PropulsionValues += string(gcvt(Propeller->GetThrust(), 10, buff)) + ", "; - if (Propeller->IsVPitch()) - PropulsionValues += string(gcvt(Propeller->GetPitch(), 10, buff)) + ", "; - PropulsionValues += string(gcvt(Propeller->GetRPM(), 10, buff)); - break; - } - } - - return PropulsionValues; -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -FGColumnVector3& FGPropulsion::GetTanksMoment(void) -{ - iTank = Tanks.begin(); - vXYZtank.InitMatrix(); - while (iTank < Tanks.end()) { - vXYZtank(eX) += (*iTank)->GetX()*(*iTank)->GetContents(); - vXYZtank(eY) += (*iTank)->GetY()*(*iTank)->GetContents(); - vXYZtank(eZ) += (*iTank)->GetZ()*(*iTank)->GetContents(); - iTank++; - } - return vXYZtank; -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -double FGPropulsion::GetTanksWeight(void) -{ - double Tw = 0.0; - - iTank = Tanks.begin(); - while (iTank < Tanks.end()) { - Tw += (*iTank)->GetContents(); - iTank++; - } - return Tw; -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -double FGPropulsion::GetTanksIxx(const FGColumnVector3& vXYZcg) -{ - double I = 0.0; - iTank = Tanks.begin(); - while (iTank < Tanks.end()) { - I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetX() - vXYZcg(eX)) * (*iTank)->GetContents()/(144.0*Inertial->gravity()); - iTank++; - } - return I; -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -double FGPropulsion::GetTanksIyy(const FGColumnVector3& vXYZcg) -{ - double I = 0.0; - iTank = Tanks.begin(); - while (iTank < Tanks.end()) { - I += ((*iTank)->GetY() - vXYZcg(eY))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*Inertial->gravity()); - iTank++; - } - return I; -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -double FGPropulsion::GetTanksIzz(const FGColumnVector3& vXYZcg) -{ - double I = 0.0; - iTank = Tanks.begin(); - while (iTank < Tanks.end()) { - I += ((*iTank)->GetZ() - vXYZcg(eZ))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*Inertial->gravity()); - iTank++; - } - return I; -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -double FGPropulsion::GetTanksIxz(const FGColumnVector3& vXYZcg) -{ - double I = 0.0; - iTank = Tanks.begin(); - while (iTank < Tanks.end()) { - I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*Inertial->gravity()); - iTank++; - } - return I; -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -double FGPropulsion::GetTanksIxy(const FGColumnVector3& vXYZcg) -{ - double I = 0.0; - iTank = Tanks.begin(); - while (iTank != Tanks.end()) { - I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*Inertial->gravity()); - iTank++; - } - return I; -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -void FGPropulsion::bind(void) -{ - typedef double (FGPropulsion::*PMF)(int) const; - /* PropertyManager->Tie("propulsion/num-engines", this, - &FGPropulsion::GetNumEngines); - PropertyManager->Tie("propulsion/num-tanks", this, - &FGPropulsion::GetNumTanks); */ - PropertyManager->Tie("propulsion/num-sel-fuel-tanks", this, - &FGPropulsion::GetnumSelectedFuelTanks); - PropertyManager->Tie("propulsion/num-sel-ox-tanks", this, - &FGPropulsion::GetnumSelectedOxiTanks); - PropertyManager->Tie("forces/fbx-prop-lbs", this,1, - (PMF)&FGPropulsion::GetForces); - PropertyManager->Tie("forces/fby-prop-lbs", this,2, - (PMF)&FGPropulsion::GetForces); - PropertyManager->Tie("forces/fbz-prop-lbs", this,3, - (PMF)&FGPropulsion::GetForces); - PropertyManager->Tie("moments/l-prop-lbsft", this,1, - (PMF)&FGPropulsion::GetMoments); - PropertyManager->Tie("moments/m-prop-lbsft", this,2, - (PMF)&FGPropulsion::GetMoments); - PropertyManager->Tie("moments/n-prop-lbsft", this,3, - (PMF)&FGPropulsion::GetMoments); - //PropertyManager->Tie("propulsion/tanks-weight-lbs", this, - // &FGPropulsion::GetTanksWeight); -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -void FGPropulsion::unbind(void) -{ - /* PropertyManager->Untie("propulsion/num-engines"); - PropertyManager->Untie("propulsion/num-tanks"); */ - PropertyManager->Untie("propulsion/num-sel-fuel-tanks"); - PropertyManager->Untie("propulsion/num-sel-ox-tanks"); - PropertyManager->Untie("forces/fbx-prop-lbs"); - PropertyManager->Untie("forces/fby-prop-lbs"); - PropertyManager->Untie("forces/fbz-prop-lbs"); - PropertyManager->Untie("moments/l-prop-lbsft"); - PropertyManager->Untie("moments/m-prop-lbsft"); - PropertyManager->Untie("moments/n-prop-lbsft"); - //PropertyManager->Untie("propulsion/tanks-weight-lbs"); -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -// The bitmasked value choices are as follows: -// unset: In this case (the default) JSBSim would only print -// out the normally expected messages, essentially echoing -// the config files as they are read. If the environment -// variable is not set, debug_lvl is set to 1 internally -// 0: This requests JSBSim not to output any messages -// whatsoever. -// 1: This value explicity requests the normal JSBSim -// startup messages -// 2: This value asks for a message to be printed out when -// a class is instantiated -// 4: When this value is set, a message is displayed when a -// FGModel object executes its Run() method -// 8: When this value is set, various runtime state variables -// are printed out periodically -// 16: When set various parameters are sanity checked and -// a message is printed out when they go out of bounds - -void FGPropulsion::Debug(int from) -{ - if (debug_lvl <= 0) return; - - if (debug_lvl & 1) { // Standard console startup message output - if (from == 0) { // Constructor - - } - } - if (debug_lvl & 2 ) { // Instantiation/Destruction notification - if (from == 0) cout << "Instantiated: FGPropulsion" << endl; - if (from == 1) cout << "Destroyed: FGPropulsion" << endl; - } - if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects - } - if (debug_lvl & 8 ) { // Runtime state variables - } - if (debug_lvl & 16) { // Sanity checking - } - if (debug_lvl & 64) { - if (from == 0) { // Constructor - cout << IdSrc << endl; - cout << IdHdr << endl; - } - } -} - +/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + Module: FGPropulsion.cpp + Author: Jon S. Berndt + Date started: 08/20/00 + Purpose: Encapsulates the set of engines, tanks, and thrusters associated + with this aircraft + + ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) ------------- + + This program is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free Software + Foundation; either version 2 of the License, or (at your option) any later + version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., 59 Temple + Place - Suite 330, Boston, MA 02111-1307, USA. + + Further information about the GNU General Public License can also be found on + the world wide web at http://www.gnu.org. + +FUNCTIONAL DESCRIPTION +-------------------------------------------------------------------------------- +The Propulsion class is the container for the entire propulsion system, which is +comprised of engines, tanks, and "thrusters" (the device that transforms the +engine power into a force that acts on the aircraft, such as a nozzle or +propeller). Once the Propulsion class gets the config file, it reads in +information which is specific to a type of engine. Then: + +1) The appropriate engine type instance is created +2) A thruster object is instantiated, and is linked to the engine +3) At least one tank object is created, and is linked to an engine. + +At Run time each engines Calculate() method is called to return the excess power +generated during that iteration. The drag from the previous iteration is sub- +tracted to give the excess power available for thrust this pass. That quantity +is passed to the thrusters associated with a particular engine - perhaps with a +scaling mechanism (gearing?) to allow the engine to give its associated thrust- +ers specific distributed portions of the excess power. + +HISTORY +-------------------------------------------------------------------------------- +08/20/00 JSB Created + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +INCLUDES +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ + +#include "FGPropulsion.h" +#include "FGPropertyManager.h" + + +static const char *IdSrc = "$Id$"; +static const char *IdHdr = ID_PROPULSION; + +extern short debug_lvl; + +#if defined (__APPLE__) +/* Not all systems have the gcvt function */ +inline char* gcvt (double value, int ndigits, char *buf) { + /* note that this is not exactly what gcvt is supposed to do! */ + snprintf (buf, ndigits+1, "%f", value); + return buf; +} +#endif + + +/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CLASS IMPLEMENTATION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ + +FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec) +{ + Name = "FGPropulsion"; + numSelectedFuelTanks = numSelectedOxiTanks = 0; + numTanks = numEngines = numThrusters = 0; + numOxiTanks = numFuelTanks = 0; + dt = 0.0; + ActiveEngine = -1; // -1: ALL, 0: Engine 1, 1: Engine 2 ... + bind(); + Debug(0); +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +FGPropulsion::~FGPropulsion() +{ + for (unsigned int i=0; iGetdt(); + + vForces.InitMatrix(); + vMoments.InitMatrix(); + + if (!FGModel::Run()) { + for (unsigned int i=0; iSetdeltaT(dt*rate); + PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired()); + Thrusters[i]->Calculate(PowerAvailable); + vForces += Thrusters[i]->GetBodyForces(); // sum body frame forces + vMoments += Thrusters[i]->GetMoments(); // sum body frame moments + } + return false; + } else { + return true; + } +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +bool FGPropulsion::GetSteadyState(void) +{ + double PowerAvailable; + double currentThrust = 0, lastThrust=-1; + dt = State->Getdt(); + int steady_count,j=0; + bool steady=false; + + vForces.InitMatrix(); + vMoments.InitMatrix(); + + if (!FGModel::Run()) { + for (unsigned int i=0; iSetTrimMode(true); + Thrusters[i]->SetdeltaT(dt*rate); + steady=false; + steady_count=0; + while (!steady && j < 6000) { + PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired()); + lastThrust = currentThrust; + currentThrust = Thrusters[i]->Calculate(PowerAvailable); + if (fabs(lastThrust-currentThrust) < 0.0001) { + steady_count++; + if (steady_count > 120) { steady=true; } + } else { + steady_count=0; + } + j++; + } + vForces += Thrusters[i]->GetBodyForces(); // sum body frame forces + vMoments += Thrusters[i]->GetMoments(); // sum body frame moments + Engines[i]->SetTrimMode(false); + } + + return false; + } else { + return true; + } +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +bool FGPropulsion::ICEngineStart(void) +{ + double PowerAvailable; + int j; + dt = State->Getdt(); + + vForces.InitMatrix(); + vMoments.InitMatrix(); + + for (unsigned int i=0; iSetTrimMode(true); + Thrusters[i]->SetdeltaT(dt*rate); + j=0; + while (!Engines[i]->GetRunning() && j < 2000) { + PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired()); + Thrusters[i]->Calculate(PowerAvailable); + j++; + } + vForces += Thrusters[i]->GetBodyForces(); // sum body frame forces + vMoments += Thrusters[i]->GetMoments(); // sum body frame moments + Engines[i]->SetTrimMode(false); + } + return true; +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +bool FGPropulsion::Load(FGConfigFile* AC_cfg) +{ + string token, fullpath; + string engineFileName, engType; + string thrusterFileName, thrType; + string parameter; + string enginePath = FDMExec->GetEnginePath(); + double xLoc, yLoc, zLoc, Pitch, Yaw; + double P_Factor = 0, Sense = 0.0; + int Feed; + bool ThrottleAdded = false; + +# ifndef macintosh + fullpath = enginePath + "/"; +# else + fullpath = enginePath + ";"; +# endif + + AC_cfg->GetNextConfigLine(); + + while ((token = AC_cfg->GetValue()) != string("/PROPULSION")) { + + if (token == "AC_ENGINE") { // ============ READING ENGINES + + engineFileName = AC_cfg->GetValue("FILE"); + + if (debug_lvl > 0) cout << "\n Reading engine from file: " << fullpath + + engineFileName + ".xml"<< endl; + FGConfigFile Eng_cfg(fullpath + engineFileName + ".xml"); + + if (Eng_cfg.IsOpen()) { + Eng_cfg.GetNextConfigLine(); + engType = Eng_cfg.GetValue(); + + FCS->AddThrottle(); + ThrottleAdded = true; + + if (engType == "FG_ROCKET") { + Engines.push_back(new FGRocket(FDMExec, &Eng_cfg)); + } else if (engType == "FG_PISTON") { + Engines.push_back(new FGPiston(FDMExec, &Eng_cfg)); + } else if (engType == "FG_TURBOJET") { + Engines.push_back(new FGTurboJet(FDMExec, &Eng_cfg)); + } else if (engType == "FG_TURBOSHAFT") { + Engines.push_back(new FGTurboShaft(FDMExec, &Eng_cfg)); + } else if (engType == "FG_TURBOPROP") { + Engines.push_back(new FGTurboProp(FDMExec, &Eng_cfg)); + } else { + cerr << fgred << " Unrecognized engine type: " << underon << engType + << underoff << " found in config file." << fgdef << endl; + return false; + } + + AC_cfg->GetNextConfigLine(); + while ((token = AC_cfg->GetValue()) != string("/AC_ENGINE")) { + *AC_cfg >> token; + if (token == "XLOC") { *AC_cfg >> xLoc; } + else if (token == "YLOC") { *AC_cfg >> yLoc; } + else if (token == "ZLOC") { *AC_cfg >> zLoc; } + else if (token == "PITCH") { *AC_cfg >> Pitch;} + else if (token == "YAW") { *AC_cfg >> Yaw;} + else if (token == "FEED") { + *AC_cfg >> Feed; + Engines[numEngines]->AddFeedTank(Feed); + if (debug_lvl > 0) cout << " Feed tank: " << Feed << endl; + } else cerr << "Unknown identifier: " << token << " in engine file: " + << engineFileName << endl; + } + + if (debug_lvl > 0) { + cout << " X = " << xLoc << endl; + cout << " Y = " << yLoc << endl; + cout << " Z = " << zLoc << endl; + cout << " Pitch = " << Pitch << endl; + cout << " Yaw = " << Yaw << endl; + } + + Engines[numEngines]->SetPlacement(xLoc, yLoc, zLoc, Pitch, Yaw); + Engines[numEngines]->SetEngineNumber(numEngines); + numEngines++; + + } else { + + cerr << fgred << "\n Could not read engine config file: " << underon << + fullpath + engineFileName + ".xml" << underoff << fgdef << endl; + return false; + } + + } else if (token == "AC_TANK") { // ============== READING TANKS + + if (debug_lvl > 0) cout << "\n Reading tank definition" << endl; + Tanks.push_back(new FGTank(AC_cfg)); + switch(Tanks[numTanks]->GetType()) { + case FGTank::ttFUEL: + numSelectedFuelTanks++; + numFuelTanks++; + break; + case FGTank::ttOXIDIZER: + numSelectedOxiTanks++; + numOxiTanks++; + break; + } + + numTanks++; + + } else if (token == "AC_THRUSTER") { // ========== READING THRUSTERS + + thrusterFileName = AC_cfg->GetValue("FILE"); + + if (debug_lvl > 0) cout << "\n Reading thruster from file: " << + fullpath + thrusterFileName + ".xml" << endl; + FGConfigFile Thruster_cfg(fullpath + thrusterFileName + ".xml"); + + if (Thruster_cfg.IsOpen()) { + Thruster_cfg.GetNextConfigLine(); + thrType = Thruster_cfg.GetValue(); + + if (thrType == "FG_PROPELLER") { + Thrusters.push_back(new FGPropeller(FDMExec, &Thruster_cfg)); + } else if (thrType == "FG_NOZZLE") { + Thrusters.push_back(new FGNozzle(FDMExec, &Thruster_cfg)); + } + + AC_cfg->GetNextConfigLine(); + while ((token = AC_cfg->GetValue()) != string("/AC_THRUSTER")) { + *AC_cfg >> token; + if (token == "XLOC") *AC_cfg >> xLoc; + else if (token == "YLOC") *AC_cfg >> yLoc; + else if (token == "ZLOC") *AC_cfg >> zLoc; + else if (token == "PITCH") *AC_cfg >> Pitch; + else if (token == "YAW") *AC_cfg >> Yaw; + else if (token == "P_FACTOR") *AC_cfg >> P_Factor; + else if (token == "SENSE") *AC_cfg >> Sense; + else cerr << "Unknown identifier: " << token << " in engine file: " + << engineFileName << endl; + } + + Thrusters[numThrusters]->SetLocation(xLoc, yLoc, zLoc); + Thrusters[numThrusters]->SetAnglesToBody(0, Pitch, Yaw); + if (thrType == "FG_PROPELLER" && P_Factor > 0.001) { + ((FGPropeller*)Thrusters[numThrusters])->SetPFactor(P_Factor); + if (debug_lvl > 0) cout << " P-Factor: " << P_Factor << endl; + ((FGPropeller*)Thrusters[numThrusters])->SetSense(fabs(Sense)/Sense); + if (debug_lvl > 0) cout << " Sense: " << Sense << endl; + } + Thrusters[numThrusters]->SetdeltaT(dt*rate); + Thrusters[numThrusters]->SetThrusterNumber(numThrusters); + numThrusters++; + + } else { + cerr << "Could not read thruster config file: " << fullpath + + thrusterFileName + ".xml" << endl; + return false; + } + + } + AC_cfg->GetNextConfigLine(); + } + + if (!ThrottleAdded) FCS->AddThrottle(); // need to have at least one throttle + + return true; +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +string FGPropulsion::GetPropulsionStrings(void) +{ + string PropulsionStrings = ""; + bool firstime = true; + char buffer[5]; + + for (unsigned int i=0;iGetType()) { + case FGEngine::etPiston: + PropulsionStrings += (Engines[i]->GetName() + "_PwrAvail[" + buffer + "]"); + break; + case FGEngine::etRocket: + PropulsionStrings += (Engines[i]->GetName() + "_ChamberPress[" + buffer + "]"); + break; + case FGEngine::etTurboJet: + case FGEngine::etTurboProp: + case FGEngine::etTurboShaft: + break; + default: + PropulsionStrings += "INVALID ENGINE TYPE"; + break; + } + + PropulsionStrings += ", "; + + FGPropeller* Propeller = (FGPropeller*)Thrusters[i]; + switch(Thrusters[i]->GetType()) { + case FGThruster::ttNozzle: + PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "]"); + break; + case FGThruster::ttRotor: + break; + case FGThruster::ttPropeller: + PropulsionStrings += (Thrusters[i]->GetName() + "_Torque[" + buffer + "], "); + PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Roll[" + buffer + "], "); + PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Pitch[" + buffer + "], "); + PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Yaw[" + buffer + "], "); + PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "], "); + if (Propeller->IsVPitch()) + PropulsionStrings += (Thrusters[i]->GetName() + "_Pitch[" + buffer + "], "); + PropulsionStrings += (Thrusters[i]->GetName() + "_RPM[" + buffer + "]"); + break; + default: + PropulsionStrings += "INVALID THRUSTER TYPE"; + break; + } + } + + return PropulsionStrings; +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +string FGPropulsion::GetPropulsionValues(void) +{ + char buff[20]; + string PropulsionValues = ""; + bool firstime = true; + + for (unsigned int i=0;iGetType()) { + case FGEngine::etPiston: + PropulsionValues += (string(gcvt(((FGPiston*)Engines[i])->GetPowerAvailable(), 10, buff))); + break; + case FGEngine::etRocket: + PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetChamberPressure(), 10, buff))); + break; + case FGEngine::etTurboJet: + case FGEngine::etTurboProp: + case FGEngine::etTurboShaft: + break; + } + + PropulsionValues += ", "; + + switch(Thrusters[i]->GetType()) { + case FGThruster::ttNozzle: + PropulsionValues += (string(gcvt(((FGNozzle*)Thrusters[i])->GetThrust(), 10, buff))); + break; + case FGThruster::ttRotor: + break; + case FGThruster::ttPropeller: + FGPropeller* Propeller = (FGPropeller*)Thrusters[i]; + FGColumnVector3 vPFactor = Propeller->GetPFactor(); + PropulsionValues += string(gcvt(Propeller->GetTorque(), 10, buff)) + ", "; + PropulsionValues += string(gcvt(vPFactor(eRoll), 10, buff)) + ", "; + PropulsionValues += string(gcvt(vPFactor(ePitch), 10, buff)) + ", "; + PropulsionValues += string(gcvt(vPFactor(eYaw), 10, buff)) + ", "; + PropulsionValues += string(gcvt(Propeller->GetThrust(), 10, buff)) + ", "; + if (Propeller->IsVPitch()) + PropulsionValues += string(gcvt(Propeller->GetPitch(), 10, buff)) + ", "; + PropulsionValues += string(gcvt(Propeller->GetRPM(), 10, buff)); + break; + } + } + + return PropulsionValues; +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +FGColumnVector3& FGPropulsion::GetTanksMoment(void) +{ + iTank = Tanks.begin(); + vXYZtank.InitMatrix(); + while (iTank < Tanks.end()) { + vXYZtank(eX) += (*iTank)->GetX()*(*iTank)->GetContents(); + vXYZtank(eY) += (*iTank)->GetY()*(*iTank)->GetContents(); + vXYZtank(eZ) += (*iTank)->GetZ()*(*iTank)->GetContents(); + iTank++; + } + return vXYZtank; +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +double FGPropulsion::GetTanksWeight(void) +{ + double Tw = 0.0; + + iTank = Tanks.begin(); + while (iTank < Tanks.end()) { + Tw += (*iTank)->GetContents(); + iTank++; + } + return Tw; +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +double FGPropulsion::GetTanksIxx(const FGColumnVector3& vXYZcg) +{ + double I = 0.0; + iTank = Tanks.begin(); + while (iTank < Tanks.end()) { + I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetX() - vXYZcg(eX)) * (*iTank)->GetContents()/(144.0*Inertial->gravity()); + iTank++; + } + return I; +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +double FGPropulsion::GetTanksIyy(const FGColumnVector3& vXYZcg) +{ + double I = 0.0; + iTank = Tanks.begin(); + while (iTank < Tanks.end()) { + I += ((*iTank)->GetY() - vXYZcg(eY))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*Inertial->gravity()); + iTank++; + } + return I; +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +double FGPropulsion::GetTanksIzz(const FGColumnVector3& vXYZcg) +{ + double I = 0.0; + iTank = Tanks.begin(); + while (iTank < Tanks.end()) { + I += ((*iTank)->GetZ() - vXYZcg(eZ))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*Inertial->gravity()); + iTank++; + } + return I; +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +double FGPropulsion::GetTanksIxz(const FGColumnVector3& vXYZcg) +{ + double I = 0.0; + iTank = Tanks.begin(); + while (iTank < Tanks.end()) { + I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetZ() - vXYZcg(eZ)) * (*iTank)->GetContents()/(144.0*Inertial->gravity()); + iTank++; + } + return I; +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +double FGPropulsion::GetTanksIxy(const FGColumnVector3& vXYZcg) +{ + double I = 0.0; + iTank = Tanks.begin(); + while (iTank != Tanks.end()) { + I += ((*iTank)->GetX() - vXYZcg(eX))*((*iTank)->GetY() - vXYZcg(eY)) * (*iTank)->GetContents()/(144.0*Inertial->gravity()); + iTank++; + } + return I; +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +void FGPropulsion::SetMagnetos(int setting) +{ + if (ActiveEngine == -1) { + for (unsigned i=0; iSetMagnetos(setting); + } + } else { + Engines[ActiveEngine]->SetMagnetos(setting); + } +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +void FGPropulsion::SetStarter(int setting) +{ + if (ActiveEngine == -1) { + for (unsigned i=0; iSetStarter(setting); + } + } else { + if (setting == 0) + Engines[ActiveEngine]->SetStarter(false); + else + Engines[ActiveEngine]->SetStarter(true); + } +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +void FGPropulsion::SetActiveEngine(int engine) +{ + if ( unsigned(engine) > Engines.size()) + ActiveEngine = -1; + else + ActiveEngine = engine; +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +void FGPropulsion::bind(void) +{ + typedef double (FGPropulsion::*PMF)(int) const; + typedef int (FGPropulsion::*iPMF)(void) const; + /* PropertyManager->Tie("propulsion/num-engines", this, + &FGPropulsion::GetNumEngines); + PropertyManager->Tie("propulsion/num-tanks", this, + &FGPropulsion::GetNumTanks); */ + + PropertyManager->Tie("propulsion/magneto_cmd", this, + (iPMF)0, + &FGPropulsion::SetMagnetos, + true); + PropertyManager->Tie("propulsion/starter_cmd", this, + (iPMF)0, + &FGPropulsion::SetStarter, + true); + PropertyManager->Tie("propulsion/active_engine", this, + (iPMF)0, + &FGPropulsion::SetActiveEngine, + true); + + PropertyManager->Tie("propulsion/num-sel-fuel-tanks", this, + &FGPropulsion::GetnumSelectedFuelTanks); + PropertyManager->Tie("propulsion/num-sel-ox-tanks", this, + &FGPropulsion::GetnumSelectedOxiTanks); + PropertyManager->Tie("forces/fbx-prop-lbs", this,1, + (PMF)&FGPropulsion::GetForces); + PropertyManager->Tie("forces/fby-prop-lbs", this,2, + (PMF)&FGPropulsion::GetForces); + PropertyManager->Tie("forces/fbz-prop-lbs", this,3, + (PMF)&FGPropulsion::GetForces); + PropertyManager->Tie("moments/l-prop-lbsft", this,1, + (PMF)&FGPropulsion::GetMoments); + PropertyManager->Tie("moments/m-prop-lbsft", this,2, + (PMF)&FGPropulsion::GetMoments); + PropertyManager->Tie("moments/n-prop-lbsft", this,3, + (PMF)&FGPropulsion::GetMoments); + //PropertyManager->Tie("propulsion/tanks-weight-lbs", this, + // &FGPropulsion::GetTanksWeight); +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +void FGPropulsion::unbind(void) +{ + /* PropertyManager->Untie("propulsion/num-engines"); + PropertyManager->Untie("propulsion/num-tanks"); */ + PropertyManager->Untie("propulsion/num-sel-fuel-tanks"); + PropertyManager->Untie("propulsion/num-sel-ox-tanks"); + PropertyManager->Untie("propulsion/magneto_cmd"); + PropertyManager->Untie("propulsion/starter_cmd"); + PropertyManager->Untie("propulsion/active_engine"); + PropertyManager->Untie("forces/fbx-prop-lbs"); + PropertyManager->Untie("forces/fby-prop-lbs"); + PropertyManager->Untie("forces/fbz-prop-lbs"); + PropertyManager->Untie("moments/l-prop-lbsft"); + PropertyManager->Untie("moments/m-prop-lbsft"); + PropertyManager->Untie("moments/n-prop-lbsft"); + //PropertyManager->Untie("propulsion/tanks-weight-lbs"); +} + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +// The bitmasked value choices are as follows: +// unset: In this case (the default) JSBSim would only print +// out the normally expected messages, essentially echoing +// the config files as they are read. If the environment +// variable is not set, debug_lvl is set to 1 internally +// 0: This requests JSBSim not to output any messages +// whatsoever. +// 1: This value explicity requests the normal JSBSim +// startup messages +// 2: This value asks for a message to be printed out when +// a class is instantiated +// 4: When this value is set, a message is displayed when a +// FGModel object executes its Run() method +// 8: When this value is set, various runtime state variables +// are printed out periodically +// 16: When set various parameters are sanity checked and +// a message is printed out when they go out of bounds + +void FGPropulsion::Debug(int from) +{ + if (debug_lvl <= 0) return; + + if (debug_lvl & 1) { // Standard console startup message output + if (from == 0) { // Constructor + + } + } + if (debug_lvl & 2 ) { // Instantiation/Destruction notification + if (from == 0) cout << "Instantiated: FGPropulsion" << endl; + if (from == 1) cout << "Destroyed: FGPropulsion" << endl; + } + if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects + } + if (debug_lvl & 8 ) { // Runtime state variables + } + if (debug_lvl & 16) { // Sanity checking + } + if (debug_lvl & 64) { + if (from == 0) { // Constructor + cout << IdSrc << endl; + cout << IdHdr << endl; + } + } +} + diff --git a/src/FDM/JSBSim/FGPropulsion.h b/src/FDM/JSBSim/FGPropulsion.h index c0a9cf636..f5405a29f 100644 --- a/src/FDM/JSBSim/FGPropulsion.h +++ b/src/FDM/JSBSim/FGPropulsion.h @@ -1,219 +1,224 @@ -/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - - Header: FGPropulsion.h - Author: Jon S. Berndt - Date started: 08/20/00 - - ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------- - - This program is free software; you can redistribute it and/or modify it under - the terms of the GNU General Public License as published by the Free Software - Foundation; either version 2 of the License, or (at your option) any later - version. - - This program is distributed in the hope that it will be useful, but WITHOUT - ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS - FOR A PARTICULAR PURPOSE. See the GNU General Public License for more - details. - - You should have received a copy of the GNU General Public License along with - this program; if not, write to the Free Software Foundation, Inc., 59 Temple - Place - Suite 330, Boston, MA 02111-1307, USA. - - Further information about the GNU General Public License can also be found on - the world wide web at http://www.gnu.org. - -HISTORY --------------------------------------------------------------------------------- -08/20/00 JSB Created - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -SENTRY -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ - -#ifndef FGPROPULSION_H -#define FGPROPULSION_H - -/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -INCLUDES -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ - -#ifdef FGFS -# include -# ifdef SG_HAVE_STD_INCLUDES -# include -# include -# else -# include -# include -# endif -#else -# include -# include -#endif - -#include "FGModel.h" - -#include "FGRocket.h" -#include "FGPiston.h" -#include "FGTurboShaft.h" -#include "FGTurboJet.h" -#include "FGTurboProp.h" -#include "FGTank.h" -#include "FGPropeller.h" -#include "FGNozzle.h" - -/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -DEFINITIONS -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ - -#define ID_PROPULSION "$Id$" - -/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -FORWARD DECLARATIONS -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ - -/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -COMMENTS, REFERENCES, and NOTES [use "class documentation" below for API docs] -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ - -/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -CLASS DOCUMENTATION -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ - -/** Propulsion management class. - FGPropulsion manages all aspects of propulsive force generation, including - containment of engines, tanks, and thruster class instances in STL vectors, - and the interaction and communication between them. - @author Jon S. Berndt - @version $Id$ - @see FGEngine - @see FGTank - @see FGThruster - @see - Header File - @see - Source File -*/ - -/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -CLASS DECLARATION -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ - -class FGPropulsion : public FGModel -{ -public: - /// Constructor - FGPropulsion(FGFDMExec*); - /// Destructor - ~FGPropulsion(); - - /** Executes the propulsion model. - The initial plan for the FGPropulsion class calls for Run() to be executed, - performing the following tasks: -
    -
  1. Determine the drag - or power required - for the attached thrust effector - for this engine so that any feedback to the engine can be performed. This - is done by calling FGThruster::CalculatePReq()
  2. -
  3. Given 1, above, calculate the power available from the engine. This is - done by calling FGEngine::CalculatePAvail()
  4. -
  5. Next, calculate the thrust output from the thruster model given the power - available and the power required. This may also result in new performance - numbers for the thruster in the case of the propeller, at least. This - result is returned from a call to Calculate().
- - [Note: Should we be checking the Starved flag here?] */ - bool Run(void); - - /** Loads the propulsion system (engine[s], tank[s], thruster[s]). - Characteristics of the propulsion system are read in from the config file. - @param AC_cfg pointer to the config file instance that describes the - aircraft being modeled. - @return true if successfully loaded, otherwise false */ - bool Load(FGConfigFile* AC_cfg); - - /// Retrieves the number of engines defined for the aircraft. - inline unsigned int GetNumEngines(void) const {return Engines.size();} - - /** Retrieves an engine object pointer from the list of engines. - @param index the engine index within the vector container - @return the address of the specific engine, or zero if no such engine is - available */ - inline FGEngine* GetEngine(unsigned int index) { - if (index <= Engines.size()-1) return Engines[index]; - else return 0L; } - - // Retrieves the number of tanks defined for the aircraft. - inline unsigned int GetNumTanks(void) const {return Tanks.size();} - - /** Retrieves a tank object pointer from the list of tanks. - @param index the tank index within the vector container - @return the address of the specific tank, or zero if no such tank is - available */ - inline FGTank* GetTank(unsigned int index) { - if (index <= Tanks.size()-1) return Tanks[index]; - else return 0L; } - - /** Retrieves a thruster object pointer from the list of thrusters. - @param index the thruster index within the vector container - @return the address of the specific thruster, or zero if no such thruster is - available */ - inline FGThruster* GetThruster(unsigned int index) { - if (index <= Thrusters.size()-1) return Thrusters[index]; - else return 0L; } - - /** Returns the number of fuel tanks currently actively supplying fuel */ - inline int GetnumSelectedFuelTanks(void) const {return numSelectedFuelTanks;} - - /** Returns the number of oxidizer tanks currently actively supplying oxidizer */ - inline int GetnumSelectedOxiTanks(void) const {return numSelectedOxiTanks;} - - /** Loops the engines/thrusters until thrust output steady (used for trimming) */ - bool GetSteadyState(void); - - /** starts the engines in IC mode (dt=0). All engine-specific setup must - be done before calling this (i.e. magnetos, starter engage, etc.) */ - bool ICEngineStart(void); - - string GetPropulsionStrings(void); - string GetPropulsionValues(void); - - inline FGColumnVector3& GetForces(void) {return vForces; } - inline double GetForces(int n) const { return vForces(n);} - inline FGColumnVector3& GetMoments(void) {return vMoments;} - inline double GetMoments(int n) const {return vMoments(n);} - - FGColumnVector3& GetTanksMoment(void); - double GetTanksWeight(void); - - double GetTanksIxx(const FGColumnVector3& vXYZcg); - double GetTanksIyy(const FGColumnVector3& vXYZcg); - double GetTanksIzz(const FGColumnVector3& vXYZcg); - double GetTanksIxz(const FGColumnVector3& vXYZcg); - double GetTanksIxy(const FGColumnVector3& vXYZcg); - - void bind(); - void unbind(); - -private: - vector Engines; - vector Tanks; - vector ::iterator iTank; - vector Thrusters; - unsigned int numSelectedFuelTanks; - unsigned int numSelectedOxiTanks; - unsigned int numFuelTanks; - unsigned int numOxiTanks; - unsigned int numEngines; - unsigned int numTanks; - unsigned int numThrusters; - double dt; - FGColumnVector3 vForces; - FGColumnVector3 vMoments; - FGColumnVector3 vXYZtank; - void Debug(int from); -}; - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -#endif - +/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + + Header: FGPropulsion.h + Author: Jon S. Berndt + Date started: 08/20/00 + + ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------- + + This program is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free Software + Foundation; either version 2 of the License, or (at your option) any later + version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + details. + + You should have received a copy of the GNU General Public License along with + this program; if not, write to the Free Software Foundation, Inc., 59 Temple + Place - Suite 330, Boston, MA 02111-1307, USA. + + Further information about the GNU General Public License can also be found on + the world wide web at http://www.gnu.org. + +HISTORY +-------------------------------------------------------------------------------- +08/20/00 JSB Created + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +SENTRY +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ + +#ifndef FGPROPULSION_H +#define FGPROPULSION_H + +/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +INCLUDES +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ + +#ifdef FGFS +# include +# ifdef SG_HAVE_STD_INCLUDES +# include +# include +# else +# include +# include +# endif +#else +# include +# include +#endif + +#include "FGModel.h" + +#include "FGRocket.h" +#include "FGPiston.h" +#include "FGTurboShaft.h" +#include "FGTurboJet.h" +#include "FGTurboProp.h" +#include "FGTank.h" +#include "FGPropeller.h" +#include "FGNozzle.h" + +/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +DEFINITIONS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ + +#define ID_PROPULSION "$Id$" + +/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +FORWARD DECLARATIONS +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ + +/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +COMMENTS, REFERENCES, and NOTES [use "class documentation" below for API docs] +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ + +/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CLASS DOCUMENTATION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ + +/** Propulsion management class. + FGPropulsion manages all aspects of propulsive force generation, including + containment of engines, tanks, and thruster class instances in STL vectors, + and the interaction and communication between them. + @author Jon S. Berndt + @version $Id$ + @see FGEngine + @see FGTank + @see FGThruster + @see + Header File + @see + Source File +*/ + +/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +CLASS DECLARATION +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ + +class FGPropulsion : public FGModel +{ +public: + /// Constructor + FGPropulsion(FGFDMExec*); + /// Destructor + ~FGPropulsion(); + + /** Executes the propulsion model. + The initial plan for the FGPropulsion class calls for Run() to be executed, + performing the following tasks: +
    +
  1. Determine the drag - or power required - for the attached thrust effector + for this engine so that any feedback to the engine can be performed. This + is done by calling FGThruster::CalculatePReq()
  2. +
  3. Given 1, above, calculate the power available from the engine. This is + done by calling FGEngine::CalculatePAvail()
  4. +
  5. Next, calculate the thrust output from the thruster model given the power + available and the power required. This may also result in new performance + numbers for the thruster in the case of the propeller, at least. This + result is returned from a call to Calculate().
+ + [Note: Should we be checking the Starved flag here?] */ + bool Run(void); + + /** Loads the propulsion system (engine[s], tank[s], thruster[s]). + Characteristics of the propulsion system are read in from the config file. + @param AC_cfg pointer to the config file instance that describes the + aircraft being modeled. + @return true if successfully loaded, otherwise false */ + bool Load(FGConfigFile* AC_cfg); + + /// Retrieves the number of engines defined for the aircraft. + inline unsigned int GetNumEngines(void) const {return Engines.size();} + + /** Retrieves an engine object pointer from the list of engines. + @param index the engine index within the vector container + @return the address of the specific engine, or zero if no such engine is + available */ + inline FGEngine* GetEngine(unsigned int index) { + if (index <= Engines.size()-1) return Engines[index]; + else return 0L; } + + // Retrieves the number of tanks defined for the aircraft. + inline unsigned int GetNumTanks(void) const {return Tanks.size();} + + /** Retrieves a tank object pointer from the list of tanks. + @param index the tank index within the vector container + @return the address of the specific tank, or zero if no such tank is + available */ + inline FGTank* GetTank(unsigned int index) { + if (index <= Tanks.size()-1) return Tanks[index]; + else return 0L; } + + /** Retrieves a thruster object pointer from the list of thrusters. + @param index the thruster index within the vector container + @return the address of the specific thruster, or zero if no such thruster is + available */ + inline FGThruster* GetThruster(unsigned int index) { + if (index <= Thrusters.size()-1) return Thrusters[index]; + else return 0L; } + + /** Returns the number of fuel tanks currently actively supplying fuel */ + inline int GetnumSelectedFuelTanks(void) const {return numSelectedFuelTanks;} + + /** Returns the number of oxidizer tanks currently actively supplying oxidizer */ + inline int GetnumSelectedOxiTanks(void) const {return numSelectedOxiTanks;} + + /** Loops the engines/thrusters until thrust output steady (used for trimming) */ + bool GetSteadyState(void); + + /** starts the engines in IC mode (dt=0). All engine-specific setup must + be done before calling this (i.e. magnetos, starter engage, etc.) */ + bool ICEngineStart(void); + + string GetPropulsionStrings(void); + string GetPropulsionValues(void); + + inline FGColumnVector3& GetForces(void) {return vForces; } + inline double GetForces(int n) const { return vForces(n);} + inline FGColumnVector3& GetMoments(void) {return vMoments;} + inline double GetMoments(int n) const {return vMoments(n);} + + FGColumnVector3& GetTanksMoment(void); + double GetTanksWeight(void); + + double GetTanksIxx(const FGColumnVector3& vXYZcg); + double GetTanksIyy(const FGColumnVector3& vXYZcg); + double GetTanksIzz(const FGColumnVector3& vXYZcg); + double GetTanksIxz(const FGColumnVector3& vXYZcg); + double GetTanksIxy(const FGColumnVector3& vXYZcg); + + void SetMagnetos(int setting); + void SetStarter(int setting); + void SetActiveEngine(int engine); + + void bind(); + void unbind(); + +private: + vector Engines; + vector Tanks; + vector ::iterator iTank; + vector Thrusters; + unsigned int numSelectedFuelTanks; + unsigned int numSelectedOxiTanks; + unsigned int numFuelTanks; + unsigned int numOxiTanks; + unsigned int numEngines; + unsigned int numTanks; + unsigned int numThrusters; + int ActiveEngine; + double dt; + FGColumnVector3 vForces; + FGColumnVector3 vMoments; + FGColumnVector3 vXYZtank; + void Debug(int from); +}; + +//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +#endif + diff --git a/src/FDM/JSBSim/FGRotation.cpp b/src/FDM/JSBSim/FGRotation.cpp index aa48af0e1..88eeea4d9 100644 --- a/src/FDM/JSBSim/FGRotation.cpp +++ b/src/FDM/JSBSim/FGRotation.cpp @@ -80,9 +80,14 @@ CLASS IMPLEMENTATION FGRotation::FGRotation(FGFDMExec* fdmex) : FGModel(fdmex) { Name = "FGRotation"; - cTht=cPhi=cPsi=1.0; - sTht=sPhi=sPsi=0.0; - + cTht = cPhi = cPsi = 1.0; + sTht = sPhi = sPsi = 0.0; + + vPQRdot.InitMatrix(); + vPQRdot_prev[0].InitMatrix(); + vPQRdot_prev[1].InitMatrix(); + vPQRdot_prev[2].InitMatrix(); + bind(); Debug(0); @@ -110,10 +115,12 @@ bool FGRotation::Run(void) N1 = vMoments(eN) - (Iyy-Ixx)*vPQR(eP)*vPQR(eQ) - Ixz*vPQR(eR)*vPQR(eQ); vPQRdot(eP) = (L2*Izz - N1*Ixz) / (Ixx*Izz - Ixz*Ixz); - vPQRdot(eQ) = (vMoments(eM) - (Ixx-Izz)*vPQR(eP)*vPQR(eR) - Ixz*(vPQR(eP)*vPQR(eP) - vPQR(eR)*vPQR(eR)))/Iyy; + vPQRdot(eQ) = (vMoments(eM) - (Ixx-Izz)*vPQR(eP)*vPQR(eR) + - Ixz*(vPQR(eP)*vPQR(eP) - vPQR(eR)*vPQR(eR)))/Iyy; vPQRdot(eR) = (N1*Ixx + L2*Ixz) / (Ixx*Izz - Ixz*Ixz); - vPQR += dt*rate*(vlastPQRdot + vPQRdot)/2.0; + vPQR += State->Integrate(FGState::TRAPZ, dt*rate, vPQRdot, vPQRdot_prev); + vAeroPQR = vPQR + Atmosphere->GetTurbPQR(); State->IntegrateQuat(vPQR, rate); @@ -131,8 +138,6 @@ bool FGRotation::Run(void) vEulerRates(ePsi) = (vPQR(2)*sPhi + vPQR(3)*cPhi)/cTht; } - vlastPQRdot = vPQRdot; - if (debug_lvl > 1) Debug(2); return false; diff --git a/src/FDM/JSBSim/FGRotation.h b/src/FDM/JSBSim/FGRotation.h index 068b44c29..5122535fc 100644 --- a/src/FDM/JSBSim/FGRotation.h +++ b/src/FDM/JSBSim/FGRotation.h @@ -121,15 +121,14 @@ public: void bind(void); void unbind(void); - private: FGColumnVector3 vPQR; FGColumnVector3 vAeroPQR; FGColumnVector3 vPQRdot; + FGColumnVector3 vPQRdot_prev[3]; FGColumnVector3 vMoments; FGColumnVector3 vEuler; FGColumnVector3 vEulerRates; - FGColumnVector3 vlastPQRdot; double cTht,sTht; double cPhi,sPhi; diff --git a/src/FDM/JSBSim/FGState.cpp b/src/FDM/JSBSim/FGState.cpp index f76e5d027..5759173d0 100644 --- a/src/FDM/JSBSim/FGState.cpp +++ b/src/FDM/JSBSim/FGState.cpp @@ -64,13 +64,6 @@ MACROS CLASS IMPLEMENTATION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -// -// For every term registered here there must be a corresponding handler in -// GetParameter() below that retrieves that parameter. Also, there must be an -// entry in the enum eParam definition in FGJSBBase.h. The ID is what must be used -// in any config file entry which references that item. - FGState::FGState(FGFDMExec* fdex) { FDMExec = fdex; @@ -78,7 +71,6 @@ FGState::FGState(FGFDMExec* fdex) a = 1000.0; sim_time = 0.0; dt = 1.0/120.0; - ActiveEngine = -1; Aircraft = FDMExec->GetAircraft(); Translation = FDMExec->GetTranslation(); @@ -92,6 +84,8 @@ FGState::FGState(FGFDMExec* fdex) Propulsion = FDMExec->GetPropulsion(); PropertyManager = FDMExec->GetPropertyManager(); + for(int i=0;i<3;i++) vQdot_prev[i].InitMatrix(); + InitPropertyMaps(); bind(); @@ -159,7 +153,6 @@ bool FGState::Reset(string path, string acname, string fname) resetfile >> token; } - Position->SetLatitude(latitude*degtorad); Position->SetLongitude(longitude*degtorad); Position->Seth(h); @@ -336,11 +329,10 @@ void FGState::IntegrateQuat(FGColumnVector3 vPQR, int rate) vQdot(2) = 0.5*(vQtrn(1)*vPQR(eP) + vQtrn(3)*vPQR(eR) - vQtrn(4)*vPQR(eQ)); vQdot(3) = 0.5*(vQtrn(1)*vPQR(eQ) + vQtrn(4)*vPQR(eP) - vQtrn(2)*vPQR(eR)); vQdot(4) = 0.5*(vQtrn(1)*vPQR(eR) + vQtrn(2)*vPQR(eQ) - vQtrn(3)*vPQR(eP)); - vQtrn += 0.5*dt*rate*(vlastQdot + vQdot); + + vQtrn += Integrate(TRAPZ, dt*rate, vQdot, vQdot_prev); vQtrn.Normalize(); - - vlastQdot = vQdot; } //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -553,17 +545,17 @@ void FGState::InitPropertyMaps(void) ParamNameToProp[ "FG_THROTTLE_POS" ]="fcs/throttle-pos-norm"; ParamNameToProp[ "FG_MIXTURE_CMD" ]="fcs/mixture-cmd-norm"; ParamNameToProp[ "FG_MIXTURE_POS" ]="fcs/mixture-pos-norm"; - ParamNameToProp[ "FG_MAGNETO_CMD" ]="zero"; - ParamNameToProp[ "FG_STARTER_CMD" ]="zero"; - ParamNameToProp[ "FG_ACTIVE_ENGINE" ]="zero"; + ParamNameToProp[ "FG_MAGNETO_CMD" ]="propulsion/magneto_cmd"; + ParamNameToProp[ "FG_STARTER_CMD" ]="propulsion/starter_cmd"; + ParamNameToProp[ "FG_ACTIVE_ENGINE" ]="propulsion/active_engine"; ParamNameToProp[ "FG_HOVERB" ]="aero/h_b-mac-ft"; ParamNameToProp[ "FG_PITCH_TRIM_CMD" ]="fcs/pitch-trim-cmd-norm"; ParamNameToProp[ "FG_YAW_TRIM_CMD" ]="fcs/yaw-trim-cmd-norm"; ParamNameToProp[ "FG_ROLL_TRIM_CMD" ]="fcs/roll-trim-cmd-norm"; - ParamNameToProp[ "FG_LEFT_BRAKE_CMD" ]="zero"; - ParamNameToProp[ "FG_CENTER_BRAKE_CMD" ]="zero"; - ParamNameToProp[ "FG_RIGHT_BRAKE_CMD" ]="zero"; - ParamNameToProp[ "FG_SET_LOGGING" ]="zero"; + ParamNameToProp[ "FG_LEFT_BRAKE_CMD" ]="fcs/left_brake"; + ParamNameToProp[ "FG_CENTER_BRAKE_CMD" ]="fcs/center_brake"; + ParamNameToProp[ "FG_RIGHT_BRAKE_CMD" ]="fcs/right_brake"; + ParamNameToProp[ "FG_SET_LOGGING" ]="sim/set_logging"; ParamNameToProp[ "FG_ALPHAH" ]="aero/alpha-rad"; ParamNameToProp[ "FG_ALPHAW" ]="aero/alpha-wing-rad"; ParamNameToProp[ "FG_LBARH" ]="metrics/lh-norm"; diff --git a/src/FDM/JSBSim/FGState.h b/src/FDM/JSBSim/FGState.h index 5d7b70dcd..681e94611 100644 --- a/src/FDM/JSBSim/FGState.h +++ b/src/FDM/JSBSim/FGState.h @@ -229,6 +229,77 @@ public: @param rate the integration rate in seconds. */ void IntegrateQuat(FGColumnVector3 vPQR, int rate); + + // ======================================= General Purpose INTEGRATOR + + enum iType {AB4, AB3, AB2, AM3, EULER, TRAPZ}; + + /** Multi-method integrator. + @param type Type of intergation scheme to use. Can be one of: +
    +
  • AB4 - Adams-Bashforth, fourth order
  • +
  • AB3 - Adams-Bashforth, third order
  • +
  • AB2 - Adams-Bashforth, second order
  • +
  • AM3 - Adams Moulton, third order
  • +
  • EULER - Euler
  • +
  • TRAPZ - Trapezoidal
  • +
+ @param delta_t the integration time step in seconds + @param vTDeriv a reference to the current value of the time derivative of + the quantity being integrated (i.e. if vUVW is being integrated + vTDeriv is the current value of vUVWdot) + @param vLastArray an array of previously calculated and saved values of + the quantity being integrated (i.e. if vUVW is being integrated + vLastArray[0] is the past value of vUVWdot, vLastArray[1] is the value of + vUVWdot prior to that, etc.) + @return the current, incremental value of the item integrated to add to the + previous value. */ + + template T Integrate(iType type, double delta_t, T& vTDeriv, T *vLastArray) + { + T vResult; + + switch (type) { + case AB4: + vResult = (delta_t/24.0)*( 55.0 * vTDeriv + - 59.0 * vLastArray[0] + + 37.0 * vLastArray[1] + - 9.0 * vLastArray[2] ); + vLastArray[2] = vLastArray[1]; + vLastArray[1] = vLastArray[0]; + vLastArray[0] = vTDeriv; + break; + case AB3: + vResult = (delta_t/12.0)*( 23.0 * vTDeriv + - 16.0 * vLastArray[0] + + 5.0 * vLastArray[1] ); + vLastArray[1] = vLastArray[0]; + vLastArray[0] = vTDeriv; + break; + case AB2: + vResult = (delta_t/2.0)*( 3.0 * vTDeriv - vLastArray[0] ); + vLastArray[0] = vTDeriv; + break; + case AM3: + vResult = (delta_t/12.0)*( 5.0 * vTDeriv + + 8.0 * vLastArray[0] + - 1.0 * vLastArray[1] ); + vLastArray[1] = vLastArray[0]; + vLastArray[0] = vTDeriv; + break; + case EULER: + vResult = delta_t * vTDeriv; + break; + case TRAPZ: + vResult = (delta_t*0.5) * (vTDeriv + vLastArray[0]); + vLastArray[0] = vTDeriv; + break; + } + + return vResult; + } + + // ======================================= /** Calculates Euler angles from the local-to-body matrix. @return a reference to the vEuler column vector. @@ -275,8 +346,6 @@ public: void ReportState(void); inline string GetPropertyName(string prm) { return ParamNameToProp[prm]; } - //inline string GetPropertyName(eParam prm) { return ParamIdxToProp[prm]; } - //inline eParam GetParam(string property) { return PropToParam[property]; } void bind(); void unbind(); @@ -292,7 +361,7 @@ private: FGMatrix33 mTs2b; FGMatrix33 mTb2s; FGColumnVector4 vQtrn; - FGColumnVector4 vlastQdot; + FGColumnVector4 vQdot_prev[3]; FGColumnVector4 vQdot; FGColumnVector3 vUVW; FGColumnVector3 vLocalVelNED; @@ -313,22 +382,9 @@ private: FGPropulsion* Propulsion; FGPropertyManager* PropertyManager; - /* typedef map CoeffMap; - CoeffMap coeffdef; - - typedef map ParamMap; - //ParamMap paramdef; */ - - typedef map ParamNameMap; ParamNameMap ParamNameToProp; - typedef map ParamIdxMap; - ParamIdxMap ParamIdxToProp; - //CoeffMap PropToParam; - - int ActiveEngine; - void InitPropertyMaps(void); void Debug(int from); diff --git a/src/FDM/JSBSim/FGTranslation.cpp b/src/FDM/JSBSim/FGTranslation.cpp index 8c4aa657c..9cdaf9e4f 100644 --- a/src/FDM/JSBSim/FGTranslation.cpp +++ b/src/FDM/JSBSim/FGTranslation.cpp @@ -88,6 +88,12 @@ FGTranslation::FGTranslation(FGFDMExec* fdmex) : FGModel(fdmex) Mach = 0.0; alpha = beta = 0.0; adot = bdot = 0.0; + + vUVWdot.InitMatrix(); + vUVWdot_prev[0].InitMatrix(); + vUVWdot_prev[1].InitMatrix(); + vUVWdot_prev[2].InitMatrix(); + bind(); Debug(0); } @@ -104,8 +110,6 @@ FGTranslation::~FGTranslation(void) bool FGTranslation::Run(void) { - double Tc = 0.5*State->Getdt()*rate; - if (!FGModel::Run()) { mVel(1,1) = 0.0; @@ -120,7 +124,7 @@ bool FGTranslation::Run(void) vUVWdot = mVel*Rotation->GetPQR() + Aircraft->GetBodyAccel(); - vUVW += Tc*(vUVWdot + vlastUVWdot); + vUVW += State->Integrate(FGState::TRAPZ, State->Getdt()*rate, vUVWdot, vUVWdot_prev); vAeroUVW = vUVW + State->GetTl2b()*Atmosphere->GetWindNED(); @@ -155,8 +159,6 @@ bool FGTranslation::Run(void) qbarUV = 0.5*Atmosphere->GetDensity()*(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eV)*vAeroUVW(eV)); Mach = Vt / State->Geta(); - vlastUVWdot = vUVWdot; - if (debug_lvl > 1) Debug(1); return false; diff --git a/src/FDM/JSBSim/FGTranslation.h b/src/FDM/JSBSim/FGTranslation.h index 90fb53050..8a17e9581 100644 --- a/src/FDM/JSBSim/FGTranslation.h +++ b/src/FDM/JSBSim/FGTranslation.h @@ -128,8 +128,8 @@ public: private: FGColumnVector3 vUVW; FGColumnVector3 vUVWdot; - FGColumnVector3 vlastUVWdot; - FGMatrix33 mVel; + FGColumnVector3 vUVWdot_prev[3]; + FGMatrix33 mVel; FGColumnVector3 vAeroUVW; double Vt, Mach; @@ -137,7 +137,6 @@ private: double dt; double alpha, beta; double adot,bdot; - void Debug(int from); };