%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGAerodynamics.h"
-#include "FGTranslation.h"
+#include "FGPropagate.h"
#include "FGAircraft.h"
#include "FGState.h"
#include "FGMassBalance.h"
static const char *IdSrc = "$Id$";
static const char *IdHdr = ID_AERODYNAMICS;
-const unsigned NAxes=6;
+const unsigned NAxes=6;
const char* AxisNames[] = { "drag", "side-force", "lift", "rolling-moment",
- "pitching-moment","yawing-moment" };
+ "pitching-moment","yawing-moment" };
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
AxisIdx["YAW"] = 5;
Coeff = new CoeffArray[6];
-
+
impending_stall = stall_hyst = 0.0;
alphaclmin = alphaclmax = 0.0;
alphahystmin = alphahystmax = 0.0;
clsq = lod = 0.0;
- alphaw = 0.0;
+ alphaw = 0.0;
bi2vel = ci2vel = 0.0;
bind();
FGAerodynamics::~FGAerodynamics()
{
unsigned int i,j;
-
+
unbind();
-
+
for (i=0; i<6; i++) {
for (j=0; j<Coeff[i].size(); j++) {
delete Coeff[i][j];
}
}
delete[] Coeff;
-
+
Debug(1);
}
if (!FGModel::Run()) {
- twovel = 2*Translation->GetVt();
+ twovel = 2*Auxiliary->GetVt();
if (twovel != 0) {
bi2vel = Aircraft->GetWingSpan() / twovel;
ci2vel = Aircraft->Getcbar() / twovel;
- }
-
- alphaw = Translation->Getalpha() + Aircraft->GetWingIncidence();
-
- alpha = Translation->Getalpha();
-
+ }
+
+ alphaw = Auxiliary->Getalpha() + Aircraft->GetWingIncidence();
+
+ alpha = Auxiliary->Getalpha();
+
if (alphaclmax != 0) {
if (alpha > 0.85*alphaclmax) {
impending_stall = 10*(alpha/alphaclmax - 0.85);
impending_stall = 0;
}
}
-
+
if (alphahystmax != 0.0 && alphahystmin != 0.0) {
if (alpha > alphahystmax) {
stall_hyst = 1;
} else if (alpha < alphahystmin) {
stall_hyst = 0;
- }
+ }
}
-
+
vLastFs = vFs;
vFs.InitMatrix();
//correct signs of drag and lift to wind axes convention
//positive forward, right, down
- if ( Translation->Getqbar() > 0) {
- clsq = vFs(eLift) / (Aircraft->GetWingArea()*Translation->Getqbar());
+ if ( Auxiliary->Getqbar() > 0) {
+ clsq = vFs(eLift) / (Aircraft->GetWingArea()*Auxiliary->Getqbar());
clsq *= clsq;
}
if ( vFs(eDrag) > 0) {
lod = vFs(eLift) / vFs(eDrag);
- }
-
+ }
+
//correct signs of drag and lift to wind axes convention
//positive forward, right, down
vFs(eDrag)*=-1; vFs(eLift)*=-1;
}
bindModel();
-
+
return true;
}
PropertyManager->Tie("forces/lod-norm", this,
&FGAerodynamics::GetLoD);
PropertyManager->Tie("aero/cl-squared-norm", this,
- &FGAerodynamics::GetClSquared);
+ &FGAerodynamics::GetClSquared);
PropertyManager->Tie("aero/alpha-max-deg", this,
&FGAerodynamics::GetAlphaCLMax,
&FGAerodynamics::SetAlphaCLMax,
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGAerodynamics::bindModel(void)
-{
+{
unsigned i,j;
FGPropertyManager* node;
string axis_node_name;
node = node->GetNode( string(AxisNames[i]),true );
for (j=0; j < Coeff[i].size(); j++) {
Coeff[i][j]->bind(node);
- }
- node = (FGPropertyManager*)node->getParent();
+ }
+ node = (FGPropertyManager*)node->getParent();
}
}
PropertyManager->Untie("forces/fwy-aero-lbs");
PropertyManager->Untie("forces/fwz-aero-lbs");
PropertyManager->Untie("forces/lod-norm");
- PropertyManager->Untie("aero/cl-squared-norm");
+ PropertyManager->Untie("aero/cl-squared-norm");
PropertyManager->Untie("aero/alpha-max-deg");
PropertyManager->Untie("aero/alpha-min-deg");
PropertyManager->Untie("aero/bi2vel");
for ( i=0; i<NAxes; i++ ) {
for ( j=0; j < Coeff[i].size(); j++ ) {
Coeff[i][j]->unbind();
-
+
}
}
}
#include "FGAerodynamics.h"
#include "FGState.h"
#include "FGFDMExec.h"
-#include "FGPosition.h"
+#include "FGPropagate.h"
#include "FGPropertyManager.h"
namespace JSBSim {
if (!FGModel::Run()) { // if false then execute this Run()
vForces.InitMatrix();
vForces += Aerodynamics->GetForces();
- vForces += Inertial->GetForces();
vForces += Propulsion->GetForces();
vForces += GroundReactions->GetForces();
} else if (parameter == "AC_VRP") {
*AC_cfg >> vXYZvrp(eX) >> vXYZvrp(eY) >> vXYZvrp(eZ);
if (debug_lvl > 0) cout << " Visual Ref Pt (x, y, z): " << vXYZvrp << endl;
- Position->SetVRP(vXYZvrp);
} else if (parameter == "AC_POINTMASS") {
*AC_cfg >> pmWt >> pmX >> pmY >> pmZ;
MassBalance->AddPointMass(pmWt, pmX, pmY, pmZ);
Module: FGAtmosphere.cpp
Author: Jon Berndt
- Implementation of 1959 Standard Atmosphere added by Tony Peden
+ Implementation of 1959 Standard Atmosphere added by Tony Peden
Date started: 11/24/98
Purpose: Models the atmosphere
Called by: FGSimExec
--------------------------------------------------------------------------------
11/24/98 JSB Created
07/23/99 TP Added implementation of 1959 Standard Atmosphere
- Moved calculation of Mach number to FGTranslation
+ Moved calculation of Mach number to FGPropagate
Later updated to '76 model
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
COMMENTS, REFERENCES, and NOTES
#include "FGState.h"
#include "FGFDMExec.h"
#include "FGAircraft.h"
-#include "FGPosition.h"
+#include "FGPropagate.h"
#include "FGInertial.h"
#include "FGPropertyManager.h"
// turbType = ttBerndt;
TurbGain = 0.0;
TurbRate = 1.0;
-
+
bind();
Debug(0);
}
temperature=&intTemperature;
pressure=&intPressure;
density=&intDensity;
-
+
useExternal=false;
-
+
return true;
}
if (!FGModel::Run()) { // if false then execute this Run()
//do temp, pressure, and density first
if (!useExternal) {
- h = Position->Geth();
+ h = Propagate->Geth();
Calculate(h);
- }
+ }
if (turbType != ttNone) {
Turbulence();
i = lastIndex;
if (altitude < htab[lastIndex]) {
- if (altitude <= 0) {
+ if (altitude <= 0) {
i = 0;
altitude=0;
} else {
i = lastIndex-1;
while (htab[i] > altitude) i--;
- }
+ }
} else if (altitude > htab[lastIndex+1]) {
if (altitude >= htab[7]) {
i = 7;
} else {
i = lastIndex+1;
while (htab[i+1] < altitude) i++;
- }
- }
+ }
+ }
switch(i) {
case 1: // 36089 ft.
refpress = 2116.22; // psf
//refdens = 0.00237767; // slugs/cubic ft.
break;
-
+
}
-
+
if (slope == 0) {
intTemperature = reftemp;
intPressure = refpress*exp(-Inertial->SLgravity()/(reftemp*Reng)*(altitude-htab[i]));
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// Return the pressure at an arbitrary altitude and then restore the internal state
+
+double FGAtmosphere::GetPressure(double alt) {
+ Calculate(alt);
+ double p = *pressure;
+ // Reset the internal atmospheric state
+ Run();
+ return(p);
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// square a value, but preserve the original sign
-static inline double
-square_signed (double value)
+
+static inline double square_signed (double value)
{
if (value < 0)
return value * value * -1;
return value * value;
}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
void FGAtmosphere::Turbulence(void)
{
switch (turbType) {
vDirection += vDirectionAccel*rate*State->Getdt();
vDirection.Normalize();
-
+
// Diminish turbulence within three wingspans
// of the ground
vTurbulence = TurbGain * Magnitude * vDirection;
- double HOverBMAC = Position->GetHOverBMAC();
+ double HOverBMAC = Auxiliary->GetHOverBMAC();
if (HOverBMAC < 3.0)
vTurbulence *= (HOverBMAC / 3.0) * (HOverBMAC / 3.0);
vTurbulenceGrad = TurbGain*MagnitudeAccel * vDirection;
- vBodyTurbGrad = State->GetTl2b()*vTurbulenceGrad;
-
+ vBodyTurbGrad = Propagate->GetTl2b()*vTurbulenceGrad;
+
if (Aircraft->GetWingSpan() > 0) {
vTurbPQR(eP) = vBodyTurbGrad(eY)/Aircraft->GetWingSpan();
} else {
vDirectiondAccelDt(eY) = 1 - 2.0*(double(rand())/double(RAND_MAX));
vDirectiondAccelDt(eZ) = 1 - 2.0*(double(rand())/double(RAND_MAX));
-
+
MagnitudedAccelDt = 1 - 2.0*(double(rand())/double(RAND_MAX)) - Magnitude;
MagnitudeAccel += MagnitudedAccelDt*rate*State->Getdt();
Magnitude += MagnitudeAccel*rate*State->Getdt();
// Diminish z-vector within two wingspans
// of the ground
- double HOverBMAC = Position->GetHOverBMAC();
+ double HOverBMAC = Auxiliary->GetHOverBMAC();
if (HOverBMAC < 2.0)
vDirection(eZ) *= HOverBMAC / 2.0;
vDirection.Normalize();
-
+
vTurbulence = TurbGain*Magnitude * vDirection;
vTurbulenceGrad = TurbGain*MagnitudeAccel * vDirection;
- vBodyTurbGrad = State->GetTl2b()*vTurbulenceGrad;
+ vBodyTurbGrad = Propagate->GetTl2b()*vTurbulenceGrad;
vTurbPQR(eP) = vBodyTurbGrad(eY)/Aircraft->GetWingSpan();
if (Aircraft->GetHTailArm() > 0)
vTurbPQR(eQ) = vBodyTurbGrad(eZ)/Aircraft->GetHTailArm();
density=&intDensity;
useExternal=false;
}
-
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
&FGAtmosphere::GetTemperature);
PropertyManager->Tie("atmosphere/rho-slugs_ft3", this,
&FGAtmosphere::GetDensity);
- PropertyManager->Tie("atmosphere/P-psf", this,
- &FGAtmosphere::GetPressure);
+// PropertyManager->Tie("atmosphere/P-psf", this,
+// &FGAtmosphere::GetPressure);
PropertyManager->Tie("atmosphere/a-fps", this,
&FGAtmosphere::GetSoundSpeed);
PropertyManager->Tie("atmosphere/T-sl-R", this,
{
PropertyManager->Untie("atmosphere/T-R");
PropertyManager->Untie("atmosphere/rho-slugs_ft3");
- PropertyManager->Untie("atmosphere/P-psf");
+// PropertyManager->Untie("atmosphere/P-psf");
PropertyManager->Untie("atmosphere/a-fps");
PropertyManager->Untie("atmosphere/T-sl-R");
PropertyManager->Untie("atmosphere/rho-sl-slugs_ft3");
--------------------------------------------------------------------------------
11/24/98 JSB Created
07/23/99 TP Added implementation of 1959 Standard Atmosphere
- Moved calculation of Mach number to FGTranslation
+ Moved calculation of Mach number to FGPropagate
Updated to '76 model
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
inline double GetDensity(void) const {return *density;}
/// Returns the pressure in psf.
inline double GetPressure(void) const {return *pressure;}
+ /// Returns the pressure at an arbitrary altitude in psf
+ double GetPressure(double alt);
/// Returns the speed of sound in ft/sec.
inline double GetSoundSpeed(void) const {return soundspeed;}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
+
Module: FGAuxiliary.cpp
Author: Tony Peden, Jon Berndt
Date started: 01/26/99
Purpose: Calculates additional parameters needed by the visual system, etc.
Called by: FGSimExec
-
+
------------- 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
#include "FGAuxiliary.h"
#include "FGAerodynamics.h"
-#include "FGTranslation.h"
-#include "FGRotation.h"
+#include "FGPropagate.h"
#include "FGAtmosphere.h"
#include "FGState.h"
#include "FGFDMExec.h"
FGAuxiliary::FGAuxiliary(FGFDMExec* fdmex) : FGModel(fdmex)
{
Name = "FGAuxiliary";
- vcas = veas = mach = qbar = pt = tat = 0;
+ vcas = veas = pt = tat = 0;
psl = rhosl = 1;
earthPosAngle = 0.0;
-
+ qbar = 0;
+ qbarUW = 0.0;
+ qbarUV = 0.0;
+ Mach = 0.0;
+ alpha = beta = 0.0;
+ adot = bdot = 0.0;
+ gamma = Vt = Vground = 0.0;
+ psigt = 0.0;
+ day_of_year = 1;
+ seconds_in_day = 0.0;
+ hoverbmac = hoverbcg = 0.0;
+
+ vPilotAccel.InitMatrix();
vPilotAccelN.InitMatrix();
-
+ vToEyePt.InitMatrix();
+ vAeroPQR.InitMatrix();
+ vEulerRates.InitMatrix();
+
bind();
-
+
Debug(0);
}
bool FGAuxiliary::Run()
{
- double A,B,D;
-
- if (!FGModel::Run()) {
- GetState();
-
- //calculate total temperature assuming isentropic flow
- tat=sat*(1 + 0.2*mach*mach);
- tatc=RankineToCelsius(tat);
-
- if (mach < 1) { //calculate total pressure assuming isentropic flow
- pt = p*pow((1 + 0.2*machU*machU),3.5);
+ double A,B,D, hdot_Vt;
+ const FGColumnVector3& vPQR = Propagate->GetPQR();
+ const FGColumnVector3& vUVW = Propagate->GetUVW();
+ const FGColumnVector3& vUVWdot = Propagate->GetUVWdot();
+ const FGColumnVector3& vVel = Propagate->GetVel();
+
+ if (!FGModel::Run())
+ {
+ p = Atmosphere->GetPressure();
+ rhosl = Atmosphere->GetDensitySL();
+ psl = Atmosphere->GetPressureSL();
+ sat = Atmosphere->GetTemperature();
+
+// Rotation
+
+ double cTht = Propagate->GetCostht();
+ double cPhi = Propagate->GetCosphi();
+ double sPhi = Propagate->GetSinphi();
+
+ vEulerRates(eTht) = vPQR(eQ)*cPhi - vPQR(eR)*sPhi;
+ if (cTht != 0.0) {
+ vEulerRates(ePsi) = (vPQR(eQ)*sPhi + vPQR(eR)*cPhi)/cTht;
+ vEulerRates(ePhi) = vPQR(eP) + vEulerRates(ePsi)*sPhi;
+ }
+
+ vAeroPQR = vPQR + Atmosphere->GetTurbPQR();
+
+// Translation
+
+ vAeroUVW = vUVW + Propagate->GetTl2b()*Atmosphere->GetWindNED();
+
+ Vt = vAeroUVW.Magnitude();
+ if ( Vt > 0.05) {
+ if (vAeroUVW(eW) != 0.0)
+ alpha = vAeroUVW(eU)*vAeroUVW(eU) > 0.0 ? atan2(vAeroUVW(eW), vAeroUVW(eU)) : 0.0;
+ if (vAeroUVW(eV) != 0.0)
+ beta = vAeroUVW(eU)*vAeroUVW(eU)+vAeroUVW(eW)*vAeroUVW(eW) > 0.0 ? atan2(vAeroUVW(eV),
+ sqrt(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW))) : 0.0;
+
+ double mUW = (vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW));
+ double signU=1;
+ if (vAeroUVW(eU) != 0.0)
+ signU = vAeroUVW(eU)/fabs(vAeroUVW(eU));
+
+ if ( (mUW == 0.0) || (Vt == 0.0) ) {
+ adot = 0.0;
+ bdot = 0.0;
+ } else {
+ adot = (vAeroUVW(eU)*vUVWdot(eW) - vAeroUVW(eW)*vUVWdot(eU))/mUW;
+ bdot = (signU*mUW*vUVWdot(eV) - vAeroUVW(eV)*(vAeroUVW(eU)*vUVWdot(eU)
+ + vAeroUVW(eW)*vUVWdot(eW)))/(Vt*Vt*sqrt(mUW));
+ }
} else {
- // shock in front of pitot tube, we'll assume its normal and use
- // the Rayleigh Pitot Tube Formula, i.e. the ratio of total
- // pressure behind the shock to the static pressure in front
+ alpha = beta = adot = bdot = 0;
+ }
+
+ qbar = 0.5*Atmosphere->GetDensity()*Vt*Vt;
+ qbarUW = 0.5*Atmosphere->GetDensity()*(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW));
+ qbarUV = 0.5*Atmosphere->GetDensity()*(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eV)*vAeroUVW(eV));
+ Mach = Vt / Atmosphere->GetSoundSpeed();
+ MachU = vMachUVW(eU) = vAeroUVW(eU) / Atmosphere->GetSoundSpeed();
+ vMachUVW(eV) = vAeroUVW(eV) / Atmosphere->GetSoundSpeed();
+ vMachUVW(eW) = vAeroUVW(eW) / Atmosphere->GetSoundSpeed();
+
+// Position
+
+ Vground = sqrt( vVel(eNorth)*vVel(eNorth) + vVel(eEast)*vVel(eEast) );
+
+ if (vVel(eNorth) == 0) psigt = 0;
+ else psigt = atan2(vVel(eEast), vVel(eNorth));
+
+ if (psigt < 0.0) psigt += 2*M_PI;
- B = 5.76*machU*machU/(5.6*machU*machU - 0.8);
+ if (Vt != 0) {
+ hdot_Vt = -vVel(eDown)/Vt;
+ if (fabs(hdot_Vt) <= 1) gamma = asin(hdot_Vt);
+ } else {
+ gamma = 0.0;
+ }
- // The denominator above is zero for Mach ~ 0.38, for which
- // we'll never be here, so we're safe
+ tat = sat*(1 + 0.2*Mach*Mach); // Total Temperature, isentropic flow
+ tatc = RankineToCelsius(tat);
- D = (2.8*machU*machU-0.4)*0.4167;
+ if (MachU < 1) { // Calculate total pressure assuming isentropic flow
+ pt = p*pow((1 + 0.2*MachU*MachU),3.5);
+ } else {
+ // Use Rayleigh pitot tube formula for normal shock in front of pitot tube
+ B = 5.76*MachU*MachU/(5.6*MachU*MachU - 0.8);
+ D = (2.8*MachU*MachU-0.4)*0.4167;
pt = p*pow(B,3.5)*D;
}
A = pow(((pt-p)/psl+1),0.28571);
- if (machU > 0.0) {
+ if (MachU > 0.0) {
vcas = sqrt(7*psl/rhosl*(A-1));
veas = sqrt(2*qbar/rhosl);
} else {
vcas = veas = 0.0;
}
- // Pilot sensed accelerations are calculated here. This is used
- // for the coordinated turn ball instrument. Motion base platforms sometimes
- // use the derivative of pilot sensed accelerations as the driving parameter,
- // rather than straight accelerations.
- //
- // The theory behind pilot-sensed calculations is presented:
- //
- // For purposes of discussion and calculation, assume for a minute that the
- // pilot is in space and motionless in inertial space. She will feel
- // no accelerations. If the aircraft begins to accelerate along any axis or
- // axes (without rotating), the pilot will sense those accelerations. If
- // any rotational moment is applied, the pilot will sense an acceleration
- // due to that motion in the amount:
- //
- // [wdot X R] + [w X (w X R)]
- // Term I Term II
- //
- // where:
- //
- // wdot = omegadot, the rotational acceleration rate vector
- // w = omega, the rotational rate vector
- // R = the vector from the aircraft CG to the pilot eyepoint
- //
- // The sum total of these two terms plus the acceleration of the aircraft
- // body axis gives the acceleration the pilot senses in inertial space.
- // In the presence of a large body such as a planet, a gravity field also
- // provides an accelerating attraction. This acceleration can be transformed
- // from the reference frame of the planet so as to be expressed in the frame
- // of reference of the aircraft. This gravity field accelerating attraction
- // is felt by the pilot as a force on her tushie as she sits in her aircraft
- // on the runway awaiting takeoff clearance.
- //
- // In JSBSim the acceleration of the body frame in inertial space is given
- // by the F = ma relation. If the vForces vector is divided by the aircraft
- // mass, the acceleration vector is calculated. The term wdot is equivalent
- // to the JSBSim vPQRdot vector, and the w parameter is equivalent to vPQR.
- // The radius R is calculated below in the vector vToEyePt.
-
- vPilotAccel.InitMatrix();
- if ( Translation->GetVt() > 1 ) {
- vPilotAccel = Aerodynamics->GetForces()
+ vPilotAccel.InitMatrix();
+ if ( Vt > 1.0 ) {
+ vPilotAccel = Aerodynamics->GetForces()
+ Propulsion->GetForces()
+ GroundReactions->GetForces();
vPilotAccel /= MassBalance->GetMass();
vToEyePt = MassBalance->StructuralToBody(Aircraft->GetXYZep());
- vPilotAccel += Rotation->GetPQRdot() * vToEyePt;
- vPilotAccel += Rotation->GetPQR() * (Rotation->GetPQR() * vToEyePt);
+ vPilotAccel += Propagate->GetPQRdot() * vToEyePt;
+ vPilotAccel += vPQR * (vPQR * vToEyePt);
} else {
- vPilotAccel = -1*( State->GetTl2b() * Inertial->GetGravity() );
- }
+ vPilotAccel = Propagate->GetTl2b() * FGColumnVector3( 0.0, 0.0, Inertial->gravity() );
+ }
vPilotAccelN = vPilotAccel/Inertial->gravity();
earthPosAngle += State->Getdt()*Inertial->omega();
+
+ // VRP computation
+ const FGLocation& vLocation = Propagate->GetLocation();
+ FGColumnVector3 vrpStructural = Aircraft->GetXYZvrp();
+ FGColumnVector3 vrpBody = MassBalance->StructuralToBody( vrpStructural );
+ FGColumnVector3 vrpLocal = Propagate->GetTb2l() * vrpBody;
+ vLocationVRP = vLocation.LocalToLocation( vrpLocal );
+
+ // Recompute some derived values now that we know the dependent parameters values ...
+ hoverbcg = Propagate->GetDistanceAGL() / Aircraft->GetWingSpan();
+
+ FGColumnVector3 vMac = Propagate->GetTb2l()*MassBalance->StructuralToBody(Aircraft->GetXYZrp());
+ hoverbmac = (Propagate->GetDistanceAGL() + vMac(3)) / Aircraft->GetWingSpan();
+
return false;
} else {
return true;
double FGAuxiliary::GetHeadWind(void)
{
- double psiw,vw,psi;
+ double psiw,vw;
psiw = Atmosphere->GetWindPsi();
- psi = Rotation->Getpsi();
vw = Atmosphere->GetWindNED().Magnitude();
- return vw*cos(psiw - psi);
+ return vw*cos(psiw - Propagate->Getpsi());
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGAuxiliary::GetCrossWind(void)
{
- double psiw,vw,psi;
+ double psiw,vw;
psiw = Atmosphere->GetWindPsi();
- psi = Rotation->Getpsi();
vw = Atmosphere->GetWindNED().Magnitude();
- return vw*sin(psiw - psi);
+ return vw*sin(psiw - Propagate->Getpsi());
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGAuxiliary::bind(void)
{
typedef double (FGAuxiliary::*PMF)(int) const;
- PropertyManager->Tie("velocities/vc-fps", this,
- &FGAuxiliary::GetVcalibratedFPS);
- PropertyManager->Tie("velocities/vc-kts", this,
- &FGAuxiliary::GetVcalibratedKTS);
- PropertyManager->Tie("velocities/ve-fps", this,
- &FGAuxiliary::GetVequivalentFPS);
- PropertyManager->Tie("velocities/ve-kts", this,
- &FGAuxiliary::GetVequivalentKTS);
- PropertyManager->Tie("velocities/machU", this,
- &FGAuxiliary::GetMachU);
- PropertyManager->Tie("velocities/tat-r", this,
- &FGAuxiliary::GetTotalTemperature);
- PropertyManager->Tie("velocities/tat-c", this,
- &FGAuxiliary::GetTAT_C);
- PropertyManager->Tie("velocities/pt-lbs_sqft", this,
- &FGAuxiliary::GetTotalPressure);
-
- PropertyManager->Tie("accelerations/a-pilot-x-ft_sec2", this,1,
- (PMF)&FGAuxiliary::GetPilotAccel);
- PropertyManager->Tie("accelerations/a-pilot-y-ft_sec2", this,2,
- (PMF)&FGAuxiliary::GetPilotAccel);
- PropertyManager->Tie("accelerations/a-pilot-z-ft_sec2", this,3,
- (PMF)&FGAuxiliary::GetPilotAccel);
- PropertyManager->Tie("accelerations/n-pilot-x-norm", this,1,
- (PMF)&FGAuxiliary::GetNpilot);
- PropertyManager->Tie("accelerations/n-pilot-y-norm", this,2,
- (PMF)&FGAuxiliary::GetNpilot);
- PropertyManager->Tie("accelerations/n-pilot-z-norm", this,3,
- (PMF)&FGAuxiliary::GetNpilot);
- PropertyManager->Tie("position/epa-rad", this,
- &FGAuxiliary::GetEarthPositionAngle);
- /* PropertyManager->Tie("atmosphere/headwind-fps", this,
- &FGAuxiliary::GetHeadWind,
- true);
- PropertyManager->Tie("atmosphere/crosswind-fps", this,
- &FGAuxiliary::GetCrossWind,
- true); */
+ typedef double (FGAuxiliary::*PF)(void) const;
+ PropertyManager->Tie("velocities/vc-fps", this, &FGAuxiliary::GetVcalibratedFPS);
+ PropertyManager->Tie("velocities/vc-kts", this, &FGAuxiliary::GetVcalibratedKTS);
+ PropertyManager->Tie("velocities/ve-fps", this, &FGAuxiliary::GetVequivalentFPS);
+ PropertyManager->Tie("velocities/ve-kts", this, &FGAuxiliary::GetVequivalentKTS);
+ PropertyManager->Tie("velocities/machU", this, &FGAuxiliary::GetMachU);
+ PropertyManager->Tie("velocities/tat-r", this, &FGAuxiliary::GetTotalTemperature);
+ PropertyManager->Tie("velocities/tat-c", this, &FGAuxiliary::GetTAT_C);
+ PropertyManager->Tie("velocities/pt-lbs_sqft", this, &FGAuxiliary::GetTotalPressure);
+ PropertyManager->Tie("velocities/p-aero-rad_sec", this, eX, (PMF)&FGAuxiliary::GetAeroPQR);
+ PropertyManager->Tie("velocities/q-aero-rad_sec", this, eY, (PMF)&FGAuxiliary::GetAeroPQR);
+ PropertyManager->Tie("velocities/r-aero-rad_sec", this, eZ, (PMF)&FGAuxiliary::GetAeroPQR);
+ PropertyManager->Tie("velocities/phidot-rad_sec", this, ePhi, (PMF)&FGAuxiliary::GetEulerRates);
+ PropertyManager->Tie("velocities/thetadot-rad_sec", this, eTht, (PMF)&FGAuxiliary::GetEulerRates);
+ PropertyManager->Tie("velocities/psidot-rad_sec", this, ePsi, (PMF)&FGAuxiliary::GetEulerRates);
+ PropertyManager->Tie("velocities/u-aero-fps", this, eU, (PMF)&FGAuxiliary::GetAeroUVW);
+ PropertyManager->Tie("velocities/v-aero-fps", this, eV, (PMF)&FGAuxiliary::GetAeroUVW);
+ PropertyManager->Tie("velocities/w-aero-fps", this, eW, (PMF)&FGAuxiliary::GetAeroUVW);
+ PropertyManager->Tie("velocities/vt-fps", this, &FGAuxiliary::GetVt, &FGAuxiliary::SetVt, true);
+ PropertyManager->Tie("velocities/mach-norm", this, &FGAuxiliary::GetMach, &FGAuxiliary::SetMach, true);
+ PropertyManager->Tie("velocities/vg-fps", this, &FGAuxiliary::GetVground);
+ PropertyManager->Tie("accelerations/a-pilot-x-ft_sec2", this, eX, (PMF)&FGAuxiliary::GetPilotAccel);
+ PropertyManager->Tie("accelerations/a-pilot-y-ft_sec2", this, eY, (PMF)&FGAuxiliary::GetPilotAccel);
+ PropertyManager->Tie("accelerations/a-pilot-z-ft_sec2", this, eZ, (PMF)&FGAuxiliary::GetPilotAccel);
+ PropertyManager->Tie("accelerations/n-pilot-x-norm", this, eX, (PMF)&FGAuxiliary::GetNpilot);
+ PropertyManager->Tie("accelerations/n-pilot-y-norm", this, eY, (PMF)&FGAuxiliary::GetNpilot);
+ PropertyManager->Tie("accelerations/n-pilot-z-norm", this, eZ, (PMF)&FGAuxiliary::GetNpilot);
+ PropertyManager->Tie("position/epa-rad", this, &FGAuxiliary::GetEarthPositionAngle);
+ /* PropertyManager->Tie("atmosphere/headwind-fps", this, &FGAuxiliary::GetHeadWind, true);
+ PropertyManager->Tie("atmosphere/crosswind-fps", this, &FGAuxiliary::GetCrossWind, true); */
+ PropertyManager->Tie("aero/alpha-rad", this, (PF)&FGAuxiliary::Getalpha, &FGAuxiliary::Setalpha, true);
+ PropertyManager->Tie("aero/beta-rad", this, (PF)&FGAuxiliary::Getbeta, &FGAuxiliary::Setbeta, true);
+ PropertyManager->Tie("aero/mag-beta-rad", this, (PF)&FGAuxiliary::GetMagBeta);
+ PropertyManager->Tie("aero/alpha-deg", this, inDegrees, (PMF)&FGAuxiliary::Getalpha);
+ PropertyManager->Tie("aero/beta-deg", this, inDegrees, (PMF)&FGAuxiliary::Getbeta);
+ PropertyManager->Tie("aero/mag-beta-deg", this, inDegrees, (PMF)&FGAuxiliary::GetMagBeta);
+ PropertyManager->Tie("aero/qbar-psf", this, &FGAuxiliary::Getqbar, &FGAuxiliary::Setqbar, true);
+ PropertyManager->Tie("aero/qbarUW-psf", this, &FGAuxiliary::GetqbarUW, &FGAuxiliary::SetqbarUW, true);
+ PropertyManager->Tie("aero/qbarUV-psf", this, &FGAuxiliary::GetqbarUV, &FGAuxiliary::SetqbarUV, true);
+ PropertyManager->Tie("aero/alphadot-rad_sec", this, (PF)&FGAuxiliary::Getadot, &FGAuxiliary::Setadot, true);
+ PropertyManager->Tie("aero/betadot-rad_sec", this, (PF)&FGAuxiliary::Getbdot, &FGAuxiliary::Setbdot, true);
+ PropertyManager->Tie("aero/alphadot-deg_sec", this, inDegrees, (PMF)&FGAuxiliary::Getadot);
+ PropertyManager->Tie("aero/betadot-deg_sec", this, inDegrees, (PMF)&FGAuxiliary::Getbdot);
+ PropertyManager->Tie("aero/h_b-cg-ft", this, &FGAuxiliary::GetHOverBCG);
+ PropertyManager->Tie("aero/h_b-mac-ft", this, &FGAuxiliary::GetHOverBMAC);
+ PropertyManager->Tie("flight-path/gamma-rad", this, &FGAuxiliary::GetGamma, &FGAuxiliary::SetGamma);
+ PropertyManager->Tie("flight-path/psi-gt-rad", this, &FGAuxiliary::GetGroundTrack);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
PropertyManager->Untie("velocities/machU");
PropertyManager->Untie("velocities/tat-r");
PropertyManager->Untie("velocities/tat-c");
+ PropertyManager->Untie("velocities/p-aero-rad_sec");
+ PropertyManager->Untie("velocities/q-aero-rad_sec");
+ PropertyManager->Untie("velocities/r-aero-rad_sec");
+ PropertyManager->Untie("velocities/pt-lbs_sqft");
+ PropertyManager->Untie("velocities/phidot-rad_sec");
+ PropertyManager->Untie("velocities/thetadot-rad_sec");
+ PropertyManager->Untie("velocities/psidot-rad_sec");
+ PropertyManager->Untie("velocities/u-aero-fps");
+ PropertyManager->Untie("velocities/v-aero-fps");
+ PropertyManager->Untie("velocities/w-aero-fps");
+ PropertyManager->Untie("velocities/vt-fps");
+ PropertyManager->Untie("velocities/mach-norm");
+ PropertyManager->Untie("velocities/vg-fps");
PropertyManager->Untie("accelerations/a-pilot-x-ft_sec2");
PropertyManager->Untie("accelerations/a-pilot-y-ft_sec2");
PropertyManager->Untie("accelerations/a-pilot-z-ft_sec2");
PropertyManager->Untie("position/epa-rad");
/* PropertyManager->Untie("atmosphere/headwind-fps");
PropertyManager->Untie("atmosphere/crosswind-fps"); */
-
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGAuxiliary::GetState(void)
-{
- qbar = Translation->Getqbar();
- mach = Translation->GetMach();
- machU= Translation->GetMachU();
- p = Atmosphere->GetPressure();
- rhosl = Atmosphere->GetDensitySL();
- psl = Atmosphere->GetPressureSL();
- sat = Atmosphere->GetTemperature();
+ PropertyManager->Untie("aero/qbar-psf");
+ PropertyManager->Untie("aero/qbarUW-psf");
+ PropertyManager->Untie("aero/qbarUV-psf");
+ PropertyManager->Untie("aero/alpha-rad");
+ PropertyManager->Untie("aero/beta-rad");
+ PropertyManager->Untie("aero/alpha-deg");
+ PropertyManager->Untie("aero/beta-deg");
+ PropertyManager->Untie("aero/alphadot-rad_sec");
+ PropertyManager->Untie("aero/betadot-rad_sec");
+ PropertyManager->Untie("aero/mag-beta-rad");
+ PropertyManager->Untie("aero/alphadot-deg_sec");
+ PropertyManager->Untie("aero/betadot-deg_sec");
+ PropertyManager->Untie("aero/mag-beta-deg");
+ PropertyManager->Untie("aero/h_b-cg-ft");
+ PropertyManager->Untie("aero/h_b-mac-ft");
+ PropertyManager->Untie("flight-path/gamma-rad");
+ PropertyManager->Untie("flight-path/psi-gt-rad");
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if (debug_lvl & 8 ) { // Runtime state variables
}
if (debug_lvl & 16) { // Sanity checking
+ if (Mach > 100 || Mach < 0.00)
+ cout << "FGPropagate::Mach is out of bounds: " << Mach << endl;
+ if (qbar > 1e6 || qbar < 0.00)
+ cout << "FGPropagate::qbar is out of bounds: " << qbar << endl;
}
if (debug_lvl & 64) {
if (from == 0) { // Constructor
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
+
Header: FGAuxiliary.h
Author: Jon Berndt
Date started: 01/26/99
-
+
------------- 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
--------------------------------------------------------------------------------
11/22/98 JSB Created
1/1/00 TP Added calcs and getters for VTAS, VCAS, VEAS, Vground, in knots
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGModel.h"
#include "FGColumnVector3.h"
+#include "FGLocation.h"
+#include "FGPropagate.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Encapsulates various uncategorized scheduled functions.
+ Pilot sensed accelerations are calculated here. This is used
+ for the coordinated turn ball instrument. Motion base platforms sometimes
+ use the derivative of pilot sensed accelerations as the driving parameter,
+ rather than straight accelerations.
+
+ The theory behind pilot-sensed calculations is presented:
+
+ For purposes of discussion and calculation, assume for a minute that the
+ pilot is in space and motionless in inertial space. She will feel
+ no accelerations. If the aircraft begins to accelerate along any axis or
+ axes (without rotating), the pilot will sense those accelerations. If
+ any rotational moment is applied, the pilot will sense an acceleration
+ due to that motion in the amount:
+
+ [wdot X R] + [w X (w X R)]
+ Term I Term II
+
+ where:
+
+ wdot = omegadot, the rotational acceleration rate vector
+ w = omega, the rotational rate vector
+ R = the vector from the aircraft CG to the pilot eyepoint
+
+ The sum total of these two terms plus the acceleration of the aircraft
+ body axis gives the acceleration the pilot senses in inertial space.
+ In the presence of a large body such as a planet, a gravity field also
+ provides an accelerating attraction. This acceleration can be transformed
+ from the reference frame of the planet so as to be expressed in the frame
+ of reference of the aircraft. This gravity field accelerating attraction
+ is felt by the pilot as a force on her tushie as she sits in her aircraft
+ on the runway awaiting takeoff clearance.
+
+ In JSBSim the acceleration of the body frame in inertial space is given
+ by the F = ma relation. If the vForces vector is divided by the aircraft
+ mass, the acceleration vector is calculated. The term wdot is equivalent
+ to the JSBSim vPQRdot vector, and the w parameter is equivalent to vPQR.
+ The radius R is calculated below in the vector vToEyePt.
+
@author Tony Peden, Jon Berndt
@version $Id$
*/
/** Constructor
@param Executive a pointer to the parent executive object */
FGAuxiliary(FGFDMExec* Executive);
+
/// Destructor
~FGAuxiliary();
@return false if no error */
bool Run(void);
- // Use FGInitialCondition to set these speeds
- inline double GetVcalibratedFPS(void) const { return vcas; }
- inline double GetVcalibratedKTS(void) const { return vcas*fpstokts; }
- inline double GetVequivalentFPS(void) const { return veas; }
- inline double GetVequivalentKTS(void) const { return veas*fpstokts; }
- inline double GetMachU(void) const { return machU; }
-
- inline double GetTotalTemperature(void) const { return tat; }
- inline double GetTAT_C(void) const { return tatc; }
+// GET functions
+
+ // Atmospheric parameters GET functions
+ double GetVcalibratedFPS(void) const { return vcas; }
+ double GetVcalibratedKTS(void) const { return vcas*fpstokts; }
+ double GetVequivalentFPS(void) const { return veas; }
+ double GetVequivalentKTS(void) const { return veas*fpstokts; }
// total pressure above is freestream total pressure for subsonic only
// for supersonic it is the 1D total pressure behind a normal shock
- inline double GetTotalPressure(void) const { return pt; }
-
- inline FGColumnVector3& GetPilotAccel(void) { return vPilotAccel; }
- inline double GetPilotAccel(int idx) const { return vPilotAccel(idx); }
- FGColumnVector3 GetNpilot(void) const { return vPilotAccelN; }
- double GetNpilot(int idx) const { return vPilotAccelN(idx); }
-
- inline double GetEarthPositionAngle(void) const { return earthPosAngle; }
-
+ double GetTotalPressure(void) const { return pt; }
+ double GetTotalTemperature(void) const { return tat; }
+ double GetTAT_C(void) const { return tatc; }
+
+ double GetPilotAccel(int idx) const { return vPilotAccel(idx); }
+ double GetNpilot(int idx) const { return vPilotAccelN(idx); }
+ double GetAeroPQR(int axis) const { return vAeroPQR(axis); }
+ double GetEulerRates(int axis) const { return vEulerRates(axis); }
+
+ const FGColumnVector3& GetPilotAccel (void) const { return vPilotAccel; }
+ const FGColumnVector3& GetNpilot (void) const { return vPilotAccelN; }
+ const FGColumnVector3& GetAeroPQR (void) const { return vAeroPQR; }
+ const FGColumnVector3& GetEulerRates (void) const { return vEulerRates; }
+ const FGColumnVector3& GetAeroUVW (void) const { return vAeroUVW; }
+ const FGLocation& GetLocationVRP(void) const { return vLocationVRP; }
+
+ double GethVRP(void) const { return vLocationVRP.GetRadius() - Propagate->GetSeaLevelRadius(); }
+ double GetAeroUVW (int idx) const { return vAeroUVW(idx); }
+ double Getalpha (void) const { return alpha; }
+ double Getbeta (void) const { return beta; }
+ double Getadot (void) const { return adot; }
+ double Getbdot (void) const { return bdot; }
+ double GetMagBeta (void) const { return fabs(beta); }
+
+ double Getalpha (int unit) const { if (unit == inDegrees) return alpha*radtodeg;
+ else cerr << "Bad units" << endl; return 0.0;}
+ double Getbeta (int unit) const { if (unit == inDegrees) return beta*radtodeg;
+ else cerr << "Bad units" << endl; return 0.0;}
+ double Getadot (int unit) const { if (unit == inDegrees) return adot*radtodeg;
+ else cerr << "Bad units" << endl; return 0.0;}
+ double Getbdot (int unit) const { if (unit == inDegrees) return bdot*radtodeg;
+ else cerr << "Bad units" << endl; return 0.0;}
+ double GetMagBeta (int unit) const { if (unit == inDegrees) return fabs(beta)*radtodeg;
+ else cerr << "Bad units" << endl; return 0.0;}
+
+ double Getqbar (void) const { return qbar; }
+ double GetqbarUW (void) const { return qbarUW; }
+ double GetqbarUV (void) const { return qbarUV; }
+ double GetVt (void) const { return Vt; }
+ double GetVground (void) const { return Vground; }
+ double GetMach (void) const { return Mach; }
+ double GetMachU (void) const { return MachU; }
+
+ double GetHOverBCG(void) const { return hoverbcg; }
+ double GetHOverBMAC(void) const { return hoverbmac; }
+
+ double GetGamma(void) const { return gamma; }
+ double GetGroundTrack(void) const { return psigt; }
+ double GetEarthPositionAngle(void) const { return earthPosAngle; }
+
double GetHeadWind(void);
double GetCrossWind(void);
-
+
+// SET functions
+
+ void SetAeroUVW(FGColumnVector3 tt) { vAeroUVW = tt; }
+
+ void Setalpha (double tt) { alpha = tt; }
+ void Setbeta (double tt) { beta = tt; }
+ void Setqbar (double tt) { qbar = tt; }
+ void SetqbarUW (double tt) { qbarUW = tt; }
+ void SetqbarUV (double tt) { qbarUV = tt; }
+ void SetVt (double tt) { Vt = tt; }
+ void SetMach (double tt) { Mach=tt; }
+ void Setadot (double tt) { adot = tt; }
+ void Setbdot (double tt) { bdot = tt; }
+
+ void SetAB (double t1, double t2) { alpha=t1; beta=t2; }
+ void SetGamma (double tt) { gamma = tt; }
+
+// Time routines, SET and GET functions
+
+ void SetDayOfYear (int doy) { day_of_year = doy; }
+ void SetSecondsInDay (double sid) { seconds_in_day = sid; }
+
+ int GetDayOfYear (void) const { return day_of_year; }
+ double GetSecondsInDay (void) const { return seconds_in_day; }
+
void bind(void);
void unbind(void);
private:
- double vcas;
- double veas;
- double mach;
- double machU;
- double qbar,rhosl,rho,p,psl,pt,tat,sat,tatc;
-
- // Don't add a getter for pt!
+ double vcas, veas;
+ double rhosl, rho, p, psl, pt, tat, sat, tatc; // Don't add a getter for pt!
FGColumnVector3 vPilotAccel;
FGColumnVector3 vPilotAccelN;
FGColumnVector3 vToEyePt;
-
+ FGColumnVector3 vAeroPQR;
+ FGColumnVector3 vAeroUVW;
+ FGColumnVector3 vEuler;
+ FGColumnVector3 vEulerRates;
+ FGColumnVector3 vMachUVW;
+ FGLocation vLocationVRP;
+
+ double Vt, Vground, Mach, MachU;
+ double qbar, qbarUW, qbarUV;
+ double alpha, beta;
+ double adot,bdot;
+ double psigt, gamma;
+ double seconds_in_day; // seconds since current GMT day began
+ int day_of_year; // GMT day, 1 .. 366
+
double earthPosAngle;
+ double hoverbcg, hoverbmac;
- void GetState(void);
void Debug(int from);
};
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif
-
FDMExec = fdex;
State = FDMExec->GetState();
Table = 0;
-
+
PropertyManager = FDMExec->GetPropertyManager();
-
+
Table = (FGTable*)0L;
LookupR = LookupC = 0;
numInstances = 0;
- rows = columns = 0;
+ rows = columns = tables = 0;
StaticValue = 0.0;
totalValue = 0.0;
*AC_cfg >> description;
if (method == "EQUATION") type = EQUATION;
else if (method == "TABLE") type = TABLE;
+ else if (method == "TABLE3D") type = TABLE3D;
else if (method == "VECTOR") type = VECTOR;
else if (method == "VALUE") type = VALUE;
else type = UNKNOWN;
- if (type == VECTOR || type == TABLE) {
- *AC_cfg >> rows;
- if (type == TABLE) {
- *AC_cfg >> columns;
+ if (type == VECTOR || type == TABLE || type == TABLE3D) {
+
+ if (type == TABLE3D) {
+ *AC_cfg >> rows >> columns >> tables;
+ Table = new FGTable(rows, columns, tables);
+ *AC_cfg >> multparmsRow >> multparmsCol >> multparmsTable;
+ LookupR = PropertyManager->GetNode( multparmsRow );
+ LookupC = PropertyManager->GetNode( multparmsCol );
+ LookupT = PropertyManager->GetNode( multparmsTable );
+ } else if (type == TABLE) {
+ *AC_cfg >> rows >> columns;
Table = new FGTable(rows, columns);
+ *AC_cfg >> multparmsRow >> multparmsCol;
+ LookupR = PropertyManager->GetNode( multparmsRow );
+ LookupC = PropertyManager->GetNode( multparmsCol );
} else {
+ *AC_cfg >> rows;
Table = new FGTable(rows);
+ *AC_cfg >> multparmsRow;
+ LookupR = PropertyManager->GetNode( multparmsRow );
}
-
- *AC_cfg >> multparmsRow;
- LookupR = PropertyManager->GetNode( multparmsRow );
- }
-
- if (type == TABLE) {
- *AC_cfg >> multparmsCol;
-
- LookupC = PropertyManager->GetNode( multparmsCol );
}
- // Here, read in the line of the form (e.g.) FG_MACH|FG_QBAR|FG_ALPHA
- // where each non-dimensionalizing parameter for this coefficient is
+ // Here, read in the line of the form:
+ // {property1} | {property2} | {property3}
+ // where each non-dimensionalizing property for this coefficient is
// separated by a | character
string line=AC_cfg->GetCurrentLine();
tmp[j]=line[i];
j++;
}
- }
- tmp[j]='\0'; multparms=tmp;
- end = multparms.length();
+ }
+ tmp[j]='\0'; multparms=tmp;
+ end = multparms.length();
- n = multparms.find("|");
+ n = multparms.find("|");
start = 0;
if (multparms != string("none")) {
while (n < end && n >= 0) {
// End of non-dimensionalizing parameter read-in
}
AC_cfg->GetNextConfigLine();
+
if (type == VALUE) {
*AC_cfg >> StaticValue;
- } else if (type == VECTOR || type == TABLE) {
+ } else if (type == VECTOR || type == TABLE || type == TABLE3D) {
*Table << *AC_cfg;
} else {
cerr << "Unimplemented coefficient type: " << type << endl;
return true;
} else {
return false;
- }
+ }
}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGCoefficient::Value(double rVal, double cVal, double tVal)
+{
+ double Value;
+ unsigned int midx;
+
+ SD = Value = gain*Table->GetValue(rVal, cVal, tVal) + bias;
+
+ for (midx=0; midx < multipliers.size(); midx++) {
+ Value *= multipliers[midx]->getDoubleValue();
+ }
+ return Value;
+}
+
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGCoefficient::Value(double rVal, double cVal)
double FGCoefficient::Value(double Val)
{
double Value;
-
+
SD = Value = gain*Table->GetValue(Val) + bias;
-
- for (unsigned int midx=0; midx < multipliers.size(); midx++)
+
+ for (unsigned int midx=0; midx < multipliers.size(); midx++)
Value *= multipliers[midx]->getDoubleValue();
-
+
return Value;
}
double FGCoefficient::Value(void)
{
- double Value;
+ double Value;
SD = Value = gain*StaticValue + bias;
case TABLE:
totalValue = Value( LookupR->getDoubleValue(),
- LookupC->getDoubleValue() );
+ LookupC->getDoubleValue() );
+ break;
+
+ case TABLE3D:
+ totalValue = Value( LookupR->getDoubleValue(),
+ LookupC->getDoubleValue(),
+ LookupT->getDoubleValue() );
break;
case EQUATION:
if (multipliers.size() == 0) {
cout << "none" << endl;
} else {
- for (i=0; i<multipliers.size(); i++)
+ for (i=0; i<multipliers.size(); i++)
cout << multipliers[i]->getName() << " ";
}
cout << endl;
string FGCoefficient::GetSDstring(void)
{
- char buffer[16];
+ char buffer[20];
string value;
sprintf(buffer,"%9.6f",SD);
{
string mult;
unsigned i;
-
+
node = parent->GetNode(name,true);
-
+
node->SetString("description",description);
if (LookupR) node->SetString("row-parm",LookupR->getName() );
if (LookupC) node->SetString("column-parm",LookupC->getName() );
-
+
mult="";
- if (multipliers.size() == 0)
+ if (multipliers.size() == 0)
mult="none";
-
+
for (i=0; i<multipliers.size(); i++) {
mult += multipliers[i]->getName();
- if ( i < multipliers.size()-1 ) mult += " ";
+ if ( i < multipliers.size()-1 ) mult += " ";
}
node->SetString("multipliers",mult);
-
+
node->Tie("SD-norm",this,&FGCoefficient::GetSD );
node->Tie("value-lbs",this,&FGCoefficient::GetValue );
-
+
node->Tie("bias", this, &FGCoefficient::getBias,
&FGCoefficient::setBias );
-
+
node->Tie("gain", this, &FGCoefficient::getGain,
&FGCoefficient::setGain );
void FGCoefficient::unbind(void)
{
node->Untie("SD-norm");
- node->Untie("value-lbs");
- node->Untie("bias");
+ node->Untie("value-lbs");
+ node->Untie("bias");
node->Untie("gain");
}
if ( !tmpn ) {
cerr << "Coefficient multipliers cannot create properties, check spelling?" << endl;
exit(1);
- }
- return tmpn;
+ }
+ return tmpn;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if (debug_lvl <= 0) return;
if (debug_lvl & 1) { // Standard console startup message output
-
+
if (from == 2) { // Loading
cout << "\n " << highint << underon << name << underoff << normint << endl;
cout << " " << description << endl;
cout << " " << method << endl;
- if (type == VECTOR || type == TABLE) {
- cout << " Rows: " << rows << " ";
- if (type == TABLE) {
- cout << "Cols: " << columns;
+ if (type == VECTOR || type == TABLE || type == TABLE3D) {
+ cout << " Rows: " << rows << " indexed by: " << LookupR->getName() << endl;
+ if (type == TABLE || type == TABLE3D) {
+ cout << " Cols: " << columns << " indexed by: " << LookupC->getName() << endl;
+ if (type == TABLE3D) {
+ cout << " Tables: " << tables << " indexed by: " << LookupT->getName() << endl;
+ }
}
- cout << endl << " Row indexing parameter: " << LookupR->getName() << endl;
- }
-
- if (type == TABLE) {
- cout << " Column indexing parameter: " << LookupC->getName() << endl;
- }
-
- if (type == VALUE) {
- cout << " Value = " << StaticValue << endl;
- } else if (type == VECTOR || type == TABLE) {
Table->Print();
+ } else if (type == VALUE) {
+ cout << " Value = " << StaticValue << endl;
}
DisplayCoeffFactors();
class FGAtmosphere;
class FGFCS;
class FGAircraft;
-class FGTranslation;
-class FGRotation;
-class FGPosition;
+class FGPropagate;
class FGAuxiliary;
class FGOutput;
FGCoefficient(FGFDMExec* exec);
/// Destructor.
virtual ~FGCoefficient();
-
+
/** Loads the stability derivative/aero coefficient data from the config file
as directed by the FGAerodynamics instance.
@param AC_cfg a pointer to the current config file instance. */
virtual bool Load(FGConfigFile* AC_cfg);
-
+
typedef vector <FGPropertyManager*> MultVec;
- enum Type {UNKNOWN, VALUE, VECTOR, TABLE, EQUATION};
+ enum Type {UNKNOWN, VALUE, VECTOR, TABLE, TABLE3D, EQUATION};
/** Returns the value for this coefficient.
Each instance of FGCoefficient stores a value for the "type" of coefficient
- it is, one of: VALUE, VECTOR, TABLE, or EQUATION. This TotalValue function
+ it is, one of: VALUE, VECTOR, TABLE, or EQUATION. This TotalValue function
is called when the value for a coefficient needs to be known. When it is called,
depending on what type of coefficient is represented by the FGCoefficient
instance, TotalValue() directs the appropriate Value() function to be called.
inline void setGain(double g) { gain=g; };
inline double getBias(void) const { return bias; }
inline double getGain(void) const { return gain; }
-
+
virtual void bind(FGPropertyManager *parent);
virtual void unbind(void);
string multparms;
string multparmsRow;
string multparmsCol;
+ string multparmsTable;
+ double Value(double, double, double);
double Value(double, double);
double Value(double);
double Value(void);
double StaticValue;
double totalValue;
double bias,gain;
- FGPropertyManager *LookupR, *LookupC;
-
+ FGPropertyManager *LookupR, *LookupC, *LookupT;
+
FGPropertyManager *node; // must be private!!
-
+
MultVec multipliers;
- int rows, columns;
+ int rows, columns, tables;
Type type;
double SD; // Actual stability derivative (or other coefficient) value
FGTable *Table;
FGAtmosphere* Atmosphere;
FGFCS* FCS;
FGAircraft* Aircraft;
- FGTranslation* Translation;
- FGRotation* Rotation;
- FGPosition* Position;
+ FGPropagate* Propagate;
FGAuxiliary* Auxiliary;
FGOutput* Output;
FGPropertyManager* PropertyManager;
-
+
FGPropertyManager* resolveSymbol(string name);
virtual void Debug(int from);
double FGColumnVector3::Magnitude(void) const
{
- if (data[1] == 0.0 && data[2] == 0.0 && data[3] == 0.0)
+ if (Entry(1) == 0.0 && Entry(2) == 0.0 && Entry(3) == 0.0)
return 0.0;
else
return sqrt( Entry(1)*Entry(1) + Entry(2)*Entry(2) + Entry(3)*Entry(3) );
FGColumnVector3(void);
/** Initialization by given values.
-
+
@param X value of the x-conponent.
@param Y value of the y-conponent.
@param Z value of the z-conponent.
-
+
Create a vector from the doubles given in the arguments.
*/
FGColumnVector3(double X, double Y, double Z) {
}
/** Copy constructor.
-
+
@param v Vector which is used for initialization.
-
+
Create copy of the vector given in the argument.
*/
FGColumnVector3(const FGColumnVector3& v) {
/** Read access the entries of the vector.
-
+
@param idx the component index.
-
+
Return the value of the matrix entry at the given index.
Indices are counted starting with 1.
-
+
Note that the index given in the argument is unchecked.
*/
double operator()(unsigned int idx) const { return Entry(idx); }
/** Write access the entries of the vector.
-
+
@param idx the component index.
-
+
Return a reference to the vector entry at the given index.
Indices are counted starting with 1.
-
+
Note that the index given in the argument is unchecked.
*/
double& operator()(unsigned int idx) { return Entry(idx); }
/** Read access the entries of the vector.
-
+
@param idx the component index.
-
+
Return the value of the matrix entry at the given index.
Indices are counted starting with 1.
-
+
This function is just a shortcut for the @ref double
operator()(unsigned int idx) const function. It is
used internally to access the elements in a more convenient way.
-
+
Note that the index given in the argument is unchecked.
*/
double Entry(unsigned int idx) const { return data[idx-1]; }
/** Write access the entries of the vector.
-
+
@param idx the component index.
-
+
Return a reference to the vector entry at the given index.
Indices are counted starting with 1.
-
+
This function is just a shortcut for the @ref double&
operator()(unsigned int idx) function. It is
used internally to access the elements in a more convenient way.
-
+
Note that the index given in the argument is unchecked.
*/
double& Entry(unsigned int idx) { return data[idx-1]; }
/** Assignment operator.
-
+
@param b source vector.
-
+
Copy the content of the vector given in the argument into *this.
*/
FGColumnVector3& operator=(const FGColumnVector3& b) {
return *this;
}
+ /** Comparison operator.
+
+ @param b other vector.
+
+ Returns true if both vectors are exactly the same.
+ */
+ bool operator==(const FGColumnVector3& b) const {
+ return data[0] == b.data[0] && data[1] == b.data[1] && data[2] == b.data[2];
+ }
+
+ /** Comparison operator.
+
+ @param b other vector.
+
+ Returns false if both vectors are exactly the same.
+ */
+ bool operator!=(const FGColumnVector3& b) const { return ! operator==(b); }
+
/** Multiplication by a scalar.
-
+
@param scalar scalar value to multiply the vector with.
@return The resulting vector from the multiplication with that scalar.
-
+
Multiply the vector with the scalar given in the argument.
*/
FGColumnVector3 operator*(const double scalar) const {
}
/** Multiply by 1/scalar.
-
+
@param scalar scalar value to devide the vector through.
@return The resulting vector from the division through that scalar.
-
+
Multiply the vector with the 1/scalar given in the argument.
*/
FGColumnVector3 operator/(const double scalar) const;
/** Cross product multiplication.
-
+
@param v vector to multiply with.
@return The resulting vector from the cross product multiplication.
-
+
Compute and return the cross product of the current vector with
the given argument.
*/
}
/** Length of the vector.
-
+
Compute and return the euclidean norm of this vector.
*/
double Magnitude(void) const;
- /** Normialze.
-
+ /** Normalize.
+
Normalize the vector to have the Magnitude() == 1.0. If the vector
is equal to zero it is left untouched.
*/
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-Module: FGMatrix33.cpp
-Author: Originally by Tony Peden [formatted here (and broken??) by JSB]
-Date started: 1998
-Purpose: FGMatrix33 class
-Called by: Various
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-
-HISTORY
---------------------------------------------------------------------------------
-??/??/?? TP Created
-03/16/2000 JSB Added exception throwing
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGColumnVector4.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_COLUMNVECTOR4;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-FGColumnVector4::FGColumnVector4(void)
-{
- rowCtr = 1;
- data[1]=0;data[2]=0;data[3]=0;data[4]=0;
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGColumnVector4::FGColumnVector4(double A, double B, double C, double D)
-{
- rowCtr = 1;
- data[1]=A;
- data[2]=B;
- data[3]=C;
- data[4]=D;
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGColumnVector4::~FGColumnVector4(void)
-{
- Debug(1);
-}
-
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGColumnVector4::FGColumnVector4(const FGColumnVector4& b)
-{
- data[1] = b.data[1];
- data[2] = b.data[2];
- data[3] = b.data[3];
- data[4] = b.data[4];
-
- rowCtr = 1;
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGColumnVector4 FGColumnVector4::operator=(const FGColumnVector4& b)
-{
- data[1] = b.data[1];
- data[2] = b.data[2];
- data[3] = b.data[3];
- data[4] = b.data[4];
- rowCtr = 1;
- return *this;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGColumnVector4 FGColumnVector4::operator+(const FGColumnVector4& C)
-{
- FGColumnVector4 Sum;
-
- Sum(1) = C(1) + data[1];
- Sum(2) = C(2) + data[2];
- Sum(3) = C(3) + data[3];
- Sum(4) = C(4) + data[4];
- return Sum;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGColumnVector4::operator+=(const FGColumnVector4& C)
-{
- data[1] += C(1);
- data[2] += C(2);
- data[3] += C(3);
- data[4] += C(4);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGColumnVector4 FGColumnVector4::operator*(const double scalar)
-{
- FGColumnVector4 Product;
-
- Product(1) = scalar * data[1];
- Product(2) = scalar * data[2];
- Product(3) = scalar * data[3];
- Product(4) = scalar * data[4];
-
- return Product;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGColumnVector4::operator*=(const double scalar)
-{
- data[1] *= scalar;
- data[2] *= scalar;
- data[3] *= scalar;
- data[4] *= scalar;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGColumnVector4 FGColumnVector4::operator-(const FGColumnVector4& V)
-{
-
- FGColumnVector4 Diff;
-
- Diff(1) = data[1] - V(1);
- Diff(2) = data[2] - V(2);
- Diff(3) = data[3] - V(3);
- Diff(4) = data[4] - V(4);
-
- return Diff;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGColumnVector4::operator-=(const FGColumnVector4& V)
-{
- data[1] -= V(1);
- data[2] -= V(2);
- data[3] -= V(3);
- data[4] -= V(4);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGColumnVector4 FGColumnVector4::operator/(const double scalar)
-{
- FGColumnVector4 Quotient;
-
- if (scalar != 0) {
- double tmp = 1.0/scalar;
- Quotient(1) = data[1] * tmp;
- Quotient(2) = data[2] * tmp;
- Quotient(3) = data[3] * tmp;
- Quotient(4) = data[4] * tmp;
- } else {
- cerr << "Attempt to divide by zero in method FGColumnVector4::operator/(const double scalar), object " << this << endl;
- }
- return Quotient;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGColumnVector4::operator/=(const double scalar)
-{
- FGColumnVector4 Quotient;
-
- if (scalar != 0) {
- double tmp = 1.0/scalar;
- data[1] *= tmp;
- data[2] *= tmp;
- data[3] *= tmp;
- data[4] *= tmp;
- } else {
- cerr << "Attempt to divide by zero in method FGColumnVector4::operator/=(const double scalar), object " << this << endl;
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGColumnVector4 operator*(const double scalar, const FGColumnVector4& C)
-{
- FGColumnVector4 Product;
-
- Product(1) = scalar * C(1);
- Product(2) = scalar * C(2);
- Product(3) = scalar * C(3);
- Product(4) = scalar * C(4);
- return Product;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGColumnVector4::Magnitude(void)
-{
- double num;
-
- if ((data[1] == 0.00) &&
- (data[2] == 0.00) &&
- (data[3] == 0.00) &&
- (data[4] == 0.00))
- {
- return 0.00;
- } else {
- num = data[1]*data[1];
- num += data[2]*data[2];
- num += data[3]*data[3];
- num += data[4]*data[4];
- return sqrt(num);
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGColumnVector4 FGColumnVector4::Normalize(void)
-{
- double Mag = Magnitude();
-
- if (Mag != 0) {
- Mag = 1.0/Mag;
- data[1] *= Mag;
- data[2] *= Mag;
- data[3] *= Mag;
- data[4] *= Mag;
- }
-
- return *this;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGColumnVector4 FGColumnVector4::multElementWise(const FGColumnVector4& V)
-{
- FGColumnVector4 Product;
-
- Product(1) = data[1] * V(1);
- Product(2) = data[2] * V(2);
- Product(3) = data[3] * V(3);
- Product(4) = data[4] * V(4);
-
- return Product;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-ostream& operator<<(ostream& os, FGColumnVector4& col)
-{
- os << col(1) << " , " << col(2) << " , " << col(3) << " , " << col(4);
- return os;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGColumnVector4& FGColumnVector4::operator<<(const double ff)
-{
- data[rowCtr] = ff;
- if (++rowCtr > 4) rowCtr = 1;
- return *this;
-}
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-// 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 FGColumnVector4::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGColumnVector4" << endl;
- if (from == 1) cout << "Destroyed: FGColumnVector4" << 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) { // Sanity checking
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-Header: FGColumnVector4.h
-Author: Originally by Tony Peden [formatted and adapted here by Jon Berndt]
-Date started: Unknown
-
-HISTORY
---------------------------------------------------------------------------------
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGCOLUMNVECTOR4_H
-#define FGCOLUMNVECTOR4_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include <stdlib.h>
-#ifdef FGFS
-# include <math.h>
-# include <simgear/compiler.h>
-# include STL_STRING
-# include STL_FSTREAM
-# include STL_IOSTREAM
- SG_USING_STD(string);
- SG_USING_STD(ostream);
- SG_USING_STD(istream);
- SG_USING_STD(cerr);
- SG_USING_STD(cout);
- SG_USING_STD(endl);
-// SG_USING_STD(sqrt);
-#else
-# include <string>
-# if defined (sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
-# include <fstream.h>
-# include <iostream.h>
-# include <math.h>
-# else
-# include <fstream>
-# if defined (sgi) && !defined(__GNUC__)
-# include <math.h>
-# else
-# include <cmath>
-# endif
-# include <iostream>
- using std::ostream;
- using std::istream;
- using std::cerr;
- using std::cout;
- using std::endl;
- using std::sqrt;
-# endif
- using std::string;
-#endif
-
-#include "FGJSBBase.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_COLUMNVECTOR4 "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** This class implements a 4 dimensional vector.
- @author Jon S. Berndt, Tony Peden, et. al.
- @version $Id$
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGColumnVector4 : public FGJSBBase
-{
-public:
- FGColumnVector4(void);
- FGColumnVector4(double A, double B, double C, double D);
- FGColumnVector4(const FGColumnVector4& b);
- ~FGColumnVector4(void);
-
- FGColumnVector4 operator=(const FGColumnVector4& b);
-
- FGColumnVector4 operator*(const double scalar);
- FGColumnVector4 operator/(const double scalar);
- FGColumnVector4 operator+(const FGColumnVector4& B); // must not return reference
- FGColumnVector4 operator-(const FGColumnVector4& B);
-
- void operator-=(const FGColumnVector4 &B);
- void operator+=(const FGColumnVector4 &B);
- void operator*=(const double scalar);
- void operator/=(const double scalar);
-
- inline double operator()(int m) const { return data[m]; }
- inline double& operator()(int m) { return data[m]; }
-
- FGColumnVector4& operator<<(const double ff);
-
- inline void InitMatrix(void) { data[1]=0; data[2]=0; data[3]=0; data[4]=0; }
- inline void InitMatrix(double ff) { data[1]=ff; data[2]=ff; data[3]=ff; data[4]=ff;}
-
- double Magnitude(void);
- FGColumnVector4 Normalize(void);
-
- friend FGColumnVector4 operator*(const double scalar, const FGColumnVector4& A);
-
- friend ostream& operator<<(ostream& os, FGColumnVector4& col);
-
-
- FGColumnVector4 multElementWise(const FGColumnVector4& V);
-
-private:
- double data[5];
- int rowCtr;
- void Debug(int from);
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
-
+++ /dev/null
-/*******************************************************************************
-
- Header: FGDefs.h
- Author: Jon S. Berndt
- Date started: 02/01/99
-
- ------------- 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
---------------------------------------------------------------------------------
-02/01/99 JSB Created
-
-********************************************************************************
-SENTRY
-*******************************************************************************/
-
-#ifndef FGDEFS_H
-#define FGDEFS_H
-
-#define GRAVITY 32.174
-#define INVGRAVITY 0.031081
-#define EARTHRAD 20925650.00 // feet, equatorial
-#define EARTHRADSQRD 437882827922500.0
-#define ONESECOND 4.848136811E-6
-#define Reng 1716 //Specific Gas Constant,ft^2/(sec^2*R)
-#define SHRATIO 1.4 //Specific Heat Ratio
-#define RADTODEG 57.29578
-#define DEGTORAD 1.745329E-2
-#define KTSTOFPS 1.68781
-#define FPSTOKTS 0.592484
-#define INCHTOFT 0.08333333
-#define OMEGA_EARTH .00007272205217
-#define NEEDED_CFG_VERSION "1.50"
-#define JSBSIM_VERSION "0.9.0"
-
-#define HPTOFTLBSSEC 550
-#define METERS_TO_FEET 3.2808
-
-#if defined ( sgi ) && !defined( __GNUC__ )
-#define __STL_FUNCTION_TMPL_PARTIAL_ORDER
-#endif
-
-enum eParam {
- FG_UNDEF = 0,
- FG_TIME,
- FG_QBAR,
- FG_WINGAREA,
- FG_WINGSPAN,
- FG_CBAR,
- FG_ALPHA,
- FG_ALPHADOT,
- FG_BETA,
- FG_BETADOT,
- FG_PHI,
- FG_THT,
- FG_PSI,
- FG_PITCHRATE,
- FG_ROLLRATE,
- FG_YAWRATE,
- FG_CL_SQRD,
- FG_MACH,
- FG_ALTITUDE,
- FG_BI2VEL,
- FG_CI2VEL,
- FG_ELEVATOR_POS,
- FG_AILERON_POS,
- FG_RUDDER_POS,
- FG_SPDBRAKE_POS,
- FG_SPOILERS_POS,
- FG_FLAPS_POS,
- FG_ELEVATOR_CMD,
- FG_AILERON_CMD,
- FG_RUDDER_CMD,
- FG_SPDBRAKE_CMD,
- FG_SPOILERS_CMD,
- FG_FLAPS_CMD,
- FG_THROTTLE_CMD,
- FG_THROTTLE_POS,
- FG_MIXTURE_CMD,
- FG_MIXTURE_POS,
- FG_MAGNETO_CMD,
- FG_STARTER_CMD,
- FG_ACTIVE_ENGINE,
- FG_HOVERB,
- FG_PITCH_TRIM_CMD,
- FG_LEFT_BRAKE_CMD,
- FG_CENTER_BRAKE_CMD,
- FG_RIGHT_BRAKE_CMD,
- FG_SET_LOGGING,
- FG_ALPHAH,
- FG_ALPHAW,
- FG_LBARH, //normalized horizontal tail arm
- FG_LBARV, //normalized vertical tail arm
- FG_HTAILAREA,
- FG_VTAILAREA,
- FG_VBARH, //horizontal tail volume
- FG_VBARV //vertical tail volume
-};
-
-enum eAction {
- FG_RAMP = 1,
- FG_STEP = 2,
- FG_EXP = 3
-};
-
-enum eType {
- FG_VALUE = 1,
- FG_DELTA = 2,
- FG_BOOL = 3
-};
-
-/******************************************************************************/
-#endif
-
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGElectric.cpp
+ Author: David Culp
+ Date started: 04/07/2004
+ Purpose: This module models an electric motor
+
+ --------- Copyright (C) 2004 David Culp (davidculp2@comcast.net) -------------
+
+ 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
+--------------------------------------------------------------------------------
+
+This class descends from the FGEngine class and models an electric motor based on
+parameters given in the engine config file for this class
+
+HISTORY
+--------------------------------------------------------------------------------
+04/07/2004 DPC Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGElectric.h"
+#include "FGPropulsion.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_ELECTRIC;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGElectric::FGElectric(FGFDMExec* exec, FGConfigFile* Eng_cfg) : FGEngine(exec)
+{
+ string token;
+
+ Type = etElectric;
+ EngineNumber = 0;
+ PowerWatts = 745.7;
+ hptowatts = 745.7;
+
+ dt = State->Getdt();
+
+ Name = Eng_cfg->GetValue("NAME");
+ Eng_cfg->GetNextConfigLine();
+ while (Eng_cfg->GetValue() != string("/FG_ELECTRIC")) {
+ *Eng_cfg >> token;
+ if (token == "POWER_WATTS") *Eng_cfg >> PowerWatts;
+ else cerr << "Unhandled token in Engine config file: " << token << endl;
+ }
+
+ Debug(0); // Call Debug() routine from constructor if needed
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGElectric::~FGElectric()
+{
+ Debug(1); // Call Debug() routine from constructor if needed
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGElectric::Calculate(void)
+{
+ Throttle = FCS->GetThrottlePos(EngineNumber);
+
+ RPM = Thruster->GetRPM() * Thruster->GetGearRatio();
+
+ HP = PowerWatts * Throttle / hptowatts;
+
+ PowerAvailable = (HP * hptoftlbssec) - Thruster->GetPowerRequired();
+
+ return Thruster->Calculate(PowerAvailable);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGElectric::GetEngineLabels(void)
+{
+ return ""; // currently no labels are returned for this engine
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGElectric::GetEngineValues(void)
+{
+ return ""; // currently no values are returned for this engine
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+//
+// 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 FGElectric::Debug(int from)
+{
+ if (debug_lvl <= 0) return;
+
+ if (debug_lvl & 1) { // Standard console startup message output
+ if (from == 0) { // Constructor
+
+ cout << "\n Engine Name: " << Name << endl;
+ cout << " Power Watts: " << PowerWatts << endl;
+
+ }
+ }
+ if (debug_lvl & 2 ) { // Instantiation/Destruction notification
+ if (from == 0) cout << "Instantiated: FGElectric" << endl;
+ if (from == 1) cout << "Destroyed: FGElectric" << 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;
+ }
+ }
+}
+
+double
+FGElectric::CalcFuelNeed(void)
+{
+ return 0;
+}
+
+} // namespace JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGElectric.h
+ Author: David Culp
+ Date started: 04/07/2004
+
+ ----- Copyright (C) 2004 David P. Culp (davidculp2@comcast.net) --------------
+
+ 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
+--------------------------------------------------------------------------------
+04/07/2004 DPC Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGELECTRIC_H
+#define FGELECTRIC_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGEngine.h"
+#include "FGConfigFile.h"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_ELECTRIC "$Id$";
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models and electric motor.
+ FGElectric models an electric motor based on the configuration file
+ POWER_WATTS parameter. The throttle controls motor output linearly from
+ zero to POWER_WATTS. This power value (converted internally to horsepower)
+ is then used by FGPropeller to apply torque to the propeller.
+ @author David Culp
+ @version "$Id$"
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGElectric : public FGEngine
+{
+public:
+ /// Constructor
+ FGElectric(FGFDMExec* exec, FGConfigFile* Eng_cfg);
+ /// Destructor
+ ~FGElectric();
+
+ double Calculate(void);
+ double GetPowerAvailable(void) {return PowerAvailable;}
+ double CalcFuelNeed(void);
+ double getRPM(void) {return RPM;}
+ string GetEngineLabels(void);
+ string GetEngineValues(void);
+
+private:
+
+ double BrakeHorsePower;
+ double PowerAvailable;
+
+ // timestep
+ double dt;
+
+ // constants
+ double hptowatts;
+
+ double PowerWatts; // maximum engine power
+ double RPM; // revolutions per minute
+ double HP;
+
+ void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
+
Module: FGEngine.cpp
Author: Jon Berndt
Date started: 01/21/99
Called by: FGAircraft
-
+
------------- 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.
-
+
FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------
See header file.
-
+
HISTORY
--------------------------------------------------------------------------------
01/21/99 JSB Created
09/03/99 JSB Changed Rocket thrust equation to correct -= Thrust instead of
+= Thrust (thanks to Tony Peden)
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGEngine.h"
#include "FGTank.h"
+#include "FGPropeller.h"
+#include "FGNozzle.h"
namespace JSBSim {
FCS = FDMExec->GetFCS();
Propulsion = FDMExec->GetPropulsion();
Aircraft = FDMExec->GetAircraft();
- Translation = FDMExec->GetTranslation();
- Rotation = FDMExec->GetRotation();
- Position = FDMExec->GetPosition();
+ Propagate = FDMExec->GetPropagate();
Auxiliary = FDMExec->GetAuxiliary();
Output = FDMExec->GetOutput();
-
+
PropertyManager = FDMExec->GetPropertyManager();
Debug(0);
void FGEngine::ConsumeFuel(void)
{
- double Fshortage, Oshortage;
+ double Fshortage, Oshortage, TanksWithFuel;
FGTank* Tank;
if (TrimMode) return;
- Fshortage = Oshortage = 0.0;
+ Fshortage = Oshortage = TanksWithFuel = 0.0;
+
+ // count how many assigned tanks have fuel
+ for (unsigned int i=0; i<SourceTanks.size(); i++) {
+ Tank = Propulsion->GetTank(SourceTanks[i]);
+ if (Tank->GetContents() > 0.0) {
+ ++TanksWithFuel;
+ }
+ }
+ if (!TanksWithFuel) return;
+
for (unsigned int i=0; i<SourceTanks.size(); i++) {
Tank = Propulsion->GetTank(SourceTanks[i]);
if (Tank->GetType() == FGTank::ttFUEL) {
- Fshortage += Tank->Reduce(CalcFuelNeed()/Propulsion->GetnumSelectedFuelTanks());
+ Fshortage += Tank->Drain(CalcFuelNeed()/TanksWithFuel);
} else {
- Oshortage += Tank->Reduce(CalcOxidizerNeed()/Propulsion->GetnumSelectedOxiTanks());
+ Oshortage += Tank->Drain(CalcOxidizerNeed()/TanksWithFuel);
}
}
SourceTanks.push_back(tkID);
}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGColumnVector3& FGEngine::GetBodyForces(void)
+{
+ return Thruster->GetBodyForces();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGColumnVector3& FGEngine::GetMoments(void)
+{
+ return Thruster->GetMoments();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGEngine::LoadThruster(FGConfigFile* AC_cfg)
+{
+ string token, fullpath, localpath;
+ string thrusterFileName, thrType, engineFileName;
+ FGConfigFile* Cfg_ptr = 0;
+ double xLoc, yLoc, zLoc, Pitch, Yaw;
+ double P_Factor = 0, Sense = 0.0;
+ string enginePath = FDMExec->GetEnginePath();
+ string aircraftPath = FDMExec->GetAircraftPath();
+ thrusterFileName = AC_cfg->GetValue("FILE");
+
+# ifndef macintosh
+ fullpath = enginePath + "/";
+ localpath = aircraftPath + "/" + "/Engines/";
+# else
+ fullpath = enginePath + ";";
+ localpath = aircraftPath + ";" + ";Engines;";
+# endif
+
+ // Look in the Aircraft/Engines directory first
+ FGConfigFile Local_Thruster_cfg(localpath + thrusterFileName + ".xml");
+ FGConfigFile Thruster_cfg(fullpath + thrusterFileName + ".xml");
+
+ if (Local_Thruster_cfg.IsOpen()) {
+ Cfg_ptr = &Local_Thruster_cfg;
+ if (debug_lvl > 0) cout << "\n Reading thruster from file: " << localpath
+ + thrusterFileName + ".xml"<< endl;
+ } else {
+ if (Thruster_cfg.IsOpen()) {
+ Cfg_ptr = &Thruster_cfg;
+ if (debug_lvl > 0) cout << "\n Reading thruster from file: " << fullpath
+ + thrusterFileName + ".xml"<< endl;
+ }
+ }
+
+ if (Cfg_ptr) {
+ Cfg_ptr->GetNextConfigLine();
+ thrType = Cfg_ptr->GetValue();
+
+ if (thrType == "FG_PROPELLER") {
+ Thruster = new FGPropeller(FDMExec, Cfg_ptr);
+ } else if (thrType == "FG_NOZZLE") {
+ Thruster = new FGNozzle(FDMExec, Cfg_ptr);
+ } else if (thrType == "FG_DIRECT") {
+ Thruster = new FGThruster( FDMExec, Cfg_ptr);
+ }
+
+ 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;
+ }
+
+ Thruster->SetLocation(xLoc, yLoc, zLoc);
+ Thruster->SetAnglesToBody(0, Pitch, Yaw);
+ if (thrType == "FG_PROPELLER" && P_Factor > 0.001) {
+ ((FGPropeller*)Thruster)->SetPFactor(P_Factor);
+ if (debug_lvl > 0) cout << " P-Factor: " << P_Factor << endl;
+ ((FGPropeller*)Thruster)->SetSense(fabs(Sense)/Sense);
+ if (debug_lvl > 0) cout << " Sense: " << Sense << endl;
+ }
+ Thruster->SetdeltaT(State->Getdt() * Propulsion->GetRate());
+ return true;
+ } else {
+
+ cerr << "Could not read thruster config file: " << fullpath
+ + thrusterFileName + ".xml" << endl;
+ return false;
+ }
+
+}
+
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
#endif
#include "FGJSBBase.h"
+#include "FGThruster.h"
#include "FGPropertyManager.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
class FGAtmosphere;
class FGFCS;
class FGAircraft;
-class FGTranslation;
-class FGRotation;
+class FGPropagate;
class FGPropulsion;
-class FGPosition;
class FGAuxiliary;
class FGOutput;
+class FGThruster;
+class FGConfigFile;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DOCUMENTATION
This base class contains methods and members common to all engines, such as
logic to drain fuel from the appropriate tank, etc.
@author Jon S. Berndt
- @version $Id$
+ @version $Id$
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGEngine(FGFDMExec* exec);
virtual ~FGEngine();
- enum EngineType {etUnknown, etRocket, etPiston, etTurbine, etSimTurbine};
+ enum EngineType {etUnknown, etRocket, etPiston, etTurbine, etElectric};
EngineType GetType(void) { return Type; }
virtual string GetName(void) { return Name; }
virtual void SetStarter(bool s) { Starter = s; }
/** Calculates the thrust of the engine, and other engine functions.
- @param PowerRequired this is the power required to run the thrusting device
- such as a propeller. This resisting effect must be provided to the
- engine model.
@return Thrust in pounds */
- virtual double Calculate(double PowerRequired) {return 0.0;};
+ virtual double Calculate(void) {return 0.0;}
/** Reduces the fuel in the active tanks by the amount required.
This function should be called from within the
virtual bool GetTrimMode(void) {return TrimMode;}
virtual void SetTrimMode(bool state) {TrimMode = state;}
+ virtual FGColumnVector3& GetBodyForces(void);
+ virtual FGColumnVector3& GetMoments(void);
+
+ bool LoadThruster(FGConfigFile* AC_cfg);
+ FGThruster* GetThruster(void) {return Thruster;}
+
+ virtual string GetEngineLabels(void) = 0;
+ virtual string GetEngineValues(void) = 0;
+
protected:
FGPropertyManager* PropertyManager;
string Name;
FGFCS* FCS;
FGPropulsion* Propulsion;
FGAircraft* Aircraft;
- FGTranslation* Translation;
- FGRotation* Rotation;
- FGPosition* Position;
+ FGPropagate* Propagate;
FGAuxiliary* Auxiliary;
FGOutput* Output;
+ FGThruster* Thruster;
vector <int> SourceTanks;
void Debug(int from);
#include "FGAtmosphere.h"
#include "FGFCS.h"
#include "FGAircraft.h"
-#include "FGTranslation.h"
-#include "FGRotation.h"
+#include "FGPropagate.h"
#include "FGPropulsion.h"
-#include "FGPosition.h"
#include "FGAuxiliary.h"
#include "FGOutput.h"
+#include "FGThruster.h"
+#include "FGConfigFile.h"
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif
APAttitudeSetPt = APAltitudeSetPt = APHeadingSetPt = APAirspeedSetPt = 0.0;
DoNormalize=true;
- eMode = mNone;
-
bind();
for (i=0;i<=NForms;i++) {
DePos[i] = DaLPos[i] = DaRPos[i] = DrPos[i] = 0.0;
{
unsigned int i;
- if (!FGModel::Run()) {
- for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = ThrottleCmd[i];
- for (i=0; i<MixturePos.size(); i++) MixturePos[i] = MixtureCmd[i];
- for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i];
- for (i=0; i<APComponents.size(); i++) {
- eMode = mAP;
- APComponents[i]->Run();
- eMode = mNone;
- }
- for (i=0; i<FCSComponents.size(); i++) {
- eMode = mFCS;
- FCSComponents[i]->Run();
- eMode = mNone;
- }
- if (DoNormalize) Normalize();
+ if (FGModel::Run()) return true; // fast exit if nothing to do
- return false;
- } else {
- return true;
- }
+ for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = ThrottleCmd[i];
+ for (i=0; i<MixturePos.size(); i++) MixturePos[i] = MixtureCmd[i];
+ for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i];
+
+ for (i=0; i<APComponents.size(); i++) APComponents[i]->Run(); // cycle AP components
+ for (i=0; i<FCSComponents.size(); i++) FCSComponents[i]->Run(); // cycle FCS components
+
+ if (DoNormalize) Normalize();
+
+ return false;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
}
# ifndef macintosh
- file = "control/" + fname + ".xml";
+// file = "control/" + fname + ".xml";
+ file = FDMExec->GetAircraftPath() + "/" + FDMExec->GetModelName() + "/" + fname + ".xml";
# else
- file = "control;" + fname + ".xml";
+// file = "control;" + fname + ".xml";
+ file = FDMExec->GetAircraftPath() + ";" + FDMExec->GetModelName() + ";" + fname + ".xml";
# endif
if (name.empty()) {
if (delimiter == "AUTOPILOT") {
Components = &APComponents;
- eMode = mAP;
Name = "Autopilot: " + name;
} else if (delimiter == "FLIGHT_CONTROL") {
Components = &FCSComponents;
- eMode = mFCS;
Name = "FCS: " + name;
} else {
cerr << endl << "Unknown FCS delimiter" << endl << endl;
if (delimiter == "FLIGHT_CONTROL") bindModel();
- eMode = mNone;
-
return true;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-double FGFCS::GetComponentOutput(int idx)
-{
- switch (eMode) {
- case mFCS:
- return FCSComponents[idx]->GetOutput();
- case mAP:
- return APComponents[idx]->GetOutput();
- case mNone:
- cerr << "Unknown FCS mode" << endl;
- break;
- }
- return 0.0;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-string FGFCS::GetComponentName(int idx)
-{
- switch (eMode) {
- case mFCS:
- return FCSComponents[idx]->GetName();
- case mAP:
- return APComponents[idx]->GetName();
- case mNone:
- cerr << "Unknown FCS mode" << endl;
- break;
- }
- return string("");
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
double FGFCS::GetBrake(FGLGear::BrakeGroup bg)
{
switch (bg) {
{
unsigned int comp;
string CompValues = "";
- char buffer[10];
+ char buffer[12];
bool firstime = true;
for (comp = 0; comp < FCSComponents.size(); comp++) {
Header: FGGFCS.h
Author: Jon S. Berndt
Date started: 12/12/98
-
+
------------- 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
--------------------------------------------------------------------------------
12/12/98 JSB Created
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
or command and ends at an effector, e.g. an aerosurface. The FCS components
which comprise the control laws for an axis are defined sequentially in
the configuration file. For instance, for the X-15:
-
+
<pre>
- < FLIGHT_CONTROL NAME="X-15 SAS">
-
- < COMPONENT NAME="Pitch Trim Sum" TYPE="SUMMER">
- ID 0
- INPUT FG_ELEVATOR_CMD
- INPUT FG_PITCH_TRIM_CMD
- CLIPTO -1 1
- </COMPONENT>
-
- < COMPONENT NAME="Pitch Command Scale" TYPE="AEROSURFACE_SCALE">
- ID 1
- INPUT 0
+ \<FLIGHT_CONTROL NAME="X-15 SAS">
+
+ \<COMPONENT NAME="Pitch Trim Sum" TYPE="SUMMER">
+ INPUT fcs/elevator-cmd-norm
+ INPUT fcs/pitch-trim-cmd-norm
+ CLIPTO -1 1
+ \</COMPONENT>
+
+ \<COMPONENT NAME="Pitch Command Scale" TYPE="AEROSURFACE_SCALE">
+ INPUT fcs/pitch-trim-sum
MIN -50
MAX 50
- </COMPONENT>
+ \</COMPONENT>
- < COMPONENT NAME="Pitch Gain 1" TYPE="PURE_GAIN">
- ID 2
- INPUT 1
+ \<COMPONENT NAME="Pitch Gain 1" TYPE="PURE_GAIN">
+ INPUT fcs/pitch-command-scale
GAIN -0.36
- </COMPONENT>
-
- < COMPONENT NAME="Pitch Scheduled Gain 1" TYPE="SCHEDULED_GAIN">
- ID 3
- INPUT 2
- GAIN 0.017
- SCHEDULED_BY FG_ELEVATOR_POS
- -0.35 -6.0
- -0.17 -3.0
- 0.00 -2.0
- 0.09 -3.0
- 0.17 -5.0
- 0.60 -12.0
- </COMPONENT>
+ \</COMPONENT>
... etc.
</pre>
-
+
In the above case we can see the first few components of the pitch channel
defined. The input to the first component, as can be seen in the "Pitch trim
sum" component, is really the sum of two parameters: elevator command (from
the stick - a pilot input), and pitch trim. The type of this component is
- "Summer". Its ID is 0 - the ID is used by other components to reference it.
+ "Summer".
The next component created is an aerosurface scale component - a type of
gain (see the LoadFCS() method for insight on how the various types of
- components map into the actual component classes). You can see the input of
- the "Pitch Command Scale" component takes "0" as input. When a number is
- specified as an input, it refers to the ID of another FCS component. In this
- case, ID 0 refers to the previously defined and discussed "Pitch Trim Sum"
- component. This continues until the final component for an axis when the
+ components map into the actual component classes). This continues until the
+ final component for an axis when the
OUTPUT keyword specifies where the output is supposed to go. See the
individual components for more information on how they are mechanized.
-
+
+ Another option for the flight controls portion of the config file is that in
+ addition to using the "NAME" attribute in,
+
+ <pre>
+ \<FLIGHT_CONTROL NAME="X-15 SAS">
+ </pre>
+
+ one can also supply a filename:
+
+ <pre>
+ \<FLIGHT_CONTROL NAME="X-15 SAS" FILE="X15.xml">
+ \</FLIGHT_CONTROL>
+ </pre>
+
+ In this case, the FCS would be read in from another file.
+
@author Jon S. Berndt
@version $Id$
@see FGFCSComponent
/** Gets the aileron command.
@return aileron command in percent */
inline double GetDaCmd(void) const { return DaCmd; }
-
+
/** Gets the elevator command.
@return elevator command in percent */
inline double GetDeCmd(void) const { return DeCmd; }
/** Gets the pitch trim command.
@return pitch trim command in percent */
inline double GetPitchTrimCmd(void) const { return PTrimCmd; }
-
+
/** Gets the rudder trim command.
@return rudder trim command in percent */
inline double GetYawTrimCmd(void) const { return YTrimCmd; }
-
+
/** Gets the aileron trim command.
@return aileron trim command in percent */
inline double GetRollTrimCmd(void) const { return RTrimCmd; }
-
+
/** Get the gear extend/retract command. 0 commands gear up, 1 down.
defaults to down.
@return the current value of the gear extend/retract command*/
- inline double GetGearCmd(void) const { return GearCmd; }
+ inline double GetGearCmd(void) const { return GearCmd; }
//@}
/// @name AUTOPilot -> FCS effectors command retrieval
/** Gets the AUTOPilot aileron command.
@return aileron command in radians */
inline double GetAPDaCmd(void) const { return AP_DaCmd; }
-
+
/** Gets the AUTOPilot elevator command.
@return elevator command in radians */
inline double GetAPDeCmd(void) const { return AP_DeCmd; }
/** Gets the AUTOPilot rudder command.
@return rudder command in radians */
inline double GetAPDrCmd(void) const { return AP_DrCmd; }
-
+
/** Gets the AUTOPilot throttle (all engines) command.
@return throttle command in percent */
inline double GetAPThrottleCmd(void) const { return AP_ThrottleCmd; }
/** Turns on/off the attitude-seeking autopilot.
@param set true turns the mode on, false turns it off **/
inline void SetAPAcquireAttitude(bool set) {APAcquireAttitude = set;}
-
+
/** Turns on/off the altitude-seeking autopilot.
@param set true turns the mode on, false turns it off **/
inline void SetAPAcquireAltitude(bool set) {APAcquireAltitude = set;}
-
+
/** Turns on/off the heading-seeking autopilot.
@param set true turns the mode on, false turns it off **/
inline void SetAPAcquireHeading(bool set) {APAcquireHeading = set;}
-
+
/** Turns on/off the airspeed-seeking autopilot.
@param set true turns the mode on, false turns it off **/
inline void SetAPAcquireAirspeed(bool set) {APAcquireAirspeed = set;}
-
+
/** Turns on/off the attitude-holding autopilot.
@param set true turns the mode on, false turns it off **/
inline void SetAPAttitudeHold(bool set) {APAttitudeHold = set;}
@param set true turns the mode on, false turns it off **/
inline void SetAPWingsLevelHold(bool set) {APWingsLevelHold = set;}
//@}
-
+
/// @name AUTOPilot mode retrieval
//@{
/** Retrieves the on/off mode of the autopilot AcquireAttitude mode
//@{
/** Gets the left aileron position.
@return aileron position in radians */
- inline double GetDaLPos( int form = ofRad )
+ inline double GetDaLPos( int form = ofRad )
const { return DaLPos[form]; }
/// @name Aerosurface position retrieval
//@{
/** Gets the right aileron position.
@return aileron position in radians */
- inline double GetDaRPos( int form = ofRad )
+ inline double GetDaRPos( int form = ofRad )
const { return DaRPos[form]; }
/** Gets the elevator position.
@return elevator position in radians */
- inline double GetDePos( int form = ofRad )
+ inline double GetDePos( int form = ofRad )
const { return DePos[form]; }
-
+
/** Gets the rudder position.
@return rudder position in radians */
- inline double GetDrPos( int form = ofRad )
+ inline double GetDrPos( int form = ofRad )
const { return DrPos[form]; }
/** Gets the speedbrake position.
@return speedbrake position in radians */
- inline double GetDsbPos( int form = ofRad )
+ inline double GetDsbPos( int form = ofRad )
const { return DsbPos[form]; }
/** Gets the spoiler position.
@return spoiler position in radians */
- inline double GetDspPos( int form = ofRad )
+ inline double GetDspPos( int form = ofRad )
const { return DspPos[form]; }
-
+
/** Gets the flaps position.
@return flaps position in radians */
- inline double GetDfPos( int form = ofRad )
+ inline double GetDfPos( int form = ofRad )
const { return DfPos[form]; }
-
+
/** Gets the throttle position.
@param engine engine ID number
@return throttle position for the given engine in percent ( 0 - 100)*/
@param engine engine ID number
@return mixture position for the given engine in percent ( 0 - 100)*/
inline double GetMixturePos(int engine) const { return MixturePos[engine]; }
-
+
/** Gets the gear position (0 up, 1 down), defaults to down
@return gear position (0 up, 1 down) */
- inline double GetGearPos(void) const { return GearPos; }
+ inline double GetGearPos(void) const { return GearPos; }
/** Gets the prop pitch position.
@param engine engine ID number
@return pointer to the State object */
inline FGState* GetState(void) { return State; }
- /** Retrieves a components output value
- @param idx the index of the component (the component ID)
- @return output value from the component */
- double GetComponentOutput(int idx);
-
- /** Retrieves the component name
- @param idx the index of the component (the component ID)
- @return name of the component */
- string GetComponentName(int idx);
-
/** Retrieves all component names for inclusion in output stream */
string GetComponentStrings(void);
@param engine engine ID number
@param cmd mixture command in percent (0 - 100)*/
void SetMixtureCmd(int engine, double cmd);
-
+
/** Set the gear extend/retract command, defaults to down
@param gear command 0 for up, 1 for down */
- void SetGearCmd(double gearcmd) { GearCmd = gearcmd; }
+ void SetGearCmd(double gearcmd) { GearCmd = gearcmd; }
/** Sets the propeller pitch command for the specified engine
@param engine engine ID number
//@{
/** Sets the left aileron position
@param cmd left aileron position in radians*/
- inline void SetDaLPos( int form , double pos )
+ inline void SetDaLPos( int form , double pos )
{ DaLPos[form] = pos; }
/** Sets the right aileron position
@param cmd right aileron position in radians*/
- inline void SetDaRPos( int form , double pos )
+ inline void SetDaRPos( int form , double pos )
{ DaRPos[form] = pos; }
/** Sets the elevator position
@param cmd elevator position in radians*/
- inline void SetDePos( int form , double pos )
+ inline void SetDePos( int form , double pos )
{ DePos[form] = pos; }
/** Sets the rudder position
@param cmd rudder position in radians*/
- inline void SetDrPos( int form , double pos )
+ inline void SetDrPos( int form , double pos )
{ DrPos[form] = pos; }
-
+
/** Sets the flaps position
@param cmd flaps position in radians*/
- inline void SetDfPos( int form , double pos )
+ inline void SetDfPos( int form , double pos )
{ DfPos[form] = pos; }
-
+
/** Sets the speedbrake position
@param cmd speedbrake position in radians*/
- inline void SetDsbPos( int form , double pos )
+ inline void SetDsbPos( int form , double pos )
{ DsbPos[form] = pos; }
/** Sets the spoiler position
@param cmd spoiler position in radians*/
- inline void SetDspPos( int form , double pos )
+ inline void SetDspPos( int form , double pos )
{ DspPos[form] = pos; }
-
+
/** Sets the actual throttle setting for the specified engine
@param engine engine ID number
@param cmd throttle setting in percent (0 - 100)*/
@param engine engine ID number
@param cmd mixture setting in percent (0 - 100)*/
void SetMixturePos(int engine, double cmd);
-
+
/** Set the gear extend/retract position, defaults to down
@param gear position 0 up, 1 down */
- void SetGearPos(double gearpos) { GearPos = gearpos; }
+ void SetGearPos(double gearpos) { GearPos = gearpos; }
/** Sets the actual prop pitch setting for the specified engine
bool Load(FGConfigFile* AC_cfg);
void AddThrottle(void);
-
+
FGPropertyManager* GetPropertyManager(void) { return PropertyManager; }
-
+
void bind(void);
void bindModel(void);
void unbind(FGPropertyManager *node);
-
+
private:
double DaCmd, DeCmd, DrCmd, DfCmd, DsbCmd, DspCmd;
double AP_DaCmd, AP_DeCmd, AP_DrCmd, AP_ThrottleCmd;
- double DePos[NForms], DaLPos[NForms], DaRPos[NForms], DrPos[NForms];
+ double DePos[NForms], DaLPos[NForms], DaRPos[NForms], DrPos[NForms];
double DfPos[NForms], DsbPos[NForms], DspPos[NForms];
double PTrimCmd, YTrimCmd, RTrimCmd;
vector <double> ThrottleCmd;
double LeftBrake, RightBrake, CenterBrake; // Brake settings
double GearCmd,GearPos;
- enum Mode {mAP, mFCS, mNone} eMode;
-
double APAttitudeSetPt, APAltitudeSetPt, APHeadingSetPt, APAirspeedSetPt;
bool APAcquireAttitude, APAcquireAltitude, APAcquireHeading, APAcquireAirspeed;
bool APAttitudeHold, APAltitudeHold, APHeadingHold, APAirspeedHold, APWingsLevelHold;
#include "FGAerodynamics.h"
#include "FGInertial.h"
#include "FGAircraft.h"
-#include "FGTranslation.h"
-#include "FGRotation.h"
-#include "FGPosition.h"
+#include "FGPropagate.h"
#include "FGAuxiliary.h"
#include "FGOutput.h"
#include "FGConfigFile.h"
} else if ( node->getChild(i)->isTied() ) {
name = ((FGPropertyManager*)node->getChild(i))->GetFullyQualifiedName();
cerr << name << " is tied" << endl;
- }
+ }
}
-}
+}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Constructor
FGFDMExec::FGFDMExec(FGPropertyManager* root)
{
-
+
Frame = 0;
FirstModel = 0;
Error = 0;
Inertial = 0;
GroundReactions = 0;
Aircraft = 0;
- Translation = 0;
- Rotation = 0;
- Position = 0;
+ Propagate = 0;
Auxiliary = 0;
Output = 0;
IC = 0;
instance = master->GetNode("/fdm/jsbsim",IdFDM,true);
-
+
Debug(0);
-
+
// this is here to catch errors in binding member functions
// to the property tree.
try {
} catch ( string msg ) {
cout << "Caught error: " << msg << endl;
exit(1);
- }
+ }
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
checkTied( instance );
} catch ( string msg ) {
cout << "Caught error: " << msg << endl;
- }
-
+ }
+
for (unsigned int i=1; i<SlaveFDMList.size(); i++) delete SlaveFDMList[i]->exec;
SlaveFDMList.clear();
-
+
Debug(1);
}
Inertial = new FGInertial(this);
GroundReactions = new FGGroundReactions(this);
Aircraft = new FGAircraft(this);
- Translation = new FGTranslation(this);
- Rotation = new FGRotation(this);
- Position = new FGPosition(this);
+ Propagate = new FGPropagate(this);
Auxiliary = new FGAuxiliary(this);
Output = new FGOutput(this);
State = new FGState(this); // This must be done here, as the FGState
// class needs valid pointers to the above
// model classes
-
+
// Initialize models so they can communicate with each other
if (!Atmosphere->InitModel()) {
if (!Aircraft->InitModel()) {
cerr << fgred << "Aircraft model init failed" << fgdef << endl;
Error+=128;}
- if (!Translation->InitModel()) {
- cerr << fgred << "Translation model init failed" << fgdef << endl;
- Error+=256;}
- if (!Rotation->InitModel()) {
- cerr << fgred << "Rotation model init failed" << fgdef << endl;
+ if (!Propagate->InitModel()) {
+ cerr << fgred << "Propagate model init failed" << fgdef << endl;
Error+=512;}
- if (!Position->InitModel()) {
- cerr << fgred << "Position model init failed" << fgdef << endl;
- Error+=1024;}
if (!Auxiliary->InitModel()) {
cerr << fgred << "Auxiliary model init failed" << fgdef << endl;
Error+=2058;}
Error+=4096;}
if (Error > 0) result = false;
-
- IC = new FGInitialCondition(this);
-
+
+ IC = new FGInitialCondition(this);
+
// Schedule a model. The second arg (the integer) is the pass number. For
// instance, the atmosphere model gets executed every fifth pass it is called
// by the executive. Everything else here gets executed each pass.
Schedule(Inertial, 1);
Schedule(GroundReactions, 1);
Schedule(Aircraft, 1);
- Schedule(Rotation, 1);
- Schedule(Translation, 1);
- Schedule(Position, 1);
+ Schedule(Propagate, 1);
Schedule(Auxiliary, 1);
Schedule(Output, 1);
delete Inertial;
delete GroundReactions;
delete Aircraft;
- delete Translation;
- delete Rotation;
- delete Position;
+ delete Propagate;
delete Auxiliary;
delete Output;
delete State;
-
+
delete IC;
delete Trim;
-
+
FirstModel = 0L;
Error = 0;
Inertial = 0;
GroundReactions = 0;
Aircraft = 0;
- Translation = 0;
- Rotation = 0;
- Position = 0;
+ Propagate = 0;
Auxiliary = 0;
Output = 0;
model_iterator->NextModel->SetRate(rate);
}
-
+
return 0;
}
FGFDMExec::EnginePath = EnginePath;
return LoadModel(model);
-}
+}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
cerr << "aircraft and engine paths" << endl;
return false;
}
-
+
# ifndef macintosh
- aircraftCfgFileName = AircraftPath + "/" + model + "/" + model + ".xml";
+ aircraftCfgFileName = AircraftPath + "/" + model + ".xml";
# else
- aircraftCfgFileName = AircraftPath + ";" + model + ";" + model + ".xml";
+ aircraftCfgFileName = AircraftPath + ";" + model + ".xml";
# endif
FGConfigFile AC_cfg(aircraftCfgFileName);
if (!AC_cfg.IsOpen()) return false;
-
+
modelName = model;
-
+
if (modelLoaded) {
DeAllocate();
Allocate();
cerr << " You have version: " << CFGVersion << endl << fgdef << endl;
return false;
}
-
+
if (Release == "ALPHA") {
system("banner ALPHA");
cout << endl << endl
string AircraftName = AC_cfg->GetValue("FILE");
debug_lvl = 0; // turn off debug output for slave vehicle
-
+
SlaveFDMList.back()->exec->SetAircraftPath( AircraftPath );
SlaveFDMList.back()->exec->SetEnginePath( EnginePath );
SlaveFDMList.back()->exec->LoadModel(AircraftName);
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FGPropertyManager* FGFDMExec::GetPropertyManager(void) {
+FGPropertyManager* FGFDMExec::GetPropertyManager(void) {
return instance;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FGTrim* FGFDMExec::GetTrim(void) {
+FGTrim* FGFDMExec::GetTrim(void) {
delete Trim;
Trim = new FGTrim(this,tNone);
return Trim;
}
-
+
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
11/17/98 JSB Created
7/31/99 TP Added RunIC function that runs the sim so that every frame
begins with the IC values from the given FGInitialCondition
- object and dt=0.
+ object and dt=0.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY
When an aircraft model is loaded the config file is parsed and for each of the
sections of the config file (propulsion, flight control, etc.) the
- corresponding "ReadXXX()" method is called. From within this method the
+ corresponding "ReadXXX()" method is called. From within this method the
"Load()" method of that system is called (e.g. LoadFCS).
<h4>JSBSim Debugging Directives</h4>
This describes to any interested entity the debug level
requested by setting the JSBSIM_DEBUG environment variable.
- The bitmasked value choices are as follows:<ol>
- <li><b>unset</b>: In this case (the default) JSBSim would only print
+ The bitmasked value choices are as follows:
+ - <b>unset</b>: 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</li>
- <li><b>0</b>: This requests JSBSim not to output any messages
- whatsoever.</li>
- <li><b>1</b>: This value explicity requests the normal JSBSim
- startup messages</li>
- <li><b>2</b>: This value asks for a message to be printed out when
- a class is instantiated</li>
- <li><b>4</b>: When this value is set, a message is displayed when a
- FGModel object executes its Run() method</li>
- <li><b>8</b>: When this value is set, various runtime state variables
- are printed out periodically</li>
- <li><b>16</b>: When set various parameters are sanity checked and
- a message is printed out when they go out of bounds</li>
- </ol>
+ variable is not set, debug_lvl is set to 1 internally
+ - <b>0</b>: This requests JSBSim not to output any messages
+ whatsoever
+ - <b>1</b>: This value explicity requests the normal JSBSim
+ startup messages
+ - <b>2</b>: This value asks for a message to be printed out when
+ a class is instantiated
+ - <b>4</b>: When this value is set, a message is displayed when a
+ FGModel object executes its Run() method
+ - <b>8</b>: When this value is set, various runtime state variables
+ are printed out periodically
+ - <b>16</b>: When set various parameters are sanity checked and
+ a message is printed out when they go out of bounds
@author Jon S. Berndt
@version $Id$
/// Default constructor
FGFDMExec(FGPropertyManager* root = 0);
-
+
/// Default destructor
~FGFDMExec();
/// Resumes the sim
void Resume(void) {frozen = false;}
-
- /** Loads an aircraft model.
+
+ /** Loads an aircraft model.
@param AircraftPath path to the aircraft directory. For instance:
"aircraft". Under aircraft, then, would be directories for various
modeled aircraft such as C172/, x15/, etc.
instance: "aircraft/x15/x15.xml"
@return true if successful*/
bool LoadModel(string AircraftPath, string EnginePath, string model);
-
+
/** Loads an aircraft model. The paths to the aircraft and engine
config file directories must be set prior to calling this. See
instance: "aircraft/x15/x15.xml"
@return true if successful*/
bool LoadModel(string model);
-
+
/** Sets the path to the engine config file directories.
@param path path to the directory under which engine config
modeled aircraft such as C172/, x15/, etc.
*/
bool SetAircraftPath(string path) { AircraftPath = path; return true; }
-
+
/** Sets the path to the autopilot config file directories.
@param path path to the control directory. For instance:
"control".
*/
- bool SetControlPath(string path) { ControlPath = path; return true; }
-
-
+// bool SetControlPath(string path) { ControlPath = path; return true; }
+
+
/// @name Top-level executive State and Model retrieval mechanism
//@{
/// Returns the FGState pointer.
inline FGGroundReactions* GetGroundReactions(void) {return GroundReactions;}
/// Returns the FGAircraft pointer.
inline FGAircraft* GetAircraft(void) {return Aircraft;}
- /// Returns the FGTranslation pointer.
- inline FGTranslation* GetTranslation(void) {return Translation;}
- /// Returns the FGRotation pointer.
- inline FGRotation* GetRotation(void) {return Rotation;}
- /// Returns the FGPosition pointer.
- inline FGPosition* GetPosition(void) {return Position;}
+ /// Returns the FGPropagate pointer.
+ inline FGPropagate* GetPropagate(void) {return Propagate;}
/// Returns the FGAuxiliary pointer.
inline FGAuxiliary* GetAuxiliary(void) {return Auxiliary;}
/// Returns the FGOutput pointer.
// Returns a pointer to the FGTrim object
FGTrim* GetTrim(void);
//@}
-
+
/// Retrieves the engine path.
inline string GetEnginePath(void) {return EnginePath;}
/// Retrieves the aircraft path.
inline string GetAircraftPath(void) {return AircraftPath;}
- /// Retrieves the control path.
- inline string GetControlPath(void) {return ControlPath;}
-
+// /// Retrieves the control path.
+// inline string GetControlPath(void) {return ControlPath;}
+
string GetModelName(void) { return modelName; }
-
+
FGPropertyManager* GetPropertyManager(void);
vector <string> EnumerateFDMs(void);
void SetSlave(void) {IsSlave = true;}
-
+
private:
FGModel* FirstModel;
bool IsSlave;
static FGPropertyManager *master;
FGPropertyManager *instance;
-
+
struct slaveData {
FGFDMExec* exec;
string info;
string AircraftPath;
string EnginePath;
- string ControlPath;
-
+// string ControlPath;
+
string CFGVersion;
string Release;
FGInertial* Inertial;
FGGroundReactions* GroundReactions;
FGAircraft* Aircraft;
- FGTranslation* Translation;
- FGRotation* Rotation;
- FGPosition* Position;
+ FGPropagate* Propagate;
FGAuxiliary* Auxiliary;
FGOutput* Output;
-
+
FGInitialCondition* IC;
FGTrim *Trim;
class FGAtmosphere;
class FGFCS;
class FGAircraft;
-class FGTranslation;
-class FGRotation;
-class FGPosition;
+class FGPropagate;
class FGAuxiliary;
class FGOutput;
public:
FGFactorGroup(FGFDMExec* fdmex);
~FGFactorGroup();
-
+
bool Load(FGConfigFile *AC_cfg);
double TotalValue(void);
inline double GetValue(void) const { return totalValue; }
inline double GetSD(void) { return SDtotal; }
inline double GetFactorSD(void) { return FGCoefficient::GetSD(); }
-
+
void bind(FGPropertyManager* parent);
void unbind(void);
FGPropertyManager *node;
void Debug(int from);
};
-}
-#endif
+}
+#endif
#include "FGFDMExec.h"
#include "FGAircraft.h"
-#include "FGTranslation.h"
+#include "FGPropagate.h"
#include "FGMassBalance.h"
#include "FGState.h"
#include "FGForce.h"
case tWindBody:
return fdmex->GetState()->GetTs2b();
case tLocalBody:
- return fdmex->GetState()->GetTl2b();
+ return fdmex->GetPropagate()->GetTl2b();
case tCustom:
case tNone:
return mT;
vXYZn(eZ) = z;
SetActingLocation(x, y, z);
}
-
+
/** Acting point of application.
JSBsim structural coords used (inches, x +back, y +right, z +up).
This function sets the point at which the force acts - this may
inline double SetActingLocationZ(double z) {vActingXYZn(eZ) = z; return z;}
inline void SetLocation(FGColumnVector3 vv) { vXYZn = vv; SetActingLocation(vv);}
inline void SetActingLocation(FGColumnVector3 vv) { vActingXYZn = vv; }
-
+
inline double GetLocationX( void ) { return vXYZn(eX);}
inline double GetLocationY( void ) { return vXYZn(eY);}
inline double GetLocationZ( void ) { return vXYZn(eZ);}
FGColumnVector3 vFn;
FGColumnVector3 vMn;
FGColumnVector3 vH;
-
+
private:
FGColumnVector3 vFb;
FGColumnVector3 vM;
FGMatrix33 mT;
- virtual void Debug(int from);
+ void Debug(int from);
};
}
#endif
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+#include <sstream>
+#include <iomanip>
+
#include "FGGroundReactions.h"
#include "FGPropertyManager.h"
static const char *IdSrc = "$Id$";
static const char *IdHdr = ID_GROUNDREACTIONS;
-#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
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
FGGroundReactions::FGGroundReactions(FGFDMExec* fgex) : FGModel(fgex)
{
Name = "FGGroundReactions";
-
+
bind();
Debug(0);
vMoments.InitMatrix();
// Only execute gear force code below 300 feet
- if ( Position->GetDistanceAGL() < 300.0 ) {
+ if ( Propagate->GetDistanceAGL() < 300.0 ) {
vector <FGLGear>::iterator iGear = lGear.begin();
// Sum forces and moments for all gear, here.
// Some optimizations may be made here - or rather in the gear code itself.
string FGGroundReactions::GetGroundReactionStrings(void)
{
- string GroundReactionStrings = "";
- bool firstime = true;
+ std::ostringstream buf;
for (unsigned int i=0;i<lGear.size();i++) {
- if (!firstime) GroundReactionStrings += ", ";
- GroundReactionStrings += (lGear[i].GetName() + "_WOW, ");
- GroundReactionStrings += (lGear[i].GetName() + "_stroke, ");
- 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, ");
- GroundReactionStrings += (lGear[i].GetName() + "_WhlSlipDegrees");
-
- firstime = false;
+ string name = lGear[i].GetName();
+ buf << name << "_WOW, "
+ << name << "_stroke, "
+ << name << "_strokeVel, "
+ << name << "_CompressForce, "
+ << name << "_WhlSideForce, "
+ << name << "_WhlVelVecX, "
+ << name << "_WhlVelVecY, "
+ << name << "_WhlRollForce, "
+ << name << "_BodyXForce, "
+ << name << "_BodyYForce, "
+ << name << "_WhlSlipDegrees, ";
}
- GroundReactionStrings += ", TotalGearForce_X, ";
- GroundReactionStrings += "TotalGearForce_Y, ";
- GroundReactionStrings += "TotalGearForce_Z, ";
- GroundReactionStrings += "TotalGearMoment_L, ";
- GroundReactionStrings += "TotalGearMoment_M, ";
- GroundReactionStrings += "TotalGearMoment_N";
+ buf << "TotalGearForce_X, "
+ << "TotalGearForce_Y, "
+ << "TotalGearForce_Z, "
+ << "TotalGearMoment_L, "
+ << "TotalGearMoment_M, "
+ << "TotalGearMoment_N";
- return GroundReactionStrings;
+ return buf.str();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGGroundReactions::GetGroundReactionValues(void)
{
- char buff[20];
- string GroundReactionValues = "";
-
- bool firstime = true;
+ std::ostringstream buf;
for (unsigned int i=0;i<lGear.size();i++) {
- if (!firstime) GroundReactionValues += ", ";
- GroundReactionValues += string( lGear[i].GetWOW()?"1":"0" ) + ", ";
- 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)) + ", ");
- GroundReactionValues += (string(gcvt(lGear[i].GetBodyYForce(), 6, buff)) + ", ");
- GroundReactionValues += (string(gcvt(lGear[i].GetWheelSlipAngle(), 6, buff)));
-
- firstime = false;
+ FGLGear& gear = lGear[i];
+ buf << (gear.GetWOW() ? "1, " : "0, ")
+ << setprecision(5) << gear.GetCompLen() << ", "
+ << setprecision(6) << gear.GetCompVel() << ", "
+ << setprecision(10) << gear.GetCompForce() << ", "
+ << setprecision(6) << gear.GetWheelVel(eX) << ", "
+ << gear.GetWheelVel(eY) << ", "
+ << gear.GetWheelSideForce() << ", "
+ << gear.GetWheelRollForce() << ", "
+ << gear.GetBodyXForce() << ", "
+ << gear.GetBodyYForce() << ", "
+ << gear.GetWheelSlipAngle() << ", ";
}
- 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)));
+ buf << vForces(eX) << ", "
+ << vForces(eY) << ", "
+ << vForces(eZ) << ", "
+ << vMoments(eX) << ", "
+ << vMoments(eY) << ", "
+ << vMoments(eZ);
- return GroundReactionValues;
+ return buf.str();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGGroundReactions::bind(void)
-{
+{
typedef double (FGGroundReactions::*PMF)(int) const;
PropertyManager->Tie("gear/num-units", this,
- &FGGroundReactions::GetNumGearUnits);
+ &FGGroundReactions::GetNumGearUnits);
PropertyManager->Tie("moments/l-gear-lbsft", this,1,
(PMF)&FGGroundReactions::GetMoments);
PropertyManager->Tie("moments/m-gear-lbsft", this,2,
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGInertial.h"
-#include "FGPosition.h"
+#include "FGPropagate.h"
#include "FGState.h"
#include "FGMassBalance.h"
RadiusReference = 20925650.00;
gAccelReference = GM/(RadiusReference*RadiusReference);
gAccel = GM/(RadiusReference*RadiusReference);
- vRadius.InitMatrix();
- vCoriolis.InitMatrix();
- vCentrifugal.InitMatrix();
- vGravity.InitMatrix();
-
- bind();
Debug(0);
}
FGInertial::~FGInertial(void)
{
- unbind();
Debug(1);
}
bool FGInertial::Run(void)
{
- if (!FGModel::Run()) {
-
- gAccel = GM / (Position->GetRadius()*Position->GetRadius());
-
- vGravity(eDown) = gAccel;
-
- // 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
- // motion over the curved surface of the earth (second set).
-
- vOmegaLocal(eX) = omega() * cos(Position->GetLatitude());
- vOmegaLocal(eY) = 0.0;
- vOmegaLocal(eZ) = omega() * -sin(Position->GetLatitude());
+ // Fast return if we have nothing to do ...
+ if (FGModel::Run()) return true;
- vOmegaLocal(eX) += Position->GetVe() / Position->GetRadius();
- vOmegaLocal(eY) += -Position->GetVn() / Position->GetRadius();
- vOmegaLocal(eZ) += 0.00;
+ // Gravitation accel
+ double r = Propagate->GetRadius();
+ gAccel = GetGAccel(r);
- // 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.
-
- vCoriolis(eEast) = 2.0*omega() * (Position->GetVd()*cos(Position->GetLatitude()) +
- Position->GetVn()*sin(Position->GetLatitude()));
-
- vRadius(eDown) = Position->GetRadius();
- vCentrifugal(eDown) = -vOmegaLocal.Magnitude() * vOmegaLocal.Magnitude() * vRadius(eDown);
-
-// vForces = State->GetTl2b() * MassBalance->GetMass() * (vCoriolis + vCentrifugal + vGravity);
- vForces = State->GetTl2b() * MassBalance->GetMass() * vGravity;
-
- return false;
- } else {
- return true;
- }
+ return false;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-void FGInertial::bind(void)
-{
- typedef double (FGInertial::*PMF)(int) const;
- PropertyManager->Tie("forces/fbx-inertial-lbs", this,1,
- (PMF)&FGInertial::GetForces);
- PropertyManager->Tie("forces/fby-inertial-lbs", this,2,
- (PMF)&FGInertial::GetForces);
- PropertyManager->Tie("forces/fbz-inertial-lbs", this,3,
- (PMF)&FGInertial::GetForces);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGInertial::unbind(void)
-{
- PropertyManager->Untie("forces/fbx-inertial-lbs");
- PropertyManager->Untie("forces/fby-inertial-lbs");
- PropertyManager->Untie("forces/fbz-inertial-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
~FGInertial(void);
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;}
double gravity(void) const {return gAccel;}
double omega(void) const {return RotationRate;}
+ double GetGAccel(double r) const { return GM/(r*r); }
double RefRadius(void) const {return RadiusReference;}
-
- void bind(void);
- void unbind(void);
private:
- FGColumnVector3 vOmegaLocal;
- FGColumnVector3 vForces;
- FGColumnVector3 vRadius;
- FGColumnVector3 vGravity;
- FGColumnVector3 vCoriolis;
- FGColumnVector3 vCentrifugal;
double gAccel;
double gAccelReference;
double RadiusReference;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif
-
#include "FGInertial.h"
#include "FGAtmosphere.h"
#include "FGAerodynamics.h"
-#include "FGPosition.h"
+#include "FGPropagate.h"
#include "FGConfigFile.h"
#include "FGPropertyManager.h"
altitude=hdot=0;
latitude=longitude=0;
u=v=w=0;
+ p=q=r=0;
uw=vw=ww=0;
vnorth=veast=vdown=0;
wnorth=weast=wdown=0;
if(FDMExec != NULL ) {
fdmex=FDMExec;
- fdmex->GetPosition()->Seth(altitude);
+ fdmex->GetPropagate()->Seth(altitude);
fdmex->GetAtmosphere()->Run();
PropertyManager=fdmex->GetPropertyManager();
bind();
//******************************************************************************
-double FGInitialCondition::GetUBodyFpsIC(void) {
+double FGInitialCondition::GetUBodyFpsIC(void) const {
if(lastSpeedSet == setvg )
return u;
else
//******************************************************************************
-double FGInitialCondition::GetVBodyFpsIC(void) {
+double FGInitialCondition::GetVBodyFpsIC(void) const {
if( lastSpeedSet == setvg )
return v;
else {
//******************************************************************************
-double FGInitialCondition::GetWBodyFpsIC(void) {
+double FGInitialCondition::GetWBodyFpsIC(void) const {
if( lastSpeedSet == setvg )
return w;
else
void FGInitialCondition::SetAltitudeFtIC(double tt) {
altitude=tt;
- fdmex->GetPosition()->Seth(altitude);
+ fdmex->GetPropagate()->Seth(altitude);
fdmex->GetAtmosphere()->Run();
//lets try to make sure the user gets what they intended
//******************************************************************************
void FGInitialCondition::SetAltitudeAGLFtIC(double tt) {
- fdmex->GetPosition()->SetDistanceAGL(tt);
- altitude=fdmex->GetPosition()->Geth();
+ fdmex->GetPropagate()->SetDistanceAGL(tt);
+ altitude=fdmex->GetPropagate()->Geth();
SetAltitudeFtIC(altitude);
}
&FGInitialCondition::GetLongitudeRadIC,
&FGInitialCondition::SetLongitudeRadIC,
true);
+ PropertyManager->Tie("ic/p-rad_sec", this,
+ &FGInitialCondition::GetPRadpsIC,
+ &FGInitialCondition::SetPRadpsIC,
+ true);
+ PropertyManager->Tie("ic/q-rad_sec", this,
+ &FGInitialCondition::GetQRadpsIC,
+ &FGInitialCondition::SetQRadpsIC,
+ true);
+ PropertyManager->Tie("ic/r-rad_sec", this,
+ &FGInitialCondition::GetRRadpsIC,
+ &FGInitialCondition::SetRRadpsIC,
+ true);
+
}
//******************************************************************************
PropertyManager->Untie("ic/psi-true-rad");
PropertyManager->Untie("ic/lat-gc-rad");
PropertyManager->Untie("ic/long-gc-rad");
+ PropertyManager->Untie("ic/p-rad_sec");
+ PropertyManager->Untie("ic/q-rad_sec");
+ PropertyManager->Untie("ic/r-rad_sec");
+
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void SetVnorthFpsIC(double tt);
void SetVeastFpsIC(double tt);
void SetVdownFpsIC(double tt);
+ void SetPRadpsIC(double tt) { p = tt; }
+ void SetQRadpsIC(double tt) { q = tt; }
+ void SetRRadpsIC(double tt) { r = tt; }
void SetWindNEDFpsIC(double wN, double wE, double wD);
inline double GetWindFpsIC(void) const { return sqrt(wnorth*wnorth + weast*weast); }
double GetWindDirDegIC(void);
inline double GetClimbRateFpsIC(void) const { return hdot; }
- double GetUBodyFpsIC(void);
- double GetVBodyFpsIC(void);
- double GetWBodyFpsIC(void);
+ double GetUBodyFpsIC(void) const;
+ double GetVBodyFpsIC(void) const;
+ double GetWBodyFpsIC(void) const;
+ double GetPRadpsIC() const { return p; }
+ double GetQRadpsIC() const { return q; }
+ double GetRRadpsIC() const { return r; }
void SetFlightPathAngleRadIC(double tt);
void SetAlphaRadIC(double tt);
void SetPitchAngleRadIC(double tt);
double altitude,hdot;
double latitude,longitude;
double u,v,w;
+ double p,q,r;
double uw,vw,ww;
double vnorth,veast,vdown;
double wnorth,weast,wdown;
const double FGJSBBase::slugtolb = 32.174049;
const double FGJSBBase::lbtoslug = 1.0/slugtolb;
-const string FGJSBBase::needed_cfg_version = "1.61";
+const string FGJSBBase::needed_cfg_version = "1.65";
const string FGJSBBase::JSBSim_version = "0.9.5";
std::queue <FGJSBBase::Message*> FGJSBBase::Messages;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FGJSBBase::FGJSBBase()
-{
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
FGJSBBase::Message* FGJSBBase::PutMessage(Message* msg)
{
Messages.push(msg);
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FGJSBBase::Message* FGJSBBase::PutMessage(string text)
+FGJSBBase::Message* FGJSBBase::PutMessage(const string& text)
{
Message *msg = new Message();
msg->text = text;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FGJSBBase::Message* FGJSBBase::PutMessage(string text, bool bVal)
+FGJSBBase::Message* FGJSBBase::PutMessage(const string& text, bool bVal)
{
Message *msg = new Message();
msg->text = text;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FGJSBBase::Message* FGJSBBase::PutMessage(string text, int iVal)
+FGJSBBase::Message* FGJSBBase::PutMessage(const string& text, int iVal)
{
Message *msg = new Message();
msg->text = text;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FGJSBBase::Message* FGJSBBase::PutMessage(string text, double dVal)
+FGJSBBase::Message* FGJSBBase::PutMessage(const string& text, double dVal)
{
Message *msg = new Message();
msg->text = text;
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+#include <limits>
+
#ifdef FGFS
# include <simgear/compiler.h>
# include <math.h>
using std::max;
#endif
-#ifdef __FreeBSD__ // define gcvt on FreeBSD
-
-#include <stdio.h>
-
-static char *gcvt(double number, size_t ndigit, char *buf)
-{
- sprintf(buf, "%f", number);
- return buf;
-}
-#endif
-
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGJSBBase {
public:
/// Constructor for FGJSBBase.
- FGJSBBase();
+ FGJSBBase() {};
/// Destructor for FGJSBBase.
- virtual ~FGJSBBase() {};
+ ~FGJSBBase() {};
/// JSBSim Message structure
typedef struct Msg {
double dVal;
} Message;
- ///@name JSBSim Enums.
- //@{
- /// Moments L, M, N
- enum {eL = 1, eM, eN };
- /// Rates P, Q, R
- enum {eP = 1, eQ, eR };
- /// Velocities U, V, W
- enum {eU = 1, eV, eW };
- /// Positions X, Y, Z
- enum {eX = 1, eY, eZ };
- /// Euler angles Phi, Theta, Psi
- enum {ePhi = 1, eTht, ePsi };
- /// Stability axis forces, Drag, Side force, Lift
- enum {eDrag = 1, eSide, eLift };
- /// Local frame orientation Roll, Pitch, Yaw
- enum {eRoll = 1, ePitch, eYaw };
- /// Local frame position North, East, Down
- enum {eNorth = 1, eEast, eDown };
- //@}
-
///@name JSBSim console output highlighting terms.
//@{
/// highlights text
/** Creates a message with the given text and places it on the queue.
@param text message text
@return pointer to a Message structure */
- Message* PutMessage(string text);
+ Message* PutMessage(const string& text);
/** Creates a message with the given text and boolean value and places it on the queue.
@param text message text
@param bVal boolean value associated with the message
@return pointer to a Message structure */
- Message* PutMessage(string text, bool bVal);
+ Message* PutMessage(const string& text, bool bVal);
/** Creates a message with the given text and integer value and places it on the queue.
@param text message text
@param iVal integer value associated with the message
@return pointer to a Message structure */
- Message* PutMessage(string text, int iVal);
+ Message* PutMessage(const string& text, int iVal);
/** Creates a message with the given text and double value and places it on the queue.
@param text message text
@param dVal double value associated with the message
@return pointer to a Message structure */
- Message* PutMessage(string text, double dVal);
+ Message* PutMessage(const string& text, double dVal);
/** Reads the message on the queue (but does not delete it).
@return pointer to a Message structure (or NULL if no mesage) */
Message* ReadMessage(void);
Message* ProcessMessage(void);
//@}
string GetVersion(void) {return JSBSim_version;}
-
+
void disableHighLighting(void);
static short debug_lvl;
- double KelvinToFahrenheit (double kelvin) {
+ static double KelvinToFahrenheit (double kelvin) {
return 1.8*kelvin - 459.4;
}
- double RankineToCelsius (double rankine) {
+ static double RankineToCelsius (double rankine) {
return (rankine - 491.67)/1.8;
}
+ static double FahrenheitToCelsius (double fahrenheit) {
+ return (fahrenheit - 32.0)/1.8;
+ }
+
+ static double CelsiusToFahrenheit (double celsius) {
+ return celsius * 1.8 + 32.0;
+ }
+
+
+ /** Finite precision comparison.
+ @param a first value to compare
+ @param b second value to compare
+ @return if the two values can be considered equal up to roundoff */
+ static bool EqualToRoundoff(double a, double b) {
+ double eps = 2.0*std::numeric_limits<double>::epsilon();
+ return fabs(a - b) <= eps*max(fabs(a), fabs(b));
+ }
+
+ /** Finite precision comparison.
+ @param a first value to compare
+ @param b second value to compare
+ @return if the two values can be considered equal up to roundoff */
+ static bool EqualToRoundoff(float a, float b) {
+ float eps = 2.0*std::numeric_limits<float>::epsilon();
+ return fabs(a - b) <= eps*max(fabs(a), fabs(b));
+ }
+
+ /** Finite precision comparison.
+ @param a first value to compare
+ @param b second value to compare
+ @return if the two values can be considered equal up to roundoff */
+ static bool EqualToRoundoff(float a, double b) {
+ return EqualToRoundoff(a, (float)b);
+ }
+
+ /** Finite precision comparison.
+ @param a first value to compare
+ @param b second value to compare
+ @return if the two values can be considered equal up to roundoff */
+ static bool EqualToRoundoff(double a, float b) {
+ return EqualToRoundoff((float)a, b);
+ }
+
protected:
static Message localMsg;
-
+
static std::queue <Message*> Messages;
- virtual void Debug(int from) {};
+ void Debug(int from) {};
static unsigned int frame;
static unsigned int messageId;
-
+
static const double radtodeg;
static const double degtorad;
static const double hptoftlbssec;
static const string needed_cfg_version;
static const string JSBSim_version;
};
+
+/// Moments L, M, N
+enum {eL = 1, eM, eN };
+/// Rates P, Q, R
+enum {eP = 1, eQ, eR };
+/// Velocities U, V, W
+enum {eU = 1, eV, eW };
+/// Positions X, Y, Z
+enum {eX = 1, eY, eZ };
+/// Euler angles Phi, Theta, Psi
+enum {ePhi = 1, eTht, ePsi };
+/// Stability axis forces, Drag, Side force, Lift
+enum {eDrag = 1, eSide, eLift };
+/// Local frame orientation Roll, Pitch, Yaw
+enum {eRoll = 1, ePitch, eYaw };
+/// Local frame position North, East, Down
+enum {eNorth = 1, eEast, eDown };
+/// Locations Radius, Latitude, Longitude
+enum {eLat = 1, eLong, eRad };
+/// Conversion specifiers
+enum {inNone = 0, inDegrees, inRadians, inMeters, inFeet };
+
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif
FGLGear::FGLGear(FGConfigFile* AC_cfg, FGFDMExec* fdmex) : Exec(fdmex)
{
string tmp;
-
+
*AC_cfg >> tmp >> name >> vXYZ(1) >> vXYZ(2) >> vXYZ(3)
>> kSpring >> bDamp>> dynamicFCoeff >> staticFCoeff
- >> rollingFCoeff >> sSteerType >> sBrakeGroup
+ >> rollingFCoeff >> sSteerType >> sBrakeGroup
>> maxSteerAngle >> sRetractable;
if (sBrakeGroup == "LEFT" ) eBrakeGrp = bgLeft;
cerr << "Improper steering type specification in config file: "
<< sSteerType << " is undefined." << endl;
}
-
+
if ( sRetractable == "RETRACT" ) {
isRetractable = true;
} else {
isRetractable = false;
- }
-
+ }
+
GearUp = false;
GearDown = true;
Servicable = true;
State = Exec->GetState();
Aircraft = Exec->GetAircraft();
- Position = Exec->GetPosition();
- Rotation = Exec->GetRotation();
+ Propagate = Exec->GetPropagate();
+ Auxiliary = Exec->GetAuxiliary();
FCS = Exec->GetFCS();
MassBalance = Exec->GetMassBalance();
SinkRate = GroundSpeed = 0.0;
vWhlBodyVec = MassBalance->StructuralToBody(vXYZ);
-
- vLocalGear = State->GetTb2l() * vWhlBodyVec;
+
+ vLocalGear = Propagate->GetTb2l() * vWhlBodyVec;
compressLength = 0.0;
compressSpeed = 0.0;
{
State = lgear.State;
Aircraft = lgear.Aircraft;
- Position = lgear.Position;
- Rotation = lgear.Rotation;
+ Propagate = lgear.Propagate;
+ Auxiliary = lgear.Auxiliary;
Exec = lgear.Exec;
FCS = lgear.FCS;
MassBalance = lgear.MassBalance;
FGColumnVector3& FGLGear::Force(void)
{
- double SteerGain = 0;
double SinWheel, CosWheel;
double deltaSlip;
double deltaT = State->Getdt()*Aircraft->GetRate();
} else {
GearUp = false;
GearDown = true;
- }
-
+ }
+
if (GearDown) {
vWhlBodyVec = MassBalance->StructuralToBody(vXYZ);
// vWhlBodyVec now stores the vector from the cg to this wheel
- vLocalGear = State->GetTb2l() * vWhlBodyVec;
+ vLocalGear = Propagate->GetTb2l() * vWhlBodyVec;
// vLocalGear now stores the vector from the cg to the wheel in local coords.
- compressLength = vLocalGear(eZ) - Position->GetDistanceAGL();
+ compressLength = vLocalGear(eZ) - Propagate->GetDistanceAGL();
// The compression length is currently measured in the Z-axis, only, at this time.
// It should be measured along the strut axis. If the local-frame gear position
// (used for calculating damping force) is found by taking the Z-component of the
// wheel velocity.
- vWhlVelVec = State->GetTb2l() * (Rotation->GetPQR() * vWhlBodyVec);
- vWhlVelVec += Position->GetVel();
+ vWhlVelVec = Propagate->GetTb2l() * (Propagate->GetPQR() * vWhlBodyVec);
+ vWhlVelVec += Propagate->GetVel();
compressSpeed = vWhlVelVec(eZ);
// If this is the first time the wheel has made contact, remember some values
if (!FirstContact) {
FirstContact = true;
SinkRate = compressSpeed;
- GroundSpeed = Position->GetVel().Magnitude();
+ GroundSpeed = Propagate->GetVel().Magnitude();
TakeoffReported = false;
}
// If the takeoff run is starting, initialize.
- if ((Position->GetVel().Magnitude() > 0.1) &&
+ if ((Propagate->GetVel().Magnitude() > 0.1) &&
(FCS->GetBrake(bgLeft) == 0) &&
(FCS->GetBrake(bgRight) == 0) &&
(FCS->GetThrottlePos(0) == 1) && !StartedGroundRun)
switch (eSteerType) {
case stSteer:
- SteerAngle = -maxSteerAngle * FCS->GetDrCmd() * 0.01745;
+ SteerAngle = -maxSteerAngle * FCS->GetDrCmd() * 0.01745;
break;
case stFixed:
SteerAngle = 0.0;
// For now, steering angle is assumed to happen in the Local Z axis,
// not the strut axis as it should be. Will fix this later.
- SinWheel = sin(Rotation->Getpsi() + SteerAngle);
- CosWheel = cos(Rotation->Getpsi() + SteerAngle);
+ SinWheel = sin(Propagate->Getpsi() + SteerAngle);
+ CosWheel = cos(Propagate->Getpsi() + SteerAngle);
RollingWhlVel = vWhlVelVec(eX)*CosWheel + vWhlVelVec(eY)*SinWheel;
SideWhlVel = vWhlVelVec(eY)*CosWheel - vWhlVelVec(eX)*SinWheel;
{
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.
+// of this that avoid the discrete jump (similar to Pacejka). Will fix this later.
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 +
+ FCoeff = (dynamicFCoeff*(fabs(WheelSlip) - 20.0)/20.0 +
staticFCoeff*(40.0 - fabs(WheelSlip))/20.0)*fabs(WheelSlip)/WheelSlip;
} else {
FCoeff = dynamicFCoeff*fabs(WheelSlip)/WheelSlip;
// Transform the forces back to the body frame and compute the moment.
- vForce = State->GetTl2b() * vLocalForce;
+ vForce = Propagate->GetTl2b() * vLocalForce;
vMoment = vWhlBodyVec * vForce;
} else { // Gear is NOT compressed
WOW = false;
- if (Position->GetDistanceAGL() > 200.0) {
+ if (Propagate->GetDistanceAGL() > 200.0) {
FirstContact = false;
StartedGroundRun = false;
LandingReported = false;
compressLength = 0.0; // reset compressLength to zero for data output validity
}
- if (FirstContact) LandingDistanceTraveled += Position->GetVground()*deltaT;
-
+ if (FirstContact) LandingDistanceTraveled += Auxiliary->GetVground()*deltaT;
+
if (StartedGroundRun) {
- TakeoffDistanceTraveled50ft += Position->GetVground()*deltaT;
- if (WOW) TakeoffDistanceTraveled += Position->GetVground()*deltaT;
+ TakeoffDistanceTraveled50ft += Auxiliary->GetVground()*deltaT;
+ if (WOW) TakeoffDistanceTraveled += Auxiliary->GetVground()*deltaT;
}
- if (ReportEnable && Position->GetVground() <= 0.05 && !LandingReported) {
+ if (ReportEnable && Auxiliary->GetVground() <= 0.05 && !LandingReported) {
if (debug_lvl > 0) Report(erLand);
}
if (ReportEnable && !TakeoffReported &&
- (vLocalGear(eZ) - Position->GetDistanceAGL()) < -50.0)
+ (vLocalGear(eZ) - Propagate->GetDistanceAGL()) < -50.0)
{
if (debug_lvl > 0) Report(erTakeoff);
}
PutMessage("Crash Detected: Simulation FREEZE.");
Exec->Freeze();
}
- }
- return vForce;
+ }
+ return vForce;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#include "FGJSBBase.h"
#include "FGFDMExec.h"
-#include <string>
#include "FGConfigFile.h"
#include "FGColumnVector3.h"
+#include <string>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
namespace JSBSim {
class FGAircraft;
-class FGPosition;
-class FGRotation;
+class FGPropagate;
class FGFCS;
class FGState;
class FGMassBalance;
+class FGAuxiliary;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DOCUMENTATION
@author Jon S. Berndt
@version $Id$
@see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
- NASA-Ames", NASA CR-2497, January 1975
+ NASA-Ames", NASA CR-2497, January 1975
@see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
- Wiley & Sons, 1979 ISBN 0-471-03032-5
+ Wiley & Sons, 1979 ISBN 0-471-03032-5
@see W. A. Ragsdale, "A Generic Landing Gear Dynamics Model for LASRS++",
AIAA-2000-4303
*/
inline double GetTirePressure(void) { return TirePressureNorm; }
/// Sets the new normalized tire pressure
inline void SetTirePressure(double p) { TirePressureNorm = p; }
-
+
/// Sets the brake value in percent (0 - 100)
inline void SetBrake(double bp) {brakePct = bp;}
inline bool GetReport(void) { return ReportEnable; }
inline double GetSteerAngle(void) { return SteerAngle;}
inline double GetstaticFCoeff(void) { return staticFCoeff;}
-
+
inline int GetBrakeGroup(void) { return (int)eBrakeGrp; }
inline int GetSteerType(void) { return (int)eSteerType; }
-
+
inline bool GetRetractable(void) { return isRetractable; }
inline bool GetGearUnitUp(void) { return GearUp; }
inline bool GetGearUnitDown(void) { return GearDown; }
inline double GetBodyYForce(void) { return vLocalForce(eY); }
inline double GetWheelSlipAngle(void) { return WheelSlip; }
double GetWheelVel(int axis) { return vWhlVelVec(axis);}
-
+
private:
FGColumnVector3 vXYZ;
FGColumnVector3 vMoment;
string sSteerType;
string sBrakeGroup;
string sRetractable;
-
+
BrakeGroup eBrakeGrp;
SteerType eSteerType;
double maxSteerAngle;
- FGFDMExec* Exec;
- FGState* State;
- FGAircraft* Aircraft;
- FGPosition* Position;
- FGRotation* Rotation;
- FGFCS* FCS;
+ FGFDMExec* Exec;
+ FGState* State;
+ FGAircraft* Aircraft;
+ FGPropagate* Propagate;
+ FGAuxiliary* Auxiliary;
+ FGFCS* FCS;
FGMassBalance* MassBalance;
void Report(ReportType rt);
};
}
#include "FGAircraft.h"
-#include "FGPosition.h"
-#include "FGRotation.h"
+#include "FGPropagate.h"
+#include "FGAuxiliary.h"
#include "FGFCS.h"
#include "FGMassBalance.h"
+#include "FGState.h"
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#include "FGState.h"
-
#endif
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGLocation.cpp
+ Author: Jon S. Berndt
+ Date started: 04/04/2004
+ Purpose: Store an arbitrary location on the globe
+
+ ------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------------
+ ------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
+
+ 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
+------------------------------------------------------------------------------
+This class encapsulates an arbitrary position in the globe with its accessors.
+It has vector properties, so you can add multiply ....
+
+HISTORY
+------------------------------------------------------------------------------
+04/04/2004 MF Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# ifdef SG_HAVE_STD_INCLUDES
+# include <cmath>
+# else
+# include <math.h>
+# endif
+#else
+# if defined(sgi) && !defined(__GNUC__)
+# include <math.h>
+# else
+# include <cmath>
+# endif
+#endif
+
+#include "FGLocation.h"
+#include "FGPropertyManager.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_LOCATION;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGLocation::FGLocation(double lon, double lat, double radius)
+{
+ mCacheValid = false;
+
+ double sinLat = sin(lat);
+ double cosLat = cos(lat);
+ double sinLon = sin(lon);
+ double cosLon = cos(lon);
+ mECLoc = FGColumnVector3( radius*cosLat*cosLon,
+ radius*cosLat*sinLon,
+ radius*sinLat );
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGLocation::SetLongitude(double longitude)
+{
+ double rtmp = sqrt(mECLoc(eX)*mECLoc(eX) + mECLoc(eY)*mECLoc(eY));
+ // Fast return if we are on the north or south pole ...
+ if (rtmp == 0.0)
+ return;
+
+ mCacheValid = false;
+
+ mECLoc(eX) = rtmp*sin(longitude);
+ mECLoc(eY) = rtmp*cos(longitude);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGLocation::SetLatitude(double latitude)
+{
+ mCacheValid = false;
+
+ double r = mECLoc.Magnitude();
+ if (r == 0.0) {
+ mECLoc(eX) = 1.0;
+ r = 1.0;
+ }
+
+ double rtmp = sqrt(mECLoc(eX)*mECLoc(eX) + mECLoc(eY)*mECLoc(eY));
+ if (rtmp != 0.0) {
+ double fac = r/rtmp*cos(latitude);
+ mECLoc(eX) *= fac;
+ mECLoc(eY) *= fac;
+ } else {
+ mECLoc(eX) = r*cos(latitude);
+ mECLoc(eY) = 0.0;
+ }
+ mECLoc(eZ) = r*sin(latitude);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGLocation::SetRadius(double radius)
+{
+ mCacheValid = false;
+
+ double rold = mECLoc.Magnitude();
+ if (rold == 0.0)
+ mECLoc(eX) = radius;
+ else
+ mECLoc *= radius/rold;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGLocation::ComputeDerivedUnconditional(void) const
+{
+ // The radius is just the Euclidean norm of the vector.
+ mRadius = mECLoc.Magnitude();
+
+ // The distance of the location to the y-axis, which is the axis
+ // through the poles.
+ double rxy = sqrt(mECLoc(eX)*mECLoc(eX) + mECLoc(eY)*mECLoc(eY));
+
+ // Compute the sin/cos values of the longitude
+ double sinLon, cosLon;
+ if (rxy == 0.0) {
+ sinLon = 0.0;
+ cosLon = 1.0;
+ } else {
+ sinLon = mECLoc(eY)/rxy;
+ cosLon = mECLoc(eX)/rxy;
+ }
+
+ // Compute the sin/cos values of the latitude
+ double sinLat, cosLat;
+ if (mRadius == 0.0) {
+ sinLat = 0.0;
+ cosLat = 1.0;
+ } else {
+ sinLat = mECLoc(eZ)/mRadius;
+ cosLat = rxy/mRadius;
+ }
+
+ // Compute the longitude and latitude itself
+ if ( mECLoc( eX ) == 0.0 && mECLoc( eY ) == 0.0 )
+ mLon = 0.0;
+ else
+ mLon = atan2( mECLoc( eY ), mECLoc( eX ) );
+
+ if ( rxy == 0.0 && mECLoc( eZ ) == 0.0 )
+ mLat = 0.0;
+ else
+ mLat = atan2( mECLoc(eZ), rxy );
+
+ // Compute the transform matrices from and to the earth centered frame.
+ // see Durham Chapter 4, problem 1, page 52
+ mTec2l = FGMatrix33( -cosLon*sinLat, -sinLon*sinLat, cosLat,
+ -sinLon , cosLon , 0.0 ,
+ -cosLon*cosLat, -sinLon*cosLat, -sinLat );
+
+ mTl2ec = mTec2l.Transposed();
+
+ // Mark the cached values as valid
+ mCacheValid = true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGLocation::bind(FGPropertyManager* PropertyManager, const string& prefix) const
+{
+ PropertyManager->Tie(prefix + "lat-gc-rad", (FGLocation*)this,
+ &FGLocation::GetLatitude);
+ PropertyManager->Tie(prefix + "lat-gc-deg", (FGLocation*)this,
+ &FGLocation::GetLatitudeDeg);
+ PropertyManager->Tie(prefix + "long-gc-rad", (FGLocation*)this,
+ &FGLocation::GetLongitude);
+ PropertyManager->Tie(prefix + "long-gc-deg", (FGLocation*)this,
+ &FGLocation::GetLongitudeDeg);
+ PropertyManager->Tie(prefix + "radius-ft", (FGLocation*)this,
+ &FGLocation::GetRadius);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGLocation::unbind(FGPropertyManager* PropertyManager, const string& prefix) const
+{
+ PropertyManager->Untie(prefix + "lat-gc-rad");
+ PropertyManager->Untie(prefix + "lat-gc-deg");
+ PropertyManager->Untie(prefix + "long-gc-rad");
+ PropertyManager->Untie(prefix + "long-gc-deg");
+ PropertyManager->Untie(prefix + "radius-ft");
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+} // namespace JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGLocation.h
+ Author: Jon S. Berndt, Mathias Froehlich
+ Date started: 04/04/2004
+
+ ------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------------
+ ------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
+
+ 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
+-------------------------------------------------------------------------------
+04/04/2004 MF Created from code previously in the old positions class.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGLOCATION_H
+#define FGLOCATION_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGJSBBase.h"
+#include "FGPropertyManager.h"
+#include "FGColumnVector3.h"
+#include "FGMatrix33.h"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_LOCATION "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Holds an arbitrary location in the earth centered reference frame.
+ This coordinate frame has its center in the middle of the earth.
+ Its x-axis points from the center of the earth towards a location
+ with zero latitude and longitude on the earths surface. The y-axis
+ points from the center of the earth towards a location with zero
+ latitude and 90deg longitude on the earths surface. The z-axis
+ points from the earths center to the geographic north pole.
+
+ This class provides access functions to set and get the location as
+ either the simple x, y and z values in ft or longitude/latitude and
+ the radial distance of the location from the earth center.
+
+ It is common to associate a parent frame with a location. This
+ frame is usually called the local horizontal frame or simply the local
+ frame. This frame has its x/y plane parallel to the surface of the earth
+ (with the assumption of a spherical earth). The x-axis points
+ towards north, the y-axis points towards east and the z-axis
+ points to the center of the earth.
+
+ Since this frame is determined by the location, this class also
+ provides the rotation matrices required to transform from the
+ earth centered frame to the local horizontal frame and back. There
+ are also conversion functions for conversion of position vectors
+ given in the one frame to positions in the other frame.
+
+ The earth centered reference frame is *NOT* an inertial frame
+ since it rotates with the earth.
+
+ The coordinates in the earth centered frame are the master values.
+ All other values are computed from these master values and are
+ cached as long as the location is changed by access through a
+ non-const member function. Values are cached to improve performance.
+ It is best practice to work with a natural set of master values.
+ Other parameters that are derived from these master values are calculated
+ only when needed, and IF they are needed and calculated, then they are
+ cached (stored and remembered) so they do not need to be re-calculated
+ until the master values they are derived from are themselves changed
+ (and become stale).
+
+ Accuracy and round off:
+
+ Given that we model a vehicle near the earth, the earths surface
+ radius is about 2*10^7, ft and that we use double values for the
+ representation of the location, we have an accuracy of about
+ 1e-16*2e7ft/1=2e-9ft left. This should be sufficient for our needs.
+ Note that this is the same relative accuracy we would have when we
+ compute directly with lon/lat/radius. For the radius value this
+ is clear. For the lon/lat pair this is easy to see. Take for
+ example KSFO located at about 37.61deg north 122.35deg west, which
+ corresponds to 0.65642rad north and 2.13541rad west. Both values
+ are of magnitude of about 1. But 1ft corresponds to about
+ 1/(2e7*2*pi)=7.9577e-09rad. So the left accuracy with this
+ representation is also about 1*1e-16/7.9577e-09=1.2566e-08 which
+ is of the same magnitude as the representation chosen here.
+
+ The advantage of this representation is that it is a linear space
+ without singularities. The singularities are the north and south
+ pole and most notably the non-steady jump at -pi to pi. It is
+ harder to track this jump correctly especially when we need to
+ work with error norms and derivatives of the equations of motion
+ within the time-stepping code. Also, the rate of change is of the
+ same magnitude for all components in this representation which is
+ an advantage for numerical stability in implicit time-stepping too.
+
+ @see W. C. Durham "Aircraft Dynamics & Control", section 2.2
+
+ @author Mathias Froehlich
+ @version $Id$
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGLocation : virtual FGJSBBase
+{
+public:
+ /** Default constructor. */
+ FGLocation() { mCacheValid = false; }
+
+ /** Constructor to set the longitude, latitude and the distance
+ from the center of the earth. */
+ FGLocation(double lon, double lat, double radius);
+
+ /** Copy constructor. */
+ FGLocation(const FGColumnVector3& lv)
+ : mECLoc(lv), mCacheValid(false) {}
+
+ /** Copy constructor. */
+ FGLocation(const FGLocation& l)
+ : mECLoc(l.mECLoc), mCacheValid(l.mCacheValid) {
+ if (!mCacheValid)
+ return;
+
+ mLon = l.mLon;
+ mLat = l.mLat;
+ mRadius = l.mRadius;
+
+ mTl2ec = l.mTl2ec;
+ mTec2l = l.mTec2l;
+ }
+
+ /** Get the longitude.
+ @return the longitude in rad of the location represented with this
+ class instance. The returned values are in the range between
+ -pi <= lon <= pi. Longitude is positive east and negative west. */
+ double GetLongitude() const { ComputeDerived(); return mLon; }
+
+ /** Get the longitude.
+ @return the longitude in deg of the location represented with this
+ class instance. The returned values are in the range between
+ -180 <= lon <= 180. Longitude is positive east and negative west. */
+ double GetLongitudeDeg() const { ComputeDerived(); return radtodeg*mLon; }
+
+ /** Set the longitude.
+ @param longitude Longitude in rad to set.
+ Sets the longitude of the location represented with this class
+ instance to the value of the given argument. The value is meant
+ to be in rad. The latitude and the radius value are preserved
+ with this call with the exception of radius being equal to
+ zero. If the radius is previously set to zero it is changed to be
+ equal to 1.0 past this call. Longitude is positive east and negative west. */
+ void SetLongitude(double longitude);
+
+ /** Get the sine of Longitude. */
+ double GetSinLongitude() const { ComputeDerived(); return -mTec2l(2,1); }
+
+ /** Get the cosine of Longitude. */
+ double GetCosLongitude() const { ComputeDerived(); return mTec2l(2,2); }
+
+ /** Get the latitude.
+ @return the latitude in rad of the location represented with this
+ class instance. The returned values are in the range between
+ -pi/2 <= lon <= pi/2. Latitude is positive north and negative south. */
+ double GetLatitude() const { ComputeDerived(); return mLat; }
+
+ /** Get the latitude.
+ @return the latitude in deg of the location represented with this
+ class instance. The returned values are in the range between
+ -90 <= lon <= 90. Latitude is positive north and negative south. */
+ double GetLatitudeDeg() const { ComputeDerived(); return radtodeg*mLat; }
+
+ /** Set the latitude.
+ @param latitude Latitude in rad to set.
+ Sets the latitude of the location represented with this class
+ instance to the value of the given argument. The value is meant
+ to be in rad. The longitude and the radius value are preserved
+ with this call with the exception of radius being equal to
+ zero. If the radius is previously set to zero it is changed to be
+ equal to 1.0 past this call.
+ Latitude is positive north and negative south.
+ The arguments should be within the bounds of -pi/2 <= lat <= pi/2.
+ The behavior of this function with arguments outside this range is
+ left as an exercise to the gentle reader ... */
+ void SetLatitude(double latitude);
+
+ /** Get the sine of Latitude. */
+ double GetSinLatitude() const { ComputeDerived(); return -mTec2l(3,3); }
+
+ /** Get the cosine of Latitude. */
+ double GetCosLatitude() const { ComputeDerived(); return mTec2l(1,3); }
+
+ /** Get the cosine of Latitude. */
+ double GetTanLatitude() const {
+ ComputeDerived();
+ double cLat = mTec2l(1,3);
+ if (cLat == 0.0)
+ return 0.0;
+ else
+ return -mTec2l(3,3)/cLat;
+ }
+
+ /** Get the distance from the center of the earth.
+ @return the distance of the location represented with this class
+ instance to the center of the earth in ft. The radius value is
+ always positive. */
+ double GetRadius() const { ComputeDerived(); return mRadius; }
+
+ /** Set the distance from the center of the earth.
+ @param radius Radius in ft to set.
+ Sets the radius of the location represented with this class
+ instance to the value of the given argument. The value is meant
+ to be in ft. The latitude and longitude values are preserved
+ with this call with the exception of radius being equal to
+ zero. If the radius is previously set to zero, latitude and
+ longitude is set equal to zero past this call.
+ The argument should be positive.
+ The behavior of this function called with a negative argument is
+ left as an exercise to the gentle reader ... */
+ void SetRadius(double radius);
+
+ /** Transform matrix from local horizontal to earth centered frame.
+ Returns a const reference to the rotation matrix of the transform from
+ the local horizontal frame to the earth centered frame. */
+ const FGMatrix33& GetTl2ec(void) const { ComputeDerived(); return mTl2ec; }
+
+ /** Transform matrix from the earth centered to local horizontal frame.
+ Returns a const reference to the rotation matrix of the transform from
+ the earth centered frame to the local horizontal frame. */
+ const FGMatrix33& GetTec2l(void) const { ComputeDerived(); return mTec2l; }
+
+ /** Conversion from Local frame coordinates to a location in the
+ earth centered and fixed frame.
+ @parm lvec Vector in the local horizontal coordinate frame
+ @return The location in the earth centered and fixed frame */
+ FGLocation LocalToLocation(const FGColumnVector3& lvec) const {
+ ComputeDerived(); return mTl2ec*lvec + mECLoc;
+ }
+
+ /** Conversion from a location in the earth centered and fixed frame
+ to local horizontal frame coordinates.
+ @parm ecvec Vector in the earth centered and fixed frame
+ @return The vector in the local horizontal coordinate frame */
+ FGColumnVector3 LocationToLocal(const FGColumnVector3& ecvec) const {
+ ComputeDerived(); return mTec2l*(ecvec - mECLoc);
+ }
+
+ // For time-stepping, locations have vector properties...
+
+ /** Read access the entries of the vector.
+ @param idx the component index.
+ Return the value of the matrix entry at the given index.
+ Indices are counted starting with 1.
+ Note that the index given in the argument is unchecked. */
+ double operator()(unsigned int idx) const { return Entry(idx); }
+
+ /** Write access the entries of the vector.
+ @param idx the component index.
+ @return a reference to the vector entry at the given index.
+ Indices are counted starting with 1.
+ Note that the index given in the argument is unchecked. */
+ double& operator()(unsigned int idx) { return Entry(idx); }
+
+ /** Read access the entries of the vector.
+ @param idx the component index.
+ @return the value of the matrix entry at the given index.
+ Indices are counted starting with 1.
+ This function is just a shortcut for the @ref double
+ operator()(unsigned int idx) const function. It is
+ used internally to access the elements in a more convenient way.
+ Note that the index given in the argument is unchecked. */
+ double Entry(unsigned int idx) const { return mECLoc.Entry(idx); }
+
+ /** Write access the entries of the vector.
+ @param idx the component index.
+ @return a reference to the vector entry at the given index.
+ Indices are counted starting with 1.
+ This function is just a shortcut for the double&
+ operator()(unsigned int idx) function. It is
+ used internally to access the elements in a more convenient way.
+ Note that the index given in the argument is unchecked. */
+ double& Entry(unsigned int idx) {
+ mCacheValid = false; return mECLoc.Entry(idx);
+ }
+
+ const FGLocation& operator=(const FGLocation& l) {
+ mECLoc = l.mECLoc;
+ mCacheValid = l.mCacheValid;
+ if (!mCacheValid)
+ return *this;
+
+ mLon = l.mLon;
+ mLat = l.mLat;
+ mRadius = l.mRadius;
+
+ mTl2ec = l.mTl2ec;
+ mTec2l = l.mTec2l;
+
+ return *this;
+ }
+ bool operator==(const FGLocation& l) const {
+ return mECLoc == l.mECLoc;
+ }
+ bool operator!=(const FGLocation& l) const { return ! operator==(l); }
+ const FGLocation& operator+=(const FGLocation &l) {
+ mCacheValid = false;
+ mECLoc += l.mECLoc;
+ return *this;
+ }
+ const FGLocation& operator-=(const FGLocation &l) {
+ mCacheValid = false;
+ mECLoc -= l.mECLoc;
+ return *this;
+ }
+ const FGLocation& operator*=(double scalar) {
+ mCacheValid = false;
+ mECLoc *= scalar;
+ return *this;
+ }
+ const FGLocation& operator/=(double scalar) {
+ return operator*=(1.0/scalar);
+ }
+ FGLocation operator+(const FGLocation& l) const {
+ return FGLocation(mECLoc + l.mECLoc);
+ }
+ FGLocation operator-(const FGLocation& l) const {
+ return FGLocation(mECLoc - l.mECLoc);
+ }
+
+ FGLocation operator*(double scalar) const {
+ return FGLocation(scalar*mECLoc);
+ }
+
+ /** Cast to a simple 3d vector */
+ operator const FGColumnVector3&() const {
+ return mECLoc;
+ }
+
+ /** Ties into the property tree.
+ Ties the variables represented by this class into the property tree. */
+ void bind(FGPropertyManager*, const string&) const;
+
+ /** Remove from property tree.
+ Unties the variables represented by this class into the property tree. */
+ void unbind(FGPropertyManager*, const string&) const;
+
+private:
+ /** Computation of derived values.
+ This function re-computes the derived values like lat/lon and
+ transformation matrices. It does this unconditionally. */
+ void ComputeDerivedUnconditional(void) const;
+
+ /** Computation of derived values.
+ This function checks if the derived values like lat/lon and
+ transformation matrices are already computed. If so, it
+ returns. If they need to be computed this is done here. */
+ void ComputeDerived(void) const {
+ if (!mCacheValid)
+ ComputeDerivedUnconditional();
+ }
+
+ /** The coordinates in the earth centered frame. This is the master copy.
+ The coordinate frame has its center in the middle of the earth.
+ Its x-axis points from the center of the earth towards a
+ location with zero latitude and longitude on the earths
+ surface. The y-axis points from the center of the earth towards a
+ location with zero latitude and 90deg longitude on the earths
+ surface. The z-axis points from the earths center to the
+ geographic north pole.
+ @see W. C. Durham "Aircraft Dynamics & Control", section 2.2 */
+ FGColumnVector3 mECLoc;
+
+ /** The cached lon/lat/radius values. */
+ mutable double mLon;
+ mutable double mLat;
+ mutable double mRadius;
+
+ /** The cached rotation matrices from and to the associated frames. */
+ mutable FGMatrix33 mTl2ec;
+ mutable FGMatrix33 mTec2l;
+
+ /** A data validity flag.
+ This class implements caching of the derived values like the
+ orthogonal rotation matrices or the lon/lat/radius values. For caching we
+ carry a flag which signals if the values are valid or not.
+ The C++ keyword "mutable" tells the compiler that the data member is
+ allowed to change during a const member function. */
+ mutable bool mCacheValid;
+};
+
+/** Scalar multiplication.
+
+ @param scalar scalar value to multiply with.
+ @param l Vector to multiply.
+
+ Multiply the Vector with a scalar value. */
+inline FGLocation operator*(double scalar, const FGLocation& l)
+{
+ return l.operator*(scalar);
+}
+
+} // namespace JSBSim
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------
-This base class for the FGAero, FGRotational, etc. classes defines methods
+This base class for the FGAerodynamics, FGPropagate, etc. classes defines methods
common to all models.
HISTORY
#include "FGInertial.h"
#include "FGGroundReactions.h"
#include "FGAircraft.h"
-#include "FGTranslation.h"
-#include "FGRotation.h"
-#include "FGPosition.h"
+#include "FGPropagate.h"
#include "FGAuxiliary.h"
#include "FGOutput.h"
Inertial = 0;
GroundReactions = 0;
Aircraft = 0;
- Translation = 0;
- Rotation = 0;
- Position = 0;
+ Propagate = 0;
Auxiliary = 0;
Output = 0;
-
+
//in order for FGModel derived classes to self-bind (that is, call
//their bind function in the constructor, the PropertyManager pointer
//must be brought up now.
PropertyManager = FDMExec->GetPropertyManager();
-
+
exe_ctr = 1;
rate = 1;
Inertial = FDMExec->GetInertial();
GroundReactions = FDMExec->GetGroundReactions();
Aircraft = FDMExec->GetAircraft();
- Translation = FDMExec->GetTranslation();
- Rotation = FDMExec->GetRotation();
- Position = FDMExec->GetPosition();
+ Propagate = FDMExec->GetPropagate();
Auxiliary = FDMExec->GetAuxiliary();
Output = FDMExec->GetOutput();
-
+
if (!State ||
!Atmosphere ||
!FCS ||
!Inertial ||
!GroundReactions ||
!Aircraft ||
- !Translation ||
- !Rotation ||
- !Position ||
+ !Propagate ||
!Auxiliary ||
!Output) return(false);
else return(true);
class FGInertial;
class FGGroundReactions;
class FGAircraft;
-class FGTranslation;
-class FGRotation;
-class FGPosition;
+class FGPropagate;
class FGAuxiliary;
class FGOutput;
class FGConfigFile;
@param Config a pointer to the config file instance
@return true if model is successfully loaded*/
virtual bool Load(FGConfigFile* Config) {return true;}
-
+
FGModel* NextModel;
string Name;
virtual bool InitModel(void);
virtual void SetRate(int tt) {rate = tt;}
virtual int GetRate(void) {return rate;}
-
+
void SetPropertyManager(FGPropertyManager *fgpm) { PropertyManager=fgpm;}
protected:
int exe_ctr;
int rate;
-
+
virtual void Debug(int from);
FGFDMExec* FDMExec;
FGInertial* Inertial;
FGGroundReactions* GroundReactions;
FGAircraft* Aircraft;
- FGTranslation* Translation;
- FGRotation* Rotation;
- FGPosition* Position;
+ FGPropagate* Propagate;
FGAuxiliary* Auxiliary;
FGOutput* Output;
FGPropertyManager* PropertyManager;
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#ifdef FGFS
-# include <simgear/compiler.h>
-# include STL_ALGORITHM
-#else
-# include <algorithm>
-#endif
+#include <sstream>
#include "FGNozzle.h"
#include "FGAtmosphere.h"
return PE;
}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGNozzle::GetThrusterLabels(int id)
+{
+ std::ostringstream buf;
+
+ buf << Name << "_Thrust[" << id << ']';
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGNozzle::GetThrusterValues(int id)
+{
+ std::ostringstream buf;
+
+ buf << Thrust;
+
+ return buf.str();
+}
+
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
double Calculate(double CfPc);
double GetPowerRequired(void);
-
+ string GetThrusterLabels(int id);
+ string GetThrusterValues(int id);
+
private:
double ReverserAngle;
double PE;
#include "FGGroundReactions.h"
#include "FGAircraft.h"
#include "FGMassBalance.h"
-#include "FGTranslation.h"
-#include "FGRotation.h"
-#include "FGPosition.h"
+#include "FGPropagate.h"
#include "FGAuxiliary.h"
#include "FGInertial.h"
+#include <iomanip>
+
namespace JSBSim {
static const char *IdSrc = "$Id$";
bool FGOutput::Run(void)
{
if (enabled) {
- if (!FGModel::Run()) {
-
- if (Type == otSocket) {
- SocketOutput();
- } else if (Type == otCSV) {
- DelimitedOutput(Filename);
- } else if (Type == otTerminal) {
- // Not done yet
- } else if (Type == otNone) {
- // Do nothing
- } else {
- // Not a valid type of output
- }
- return false;
+ if (FGModel::Run()) return true;
+ if (Type == otSocket) {
+ SocketOutput();
+ } else if (Type == otCSV) {
+ DelimitedOutput(Filename);
+ } else if (Type == otTerminal) {
+ // Not done yet
+ } else if (Type == otNone) {
+ // Do nothing
} else {
- return true;
+ // Not a valid type of output
}
}
return false;
outstream << ", ";
outstream << "Drag, Side, Lift, ";
outstream << "L/D, ";
- outstream << "Xforce, Yforce, Zforce, ";
- outstream << "xGravity, yGravity, zGravity, ";
- outstream << "xCoriolis, yCoriolis, zCoriolis, ";
- outstream << "xCentrifugal, yCentrifugal, zCentrifugal";
+ outstream << "Xforce, Yforce, Zforce";
}
if (SubSystems & ssMoments) {
outstream << ", ";
outstream << "Mass, ";
outstream << "Xcg, Ycg, Zcg";
}
- if (SubSystems & ssPosition) {
+ if (SubSystems & ssPropagate) {
outstream << ", ";
outstream << "Altitude, ";
outstream << "Phi, Tht, Psi, ";
outstream << "Alpha, ";
outstream << "Beta, ";
- outstream << "Latitude, ";
- outstream << "Longitude, ";
+ outstream << "Latitude (Deg), ";
+ outstream << "Longitude (Deg), ";
outstream << "Distance AGL, ";
outstream << "Runway Radius";
}
}
if (SubSystems & ssRates) {
outstream << ", ";
- outstream << Rotation->GetPQR() << ", ";
- outstream << Rotation->GetPQRdot();
+ outstream << Propagate->GetPQR() << ", ";
+ outstream << Propagate->GetPQRdot();
}
if (SubSystems & ssVelocities) {
outstream << ", ";
- outstream << Translation->Getqbar() << ", ";
- outstream << Translation->GetVt() << ", ";
- outstream << Translation->GetUVW() << ", ";
- outstream << Translation->GetAeroUVW() << ", ";
- outstream << Position->GetVel();
+ outstream << Auxiliary->Getqbar() << ", ";
+ outstream << setprecision(12) << Auxiliary->GetVt() << ", ";
+ outstream << setprecision(12) << Propagate->GetUVW() << ", ";
+ outstream << Auxiliary->GetAeroUVW() << ", ";
+ outstream << Propagate->GetVel();
}
if (SubSystems & ssForces) {
outstream << ", ";
outstream << Aerodynamics->GetvFs() << ", ";
outstream << Aerodynamics->GetLoD() << ", ";
- outstream << Aircraft->GetForces() << ", ";
- outstream << Inertial->GetGravity() << ", ";
- outstream << Inertial->GetCoriolis() << ", ";
- outstream << Inertial->GetCentrifugal();
+ outstream << Aircraft->GetForces();
}
if (SubSystems & ssMoments) {
outstream << ", ";
outstream << MassBalance->GetMass() << ", ";
outstream << MassBalance->GetXYZcg();
}
- if (SubSystems & ssPosition) {
+ if (SubSystems & ssPropagate) {
outstream << ", ";
- outstream << Position->Geth() << ", ";
- outstream << Rotation->GetEuler() << ", ";
- outstream << Translation->Getalpha() << ", ";
- outstream << Translation->Getbeta() << ", ";
- outstream << Position->GetLatitude() << ", ";
- outstream << Position->GetLongitude() << ", ";
- outstream << Position->GetDistanceAGL() << ", ";
- outstream << Position->GetRunwayRadius();
+ outstream << Propagate->Geth() << ", ";
+ outstream << Propagate->GetEuler() << ", ";
+ outstream << Auxiliary->Getalpha(inDegrees) << ", ";
+ outstream << Auxiliary->Getbeta(inDegrees) << ", ";
+ outstream << Propagate->GetLocation().GetLatitudeDeg() << ", ";
+ outstream << Propagate->GetLocation().GetLongitudeDeg() << ", ";
+ outstream << Propagate->GetDistanceAGL() << ", ";
+ outstream << Propagate->GetRunwayRadius();
}
if (SubSystems & ssCoefficients) {
scratch = Aerodynamics->GetCoefficientValues();
socket->Append("Fx");
socket->Append("Fy");
socket->Append("Fz");
- socket->Append("Latitude");
- socket->Append("Longitude");
+ socket->Append("Latitude (Deg)");
+ socket->Append("Longitude (Deg)");
socket->Append("QBar");
socket->Append("Alpha");
socket->Append("L");
socket->Clear();
socket->Append(State->Getsim_time());
- socket->Append(Position->Geth());
- socket->Append(Rotation->Getphi());
- socket->Append(Rotation->Gettht());
- socket->Append(Rotation->Getpsi());
+ socket->Append(Propagate->Geth());
+ socket->Append(Propagate->Getphi());
+ socket->Append(Propagate->Gettht());
+ socket->Append(Propagate->Getpsi());
socket->Append(Atmosphere->GetDensity());
- socket->Append(Translation->GetVt());
- socket->Append(Translation->GetUVW(eU));
- socket->Append(Translation->GetUVW(eV));
- socket->Append(Translation->GetUVW(eW));
- socket->Append(Translation->GetAeroUVW(eU));
- socket->Append(Translation->GetAeroUVW(eV));
- socket->Append(Translation->GetAeroUVW(eW));
- socket->Append(Position->GetVn());
- socket->Append(Position->GetVe());
- socket->Append(Position->GetVd());
- socket->Append(Translation->GetUVWdot(eU));
- socket->Append(Translation->GetUVWdot(eV));
- socket->Append(Translation->GetUVWdot(eW));
- socket->Append(Rotation->GetPQR(eP));
- socket->Append(Rotation->GetPQR(eQ));
- socket->Append(Rotation->GetPQR(eR));
- socket->Append(Rotation->GetPQRdot(eP));
- socket->Append(Rotation->GetPQRdot(eQ));
- socket->Append(Rotation->GetPQRdot(eR));
+ socket->Append(Auxiliary->GetVt());
+ socket->Append(Propagate->GetUVW(eU));
+ socket->Append(Propagate->GetUVW(eV));
+ socket->Append(Propagate->GetUVW(eW));
+ socket->Append(Auxiliary->GetAeroUVW(eU));
+ socket->Append(Auxiliary->GetAeroUVW(eV));
+ socket->Append(Auxiliary->GetAeroUVW(eW));
+ socket->Append(Propagate->GetVel(eNorth));
+ socket->Append(Propagate->GetVel(eEast));
+ socket->Append(Propagate->GetVel(eDown));
+ socket->Append(Propagate->GetUVWdot(eU));
+ socket->Append(Propagate->GetUVWdot(eV));
+ socket->Append(Propagate->GetUVWdot(eW));
+ socket->Append(Propagate->GetPQR(eP));
+ socket->Append(Propagate->GetPQR(eQ));
+ socket->Append(Propagate->GetPQR(eR));
+ socket->Append(Propagate->GetPQRdot(eP));
+ socket->Append(Propagate->GetPQRdot(eQ));
+ socket->Append(Propagate->GetPQRdot(eR));
socket->Append(Aircraft->GetForces(eX));
socket->Append(Aircraft->GetForces(eY));
socket->Append(Aircraft->GetForces(eZ));
- socket->Append(Position->GetLatitude());
- socket->Append(Position->GetLongitude());
- socket->Append(Translation->Getqbar());
- socket->Append(Translation->Getalpha());
+ socket->Append(Propagate->GetLocation().GetLatitudeDeg());
+ socket->Append(Propagate->GetLocation().GetLongitudeDeg());
+ socket->Append(Auxiliary->Getqbar());
+ socket->Append(Auxiliary->Getalpha(inDegrees));
socket->Append(Aircraft->GetMoments(eL));
socket->Append(Aircraft->GetMoments(eM));
socket->Append(Aircraft->GetMoments(eN));
int OutRate = 0;
FGConfigFile* Output_cfg;
string property;
+ unsigned int port;
# ifndef macintosh
separator = "/";
name = AC_cfg->GetValue("NAME");
fname = AC_cfg->GetValue("FILE");
token = AC_cfg->GetValue("TYPE");
+ port = atoi(AC_cfg->GetValue("PORT").c_str());
+
Output->SetType(token);
-#if defined( FG_WITH_JSBSIM_SOCKET ) || !defined( FGFS )
if (token == "SOCKET") {
- socket = new FGfdmSocket("localhost",1138);
+ socket = new FGfdmSocket(name,port);
}
-#endif
if (!fname.empty()) {
outputInFileName = FDMExec->GetAircraftPath() + separator
}
if (parameter == "POSITION") {
*Output_cfg >> parameter;
- if (parameter == "ON") SubSystems += ssPosition;
+ if (parameter == "ON") SubSystems += ssPropagate;
}
if (parameter == "COEFFICIENTS") {
*Output_cfg >> parameter;
if (SubSystems & ssAtmosphere) cout << " Atmosphere parameters logged" << endl;
if (SubSystems & ssMassProps) cout << " Mass parameters logged" << endl;
if (SubSystems & ssCoefficients) cout << " Coefficient parameters logged" << endl;
- if (SubSystems & ssPosition) cout << " Position parameters logged" << endl;
+ if (SubSystems & ssPropagate) cout << " Propagate parameters logged" << endl;
if (SubSystems & ssGroundReactions) cout << " Ground parameters logged" << endl;
if (SubSystems & ssFCS) cout << " FCS parameters logged" << endl;
if (SubSystems & ssPropulsion) cout << " Propulsion parameters logged" << endl;
+ if (OutputProperties.size() > 0) cout << " Properties logged:" << endl;
+ for (unsigned int i=0;i<OutputProperties.size();i++) {
+ cout << " - " << OutputProperties[i]->GetName() << endl;
+ }
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Handles simulation output.
- */
+ OUTPUT section definition
+
+ The following specifies the way that JSBSim writes out data.
+
+ NAME is the filename you want the output to go to
+
+ TYPE can be:
+ CSV Comma separated data. If a filename is supplied then the data
+ goes to that file. If COUT or cout is specified, the data goes
+ to stdout. If the filename is a null filename the data goes to
+ stdout, as well.
+ SOCKET Will eventually send data to a socket output, where NAME
+ would then be the IP address of the machine the data should be
+ sent to. DON'T USE THIS YET!
+ TABULAR Columnar data. NOT IMPLEMENTED YET!
+ TERMINAL Output to terminal. NOT IMPLEMENTED YET!
+ NONE Specifies to do nothing. THis setting makes it easy to turn on and
+ off the data output without having to mess with anything else.
+
+ The arguments that can be supplied, currently, are
+
+ RATE_IN_HZ An integer rate in times-per-second that the data is output. This
+ value may not be *exactly* what you want, due to the dependence
+ on dt, the cycle rate for the FDM.
+
+ The following parameters tell which subsystems of data to output:
+
+ SIMULATION ON|OFF
+ ATMOSPHERE ON|OFF
+ MASSPROPS ON|OFF
+ AEROSURFACES ON|OFF
+ RATES ON|OFF
+ VELOCITIES ON|OFF
+ FORCES ON|OFF
+ MOMENTS ON|OFF
+ POSITION ON|OFF
+ COEFFICIENTS ON|OFF
+ GROUND_REACTIONS ON|OFF
+ FCS ON|OFF
+ PROPULSION ON|OFF
+
+ NOTE that Time is always output with the data.
+ @version $Id$
+ */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DECLARATION
/** Subsystem: Atmosphere (= 64) */ ssAtmosphere = 64,
/** Subsystem: Mass Properties (= 128) */ ssMassProps = 128,
/** Subsystem: Coefficients (= 256) */ ssCoefficients = 256,
- /** Subsystem: Position (= 512) */ ssPosition = 512,
+ /** Subsystem: Propagate (= 512) */ ssPropagate = 512,
/** Subsystem: Ground Reactions (= 1024) */ ssGroundReactions = 1024,
/** Subsystem: FCS (= 2048) */ ssFCS = 2048,
/** Subsystem: Propulsion (= 4096) */ ssPropulsion = 4096
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+#include <sstream>
+
#include "FGPiston.h"
#include "FGPropulsion.h"
+#include "FGPropeller.h"
namespace JSBSim {
MinManifoldPressure_inHg = 6.5;
MaxManifoldPressure_inHg = 28.5;
ManifoldPressure_inHg = Atmosphere->GetPressure() * psftoinhg; // psf to in Hg
+ minMAP = 21950;
+ maxMAP = 96250;
+ MAP = Atmosphere->GetPressure() * 47.88; // psf to Pa
CylinderHeadTemp_degK = 0.0;
Displacement = 360;
MaxHP = 200;
dt = State->Getdt();
+ // Supercharging
+ BoostSpeeds = 0; // Default to no supercharging
+ BoostSpeed = 0;
+ Boosted = false;
+ BoostOverride = 0;
+ bBoostOverride = false;
+ bTakeoffBoost = false;
+ TakeoffBoost = 0.0; // Default to no extra takeoff-boost
+ int i;
+ for(i=0; i<FG_MAX_BOOST_SPEEDS; ++i) {
+ RatedBoost[i] = 0.0;
+ RatedPower[i] = 0.0;
+ RatedAltitude[i] = 0.0;
+ BoostMul[i] = 1.0;
+ RatedMAP[i] = 100000;
+ RatedRPM[i] = 2500;
+ TakeoffMAP[i] = 100000;
+ }
+
// Initialisation
volumetric_efficiency = 0.8; // Actually f(speed, load) but this will get us running
else if (token == "IDLERPM") *Eng_cfg >> IdleRPM;
else if (token == "MAXTHROTTLE") *Eng_cfg >> MaxThrottle;
else if (token == "MINTHROTTLE") *Eng_cfg >> MinThrottle;
+ else if (token == "NUMBOOSTSPEEDS") *Eng_cfg >> BoostSpeeds;
+ else if (token == "BOOSTOVERRIDE") *Eng_cfg >> BoostOverride;
+ else if (token == "TAKEOFFBOOST") *Eng_cfg >> TakeoffBoost;
+ else if (token == "RATEDBOOST1") *Eng_cfg >> RatedBoost[0];
+ else if (token == "RATEDBOOST2") *Eng_cfg >> RatedBoost[1];
+ else if (token == "RATEDBOOST3") *Eng_cfg >> RatedBoost[2];
+ else if (token == "RATEDPOWER1") *Eng_cfg >> RatedPower[0];
+ else if (token == "RATEDPOWER2") *Eng_cfg >> RatedPower[1];
+ else if (token == "RATEDPOWER3") *Eng_cfg >> RatedPower[2];
+ else if (token == "RATEDRPM1") *Eng_cfg >> RatedRPM[0];
+ else if (token == "RATEDRPM2") *Eng_cfg >> RatedRPM[1];
+ else if (token == "RATEDRPM3") *Eng_cfg >> RatedRPM[2];
+ else if (token == "RATEDALTITUDE1") *Eng_cfg >> RatedAltitude[0];
+ else if (token == "RATEDALTITUDE2") *Eng_cfg >> RatedAltitude[1];
+ else if (token == "RATEDALTITUDE3") *Eng_cfg >> RatedAltitude[2];
else cerr << "Unhandled token in Engine config file: " << token << endl;
}
+ minMAP = MinManifoldPressure_inHg * 3376.85; // inHg to Pa
+ maxMAP = MaxManifoldPressure_inHg * 3376.85;
+
+ // Set up and sanity-check the turbo/supercharging configuration based on the input values.
+ if(TakeoffBoost > RatedBoost[0]) bTakeoffBoost = true;
+ for(i=0; i<BoostSpeeds; ++i) {
+ bool bad = false;
+ if(RatedBoost[i] <= 0.0) bad = true;
+ if(RatedPower[i] <= 0.0) bad = true;
+ if(RatedAltitude[i] < 0.0) bad = true; // 0.0 is deliberately allowed - this corresponds to unregulated supercharging.
+ if(i > 0 && RatedAltitude[i] < RatedAltitude[i - 1]) bad = true;
+ if(bad) {
+ // We can't recover from the above - don't use this supercharger speed.
+ BoostSpeeds--;
+ // TODO - put out a massive error message!
+ break;
+ }
+ // Now sanity-check stuff that is recoverable.
+ if(i < BoostSpeeds - 1) {
+ if(BoostSwitchAltitude[i] < RatedAltitude[i]) {
+ // TODO - put out an error message
+ // But we can also make a reasonable estimate, as below.
+ BoostSwitchAltitude[i] = RatedAltitude[i] + 1000;
+ }
+ BoostSwitchPressure[i] = Atmosphere->GetPressure(BoostSwitchAltitude[i]) * 47.88;
+ //cout << "BoostSwitchAlt = " << BoostSwitchAltitude[i] << ", pressure = " << BoostSwitchPressure[i] << '\n';
+ // Assume there is some hysteresis on the supercharger gear switch, and guess the value for now
+ BoostSwitchHysteresis = 1000;
+ }
+ // Now work out the supercharger pressure multiplier of this speed from the rated boost and altitude.
+ RatedMAP[i] = Atmosphere->GetPressureSL() * 47.88 + RatedBoost[i] * 6895; // psf*47.88 = Pa, psi*6895 = Pa.
+ // Sometimes a separate BCV setting for takeoff or extra power is fitted.
+ if(TakeoffBoost > RatedBoost[0]) {
+ // Assume that the effect on the BCV is the same whichever speed is in use.
+ TakeoffMAP[i] = RatedMAP[i] + ((TakeoffBoost - RatedBoost[0]) * 6895);
+ bTakeoffBoost = true;
+ } else {
+ TakeoffMAP[i] = RatedMAP[i];
+ bTakeoffBoost = false;
+ }
+ BoostMul[i] = RatedMAP[i] / (Atmosphere->GetPressure(RatedAltitude[i]) * 47.88);
+
+ // TODO - get rid of the debugging output before sending it to Jon
+ //cout << "Speed " << i+1 << '\n';
+ //cout << "BoostMul = " << BoostMul[i] << ", RatedMAP = " << RatedMAP[i] << ", TakeoffMAP = " << TakeoffMAP[i] << '\n';
+ }
+
+ if(BoostSpeeds > 0) {
+ Boosted = true;
+ BoostSpeed = 0;
+ }
+ bBoostOverride = (BoostOverride == 1 ? true : false);
+
+ //cout << "Engine is " << (Boosted ? "supercharged" : "naturally aspirated") << '\n';
+
Debug(0); // Call Debug() routine from constructor if needed
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-double FGPiston::Calculate(double PowerRequired)
+double FGPiston::Calculate(void)
{
if (FuelFlow_gph > 0.0) ConsumeFuel();
// Input values.
//
- p_amb = Atmosphere->GetPressure() * 48; // convert from lbs/ft2 to Pa
- p_amb_sea_level = Atmosphere->GetPressureSL() * 48;
+ p_amb = Atmosphere->GetPressure() * 47.88; // convert from lbs/ft2 to Pa
+ p_amb_sea_level = Atmosphere->GetPressureSL() * 47.88;
T_amb = Atmosphere->GetTemperature() * (5.0 / 9.0); // convert from Rankine to Kelvin
- RPM = Propulsion->GetThruster(EngineNumber)->GetRPM() *
- Propulsion->GetThruster(EngineNumber)->GetGearRatio();
-
+ RPM = Thruster->GetRPM() * Thruster->GetGearRatio();
+
IAS = Auxiliary->GetVcalibratedKTS();
- doEngineStartup();
- doManifoldPressure();
- doAirFlow();
- doFuelFlow();
+ doEngineStartup();
+ if(Boosted) doBoostControl();
+ doMAP();
+ doAirFlow();
+ doFuelFlow();
//Now that the fuel flow is done check if the mixture is too lean to run the engine
//Assume lean limit at 22 AFR for now - thats a thi of 0.668
Running = false;
doEnginePower();
- doEGT();
- doCHT();
- doOilTemperature();
- doOilPressure();
+ doEGT();
+ doCHT();
+ doOilTemperature();
+ doOilPressure();
+
+ if (Thruster->GetType() == FGThruster::ttPropeller) {
+ ((FGPropeller*)Thruster)->SetAdvance(FCS->GetPropAdvance(EngineNumber));
+ }
- PowerAvailable = (HP * hptoftlbssec) - PowerRequired;
- return PowerAvailable;
+ PowerAvailable = (HP * hptoftlbssec) - Thruster->GetPowerRequired();
+
+ return Thruster->Calculate(PowerAvailable);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGPiston::doEngineStartup(void)
{
- // Check parameters that may alter the operating state of the engine.
+ // Check parameters that may alter the operating state of the engine.
// (spark, fuel, starter motor etc)
bool spark;
bool fuel;
} else {
spark = false;
} // neglects battery voltage, master on switch, etc for now.
-
+
if ((Magnetos == 1) || (Magnetos > 2)) Magneto_Left = true;
if (Magnetos > 1) Magneto_Right = true;
}
if (Cranking) crank_counter++; //Check mode of engine operation
-
+
if (!Running && spark && fuel) { // start the engine if revs high enough
if (Cranking) {
if ((RPM > 450) && (crank_counter > 175)) // Add a little delay to startup
if ( Running && (!spark || !fuel) ) Running = false;
// Check for stalling (RPM = 0).
- if (Running) {
+ if (Running) {
if (RPM == 0) {
Running = false;
} else if ((RPM <= 480) && (Cranking)) {
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/**
- * Calculate the nominal manifold pressure in inches hg
+ * Calculate the Current Boost Speed
*
- * This function calculates nominal manifold pressure directly
- * from the throttle position, and does not adjust it for the
- * difference between the pressure at sea level and the pressure
- * at the current altitude (that adjustment takes place in
- * {@link #doEnginePower}).
+ * This function calculates the current turbo/supercharger boost speed
+ * based on altitude and the (automatic) boost-speed control valve configuration.
+ *
+ * Inputs: p_amb, BoostSwitchPressure, BoostSwitchHysteresis
+ *
+ * Outputs: BoostSpeed
+ */
+
+void FGPiston::doBoostControl(void)
+{
+ if(BoostSpeed < BoostSpeeds - 1) {
+ // Check if we need to change to a higher boost speed
+ if(p_amb < BoostSwitchPressure[BoostSpeed] - BoostSwitchHysteresis) {
+ BoostSpeed++;
+ }
+ } else if(BoostSpeed > 0) {
+ // Check if we need to change to a lower boost speed
+ if(p_amb > BoostSwitchPressure[BoostSpeed - 1] + BoostSwitchHysteresis) {
+ BoostSpeed--;
+ }
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/**
+ * Calculate the manifold absolute pressure (MAP) in inches hg
+ *
+ * This function calculates manifold absolute pressure (MAP)
+ * from the throttle position, turbo/supercharger boost control
+ * system, engine speed and local ambient air density.
*
* TODO: changes in MP should not be instantaneous -- introduce
* a lag between throttle changes and MP changes, to allow pressure
* to build up or disperse.
*
- * Inputs: MinManifoldPressure_inHg, MaxManifoldPressure_inHg, Throttle
+ * Inputs: minMAP, maxMAP, p_amb, Throttle
*
- * Outputs: ManifoldPressure_inHg
+ * Outputs: MAP, ManifoldPressure_inHg
*/
-void FGPiston::doManifoldPressure(void)
+void FGPiston::doMAP(void)
{
- if (Running || Cranking) {
- ManifoldPressure_inHg = MinManifoldPressure_inHg +
- (Throttle * (MaxManifoldPressure_inHg - MinManifoldPressure_inHg));
+ if(RPM > 10) {
+ // Naturally aspirated
+ MAP = minMAP + (Throttle * (maxMAP - minMAP));
+ MAP *= p_amb / p_amb_sea_level;
+ if(Boosted) {
+ // If takeoff boost is fitted, we currently assume the following throttle map:
+ // (In throttle % - actual input is 0 -> 1)
+ // 99 / 100 - Takeoff boost
+ // 96 / 97 / 98 - Rated boost
+ // 0 - 95 - Idle to Rated boost (MinManifoldPressure to MaxManifoldPressure)
+ // In real life, most planes would be fitted with a mechanical 'gate' between
+ // the rated boost and takeoff boost positions.
+ double T = Throttle; // processed throttle value.
+ bool bTakeoffPos = false;
+ if(bTakeoffBoost) {
+ if(Throttle > 0.98) {
+ //cout << "Takeoff Boost!!!!\n";
+ bTakeoffPos = true;
+ } else if(Throttle <= 0.95) {
+ bTakeoffPos = false;
+ T *= 1.0 / 0.95;
+ } else {
+ bTakeoffPos = false;
+ //cout << "Rated Boost!!\n";
+ T = 1.0;
+ }
+ }
+ // Boost the manifold pressure.
+ MAP *= BoostMul[BoostSpeed];
+ // Now clip the manifold pressure to BCV or Wastegate setting.
+ if(bTakeoffPos) {
+ if(MAP > TakeoffMAP[BoostSpeed]) {
+ MAP = TakeoffMAP[BoostSpeed];
+ }
+ } else {
+ if(MAP > RatedMAP[BoostSpeed]) {
+ MAP = RatedMAP[BoostSpeed];
+ }
+ }
+ }
} else {
- ManifoldPressure_inHg = Atmosphere->GetPressure() * psftoinhg; // psf to in Hg
- }
+ // rpm < 10 - effectively stopped.
+ // TODO - add a better variation of MAP with engine speed
+ MAP = Atmosphere->GetPressure() * 47.88; // psf to Pa
+ }
+
+ // And set the value in American units as well
+ ManifoldPressure_inHg = MAP / 3376.85;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/**
* Calculate the air flow through the engine.
+ * Also calculates ambient air density
+ * (used in CHT calculation for air-cooled engines).
*
- * At this point, ManifoldPressure_inHg still represents the sea-level
- * MP, not adjusted for altitude.
- *
- * Inputs: p_amb, R_air, T_amb, ManifoldPressure_inHg, Displacement,
+ * Inputs: p_amb, R_air, T_amb, MAP, Displacement,
* RPM, volumetric_efficiency
*
+ * TODO: Model inlet manifold air temperature.
+ *
* Outputs: rho_air, m_dot_air
*/
void FGPiston::doAirFlow(void)
{
rho_air = p_amb / (R_air * T_amb);
- double rho_air_manifold = rho_air * ManifoldPressure_inHg / 29.6;
+ double rho_air_manifold = MAP / (R_air * T_amb);
double displacement_SI = Displacement * in3tom3;
double swept_volume = (displacement_SI * (RPM/60)) / 2;
double v_dot_air = swept_volume * volumetric_efficiency;
* When tested with sufficient RPM, it has no trouble reaching
* 200HP.
*
- * Inputs: ManifoldPressure_inHg, p_amb, p_amb_sea_level, RPM, T_amb,
+ * Inputs: ManifoldPressure_inHg, p_amb, p_amb_sea_level, RPM, T_amb,
* equivalence_ratio, Cycles, MaxHP
*
* Outputs: Percentage_Power, HP
void FGPiston::doEnginePower(void)
{
- ManifoldPressure_inHg *= p_amb / p_amb_sea_level;
-
- if (Running) {
- double ManXRPM = ManifoldPressure_inHg * RPM;
+ if (Running) {
double T_amb_degF = KelvinToFahrenheit(T_amb);
- double T_amb_sea_lev_degF = KelvinToFahrenheit(288);
+ double T_amb_sea_lev_degF = KelvinToFahrenheit(288);
// FIXME: this needs to be generalized
- Percentage_Power = (6e-9 * ManXRPM * ManXRPM) + (8e-4 * ManXRPM) - 1.0;
- Percentage_Power += ((T_amb_sea_lev_degF - T_amb_degF) * 7 /120);
+ double ManXRPM; // Convienience term for use in the calculations
+ if(Boosted) {
+ // Currently a simple linear fit.
+ // The zero crossing is moved up the speed-load range to reduce the idling power.
+ // This will change!
+ double zeroOffset = (minMAP / 2.0) * (IdleRPM / 2.0);
+ ManXRPM = MAP * (RPM > RatedRPM[BoostSpeed] ? RatedRPM[BoostSpeed] : RPM);
+ // The speed clip in the line above is deliberate.
+ Percentage_Power = ((ManXRPM - zeroOffset) / ((RatedMAP[BoostSpeed] * RatedRPM[BoostSpeed]) - zeroOffset)) * 107.0;
+ Percentage_Power -= 7.0; // Another idle power reduction offset - see line above with 107.
+ if (Percentage_Power < 0.0) Percentage_Power = 0.0;
+ // Note that %power is allowed to go over 100 for boosted powerplants
+ // such as for the BCV-override or takeoff power settings.
+ // TODO - currently no altitude effect (temperature & exhaust back-pressure) modelled
+ // for boosted engines.
+ } else {
+ ManXRPM = ManifoldPressure_inHg * RPM; // Note that inHg must be used for the following correlation.
+ Percentage_Power = (6e-9 * ManXRPM * ManXRPM) + (8e-4 * ManXRPM) - 1.0;
+ Percentage_Power += ((T_amb_sea_lev_degF - T_amb_degF) * 7 /120);
+ if (Percentage_Power < 0.0) Percentage_Power = 0.0;
+ else if (Percentage_Power > 100.0) Percentage_Power = 100.0;
+ }
double Percentage_of_best_power_mixture_power =
Power_Mixture_Correlation->GetValue(14.7 / equivalence_ratio);
Percentage_Power *= Percentage_of_best_power_mixture_power / 100.0;
- if (Percentage_Power < 0.0) Percentage_Power = 0.0;
- else if (Percentage_Power > 100.0) Percentage_Power = 100.0;
-
- HP = Percentage_Power * MaxHP / 100.0;
+ if(Boosted) {
+ HP = Percentage_Power * RatedPower[BoostSpeed] / 100.0;
+ } else {
+ HP = Percentage_Power * MaxHP / 100.0;
+ }
} else {
// the first time step. It may possibly need to be changed
// if the prop model is changed.
} else if (RPM < 480) {
- HP = 3.0 + ((480 - RPM) / 10.0);
+ HP = 3.0 + ((480 - RPM) / 10.0);
// This is a guess - would be nice to find a proper starter moter torque curve
} else {
HP = 3.0;
HP = 0.0;
}
}
+ //cout << "Power = " << HP << '\n';
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/**
* Calculate the exhaust gas temperature.
*
- * Inputs: equivalence_ratio, m_dot_fuel, calorific_value_fuel,
+ * Inputs: equivalence_ratio, m_dot_fuel, calorific_value_fuel,
* Cp_air, m_dot_air, Cp_fuel, m_dot_fuel, T_amb, Percentage_Power
*
* Outputs: combustion_efficiency, ExhaustGasTemp_degK
if ((Running) && (m_dot_air > 0.0)) { // do the energy balance
combustion_efficiency = Lookup_Combustion_Efficiency->GetValue(equivalence_ratio);
- enthalpy_exhaust = m_dot_fuel * calorific_value_fuel *
+ enthalpy_exhaust = m_dot_fuel * calorific_value_fuel *
combustion_efficiency * 0.33;
heat_capacity_exhaust = (Cp_air * m_dot_air) + (Cp_fuel * m_dot_fuel);
delta_T_exhaust = enthalpy_exhaust / heat_capacity_exhaust;
double v_apparent = IAS * 0.5144444;
double v_dot_cooling_air = arbitary_area * v_apparent;
double m_dot_cooling_air = v_dot_cooling_air * rho_air;
- double dqdt_from_combustion =
+ double dqdt_from_combustion =
m_dot_fuel * calorific_value_fuel * combustion_efficiency * 0.33;
- double dqdt_forced = (h2 * m_dot_cooling_air * temperature_difference) +
+ double dqdt_forced = (h2 * m_dot_cooling_air * temperature_difference) +
(h3 * RPM * temperature_difference);
double dqdt_free = h1 * temperature_difference;
double dqdt_cylinder_head = dqdt_from_combustion + dqdt_forced + dqdt_free;
-
+
double HeatCapacityCylinderHead = CpCylinderHead * MassCylinderHead;
-
+
CylinderHeadTemp_degK +=
(dqdt_cylinder_head / HeatCapacityCylinderHead) * dt;
}
target_oil_temp = 363;
time_constant = 500; // Time constant for engine-on idling.
if (Percentage_Power > idle_percentage_power) {
- time_constant /= ((Percentage_Power / idle_percentage_power) / 10.0); // adjust for power
+ time_constant /= ((Percentage_Power / idle_percentage_power) / 10.0); // adjust for power
}
} else {
target_oil_temp = 298;
OilPressure_psi += (Design_Oil_Temp - OilTemp_degK) * Oil_Viscosity_Index;
}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGPiston::GetEngineLabels(void)
+{
+ std::ostringstream buf;
+
+ buf << Name << "_PwrAvail[" << EngineNumber << "], "
+ << Thruster->GetThrusterLabels(EngineNumber);
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGPiston::GetEngineValues(void)
+{
+ std::ostringstream buf;
+
+ buf << PowerAvailable << ", " << Thruster->GetThrusterValues(EngineNumber);
+
+ return buf.str();
+}
+
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
// The bitmasked value choices are as follows:
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_PISTON "$Id$";
+#define FG_MAX_BOOST_SPEEDS 3
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-/** Models Dave Luff's engine model as ported into JSBSim by David Megginson.
+/** Models Dave Luff's Turbo/Supercharged Piston engine model.
+ Additional elements are required for a supercharged engine. These can be
+ left off a non-supercharged engine, ie. the changes are all backward
+ compatible at present.
+
+ - NUMBOOSTSPEEDS - zero (or not present) for a naturally-aspirated engine,
+ either 1, 2 or 3 for a boosted engine. This corresponds to the number of
+ supercharger speeds. Merlin XII had 1 speed, Merlin 61 had 2, a late
+ Griffon engine apparently had 3. No known engine more than 3, although
+ some German engines apparently had a continuously variable-speed
+ supercharger.
+
+ - BOOSTOVERRIDE - whether the boost pressure control system (either a boost
+ control valve for superchargers or wastegate for turbochargers) can be
+ overriden by the pilot. During wartime this was commonly possible, and
+ known as "War Emergency Power" by the Brits. 1 or 0 in the config file.
+ This isn't implemented in the model yet though, there would need to be
+ some way of getting the boost control cutout lever position (on or off)
+ from FlightGear first.
+
+ - The next items are all appended with either 1, 2 or 3 depending on which
+ boost speed they refer to, eg RATEDBOOST1. The rated values seems to have
+ been a common convention at the time to express the maximum continuously
+ available power, and the conditions to attain that power.
+
+ - RATEDBOOST[123] - the absolute rated boost above sea level ambient for a
+ given boost speed, in psi. Eg the Merlin XII had a rated boost of 9psi,
+ giving approximately 42inHg manifold pressure up to the rated altitude.
+
+ - RATEDALTITUDE[123] - The altitude up to which rated boost can be
+ maintained. Up to this altitude the boost is maintained constant for a
+ given throttle position by the BCV or wastegate. Beyond this altitude the
+ manifold pressure must drop, since the supercharger is now at maximum
+ unregulated output. The actual pressure multiplier of the supercharger
+ system is calculated at initialisation from this value.
+
+ - RATEDPOWER[123] - The power developed at rated boost at rated altitude at
+ rated rpm.
+
+ - RATEDRPM[123] - The rpm at which rated power is developed.
+
+ - TAKEOFFBOOST - Takeoff boost in psi above ambient. Many aircraft had an
+ extra boost setting beyond rated boost, but not totally uncontrolled as in
+ the already mentioned boost-control-cutout, typically attained by pushing
+ the throttle past a mechanical 'gate' preventing its inadvertant use. This
+ was typically used for takeoff, and emergency situations, generally for
+ not more than five minutes. This is a change in the boost control
+ setting, not the actual supercharger speed, and so would only give extra
+ power below the rated altitude. When TAKEOFFBOOST is specified in the
+ config file (and is above RATEDBOOST1), then the throttle position is
+ interpreted as:
+
+ - 0 to 0.95 : idle manifold pressure to rated boost (where attainable)
+ - 0.96, 0.97, 0.98 : rated boost (where attainable).
+ - 0.99, 1.0 : takeoff boost (where attainable).
+
+ A typical takeoff boost for an earlyish Merlin was about 12psi, compared
+ with a rated boost of 9psi.
+
+ It is quite possible that other boost control settings could have been used
+ on some aircraft, or that takeoff/extra boost could have activated by other
+ means than pushing the throttle full forward through a gate, but this will
+ suffice for now.
+
+ Note that MAXMP is still the non-boosted max manifold pressure even for
+ boosted engines - effectively this is simply a measure of the pressure drop
+ through the fully open throttle.
+
@author Jon S. Berndt (Engine framework code and framework-related mods)
@author Dave Luff (engine operational code)
- @author David Megginson (porting and additional code)
- @version "$Id$"
+ @author David Megginson (initial porting and additional code)
+ @version $Id$
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/// Destructor
~FGPiston();
- double Calculate(double PowerRequired);
+ string GetEngineLabels(void);
+ string GetEngineValues(void);
+
+ double Calculate(void);
double GetPowerAvailable(void) {return PowerAvailable;}
double CalcFuelNeed(void);
double getCylinderHeadTemp_degF(void) {return KelvinToFahrenheit(CylinderHeadTemp_degK);}
double getOilPressure_psi(void) const {return OilPressure_psi;}
double getOilTemp_degF (void) {return KelvinToFahrenheit(OilTemp_degK);}
- double getRPM(void) {return RPM;}
+ double getRPM(void) {return RPM;}
private:
int crank_counter;
double dt;
void doEngineStartup(void);
- void doManifoldPressure(void);
+ void doBoostControl(void);
+ void doMAP(void);
void doAirFlow(void);
void doFuelFlow(void);
void doEnginePower(void);
double MaxHP; // horsepower
double Cycles; // cycles/power stroke
double IdleRPM; // revolutions per minute
+ int BoostSpeeds; // Number of super/turbocharger boost speeds - zero implies no turbo/supercharging.
+ int BoostSpeed; // The current boost-speed (zero-based).
+ bool Boosted; // Set true for boosted engine.
+ int BoostOverride; // The raw value read in from the config file - should be 1 or 0 - see description below.
+ bool bBoostOverride; // Set true if pilot override of the boost regulator was fitted.
+ // (Typically called 'war emergency power').
+ bool bTakeoffBoost; // Set true if extra takeoff / emergency boost above rated boost could be attained.
+ // (Typically by extra throttle movement past a mechanical 'gate').
+ double TakeoffBoost; // Sea-level takeoff boost in psi. (if fitted).
+ double RatedBoost[FG_MAX_BOOST_SPEEDS]; // Sea-level rated boost in psi.
+ double RatedAltitude[FG_MAX_BOOST_SPEEDS]; // Altitude at which full boost is reached (boost regulation ends)
+ // and at which power starts to fall with altitude [ft].
+ double RatedRPM[FG_MAX_BOOST_SPEEDS]; // Engine speed at which the rated power for each boost speed is delivered [rpm].
+ double RatedPower[FG_MAX_BOOST_SPEEDS]; // Power at rated throttle position at rated altitude [HP].
+ double BoostSwitchAltitude[FG_MAX_BOOST_SPEEDS - 1]; // Altitude at which switchover (currently assumed automatic)
+ // from one boost speed to next occurs [ft].
+ double BoostSwitchPressure[FG_MAX_BOOST_SPEEDS - 1]; // Pressure at which boost speed switchover occurs [Pa]
+ double BoostMul[FG_MAX_BOOST_SPEEDS]; // Pressure multipier of unregulated supercharger
+ double RatedMAP[FG_MAX_BOOST_SPEEDS]; // Rated manifold absolute pressure [Pa] (BCV clamp)
+ double TakeoffMAP[FG_MAX_BOOST_SPEEDS]; // Takeoff setting manifold absolute pressure [Pa] (BCV clamp)
+ double BoostSwitchHysteresis; // Pa.
+
+ double minMAP; // Pa
+ double maxMAP; // Pa
+ double MAP; // Pa
//
// Inputs (in addition to those in FGEngine).
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGPosition.cpp
- Author: Jon S. Berndt
- Date started: 01/05/99
- Purpose: Integrate the EOM to determine instantaneous position
- Called by: FGFDMExec
-
- ------------- 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.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-This class encapsulates the integration of rates and accelerations to get the
-current position of the aircraft.
-
-HISTORY
---------------------------------------------------------------------------------
-01/05/99 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-COMMENTS, REFERENCES, and NOTES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-[1] Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
- Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
- School, January 1994
-[2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
- JSC 12960, July 1977
-[3] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
- NASA-Ames", NASA CR-2497, January 1975
-[4] Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
- Wiley & Sons, 1979 ISBN 0-471-03032-5
-[5] Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
- 1982 ISBN 0-471-08936-2
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef FGFS
-# include <simgear/compiler.h>
-# ifdef SG_HAVE_STD_INCLUDES
-# include <cmath>
-# include <iomanip>
-# else
-# include <math.h>
-# include <iomanip.h>
-# endif
-#else
-# if defined(sgi) && !defined(__GNUC__)
-# include <math.h>
-# if (_COMPILER_VERSION < 740)
-# include <iomanip.h>
-# else
-# include <iomanip>
-# endif
-# else
-# include <cmath>
-# include <iomanip>
-# endif
-#endif
-
-#include "FGPosition.h"
-#include "FGState.h"
-#include "FGFDMExec.h"
-#include "FGAircraft.h"
-#include "FGMassBalance.h"
-#include "FGTranslation.h"
-#include "FGRotation.h"
-#include "FGInertial.h"
-#include "FGPropertyManager.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_POSITION;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-FGPosition::FGPosition(FGFDMExec* fdmex) : FGModel(fdmex)
-{
- Name = "FGPosition";
- LongitudeDot = LatitudeDot = RadiusDot = 0.0;
-
- for (int i=0;i<4;i++) {
- LatitudeDot_prev[i] = 0.0;
- LongitudeDot_prev[i] = 0.0;
- RadiusDot_prev[i] = 0.0;
- }
-
- vVRPoffset.InitMatrix();
-
- Longitude = Latitude = 0.0;
- LongitudeVRP = LatitudeVRP = 0.0;
- gamma = Vt = Vground = 0.0;
- hoverbmac = hoverbcg = 0.0;
- psigt = 0.0;
- bind();
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGPosition::~FGPosition(void)
-{
- unbind();
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGPosition::InitModel(void)
-{
- FGModel::InitModel();
-
- h = 3.0; // Est. height of aircraft cg off runway
- SeaLevelRadius = Inertial->RefRadius(); // For initialization ONLY
- Radius = SeaLevelRadius + h;
- RunwayRadius = SeaLevelRadius;
- DistanceAGL = Radius - RunwayRadius; // Geocentric
- vRunwayNormal(3) = -1.0; // Initialized for standalone mode
- b = 1;
- return true;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-/*
-Purpose: Called on a schedule to perform Positioning algorithms
-Notes: [TP] Make sure that -Vt <= hdot <= Vt, which, of course, should always
- be the case
- [JB] Run in standalone mode, SeaLevelRadius will be reference radius.
- In FGFS, SeaLevelRadius is stuffed from FGJSBSim in JSBSim.cxx each pass.
-*/
-
-bool FGPosition::Run(void)
-{
- double cosLat;
- double hdot_Vt;
-
- if (!FGModel::Run()) {
- GetState();
-
- Vground = sqrt( vVel(eNorth)*vVel(eNorth) + vVel(eEast)*vVel(eEast) );
-
- if (vVel(eNorth) == 0) psigt = 0;
- else psigt = atan2(vVel(eEast), vVel(eNorth));
-
- if (psigt < 0.0) psigt += 2*M_PI;
-
- Radius = h + SeaLevelRadius;
-
- cosLat = cos(Latitude);
- if (cosLat != 0) LongitudeDot = vVel(eEast) / (Radius * cosLat);
- LatitudeDot = vVel(eNorth) / Radius;
- RadiusDot = -vVel(eDown);
-
- 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
-
- vVRPoffset = State->GetTb2l() * MassBalance->StructuralToBody(Aircraft->GetXYZvrp());
-
- // vVRP - the vector to the Visual Reference Point - now contains the
- // offset from the CG to the VRP, in units of feet, in the Local coordinate
- // frame, where X points north, Y points East, and Z points down. This needs
- // to be converted to Lat/Lon/Alt, now.
-
- if (cosLat != 0)
- LongitudeVRP = vVRPoffset(eEast) / (Radius * cosLat) + Longitude;
-
- LatitudeVRP = vVRPoffset(eNorth) / Radius + Latitude;
- hVRP = h - vVRPoffset(eDown);
-/*
-cout << "Lat/Lon/Alt : " << Latitude << " / " << Longitude << " / " << h << endl;
-cout << "Lat/Lon/Alt VRP: " << LatitudeVRP << " / " << LongitudeVRP << " / " << hVRP << endl << endl;
-*/
- DistanceAGL = Radius - RunwayRadius; // Geocentric
-
- hoverbcg = DistanceAGL/b;
-
- vMac = State->GetTb2l()*MassBalance->StructuralToBody(Aircraft->GetXYZrp());
- hoverbmac = (DistanceAGL + vMac(3)) / b;
-
- if (Vt > 0) {
- hdot_Vt = RadiusDot/Vt;
- if (fabs(hdot_Vt) <= 1) gamma = asin(hdot_Vt);
- } else {
- gamma = 0.0;
- }
-
- return false;
-
- } else {
- return true;
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPosition::GetState(void)
-{
- dt = State->Getdt();
-
- Vt = Translation->GetVt();
- vVel = State->GetTb2l() * Translation->GetUVW();
- vVelDot = State->GetTb2l() * Translation->GetUVWdot();
-
- b = Aircraft->GetWingSpan();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPosition::Seth(double tt)
-{
- h = tt;
- Radius = h + SeaLevelRadius;
- DistanceAGL = Radius - RunwayRadius; // Geocentric
- hoverbcg = DistanceAGL/b;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPosition::SetDistanceAGL(double tt)
-{
- DistanceAGL=tt;
- Radius = RunwayRadius + DistanceAGL;
- h = Radius - SeaLevelRadius;
- hoverbcg = DistanceAGL/b;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPosition::bind(void)
-{
- PropertyManager->Tie("velocities/v-north-fps", this,
- &FGPosition::GetVn);
- PropertyManager->Tie("velocities/v-east-fps", this,
- &FGPosition::GetVe);
- PropertyManager->Tie("velocities/v-down-fps", this,
- &FGPosition::GetVd);
- PropertyManager->Tie("velocities/vg-fps", this,
- &FGPosition::GetVground);
- PropertyManager->Tie("flight-path/psi-gt-rad", this,
- &FGPosition::GetGroundTrack);
- PropertyManager->Tie("position/h-sl-ft", this,
- &FGPosition::Geth,
- &FGPosition::Seth,
- true);
- PropertyManager->Tie("velocities/h-dot-fps", this,
- &FGPosition::Gethdot);
- PropertyManager->Tie("position/lat-gc-rad", this,
- &FGPosition::GetLatitude,
- &FGPosition::SetLatitude);
- PropertyManager->Tie("position/lat-dot-gc-rad", this,
- &FGPosition::GetLatitudeDot);
- PropertyManager->Tie("position/long-gc-rad", this,
- &FGPosition::GetLongitude,
- &FGPosition::SetLongitude,
- true);
- PropertyManager->Tie("position/long-dot-gc-rad", this,
- &FGPosition::GetLongitudeDot);
- PropertyManager->Tie("metrics/runway-radius", this,
- &FGPosition::GetRunwayRadius,
- &FGPosition::SetRunwayRadius);
- PropertyManager->Tie("position/h-agl-ft", this,
- &FGPosition::GetDistanceAGL,
- &FGPosition::SetDistanceAGL);
- PropertyManager->Tie("position/radius-to-vehicle-ft", this,
- &FGPosition::GetRadius);
- PropertyManager->Tie("flight-path/gamma-rad", this,
- &FGPosition::GetGamma,
- &FGPosition::SetGamma);
- PropertyManager->Tie("aero/h_b-cg-ft", this,
- &FGPosition::GetHOverBCG);
- PropertyManager->Tie("aero/h_b-mac-ft", this,
- &FGPosition::GetHOverBMAC);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGPosition::unbind(void)
-{
- PropertyManager->Untie("velocities/v-north-fps");
- PropertyManager->Untie("velocities/v-east-fps");
- PropertyManager->Untie("velocities/v-down-fps");
- PropertyManager->Untie("velocities/vg-fps");
- PropertyManager->Untie("flight-path/psi-gt-rad");
- PropertyManager->Untie("position/h-sl-ft");
- PropertyManager->Untie("velocities/h-dot-fps");
- PropertyManager->Untie("position/lat-gc-rad");
- PropertyManager->Untie("position/lat-dot-gc-rad");
- PropertyManager->Untie("position/long-gc-rad");
- PropertyManager->Untie("position/long-dot-gc-rad");
- PropertyManager->Untie("metrics/runway-radius");
- PropertyManager->Untie("position/h-agl-ft");
- PropertyManager->Untie("position/radius-to-vehicle-ft");
- PropertyManager->Untie("flight-path/gamma-rad");
- PropertyManager->Untie("aero/h_b-cg-ft");
- PropertyManager->Untie("aero/h_b-mac-ft");
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// 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 FGPosition::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: FGPosition" << endl;
- if (from == 1) cout << "Destroyed: FGPosition" << 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;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGPosition.h
- Author: Jon S. Berndt
- Date started: 1/5/99
-
- ------------- 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
---------------------------------------------------------------------------------
-01/05/99 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGPOSITION_H
-#define FGPOSITION_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGModel.h"
-#include "FGColumnVector3.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_POSITION "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Models the lateral and longitudinal translational EOM.
- @author Jon S. Berndt
- @version $Id$
- */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGPosition : public FGModel {
-public:
- /** Constructor
- @param Executive a pointer to the parent executive object */
- FGPosition(FGFDMExec* Executive);
-
- /// Destructor
- ~FGPosition();
-
- bool InitModel(void);
-
- /** Runs the Position model; called by the Executive
- @see JSBSim.cpp documentation
- @return false if no error */
- bool Run(void);
-
- inline FGColumnVector3& GetVel(void) { return vVel; }
- inline FGColumnVector3& GetVelDot(void) { return vVelDot; }
- inline double GetVn(void) const { return vVel(eX); }
- inline double GetVe(void) const { return vVel(eY); }
- inline double GetVd(void) const { return vVel(eZ); }
- inline double GetVground(void) const { return Vground; }
- inline double GetGroundTrack(void) const { return psigt; }
- inline double Geth(void) const { return h; }
- inline double GethVRP(void) const { return hVRP; }
- inline double Gethdot(void) const { return RadiusDot; }
- inline double GetLatitude(void) const { return Latitude; }
- inline double GetLatitudeVRP(void) const { return LatitudeVRP; }
- inline double GetLatitudeDot(void) const { return LatitudeDot; }
- inline double GetLongitude(void) const { return Longitude; }
- inline double GetLongitudeVRP(void) const { return LongitudeVRP; }
- inline double GetLongitudeDot(void) const { return LongitudeDot; }
- inline double GetRunwayRadius(void) const { return RunwayRadius; }
- inline double GetDistanceAGL(void) const { return DistanceAGL; }
- inline double GetRadius(void) const { return Radius; }
- inline FGColumnVector3& GetRunwayNormal(void) { return vRunwayNormal; }
-
- inline double GetGamma(void) const { return gamma; }
- inline void SetGamma(double tt) { gamma = tt; }
- inline double GetHOverBCG(void) const { return hoverbcg; }
- inline double GetHOverBMAC(void) const { return hoverbmac; }
- void SetvVel(const FGColumnVector3& v) { vVel = v; }
- void SetLatitude(double tt) { Latitude = tt; }
- void SetLongitude(double tt) { Longitude = tt; }
- void Seth(double tt);
- void SetRunwayRadius(double tt) { RunwayRadius = tt; }
- void SetSeaLevelRadius(double tt) { SeaLevelRadius = tt;}
- void SetDistanceAGL(double tt);
- inline void SetRunwayNormal(double fgx, double fgy, double fgz ) {
- vRunwayNormal << fgx << fgy << fgz;
- }
- void SetVRP(FGColumnVector3& vrp) {vVRP = vrp;}
-
- void bind(void);
- void unbind(void);
-
-private:
- FGColumnVector3 vVel;
- FGColumnVector3 vVelDot;
- FGColumnVector3 vRunwayNormal;
- FGColumnVector3 vVRP;
- FGColumnVector3 vVRPoffset;
- FGColumnVector3 vMac;
-
- double Radius, h, hVRP;
- double LatitudeDot, LongitudeDot, RadiusDot;
- double LatitudeDot_prev[4], LongitudeDot_prev[4], RadiusDot_prev[4];
- double Longitude, Latitude;
- double LongitudeVRP, LatitudeVRP;
- double dt;
- double RunwayRadius;
- double DistanceAGL;
- double SeaLevelRadius;
- double gamma;
- double Vt, Vground;
- double hoverbcg,hoverbmac,b;
-
- double psigt;
-
- void GetState(void);
- void Debug(int from);
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
-
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGPropagate.cpp
+ Author: Jon S. Berndt
+ Date started: 01/05/99
+ Purpose: Integrate the EOM to determine instantaneous position
+ Called by: FGFDMExec
+
+ ------------- 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.
+
+FUNCTIONAL DESCRIPTION
+--------------------------------------------------------------------------------
+This class encapsulates the integration of rates and accelerations to get the
+current position of the aircraft.
+
+HISTORY
+--------------------------------------------------------------------------------
+01/05/99 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+COMMENTS, REFERENCES, and NOTES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+[1] Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
+ Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
+ School, January 1994
+[2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
+ JSC 12960, July 1977
+[3] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
+ NASA-Ames", NASA CR-2497, January 1975
+[4] Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
+ Wiley & Sons, 1979 ISBN 0-471-03032-5
+[5] Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
+ 1982 ISBN 0-471-08936-2
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <simgear/compiler.h>
+# ifdef SG_HAVE_STD_INCLUDES
+# include <cmath>
+# include <iomanip>
+# else
+# include <math.h>
+# include <iomanip.h>
+# endif
+#else
+# if defined(sgi) && !defined(__GNUC__)
+# include <math.h>
+# if (_COMPILER_VERSION < 740)
+# include <iomanip.h>
+# else
+# include <iomanip>
+# endif
+# else
+# include <cmath>
+# include <iomanip>
+# endif
+#endif
+
+#include "FGPropagate.h"
+#include "FGState.h"
+#include "FGFDMExec.h"
+#include "FGAircraft.h"
+#include "FGMassBalance.h"
+#include "FGInertial.h"
+#include "FGPropertyManager.h"
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_PROPAGATE;
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS IMPLEMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+FGPropagate::FGPropagate(FGFDMExec* fdmex) : FGModel(fdmex)
+{
+ Name = "FGPropagate";
+
+ bind();
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+FGPropagate::~FGPropagate(void)
+{
+ unbind();
+ Debug(1);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+bool FGPropagate::InitModel(void)
+{
+ FGModel::InitModel();
+
+ SeaLevelRadius = Inertial->RefRadius(); // For initialization ONLY
+ RunwayRadius = SeaLevelRadius;
+
+ VState.vLocation.SetRadius( SeaLevelRadius + 4.0 );
+
+ return true;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
+{
+ SeaLevelRadius = FGIC->GetSeaLevelRadiusFtIC();
+ RunwayRadius = FGIC->GetSeaLevelRadiusFtIC() + FGIC->GetTerrainAltitudeFtIC();
+
+ // Set the position lat/lon/radius
+ VState.vLocation = FGLocation( FGIC->GetLongitudeRadIC(),
+ FGIC->GetLatitudeRadIC(),
+ FGIC->GetAltitudeFtIC() + FGIC->GetSeaLevelRadiusFtIC() );
+
+ // Set the Orientation from the euler angles
+ VState.vQtrn = FGQuaternion( FGIC->GetPhiRadIC(),
+ FGIC->GetThetaRadIC(),
+ FGIC->GetPsiRadIC() );
+
+ // Set the velocities in the instantaneus body frame
+ VState.vUVW = FGColumnVector3( FGIC->GetUBodyFpsIC(),
+ FGIC->GetVBodyFpsIC(),
+ FGIC->GetWBodyFpsIC() );
+
+ // Set the angular velocities in the instantaneus body frame.
+ VState.vPQR = FGColumnVector3( FGIC->GetPRadpsIC(),
+ FGIC->GetQRadpsIC(),
+ FGIC->GetRRadpsIC() );
+
+ // Compute some derived values.
+ vVel = VState.vQtrn.GetTInv()*VState.vUVW;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+/*
+Purpose: Called on a schedule to perform EOM integration
+Notes: [JB] Run in standalone mode, SeaLevelRadius will be reference radius.
+ In FGFS, SeaLevelRadius is stuffed from FGJSBSim in JSBSim.cxx each pass.
+
+At the top of this Run() function, see several "shortcuts" (or, aliases) being
+set up for use later, rather than using the longer class->function() notation.
+
+Here, propagation of state is done using a simple explicit Euler scheme (see the
+bottom of the function). This propagation is done using the current state values
+and current derivatives. Based on these values we compute an approximation to the
+state values for (now + dt).
+
+*/
+
+bool FGPropagate::Run(void)
+{
+ if (FGModel::Run()) return true; // Fast return if we have nothing to do ...
+
+ double dt = State->Getdt()*rate; // The 'stepsize'
+ const FGColumnVector3 omega( 0.0, 0.0, Inertial->omega() ); // earth rotation
+ const FGColumnVector3& vForces = Aircraft->GetForces(); // current forces
+ const FGColumnVector3& vMoments = Aircraft->GetMoments(); // current moments
+
+ double mass = MassBalance->GetMass(); // mass
+ const FGMatrix33& J = MassBalance->GetJ(); // inertia matrix
+ const FGMatrix33& Jinv = MassBalance->GetJinv(); // inertia matrix inverse
+ double r = GetRadius(); // radius
+ if (r == 0.0) {cerr << "radius = 0 !" << endl; r = 1e-16;} // radius check
+ double rInv = 1.0/r;
+ FGColumnVector3 gAccel( 0.0, 0.0, Inertial->GetGAccel(r) );
+
+ // The rotation matrices:
+ const FGMatrix33& Tl2b = GetTl2b(); // local to body frame
+ const FGMatrix33& Tb2l = GetTb2l(); // body to local frame
+ const FGMatrix33& Tec2l = VState.vLocation.GetTec2l(); // earth centered to local frame
+ const FGMatrix33& Tl2ec = VState.vLocation.GetTl2ec(); // local to earth centered frame
+
+ // Inertial angular velocity measured in the body frame.
+ const FGColumnVector3 pqri = VState.vPQR + Tl2b*(Tec2l*omega);
+
+ // Compute vehicle velocity wrt EC frame, expressed in Local horizontal frame.
+ vVel = Tb2l * VState.vUVW;
+
+ // First compute the time derivatives of the vehicle state values:
+
+ // Compute body frame rotational accelerations based on the current body moments
+ vPQRdot = Jinv*(vMoments - pqri*(J*pqri));
+
+ // Compute body frame accelerations based on the current body forces
+ vUVWdot = VState.vUVW*VState.vPQR + vForces/mass;
+
+ // Centrifugal acceleration.
+ FGColumnVector3 ecVel = Tl2ec*vVel;
+ FGColumnVector3 ace = 2.0*omega*ecVel;
+ vUVWdot -= Tl2b*(Tec2l*ace);
+
+ // Coriolis acceleration.
+ FGColumnVector3 aeec = omega*(omega*VState.vLocation);
+ vUVWdot -= Tl2b*(Tec2l*aeec);
+
+ // Gravitation accel
+ vUVWdot += Tl2b*gAccel;
+
+ // Compute vehicle velocity wrt EC frame, expressed in EC frame
+ FGColumnVector3 vLocationDot = Tl2ec * vVel;
+
+ FGColumnVector3 omegaLocal( rInv*vVel(eEast),
+ -rInv*vVel(eNorth),
+ -rInv*vVel(eEast)*VState.vLocation.GetTanLatitude() );
+
+ // Compute quaternion orientation derivative on current body rates
+ FGQuaternion vQtrndot = VState.vQtrn.GetQDot( VState.vPQR - Tl2b*omegaLocal );
+
+ // Propagate velocities
+ VState.vPQR += dt*vPQRdot;
+ VState.vUVW += dt*vUVWdot;
+
+ // Propagate positions
+ VState.vQtrn += dt*vQtrndot;
+ VState.vLocation += dt*vLocationDot;
+
+ return false;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropagate::Seth(double tt)
+{
+ VState.vLocation.SetRadius( tt + SeaLevelRadius );
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropagate::SetDistanceAGL(double tt)
+{
+ VState.vLocation.SetRadius( tt + RunwayRadius );
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropagate::bind(void)
+{
+ typedef double (FGPropagate::*PMF)(int) const;
+ PropertyManager->Tie("velocities/h-dot-fps", this, &FGPropagate::Gethdot);
+
+ PropertyManager->Tie("velocities/v-north-fps", this, eNorth, (PMF)&FGPropagate::GetVel);
+ PropertyManager->Tie("velocities/v-east-fps", this, eEast, (PMF)&FGPropagate::GetVel);
+ PropertyManager->Tie("velocities/v-down-fps", this, eDown, (PMF)&FGPropagate::GetVel);
+
+ PropertyManager->Tie("velocities/u-fps", this, eU, (PMF)&FGPropagate::GetUVW);
+ PropertyManager->Tie("velocities/v-fps", this, eV, (PMF)&FGPropagate::GetUVW);
+ PropertyManager->Tie("velocities/w-fps", this, eW, (PMF)&FGPropagate::GetUVW);
+
+ PropertyManager->Tie("velocities/p-rad_sec", this, eP, (PMF)&FGPropagate::GetPQR);
+ PropertyManager->Tie("velocities/q-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQR);
+ PropertyManager->Tie("velocities/r-rad_sec", this, eR, (PMF)&FGPropagate::GetPQR);
+
+ PropertyManager->Tie("accelerations/pdot-rad_sec", this, eP, (PMF)&FGPropagate::GetPQRdot);
+ PropertyManager->Tie("accelerations/qdot-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQRdot);
+ PropertyManager->Tie("accelerations/rdot-rad_sec", this, eR, (PMF)&FGPropagate::GetPQRdot);
+
+ PropertyManager->Tie("accelerations/udot-fps", this, eU, (PMF)&FGPropagate::GetUVWdot);
+ PropertyManager->Tie("accelerations/vdot-fps", this, eV, (PMF)&FGPropagate::GetUVWdot);
+ PropertyManager->Tie("accelerations/wdot-fps", this, eW, (PMF)&FGPropagate::GetUVWdot);
+
+ PropertyManager->Tie("position/h-sl-ft", this, &FGPropagate::Geth, &FGPropagate::Seth, true);
+ PropertyManager->Tie("position/lat-gc-rad", this, &FGPropagate::GetLatitude, &FGPropagate::SetLatitude);
+ PropertyManager->Tie("position/long-gc-rad", this, &FGPropagate::GetLongitude, &FGPropagate::SetLongitude);
+ PropertyManager->Tie("position/h-agl-ft", this, &FGPropagate::GetDistanceAGL, &FGPropagate::SetDistanceAGL);
+ PropertyManager->Tie("position/radius-to-vehicle-ft", this, &FGPropagate::GetRadius);
+
+ PropertyManager->Tie("metrics/runway-radius", this, &FGPropagate::GetRunwayRadius, &FGPropagate::SetRunwayRadius);
+
+ PropertyManager->Tie("attitude/phi-rad", this, &FGPropagate::Getphi);
+ PropertyManager->Tie("attitude/theta-rad", this, &FGPropagate::Gettht);
+ PropertyManager->Tie("attitude/psi-rad", this, &FGPropagate::Getpsi);
+
+ PropertyManager->Tie("attitude/roll-rad", this, &FGPropagate::Getphi);
+ PropertyManager->Tie("attitude/pitch-rad", this, &FGPropagate::Gettht);
+ PropertyManager->Tie("attitude/heading-true-rad", this, &FGPropagate::Getpsi);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropagate::unbind(void)
+{
+ PropertyManager->Untie("velocities/v-north-fps");
+ PropertyManager->Untie("velocities/v-east-fps");
+ PropertyManager->Untie("velocities/v-down-fps");
+ PropertyManager->Untie("velocities/h-dot-fps");
+ PropertyManager->Untie("velocities/u-fps");
+ PropertyManager->Untie("velocities/v-fps");
+ PropertyManager->Untie("velocities/w-fps");
+ PropertyManager->Untie("velocities/p-rad_sec");
+ PropertyManager->Untie("velocities/q-rad_sec");
+ PropertyManager->Untie("velocities/r-rad_sec");
+ PropertyManager->Untie("accelerations/udot-fps");
+ PropertyManager->Untie("accelerations/vdot-fps");
+ PropertyManager->Untie("accelerations/wdot-fps");
+ PropertyManager->Untie("accelerations/pdot-rad_sec");
+ PropertyManager->Untie("accelerations/qdot-rad_sec");
+ PropertyManager->Untie("accelerations/rdot-rad_sec");
+ PropertyManager->Untie("position/h-sl-ft");
+ PropertyManager->Untie("position/lat-gc-rad");
+ PropertyManager->Untie("position/long-gc-rad");
+ PropertyManager->Untie("position/h-agl-ft");
+ PropertyManager->Untie("position/radius-to-vehicle-ft");
+ PropertyManager->Untie("metrics/runway-radius");
+ PropertyManager->Untie("attitude/phi-rad");
+ PropertyManager->Untie("attitude/theta-rad");
+ PropertyManager->Untie("attitude/psi-rad");
+ PropertyManager->Untie("attitude/roll-rad");
+ PropertyManager->Untie("attitude/pitch-rad");
+ PropertyManager->Untie("attitude/heading-true-rad");
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// 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 FGPropagate::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: FGPropagate" << endl;
+ if (from == 1) cout << "Destroyed: FGPropagate" << 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;
+ }
+ }
+}
+}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGPropagate.h
+ Author: Jon S. Berndt
+ Date started: 1/5/99
+
+ ------------- 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
+--------------------------------------------------------------------------------
+01/05/99 JSB Created
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGPROPAGATE_H
+#define FGPROPAGATE_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+INCLUDES
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGModel.h"
+#include "FGColumnVector3.h"
+#include "FGInitialCondition.h"
+#include "FGLocation.h"
+#include "FGQuaternion.h"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+DEFINITIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_PROPAGATE "$Id$"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FORWARD DECLARATIONS
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models the EOM and integration/propagation of state
+ @author Jon S. Berndt, Mathias Froehlich
+ @version $Id$
+ */
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DECLARATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+// state vector
+
+struct VehicleState {
+ FGLocation vLocation;
+ FGColumnVector3 vUVW;
+ FGColumnVector3 vPQR;
+ FGQuaternion vQtrn;
+};
+
+class FGPropagate : public FGModel {
+public:
+ /** Constructor
+ @param Executive a pointer to the parent executive object */
+ FGPropagate(FGFDMExec* Executive);
+
+ /// Destructor
+ ~FGPropagate();
+
+ bool InitModel(void);
+
+ /** Runs the Propagate model; called by the Executive
+ @return false if no error */
+ bool Run(void);
+
+ const FGColumnVector3& GetVel(void) const { return vVel; }
+ const FGColumnVector3& GetUVW(void) const { return VState.vUVW; }
+ const FGColumnVector3& GetUVWdot(void) const { return vUVWdot; }
+ const FGColumnVector3& GetPQR(void) const {return VState.vPQR;}
+ const FGColumnVector3& GetPQRdot(void) const {return vPQRdot;}
+ const FGColumnVector3& GetEuler(void) const { return VState.vQtrn.GetEuler(); }
+
+ double GetUVW (int idx) const { return VState.vUVW(idx); }
+ double GetUVWdot(int idx) const { return vUVWdot(idx); }
+ double GetVel(int idx) const { return vVel(idx); }
+ double Geth(void) const { return VState.vLocation.GetRadius() - SeaLevelRadius; }
+ double GetPQR(int axis) const {return VState.vPQR(axis);}
+ double GetPQRdot(int idx) const {return vPQRdot(idx);}
+ double GetEuler(int axis) const { return VState.vQtrn.GetEuler()(axis); }
+ double Gethdot(void) const { return -vVel(eDown); }
+
+ /** Returns the "constant" RunwayRadius.
+ The RunwayRadius parameter is set by the calling application or set to
+ zero if JSBSim is running in standalone mode.
+ @return distance of the runway from the center of the earth.
+ @units feet */
+ double GetRunwayRadius(void) const { return RunwayRadius; }
+ double GetSeaLevelRadius(void) const { return SeaLevelRadius; }
+ double GetDistanceAGL(void) const { return VState.vLocation.GetRadius()-RunwayRadius; }
+ double GetRadius(void) const { return VState.vLocation.GetRadius(); }
+ double GetLongitude(void) const { return VState.vLocation.GetLongitude(); }
+ double GetLatitude(void) const { return VState.vLocation.GetLatitude(); }
+ const FGLocation& GetLocation(void) const { return VState.vLocation; }
+
+ double Getphi(void) const { return VState.vQtrn.GetEulerPhi(); }
+ double Gettht(void) const { return VState.vQtrn.GetEulerTheta(); }
+ double Getpsi(void) const { return VState.vQtrn.GetEulerPsi(); }
+
+ double GetCosphi(void) const { return VState.vQtrn.GetCosEulerPhi(); }
+ double GetCostht(void) const { return VState.vQtrn.GetCosEulerTheta(); }
+ double GetCospsi(void) const { return VState.vQtrn.GetCosEulerPsi(); }
+
+ double GetSinphi(void) const { return VState.vQtrn.GetSinEulerPhi(); }
+ double GetSintht(void) const { return VState.vQtrn.GetSinEulerTheta(); }
+ double GetSinpsi(void) const { return VState.vQtrn.GetSinEulerPsi(); }
+
+ /** Retrieves the local-to-body transformation matrix.
+ @return a reference to the local-to-body transformation matrix. */
+ const FGMatrix33& GetTl2b(void) const { return VState.vQtrn.GetT(); }
+
+ /** Retrieves the body-to-local transformation matrix.
+ @return a reference to the body-to-local matrix. */
+ const FGMatrix33& GetTb2l(void) const { return VState.vQtrn.GetTInv(); }
+
+// SET functions
+
+ void SetLongitude(double lon) { VState.vLocation.SetLongitude(lon); }
+ void SetLatitude(double lat) { VState.vLocation.SetLatitude(lat); }
+ void SetRadius(double r) { VState.vLocation.SetRadius(r); }
+ void SetLocation(const FGLocation& l) { VState.vLocation = l; }
+ void Seth(double tt);
+ void SetRunwayRadius(double tt) { RunwayRadius = tt; }
+ void SetSeaLevelRadius(double tt) { SeaLevelRadius = tt; }
+ void SetDistanceAGL(double tt);
+ void SetInitialState(const FGInitialCondition *);
+
+ void bind(void);
+ void unbind(void);
+
+private:
+
+// state vector
+
+ struct VehicleState VState;
+
+ FGColumnVector3 vVel;
+ FGColumnVector3 vPQRdot;
+ FGColumnVector3 vUVWdot;
+
+ double RunwayRadius, SeaLevelRadius;
+
+ void Debug(int from);
+};
+}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+#endif
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+#include <sstream>
+
#include "FGPropeller.h"
-#include "FGTranslation.h"
-#include "FGRotation.h"
-#include "FGFCS.h"
+#include "FGPropagate.h"
#include "FGAtmosphere.h"
+#include "FGAuxiliary.h"
namespace JSBSim {
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-// This class currently makes certain assumptions when calculating torque and
+// This class currently makes certain assumptions when calculating torque and
// p-factor. That is, that the axis of rotation is the X axis of the aircraft -
-// not just the X-axis of the engine/propeller. This may or may not work for a
+// not just the X-axis of the engine/propeller. This may or may not work for a
// helicopter.
FGPropeller::FGPropeller(FGFDMExec* exec, FGConfigFile* Prop_cfg) : FGThruster(exec)
string token;
int rows, cols;
- MaxPitch = MinPitch = P_Factor = Sense = Pitch = 0.0;
+ MaxPitch = MinPitch = P_Factor = Sense = Pitch = Advance = 0.0;
GearRatio = 1.0;
Name = Prop_cfg->GetValue("NAME");
double FGPropeller::Calculate(double PowerAvailable)
{
double J, C_Thrust, omega;
- double Vel = fdmex->GetTranslation()->GetAeroUVW(eU);
+ double Vel = fdmex->GetAuxiliary()->GetAeroUVW(eU);
double rho = fdmex->GetAtmosphere()->GetDensity();
double RPS = RPM/60.0;
double alpha, beta;
}
if (P_Factor > 0.0001) {
- alpha = fdmex->GetTranslation()->Getalpha();
- beta = fdmex->GetTranslation()->Getbeta();
+ alpha = fdmex->GetAuxiliary()->Getalpha();
+ beta = fdmex->GetAuxiliary()->Getbeta();
SetActingLocationY( GetLocationY() + P_Factor*alpha*Sense);
SetActingLocationZ( GetLocationZ() + P_Factor*beta*Sense);
} else if (P_Factor < 0.000) {
Thrust = C_Thrust*RPS*RPS*Diameter*Diameter*Diameter*Diameter*rho;
omega = RPS*2.0*M_PI;
- // Check for windmilling.
- double radius = Diameter * 0.375; // 75% of radius
- double windmill_cutoff = tan(Pitch * 1.745329E-2) * omega * radius;
- if (Vel > windmill_cutoff)
- Thrust = -Thrust;
-
vFn(1) = Thrust;
// The Ixx value and rotation speed given below are for rotation about the
ExcessTorque = PowerAvailable / omega * GearRatio;
RPM = (RPS + ((ExcessTorque / Ixx) / (2.0 * M_PI)) * deltaT) * 60.0;
- // The friction from the engine should
- // stop it somewhere; I chose an
- // arbitrary point.
+ // The friction from the engine should
+ // stop it somewhere; I chose an
+ // arbitrary point.
if (RPM < 5.0)
RPM = 0;
- vMn = fdmex->GetRotation()->GetPQR()*vH + vTorque*Sense;
+ vMn = fdmex->GetPropagate()->GetPQR()*vH + vTorque*Sense;
return Thrust; // return thrust in pounds
}
double cPReq, RPS = RPM / 60.0;
- double J = fdmex->GetTranslation()->GetAeroUVW(eU) / (Diameter * RPS);
+ double J = fdmex->GetAuxiliary()->GetAeroUVW(eU) / (Diameter * RPS);
double rho = fdmex->GetAtmosphere()->GetDensity();
if (MaxPitch == MinPitch) { // Fixed pitch prop
Pitch = MinPitch;
cPReq = cPower->GetValue(J);
} else { // Variable pitch prop
- double advance = fdmex->GetFCS()->GetPropAdvance(ThrusterNumber);
if (MaxRPM != MinRPM) { // fixed-speed prop
- double rpmReq = MinRPM + (MaxRPM - MinRPM) * advance;
+ double rpmReq = MinRPM + (MaxRPM - MinRPM) * Advance;
double dRPM = rpmReq - RPM;
Pitch -= dRPM / 10;
else if (Pitch > MaxPitch) Pitch = MaxPitch;
} else {
- Pitch = MinPitch + (MaxPitch - MinPitch) * advance;
+ Pitch = MinPitch + (MaxPitch - MinPitch) * Advance;
}
cPReq = cPower->GetValue(J, Pitch);
}
return FGColumnVector3(px, py, pz);
}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGPropeller::GetThrusterLabels(int id)
+{
+ std::ostringstream buf;
+
+ buf << Name << "_Torque[" << id << "], "
+ << Name << "_PFactor_Pitch[" << id << "], "
+ << Name << "_PFactor_Yaw[" << id << "], "
+ << Name << "_Thrust[" << id << "], ";
+ if (IsVPitch())
+ buf << Name << "_Pitch[" << id << "], ";
+ buf << Name << "_RPM[" << id << "]";
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGPropeller::GetThrusterValues(int id)
+{
+ std::ostringstream buf;
+
+ FGColumnVector3 vPFactor = GetPFactor();
+ buf << vTorque(eX) << ", "
+ << vPFactor(ePitch) << ", "
+ << vPFactor(eYaw) << ", "
+ << Thrust << ", ";
+ if (IsVPitch())
+ buf << Pitch << ", ";
+ buf << RPM;
+
+ return buf.str();
+}
+
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
@param pitch the pitch of the blade in degrees. */
void SetPitch(double pitch) {Pitch = pitch;}
+ void SetAdvance(double advance) {Advance = advance;}
+
/// Sets the P-Factor constant
void SetPFactor(double pf) {P_Factor = pf;}
/// Retrieves the pitch of the propeller in degrees.
double GetPitch(void) { return Pitch; }
-
+
/// Retrieves the RPMs of the propeller
double GetRPM(void) { return RPM; }
-
+
/// Retrieves the propeller moment of inertia
double GetIxx(void) { return Ixx; }
-
+
/// Retrieves the Torque in foot-pounds (Don't you love the English system?)
double GetTorque(void) { return vTorque(eX); }
-
+
/** Retrieves the power required (or "absorbed") by the propeller -
i.e. the power required to keep spinning the propeller at the current
velocity, air density, and rotational rate. */
double GetPowerRequired(void);
-
+
/** Calculates and returns the thrust produced by this propeller.
Given the excess power available from the engine (in foot-pounds), the thrust is
calculated, as well as the current RPM. The RPM is calculated by integrating
@return the thrust in pounds */
double Calculate(double PowerAvailable);
FGColumnVector3 GetPFactor(void);
+ string GetThrusterLabels(int id);
+ string GetThrusterValues(int id);
private:
int numBlades;
double P_Factor;
double Sense;
double Pitch;
+ double Advance;
double ExcessTorque;
FGColumnVector3 vTorque;
FGTable *cThrust;
Module: FGPropulsion.cpp
Author: Jon S. Berndt
Date started: 08/20/00
- Purpose: Encapsulates the set of engines, tanks, and thrusters associated
+ Purpose: Encapsulates the set of engines and tanks associated
with this aircraft
------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.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:
+comprised of engines and tanks. 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.
+2) 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.
+At Run time each engines Calculate() method is called.
HISTORY
--------------------------------------------------------------------------------
#include "FGPropulsion.h"
#include "FGRocket.h"
-#include "FGSimTurbine.h"
#include "FGTurbine.h"
-#include "FGPropeller.h"
-#include "FGNozzle.h"
#include "FGPiston.h"
+#include "FGElectric.h"
#include "FGPropertyManager.h"
-#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
-
namespace JSBSim {
static const char *IdSrc = "$Id$";
Name = "FGPropulsion";
numSelectedFuelTanks = numSelectedOxiTanks = 0;
- numTanks = numEngines = numThrusters = 0;
+ numTanks = numEngines = 0;
numOxiTanks = numFuelTanks = 0;
- dt = 0.0;
ActiveEngine = -1; // -1: ALL, 0: Engine 1, 1: Engine 2 ...
tankJ.InitMatrix();
+ refuel = false;
bind();
bool FGPropulsion::Run(void)
{
- double PowerAvailable;
- dt = State->Getdt();
+ if (FGModel::Run()) return true;
+
+ double dt = State->Getdt();
vForces.InitMatrix();
vMoments.InitMatrix();
- if (!FGModel::Run()) {
- for (unsigned int i=0; i<numEngines; i++) {
- Thrusters[i]->SetdeltaT(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;
+ for (unsigned int i=0; i<numEngines; i++) {
+ Engines[i]->Calculate();
+ vForces += Engines[i]->GetBodyForces(); // sum body frame forces
+ vMoments += Engines[i]->GetMoments(); // sum body frame moments
}
+
+ for (unsigned int i=0; i<numTanks; i++) {
+ Tanks[i]->Calculate( dt * rate );
+ }
+
+ if (refuel) DoRefuel( dt * rate );
+
+ return false;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGPropulsion::GetSteadyState(void)
{
- double PowerAvailable;
double currentThrust = 0, lastThrust=-1;
- dt = State->Getdt();
int steady_count,j=0;
bool steady=false;
if (!FGModel::Run()) {
for (unsigned int i=0; i<numEngines; i++) {
Engines[i]->SetTrimMode(true);
- Thrusters[i]->SetdeltaT(dt*rate);
steady=false;
steady_count=0;
while (!steady && j < 6000) {
- PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired());
+ Engines[i]->Calculate();
lastThrust = currentThrust;
- currentThrust = Thrusters[i]->Calculate(PowerAvailable);
+ currentThrust = Engines[i]->GetThrust();
if (fabs(lastThrust-currentThrust) < 0.0001) {
steady_count++;
if (steady_count > 120) { steady=true; }
}
j++;
}
- vForces += Thrusters[i]->GetBodyForces(); // sum body frame forces
- vMoments += Thrusters[i]->GetMoments(); // sum body frame moments
+ vForces += Engines[i]->GetBodyForces(); // sum body frame forces
+ vMoments += Engines[i]->GetMoments(); // sum body frame moments
Engines[i]->SetTrimMode(false);
}
bool FGPropulsion::ICEngineStart(void)
{
- double PowerAvailable;
int j;
- dt = State->Getdt();
vForces.InitMatrix();
vMoments.InitMatrix();
for (unsigned int i=0; i<numEngines; i++) {
Engines[i]->SetTrimMode(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);
+ Engines[i]->Calculate();
j++;
}
- vForces += Thrusters[i]->GetBodyForces(); // sum body frame forces
- vMoments += Thrusters[i]->GetMoments(); // sum body frame moments
+ vForces += Engines[i]->GetBodyForces(); // sum body frame forces
+ vMoments += Engines[i]->GetMoments(); // sum body frame moments
Engines[i]->SetTrimMode(false);
}
return true;
bool FGPropulsion::Load(FGConfigFile* AC_cfg)
{
- string token, fullpath;
+ string token, fullpath, localpath;
string engineFileName, engType;
- string thrusterFileName, thrType;
string parameter;
string enginePath = FDMExec->GetEnginePath();
+ string aircraftPath = FDMExec->GetAircraftPath();
double xLoc, yLoc, zLoc, Pitch, Yaw;
- double P_Factor = 0, Sense = 0.0;
int Feed;
bool ThrottleAdded = false;
+ FGConfigFile* Cfg_ptr = 0;
# ifndef macintosh
fullpath = enginePath + "/";
+ localpath = aircraftPath + "/Engines/";
# else
fullpath = enginePath + ";";
+ localpath = aircraftPath + ";Engines;";
# endif
AC_cfg->GetNextConfigLine();
engineFileName = AC_cfg->GetValue("FILE");
- if (debug_lvl > 0) cout << "\n Reading engine from file: " << fullpath
- + engineFileName + ".xml"<< endl;
+ // Look in the Aircraft/Engines directory first
+ Cfg_ptr = 0;
+ FGConfigFile Local_cfg(localpath + engineFileName + ".xml");
FGConfigFile Eng_cfg(fullpath + engineFileName + ".xml");
+ if (Local_cfg.IsOpen()) {
+ Cfg_ptr = &Local_cfg;
+ if (debug_lvl > 0) cout << "\n Reading engine from file: " << localpath
+ + engineFileName + ".xml"<< endl;
+ } else {
+ if (Eng_cfg.IsOpen()) {
+ Cfg_ptr = &Eng_cfg;
+ if (debug_lvl > 0) cout << "\n Reading engine from file: " << fullpath
+ + engineFileName + ".xml"<< endl;
+ }
+ }
- if (Eng_cfg.IsOpen()) {
- Eng_cfg.GetNextConfigLine();
- engType = Eng_cfg.GetValue();
+ if (Cfg_ptr) {
+ Cfg_ptr->GetNextConfigLine();
+ engType = Cfg_ptr->GetValue();
FCS->AddThrottle();
ThrottleAdded = true;
if (engType == "FG_ROCKET") {
- Engines.push_back(new FGRocket(FDMExec, &Eng_cfg));
+ Engines.push_back(new FGRocket(FDMExec, Cfg_ptr));
} else if (engType == "FG_PISTON") {
- Engines.push_back(new FGPiston(FDMExec, &Eng_cfg));
+ Engines.push_back(new FGPiston(FDMExec, Cfg_ptr));
} else if (engType == "FG_TURBINE") {
- Engines.push_back(new FGTurbine(FDMExec, &Eng_cfg));
+ Engines.push_back(new FGTurbine(FDMExec, Cfg_ptr));
} else if (engType == "FG_SIMTURBINE") {
- Engines.push_back(new FGSimTurbine(FDMExec, &Eng_cfg));
+ cerr << endl;
+ cerr << "The FG_SIMTURBINE engine type has been renamed to FG_TURBINE." << endl;
+ cerr << "To fix this problem, simply replace the FG_SIMTURBINE name " << endl;
+ cerr << "in your engine file to FG_TURBINE." << endl;
+ cerr << endl;
+ Engines.push_back(new FGTurbine(FDMExec, Cfg_ptr));
+ } else if (engType == "FG_ELECTRIC") {
+ Engines.push_back(new FGElectric(FDMExec, Cfg_ptr));
} else {
cerr << fgred << " Unrecognized engine type: " << underon << engType
<< underoff << " found in config file." << fgdef << endl;
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 == "YAW") { *AC_cfg >> Yaw; }
+ else if (token.find("AC_THRUSTER") != string::npos) {
+ if (debug_lvl > 0) cout << "\n Reading thruster definition" << endl;
+ Engines.back()->LoadThruster(AC_cfg);
+ AC_cfg->GetNextConfigLine();
+ }
else if (token == "FEED") {
*AC_cfg >> Feed;
Engines[numEngines]->AddFeedTank(Feed);
} else {
cerr << fgred << "\n Could not read engine config file: " << underon <<
- fullpath + engineFileName + ".xml" << underoff << fgdef << endl;
+ 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));
+ Tanks.push_back(new FGTank(AC_cfg, FDMExec));
switch(Tanks[numTanks]->GetType()) {
case FGTank::ttFUEL:
numSelectedFuelTanks++;
}
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 ));
- } else if (thrType == "FG_DIRECT") {
- Thrusters.push_back(new FGThruster( 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();
}
{
string PropulsionStrings = "";
bool firstime = true;
- char buffer[5];
for (unsigned int i=0;i<Engines.size();i++) {
if (firstime) firstime = false;
else PropulsionStrings += ", ";
- sprintf(buffer, "%d", i);
-
- switch(Engines[i]->GetType()) {
- case FGEngine::etPiston:
- PropulsionStrings += (Engines[i]->GetName() + "_PwrAvail[" + buffer + "]");
- break;
- case FGEngine::etRocket:
- PropulsionStrings += (Engines[i]->GetName() + "_ChamberPress[" + buffer + "]");
- break;
- case FGEngine::etTurbine:
- break;
- case FGEngine::etSimTurbine:
- PropulsionStrings += (Engines[i]->GetName() + "_N1[" + buffer + "], ");
- PropulsionStrings += (Engines[i]->GetName() + "_N2[" + buffer + "]");
- 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;
- case FGThruster::ttDirect:
- PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "]");
- break;
- default:
- PropulsionStrings += "INVALID THRUSTER TYPE";
- break;
- }
+ PropulsionStrings += Engines[i]->GetEngineLabels() + ", ";
}
return PropulsionStrings;
string FGPropulsion::GetPropulsionValues(void)
{
- char buff[20];
string PropulsionValues = "";
bool firstime = true;
if (firstime) firstime = false;
else PropulsionValues += ", ";
- switch(Engines[i]->GetType()) {
- 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::etTurbine:
- break;
- case FGEngine::etSimTurbine:
- PropulsionValues += (string(gcvt(((FGSimTurbine*)Engines[i])->GetN1(), 10, buff))) + ", ";
- PropulsionValues += (string(gcvt(((FGSimTurbine*)Engines[i])->GetN2(), 10, buff)));
- 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::ttDirect:
- PropulsionValues += (string(gcvt(((FGThruster*)Thrusters[i])->GetThrust(), 10, buff)));
- 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;
- }
+ PropulsionValues += Engines[i]->GetEngineValues() + ", ";
}
return PropulsionValues;
if (ActiveEngine < 0) {
for (unsigned i=0; i<Engines.size(); i++) {
if (setting == 0)
- ((FGSimTurbine*)Engines[i])->SetCutoff(false);
+ ((FGTurbine*)Engines[i])->SetCutoff(false);
else
- ((FGSimTurbine*)Engines[i])->SetCutoff(true);
+ ((FGTurbine*)Engines[i])->SetCutoff(true);
}
} else {
if (setting == 0)
- ((FGSimTurbine*)Engines[ActiveEngine])->SetCutoff(false);
+ ((FGTurbine*)Engines[ActiveEngine])->SetCutoff(false);
else
- ((FGSimTurbine*)Engines[ActiveEngine])->SetCutoff(true);
+ ((FGTurbine*)Engines[ActiveEngine])->SetCutoff(true);
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+double FGPropulsion::Transfer(int source, int target, double amount)
+{
+ double shortage, overage;
+
+ if (source == -1) {
+ shortage = 0.0;
+ } else {
+ shortage = Tanks[source]->Drain(amount);
+ }
+ if (target == -1) {
+ overage = 0.0;
+ } else {
+ overage = Tanks[target]->Fill(amount - shortage);
+ }
+ return overage;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGPropulsion::DoRefuel(double time_slice)
+{
+ double fillrate = 100 * time_slice; // 100 lbs/sec = 6000 lbs/min
+ int TanksNotFull = 0;
+
+ for (unsigned int i=0; i<numTanks; i++) {
+ if (Tanks[i]->GetPctFull() < 99.99) ++TanksNotFull;
+ }
+
+ if (TanksNotFull) {
+ for (unsigned int i=0; i<numTanks; i++) {
+ if (Tanks[i]->GetPctFull() < 99.99)
+ Transfer(-1, i, fillrate/TanksNotFull);
+ }
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
void FGPropulsion::bind(void)
{
typedef double (FGPropulsion::*PMF)(int) const;
#include "FGModel.h"
#include "FGEngine.h"
#include "FGTank.h"
-#include "FGThruster.h"
#include "FGMatrix33.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/** Propulsion management class.
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:
+ comprised of engines, and tanks. Once the Propulsion class gets the config file,
+ it reads in information which is specific to a type of engine. Then:
-# The appropriate engine type instance is created
- -# A thruster object is instantiated, and is linked to the engine
-# 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.
+ At Run time each engines Calculate() method is called.
@author Jon S. Berndt
@version $Id$
@see
FGEngine
FGTank
- FGThruster
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/** Executes the propulsion model.
The initial plan for the FGPropulsion class calls for Run() to be executed,
- performing the following tasks:
- <ol>
- <li>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()</li>
- <li>Given 1, above, calculate the power available from the engine. This is
- done by calling FGEngine::CalculatePAvail()</li>
- <li>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().</li></ol>
+ calculating the power available from the engine.
[Note: Should we be checking the Starved flag here?] */
bool Run(void);
- /** Loads the propulsion system (engine[s], tank[s], thruster[s]).
+ /** Loads the propulsion system (engine[s] and tank[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.
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) */
+ /** Loops the engines until thrust output steady (used for trimming) */
bool GetSteadyState(void);
/** starts the engines in IC mode (dt=0). All engine-specific setup must
inline FGColumnVector3& GetMoments(void) {return vMoments;}
inline double GetMoments(int n) const {return vMoments(n);}
+ inline bool GetRefuel(void) {return refuel;}
+ inline void SetRefuel(bool setting) {refuel = setting;}
+ double Transfer(int source, int target, double amount);
+ void DoRefuel(double time_slice);
+
FGColumnVector3& GetTanksMoment(void);
double GetTanksWeight(void);
vector <FGEngine*> Engines;
vector <FGTank*> Tanks;
vector <FGTank*>::iterator iTank;
- vector <FGThruster*> 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 vTankXYZ;
FGColumnVector3 vXYZtank_arm;
FGMatrix33 tankJ;
+ bool refuel;
+
void Debug(int from);
};
}
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Module: FGQuaternion.cpp
+ Author: Jon Berndt, Mathias Froehlich
+ Date started: 12/02/98
+
+ ------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------------
+ ------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
+
+ 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
+-------------------------------------------------------------------------------
+12/02/98 JSB Created
+15/01/04 Mathias Froehlich implemented a quaternion class from many places
+ in JSBSim.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ INCLUDES
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifdef FGFS
+# include <math.h>
+# include <simgear/compiler.h>
+# include STL_IOSTREAM
+ SG_USING_STD(cerr);
+ SG_USING_STD(cout);
+ SG_USING_STD(endl);
+#else
+# include <string>
+# if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
+# include <iostream.h>
+# include <math.h>
+# else
+# include <iostream>
+# if defined(sgi) && !defined(__GNUC__)
+# include <math.h>
+# else
+# include <cmath>
+# endif
+ using std::cerr;
+ using std::cout;
+ using std::endl;
+# endif
+#endif
+
+#include "FGMatrix33.h"
+#include "FGColumnVector3.h"
+
+#include "FGQuaternion.h"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ DEFINITIONS
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+namespace JSBSim {
+
+static const char *IdSrc = "$Id$";
+static const char *IdHdr = ID_QUATERNION;
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+// Initialize from q
+FGQuaternion::FGQuaternion(const FGQuaternion& q)
+ : mCacheValid(q.mCacheValid) {
+ Entry(1) = q(1);
+ Entry(2) = q(2);
+ Entry(3) = q(3);
+ Entry(4) = q(4);
+ if (mCacheValid) {
+ mT = q.mT;
+ mTInv = q.mTInv;
+ mEulerAngles = q.mEulerAngles;
+ mEulerSines = q.mEulerSines;
+ mEulerCosines = q.mEulerCosines;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+// Initialize with the three euler angles
+FGQuaternion::FGQuaternion(double phi, double tht, double psi)
+ : mCacheValid(false) {
+ double thtd2 = 0.5*tht;
+ double psid2 = 0.5*psi;
+ double phid2 = 0.5*phi;
+
+ double Sthtd2 = sin(thtd2);
+ double Spsid2 = sin(psid2);
+ double Sphid2 = sin(phid2);
+
+ double Cthtd2 = cos(thtd2);
+ double Cpsid2 = cos(psid2);
+ double Cphid2 = cos(phid2);
+
+ double Cphid2Cthtd2 = Cphid2*Cthtd2;
+ double Cphid2Sthtd2 = Cphid2*Sthtd2;
+ double Sphid2Sthtd2 = Sphid2*Sthtd2;
+ double Sphid2Cthtd2 = Sphid2*Cthtd2;
+
+ Entry(1) = Cphid2Cthtd2*Cpsid2 + Sphid2Sthtd2*Spsid2;
+ Entry(2) = Sphid2Cthtd2*Cpsid2 - Cphid2Sthtd2*Spsid2;
+ Entry(3) = Cphid2Sthtd2*Cpsid2 + Sphid2Cthtd2*Spsid2;
+ Entry(4) = Cphid2Cthtd2*Spsid2 - Sphid2Sthtd2*Cpsid2;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+/**
+ Returns the derivative of the quaternion coresponding to the
+ angular velocities PQR.
+*/
+FGQuaternion FGQuaternion::GetQDot(const FGColumnVector3& PQR) const {
+ FGQuaternion QDot;
+ QDot(1) = -0.5*(Entry(2)*PQR(eP) + Entry(3)*PQR(eQ) + Entry(4)*PQR(eR));
+ QDot(2) = 0.5*(Entry(1)*PQR(eP) + Entry(3)*PQR(eR) - Entry(4)*PQR(eQ));
+ QDot(3) = 0.5*(Entry(1)*PQR(eQ) + Entry(4)*PQR(eP) - Entry(2)*PQR(eR));
+ QDot(4) = 0.5*(Entry(1)*PQR(eR) + Entry(2)*PQR(eQ) - Entry(3)*PQR(eP));
+ return QDot;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGQuaternion::Normalize()
+{
+ // Note: this does not touch the cache
+ // since it does not change the orientation ...
+
+ double norm = Magnitude();
+ if (norm == 0.0)
+ return;
+
+ double rnorm = 1.0/norm;
+ Entry(1) *= rnorm;
+ Entry(2) *= rnorm;
+ Entry(3) *= rnorm;
+ Entry(4) *= rnorm;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+// Compute the derived values if required ...
+void FGQuaternion::ComputeDerivedUnconditional(void) const
+{
+ mCacheValid = true;
+
+ // First normalize the 4-vector
+ double norm = Magnitude();
+ if (norm == 0.0)
+ return;
+
+ double rnorm = 1.0/norm;
+ double q1 = rnorm*Entry(1);
+ double q2 = rnorm*Entry(2);
+ double q3 = rnorm*Entry(3);
+ double q4 = rnorm*Entry(4);
+
+ // Now compute the transformation matrix.
+ double q1q1 = q1*q1;
+ double q2q2 = q2*q2;
+ double q3q3 = q3*q3;
+ double q4q4 = q4*q4;
+ double q1q2 = q1*q2;
+ double q1q3 = q1*q3;
+ double q1q4 = q1*q4;
+ double q2q3 = q2*q3;
+ double q2q4 = q2*q4;
+ double q3q4 = q3*q4;
+
+ mT(1,1) = q1q1 + q2q2 - q3q3 - q4q4;
+ mT(1,2) = 2.0*(q2q3 + q1q4);
+ mT(1,3) = 2.0*(q2q4 - q1q3);
+ mT(2,1) = 2.0*(q2q3 - q1q4);
+ mT(2,2) = q1q1 - q2q2 + q3q3 - q4q4;
+ mT(2,3) = 2.0*(q3q4 + q1q2);
+ mT(3,1) = 2.0*(q2q4 + q1q3);
+ mT(3,2) = 2.0*(q3q4 - q1q2);
+ mT(3,3) = q1q1 - q2q2 - q3q3 + q4q4;
+ // Since this is an orthogonal matrix, the inverse is simply
+ // the transpose.
+ mTInv = mT;
+ mTInv.T();
+
+ // Compute the Euler-angles
+ if (mT(3,3) == 0.0)
+ mEulerAngles(ePhi) = 0.5*M_PI;
+ else
+ mEulerAngles(ePhi) = atan2(mT(2,3), mT(3,3));
+
+ if (mT(1,3) < -1.0)
+ mEulerAngles(eTht) = 0.5*M_PI;
+ else if (1.0 < mT(1,3))
+ mEulerAngles(eTht) = -0.5*M_PI;
+ else
+ mEulerAngles(eTht) = asin(-mT(1,3));
+
+ if (mT(1,1) == 0.0)
+ mEulerAngles(ePsi) = 0.5*M_PI;
+ else {
+ double psi = atan2(mT(1,2), mT(1,1));
+ if (psi < 0.0)
+ psi += 2*M_PI;
+ mEulerAngles(ePsi) = psi;
+ }
+
+ // FIXME: may be one can compute those values easier ???
+ mEulerSines(ePhi) = sin(mEulerAngles(ePhi));
+ // mEulerSines(eTht) = sin(mEulerAngles(eTht));
+ mEulerSines(eTht) = -mT(1,3);
+ mEulerSines(ePsi) = sin(mEulerAngles(ePsi));
+ mEulerCosines(ePhi) = cos(mEulerAngles(ePhi));
+ mEulerCosines(eTht) = cos(mEulerAngles(eTht));
+ mEulerCosines(ePsi) = cos(mEulerAngles(ePsi));
+}
+
+} // namespace JSBSim
--- /dev/null
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+ Header: FGQuaternion.h
+ Author: Jon Berndt, Mathis Froehlich
+ Date started: 12/02/98
+
+ ------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------------
+ ------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
+
+ 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
+-------------------------------------------------------------------------------
+12/02/98 JSB Created
+15/01/04 MF Quaternion class from old FGColumnVector4
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+SENTRY
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#ifndef FGQUATERNION_H
+#define FGQUATERNION_H
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ INCLUDES
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#include "FGJSBBase.h"
+#include "FGMatrix33.h"
+#include "FGColumnVector3.h"
+#include "FGPropertyManager.h"
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ DEFINITIONS
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+#define ID_QUATERNION "$Id$"
+
+namespace JSBSim {
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ CLASS DOCUMENTATION
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** Models the Quaternion representation of rotations.
+ FGQuaternion is a representation of an arbitrary rotation through a
+ quaternion. It has vector properties. This class also contains access
+ functions to the euler angle representation of rotations and access to
+ transformation matrices for 3D vectors. Transformations and euler angles are
+ therefore computed once they are requested for the first time. Then they are
+ cached for later usage as long as the class is not accessed trough
+ a nonconst member function.
+
+ Note: The order of rotations used in this class corresponds to a 3-2-1 sequence,
+ or Y-P-R, or Z-Y-X, if you prefer.
+
+ @see Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
+ Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
+ School, January 1994
+ @see D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
+ JSC 12960, July 1977
+ @see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
+ NASA-Ames", NASA CR-2497, January 1975
+ @see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
+ Wiley & Sons, 1979 ISBN 0-471-03032-5
+ @see Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
+ 1982 ISBN 0-471-08936-2
+ @author Mathias Froehlich, extended FGColumnVector4 originally by Tony Peden
+ and Jon Berndt
+*/
+
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+ CLASS DECLARATION
+ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+class FGQuaternion
+ : virtual FGJSBBase {
+public:
+ /** Default initializer.
+ Default initializer, initializes the class with the identity rotation. */
+ FGQuaternion() : mCacheValid(false) {
+ Entry(1) = 1.0;
+ Entry(2) = Entry(3) = Entry(4) = 0.0;
+ }
+
+ /** Copy constructor.
+ Copy constructor, initializes the quaternion.
+ @param q a constant reference to another FGQuaternion instance */
+ FGQuaternion(const FGQuaternion& q);
+
+ /** Initializer by euler angles.
+ Initialize the quaternion with the euler angles.
+ @param phi The euler X axis (roll) angle in radians
+ @param tht The euler Y axis (attitude) angle in radians
+ @param psi The euler Z axis (heading) angle in radians */
+ FGQuaternion(double phi, double tht, double psi);
+
+ /// Destructor.
+ ~FGQuaternion() {}
+
+ /** Quaternion 'velocity' for given angular rates.
+ Computes the quaternion derivative which results from the given
+ angular velocities
+ @param PQR a constant reference to the body rate vector
+ @return the quaternion derivative */
+ FGQuaternion GetQDot(const FGColumnVector3& PQR) const;
+
+ /** Transformation matrix.
+ @return a reference to the transformation/rotation matrix
+ corresponding to this quaternion rotation. */
+ const FGMatrix33& GetT() const { ComputeDerived(); return mT; }
+
+ /** Backward transformation matrix.
+ @return a reference to the inverse transformation/rotation matrix
+ corresponding to this quaternion rotation. */
+ const FGMatrix33& GetTInv() const { ComputeDerived(); return mTInv; }
+
+ /** Retrieves the Euler angles.
+ @return a reference to the triad of euler angles corresponding
+ to this quaternion rotation.
+ @units radians */
+ const FGColumnVector3& GetEuler() const {
+ ComputeDerived();
+ return mEulerAngles;
+ }
+
+ /** Euler angle theta.
+ @return the euler angle theta (pitch attitude) corresponding to this
+ quaternion rotation.
+ @units radians */
+ double GetEulerTheta() const {
+ ComputeDerived();
+ return mEulerAngles(eTht);
+ }
+
+ /** Euler angle theta.
+ @return the euler angle theta (pitch attitude) corresponding to
+ this quaternion rotation.
+ @units degrees */
+ double GetEulerThetaDeg() const {
+ ComputeDerived();
+ return radtodeg*mEulerAngles(eTht);
+ }
+
+ /** Euler angle psi.
+ @return the heading euler angle (psi) corresponding to this quaternion
+ rotation.
+ @units radians */
+ double GetEulerPsi() const {
+ ComputeDerived();
+ return mEulerAngles(ePsi);
+ }
+
+ /** Retrieves the heading angle.
+ @return the Euler angle psi (heading) corresponding to this quaternion
+ rotation.
+ @units degrees */
+ double GetEulerPsiDeg() const {
+ ComputeDerived();
+ return radtodeg*mEulerAngles(ePsi);
+ }
+
+ /** Retrieves the roll angle.
+ @return the euler angle phi (roll) corresponding to this quaternion
+ rotation.
+ @units radians */
+ double GetEulerPhi() const {
+ ComputeDerived();
+ return mEulerAngles(ePhi);
+ }
+
+ /** Retrieves the roll angle.
+ Returns the Euler angle phi (roll) corresponding to this quaternion rotation.
+ @units degrees */
+ double GetEulerPhiDeg() const {
+ ComputeDerived();
+ return radtodeg*mEulerAngles(ePhi);
+ }
+
+ /** Retrieves sine theta.
+ @return the sine of the Euler angle theta (pitch attitude) corresponding
+ to this quaternion rotation. */
+ double GetSinEulerTheta() const {
+ ComputeDerived();
+ return mEulerSines(eTht);
+ }
+
+ /** Retrieves sine psi.
+ @return the sine of the Euler angle psi (heading) corresponding to this
+ quaternion rotation. */
+ double GetSinEulerPsi() const {
+ ComputeDerived();
+ return mEulerSines(ePsi);
+ }
+
+ /** Sine of euler angle phi.
+ @return the sine of the Euler angle phi (roll) corresponding to this
+ quaternion rotation. */
+ double GetSinEulerPhi() const {
+ ComputeDerived();
+ return mEulerSines(ePhi);
+ }
+
+ /** Cosine of euler angle theta.
+ @return the cosine of the Euler angle theta (pitch) corresponding to this
+ quaternion rotation. */
+ double GetCosEulerTheta() const {
+ ComputeDerived();
+ return mEulerCosines(eTht);
+ }
+
+ /** Cosine of euler angle psi.
+ @return the cosine of the Euler angle psi (heading) corresponding to this
+ quaternion rotation. */
+ double GetCosEulerPsi() const {
+ ComputeDerived();
+ return mEulerCosines(ePsi);
+ }
+
+ /** Cosine of euler angle phi.
+ @return the cosine of the Euler angle phi (roll) corresponding to this
+ quaternion rotation. */
+ double GetCosEulerPhi() const {
+ ComputeDerived();
+ return mEulerCosines(ePhi);
+ }
+
+ /** Read access the entries of the vector.
+
+ @param idx the component index.
+
+ Return the value of the matrix entry at the given index.
+ Indices are counted starting with 1.
+
+ Note that the index given in the argument is unchecked.
+ */
+ double operator()(unsigned int idx) const { return Entry(idx); }
+
+ /** Write access the entries of the vector.
+
+ @param idx the component index.
+
+ Return a reference to the vector entry at the given index.
+ Indices are counted starting with 1.
+
+ Note that the index given in the argument is unchecked.
+ */
+ double& operator()(unsigned int idx) { return Entry(idx); }
+
+ /** Read access the entries of the vector.
+
+ @param idx the component index.
+
+ Return the value of the matrix entry at the given index.
+ Indices are counted starting with 1.
+
+ This function is just a shortcut for the @ref double
+ operator()(unsigned int idx) const function. It is
+ used internally to access the elements in a more convenient way.
+
+ Note that the index given in the argument is unchecked.
+ */
+ double Entry(unsigned int idx) const { return mData[idx-1]; }
+
+ /** Write access the entries of the vector.
+
+ @param idx the component index.
+
+ Return a reference to the vector entry at the given index.
+ Indices are counted starting with 1.
+
+ This function is just a shortcut for the @ref double&
+ operator()(unsigned int idx) function. It is
+ used internally to access the elements in a more convenient way.
+
+ Note that the index given in the argument is unchecked.
+ */
+ double& Entry(unsigned int idx) { mCacheValid = false; return mData[idx-1]; }
+
+ /** Assignment operator "=".
+ Assign the value of q to the current object. Cached values are
+ conserved.
+ @param q reference to an FGQuaternion instance
+ @return reference to a quaternion object */
+ const FGQuaternion& operator=(const FGQuaternion& q) {
+ // Copy the master values ...
+ Entry(1) = q(1);
+ Entry(2) = q(2);
+ Entry(3) = q(3);
+ Entry(4) = q(4);
+ // .. and copy the derived values if they are valid
+ mCacheValid = q.mCacheValid;
+ if (mCacheValid) {
+ mT = q.mT;
+ mTInv = q.mTInv;
+ mEulerAngles = q.mEulerAngles;
+ mEulerSines = q.mEulerSines;
+ mEulerCosines = q.mEulerCosines;
+ }
+ return *this;
+ }
+
+ /** Comparison operator "==".
+ @param q a quaternion reference
+ @return true if both quaternions represent the same rotation. */
+ bool operator==(const FGQuaternion& q) const {
+ return Entry(1) == q(1) && Entry(2) == q(2)
+ && Entry(3) == q(3) && Entry(4) == q(4);
+ }
+
+ /** Comparison operator "!=".
+ @param q a quaternion reference
+ @return true if both quaternions do not represent the same rotation. */
+ bool operator!=(const FGQuaternion& q) const { return ! operator==(q); }
+ const FGQuaternion& operator+=(const FGQuaternion& q) {
+ // Copy the master values ...
+ Entry(1) += q(1);
+ Entry(2) += q(2);
+ Entry(3) += q(3);
+ Entry(4) += q(4);
+ mCacheValid = false;
+ return *this;
+ }
+
+ /** Arithmetic operator "-=".
+ @param q a quaternion reference.
+ @return a quaternion reference representing Q, where Q = Q - q. */
+ const FGQuaternion& operator-=(const FGQuaternion& q) {
+ // Copy the master values ...
+ Entry(1) -= q(1);
+ Entry(2) -= q(2);
+ Entry(3) -= q(3);
+ Entry(4) -= q(4);
+ mCacheValid = false;
+ return *this;
+ }
+
+ /** Arithmetic operator "*=".
+ @param scalar a multiplicative value.
+ @return a quaternion reference representing Q, where Q = Q * scalar. */
+ const FGQuaternion& operator*=(double scalar) {
+ Entry(1) *= scalar;
+ Entry(2) *= scalar;
+ Entry(3) *= scalar;
+ Entry(4) *= scalar;
+ mCacheValid = false;
+ return *this;
+ }
+
+ /** Arithmetic operator "/=".
+ @param scalar a divisor value.
+ @return a quaternion reference representing Q, where Q = Q / scalar. */
+ const FGQuaternion& operator/=(double scalar) {
+ return operator*=(1.0/scalar);
+ }
+
+ /** Arithmetic operator "+".
+ @param q a quaternion to be summed.
+ @return a quaternion representing Q, where Q = Q + q. */
+ FGQuaternion operator+(const FGQuaternion& q) const {
+ return FGQuaternion(Entry(1)+q(1), Entry(2)+q(2),
+ Entry(3)+q(3), Entry(4)+q(4));
+ }
+
+ /** Arithmetic operator "-".
+ @param q a quaternion to be subtracted.
+ @return a quaternion representing Q, where Q = Q - q. */
+ FGQuaternion operator-(const FGQuaternion& q) const {
+ return FGQuaternion(Entry(1)-q(1), Entry(2)-q(2),
+ Entry(3)-q(3), Entry(4)-q(4));
+ }
+
+ /** Arithmetic operator "*".
+ Multiplication of two quaternions is like performing successive rotations.
+ @param q a quaternion to be multiplied.
+ @return a quaternion representing Q, where Q = Q * q. */
+ FGQuaternion operator*(const FGQuaternion& q) const {
+ return FGQuaternion(Entry(1)*q(1)-Entry(2)*q(2)-Entry(3)*q(3)-Entry(4)*q(4),
+ Entry(1)*q(2)+Entry(2)*q(1)+Entry(3)*q(4)-Entry(4)*q(3),
+ Entry(1)*q(3)-Entry(2)*q(4)+Entry(3)*q(1)+Entry(4)*q(2),
+ Entry(1)*q(4)+Entry(2)*q(3)-Entry(3)*q(2)+Entry(4)*q(1));
+ }
+
+ /** Arithmetic operator "*=".
+ Multiplication of two quaternions is like performing successive rotations.
+ @param q a quaternion to be multiplied.
+ @return a quaternion reference representing Q, where Q = Q * q. */
+ const FGQuaternion& operator*=(const FGQuaternion& q) {
+ double q0 = Entry(1)*q(1)-Entry(2)*q(2)-Entry(3)*q(3)-Entry(4)*q(4);
+ double q1 = Entry(1)*q(2)+Entry(2)*q(1)+Entry(3)*q(4)-Entry(4)*q(3);
+ double q2 = Entry(1)*q(3)-Entry(2)*q(4)+Entry(3)*q(1)+Entry(4)*q(2);
+ double q3 = Entry(1)*q(4)+Entry(2)*q(3)-Entry(3)*q(2)+Entry(4)*q(1);
+ Entry(1) = q0;
+ Entry(2) = q1;
+ Entry(3) = q2;
+ Entry(4) = q3;
+ mCacheValid = false;
+ return *this;
+ }
+
+ friend FGQuaternion operator*(double, const FGQuaternion&);
+
+ /** Length of the vector.
+
+ Compute and return the euclidean norm of this vector.
+ */
+ double Magnitude() const { return sqrt(SqrMagnitude()); }
+
+ /** Square of the length of the vector.
+
+ Compute and return the square of the euclidean norm of this vector.
+ */
+ double SqrMagnitude() const {
+ return Entry(1)*Entry(1)+Entry(2)*Entry(2)
+ +Entry(3)*Entry(3)+Entry(4)*Entry(4);
+ }
+
+ /** Normialze.
+
+ Normalize the vector to have the Magnitude() == 1.0. If the vector
+ is equal to zero it is left untouched.
+ */
+ void Normalize();
+
+ /** Zero quaternion vector. Does not represent any orientation.
+ Useful for initialization of increments */
+ static FGQuaternion zero(void) { return FGQuaternion( 0.0, 0.0, 0.0, 0.0 ); }
+
+private:
+ /** Copying by assigning the vector valued components. */
+ FGQuaternion(double q1, double q2, double q3, double q4) : mCacheValid(false)
+ { Entry(1) = q1; Entry(2) = q2; Entry(3) = q3; Entry(4) = q4; }
+
+ /** Computation of derived values.
+ This function recomputes the derived values like euler angles and
+ transformation matrices. It does this unconditionally. */
+ void ComputeDerivedUnconditional(void) const;
+
+ /** Computation of derived values.
+ This function checks if the derived values like euler angles and
+ transformation matrices are already computed. If so, it
+ returns. If they need to be computed this is done here. */
+ void ComputeDerived(void) const {
+ if (!mCacheValid)
+ ComputeDerivedUnconditional();
+ }
+
+ /** The quaternion values itself. This is the master copy. */
+ double mData[4];
+
+ /** A data validity flag.
+ This class implements caching of the derived values like the
+ orthogonal rotation matrices or the Euler angles. For caching we
+ carry a flag which signals if the values are valid or not.
+ The C++ keyword "mutable" tells the compiler that the data member is
+ allowed to change during a const member function. */
+ mutable bool mCacheValid;
+
+ /** This stores the transformation matrices. */
+ mutable FGMatrix33 mT;
+ mutable FGMatrix33 mTInv;
+
+ /** The cached euler angles. */
+ mutable FGColumnVector3 mEulerAngles;
+
+ /** The cached sines and cosines of the euler angles. */
+ mutable FGColumnVector3 mEulerSines;
+ mutable FGColumnVector3 mEulerCosines;
+};
+
+/** Scalar multiplication.
+
+ @param scalar scalar value to multiply with.
+ @param p Vector to multiply.
+
+ Multiply the Vector with a scalar value.
+*/
+inline FGQuaternion operator*(double scalar, const FGQuaternion& q) {
+ return FGQuaternion(scalar*q(1), scalar*q(2), scalar*q(3), scalar*q(4));
+}
+
+} // namespace JSBSim
+
+#endif
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+#include <sstream>
+
#include "FGRocket.h"
namespace JSBSim {
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-double FGRocket::Calculate(double pe)
+double FGRocket::Calculate(void)
{
double Cf=0;
} else {
PctPower = Throttle / MaxThrottle;
PC = maxPC*PctPower * (1.0 + Variance * ((double)rand()/(double)RAND_MAX - 0.5));
- Cf = sqrt(kFactor*(1 - pow(pe/(PC), (SHR-1)/SHR)));
+ Cf = sqrt(kFactor*(1 - pow(Thruster->GetPowerRequired()/(PC), (SHR-1)/SHR)));
Flameout = false;
}
- return Cf*maxPC*PctPower*propEff;
+ return Thruster->Calculate(Cf*maxPC*PctPower*propEff);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGRocket::GetEngineLabels(void)
+{
+ std::ostringstream buf;
+
+ buf << Name << "_ChamberPress[" << EngineNumber << "], "
+ << Thruster->GetThrusterLabels(EngineNumber);
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGRocket::GetEngineValues(void)
+{
+ std::ostringstream buf;
+
+ buf << PC << ", " << Thruster->GetThrusterValues(EngineNumber);
+
+ return buf.str();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
~FGRocket(void);
/** Determines the thrust coefficient.
- This routine takes the nozzle exit pressure and calculates the thrust
- coefficient times the chamber pressure.
- @param pe nozzle exit pressure
@return thrust coefficient times chamber pressure */
- double Calculate(double pe);
-
+ double Calculate(void);
+
/** Gets the chamber pressure.
@return chamber pressure in psf. */
double GetChamberPressure(void) {return PC;}
/** Gets the flame-out status.
- The engine will "flame out" if the throttle is set below the minimum
+ The engine will "flame out" if the throttle is set below the minimum
sustainable setting.
@return true if engine has flamed out. */
bool GetFlameout(void) {return Flameout;}
+ string GetEngineLabels(void);
+ string GetEngineValues(void);
private:
double SHR;
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGRotation.cpp
- Author: Jon Berndt
- Date started: 12/02/98
- Purpose: Integrates the rotational EOM
- Called by: FGFDMExec
-
- ------------- 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.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-This class integrates the rotational EOM.
-
-HISTORY
---------------------------------------------------------------------------------
-12/02/98 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-COMMENTS, REFERENCES, and NOTES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-[1] Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
- Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
- School, January 1994
-[2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
- JSC 12960, July 1977
-[3] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
- NASA-Ames", NASA CR-2497, January 1975
-[4] Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
- Wiley & Sons, 1979 ISBN 0-471-03032-5
-[5] Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
- 1982 ISBN 0-471-08936-2
-
- The order of rotations used in this class corresponds to a 3-2-1 sequence,
- or Y-P-R, or Z-Y-X, if you prefer.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGRotation.h"
-#include "FGAtmosphere.h"
-#include "FGState.h"
-#include "FGFDMExec.h"
-#include "FGAircraft.h"
-#include "FGMassBalance.h"
-#include "FGPropertyManager.h"
-
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_ROTATION;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-
-FGRotation::FGRotation(FGFDMExec* fdmex) : FGModel(fdmex)
-{
- Name = "FGRotation";
- cTht = cPhi = cPsi = 1.0;
- sTht = sPhi = sPsi = 0.0;
-
- vPQRdot.InitMatrix();
- vPQRdot_prev[0].InitMatrix();
- vPQRdot_prev[1].InitMatrix();
- vPQRdot_prev[2].InitMatrix();
- vPQRdot_prev[3].InitMatrix();
-
- bind();
-
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGRotation::~FGRotation()
-{
- unbind();
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGRotation::Run(void)
-{
- double tTheta;
-
- if (!FGModel::Run()) {
- GetState();
-
- vPQRdot = MassBalance->GetJinv()*(vMoments - vPQR*(MassBalance->GetJ()*vPQR));
- vPQR += State->Integrate(FGState::TRAPZ, dt*rate, vPQRdot, vPQRdot_prev);
-
- vAeroPQR = vPQR + Atmosphere->GetTurbPQR();
-
- State->IntegrateQuat(vPQR, rate);
- State->CalcMatrices();
- vEuler = State->CalcEuler();
-
- cTht = cos(vEuler(eTht)); sTht = sin(vEuler(eTht));
- cPhi = cos(vEuler(ePhi)); sPhi = sin(vEuler(ePhi));
- cPsi = cos(vEuler(ePsi)); sPsi = sin(vEuler(ePsi));
-
- vEulerRates(eTht) = vPQR(2)*cPhi - vPQR(3)*sPhi;
- if (cTht != 0.0) {
- tTheta = sTht/cTht; // what's cheaper: / or tan() ?
- vEulerRates(ePhi) = vPQR(1) + (vPQR(2)*sPhi + vPQR(3)*cPhi)*tTheta;
- vEulerRates(ePsi) = (vPQR(2)*sPhi + vPQR(3)*cPhi)/cTht;
- }
-
- if (debug_lvl > 1) Debug(2);
-
- return false;
- } else {
- return true;
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGRotation::GetState(void)
-{
- dt = State->Getdt();
- vMoments = Aircraft->GetMoments();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGRotation::bind(void)
-{
- typedef double (FGRotation::*PMF)(int) const;
- PropertyManager->Tie("velocities/p-rad_sec", this,1,
- (PMF)&FGRotation::GetPQR);
- PropertyManager->Tie("velocities/q-rad_sec", this,2,
- (PMF)&FGRotation::GetPQR);
- PropertyManager->Tie("velocities/r-rad_sec", this,3,
- (PMF)&FGRotation::GetPQR);
- PropertyManager->Tie("velocities/p-aero-rad_sec", this,1,
- (PMF)&FGRotation::GetAeroPQR);
- PropertyManager->Tie("velocities/q-aero-rad_sec", this,2,
- (PMF)&FGRotation::GetAeroPQR);
- PropertyManager->Tie("velocities/r-aero-rad_sec", this,3,
- (PMF)&FGRotation::GetAeroPQR);
- PropertyManager->Tie("accelerations/pdot-rad_sec", this,1,
- (PMF)&FGRotation::GetPQRdot);
- PropertyManager->Tie("accelerations/qdot-rad_sec", this,2,
- (PMF)&FGRotation::GetPQRdot);
- PropertyManager->Tie("accelerations/rdot-rad_sec", this,3,
- (PMF)&FGRotation::GetPQRdot);
- PropertyManager->Tie("attitude/roll-rad", this,1,
- (PMF)&FGRotation::GetEuler);
- PropertyManager->Tie("attitude/pitch-rad", this,2,
- (PMF)&FGRotation::GetEuler);
- PropertyManager->Tie("attitude/heading-true-rad", this,3,
- (PMF)&FGRotation::GetEuler);
- PropertyManager->Tie("velocities/phidot-rad_sec", this,1,
- (PMF)&FGRotation::GetEulerRates);
- PropertyManager->Tie("velocities/thetadot-rad_sec", this,2,
- (PMF)&FGRotation::GetEulerRates);
- PropertyManager->Tie("velocities/psidot-rad_sec", this,3,
- (PMF)&FGRotation::GetEulerRates);
- PropertyManager->Tie("attitude/phi-rad", this,
- &FGRotation::Getphi);
- PropertyManager->Tie("attitude/theta-rad", this,
- &FGRotation::Gettht);
- PropertyManager->Tie("attitude/psi-true-rad", this,
- &FGRotation::Getpsi);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGRotation::unbind(void)
-{
- PropertyManager->Untie("velocities/p-rad_sec");
- PropertyManager->Untie("velocities/q-rad_sec");
- PropertyManager->Untie("velocities/r-rad_sec");
- PropertyManager->Untie("velocities/p-aero-rad_sec");
- PropertyManager->Untie("velocities/q-aero-rad_sec");
- PropertyManager->Untie("velocities/r-aero-rad_sec");
- PropertyManager->Untie("accelerations/pdot-rad_sec");
- PropertyManager->Untie("accelerations/qdot-rad_sec");
- PropertyManager->Untie("accelerations/rdot-rad_sec");
- PropertyManager->Untie("attitude/roll-rad");
- PropertyManager->Untie("attitude/pitch-rad");
- PropertyManager->Untie("attitude/heading-true-rad");
- PropertyManager->Untie("velocities/phidot-rad_sec");
- PropertyManager->Untie("velocities/thetadot-rad_sec");
- PropertyManager->Untie("velocities/psidot-rad_sec");
- PropertyManager->Untie("attitude/phi-rad");
- PropertyManager->Untie("attitude/theta-rad");
- PropertyManager->Untie("attitude/psi-true-rad");
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// 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 FGRotation::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: FGRotation" << endl;
- if (from == 1) cout << "Destroyed: FGRotation" << 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 check variables
- if (from == 2) {
- if (fabs(vPQR(eP)) > 100)
- cout << "FGRotation::P (Roll Rate) out of bounds: " << vPQR(eP) << endl;
- if (fabs(vPQR(eQ)) > 100)
- cout << "FGRotation::Q (Pitch Rate) out of bounds: " << vPQR(eQ) << endl;
- if (fabs(vPQR(eR)) > 100)
- cout << "FGRotation::R (Yaw Rate) out of bounds: " << vPQR(eR) << endl;
- }
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGRotation.h
- Author: Jon Berndt
- Date started: 12/02/98
-
- ------------- 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
---------------------------------------------------------------------------------
-12/02/98 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGROTATION_H
-#define FGROTATION_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef FGFS
-# include <simgear/compiler.h>
-# include <math.h>
-#else
-# if defined (sgi) && !defined(__GNUC__)
-# include <math.h>
-# else
-# include <cmath>
-# endif
-#endif
-
-#include "FGModel.h"
-#include "FGColumnVector3.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_ROTATION "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Models the rotational portion of the Equations of Motion.
- Note: The order of rotations used in this class corresponds to a 3-2-1 sequence,
- or Y-P-R, or Z-Y-X, if you prefer.
- @see Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
- Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
- School, January 1994
- @see D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
- JSC 12960, July 1977
- @see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
- NASA-Ames", NASA CR-2497, January 1975
- @see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
- Wiley & Sons, 1979 ISBN 0-471-03032-5
- @see Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
- 1982 ISBN 0-471-08936-2
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGRotation : public FGModel
-{
-public:
- FGRotation(FGFDMExec*);
- ~FGRotation();
-
- bool Run(void);
-
- inline FGColumnVector3& GetPQR(void) {return vPQR;}
- inline double GetPQR(int axis) const {return vPQR(axis);}
- inline FGColumnVector3& GetAeroPQR(void) {return vAeroPQR;}
- inline double GetAeroPQR(int axis) const {return vAeroPQR(axis);}
- inline FGColumnVector3& GetPQRdot(void) {return vPQRdot;}
- inline double GetPQRdot(int idx) const {return vPQRdot(idx);}
- inline FGColumnVector3& GetEuler(void) {return vEuler;}
- inline double GetEuler(int axis) const {return vEuler(axis);}
- inline FGColumnVector3& GetEulerRates(void) { return vEulerRates; }
- inline double GetEulerRates(int axis) const { return vEulerRates(axis); }
- inline void SetPQR(FGColumnVector3 tt) {vPQR = tt;}
- inline void SetPQR(double p, double q, double r) {vPQR(eP)=p;
- vPQR(eQ)=q;
- vPQR(eR)=r;}
- inline void SetAeroPQR(FGColumnVector3 tt) {vAeroPQR = tt;}
- inline void SetAeroPQR(double p, double q, double r) {vAeroPQR(eP)=p;
- vAeroPQR(eQ)=q;
- vAeroPQR(eR)=r;}
- inline void SetEuler(FGColumnVector3 tt) {vEuler = tt;}
-
- inline double Getphi(void) const {return vEuler(1);}
- inline double Gettht(void) const {return vEuler(2);}
- inline double Getpsi(void) const {return vEuler(3);}
-
- inline double GetCosphi(void) const {return cPhi;}
- inline double GetCostht(void) const {return cTht;}
- inline double GetCospsi(void) const {return cPsi;}
-
- inline double GetSinphi(void) const {return sPhi;}
- inline double GetSintht(void) const {return sTht;}
- inline double GetSinpsi(void) const {return sPsi;}
-
- void bind(void);
- void unbind(void);
-
-private:
- FGColumnVector3 vPQR;
- FGColumnVector3 vAeroPQR;
- FGColumnVector3 vPQRdot;
- FGColumnVector3 vPQRdot_prev[4];
- FGColumnVector3 vMoments;
- FGColumnVector3 vEuler;
- FGColumnVector3 vEulerRates;
-
- double cTht,sTht;
- double cPhi,sPhi;
- double cPsi,sPsi;
-
- double dt;
-
- void GetState(void);
-
- void Debug(int from);
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
-
return 0.0;
}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGRotor::GetThrusterLabels(int id)
+{
+ return "";
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGRotor::GetThrusterValues(int id)
+{
+ return "";
+}
+
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
~FGRotor();
double Calculate(double);
+ string GetThrusterLabels(int id);
+ string GetThrusterValues(int id);
private:
void Debug(int from);
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGSimTurbine.cpp
- Author: David Culp
- Date started: 03/11/2003
- Purpose: This module models a turbine engine.
-
- ------------- Copyright (C) 2003 David Culp (davidculp2@comcast.net) ---------
-
- 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
---------------------------------------------------------------------------------
-
-This class descends from the FGEngine class and models a Turbine engine based
-on parameters given in the engine config file for this class
-
-HISTORY
---------------------------------------------------------------------------------
-03/11/2003 DPC Created
-09/08/2003 DPC Changed Calculate() and added engine phases
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include <vector>
-#include "FGSimTurbine.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_SIMTURBINE;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-
-FGSimTurbine::FGSimTurbine(FGFDMExec* exec, FGConfigFile* cfg) : FGEngine(exec)
-{
- SetDefaults();
-
- Load(cfg);
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGSimTurbine::~FGSimTurbine()
-{
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// The main purpose of Calculate() is to determine what phase the engine should
-// be in, then call the corresponding function.
-
-double FGSimTurbine::Calculate(double dummy)
-{
- TAT = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556;
- dt = State->Getdt() * Propulsion->GetRate();
- ThrottleCmd = FCS->GetThrottleCmd(EngineNumber);
-
- // When trimming is finished check if user wants engine OFF or RUNNING
- if ((phase == tpTrim) && (dt > 0)) {
- if (Running && !Starved) {
- phase = tpRun;
- N2 = IdleN2;
- N1 = IdleN1;
- OilTemp_degK = 366.0;
- Cutoff = false;
- }
- else {
- phase = tpOff;
- Cutoff = true;
- EGT_degC = TAT;
- }
- }
-
- if (!Running && Cutoff && Starter) {
- if (phase == tpOff) phase = tpSpinUp;
- }
- if (!Running && !Cutoff && (N2 > 15.0)) phase = tpStart;
- if (Cutoff && (phase != tpSpinUp)) phase = tpOff;
- if (dt == 0) phase = tpTrim;
- if (Starved) phase = tpOff;
- if (Stalled) phase = tpStall;
- if (Seized) phase = tpSeize;
-
- switch (phase) {
- case tpOff: Thrust = Off(); break;
- case tpRun: Thrust = Run(); break;
- case tpSpinUp: Thrust = SpinUp(); break;
- case tpStart: Thrust = Start(); break;
- case tpStall: Thrust = Stall(); break;
- case tpSeize: Thrust = Seize(); break;
- case tpTrim: Thrust = Trim(); break;
- default: Thrust = Off();
- }
-
- return Thrust;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGSimTurbine::Off(void)
-{
- double qbar = Translation->Getqbar();
- Running = false;
- FuelFlow_pph = Seek(&FuelFlow_pph, 0, 1000.0, 10000.0);
- N1 = Seek(&N1, qbar/10.0, N1/2.0, N1/2.0);
- N2 = Seek(&N2, qbar/15.0, N2/2.0, N2/2.0);
- EGT_degC = Seek(&EGT_degC, TAT, 11.7, 7.3);
- OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0.2, 0.2);
- OilPressure_psi = N2 * 0.62;
- NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
- EPR = Seek(&EPR, 1.0, 0.2, 0.2);
- Augmentation = false;
- return 0.0;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGSimTurbine::Run(void)
-{
- double idlethrust, milthrust, thrust;
- double N2norm; // 0.0 = idle N2, 1.0 = maximum N2
- idlethrust = MilThrust * ThrustTables[0]->TotalValue();
- milthrust = (MilThrust - idlethrust) * ThrustTables[1]->TotalValue();
-
- Running = true;
- Starter = false;
-
- N2 = Seek(&N2, IdleN2 + ThrottleCmd * N2_factor, delay, delay * 3.0);
- N1 = Seek(&N1, IdleN1 + ThrottleCmd * N1_factor, delay, delay * 2.4);
- N2norm = (N2 - IdleN2) / N2_factor;
- thrust = idlethrust + (milthrust * N2norm * N2norm);
- thrust = thrust * (1.0 - BleedDemand);
- EGT_degC = TAT + 363.1 + ThrottleCmd * 357.1;
- OilPressure_psi = N2 * 0.62;
- OilTemp_degK = Seek(&OilTemp_degK, 366.0, 1.2, 0.1);
- EPR = 1.0 + thrust/MilThrust;
-
- if (!Augmentation) {
- FuelFlow_pph = Seek(&FuelFlow_pph, thrust * TSFC, 1000.0, 100000);
- if (FuelFlow_pph < IdleFF) FuelFlow_pph = IdleFF;
- NozzlePosition = Seek(&NozzlePosition, 1.0 - N2norm, 0.8, 0.8);
- }
-
- if (AugMethod == 1) {
- if ((ThrottleCmd > 0.99) && (N2 > 97.0)) {Augmentation = true;}
- else {Augmentation = false;}
- }
-
- if ((Augmented == 1) && Augmentation) {
- thrust = MaxThrust * ThrustTables[2]->TotalValue();
- FuelFlow_pph = Seek(&FuelFlow_pph, thrust * ATSFC, 5000.0, 10000.0);
- NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
- }
-
- if ((Injected == 1) && Injection)
- thrust = thrust * ThrustTables[3]->TotalValue();
-
- ConsumeFuel();
- if (Cutoff) phase = tpOff;
- if (Starved) phase = tpOff;
-
- return thrust;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGSimTurbine::SpinUp(void)
-{
- Running = false;
- FuelFlow_pph = 0.0;
- N2 = Seek(&N2, 25.18, 3.0, N2/2.0);
- N1 = Seek(&N1, 5.21, 1.0, N1/2.0);
- EGT_degC = Seek(&EGT_degC, TAT, 11.7, 7.3);
- OilPressure_psi = N2 * 0.62;
- OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0.2, 0.2);
- EPR = 1.0;
- NozzlePosition = 1.0;
-
- return 0.0;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGSimTurbine::Start(void)
-{
- if ((N2 > 15.0) && !Starved) { // minimum 15% N2 needed for start
- Cranking = true; // provided for sound effects signal
- if (N2 < IdleN2) {
- N2 = Seek(&N2, IdleN2, 2.0, N2/2.0);
- N1 = Seek(&N1, IdleN1, 1.4, N1/2.0);
- EGT_degC = Seek(&EGT_degC, TAT + 363.1, 21.3, 7.3);
- FuelFlow_pph = Seek(&FuelFlow_pph, IdleFF, 103.7, 103.7);
- OilPressure_psi = N2 * 0.62;
- }
- else {
- phase = tpRun;
- Running = true;
- Starter = false;
- Cranking = false;
- }
- }
- else { // no start if N2 < 15%
- phase = tpOff;
- Starter = false;
- }
-
- return 0.0;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGSimTurbine::Stall(void)
-{
- double qbar = Translation->Getqbar();
- EGT_degC = TAT + 903.14;
- FuelFlow_pph = IdleFF;
- N1 = Seek(&N1, qbar/10.0, 0, N1/10.0);
- N2 = Seek(&N2, qbar/15.0, 0, N2/10.0);
- if (ThrottleCmd == 0) phase = tpRun; // clear the stall with throttle
-
- return 0.0;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGSimTurbine::Seize(void)
-{
- double qbar = Translation->Getqbar();
- N2 = 0.0;
- N1 = Seek(&N1, qbar/20.0, 0, N1/15.0);
- FuelFlow_pph = IdleFF;
- OilPressure_psi = 0.0;
- OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0, 0.2);
- Running = false;
- return 0.0;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGSimTurbine::Trim(void)
-{
- double idlethrust, milthrust, thrust;
- idlethrust = MilThrust * ThrustTables[0]->TotalValue();
- milthrust = (MilThrust - idlethrust) * ThrustTables[1]->TotalValue();
- thrust = idlethrust + (milthrust * ThrottleCmd * ThrottleCmd);
- return thrust;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGSimTurbine::CalcFuelNeed(void)
-{
- return FuelFlow_pph /3600 * State->Getdt() * Propulsion->GetRate();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGSimTurbine::GetPowerAvailable(void) {
- if( ThrottleCmd <= 0.77 )
- return 64.94*ThrottleCmd;
- else
- return 217.38*ThrottleCmd - 117.38;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-double FGSimTurbine::Seek(double *var, double target, double accel, double decel) {
- double v = *var;
- if (v > target) {
- v -= dt * decel;
- if (v < target) v = target;
- } else if (v < target) {
- v += dt * accel;
- if (v > target) v = target;
- }
- return v;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGSimTurbine::SetDefaults(void)
-{
- Name = "Not defined";
- N1 = N2 = 0.0;
- Type = etSimTurbine;
- MilThrust = 10000.0;
- MaxThrust = 10000.0;
- BypassRatio = 0.0;
- TSFC = 0.8;
- ATSFC = 1.7;
- IdleN1 = 30.0;
- IdleN2 = 60.0;
- MaxN1 = 100.0;
- MaxN2 = 100.0;
- Augmented = 0;
- AugMethod = 0;
- Injected = 0;
- BleedDemand = 0.0;
- ThrottleCmd = 0.0;
- InletPosition = 1.0;
- NozzlePosition = 1.0;
- Augmentation = false;
- Injection = false;
- Reversed = false;
- Cutoff = true;
- phase = tpOff;
- Stalled = false;
- Seized = false;
- Overtemp = false;
- Fire = false;
- EGT_degC = 0.0;
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGSimTurbine::Load(FGConfigFile *Eng_cfg)
-{
- string token;
-
- Name = Eng_cfg->GetValue("NAME");
- Eng_cfg->GetNextConfigLine();
- int counter=0;
-
- while (Eng_cfg->GetValue() != string("/FG_SIMTURBINE")) {
- *Eng_cfg >> token;
-
- if (token[0] == '<') token.erase(0,1); // Tables are read "<TABLE"
-
- if (token == "MILTHRUST") *Eng_cfg >> MilThrust;
- else if (token == "MAXTHRUST") *Eng_cfg >> MaxThrust;
- else if (token == "BYPASSRATIO") *Eng_cfg >> BypassRatio;
- else if (token == "TSFC") *Eng_cfg >> TSFC;
- else if (token == "ATSFC") *Eng_cfg >> ATSFC;
- else if (token == "IDLEN1") *Eng_cfg >> IdleN1;
- else if (token == "IDLEN2") *Eng_cfg >> IdleN2;
- else if (token == "MAXN1") *Eng_cfg >> MaxN1;
- else if (token == "MAXN2") *Eng_cfg >> MaxN2;
- else if (token == "AUGMENTED") *Eng_cfg >> Augmented;
- else if (token == "AUGMETHOD") *Eng_cfg >> AugMethod;
- else if (token == "INJECTED") *Eng_cfg >> Injected;
- else if (token == "MINTHROTTLE") *Eng_cfg >> MinThrottle;
- else if (token == "TABLE") {
- if (counter++ == 0) Debug(2); // print engine specs prior to table read
- ThrustTables.push_back( new FGCoefficient(FDMExec) );
- ThrustTables.back()->Load(Eng_cfg);
- }
- else cerr << "Unhandled token in Engine config file: " << token << endl;
- }
-
- // Pre-calculations and initializations
-
- delay = 60.0 / (BypassRatio + 3.0);
- N1_factor = MaxN1 - IdleN1;
- N2_factor = MaxN2 - IdleN2;
- OilTemp_degK = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556 + 273.0;
- IdleFF = pow(MilThrust, 0.2) * 107.0; // just an estimate
-
- return true;
-}
-
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// 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 FGSimTurbine::Debug(int from)
-{
- if (debug_lvl <= 0) return;
-
- if (debug_lvl & 1) { // Standard console startup message output
- if (from == 0) { // Constructor
-
- }
- if (from == 2) { // called from Load()
- cout << "\n Engine Name: " << Name << endl;
- cout << " MilThrust: " << MilThrust << endl;
- cout << " MaxThrust: " << MaxThrust << endl;
- cout << " BypassRatio: " << BypassRatio << endl;
- cout << " TSFC: " << TSFC << endl;
- cout << " ATSFC: " << ATSFC << endl;
- cout << " IdleN1: " << IdleN1 << endl;
- cout << " IdleN2: " << IdleN2 << endl;
- cout << " MaxN1: " << MaxN1 << endl;
- cout << " MaxN2: " << MaxN2 << endl;
- cout << " Augmented: " << Augmented << endl;
- cout << " AugMethod: " << AugMethod << endl;
- cout << " Injected: " << Injected << endl;
- cout << " MinThrottle: " << MinThrottle << endl;
-
- cout << endl;
- }
- }
- if (debug_lvl & 2 ) { // Instantiation/Destruction notification
- if (from == 0) cout << "Instantiated: FGSimTurbine" << endl;
- if (from == 1) cout << "Destroyed: FGSimTurbine" << 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;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGSimTurbine.h
- Author: David Culp
- Date started: 03/11/2003
-
- ------------- Copyright (C) 2003 David Culp (davidculp2@comcast.net)----------
-
- 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
---------------------------------------------------------------------------------
-03/11/2003 DPC Created, based on FGTurbine
-09/22/2003 DPC Added starting, stopping, new framework
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGSIMTURBINE_H
-#define FGSIMTURBINE_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include <vector>
-#include "FGEngine.h"
-#include "FGConfigFile.h"
-#include "FGCoefficient.h"
-
-#define ID_SIMTURBINE "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** This class models a turbine engine. Based on Jon Berndt's FGTurbine module.
- Here the term "phase" signifies the engine's mode of operation. At any given
- time the engine is in only one phase. At simulator startup the engine will be
- placed in the Trim phase in order to provide a simplified thrust value without
- throttle lag. When trimming is complete the engine will go to the Off phase,
- unless the value FGEngine::Running has been previously set to true, in which
- case the engine will go to the Run phase. Once an engine is in the Off phase
- the full starting procedure (or airstart) must be used to get it running.
-<P>
- - STARTING (on ground):
- -# Set the control FGEngine::Starter to true. The engine will spin up to
- a maximum of about %25 N2 (%5.2 N1). This simulates the action of a
- pneumatic starter.
- -# After reaching %15 N2 set the control FGEngine::Cutoff to false. If fuel
- is available the engine will now accelerate to idle. The starter will
- automatically be set to false after the start cycle.
-<P>
- - STARTING (in air):
- -# Increase speed to obtain a minimum of %15 N2. If this is not possible,
- the starter may be used to assist.
- -# Place the control FGEngine::Cutoff to false.
-<P>
- Ignition is assumed to be on anytime the Cutoff control is set to false,
- therefore a seperate ignition system is not modeled.
-
-Configuration File Format
-<pre>
-\<FG_SIMTURBINE NAME="<name>">
- MILTHRUST \<thrust>
- MAXTHRUST \<thrust>
- BYPASSRATIO \<bypass ratio>
- TSFC \<thrust specific fuel consumption>
- ATSFC \<afterburning thrust specific fuel consumption>
- IDLEN1 \<idle N1>
- IDLEN2 \<idle N2>
- MAXN1 \<max N1>
- MAXN2 \<max N2>
- AUGMENTED \<0|1>
- AUGMETHOD \<0|1>
- INJECTED \<0|1>
- ...
-\</FG_SIMTURBINE>
-</pre>
-Definition of the turbine engine configuration file parameters:
-<pre>
-<b>MILTHRUST</b> - Maximum thrust, static, at sea level, lbf.
-<b>MAXTHRUST</b> - Afterburning thrust, static, at sea level, lbf
-[this value will be ignored when AUGMENTED is zero (false)].
-<b>BYPASSRATIO</b> - Ratio of bypass air flow to core air flow.
-<b>TSFC</b> - Thrust-specific fuel consumption, lbm/hr/lbf
-[i.e. fuel flow divided by thrust].
-<b>ATSFC</b> - Afterburning TSFC, lbm/hr/lbf
-[this value will be ignored when AUGMENTED is zero (false)]
-<b>IDLEN1</b> - Fan rotor rpm (% of max) at idle
-<b>IDLEN2</b> - Core rotor rpm (% of max) at idle
-<b>MAXN1</b> - Fan rotor rpm (% of max) at full throttle [not always 100!]
-<b>MAXN2</b> - Core rotor rpm (% of max) at full throttle [not always 100!]
-<b>AUGMENTED</b>
- 0 == afterburner not installed
- 1 == afterburner installed
-<b>AUGMETHOD</b>
- 0 == afterburner activated by property /engines/engine[n]/augmentation
- 1 == afterburner activated by pushing throttle above 99% position
- [this item will be ignored when AUGMENTED == 0]
-<b>INJECTED</b>
- 0 == Water injection not installed
- 1 == Water injection installed
-</pre>
- @author David P. Culp
- @version "$Id$"
-*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGSimTurbine : public FGEngine
-{
-public:
- /** Constructor
- @param Executive pointer to executive structure
- @param Eng_cfg pointer to engine config file instance */
- FGSimTurbine(FGFDMExec* Executive, FGConfigFile* Eng_cfg);
- /// Destructor
- ~FGSimTurbine();
-
- enum phaseType { tpOff, tpRun, tpSpinUp, tpStart, tpStall, tpSeize, tpTrim };
-
- double Calculate(double PowerRequired);
- double CalcFuelNeed(void);
- double GetPowerAvailable(void);
- double Seek(double* var, double target, double accel, double decel);
-
- phaseType GetPhase(void) { return phase; }
-
- bool GetOvertemp(void) {return Overtemp; }
- bool GetInjection(void) {return Injection;}
- bool GetFire(void) { return Fire; }
- bool GetAugmentation(void) {return Augmentation;}
- bool GetReversed(void) { return Reversed; }
- bool GetCutoff(void) { return Cutoff; }
- int GetIgnition(void) {return Ignition;}
-
- double GetInlet(void) { return InletPosition; }
- double GetNozzle(void) { return NozzlePosition; }
- double GetBleedDemand(void) {return BleedDemand;}
- double GetN1(void) {return N1;}
- double GetN2(void) {return N2;}
- double GetEPR(void) {return EPR;}
- double GetEGT(void) {return EGT_degC;}
-
- double getOilPressure_psi () const {return OilPressure_psi;}
- double getOilTemp_degF (void) {return KelvinToFahrenheit(OilTemp_degK);}
-
- void SetInjection(bool injection) {Injection = injection;}
- void SetIgnition(int ignition) {Ignition = ignition;}
- void SetAugmentation(bool augmentation) {Augmentation = augmentation;}
- void SetPhase( phaseType p ) { phase = p; }
- void SetEPR(double epr) {EPR = epr;}
- void SetBleedDemand(double bleedDemand) {BleedDemand = bleedDemand;}
- void SetReverse(bool reversed) { Reversed = reversed; }
- void SetCutoff(bool cutoff) { Cutoff = cutoff; }
-
-private:
-
- typedef vector<FGCoefficient*> CoeffArray;
- CoeffArray ThrustTables;
-
- phaseType phase; ///< Operating mode, or "phase"
- double MilThrust; ///< Maximum Unaugmented Thrust, static @ S.L. (lbf)
- double MaxThrust; ///< Maximum Augmented Thrust, static @ S.L. (lbf)
- double BypassRatio; ///< Bypass Ratio
- double TSFC; ///< Thrust Specific Fuel Consumption (lbm/hr/lbf)
- double ATSFC; ///< Augmented TSFC (lbm/hr/lbf)
- double IdleN1; ///< Idle N1
- double IdleN2; ///< Idle N2
- double N1; ///< N1
- double N2; ///< N2
- double MaxN1; ///< N1 at 100% throttle
- double MaxN2; ///< N2 at 100% throttle
- double IdleFF; ///< Idle Fuel Flow (lbm/hr)
- double delay; ///< Inverse spool-up time from idle to 100% (seconds)
- double dt; ///< Simulator time slice
- double N1_factor; ///< factor to tie N1 and throttle
- double N2_factor; ///< factor to tie N2 and throttle
- double ThrottleCmd; ///< FCS-supplied throttle position
- double TAT; ///< total air temperature (deg C)
- bool Stalled; ///< true if engine is compressor-stalled
- bool Seized; ///< true if inner spool is seized
- bool Overtemp; ///< true if EGT exceeds limits
- bool Fire; ///< true if engine fire detected
- bool Injection;
- bool Augmentation;
- bool Reversed;
- bool Cutoff;
- int Injected; ///< = 1 if water injection installed
- int Ignition;
- int Augmented; ///< = 1 if augmentation installed
- int AugMethod; ///< = 0 if using property /engine[n]/augmentation
- ///< = 1 if using last 1% of throttle movement
- double EGT_degC;
- double EPR;
- double OilPressure_psi;
- double OilTemp_degK;
- double BleedDemand;
- double InletPosition;
- double NozzlePosition;
-
- double Off(void);
- double Run(void);
- double SpinUp(void);
- double Start(void);
- double Stall(void);
- double Seize(void);
- double Trim(void);
-
- void SetDefaults(void);
- bool Load(FGConfigFile *ENG_cfg);
- void Debug(int from);
-
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
-
# endif
#endif
-#ifdef _MSC_VER
-#define snprintf _snprintf
+#ifdef _WIN32
+//#define snprintf _snprintf
#endif
#include "FGState.h"
dt = 1.0/120.0;
Aircraft = FDMExec->GetAircraft();
- Translation = FDMExec->GetTranslation();
- Rotation = FDMExec->GetRotation();
- Position = FDMExec->GetPosition();
+ Propagate = FDMExec->GetPropagate();
+ Auxiliary = FDMExec->GetAuxiliary();
FCS = FDMExec->GetFCS();
Output = FDMExec->GetOutput();
Atmosphere = FDMExec->GetAtmosphere();
Propulsion = FDMExec->GetPropulsion();
PropertyManager = FDMExec->GetPropertyManager();
- for(int i=0;i<4;i++) vQdot_prev[i].InitMatrix();
-
bind();
Debug(0);
Debug(1);
}
-//***************************************************************************
-//
-// Initialize: Assume all angles GIVEN IN RADIANS !!
-//
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-void FGState::Initialize(double U, double V, double W,
- double phi, double tht, double psi,
- double Latitude, double Longitude, double H,
- double wnorth, double weast, double wdown)
+void FGState::Initialize(FGInitialCondition *FGIC)
{
- double alpha, beta;
- double qbar, Vt;
- FGColumnVector3 vAeroUVW;
- FGColumnVector3 vUVW;
+ sim_time = 0.0;
- Position->SetLatitude(Latitude);
- Position->SetLongitude(Longitude);
- Position->Seth(H);
+ Propagate->SetInitialState( FGIC );
Atmosphere->Run();
+ Atmosphere->SetWindNED( FGIC->GetWindNFpsIC(),
+ FGIC->GetWindEFpsIC(),
+ FGIC->GetWindDFpsIC() );
- vLocalEuler << phi << tht << psi;
- Rotation->SetEuler(vLocalEuler);
-
- InitMatrices(phi, tht, psi);
-
- vUVW << U << V << W;
- Translation->SetUVW(vUVW);
-
- Atmosphere->SetWindNED(wnorth, weast, wdown);
-
- vAeroUVW = vUVW + mTl2b*Atmosphere->GetWindNED();
+ FGColumnVector3 vAeroUVW;
+ vAeroUVW = Propagate->GetUVW() + Propagate->GetTl2b()*Atmosphere->GetWindNED();
+ double alpha, beta;
if (vAeroUVW(eW) != 0.0)
alpha = vAeroUVW(eU)*vAeroUVW(eU) > 0.0 ? atan2(vAeroUVW(eW), vAeroUVW(eU)) : 0.0;
else
else
beta = 0.0;
- Translation->SetAB(alpha, beta);
+ Auxiliary->SetAB(alpha, beta);
- Vt = sqrt(U*U + V*V + W*W);
- Translation->SetVt(Vt);
+ double Vt = vAeroUVW.Magnitude();
+ Auxiliary->SetVt(Vt);
- Translation->SetMach(Vt/Atmosphere->GetSoundSpeed());
+ Auxiliary->SetMach(Vt/Atmosphere->GetSoundSpeed());
- qbar = 0.5*(U*U + V*V + W*W)*Atmosphere->GetDensity();
- Translation->Setqbar(qbar);
-
- vLocalVelNED = mTb2l*vUVW;
- Position->SetvVel(vLocalVelNED);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGState::Initialize(FGInitialCondition *FGIC)
-{
- double tht,psi,phi;
- double U, V, W, h;
- double latitude, longitude;
- double wnorth,weast, wdown;
-
- latitude = FGIC->GetLatitudeRadIC();
- longitude = FGIC->GetLongitudeRadIC();
- h = FGIC->GetAltitudeFtIC();
- U = FGIC->GetUBodyFpsIC();
- V = FGIC->GetVBodyFpsIC();
- W = FGIC->GetWBodyFpsIC();
- tht = FGIC->GetThetaRadIC();
- phi = FGIC->GetPhiRadIC();
- psi = FGIC->GetPsiRadIC();
- wnorth = FGIC->GetWindNFpsIC();
- weast = FGIC->GetWindEFpsIC();
- wdown = FGIC->GetWindDFpsIC();
-
- Position->SetSeaLevelRadius( FGIC->GetSeaLevelRadiusFtIC() );
- Position->SetRunwayRadius( FGIC->GetSeaLevelRadiusFtIC() +
- FGIC->GetTerrainAltitudeFtIC() );
-
- // need to fix the wind speed args, here.
- Initialize(U, V, W, phi, tht, psi, latitude, longitude, h, wnorth, weast, wdown);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGState::InitMatrices(double phi, double tht, double psi)
-{
- double thtd2, psid2, phid2;
- double Sthtd2, Spsid2, Sphid2;
- double Cthtd2, Cpsid2, Cphid2;
- double Cphid2Cthtd2;
- double Cphid2Sthtd2;
- double Sphid2Sthtd2;
- double Sphid2Cthtd2;
-
- thtd2 = tht/2.0;
- psid2 = psi/2.0;
- phid2 = phi/2.0;
-
- Sthtd2 = sin(thtd2);
- Spsid2 = sin(psid2);
- Sphid2 = sin(phid2);
-
- Cthtd2 = cos(thtd2);
- Cpsid2 = cos(psid2);
- Cphid2 = cos(phid2);
-
- Cphid2Cthtd2 = Cphid2*Cthtd2;
- Cphid2Sthtd2 = Cphid2*Sthtd2;
- Sphid2Sthtd2 = Sphid2*Sthtd2;
- Sphid2Cthtd2 = Sphid2*Cthtd2;
-
- vQtrn(1) = Cphid2Cthtd2*Cpsid2 + Sphid2Sthtd2*Spsid2;
- vQtrn(2) = Sphid2Cthtd2*Cpsid2 - Cphid2Sthtd2*Spsid2;
- vQtrn(3) = Cphid2Sthtd2*Cpsid2 + Sphid2Cthtd2*Spsid2;
- vQtrn(4) = Cphid2Cthtd2*Spsid2 - Sphid2Sthtd2*Cpsid2;
-
- CalcMatrices();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGState::CalcMatrices(void)
-{
- double Q0Q0, Q1Q1, Q2Q2, Q3Q3;
- double Q0Q1, Q0Q2, Q0Q3, Q1Q2;
- double Q1Q3, Q2Q3;
-
- Q0Q0 = vQtrn(1)*vQtrn(1);
- Q1Q1 = vQtrn(2)*vQtrn(2);
- Q2Q2 = vQtrn(3)*vQtrn(3);
- Q3Q3 = vQtrn(4)*vQtrn(4);
- Q0Q1 = vQtrn(1)*vQtrn(2);
- Q0Q2 = vQtrn(1)*vQtrn(3);
- Q0Q3 = vQtrn(1)*vQtrn(4);
- Q1Q2 = vQtrn(2)*vQtrn(3);
- Q1Q3 = vQtrn(2)*vQtrn(4);
- Q2Q3 = vQtrn(3)*vQtrn(4);
-
- mTl2b(1,1) = Q0Q0 + Q1Q1 - Q2Q2 - Q3Q3;
- mTl2b(1,2) = 2*(Q1Q2 + Q0Q3);
- mTl2b(1,3) = 2*(Q1Q3 - Q0Q2);
- mTl2b(2,1) = 2*(Q1Q2 - Q0Q3);
- mTl2b(2,2) = Q0Q0 - Q1Q1 + Q2Q2 - Q3Q3;
- mTl2b(2,3) = 2*(Q2Q3 + Q0Q1);
- mTl2b(3,1) = 2*(Q1Q3 + Q0Q2);
- mTl2b(3,2) = 2*(Q2Q3 - Q0Q1);
- mTl2b(3,3) = Q0Q0 - Q1Q1 - Q2Q2 + Q3Q3;
-
- mTb2l = mTl2b;
- mTb2l.T();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGState::IntegrateQuat(FGColumnVector3 vPQR, int rate)
-{
- vQdot(1) = -0.5*(vQtrn(2)*vPQR(eP) + vQtrn(3)*vPQR(eQ) + vQtrn(4)*vPQR(eR));
- 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 += Integrate(TRAPZ, dt*rate, vQdot, vQdot_prev);
-
- vQtrn.Normalize();
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGColumnVector3& FGState::CalcEuler(void)
-{
- if (mTl2b(3,3) == 0.0) mTl2b(3,3) = 0.0000001;
- if (mTl2b(1,1) == 0.0) mTl2b(1,1) = 0.0000001;
-
- vEuler(ePhi) = atan2(mTl2b(2,3), mTl2b(3,3));
- vEuler(eTht) = asin(-mTl2b(1,3));
- vEuler(ePsi) = atan2(mTl2b(1,2), mTl2b(1,1));
-
- if (vEuler(ePsi) < 0.0) vEuler(ePsi) += 2*M_PI;
-
- return vEuler;
+ double qbar = 0.5*Vt*Vt*Atmosphere->GetDensity();
+ Auxiliary->Setqbar(qbar);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
{
double ca, cb, sa, sb;
- double alpha = Translation->Getalpha();
- double beta = Translation->Getbeta();
+ double alpha = Auxiliary->Getalpha();
+ double beta = Auxiliary->Getbeta();
ca = cos(alpha);
sa = sin(alpha);
float alpha,beta;
float ca, cb, sa, sb;
- alpha = Translation->Getalpha();
- beta = Translation->Getbeta();
+ alpha = Auxiliary->Getalpha();
+ beta = Auxiliary->Getbeta();
ca = cos(alpha);
sa = sin(alpha);
void FGState::ReportState(void)
{
+#if 0
#if !defined(__BORLANDCPP__)
char out[80], flap[10], gear[12];
snprintf(out,80, " Flaps: %3s Gear: %12s\n",flap,gear);
cout << out;
snprintf(out,80, " Speed: %4.0f KCAS Mach: %5.2f\n",
- FDMExec->GetAuxiliary()->GetVcalibratedKTS(),
- Translation->GetMach() );
+ Auxiliary->GetVcalibratedKTS(),
+ Auxiliary->GetMach() );
cout << out;
snprintf(out,80, " Altitude: %7.0f ft. AGL Altitude: %7.0f ft.\n",
- Position->Geth(),
- Position->GetDistanceAGL() );
+ Propagate->Geth(),
+ Propagate->GetDistanceAGL() );
cout << out;
snprintf(out,80, " Angle of Attack: %6.2f deg Pitch Angle: %6.2f deg\n",
- Translation->Getalpha()*radtodeg,
- Rotation->Gettht()*radtodeg );
+ Auxiliary->Getalpha()*radtodeg,
+ Propagate->Gettht()*radtodeg );
cout << out;
snprintf(out,80, " Flight Path Angle: %6.2f deg Climb Rate: %5.0f ft/min\n",
- Position->GetGamma()*radtodeg,
- Position->Gethdot()*60 );
+ Auxiliary->GetGamma()*radtodeg,
+ Propagate->Gethdot()*60 );
cout << out;
snprintf(out,80, " Normal Load Factor: %4.2f g's Pitch Rate: %5.2f deg/s\n",
Aircraft->GetNlf(),
- Rotation->GetPQR(2)*radtodeg );
+ Propagate->GetPQR(2)*radtodeg );
cout << out;
snprintf(out,80, " Heading: %3.0f deg true Sideslip: %5.2f deg Yaw Rate: %5.2f deg/s\n",
- Rotation->Getpsi()*radtodeg,
- Translation->Getbeta()*radtodeg,
- Rotation->GetPQR(3)*radtodeg );
+ Propagate->Getpsi()*radtodeg,
+ Auxiliary->Getbeta()*radtodeg,
+ Propagate->GetPQR(3)*radtodeg );
cout << out;
snprintf(out,80, " Bank Angle: %5.2f deg Roll Rate: %5.2f deg/s\n",
- Rotation->Getphi()*radtodeg,
- Rotation->GetPQR(1)*radtodeg );
+ Propagate->Getphi()*radtodeg,
+ Propagate->GetPQR(1)*radtodeg );
cout << out;
snprintf(out,80, " Elevator: %5.2f deg Left Aileron: %5.2f deg Rudder: %5.2f deg\n",
FCS->GetDePos(ofRad)*radtodeg,
cout << out;
snprintf(out,80, " Wind Components: %5.2f kts head wind, %5.2f kts cross wind\n",
- FDMExec->GetAuxiliary()->GetHeadWind()*fpstokts,
- FDMExec->GetAuxiliary()->GetCrossWind()*fpstokts );
+ Auxiliary->GetHeadWind()*fpstokts,
+ Auxiliary->GetCrossWind()*fpstokts );
cout << out;
snprintf(out,80, " Ground Speed: %4.0f knots , Ground Track: %3.0f deg true\n",
- Position->GetVground()*fpstokts,
- Position->GetGroundTrack()*radtodeg );
+ Auxiliary->GetVground()*fpstokts,
+ Auxiliary->GetGroundTrack()*radtodeg );
cout << out;
#endif
+#endif
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
+
Header: FGState.h
Author: Jon S. Berndt
Date started: 11/17/98
-
+
------------- 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.
-
+
FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------
-
+
HISTORY
--------------------------------------------------------------------------------
11/17/98 JSB Created
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGInitialCondition.h"
#include "FGMatrix33.h"
#include "FGColumnVector3.h"
-#include "FGColumnVector4.h"
-
+#include "FGQuaternion.h"
#include "FGFDMExec.h"
#include "FGAtmosphere.h"
#include "FGFCS.h"
-#include "FGTranslation.h"
-#include "FGRotation.h"
-#include "FGPosition.h"
+#include "FGPropagate.h"
+#include "FGAuxiliary.h"
#include "FGAerodynamics.h"
#include "FGOutput.h"
#include "FGAircraft.h"
/// Destructor
~FGState();
- /** Initializes the simulation state based on the passed-in parameters.
- @param U the body X-Axis velocity in fps.
- @param V the body Y-Axis velocity in fps.
- @param W the body Z-Axis velocity in fps.
- @param lat latitude measured in radians from the equator, negative values are south.
- @param lon longitude, measured in radians from the Greenwich meridian, negative values are west.
- @param phi the roll angle in radians.
- @param tht the pitch angle in radians.
- @param psi the heading angle in radians measured clockwise from north.
- @param h altitude in feet.
- @param wnorth north velocity in feet per second
- @param weast eastward velocity in feet per second
- @param wdown downward velocity in feet per second
- */
- void Initialize(double U,
- double V,
- double W,
- double lat,
- double lon,
- double phi,
- double tht,
- double psi,
- double h,
- double wnorth,
- double weast,
- double wdown);
-
/** Initializes the simulation state based on parameters from an Initial Conditions object.
@param FGIC pointer to an initial conditions object.
@see FGInitialConditions.
sim_time = cur_time;
return sim_time;
}
-
+
/** Sets the integration time step for the simulation executive.
@param delta_t the time step in seconds.
*/
return sim_time;
}
- /** Initializes the transformation matrices.
- @param phi the roll angle in radians.
- @param tht the pitch angle in radians.
- @param psi the heading angle in radians
- */
- void InitMatrices(double phi, double tht, double psi);
-
- /** Calculates the local-to-body and body-to-local conversion matrices.
- */
- void CalcMatrices(void);
-
- /** Integrates the quaternion.
- Given the supplied rotational rate vector and integration rate, the quaternion
- is integrated. The quaternion is later used to update the transformation
- matrices.
- @param vPQR the body rotational rate column vector.
- @param rate the integration rate in seconds.
- */
- void IntegrateQuat(FGColumnVector3 vPQR, int rate);
-
- // ======================================= General Purpose INTEGRATOR
-
- enum iType {AB4, AB3, AB2, AM3, AM4, EULER, TRAPZ};
-
- /** Multi-method integrator.
- @param type Type of intergation scheme to use. Can be one of:
- <ul>
- <li>AB4 - Adams-Bashforth, fourth order</li>
- <li>AB3 - Adams-Bashforth, third order</li>
- <li>AB2 - Adams-Bashforth, second order</li>
- <li>AM3 - Adams Moulton, third order</li>
- <li>AM4 - Adams Moulton, fourth order</li>
- <li>EULER - Euler</li>
- <li>TRAPZ - Trapezoidal</li>
- </ul>
- @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 <class T> T Integrate(iType type, double delta_t, T& vTDeriv, T *vLastArray)
- {
- T vResult;
-
- switch (type) {
- case AB4:
- vResult = (delta_t/24.0)*( 55.0 * vLastArray[0]
- - 59.0 * vLastArray[1]
- + 37.0 * vLastArray[2]
- - 9.0 * vLastArray[3] );
- vLastArray[3] = vLastArray[2];
- vLastArray[2] = vLastArray[1];
- vLastArray[1] = vLastArray[0];
- vLastArray[0] = vTDeriv;
- break;
- case AB3:
- vResult = (delta_t/12.0)*( 23.0 * vLastArray[0]
- - 16.0 * vLastArray[1]
- + 5.0 * vLastArray[2] );
- vLastArray[2] = vLastArray[1];
- vLastArray[1] = vLastArray[0];
- vLastArray[0] = vTDeriv;
- break;
- case AB2:
- vResult = (delta_t/2.0)*( 3.0 * vLastArray[0] - vLastArray[1] );
- vLastArray[1] = vLastArray[0];
- vLastArray[0] = vTDeriv;
- break;
- case AM4:
- vResult = (delta_t/24.0)*( 9.0 * vTDeriv
- + 19.0 * vLastArray[0]
- - 5.0 * vLastArray[1]
- + 1.0 * vLastArray[2] );
- vLastArray[2] = vLastArray[1];
- vLastArray[1] = 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.
- */
- FGColumnVector3& CalcEuler(void);
-
/** Calculates and returns the stability-to-body axis transformation matrix.
@return a reference to the stability-to-body transformation matrix.
*/
FGMatrix33& GetTs2b(void);
-
+
/** Calculates and returns the body-to-stability axis transformation matrix.
@return a reference to the stability-to-body transformation matrix.
*/
FGMatrix33& GetTb2s(void);
- /** Retrieves the local-to-body transformation matrix.
- @return a reference to the local-to-body transformation matrix.
- */
- FGMatrix33& GetTl2b(void) { return mTl2b; }
-
- /** Retrieves a specific local-to-body matrix element.
- @param r matrix row index.
- @param c matrix column index.
- @return the matrix element described by the row and column supplied.
- */
- double GetTl2b(int r, int c) { return mTl2b(r,c);}
-
- /** Retrieves the body-to-local transformation matrix.
- @return a reference to the body-to-local matrix.
- */
- FGMatrix33& GetTb2l(void) { return mTb2l; }
-
- /** Retrieves a specific body-to-local matrix element.
- @param r matrix row index.
- @param c matrix column index.
- @return the matrix element described by the row and column supplied.
- */
- double GetTb2l(int i, int j) { return mTb2l(i,j);}
-
- /** Prints a summary of simulator state (speed, altitude,
+ /** Prints a summary of simulator state (speed, altitude,
configuration, etc.)
*/
void ReportState(void);
-
+
void bind();
void unbind();
double saved_dt;
FGFDMExec* FDMExec;
- FGMatrix33 mTb2l;
- FGMatrix33 mTl2b;
FGMatrix33 mTs2b;
FGMatrix33 mTb2s;
- FGColumnVector4 vQtrn;
- FGColumnVector4 vQdot_prev[4];
- FGColumnVector4 vQdot;
- FGColumnVector3 vLocalVelNED;
- FGColumnVector3 vLocalEuler;
-
- FGColumnVector4 vTmp;
- FGColumnVector3 vEuler;
FGAircraft* Aircraft;
- FGPosition* Position;
- FGTranslation* Translation;
- FGRotation* Rotation;
+ FGPropagate* Propagate;
FGOutput* Output;
FGAtmosphere* Atmosphere;
FGFCS* FCS;
FGAerodynamics* Aerodynamics;
FGGroundReactions* GroundReactions;
FGPropulsion* Propulsion;
+ FGAuxiliary* Auxiliary;
FGPropertyManager* PropertyManager;
void Debug(int from);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+FGTable::FGTable(int NRows, int NCols, int NTables)
+ : nRows(NTables), nCols(1), nTables(NTables)
+{
+ Type = tt3D;
+ colCounter = 1;
+ rowCounter = 1;
+
+ Data = Allocate(); // this data array will contain the keys for the associated tables
+ Tables.reserve(nTables);
+ for (int i=0; i<nTables; i++) Tables.push_back(FGTable(NRows, NCols));
+
+ Debug(0);
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
FGTable::FGTable(int NRows, int NCols) : nRows(NRows), nCols(NCols)
{
if (NCols > 1) {
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+FGTable::FGTable(const FGTable& t)
+{
+ Type = t.Type;
+ colCounter = t.colCounter;
+ rowCounter = t.rowCounter;
+ tableCounter = t.tableCounter;
+
+ nRows = t.nRows;
+ nCols = t.nCols;
+ nTables = t.nTables;
+
+ Tables = t.Tables;
+ Data = Allocate();
+ for (int r=0; r<=nRows; r++) {
+ for (int c=0; c<=nCols; c++) {
+ Data[r][c] = t.Data[r][c];
+ }
+ }
+ lastRowIndex = t.lastRowIndex;
+ lastColumnIndex = t.lastColumnIndex;
+ lastTableIndex = t.lastTableIndex;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
double** FGTable::Allocate(void)
{
Data = new double*[nRows+1];
FGTable::~FGTable()
{
+ if (nTables > 0) Tables.clear();
for (int r=0; r<=nRows; r++) if (Data[r]) delete[] Data[r];
if (Data) delete[] Data;
Debug(1);
{
double Factor, Value, Span;
int r=lastRowIndex;
-
- //if the key is off the end of the table, just return the
+
+ //if the key is off the end of the table, just return the
//end-of-table value, do not extrapolate
if( key <= Data[1][0] ) {
lastRowIndex=2;
lastRowIndex=nRows;
//cout << "Key over table: " << key << endl;
return Data[nRows][1];
- }
+ }
// the key is somewhere in the middle, search for the right breakpoint
// assume the correct breakpoint has not changed since last frame or
// has only changed very little
-
+
if ( r > 2 && Data[r-1][0] > key ) {
while( Data[r-1][0] > key && r > 2) { r--; }
- } else if ( Data[r][0] < key ) {
- while( Data[r][0] <= key && r <= nRows) { r++; }
- }
-
- lastRowIndex=r;
+ } else if ( Data[r][0] < key ) {
+ while( Data[r][0] <= key && r <= nRows) { r++; }
+ }
+
+ lastRowIndex=r;
// make sure denominator below does not go to zero.
-
+
Span = Data[r][0] - Data[r-1][0];
if (Span != 0.0) {
Factor = (key - Data[r-1][0]) / Span;
double rFactor, cFactor, col1temp, col2temp, Value;
int r=lastRowIndex;
int c=lastColumnIndex;
-
+
if ( r > 2 && Data[r-1][0] > rowKey ) {
while ( Data[r-1][0] > rowKey && r > 2) { r--; }
- } else if ( Data[r][0] < rowKey ) {
+ } else if ( Data[r][0] < rowKey ) {
// cout << Data[r][0] << endl;
while ( r <= nRows && Data[r][0] <= rowKey ) { r++; }
- if ( r > nRows ) r = nRows;
- }
-
+ if ( r > nRows ) r = nRows;
+ }
+
if ( c > 2 && Data[0][c-1] > colKey ) {
while( Data[0][c-1] > colKey && c > 2) { c--; }
- } else if ( Data[0][c] < colKey ) {
- while( Data[0][c] <= colKey && c <= nCols) { c++; }
- if ( c > nCols ) c = nCols;
- }
+ } else if ( Data[0][c] < colKey ) {
+ while( Data[0][c] <= colKey && c <= nCols) { c++; }
+ if ( c > nCols ) c = nCols;
+ }
lastRowIndex=r;
lastColumnIndex=c;
-
+
rFactor = (rowKey - Data[r-1][0]) / (Data[r][0] - Data[r-1][0]);
cFactor = (colKey - Data[0][c-1]) / (Data[0][c] - Data[0][c-1]);
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+double FGTable::GetValue(double rowKey, double colKey, double tableKey)
+{
+ double Factor, Value, Span;
+ int r=lastRowIndex;
+
+ //if the key is off the end (or before the beginning) of the table,
+ // just return the boundary-table value, do not extrapolate
+
+ if( tableKey <= Data[1][1] ) {
+ lastRowIndex=2;
+ return Tables[0].GetValue(rowKey, colKey);
+ } else if ( tableKey >= Data[nRows][1] ) {
+ lastRowIndex=nRows;
+ return Tables[nRows-1].GetValue(rowKey, colKey);
+ }
+
+ // the key is somewhere in the middle, search for the right breakpoint
+ // assume the correct breakpoint has not changed since last frame or
+ // has only changed very little
+
+ if ( r > 2 && Data[r-1][1] > tableKey ) {
+ while( Data[r-1][1] > tableKey && r > 2) { r--; }
+ } else if ( Data[r][1] < tableKey ) {
+ while( Data[r][1] <= tableKey && r <= nRows) { r++; }
+ }
+
+ lastRowIndex=r;
+ // make sure denominator below does not go to zero.
+
+ Span = Data[r][1] - Data[r-1][1];
+ if (Span != 0.0) {
+ Factor = (tableKey - Data[r-1][1]) / Span;
+ if (Factor > 1.0) Factor = 1.0;
+ } else {
+ Factor = 1.0;
+ }
+
+ Value = Factor*(Tables[r-1].GetValue(rowKey, colKey) - Tables[r-2].GetValue(rowKey, colKey))
+ + Tables[r-1].GetValue(rowKey, colKey);
+
+ return Value;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
void FGTable::operator<<(FGConfigFile& infile)
{
- int startRow;
+ int startRow=0;
+ int startCol=0;
+ int tableCtr=0;
- if (Type == tt1D) startRow = 1;
- else startRow = 0;
+ if (Type == tt1D || Type == tt3D) startRow = 1;
+ if (Type == tt3D) startCol = 1;
for (int r=startRow; r<=nRows; r++) {
- for (int c=0; c<=nCols; c++) {
+ for (int c=startCol; c<=nCols; c++) {
if (r != 0 || c != 0) {
infile >> Data[r][c];
+ if (Type == tt3D) {
+ Tables[tableCtr] << infile;
+ tableCtr++;
+ }
}
}
}
void FGTable::Print(void)
{
- int startRow;
+ int startRow=0;
+ int startCol=0;
- if (Type == tt1D) startRow = 1;
- else startRow = 0;
+ if (Type == tt1D || Type == tt3D) startRow = 1;
+ if (Type == tt3D) startCol = 1;
#if defined (sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
unsigned long flags = cout.setf(ios::fixed);
#endif
cout.precision(4);
-
for (int r=startRow; r<=nRows; r++) {
cout << " ";
- for (int c=0; c<=nCols; c++) {
+ for (int c=startCol; c<=nCols; c++) {
if (r == 0 && c == 0) {
- cout << " ";
+ cout << " ";
} else {
- cout << Data[r][c] << " ";
+ cout << Data[r][c] << " ";
+ if (Type == tt3D) {
+ cout << endl;
+ Tables[r-1].Print();
+ }
}
}
cout << endl;
#include "FGConfigFile.h"
#include "FGJSBBase.h"
+#include <vector>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
FORWARD DECLARATIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+using std::vector;
+
namespace JSBSim {
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Lookup table class.
- Models a lookup table for use in FGCoefficient, FGPropeller, etc.
+ Models a one, two, or three dimensional lookup table for use in FGCoefficient,
+ FGPropeller, etc. A one-dimensional table is called a "VECTOR" in a coefficient
+ definition. For example:
+<pre>
+ \<COEFFICIENT NAME="{short name}" TYPE="VECTOR">
+ {name}
+ {number of rows}
+ {row lookup property}
+ {non-dimensionalizing properties}
+ {row_1_key} {col_1_data}
+ {row_2_key} {... }
+ { ... } {... }
+ {row_n_key} {... }
+ \</COEFFICIENT>
+</pre>
+ A "real life" example is as shown here:
+<pre>
+ \<COEFFICIENT NAME="CLDf" TYPE="VECTOR">
+ Delta_lift_due_to_flap_deflection
+ 4
+ fcs/flap-pos-deg
+ aero/qbar-psf | metrics/Sw-sqft
+ 0 0
+ 10 0.20
+ 20 0.30
+ 30 0.35
+ \</COEFFICIENT>
+</pre>
+ The first column in the data table represents the lookup index (or "key"). In
+ this case, the lookup index is fcs/flap-pos-deg (flap extension in degrees).
+ If the flap position is 10 degrees, the value returned from the lookup table
+ would be 0.20. This value would be multiplied by qbar (aero/qbar-psf) and wing
+ area (metrics/Sw-sqft) to get the total lift force that is a result of flap
+ deflection (measured in pounds force). If the value of the flap-pos-deg property
+ was 15 (degrees), the value output by the table routine would be 0.25 - an
+ interpolation. If the flap position in degrees ever went below 0.0, or above
+ 30 (degrees), the output from the table routine would be 0 and 0.35, respectively.
+ That is, there is no _extrapolation_ to values outside the range of the lookup
+ index. This is why it is important to chose the data for the table wisely.
+
+ The definition for a 2D table - referred to simply as a TABLE, is as follows:
+<pre>
+ \<COEFFICIENT NAME="{short name}" TYPE="TABLE">
+ {name}
+ {number of rows}
+ {number of columns}
+ {row lookup property}
+ {column lookup property}
+ {non-dimensionalizing}
+ {col_1_key col_2_key ... col_n_key }
+ {row_1_key} {col_1_data col_2_data ... col_n_data}
+ {row_2_key} {... ... ... ... }
+ { ... } {... ... ... ... }
+ {row_n_key} {... ... ... ... }
+ \</COEFFICIENT>
+</pre>
+ A "real life" example is as shown here:
+<pre>
+ \<COEFFICIENT NAME="CYb" TYPE="TABLE">
+ Side_force_due_to_beta
+ 3
+ 2
+ aero/beta-rad
+ fcs/flap-pos-deg
+ aero/qbar-psf | metrics/Sw-sqft
+ 0 30
+ -0.349 0.137 0.106
+ 0 0 0
+ 0.349 -0.137 -0.106
+ \</COEFFICIENT>
+</pre>
+ The definition for a 3D table in a coefficient would be (for example):
+<pre>
+ \<COEFFICIENT NAME="{short name}" TYPE="TABLE3D">
+ {name}
+ {number of rows}
+ {number of columns}
+ {number of tables}
+ {row lookup property}
+ {column lookup property}
+ {table lookup property}
+ {non-dimensionalizing}
+ {first table key}
+ {col_1_key col_2_key ... col_n_key }
+ {row_1_key} {col_1_data col_2_data ... col_n_data}
+ {row_2_key} {... ... ... ... }
+ { ... } {... ... ... ... }
+ {row_n_key} {... ... ... ... }
+
+ {second table key}
+ {col_1_key col_2_key ... col_n_key }
+ {row_1_key} {col_1_data col_2_data ... col_n_data}
+ {row_2_key} {... ... ... ... }
+ { ... } {... ... ... ... }
+ {row_n_key} {... ... ... ... }
+
+ ...
+
+ \</COEFFICIENT>
+</pre>
+ [At the present time, all rows and columns for each table must have the
+ same dimension.]
+
+ In addition to using a Table for something like a coefficient, where all the
+ row and column elements are read in from a file, a Table could be created
+ and populated completely within program code:
+<pre>
+ // First column is thi, second is neta (combustion efficiency)
+ Lookup_Combustion_Efficiency = new FGTable(12);
+ *Lookup_Combustion_Efficiency << 0.00 << 0.980;
+ *Lookup_Combustion_Efficiency << 0.90 << 0.980;
+ *Lookup_Combustion_Efficiency << 1.00 << 0.970;
+ *Lookup_Combustion_Efficiency << 1.05 << 0.950;
+ *Lookup_Combustion_Efficiency << 1.10 << 0.900;
+ *Lookup_Combustion_Efficiency << 1.15 << 0.850;
+ *Lookup_Combustion_Efficiency << 1.20 << 0.790;
+ *Lookup_Combustion_Efficiency << 1.30 << 0.700;
+ *Lookup_Combustion_Efficiency << 1.40 << 0.630;
+ *Lookup_Combustion_Efficiency << 1.50 << 0.570;
+ *Lookup_Combustion_Efficiency << 1.60 << 0.525;
+ *Lookup_Combustion_Efficiency << 2.00 << 0.345;
+</pre>
+ The first column in the table, above, is thi (the lookup index, or key). The
+ second column is the output data - in this case, "neta" (the Greek letter
+ referring to combustion efficiency). Later on, the table is used like this:
+
+ combustion_efficiency = Lookup_Combustion_Efficiency->GetValue(equivalence_ratio);
+
@author Jon S. Berndt
@version $Id$
@see FGCoefficient
class FGTable : public FGJSBBase
{
public:
+ /// Destructor
~FGTable();
+
+ /** This is the very important copy constructor.
+ @param table a const reference to a table.*/
+ FGTable(const FGTable& table);
+
+ /** The constructor for a VECTOR table
+ @param nRows the number of rows in this VECTOR table. */
FGTable(int nRows);
FGTable(int nRows, int nCols);
+ FGTable(int nRows, int nCols, int numTables);
double GetValue(double key);
double GetValue(double rowKey, double colKey);
+ double GetValue(double rowKey, double colKey, double TableKey);
/** Read the table in.
Data in the config file should be in matrix format with the row
independents as the first column and the column independents in
-5 1 2 3 4 ...
...
</pre>
+
+ For multiple-table (i.e. 3D) data sets there is an additional number
+ key in the table definition. For example:
+
+ <pre>
+ 0.0
+ 0 10 20 30 ...
+ -5 1 2 3 4 ...
+ ...
+ </pre>
*/
+
void operator<<(FGConfigFile&);
FGTable& operator<<(const double n);
FGTable& operator<<(const int n);
inline double GetElement(int r, int c) {return Data[r][c];}
+ inline double GetElement(int r, int c, int t);
void Print(void);
private:
- enum type {tt1D, tt2D} Type;
+ enum type {tt1D, tt2D, tt3D} Type;
double** Data;
- int nRows, nCols;
- int colCounter;
- int rowCounter;
- int lastRowIndex, lastColumnIndex;
+ vector <FGTable> Tables;
+ int nRows, nCols, nTables;
+ int colCounter, rowCounter, tableCounter;
+ int lastRowIndex, lastColumnIndex, lastTableIndex;
double** Allocate(void);
void Debug(int from);
};
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-FGTank::FGTank(FGConfigFile* AC_cfg)
+FGTank::FGTank(FGConfigFile* AC_cfg, FGFDMExec* exec)
{
string token;
double X, Y, Z;
+ Area = 1.0;
+ Temperature = -9999.0;
+ Auxiliary = exec->GetAuxiliary();
type = AC_cfg->GetValue("TYPE");
else if (token == "RADIUS") *AC_cfg >> Radius;
else if (token == "CAPACITY") *AC_cfg >> Capacity;
else if (token == "CONTENTS") *AC_cfg >> Contents;
+ else if (token == "TEMPERATURE") *AC_cfg >> Temperature;
else cerr << "Unknown identifier: " << token << " in tank definition." << endl;
}
PctFull = 0;
}
+ if (Temperature != -9999.0) Temperature = FahrenheitToCelsius(Temperature);
+ Area = 40.0 * pow(Capacity/1975, 0.666666667);
+
Debug(0);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-double FGTank::Reduce(double used)
+double FGTank::Drain(double used)
{
double shortage = Contents - used;
return shortage;
}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTank::Fill(double amount)
+{
+ double overage = 0.0;
+
+ Contents += amount;
+
+ if (Contents > Capacity) {
+ overage = Contents - Capacity;
+ Contents = Capacity;
+ PctFull = 100.0;
+ } else {
+ PctFull = Contents/Capacity*100.0;
+ }
+ return overage;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+void FGTank::SetContents(double amount)
+{
+ Contents = amount;
+ if (Contents > Capacity) {
+ Contents = Capacity;
+ PctFull = 100.0;
+ } else {
+ PctFull = Contents/Capacity*100.0;
+ }
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTank::Calculate(double dt)
+{
+ if (Temperature == -9999.0) return 0.0;
+ double HeatCapacity = 900.0; // Joules/lbm/C
+ double TempFlowFactor = 1.115; // Watts/sqft/C
+ double TAT = Auxiliary->GetTAT_C();
+ double Tdiff = TAT - Temperature;
+ double dT = 0.0; // Temp change due to one surface
+ if (fabs(Tdiff) > 0.1) {
+ dT = (TempFlowFactor * Area * Tdiff * dt) / (Contents * HeatCapacity);
+ }
+ return Temperature += (dT + dT); // For now, assume upper/lower the same
+}
+
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
#include "FGJSBBase.h"
#include "FGConfigFile.h"
#include "FGColumnVector3.h"
+#include "FGAuxiliary.h"
#ifdef FGFS
# include <simgear/compiler.h>
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Models a fuel tank.
+ @author Jon Berndt
+ @see Akbar, Raza et al. "A Simple Analysis of Fuel Addition to the CWT of
+ 747", California Institute of Technology, 1998
+<P>
+ Fuel temperature is calculated using the following assumptions:
+<P>
+ Fuel temperature will only be calculated for tanks which have an initial fuel
+ temperature specified in the configuration file.
+<P>
+ The surface area of the tank is estimated from the capacity in pounds. It
+ is assumed that the tank is a wing tank with dimensions h by 4h by 10h. The
+ volume of the tank is then 40(h)(h)(h). The area of the upper or lower
+ surface is then 40(h)(h). The volume is also equal to the capacity divided
+ by 49.368 lbs/cu-ft, for jet fuel. The surface area of one side can then be
+ derived from the tank's capacity.
+<P>
+ The heat capacity of jet fuel is assumed to be 900 Joules/lbm/K, and the
+ heat transfer factor of the tank is 1.115 Watts/sq-ft/K.
+<P>
+Configuration File Format
+<pre>
+\<AC_TANK TYPE="\<FUEL | OXIDIZER>" NUMBER="\<n>">
+ XLOC \<x location>
+ YLOC \<y location>
+ ZLOC \<z location>
+ RADIUS \<radius>
+ CAPACITY \<capacity>
+ CONTENTS \<contents>
+ TEMPERATURE \<fuel temperature>
+\</AC_TANK>
+</pre>
+Definition of the tank configuration file parameters:
+<pre>
+<b>TYPE</b> - One of FUEL or OXIDIZER.
+<b>XLOC</b> - Location of tank on aircraft's x-axis, inches.
+<b>YLOC</b> - Location of tank on aircraft's y-axis, inches.
+<b>ZLOC</b> - Location of tank on aircraft's z-axis, inches.
+<b>RADIUS</b> - Equivalent radius of tank, inches, for modeling slosh.
+<b>CAPACITY</b> - Capacity in pounds.
+<b>CONTENTS</b> - Initial contents in pounds.
+<b>TEMPERATURE</b> - Initial temperature in degrees Fahrenheit.
+</pre>
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
class FGTank : public FGJSBBase
{
public:
- FGTank(FGConfigFile*);
+ FGTank(FGConfigFile*, FGFDMExec*);
~FGTank();
- double Reduce(double);
+ double Drain(double);
+ double Calculate(double dt);
int GetType(void) {return Type;}
bool GetSelected(void) {return Selected;}
double GetPctFull(void) {return PctFull;}
double GetContents(void) {return Contents;}
+ double GetTemperature_degC(void) {return Temperature;}
+ double GetTemperature(void) {return CelsiusToFahrenheit(Temperature);}
const FGColumnVector3& GetXYZ(void) {return vXYZ;}
double GetXYZ(int idx) {return vXYZ(idx);}
- void SetContents(double contents) { Contents = contents; }
+ double Fill(double amount);
+ void SetContents(double amount);
+ void SetTemperature(double temp) { Temperature = temp; }
enum TankType {ttUNKNOWN, ttFUEL, ttOXIDIZER};
double Radius;
double PctFull;
double Contents;
+ double Area;
+ double Temperature;
bool Selected;
+ FGAuxiliary* Auxiliary;
void Debug(int from);
};
}
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+#include <sstream>
+
#include "FGThruster.h"
namespace JSBSim {
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-FGThruster::FGThruster(FGFDMExec *FDMExec) : FGForce(FDMExec),
- ThrusterNumber(0)
+FGThruster::FGThruster(FGFDMExec *FDMExec) : FGForce(FDMExec)
{
Type = ttDirect;
SetTransformType(FGForce::tCustom);
FGThruster::FGThruster(FGFDMExec *FDMExec,
FGConfigFile *Eng_cfg ): FGForce(FDMExec)
{
- ThrusterNumber = 0;
Type = ttDirect;
SetTransformType(FGForce::tCustom);
Name = Eng_cfg->GetValue();
GearRatio = 1.0;
Debug(0);
-}
+}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Debug(1);
}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGThruster::GetThrusterLabels(int id)
+{
+ std::ostringstream buf;
+
+ buf << Name << "_Thrust[" << id << "]";
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGThruster::GetThrusterValues(int id)
+{
+ std::ostringstream buf;
+
+ buf << Thrust;
+
+ return buf.str();
+}
+
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
#include "FGForce.h"
#include "FGConfigFile.h"
+#include <string>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
virtual double Calculate(double tt) { Thrust = tt; vFn(1) = Thrust; return 0.0; }
void SetName(string name) {Name = name;}
- void SetThrusterNumber(int nn) {ThrusterNumber = nn;}
virtual void SetRPM(double rpm) {};
virtual double GetPowerRequired(void) {return 0.0;}
virtual void SetdeltaT(double dt) {deltaT = dt;}
double GetThrust(void) {return Thrust;}
eType GetType(void) {return Type;}
string GetName(void) {return Name;}
- int GetThrusterNumber(void) {return ThrusterNumber;}
virtual double GetRPM(void) { return 0.0; };
- double GetGearRatio(void) {return GearRatio; }
+ double GetGearRatio(void) {return GearRatio; }
+ virtual string GetThrusterLabels(int id);
+ virtual string GetThrusterValues(int id);
protected:
eType Type;
string Name;
- int ThrusterNumber;
double Thrust;
double PowerRequired;
double deltaT;
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGTranslation.cpp
- Author: Jon Berndt
- Date started: 12/02/98
- Purpose: Integrates the translational EOM
- Called by: FDMExec
-
- ------------- 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.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-This class integrates the translational EOM.
-
-HISTORY
---------------------------------------------------------------------------------
-12/02/98 JSB Created
- 7/23/99 TP Added data member and modified Run and PutState to calcuate
- Mach number
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-COMMENTS, REFERENCES, and NOTES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-[1] Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
- Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
- School, January 1994
-[2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
- JSC 12960, July 1977
-[3] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
- NASA-Ames", NASA CR-2497, January 1975
-[4] Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
- Wiley & Sons, 1979 ISBN 0-471-03032-5
-[5] Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
- 1982 ISBN 0-471-08936-2
-
- The order of rotations used in this class corresponds to a 3-2-1 sequence,
- or Y-P-R, or Z-Y-X, if you prefer.
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGTranslation.h"
-#include "FGRotation.h"
-#include "FGAtmosphere.h"
-#include "FGState.h"
-#include "FGFDMExec.h"
-#include "FGFCS.h"
-#include "FGMassBalance.h"
-#include "FGAircraft.h"
-#include "FGPosition.h"
-#include "FGAuxiliary.h"
-#include "FGOutput.h"
-#include "FGPropertyManager.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_TRANSLATION;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-
-FGTranslation::FGTranslation(FGFDMExec* fdmex) : FGModel(fdmex)
-{
- Name = "FGTranslation";
- qbar = 0;
- qbarUW = 0.0;
- qbarUV = 0.0;
- Vt = 0.0;
- 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();
- vUVWdot_prev[3].InitMatrix();
-
- bind();
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGTranslation::~FGTranslation(void)
-{
- unbind();
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-bool FGTranslation::Run(void)
-{
- if (!FGModel::Run()) {
-
- vUVWdot = vUVW*Rotation->GetPQR() + Aircraft->GetBodyAccel();
-
- vUVW += State->Integrate(FGState::TRAPZ, State->Getdt()*rate, vUVWdot, vUVWdot_prev);
-
- vAeroUVW = vUVW + State->GetTl2b()*Atmosphere->GetWindNED();
-
- Vt = vAeroUVW.Magnitude();
- if ( Vt > 1) {
- if (vAeroUVW(eW) != 0.0)
- alpha = vAeroUVW(eU)*vAeroUVW(eU) > 0.0 ? atan2(vAeroUVW(eW), vAeroUVW(eU)) : 0.0;
- if (vAeroUVW(eV) != 0.0)
- beta = vAeroUVW(eU)*vAeroUVW(eU)+vAeroUVW(eW)*vAeroUVW(eW) > 0.0 ? atan2(vAeroUVW(eV),
- sqrt(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW))) : 0.0;
-
- double mUW = (vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW));
- double signU=1;
- if (vAeroUVW(eU) != 0.0)
- signU = vAeroUVW(eU)/fabs(vAeroUVW(eU));
-
- if ( (mUW == 0.0) || (Vt == 0.0) ) {
- adot = 0.0;
- bdot = 0.0;
- } else {
- adot = (vAeroUVW(eU)*vAeroUVW(eW) - vAeroUVW(eW)*vUVWdot(eU))/mUW;
- bdot = (signU*mUW*vUVWdot(eV) - vAeroUVW(eV)*(vAeroUVW(eU)*vUVWdot(eU)
- + vAeroUVW(eW)*vUVWdot(eW)))/(Vt*Vt*sqrt(mUW));
- }
- } else {
- alpha = beta = adot = bdot = 0;
- }
-
- qbar = 0.5*Atmosphere->GetDensity()*Vt*Vt;
- qbarUW = 0.5*Atmosphere->GetDensity()*(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW));
- qbarUV = 0.5*Atmosphere->GetDensity()*(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eV)*vAeroUVW(eV));
- Mach = Vt / Atmosphere->GetSoundSpeed();
- vMachUVW(eU) = vAeroUVW(eU) / Atmosphere->GetSoundSpeed();
- vMachUVW(eV) = vAeroUVW(eV) / Atmosphere->GetSoundSpeed();
- vMachUVW(eW) = vAeroUVW(eW) / Atmosphere->GetSoundSpeed();
-
- if (debug_lvl > 1) Debug(1);
-
- return false;
- } else {
- return true;
- }
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGTranslation::bind(void)
-{
- typedef double (FGTranslation::*PMF)(int) const;
- PropertyManager->Tie("velocities/u-fps", this,1,
- (PMF)&FGTranslation::GetUVW /*,
- &FGTranslation::SetUVW,
- true */);
- PropertyManager->Tie("velocities/v-fps", this,2,
- (PMF)&FGTranslation::GetUVW /*,
- &FGTranslation::SetUVW,
- true*/);
- PropertyManager->Tie("velocities/w-fps", this,3,
- (PMF)&FGTranslation::GetUVW /*,
- &FGTranslation::SetUVW,
- true*/);
- PropertyManager->Tie("accelerations/udot-fps", this,1,
- (PMF)&FGTranslation::GetUVWdot);
- PropertyManager->Tie("accelerations/vdot-fps", this,2,
- (PMF)&FGTranslation::GetUVWdot);
- PropertyManager->Tie("accelerations/wdot-fps", this,3,
- (PMF)&FGTranslation::GetUVWdot);
- PropertyManager->Tie("velocities/u-aero-fps", this,1,
- (PMF)&FGTranslation::GetAeroUVW);
- PropertyManager->Tie("velocities/v-aero-fps", this,2,
- (PMF)&FGTranslation::GetAeroUVW);
- PropertyManager->Tie("velocities/w-aero-fps", this,3,
- (PMF)&FGTranslation::GetAeroUVW);
- PropertyManager->Tie("aero/alpha-rad", this,
- &FGTranslation::Getalpha,
- &FGTranslation::Setalpha,
- true);
- PropertyManager->Tie("aero/beta-rad", this,
- &FGTranslation::Getbeta,
- &FGTranslation::Setbeta,
- true);
- PropertyManager->Tie("aero/mag-beta-rad", this,
- &FGTranslation::GetMagBeta);
- PropertyManager->Tie("aero/qbar-psf", this,
- &FGTranslation::Getqbar,
- &FGTranslation::Setqbar,
- true);
- PropertyManager->Tie("aero/qbarUW-psf", this,
- &FGTranslation::GetqbarUW,
- &FGTranslation::SetqbarUW,
- true);
- PropertyManager->Tie("aero/qbarUV-psf", this,
- &FGTranslation::GetqbarUV,
- &FGTranslation::SetqbarUV,
- true);
- PropertyManager->Tie("velocities/vt-fps", this,
- &FGTranslation::GetVt,
- &FGTranslation::SetVt,
- true);
- PropertyManager->Tie("velocities/mach-norm", this,
- &FGTranslation::GetMach,
- &FGTranslation::SetMach,
- true);
- PropertyManager->Tie("aero/alphadot-rad_sec", this,
- &FGTranslation::Getadot,
- &FGTranslation::Setadot,
- true);
- PropertyManager->Tie("aero/betadot-rad_sec", this,
- &FGTranslation::Getbdot,
- &FGTranslation::Setbdot,
- true);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-void FGTranslation::unbind(void)
-{
- PropertyManager->Untie("velocities/u-fps");
- PropertyManager->Untie("velocities/v-fps");
- PropertyManager->Untie("velocities/w-fps");
- PropertyManager->Untie("accelerations/udot-fps");
- PropertyManager->Untie("accelerations/vdot-fps");
- PropertyManager->Untie("accelerations/wdot-fps");
- PropertyManager->Untie("velocities/u-aero-fps");
- PropertyManager->Untie("velocities/v-aero-fps");
- PropertyManager->Untie("velocities/w-aero-fps");
- PropertyManager->Untie("aero/alpha-rad");
- PropertyManager->Untie("aero/beta-rad");
- PropertyManager->Untie("aero/qbar-psf");
- PropertyManager->Untie("aero/qbarUW-psf");
- PropertyManager->Untie("aero/qbarUV-psf");
- PropertyManager->Untie("velocities/vt-fps");
- PropertyManager->Untie("velocities/mach-norm");
- PropertyManager->Untie("aero/alphadot-rad_sec");
- PropertyManager->Untie("aero/betadot-rad_sec");
- PropertyManager->Untie("aero/mag-beta-rad");
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// 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 FGTranslation::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: FGTranslation" << endl;
- if (from == 1) cout << "Destroyed: FGTranslation" << 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 (fabs(vUVW(eU)) > 1e6)
- cout << "FGTranslation::U velocity out of bounds: " << vUVW(eU) << endl;
- if (fabs(vUVW(eV)) > 1e6)
- cout << "FGTranslation::V velocity out of bounds: " << vUVW(eV) << endl;
- if (fabs(vUVW(eW)) > 1e6)
- cout << "FGTranslation::W velocity out of bounds: " << vUVW(eW) << endl;
- if (fabs(vUVWdot(eU)) > 1e4)
- cout << "FGTranslation::U acceleration out of bounds: " << vUVWdot(eU) << endl;
- if (fabs(vUVWdot(eV)) > 1e4)
- cout << "FGTranslation::V acceleration out of bounds: " << vUVWdot(eV) << endl;
- if (fabs(vUVWdot(eW)) > 1e4)
- cout << "FGTranslation::W acceleration out of bounds: " << vUVWdot(eW) << endl;
- if (Mach > 100 || Mach < 0.00)
- cout << "FGTranslation::Mach is out of bounds: " << Mach << endl;
- if (qbar > 1e6 || qbar < 0.00)
- cout << "FGTranslation::qbar is out of bounds: " << qbar << endl;
- }
- if (debug_lvl & 64) {
- if (from == 0) { // Constructor
- cout << IdSrc << endl;
- cout << IdHdr << endl;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGTranslation.h
- Author: Jon Berndt
- Date started: 12/02/98
-
- ------------- 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
---------------------------------------------------------------------------------
-12/02/98 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGTRANSLATION_H
-#define FGTRANSLATION_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef FGFS
-# include <simgear/compiler.h>
-# ifdef SG_HAVE_STD_INCLUDES
-# include <cmath>
-# else
-# include <math.h>
-# endif
-#else
-# if defined(sgi) && !defined(__GNUC__)
-# include <math.h>
-# else
-# include <cmath>
-# endif
-#endif
-
-#include "FGModel.h"
-#include "FGColumnVector3.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINITIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_TRANSLATION "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/** Models the translation aspects of the EOM.
- Note: The order of rotations used in this class corresponds to a 3-2-1 sequence,
- or Y-P-R, or Z-Y-X, if you prefer.
- @see Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
- Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
- School, January 1994
- @see D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
- JSC 12960, July 1977
- @see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
- NASA-Ames", NASA CR-2497, January 1975
- @see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
- Wiley & Sons, 1979 ISBN 0-471-03032-5
- @see Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
- 1982 ISBN 0-471-08936-2
- */
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGTranslation : public FGModel {
-public:
- FGTranslation(FGFDMExec*);
- ~FGTranslation();
-
- inline double GetUVW (int idx) const { return vUVW(idx); }
- inline FGColumnVector3& GetUVW (void) { return vUVW; }
- inline FGColumnVector3& GetUVWdot(void) { return vUVWdot; }
- inline double GetUVWdot(int idx) const { return vUVWdot(idx); }
- inline FGColumnVector3& GetAeroUVW (void) { return vAeroUVW; }
- inline double GetAeroUVW (int idx) const { return vAeroUVW(idx); }
-
- double Getalpha(void) const { return alpha; }
- double Getbeta (void) const { return beta; }
- inline double GetMagBeta(void) const { return fabs(beta); }
- double Getqbar (void) const { return qbar; }
- double GetqbarUW (void) const { return qbarUW; }
- double GetqbarUV (void) const { return qbarUV; }
- inline double GetVt (void) const { return Vt; }
- double GetMach (void) const { return Mach; }
- double GetMachU(void) const { return vMachUVW(eU); }
- double Getadot (void) const { return adot; }
- double Getbdot (void) const { return bdot; }
-
- void SetUVW(FGColumnVector3 tt) { vUVW = tt; }
- void SetAeroUVW(FGColumnVector3 tt) { vAeroUVW = tt; }
-
- inline void Setalpha(double tt) { alpha = tt; }
- inline void Setbeta (double tt) { beta = tt; }
- inline void Setqbar (double tt) { qbar = tt; }
- inline void SetqbarUW (double tt) { qbarUW = tt; }
- inline void SetqbarUV (double tt) { qbarUV = tt; }
- inline void SetVt (double tt) { Vt = tt; }
- inline void SetMach (double tt) { Mach=tt; }
- inline void Setadot (double tt) { adot = tt; }
- inline void Setbdot (double tt) { bdot = tt; }
-
- inline void SetAB(double t1, double t2) { alpha=t1; beta=t2; }
-
- bool Run(void);
-
- void bind(void);
- void unbind(void);
-
-private:
- FGColumnVector3 vUVW;
- FGColumnVector3 vUVWdot;
- FGColumnVector3 vUVWdot_prev[4];
- FGColumnVector3 vAeroUVW;
- FGColumnVector3 vMachUVW;
-
- double Vt, Mach;
- double qbar, qbarUW, qbarUV;
- double alpha, beta;
- double adot,bdot;
- void Debug(int from);
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
-
}
fdmex->GetOutput()->Disable();
+
+ fgic->SetPRadpsIC(0.0);
+ fgic->SetQRadpsIC(0.0);
+ fgic->SetRRadpsIC(0.0);
//clear the sub iterations counts & zero out the controls
for(current_axis=0;current_axis<TrimAxes.size();current_axis++) {
<< fgic->GetVtrueFpsIC() << endl;
q=g*(targetNlf-cgamma)/fgic->GetVtrueFpsIC();
cout << targetNlf << ", " << q << endl;
- fdmex->GetRotation()->SetPQR(0,q,0);
+ fgic->SetQRadpsIC(q);
cout << "setPitchRateInPullup() complete" << endl;
}
} else {
p=q=r=0;
}
- fdmex->GetRotation()->SetPQR(p,q,r);
+ fgic->SetPRadpsIC(p);
+ fgic->SetQRadpsIC(q);
+ fgic->SetRRadpsIC(r);
} else if( mode == tPullup && fabs(targetNlf-1) > 0.01) {
float g,q,cgamma;
g=fdmex->GetInertial()->gravity();
cgamma=cos(fgic->GetFlightPathAngleRadIC());
q=g*(targetNlf-cgamma)/fgic->GetVtrueFpsIC();
- fdmex->GetRotation()->SetPQR(0,q,0);
+ fgic->SetQRadpsIC(q);
}
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
+
Header: FGTrimAxis.cpp
Author: Tony Peden
Date started: 7/3/00
-
+
--------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) ---------
-
+
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
--------------------------------------------------------------------------------
7/3/00 TP Created
-
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
case tHmgt: tolerance = 0.01; break;
case tNlf: state_target=1.0; tolerance = 1E-5; break;
case tAll: break;
- }
-
+ }
+
solver_eps=tolerance;
switch(control) {
case tThrottle:
case tAltAGL:
control_min=0;
control_max=30;
- control_value=fdmex->GetPosition()->GetDistanceAGL();
+ control_value=fdmex->GetPropagate()->GetDistanceAGL();
solver_eps=tolerance/100;
break;
case tTheta:
- control_min=fdmex->GetRotation()->Gettht() - 5*degtorad;
- control_max=fdmex->GetRotation()->Gettht() + 5*degtorad;
+ control_min=fdmex->GetPropagate()->Gettht() - 5*degtorad;
+ control_max=fdmex->GetPropagate()->Gettht() + 5*degtorad;
state_convert=radtodeg;
break;
case tPhi:
- control_min=fdmex->GetRotation()->Getphi() - 30*degtorad;
- control_max=fdmex->GetRotation()->Getphi() + 30*degtorad;
+ control_min=fdmex->GetPropagate()->Getphi() - 30*degtorad;
+ control_max=fdmex->GetPropagate()->Getphi() + 30*degtorad;
state_convert=radtodeg;
control_convert=radtodeg;
break;
control_convert=radtodeg;
break;
case tHeading:
- control_min=fdmex->GetRotation()->Getpsi() - 30*degtorad;
- control_max=fdmex->GetRotation()->Getpsi() + 30*degtorad;
+ control_min=fdmex->GetPropagate()->Getpsi() - 30*degtorad;
+ control_max=fdmex->GetPropagate()->Getpsi() + 30*degtorad;
state_convert=radtodeg;
break;
}
-
-
+
+
Debug(0);
}
void FGTrimAxis::getState(void) {
switch(state) {
- case tUdot: state_value=fdmex->GetTranslation()->GetUVWdot(1)-state_target; break;
- case tVdot: state_value=fdmex->GetTranslation()->GetUVWdot(2)-state_target; break;
- case tWdot: state_value=fdmex->GetTranslation()->GetUVWdot(3)-state_target; break;
- case tQdot: state_value=fdmex->GetRotation()->GetPQRdot(2)-state_target;break;
- case tPdot: state_value=fdmex->GetRotation()->GetPQRdot(1)-state_target; break;
- case tRdot: state_value=fdmex->GetRotation()->GetPQRdot(3)-state_target; break;
+ case tUdot: state_value=fdmex->GetPropagate()->GetUVWdot(1)-state_target; break;
+ case tVdot: state_value=fdmex->GetPropagate()->GetUVWdot(2)-state_target; break;
+ case tWdot: state_value=fdmex->GetPropagate()->GetUVWdot(3)-state_target; break;
+ case tQdot: state_value=fdmex->GetPropagate()->GetPQRdot(2)-state_target;break;
+ case tPdot: state_value=fdmex->GetPropagate()->GetPQRdot(1)-state_target; break;
+ case tRdot: state_value=fdmex->GetPropagate()->GetPQRdot(3)-state_target; break;
case tHmgt: state_value=computeHmgt()-state_target; break;
case tNlf: state_value=fdmex->GetAircraft()->GetNlf()-state_target; break;
case tAll: break;
void FGTrimAxis::getControl(void) {
switch(control) {
case tThrottle: control_value=fdmex->GetFCS()->GetThrottleCmd(0); break;
- case tBeta: control_value=fdmex->GetTranslation()->Getalpha(); break;
- case tAlpha: control_value=fdmex->GetTranslation()->Getbeta(); break;
+ case tBeta: control_value=fdmex->GetAuxiliary()->Getalpha(); break;
+ case tAlpha: control_value=fdmex->GetAuxiliary()->Getbeta(); break;
case tPitchTrim: control_value=fdmex->GetFCS() -> GetPitchTrimCmd(); break;
case tElevator: control_value=fdmex->GetFCS() -> GetDeCmd(); break;
case tRollTrim:
case tAileron: control_value=fdmex->GetFCS() -> GetDaCmd(); break;
case tYawTrim:
case tRudder: control_value=fdmex->GetFCS() -> GetDrCmd(); break;
- case tAltAGL: control_value=fdmex->GetPosition()->GetDistanceAGL();break;
- case tTheta: control_value=fdmex->GetRotation()->Gettht(); break;
- case tPhi: control_value=fdmex->GetRotation()->Getphi(); break;
- case tGamma: control_value=fdmex->GetPosition()->GetGamma();break;
- case tHeading: control_value=fdmex->GetRotation()->Getpsi(); break;
+ case tAltAGL: control_value=fdmex->GetPropagate()->GetDistanceAGL();break;
+ case tTheta: control_value=fdmex->GetPropagate()->Gettht(); break;
+ case tPhi: control_value=fdmex->GetPropagate()->Getphi(); break;
+ case tGamma: control_value=fdmex->GetAuxiliary()->GetGamma();break;
+ case tHeading: control_value=fdmex->GetPropagate()->Getpsi(); break;
}
}
double FGTrimAxis::computeHmgt(void) {
double diff;
-
- diff = fdmex->GetRotation()->Getpsi() -
- fdmex->GetPosition()->GetGroundTrack();
-
+
+ diff = fdmex->GetPropagate()->Getpsi() -
+ fdmex->GetAuxiliary()->GetGroundTrack();
+
if( diff < -M_PI ) {
return (diff + 2*M_PI);
} else if( diff > M_PI ) {
}
}
-
+
/*****************************************************************************/
}
-
+
/*****************************************************************************/
// the aircraft center of rotation is no longer the cg once the gear
-// contact the ground so the altitude needs to be changed when pitch
-// and roll angle are adjusted. Instead of attempting to calculate the
+// contact the ground so the altitude needs to be changed when pitch
+// and roll angle are adjusted. Instead of attempting to calculate the
// new center of rotation, pick a gear unit as a reference and use its
// location vector to calculate the new height change. i.e. new altitude =
-// earth z component of that vector (which is in body axes )
+// earth z component of that vector (which is in body axes )
void FGTrimAxis::SetThetaOnGround(double ff) {
int center,i,ref;
// favor an off-center unit so that the same one can be used for both
- // pitch and roll. An on-center unit is used (for pitch)if that's all
+ // pitch and roll. An on-center unit is used (for pitch)if that's all
// that's in contact with the ground.
i=0; ref=-1; center=-1;
while( (ref < 0) && (i < fdmex->GetGroundReactions()->GetNumGearUnits()) ) {
ref=i;
else
center=i;
- }
- i++;
+ }
+ i++;
}
if((ref < 0) && (center >= 0)) {
ref=center;
}
cout << "SetThetaOnGround ref gear: " << ref << endl;
if(ref >= 0) {
- double sp=fdmex->GetRotation()->GetSinphi();
- double cp=fdmex->GetRotation()->GetCosphi();
- double lx=fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(1);
- double ly=fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(2);
- double lz=fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(3);
+ double sp = fdmex->GetPropagate()->GetSinphi();
+ double cp = fdmex->GetPropagate()->GetCosphi();
+ double lx = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(1);
+ double ly = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(2);
+ double lz = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(3);
double hagl = -1*lx*sin(ff) +
ly*sp*cos(ff) +
lz*cp*cos(ff);
-
+
fgic->SetAltitudeAGLFtIC(hagl);
cout << "SetThetaOnGround new alt: " << hagl << endl;
- }
- fgic->SetPitchAngleRadIC(ff);
- cout << "SetThetaOnGround new theta: " << ff << endl;
-}
+ }
+ fgic->SetPitchAngleRadIC(ff);
+ cout << "SetThetaOnGround new theta: " << ff << endl;
+}
/*****************************************************************************/
bool FGTrimAxis::initTheta(void) {
- int i,N,iAft, iForward;
- double zAft,zForward,zDiff,theta;
+ int i,N;
+ int iForward = 0;
+ int iAft = 1;
+ double zAft,zForward,zDiff,theta;
double xAft,xForward,xDiff;
- bool level;
+ bool level;
double saveAlt;
-
+
saveAlt=fgic->GetAltitudeAGLFtIC();
fgic->SetAltitudeAGLFtIC(100);
-
-
+
+
N=fdmex->GetGroundReactions()->GetNumGearUnits();
-
+
//find the first wheel unit forward of the cg
//the list is short so a simple linear search is fine
for( i=0; i<N; i++ ) {
break;
}
}
-
- // now adjust theta till the wheels are the same distance from the ground
- xAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(1);
- xForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(1);
- xDiff = xForward - xAft;
- zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
- zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
- zDiff = zForward - zAft;
- level=false;
- theta=fgic->GetPitchAngleDegIC();
- while(!level && (i < 100)) {
- theta+=180.0/M_PI*zDiff/fabs(xDiff);
- fgic->SetPitchAngleDegIC(theta);
- fdmex->RunIC();
- xAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(1);
- xForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(1);
- xDiff = xForward - xAft;
- zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
- zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
- zDiff = zForward - zAft;
+ // now adjust theta till the wheels are the same distance from the ground
+ xAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetBodyLocation(1);
+ xForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetBodyLocation(1);
+ xDiff = xForward - xAft;
+ zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
+ zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
+ zDiff = zForward - zAft;
+ level=false;
+ theta=fgic->GetPitchAngleDegIC();
+ while(!level && (i < 100)) {
+ theta+=radtodeg*atan(zDiff/xDiff);
+ fgic->SetPitchAngleDegIC(theta);
+ fdmex->RunIC();
+ zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
+ zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
zDiff = zForward - zAft;
- //cout << endl << theta << " " << zDiff << endl;
- //cout << "0: " << fdmex->GetGroundReactions()->GetGearUnit(0)->GetLocalGear() << endl;
- //cout << "1: " << fdmex->GetGroundReactions()->GetGearUnit(1)->GetLocalGear() << endl;
- if(fabs(zDiff ) < 0.1)
- level=true;
- i++;
- }
+ //cout << endl << theta << " " << zDiff << endl;
+ //cout << "0: " << fdmex->GetGroundReactions()->GetGearUnit(0)->GetLocalGear() << endl;
+ //cout << "1: " << fdmex->GetGroundReactions()->GetGearUnit(1)->GetLocalGear() << endl;
+ if(fabs(zDiff ) < 0.1)
+ level=true;
+ i++;
+ }
//cout << i << endl;
if (debug_lvl > 0) {
- cout << " Initial Theta: " << fdmex->GetRotation()->Gettht()*radtodeg << endl;
+ cout << " Initial Theta: " << fdmex->GetPropagate()->Gettht()*radtodeg << endl;
cout << " Used gear unit " << iAft << " as aft and " << iForward << " as forward" << endl;
}
control_min=(theta+5)*degtorad;
control_max=(theta-5)*degtorad;
fgic->SetAltitudeAGLFtIC(saveAlt);
- if(i < 100)
+ if(i < 100)
return true;
else
- return false;
-}
+ return false;
+}
/*****************************************************************************/
int i,ref;
i=0; ref=-1;
- //must have an off-center unit here
- while( (ref < 0) && (i < fdmex->GetGroundReactions()->GetNumGearUnits()) ) {
- if( (fdmex->GetGroundReactions()->GetGearUnit(i)->GetWOW()) &&
+ //must have an off-center unit here
+ while ( (ref < 0) && (i < fdmex->GetGroundReactions()->GetNumGearUnits()) ) {
+ if ( (fdmex->GetGroundReactions()->GetGearUnit(i)->GetWOW()) &&
(fabs(fdmex->GetGroundReactions()->GetGearUnit(i)->GetBodyLocation(2)) > 0.01))
ref=i;
- i++;
+ i++;
}
- if(ref >= 0) {
- double st=fdmex->GetRotation()->GetSintht();
- double ct=fdmex->GetRotation()->GetCostht();
- double lx=fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(1);
- double ly=fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(2);
- double lz=fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(3);
+ if (ref >= 0) {
+ double st = sin(fdmex->GetPropagate()->Gettht());
+ double ct = cos(fdmex->GetPropagate()->Gettht());
+ double lx = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(1);
+ double ly = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(2);
+ double lz = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(3);
double hagl = -1*lx*st +
ly*sin(ff)*ct +
lz*cos(ff)*ct;
-
+
fgic->SetAltitudeAGLFtIC(hagl);
- }
+ }
fgic->SetRollAngleRadIC(ff);
-}
+}
/*****************************************************************************/
/*****************************************************************************/
void FGTrimAxis::AxisReport(void) {
-
+
char out[80];
sprintf(out," %20s: %6.2f %5s: %9.2e Tolerance: %3.0e\n",
GetControlName().c_str(), GetControl()*control_convert,
- GetStateName().c_str(), GetState()+state_target, GetTolerance());
+ GetStateName().c_str(), GetState()+state_target, GetTolerance());
cout << out;
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Module: FGTurbine.cpp
- Author: Jon S. Berndt
- Date started: 08/23/2002
+ Author: David Culp
+ Date started: 03/11/2003
Purpose: This module models a turbine engine.
- ------------- Copyright (C) 2002 Jon S. Berndt (jsb@hal-pc.org) --------------
+ ------------- Copyright (C) 2003 David Culp (davidculp2@comcast.net) ---------
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
FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------
-This class descends from the FGEngine class and models a Turbine engine based
+This class descends from the FGEngine class and models a turbine engine based
on parameters given in the engine config file for this class
HISTORY
--------------------------------------------------------------------------------
-08/23/2002 JSB Created
+03/11/2003 DPC Created
+09/08/2003 DPC Changed Calculate() and added engine phases
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include <vector>
-#include "FGTurbine.h"
+#include <sstream>
+#include "FGTurbine.h"
namespace JSBSim {
FGTurbine::FGTurbine(FGFDMExec* exec, FGConfigFile* cfg) : FGEngine(exec)
{
+ SetDefaults();
+
Load(cfg);
- PowerCommand=0;
Debug(0);
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+// The main purpose of Calculate() is to determine what phase the engine should
+// be in, then call the corresponding function.
-double FGTurbine::Calculate(double dummy)
+double FGTurbine::Calculate(void)
{
- double idle,mil,aug;
- double throttle=FCS->GetThrottlePos(EngineNumber);
- double dt=State->Getdt();
- if( dt > 0 ) {
- PowerCommand+=dt*PowerLag( PowerCommand,
- ThrottleToPowerCommand(throttle) );
- if(PowerCommand > 100 )
- PowerCommand=100;
- else if(PowerCommand < 0 )
- PowerCommand=0;
-
- } else {
- PowerCommand=ThrottleToPowerCommand(throttle);
- }
-
- mil=MaxMilThrust*ThrustTables[1]->TotalValue();
-
- if( PowerCommand <= 50 ) {
- idle=MaxMilThrust*ThrustTables[0]->TotalValue();
- Thrust = idle + (mil-idle)*PowerCommand*0.02;
+ TAT = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556;
+ dt = State->Getdt() * Propulsion->GetRate();
+ ThrottlePos = FCS->GetThrottlePos(EngineNumber);
+ if (ThrottlePos > 1.0) {
+ AugmentCmd = ThrottlePos - 1.0;
+ ThrottlePos -= AugmentCmd;
} else {
- aug=MaxAugThrust*ThrustTables[2]->TotalValue();
- Thrust = mil + (aug-mil)*(PowerCommand-50)*0.02;
- }
-
- ConsumeFuel();
-
- return Thrust;
+ AugmentCmd = 0.0;
+ }
+
+ // When trimming is finished check if user wants engine OFF or RUNNING
+ if ((phase == tpTrim) && (dt > 0)) {
+ if (Running && !Starved) {
+ phase = tpRun;
+ N2 = IdleN2 + ThrottlePos * N2_factor;
+ N1 = IdleN1 + ThrottlePos * N1_factor;
+ OilTemp_degK = 366.0;
+ Cutoff = false;
+ }
+ else {
+ phase = tpOff;
+ Cutoff = true;
+ EGT_degC = TAT;
+ }
+ }
+
+ if (!Running && Cutoff && Starter) {
+ if (phase == tpOff) phase = tpSpinUp;
+ }
+ if (!Running && !Cutoff && (N2 > 15.0)) phase = tpStart;
+ if (Cutoff && (phase != tpSpinUp)) phase = tpOff;
+ if (dt == 0) phase = tpTrim;
+ if (Starved) phase = tpOff;
+ if (Stalled) phase = tpStall;
+ if (Seized) phase = tpSeize;
+
+ switch (phase) {
+ case tpOff: Thrust = Off(); break;
+ case tpRun: Thrust = Run(); break;
+ case tpSpinUp: Thrust = SpinUp(); break;
+ case tpStart: Thrust = Start(); break;
+ case tpStall: Thrust = Stall(); break;
+ case tpSeize: Thrust = Seize(); break;
+ case tpTrim: Thrust = Trim(); break;
+ default: Thrust = Off();
+ }
+
+ return Thruster->Calculate(Thrust);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-double FGTurbine::ThrottleToPowerCommand(double throttle) {
- if( throttle <= 0.77 )
- return 64.94*throttle;
- else
- return 217.38*throttle - 117.38;
-}
+double FGTurbine::Off(void)
+{
+ double qbar = Auxiliary->Getqbar();
+ Running = false;
+ FuelFlow_pph = Seek(&FuelFlow_pph, 0, 1000.0, 10000.0);
+ N1 = Seek(&N1, qbar/10.0, N1/2.0, N1/2.0);
+ N2 = Seek(&N2, qbar/15.0, N2/2.0, N2/2.0);
+ EGT_degC = Seek(&EGT_degC, TAT, 11.7, 7.3);
+ OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0.2, 0.2);
+ OilPressure_psi = N2 * 0.62;
+ NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
+ EPR = Seek(&EPR, 1.0, 0.2, 0.2);
+ Augmentation = false;
+ return 0.0;
+}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-double FGTurbine::PowerLag(double actual_power, double power_command) {
- double t, p2;
- if( power_command >= 50 ) {
- if( actual_power >= 50 ) {
- t=5;
- p2=power_command;
- } else {
- p2=60;
- t=rtau(p2-actual_power);
- }
+double FGTurbine::Run(void)
+{
+ double idlethrust, milthrust, thrust;
+ double N2norm; // 0.0 = idle N2, 1.0 = maximum N2
+ idlethrust = MilThrust * ThrustTables[0]->TotalValue();
+ milthrust = (MilThrust - idlethrust) * ThrustTables[1]->TotalValue();
+
+ Running = true;
+ Starter = false;
+
+ N2 = Seek(&N2, IdleN2 + ThrottlePos * N2_factor, delay, delay * 3.0);
+ N1 = Seek(&N1, IdleN1 + ThrottlePos * N1_factor, delay, delay * 2.4);
+ N2norm = (N2 - IdleN2) / N2_factor;
+ thrust = idlethrust + (milthrust * N2norm * N2norm);
+ EGT_degC = TAT + 363.1 + ThrottlePos * 357.1;
+ OilPressure_psi = N2 * 0.62;
+ OilTemp_degK = Seek(&OilTemp_degK, 366.0, 1.2, 0.1);
+
+ if (!Augmentation) {
+ double correctedTSFC = TSFC + TSFC - (N2norm * TSFC);
+ FuelFlow_pph = Seek(&FuelFlow_pph, thrust * correctedTSFC, 1000.0, 100000);
+ if (FuelFlow_pph < IdleFF) FuelFlow_pph = IdleFF;
+ NozzlePosition = Seek(&NozzlePosition, 1.0 - N2norm, 0.8, 0.8);
+ thrust = thrust * (1.0 - BleedDemand);
+ EPR = 1.0 + thrust/MilThrust;
+ }
+
+ if (AugMethod == 1) {
+ if ((ThrottlePos > 0.99) && (N2 > 97.0)) {Augmentation = true;}
+ else {Augmentation = false;}
+ }
+
+ if ((Augmented == 1) && Augmentation && (AugMethod < 2)) {
+ thrust = MaxThrust * ThrustTables[2]->TotalValue();
+ FuelFlow_pph = Seek(&FuelFlow_pph, thrust * ATSFC, 5000.0, 10000.0);
+ NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
+ }
+
+ if ((AugmentCmd > 0.0) && (AugMethod == 2)) {
+ Augmentation = true;
+ double tdiff = (MaxThrust * ThrustTables[2]->TotalValue()) - thrust;
+ thrust += (tdiff * AugmentCmd);
+ FuelFlow_pph = Seek(&FuelFlow_pph, thrust * ATSFC, 5000.0, 10000.0);
+ NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
} else {
- if( actual_power >= 50 ) {
- t=5;
- p2=40;
- } else {
- p2=power_command;
- t=rtau(p2-actual_power);
- }
+ Augmentation = false;
}
- return t*(p2-actual_power);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-double FGTurbine::rtau(double delta_power) {
- if( delta_power <= 25 )
- return 1.0;
- else if ( delta_power >= 50)
- return 0.1;
- else
- return 1.9-0.036*delta_power;
+ if ((Injected == 1) && Injection)
+ thrust = thrust * ThrustTables[3]->TotalValue();
+
+ ConsumeFuel();
+ if (Cutoff) phase = tpOff;
+ if (Starved) phase = tpOff;
+
+ return thrust;
}
-
+
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-void FGTurbine::doInlet(void)
+double FGTurbine::SpinUp(void)
{
+ Running = false;
+ FuelFlow_pph = 0.0;
+ N2 = Seek(&N2, 25.18, 3.0, N2/2.0);
+ N1 = Seek(&N1, 5.21, 1.0, N1/2.0);
+ EGT_degC = Seek(&EGT_degC, TAT, 11.7, 7.3);
+ OilPressure_psi = N2 * 0.62;
+ OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0.2, 0.2);
+ EPR = 1.0;
+ NozzlePosition = 1.0;
+ return 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-void FGTurbine::doCompressor(void)
+double FGTurbine::Start(void)
{
+ if ((N2 > 15.0) && !Starved) { // minimum 15% N2 needed for start
+ Cranking = true; // provided for sound effects signal
+ if (N2 < IdleN2) {
+ N2 = Seek(&N2, IdleN2, 2.0, N2/2.0);
+ N1 = Seek(&N1, IdleN1, 1.4, N1/2.0);
+ EGT_degC = Seek(&EGT_degC, TAT + 363.1, 21.3, 7.3);
+ FuelFlow_pph = Seek(&FuelFlow_pph, IdleFF, 103.7, 103.7);
+ OilPressure_psi = N2 * 0.62;
+ }
+ else {
+ phase = tpRun;
+ Running = true;
+ Starter = false;
+ Cranking = false;
+ }
+ }
+ else { // no start if N2 < 15%
+ phase = tpOff;
+ Starter = false;
+ }
+
+ return 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-void FGTurbine::doBleedDuct(void)
+double FGTurbine::Stall(void)
{
+ double qbar = Auxiliary->Getqbar();
+ EGT_degC = TAT + 903.14;
+ FuelFlow_pph = IdleFF;
+ N1 = Seek(&N1, qbar/10.0, 0, N1/10.0);
+ N2 = Seek(&N2, qbar/15.0, 0, N2/10.0);
+ if (ThrottlePos < 0.01) phase = tpRun; // clear the stall with throttle
+
+ return 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-void FGTurbine::doCombustor(void)
+double FGTurbine::Seize(void)
{
+ double qbar = Auxiliary->Getqbar();
+ N2 = 0.0;
+ N1 = Seek(&N1, qbar/20.0, 0, N1/15.0);
+ FuelFlow_pph = IdleFF;
+ OilPressure_psi = 0.0;
+ OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0, 0.2);
+ Running = false;
+ return 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-void FGTurbine::doTurbine(void)
+double FGTurbine::Trim(void)
{
+ double idlethrust, milthrust, thrust, tdiff;
+ idlethrust = MilThrust * ThrustTables[0]->TotalValue();
+ milthrust = (MilThrust - idlethrust) * ThrustTables[1]->TotalValue();
+ thrust = (idlethrust + (milthrust * ThrottlePos * ThrottlePos)) * (1.0 - BleedDemand);
+ if (AugmentCmd > 0.0) {
+ tdiff = (MaxThrust * ThrustTables[2]->TotalValue()) - thrust;
+ thrust += (tdiff * AugmentCmd);
+ }
+ return thrust;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-void FGTurbine::doConvergingNozzle(void)
+double FGTurbine::CalcFuelNeed(void)
{
+ return FuelFlow_pph /3600 * State->Getdt() * Propulsion->GetRate();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-void FGTurbine::doTransition(void)
-{
+double FGTurbine::GetPowerAvailable(void) {
+ if( ThrottlePos <= 0.77 )
+ return 64.94*ThrottlePos;
+ else
+ return 217.38*ThrottlePos - 117.38;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+double FGTurbine::Seek(double *var, double target, double accel, double decel) {
+ double v = *var;
+ if (v > target) {
+ v -= dt * decel;
+ if (v < target) v = target;
+ } else if (v < target) {
+ v += dt * accel;
+ if (v > target) v = target;
+ }
+ return v;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+void FGTurbine::SetDefaults(void)
+{
+ Name = "Not defined";
+ N1 = N2 = 0.0;
+ Type = etTurbine;
+ MilThrust = 10000.0;
+ MaxThrust = 10000.0;
+ BypassRatio = 0.0;
+ TSFC = 0.8;
+ ATSFC = 1.7;
+ IdleN1 = 30.0;
+ IdleN2 = 60.0;
+ MaxN1 = 100.0;
+ MaxN2 = 100.0;
+ Augmented = 0;
+ AugMethod = 0;
+ Injected = 0;
+ BleedDemand = 0.0;
+ ThrottlePos = 0.0;
+ AugmentCmd = 0.0;
+ InletPosition = 1.0;
+ NozzlePosition = 1.0;
+ Augmentation = false;
+ Injection = false;
+ Reversed = false;
+ Cutoff = true;
+ phase = tpOff;
+ Stalled = false;
+ Seized = false;
+ Overtemp = false;
+ Fire = false;
+ EGT_degC = 0.0;
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGTurbine::Load(FGConfigFile *Eng_cfg)
{
- int i;
string token;
+
Name = Eng_cfg->GetValue("NAME");
- cout << Name << endl;
Eng_cfg->GetNextConfigLine();
- *Eng_cfg >> token >> MaxMilThrust;
- *Eng_cfg >> token >> MaxAugThrust;
- i=0;
- while( Eng_cfg->GetValue() != string("/FG_TURBINE") && i < 10){
- ThrustTables.push_back( new FGCoefficient(FDMExec) );
- ThrustTables.back()->Load(Eng_cfg);
- i++;
+ int counter=0;
+
+ while ( ((token = Eng_cfg->GetValue()) != string("/FG_TURBINE")) &&
+ (token != string("/FG_SIMTURBINE")) ) {
+ *Eng_cfg >> token;
+
+ if (token[0] == '<') token.erase(0,1); // Tables are read "<TABLE"
+
+ if (token == "MILTHRUST") *Eng_cfg >> MilThrust;
+ else if (token == "MAXTHRUST") *Eng_cfg >> MaxThrust;
+ else if (token == "BYPASSRATIO") *Eng_cfg >> BypassRatio;
+ else if (token == "BLEED") *Eng_cfg >> BleedDemand;
+ else if (token == "TSFC") *Eng_cfg >> TSFC;
+ else if (token == "ATSFC") *Eng_cfg >> ATSFC;
+ else if (token == "IDLEN1") *Eng_cfg >> IdleN1;
+ else if (token == "IDLEN2") *Eng_cfg >> IdleN2;
+ else if (token == "MAXN1") *Eng_cfg >> MaxN1;
+ else if (token == "MAXN2") *Eng_cfg >> MaxN2;
+ else if (token == "AUGMENTED") *Eng_cfg >> Augmented;
+ else if (token == "AUGMETHOD") *Eng_cfg >> AugMethod;
+ else if (token == "INJECTED") *Eng_cfg >> Injected;
+ else if (token == "MINTHROTTLE") *Eng_cfg >> MinThrottle;
+ else if (token == "TABLE") {
+ if (counter++ == 0) Debug(2); // print engine specs prior to table read
+ ThrustTables.push_back( new FGCoefficient(FDMExec) );
+ ThrustTables.back()->Load(Eng_cfg);
+ }
+ else cerr << "Unhandled token in Engine config file: " << token << endl;
}
+ // Pre-calculations and initializations
+
+ delay = 60.0 / (BypassRatio + 3.0);
+ N1_factor = MaxN1 - IdleN1;
+ N2_factor = MaxN2 - IdleN2;
+ OilTemp_degK = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556 + 273.0;
+ IdleFF = pow(MilThrust, 0.2) * 107.0; // just an estimate
+
return true;
}
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGTurbine::GetEngineLabels(void)
+{
+ std::ostringstream buf;
+
+ buf << Name << "_N1[" << EngineNumber << "], "
+ << Name << "_N2[" << EngineNumber << "], "
+ << Thruster->GetThrusterLabels(EngineNumber);
+
+ return buf.str();
+}
+
+//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+string FGTurbine::GetEngineValues(void)
+{
+ std::ostringstream buf;
+
+ buf << N1 << ", "
+ << N2 << ", "
+ << Thruster->GetThrusterValues(EngineNumber);
+
+ return buf.str();
+}
+
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
if (from == 0) { // Constructor
}
+ if (from == 2) { // called from Load()
+ cout << "\n Engine Name: " << Name << endl;
+ cout << " MilThrust: " << MilThrust << endl;
+ cout << " MaxThrust: " << MaxThrust << endl;
+ cout << " BypassRatio: " << BypassRatio << endl;
+ cout << " TSFC: " << TSFC << endl;
+ cout << " ATSFC: " << ATSFC << endl;
+ cout << " IdleN1: " << IdleN1 << endl;
+ cout << " IdleN2: " << IdleN2 << endl;
+ cout << " MaxN1: " << MaxN1 << endl;
+ cout << " MaxN2: " << MaxN2 << endl;
+ cout << " Augmented: " << Augmented << endl;
+ cout << " AugMethod: " << AugMethod << endl;
+ cout << " Injected: " << Injected << endl;
+ cout << " MinThrottle: " << MinThrottle << endl;
+
+ cout << endl;
+ }
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
if (from == 0) cout << "Instantiated: FGTurbine" << endl;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Header: FGTurbine.h
- Author: Jon S. Berndt
- Date started: 08/23/2002
+ Author: David Culp
+ Date started: 03/11/2003
- ------------- Copyright (C) 2002 Jon S. Berndt (jsb@hal-pc.org) --------------
+ ------------- Copyright (C) 2003 David Culp (davidculp2@comcast.net)----------
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
HISTORY
--------------------------------------------------------------------------------
-08/23/2002 JSB Created
+03/11/2003 DPC Created, based on FGTurbine
+09/22/2003 DPC Added starting, stopping, new framework
+04/29/2004 DPC Renamed from FGSimTurbine to FGTurbine
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY
namespace JSBSim {
+/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+CLASS DOCUMENTATION
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/** This class models a turbine engine. Based on Jon Berndt's FGTurbine module.
+ Here the term "phase" signifies the engine's mode of operation. At any given
+ time the engine is in only one phase. At simulator startup the engine will be
+ placed in the Trim phase in order to provide a simplified thrust value without
+ throttle lag. When trimming is complete the engine will go to the Off phase,
+ unless the value FGEngine::Running has been previously set to true, in which
+ case the engine will go to the Run phase. Once an engine is in the Off phase
+ the full starting procedure (or airstart) must be used to get it running.
+<P>
+ - STARTING (on ground):
+ -# Set the control FGEngine::Starter to true. The engine will spin up to
+ a maximum of about %25 N2 (%5.2 N1). This simulates the action of a
+ pneumatic starter.
+ -# After reaching %15 N2 set the control FGEngine::Cutoff to false. If fuel
+ is available the engine will now accelerate to idle. The starter will
+ automatically be set to false after the start cycle.
+<P>
+ - STARTING (in air):
+ -# Increase speed to obtain a minimum of %15 N2. If this is not possible,
+ the starter may be used to assist.
+ -# Place the control FGEngine::Cutoff to false.
+<P>
+ Ignition is assumed to be on anytime the Cutoff control is set to false,
+ therefore a seperate ignition system is not modeled.
+
+Configuration File Format
+<pre>
+\<FG_TURBINE NAME="<name>">
+ MILTHRUST \<thrust>
+ MAXTHRUST \<thrust>
+ BYPASSRATIO \<bypass ratio>
+ TSFC \<thrust specific fuel consumption>
+ ATSFC \<afterburning thrust specific fuel consumption>
+ IDLEN1 \<idle N1>
+ IDLEN2 \<idle N2>
+ MAXN1 \<max N1>
+ MAXN2 \<max N2>
+ AUGMENTED \<0|1>
+ AUGMETHOD \<0|1>
+ INJECTED \<0|1>
+ ...
+\</FG_TURBINE>
+</pre>
+Definition of the turbine engine configuration file parameters:
+<pre>
+<b>MILTHRUST</b> - Maximum thrust, static, at sea level, lbf.
+<b>MAXTHRUST</b> - Afterburning thrust, static, at sea level, lbf
+[this value will be ignored when AUGMENTED is zero (false)].
+<b>BYPASSRATIO</b> - Ratio of bypass air flow to core air flow.
+<b>TSFC</b> - Thrust-specific fuel consumption, lbm/hr/lbf
+[i.e. fuel flow divided by thrust].
+<b>ATSFC</b> - Afterburning TSFC, lbm/hr/lbf
+[this value will be ignored when AUGMENTED is zero (false)]
+<b>IDLEN1</b> - Fan rotor rpm (% of max) at idle
+<b>IDLEN2</b> - Core rotor rpm (% of max) at idle
+<b>MAXN1</b> - Fan rotor rpm (% of max) at full throttle [not always 100!]
+<b>MAXN2</b> - Core rotor rpm (% of max) at full throttle [not always 100!]
+<b>AUGMENTED</b>
+ 0 == afterburner not installed
+ 1 == afterburner installed
+<b>AUGMETHOD</b>
+ 0 == afterburner activated by property /engines/engine[n]/augmentation
+ 1 == afterburner activated by pushing throttle above 99% position
+ 2 == throttle range is expanded in the FCS, and values above 1.0 are afterburner range
+ [this item will be ignored when AUGMENTED == 0]
+<b>INJECTED</b>
+ 0 == Water injection not installed
+ 1 == Water injection installed
+</pre>
+ @author David P. Culp
+ @version "$Id$"
+*/
+
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGTurbine : public FGEngine
{
public:
- FGTurbine(FGFDMExec* exec, FGConfigFile* Eng_cfg);
+ /** Constructor
+ @param Executive pointer to executive structure
+ @param Eng_cfg pointer to engine config file instance */
+ FGTurbine(FGFDMExec* Executive, FGConfigFile* Eng_cfg);
+ /// Destructor
~FGTurbine();
- double Calculate(double);
- double GetPowerAvailable(void) { return PowerCommand; }
+ enum phaseType { tpOff, tpRun, tpSpinUp, tpStart, tpStall, tpSeize, tpTrim };
+
+ double Calculate(void);
+ double CalcFuelNeed(void);
+ double GetPowerAvailable(void);
+ double Seek(double* var, double target, double accel, double decel);
+
+ phaseType GetPhase(void) { return phase; }
+
+ bool GetOvertemp(void) {return Overtemp; }
+ bool GetInjection(void) {return Injection;}
+ bool GetFire(void) { return Fire; }
+ bool GetAugmentation(void) {return Augmentation;}
+ bool GetReversed(void) { return Reversed; }
+ bool GetCutoff(void) { return Cutoff; }
+ int GetIgnition(void) {return Ignition;}
+
+ double GetInlet(void) { return InletPosition; }
+ double GetNozzle(void) { return NozzlePosition; }
+ double GetBleedDemand(void) {return BleedDemand;}
+ double GetN1(void) {return N1;}
+ double GetN2(void) {return N2;}
+ double GetEPR(void) {return EPR;}
+ double GetEGT(void) {return EGT_degC;}
+
+ double getOilPressure_psi () const {return OilPressure_psi;}
+ double getOilTemp_degF (void) {return KelvinToFahrenheit(OilTemp_degK);}
+
+ void SetInjection(bool injection) {Injection = injection;}
+ void SetIgnition(int ignition) {Ignition = ignition;}
+ void SetAugmentation(bool augmentation) {Augmentation = augmentation;}
+ void SetPhase( phaseType p ) { phase = p; }
+ void SetEPR(double epr) {EPR = epr;}
+ void SetBleedDemand(double bleedDemand) {BleedDemand = bleedDemand;}
+ void SetReverse(bool reversed) { Reversed = reversed; }
+ void SetCutoff(bool cutoff) { Cutoff = cutoff; }
+
+ string GetEngineLabels(void);
+ string GetEngineValues(void);
private:
+
typedef vector<FGCoefficient*> CoeffArray;
CoeffArray ThrustTables;
- string name;
- double MaxMilThrust;
- double MaxAugThrust;
-
- double PowerCommand;
-
- double ThrottleToPowerCommand(double throttle);
- double PowerLag(double actual_power, double power_command);
- double rtau(double delta_power);
-
- void doInlet(void);
- void doCompressor(void);
- void doBleedDuct(void);
- void doCombustor(void);
- void doTurbine(void);
- void doConvergingNozzle(void);
-
- void doTransition(void);
-
+ phaseType phase; ///< Operating mode, or "phase"
+ double MilThrust; ///< Maximum Unaugmented Thrust, static @ S.L. (lbf)
+ double MaxThrust; ///< Maximum Augmented Thrust, static @ S.L. (lbf)
+ double BypassRatio; ///< Bypass Ratio
+ double TSFC; ///< Thrust Specific Fuel Consumption (lbm/hr/lbf)
+ double ATSFC; ///< Augmented TSFC (lbm/hr/lbf)
+ double IdleN1; ///< Idle N1
+ double IdleN2; ///< Idle N2
+ double N1; ///< N1
+ double N2; ///< N2
+ double MaxN1; ///< N1 at 100% throttle
+ double MaxN2; ///< N2 at 100% throttle
+ double IdleFF; ///< Idle Fuel Flow (lbm/hr)
+ double delay; ///< Inverse spool-up time from idle to 100% (seconds)
+ double dt; ///< Simulator time slice
+ double N1_factor; ///< factor to tie N1 and throttle
+ double N2_factor; ///< factor to tie N2 and throttle
+ double ThrottlePos; ///< FCS-supplied throttle position
+ double AugmentCmd; ///< modulated afterburner command (0.0 to 1.0)
+ double TAT; ///< total air temperature (deg C)
+ bool Stalled; ///< true if engine is compressor-stalled
+ bool Seized; ///< true if inner spool is seized
+ bool Overtemp; ///< true if EGT exceeds limits
+ bool Fire; ///< true if engine fire detected
+ bool Injection;
+ bool Augmentation;
+ bool Reversed;
+ bool Cutoff;
+ int Injected; ///< = 1 if water injection installed
+ int Ignition;
+ int Augmented; ///< = 1 if augmentation installed
+ int AugMethod; ///< = 0 if using property /engine[n]/augmentation
+ ///< = 1 if using last 1% of throttle movement
+ ///< = 2 if using FCS-defined throttle
+ double EGT_degC;
+ double EPR;
+ double OilPressure_psi;
+ double OilTemp_degK;
+ double BleedDemand;
+ double InletPosition;
+ double NozzlePosition;
+
+ double Off(void);
+ double Run(void);
+ double SpinUp(void);
+ double Start(void);
+ double Stall(void);
+ double Seize(void);
+ double Trim(void);
+
+ void SetDefaults(void);
bool Load(FGConfigFile *ENG_cfg);
-
void Debug(int from);
+
};
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Module: FGUtility.cpp
- Author: Jon Berndt
- Date started: 01/09/99
- Purpose: Contains utility classes for the FG FDM
- Called by: FGPosition, et. al.
-
- ------------- 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.
-
-FUNCTIONAL DESCRIPTION
---------------------------------------------------------------------------------
-This class is a container for all utility classes used by the flight dynamics
-model.
-
-HISTORY
---------------------------------------------------------------------------------
-01/09/99 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifdef FGFS
-# include <simgear/compiler.h>
-# ifdef SG_HAVE_STD_INCLUDES
-# include <cmath>
-# else
-# include <math.h>
-# endif
-#else
-# if defined(sgi) && !defined(__GNUC__)
-# include <math.h>
-# else
-# include <cmath>
-# endif
-#endif
-
-#include "FGUtility.h"
-#include "FGState.h"
-#include "FGFDMExec.h"
-
-namespace JSBSim {
-
-static const char *IdSrc = "$Id$";
-static const char *IdHdr = ID_UTILITY;
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS IMPLEMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-FGUtility::FGUtility()
-{
- Debug(0);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-FGUtility::~FGUtility()
-{
- Debug(1);
-}
-
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-// 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 FGUtility::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: FGUtility" << endl;
- if (from == 1) cout << "Destroyed: FGUtility" << 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;
- }
- }
-}
-}
+++ /dev/null
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
- Header: FGUtility.h
- Author: Jon Berndt
- Date started: 01/09/99
-
- ------------- 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
---------------------------------------------------------------------------------
-01/09/99 JSB Created
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-SENTRY
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#ifndef FGUTILITY_H
-#define FGUTILITY_H
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-INCLUDES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#include "FGJSBBase.h"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-DEFINES
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-#define ID_UTILITY "$Id$"
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-FORWARD DECLARATIONS
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-namespace JSBSim {
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DOCUMENTATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-CLASS DECLARATION
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-
-class FGFDMExec;
-class FGState;
-
-class FGUtility : public FGJSBBase
-{
-public:
- FGUtility(void);
- ~FGUtility();
-
-private:
- FGState* State;
- FGFDMExec* FDMExec;
- void Debug(int from);
-};
-}
-//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-#endif
#include <FDM/JSBSim/FGFDMExec.h>
#include <FDM/JSBSim/FGAircraft.h>
#include <FDM/JSBSim/FGFCS.h>
-#include <FDM/JSBSim/FGPosition.h>
-#include <FDM/JSBSim/FGRotation.h>
+#include <FDM/JSBSim/FGPropagate.h>
#include <FDM/JSBSim/FGState.h>
-#include <FDM/JSBSim/FGTranslation.h>
#include <FDM/JSBSim/FGAuxiliary.h>
#include <FDM/JSBSim/FGInitialCondition.h>
#include <FDM/JSBSim/FGTrim.h>
#include <FDM/JSBSim/FGPropertyManager.h>
#include <FDM/JSBSim/FGEngine.h>
#include <FDM/JSBSim/FGPiston.h>
-#include <FDM/JSBSim/FGSimTurbine.h>
+#include <FDM/JSBSim/FGTurbine.h>
#include <FDM/JSBSim/FGRocket.h>
+#include <FDM/JSBSim/FGElectric.h>
#include <FDM/JSBSim/FGNozzle.h>
#include <FDM/JSBSim/FGPropeller.h>
#include <FDM/JSBSim/FGRotor.h>
+#include <FDM/JSBSim/FGTank.h>
#include "JSBSim.hxx"
static inline double
MassBalance = fdmex->GetMassBalance();
Propulsion = fdmex->GetPropulsion();
Aircraft = fdmex->GetAircraft();
- Translation = fdmex->GetTranslation();
- Rotation = fdmex->GetRotation();
- Position = fdmex->GetPosition();
+ Propagate = fdmex->GetPropagate();
Auxiliary = fdmex->GetAuxiliary();
Aerodynamics = fdmex->GetAerodynamics();
GroundReactions = fdmex->GetGroundReactions();
fgic=fdmex->GetIC();
needTrim=true;
- SGPath aircraft_path( globals->get_fg_root() );
- aircraft_path.append( "Aircraft" );
+ SGPath aircraft_path( fgGetString("/sim/aircraft-dir") );
- SGPath engine_path( globals->get_fg_root() );
+ SGPath engine_path( fgGetString("/sim/aircraft-dir") );
engine_path.append( "Engine" );
State->Setdt( dt );
SG_LOG( SG_FLIGHT, SG_ALERT, "num gear units = "
<< GroundReactions->GetNumGearUnits() );
SG_LOG( SG_FLIGHT, SG_ALERT, "This is a very bad thing because with 0 gear units, the ground trimming");
- SG_LOG( SG_FLIGHT, SG_ALERT, "routine (coming up later in the code) will core dump.");
- SG_LOG( SG_FLIGHT, SG_ALERT, "Halting the sim now, and hoping a solution will present itself soon!");
- exit(-1);
+ SG_LOG( SG_FLIGHT, SG_ALERT, "routine (coming up later in the code) will core dump.");
+ SG_LOG( SG_FLIGHT, SG_ALERT, "Halting the sim now, and hoping a solution will present itself soon!");
+ exit(-1);
}
init_gear();
for (unsigned int i = 0; i < Propulsion->GetNumEngines(); i++) {
SGPropertyNode * node = fgGetNode("engines/engine", i, true);
- Propulsion->GetThruster(i)->SetRPM(node->getDoubleValue("rpm") /
- Propulsion->GetThruster(i)->GetGearRatio());
+ Propulsion->GetEngine(i)->GetThruster()->SetRPM(node->getDoubleValue("rpm") /
+ Propulsion->GetEngine(i)->GetThruster()->GetGearRatio());
}
}
// Explicitly call the superclass's
// init method first.
+#ifdef FG_WEATHERCM
+ Atmosphere->UseInternal();
+#else
if (fgGetBool("/environment/params/control-fdm-atmosphere")) {
Atmosphere->UseExternal();
Atmosphere->SetExTemperature(
} else {
Atmosphere->UseInternal();
}
+#endif
fgic->SetVnorthFpsIC( wind_from_north->getDoubleValue() );
fgic->SetVeastFpsIC( wind_from_east->getDoubleValue() );
switch(fgic->GetSpeedSet()) {
case setned:
SG_LOG(SG_FLIGHT,SG_INFO, " Vn,Ve,Vd= "
- << Position->GetVn() << ", "
- << Position->GetVe() << ", "
- << Position->GetVd() << " ft/s");
+ << Propagate->GetVel(eNorth) << ", "
+ << Propagate->GetVel(eEast) << ", "
+ << Propagate->GetVel(eDown) << " ft/s");
break;
case setuvw:
SG_LOG(SG_FLIGHT,SG_INFO, " U,V,W= "
- << Translation->GetUVW(1) << ", "
- << Translation->GetUVW(2) << ", "
- << Translation->GetUVW(3) << " ft/s");
+ << Propagate->GetUVW(1) << ", "
+ << Propagate->GetUVW(2) << ", "
+ << Propagate->GetUVW(3) << " ft/s");
break;
case setmach:
SG_LOG(SG_FLIGHT,SG_INFO, " Mach: "
- << Translation->GetMach() );
+ << Auxiliary->GetMach() );
break;
case setvc:
default:
stall_warning->setDoubleValue(0);
SG_LOG( SG_FLIGHT, SG_INFO, " Bank Angle: "
- << Rotation->Getphi()*RADTODEG << " deg" );
+ << Propagate->Getphi()*RADTODEG << " deg" );
SG_LOG( SG_FLIGHT, SG_INFO, " Pitch Angle: "
- << Rotation->Gettht()*RADTODEG << " deg" );
+ << Propagate->Gettht()*RADTODEG << " deg" );
SG_LOG( SG_FLIGHT, SG_INFO, " True Heading: "
- << Rotation->Getpsi()*RADTODEG << " deg" );
+ << Propagate->Getpsi()*RADTODEG << " deg" );
SG_LOG( SG_FLIGHT, SG_INFO, " Latitude: "
- << Position->GetLatitude() << " deg" );
+ << Propagate->GetLocation().GetLatitudeDeg() << " deg" );
SG_LOG( SG_FLIGHT, SG_INFO, " Longitude: "
- << Position->GetLongitude() << " deg" );
+ << Propagate->GetLocation().GetLongitudeDeg() << " deg" );
SG_LOG( SG_FLIGHT, SG_INFO, " Altitude: "
- << Position->Geth() << " feet" );
+ << Propagate->Geth() << " feet" );
SG_LOG( SG_FLIGHT, SG_INFO, " loaded initial conditions" );
SG_LOG( SG_FLIGHT, SG_INFO, " set dt" );
eng->SetMagnetos( globals->get_controls()->get_magnetos(i) );
break;
} // end FGPiston code block
- case FGEngine::etSimTurbine:
- { // FGSimTurbine code block
- FGSimTurbine* eng = (FGSimTurbine*)Propulsion->GetEngine(i);
+ case FGEngine::etTurbine:
+ { // FGTurbine code block
+ FGTurbine* eng = (FGTurbine*)Propulsion->GetEngine(i);
eng->SetAugmentation( globals->get_controls()->get_augmentation(i) );
eng->SetReverse( globals->get_controls()->get_reverser(i) );
eng->SetInjection( globals->get_controls()->get_water_injection(i) );
eng->SetCutoff( globals->get_controls()->get_cutoff(i) );
eng->SetIgnition( globals->get_controls()->get_ignition(i) );
break;
- } // end FGSimTurbine code block
+ } // end FGTurbine code block
case FGEngine::etRocket:
{ // FGRocket code block
FGRocket* eng = (FGRocket*)Propulsion->GetEngine(i);
} // end FGEngine code block
}
+
_set_Runway_altitude( cur_fdm_state->get_Runway_altitude() );
- Position->SetSeaLevelRadius( get_Sea_level_radius() );
- Position->SetRunwayRadius( get_Runway_altitude()
+ Propagate->SetSeaLevelRadius( get_Sea_level_radius() );
+ Propagate->SetRunwayRadius( get_Runway_altitude()
+ get_Sea_level_radius() );
Atmosphere->SetExTemperature(
tank->SetContents(node->getDoubleValue("level-gal_us") * 6.6);
// tank->SetContents(node->getDoubleValue("level-lb"));
}
+ SGPropertyNode* node = fgGetNode("/systems/refuel", true);
+ Propulsion->SetRefuel(node->getDoubleValue("contact"));
return true;
}
// Velocities
- _set_Velocities_Local( Position->GetVn(),
- Position->GetVe(),
- Position->GetVd() );
+ _set_Velocities_Local( Propagate->GetVel(eNorth),
+ Propagate->GetVel(eEast),
+ Propagate->GetVel(eDown) );
- _set_Velocities_Wind_Body( Translation->GetUVW(1),
- Translation->GetUVW(2),
- Translation->GetUVW(3) );
+ _set_Velocities_Wind_Body( Propagate->GetUVW(1),
+ Propagate->GetUVW(2),
+ Propagate->GetUVW(3) );
// Make the HUD work ...
- _set_Velocities_Ground( Position->GetVn(),
- Position->GetVe(),
- -Position->GetVd() );
+ _set_Velocities_Ground( Propagate->GetVel(eNorth),
+ Propagate->GetVel(eEast),
+ -Propagate->GetVel(eDown) );
- _set_V_rel_wind( Translation->GetVt() );
+ _set_V_rel_wind( Auxiliary->GetVt() );
_set_V_equiv_kts( Auxiliary->GetVequivalentKTS() );
_set_V_calibrated_kts( Auxiliary->GetVcalibratedKTS() );
- _set_V_ground_speed( Position->GetVground() );
-
- _set_Omega_Body( Rotation->GetPQR(1),
- Rotation->GetPQR(2),
- Rotation->GetPQR(3) );
-
- _set_Euler_Rates( Rotation->GetEulerRates(1),
- Rotation->GetEulerRates(2),
- Rotation->GetEulerRates(3) );
+ _set_V_ground_speed( Auxiliary->GetVground() );
- _set_Geocentric_Rates(Position->GetLatitudeDot(),
- Position->GetLongitudeDot(),
- Position->Gethdot() );
+ _set_Omega_Body( Propagate->GetPQR(eP),
+ Propagate->GetPQR(eQ),
+ Propagate->GetPQR(eR) );
- _set_Mach_number( Translation->GetMach() );
+ _set_Euler_Rates( Auxiliary->GetEulerRates(ePhi),
+ Auxiliary->GetEulerRates(eTht),
+ Auxiliary->GetEulerRates(ePsi) );
- // Positions
- _updateGeocentricPosition( Position->GetLatitude(),
- Position->GetLongitude(),
- Position->Geth() );
+ _set_Mach_number( Auxiliary->GetMach() );
// Positions of Visual Reference Point
-/*
- _updateGeocentricPosition( Position->GetLatitudeVRP(),
- Position->GetLongitudeVRP(),
- Position->GethVRP() );
-*/
- _set_Altitude_AGL( Position->GetDistanceAGL() );
+ _updateGeocentricPosition( Auxiliary->GetLocationVRP().GetLatitude(),
+ Auxiliary->GetLocationVRP().GetLongitude(),
+ Auxiliary->GethVRP() );
- _set_Euler_Angles( Rotation->Getphi(),
- Rotation->Gettht(),
- Rotation->Getpsi() );
+ _set_Altitude_AGL( Propagate->GetDistanceAGL() );
- _set_Alpha( Translation->Getalpha() );
- _set_Beta( Translation->Getbeta() );
+ _set_Euler_Angles( Propagate->Getphi(),
+ Propagate->Gettht(),
+ Propagate->Getpsi() );
+ _set_Alpha( Auxiliary->Getalpha() );
+ _set_Beta( Auxiliary->Getbeta() );
- _set_Gamma_vert_rad( Position->GetGamma() );
- _set_Earth_position_angle( Auxiliary->GetEarthPositionAngle() );
+ _set_Gamma_vert_rad( Auxiliary->GetGamma() );
- _set_Climb_Rate( Position->Gethdot() );
+ _set_Earth_position_angle( Auxiliary->GetEarthPositionAngle() );
+ _set_Climb_Rate( Propagate->Gethdot() );
+ const FGMatrix33& Tl2b = Propagate->GetTl2b();
for ( i = 1; i <= 3; i++ ) {
for ( j = 1; j <= 3; j++ ) {
- _set_T_Local_to_Body( i, j, State->GetTl2b(i,j) );
+ _set_T_Local_to_Body( i, j, Tl2b(i,j) );
}
}
char buf[30];
sprintf(buf, "engines/engine[%d]/thruster", i);
SGPropertyNode * tnode = fgGetNode(buf, true);
- FGThruster * thruster = Propulsion->GetThruster(i);
+ FGThruster * thruster = Propulsion->GetEngine(i)->GetThruster();
switch (Propulsion->GetEngine(i)->GetType()) {
case FGEngine::etPiston:
FGRocket* eng = (FGRocket*)Propulsion->GetEngine(i);
} // end FGRocket code block
break;
- case FGEngine::etSimTurbine:
- { // FGSimTurbine code block
- FGSimTurbine* eng = (FGSimTurbine*)Propulsion->GetEngine(i);
+ case FGEngine::etTurbine:
+ { // FGTurbine code block
+ FGTurbine* eng = (FGTurbine*)Propulsion->GetEngine(i);
node->setDoubleValue("n1", eng->GetN1());
node->setDoubleValue("n2", eng->GetN2());
node->setDoubleValue("egt_degf", 32 + eng->GetEGT()*9/5);
node->setDoubleValue("oil-pressure-psi", eng->getOilPressure_psi());
node->setBoolValue("reversed", eng->GetReversed());
node->setBoolValue("cutoff", eng->GetCutoff());
+ node->setDoubleValue("epr", eng->GetEPR());
globals->get_controls()->set_reverser(i, eng->GetReversed() );
globals->get_controls()->set_cutoff(i, eng->GetCutoff() );
globals->get_controls()->set_water_injection(i, eng->GetInjection() );
globals->get_controls()->set_augmentation(i, eng->GetAugmentation() );
- } // end FGSimTurbine code block
+ } // end FGTurbine code block
+ break;
+ case FGEngine::etElectric:
+ { // FGElectric code block
+ FGElectric* eng = (FGElectric*)Propulsion->GetEngine(i);
+ node->setDoubleValue("rpm", eng->getRPM());
+ } // end FGElectric code block
break;
}
if ( ! fuel_freeze->getBoolValue() ) {
for (i = 0; i < Propulsion->GetNumTanks(); i++) {
SGPropertyNode * node = fgGetNode("/consumables/fuel/tank", i, true);
- double contents = Propulsion->GetTank(i)->GetContents();
+ FGTank* tank = Propulsion->GetTank(i);
+ double contents = tank->GetContents();
+ double temp = tank->GetTemperature_degC();
node->setDoubleValue("level-gal_us", contents/6.6);
node->setDoubleValue("level-lb", contents);
- // node->setDoubleValue("temperature_degC",
+ if (temp != -9999.0) node->setDoubleValue("temperature_degC", temp);
}
}
class FGAerodynamics;
class FGInertial;
class FGAircraft;
-class FGTranslation;
-class FGRotation;
-class FGPosition;
+class FGPropagate;
class FGAuxiliary;
class FGOutput;
class FGInitialCondition;
//@{
/** Set geocentric latitude
@param lat latitude in radians measured from the 0 meridian where
- the westerly direction is positive and east is negative */
+ the westerly direction is positive and east is negative */
void set_Latitude(double lat); // geocentric
/** Set longitude
@param lon longitude in radians measured from the equator where
- the northerly direction is positive and south is negative */
+ the northerly direction is positive and south is negative */
void set_Longitude(double lon);
/** Set altitude
Note: this triggers a recalculation of AGL altitude
- @param alt altitude in feet */
+ @param alt altitude in feet */
void set_Altitude(double alt); // triggers re-calc of AGL altitude
//@}
//@{
/** Sets calibrated airspeed
Setting this will trigger a recalc of the other velocity terms.
- @param vc Calibrated airspeed in ft/sec */
+ @param vc Calibrated airspeed in ft/sec */
void set_V_calibrated_kts(double vc);
/** Sets Mach number.
Setting this will trigger a recalc of the other velocity terms.
- @param mach Mach number */
+ @param mach Mach number */
void set_Mach_number(double mach);
/** Sets velocity in N-E-D coordinates.
Setting this will trigger a recalc of the other velocity terms.
- @param north velocity northward in ft/sec
- @param east velocity eastward in ft/sec
- @param down velocity downward in ft/sec */
+ @param north velocity northward in ft/sec
+ @param east velocity eastward in ft/sec
+ @param down velocity downward in ft/sec */
void set_Velocities_Local( double north, double east, double down );
/** Sets aircraft velocity in stability frame.
Setting this will trigger a recalc of the other velocity terms.
- @param u X velocity in ft/sec
- @param v Y velocity in ft/sec
- @param w Z velocity in ft/sec */
+ @param u X velocity in ft/sec
+ @param v Y velocity in ft/sec
+ @param w Z velocity in ft/sec */
void set_Velocities_Wind_Body( double u, double v, double w);
//@}
/** Euler Angle Parameter Set
@param phi roll angle in radians
- @param theta pitch angle in radians
- @param psi heading angle in radians */
+ @param theta pitch angle in radians
+ @param psi heading angle in radians */
void set_Euler_Angles( double phi, double theta, double psi );
/// @name Flight Path Parameter Set
FGPropulsion* Propulsion;
FGMassBalance* MassBalance;
FGAircraft* Aircraft;
- FGTranslation* Translation;
- FGRotation* Rotation;
- FGPosition* Position;
+ FGPropagate* Propagate;
FGAuxiliary* Auxiliary;
FGAerodynamics* Aerodynamics;
FGGroundReactions *GroundReactions;
int runcount;
float trim_elev;
float trim_throttle;
-
+
SGPropertyNode *startup_trim;
SGPropertyNode *trimmed;
SGPropertyNode *pitch_trim;
SGPropertyNode *aileron_trim;
SGPropertyNode *rudder_trim;
SGPropertyNode *stall_warning;
-
+
/* SGPropertyNode *elevator_pos_deg;
SGPropertyNode *left_aileron_pos_deg;
SGPropertyNode *right_aileron_pos_deg;
SGPropertyNode *rudder_pos_deg;
SGPropertyNode *flap_pos_deg; */
-
+
SGPropertyNode *elevator_pos_pct;
SGPropertyNode *left_aileron_pos_pct;
SGPropertyNode *right_aileron_pos_pct;
SGPropertyNode *flap_pos_pct;
SGPropertyNode *speedbrake_pos_pct;
SGPropertyNode *spoilers_pos_pct;
-
+
SGPropertyNode *gear_pos_pct;
-
+
SGPropertyNode *temperature;
SGPropertyNode *pressure;
SGPropertyNode *density;
SGPropertyNode *turbulence_gain;
SGPropertyNode *turbulence_rate;
-
+
SGPropertyNode *wind_from_north;
SGPropertyNode *wind_from_east;
SGPropertyNode *wind_from_down;
-
+
void init_gear(void);
void update_gear(void);
-
+
};
FGAuxiliary.cpp FGAuxiliary.h \
FGCoefficient.cpp FGCoefficient.h \
FGColumnVector3.cpp FGColumnVector3.h \
- FGColumnVector4.cpp FGColumnVector4.h \
FGConfigFile.cpp FGConfigFile.h \
- FGDefs.h \
FGFCS.cpp FGFCS.h \
FGFDMExec.cpp FGFDMExec.h \
FGFactorGroup.cpp FGFactorGroup.h \
FGPiston.cpp FGPiston.h \
FGPropeller.cpp FGPropeller.h \
FGPropulsion.cpp FGPropulsion.h \
- FGPosition.cpp FGPosition.h \
- FGRotation.cpp FGRotation.h \
FGRotor.cpp FGRotor.h \
FGRocket.cpp FGRocket.h \
FGScript.cpp FGScript.h \
FGState.cpp FGState.h \
FGTable.cpp FGTable.h \
FGThruster.cpp FGThruster.h \
- FGTranslation.cpp FGTranslation.h \
FGTrim.cpp FGTrim.h \
FGTrimAxis.cpp FGTrimAxis.h \
FGTurbine.cpp FGTurbine.h \
- FGUtility.cpp FGUtility.h \
FGEngine.cpp FGEngine.h \
FGTank.cpp FGTank.h \
FGfdmSocket.cpp FGfdmSocket.h \
FGTurbine.cpp FGTurbine.h \
FGPropertyManager.cpp FGPropertyManager.h \
- FGSimTurbine.cpp FGSimTurbine.h \
+ FGPropagate.cpp FGPropagate.h \
+ FGLocation.cpp FGLocation.h \
+ FGQuaternion.cpp FGQuaternion.h \
+ FGElectric.cpp FGElectric.h \
JSBSim.cxx JSBSim.hxx
Module: FGFilter.cpp
Author: Jon S. Berndt
Date started: 11/2000
-
+
------------- Copyright (C) 2000 -------------
This program is free software; you can redistribute it and/or modify it under
} else {
*AC_cfg >> token;
InputNodes.push_back( resolveSymbol(token) );
- }
+ }
}
else if (token == "OUTPUT")
{
denom = 2.00*C3 + dt*C4;
ca = (2.00*C1 + dt*C2) / denom;
cb = (dt*C2 - 2.00*C1) / denom;
- cc = (2.00*C3 - dt*C2) / denom;
+ cc = (2.00*C3 - dt*C4) / denom;
break;
case eOrder2:
denom = 4.0*C4 + 2.0*C5*dt + C6*dt*dt;
break;
case eOrder2:
Output = Input * ca + PreviousInput1 * cb + PreviousInput2 * cc
- - PreviousOutput1 * cd - PreviousOutput2 * ce;
+ - PreviousOutput1 * cd - PreviousOutput2 * ce;
break;
case eWashout:
Output = Input * ca - PreviousInput1 * ca + PreviousOutput1 * cb;
Module: FGGain.cpp
Author: Jon S. Berndt
Date started: 4/2000
-
+
------------- Copyright (C) 2000 -------------
This program is free software; you can redistribute it and/or modify it under
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include "FGGain.h"
+#include "FGGain.h"
namespace JSBSim {
OutputPct = 0;
invert = false;
ScheduledBy = 0;
+ clip = false;
+ clipmin = clipmax = 0.0;
Type = AC_cfg->GetValue("TYPE");
Name = AC_cfg->GetValue("NAME");
*AC_cfg >> Min;
} else if (token == "MAX") {
*AC_cfg >> Max;
+ } else if (token == "CLIPTO") {
+ *AC_cfg >> clipmin >> clipmax;
+ if (clipmax > clipmin) {
+ clip = true;
+ }
} else if (token == "INVERT") {
invert = true;
cerr << endl << "The INVERT keyword is being deprecated and will not be "
"supported in the future. Please use a minus sign in front "
- "of an input property in the future." << endl << endl;
+ "of an input property in the future." << endl << endl;
} else if (token == "ROWS") {
*AC_cfg >> Rows;
Table = new FGTable(Rows);
} else if (token == "SCHEDULED_BY") {
token = AC_cfg->GetValue("SCHEDULED_BY");
*AC_cfg >> strScheduledBy;
- ScheduledBy = PropertyManager->GetNode( strScheduledBy );
+ ScheduledBy = PropertyManager->GetNode( strScheduledBy );
} else if (token == "OUTPUT") {
IsOutput = true;
- *AC_cfg >> sOutputIdx;
- OutputNode = PropertyManager->GetNode( sOutputIdx );
-
+ *AC_cfg >> sOutputIdx;
+ OutputNode = PropertyManager->GetNode( sOutputIdx, true );
} else {
AC_cfg->ResetLineIndexToZero();
*Table << *AC_cfg;
}
+ if (clip) {
+ if (Output > clipmax) Output = clipmax;
+ else if (Output < clipmin) Output = clipmin;
+ }
+
if (IsOutput) SetOutput();
return true;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Header: FGGain.h
- Author:
- Date started:
+ Author:
+ Date started:
------------- Copyright (C) -------------
ROWS \<number_of_rows>
\<lookup_value gain_value>
?
+ [CLIPTO \<min> \<max> 1]
[OUTPUT \<property>]
\</COMPONENT>
</pre>
public:
FGGain(FGFCS* fcs, FGConfigFile* AC_cfg);
~FGGain();
-
+
double GetOutputPct() const { return OutputPct; }
-
+
bool Run (void);
private:
FGState* State;
double Gain;
double Min, Max;
+ double clipmin, clipmax;
double OutputPct;
- bool invert;
+ bool invert, clip;
int Rows;
FGPropertyManager* ScheduledBy;
Input = InputNodes[0]->getDoubleValue();
- if (DoScale) Input *= Detents[NumDetents-1];
+ if (DoScale) Input *= Detents[NumDetents-1];
Output = OutputNode->getDoubleValue();
// Process all detent intervals the movement traverses until either the
// final value is reached or the time interval has finished.
- while (0.0 < dt && Input != Output) {
+ while ( 0.0 < dt && !EqualToRoundoff(Input, Output) ) {
// Find the area where Output is in
int ind;
if (Detents[ind] < ThisInput) ThisInput = Detents[ind];
// Compute the time to reach the value in ThisInput
double ThisDt = fabs((ThisInput-Output)/Rate);
- if (ThisDt == 0.0)
- break;
+
// and clip to the timestep size
- if (dt < ThisDt) ThisDt = dt;
+ if (dt < ThisDt) {
+ ThisDt = dt;
+ if (Output < Input)
+ Output += ThisDt*Rate;
+ else
+ Output -= ThisDt*Rate;
+ } else
+ // Handle this case separate to make shure the termination condition
+ // is met even in inexact arithmetics ...
+ Output = ThisInput;
+
dt -= ThisDt;
- // Do the output calculation
- if (Output < Input)
- Output += ThisDt*Rate;
- else
- Output -= ThisDt*Rate;
}
}
class FGKinemat : public FGFCSComponent {
public:
+ /** Initializer.
+ @param fcs A reference to the ccurrent flightcontrolsystem.
+ @param AC_cfg reference to the current aircraft configuration file.
+ Initializes the FGKinemat object from the given configuration
+ file. The Configuration file is expected to be at the stream
+ position where the KINEMAT object starts. Also it is expected to
+ be past the end of the current KINEMAT configuration on exit.
+ */
FGKinemat(FGFCS* fcs, FGConfigFile* AC_cfg);
+
+ /** Destructor.
+ */
~FGKinemat();
+ /** Kinemat output value.
+ @return the current output of the kinemat object on the range of [0,1].
+ */
double GetOutputPct() const { return OutputPct; }
+ /** Run method, overwrites FGModel::Run().
+ @return false on success, true on failure.
+ The routine doing the work.
+ */
bool Run (void);
private:
} else if (token == "OUTPUT") {
IsOutput = true;
*AC_cfg >> sOutputIdx;
- OutputNode = PropertyManager->GetNode(sOutputIdx);
+ OutputNode = PropertyManager->GetNode(sOutputIdx, true);
}
}
{
string token, value;
struct test *current_test;
- struct FGCondition *current_condition;
+ string sOutputIdx;
Type = AC_cfg->GetValue("TYPE");
Name = AC_cfg->GetValue("NAME");
while (AC_cfg->GetValue() != string("/TEST")) {
current_test->conditions.push_back(FGCondition(AC_cfg, PropertyManager));
}
+ AC_cfg->GetNextConfigLine();
+ } else if (token == "OUTPUT") {
+ IsOutput = true;
+ *AC_cfg >> sOutputIdx;
+ *AC_cfg >> sOutputIdx;
+ OutputNode = PropertyManager->GetNode( sOutputIdx, true );
}
- AC_cfg->GetNextConfigLine();
}
FGFCSComponent::bind();
*iTests++;
}
+ if (IsOutput) SetOutput();
+
return true;
}
cout << endl;
*iTests++;
}
+ if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
<pre>
\<COMPONENT NAME="switch1" TYPE="SWITCH"\>
- \<TEST LOGIC="{AND|OR|DEFAULT}" OUTPUT="{property|value}"\>
+ \<TEST LOGIC="{AND|OR|DEFAULT}" VALUE="{property|value}"\>
{property} {conditional} {property|value}
\<CONDITION_GROUP LOGIC="{AND|OR}"\>
{property} {conditional} {property|value}
\</CONDITION_GROUP\>
...
\</TEST>
- \<TEST LOGIC="{AND|OR}" OUTPUT="{property|value}"\>
+ \<TEST LOGIC="{AND|OR}" VALUE="{property|value}"\>
{property} {conditional} {property|value}
...
\</TEST\>
...
+ [OUTPUT \<property>]
\</COMPONENT\>
</pre>