Sync w. JSBSim CVS
This commit is contained in:
parent
56f085b6f1
commit
8e1482f746
86 changed files with 5305 additions and 4950 deletions
|
@ -37,7 +37,7 @@ INCLUDES
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGAerodynamics.h"
|
||||
#include "FGTranslation.h"
|
||||
#include "FGPropagate.h"
|
||||
#include "FGAircraft.h"
|
||||
#include "FGState.h"
|
||||
#include "FGMassBalance.h"
|
||||
|
@ -109,15 +109,15 @@ bool FGAerodynamics::Run(void)
|
|||
|
||||
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();
|
||||
alphaw = Auxiliary->Getalpha() + Aircraft->GetWingIncidence();
|
||||
|
||||
alpha = Translation->Getalpha();
|
||||
alpha = Auxiliary->Getalpha();
|
||||
|
||||
if (alphaclmax != 0) {
|
||||
if (alpha > 0.85*alphaclmax) {
|
||||
|
@ -146,8 +146,8 @@ bool FGAerodynamics::Run(void)
|
|||
|
||||
//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) {
|
||||
|
|
|
@ -75,7 +75,7 @@ INCLUDES
|
|||
#include "FGAerodynamics.h"
|
||||
#include "FGState.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "FGPosition.h"
|
||||
#include "FGPropagate.h"
|
||||
#include "FGPropertyManager.h"
|
||||
|
||||
namespace JSBSim {
|
||||
|
@ -125,7 +125,6 @@ bool FGAircraft::Run(void)
|
|||
if (!FGModel::Run()) { // if false then execute this Run()
|
||||
vForces.InitMatrix();
|
||||
vForces += Aerodynamics->GetForces();
|
||||
vForces += Inertial->GetForces();
|
||||
vForces += Propulsion->GetForces();
|
||||
vForces += GroundReactions->GetForces();
|
||||
|
||||
|
@ -229,7 +228,6 @@ bool FGAircraft::Load(FGConfigFile* AC_cfg)
|
|||
} 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);
|
||||
|
|
|
@ -35,7 +35,7 @@ HISTORY
|
|||
--------------------------------------------------------------------------------
|
||||
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
|
||||
|
@ -51,7 +51,7 @@ INCLUDES
|
|||
#include "FGState.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include "FGAircraft.h"
|
||||
#include "FGPosition.h"
|
||||
#include "FGPropagate.h"
|
||||
#include "FGInertial.h"
|
||||
#include "FGPropertyManager.h"
|
||||
|
||||
|
@ -130,7 +130,7 @@ bool FGAtmosphere::Run(void)
|
|||
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);
|
||||
}
|
||||
|
||||
|
@ -250,10 +250,20 @@ void FGAtmosphere::Calculate(double altitude)
|
|||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// 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;
|
||||
|
@ -261,6 +271,8 @@ square_signed (double value)
|
|||
return value * value;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGAtmosphere::Turbulence(void)
|
||||
{
|
||||
switch (turbType) {
|
||||
|
@ -292,13 +304,13 @@ void FGAtmosphere::Turbulence(void)
|
|||
// 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();
|
||||
|
@ -341,7 +353,7 @@ void FGAtmosphere::Turbulence(void)
|
|||
|
||||
// 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;
|
||||
|
||||
|
@ -350,7 +362,7 @@ void FGAtmosphere::Turbulence(void)
|
|||
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();
|
||||
|
@ -387,7 +399,6 @@ void FGAtmosphere::UseInternal(void) {
|
|||
useExternal=false;
|
||||
}
|
||||
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGAtmosphere::bind(void)
|
||||
|
@ -397,8 +408,8 @@ void FGAtmosphere::bind(void)
|
|||
&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,
|
||||
|
@ -433,7 +444,7 @@ void FGAtmosphere::unbind(void)
|
|||
{
|
||||
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");
|
||||
|
|
|
@ -28,7 +28,7 @@ HISTORY
|
|||
--------------------------------------------------------------------------------
|
||||
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
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -92,6 +92,8 @@ public:
|
|||
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;}
|
||||
|
||||
|
|
|
@ -42,8 +42,7 @@ INCLUDES
|
|||
|
||||
#include "FGAuxiliary.h"
|
||||
#include "FGAerodynamics.h"
|
||||
#include "FGTranslation.h"
|
||||
#include "FGRotation.h"
|
||||
#include "FGPropagate.h"
|
||||
#include "FGAtmosphere.h"
|
||||
#include "FGState.h"
|
||||
#include "FGFDMExec.h"
|
||||
|
@ -64,11 +63,26 @@ CLASS IMPLEMENTATION
|
|||
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();
|
||||
|
||||
|
@ -87,93 +101,136 @@ FGAuxiliary::~FGAuxiliary()
|
|||
|
||||
bool FGAuxiliary::Run()
|
||||
{
|
||||
double A,B,D;
|
||||
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()) {
|
||||
GetState();
|
||||
if (!FGModel::Run())
|
||||
{
|
||||
p = Atmosphere->GetPressure();
|
||||
rhosl = Atmosphere->GetDensitySL();
|
||||
psl = Atmosphere->GetPressureSL();
|
||||
sat = Atmosphere->GetTemperature();
|
||||
|
||||
//calculate total temperature assuming isentropic flow
|
||||
tat=sat*(1 + 0.2*mach*mach);
|
||||
tatc=RankineToCelsius(tat);
|
||||
// Rotation
|
||||
|
||||
if (mach < 1) { //calculate total pressure assuming isentropic flow
|
||||
pt = p*pow((1 + 0.2*machU*machU),3.5);
|
||||
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;
|
||||
}
|
||||
|
||||
B = 5.76*machU*machU/(5.6*machU*machU - 0.8);
|
||||
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();
|
||||
|
||||
// The denominator above is zero for Mach ~ 0.38, for which
|
||||
// we'll never be here, so we're safe
|
||||
// Position
|
||||
|
||||
D = (2.8*machU*machU-0.4)*0.4167;
|
||||
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;
|
||||
|
||||
if (Vt != 0) {
|
||||
hdot_Vt = -vVel(eDown)/Vt;
|
||||
if (fabs(hdot_Vt) <= 1) gamma = asin(hdot_Vt);
|
||||
} else {
|
||||
gamma = 0.0;
|
||||
}
|
||||
|
||||
tat = sat*(1 + 0.2*Mach*Mach); // Total Temperature, isentropic flow
|
||||
tatc = RankineToCelsius(tat);
|
||||
|
||||
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 ) {
|
||||
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;
|
||||
|
@ -184,26 +241,24 @@ bool FGAuxiliary::Run()
|
|||
|
||||
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());
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -211,43 +266,53 @@ double FGAuxiliary::GetCrossWind(void)
|
|||
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);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -261,6 +326,19 @@ void FGAuxiliary::unbind(void)
|
|||
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");
|
||||
|
@ -270,20 +348,23 @@ void FGAuxiliary::unbind(void)
|
|||
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");
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -323,6 +404,10 @@ void FGAuxiliary::Debug(int from)
|
|||
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
|
||||
|
|
|
@ -41,6 +41,8 @@ INCLUDES
|
|||
|
||||
#include "FGModel.h"
|
||||
#include "FGColumnVector3.h"
|
||||
#include "FGLocation.h"
|
||||
#include "FGPropagate.h"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
|
@ -59,6 +61,44 @@ CLASS DOCUMENTATION
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
/** 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$
|
||||
*/
|
||||
|
@ -72,6 +112,7 @@ public:
|
|||
/** Constructor
|
||||
@param Executive a pointer to the parent executive object */
|
||||
FGAuxiliary(FGFDMExec* Executive);
|
||||
|
||||
/// Destructor
|
||||
~FGAuxiliary();
|
||||
|
||||
|
@ -79,49 +120,122 @@ public:
|
|||
@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; }
|
||||
// GET functions
|
||||
|
||||
inline double GetTotalTemperature(void) const { return tat; }
|
||||
inline double GetTAT_C(void) const { return tatc; }
|
||||
// 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; }
|
||||
double GetTotalPressure(void) const { return pt; }
|
||||
double GetTotalTemperature(void) const { return tat; }
|
||||
double GetTAT_C(void) const { return tatc; }
|
||||
|
||||
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); }
|
||||
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); }
|
||||
|
||||
inline double GetEarthPositionAngle(void) const { return earthPosAngle; }
|
||||
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);
|
||||
};
|
||||
|
||||
|
@ -129,4 +243,3 @@ private:
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#endif
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ FGCoefficient::FGCoefficient( FGFDMExec* fdex )
|
|||
Table = (FGTable*)0L;
|
||||
LookupR = LookupC = 0;
|
||||
numInstances = 0;
|
||||
rows = columns = 0;
|
||||
rows = columns = tables = 0;
|
||||
|
||||
StaticValue = 0.0;
|
||||
totalValue = 0.0;
|
||||
|
@ -122,31 +122,37 @@ bool FGCoefficient::Load(FGConfigFile *AC_cfg)
|
|||
*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();
|
||||
|
@ -159,9 +165,9 @@ bool FGCoefficient::Load(FGConfigFile *AC_cfg)
|
|||
}
|
||||
}
|
||||
tmp[j]='\0'; multparms=tmp;
|
||||
end = multparms.length();
|
||||
end = multparms.length();
|
||||
|
||||
n = multparms.find("|");
|
||||
n = multparms.find("|");
|
||||
start = 0;
|
||||
if (multparms != string("none")) {
|
||||
while (n < end && n >= 0) {
|
||||
|
@ -176,9 +182,10 @@ bool FGCoefficient::Load(FGConfigFile *AC_cfg)
|
|||
// 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;
|
||||
|
@ -195,6 +202,21 @@ bool FGCoefficient::Load(FGConfigFile *AC_cfg)
|
|||
|
||||
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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)
|
||||
|
@ -228,7 +250,7 @@ double FGCoefficient::Value(double Val)
|
|||
|
||||
double FGCoefficient::Value(void)
|
||||
{
|
||||
double Value;
|
||||
double Value;
|
||||
|
||||
SD = Value = gain*StaticValue + bias;
|
||||
|
||||
|
@ -258,7 +280,13 @@ double FGCoefficient::TotalValue(void)
|
|||
|
||||
case TABLE:
|
||||
totalValue = Value( LookupR->getDoubleValue(),
|
||||
LookupC->getDoubleValue() );
|
||||
LookupC->getDoubleValue() );
|
||||
break;
|
||||
|
||||
case TABLE3D:
|
||||
totalValue = Value( LookupR->getDoubleValue(),
|
||||
LookupC->getDoubleValue(),
|
||||
LookupT->getDoubleValue() );
|
||||
break;
|
||||
|
||||
case EQUATION:
|
||||
|
@ -289,7 +317,7 @@ void FGCoefficient::DisplayCoeffFactors(void)
|
|||
|
||||
string FGCoefficient::GetSDstring(void)
|
||||
{
|
||||
char buffer[16];
|
||||
char buffer[20];
|
||||
string value;
|
||||
|
||||
sprintf(buffer,"%9.6f",SD);
|
||||
|
@ -385,22 +413,17 @@ void FGCoefficient::Debug(int from)
|
|||
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();
|
||||
|
|
|
@ -68,9 +68,7 @@ class FGState;
|
|||
class FGAtmosphere;
|
||||
class FGFCS;
|
||||
class FGAircraft;
|
||||
class FGTranslation;
|
||||
class FGRotation;
|
||||
class FGPosition;
|
||||
class FGPropagate;
|
||||
class FGAuxiliary;
|
||||
class FGOutput;
|
||||
|
||||
|
@ -107,7 +105,7 @@ public:
|
|||
|
||||
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
|
||||
|
@ -165,18 +163,20 @@ private:
|
|||
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;
|
||||
|
@ -185,9 +185,7 @@ private:
|
|||
FGAtmosphere* Atmosphere;
|
||||
FGFCS* FCS;
|
||||
FGAircraft* Aircraft;
|
||||
FGTranslation* Translation;
|
||||
FGRotation* Rotation;
|
||||
FGPosition* Position;
|
||||
FGPropagate* Propagate;
|
||||
FGAuxiliary* Auxiliary;
|
||||
FGOutput* Output;
|
||||
FGPropertyManager* PropertyManager;
|
||||
|
|
|
@ -66,7 +66,7 @@ FGColumnVector3& FGColumnVector3::operator/=(const double scalar)
|
|||
|
||||
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) );
|
||||
|
|
|
@ -192,6 +192,24 @@ public:
|
|||
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.
|
||||
|
@ -281,7 +299,7 @@ public:
|
|||
*/
|
||||
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.
|
||||
|
|
|
@ -1,317 +0,0 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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
|
||||
|
|
@ -1,131 +0,0 @@
|
|||
/*******************************************************************************
|
||||
|
||||
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
|
||||
|
|
@ -1,12 +1,11 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
Module: FGUtility.cpp
|
||||
Author: Jon Berndt
|
||||
Date started: 01/09/99
|
||||
Purpose: Contains utility classes for the FG FDM
|
||||
Called by: FGPosition, et. al.
|
||||
Module: FGElectric.cpp
|
||||
Author: David Culp
|
||||
Date started: 04/07/2004
|
||||
Purpose: This module models an electric motor
|
||||
|
||||
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
|
||||
--------- 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
|
||||
|
@ -27,62 +26,90 @@
|
|||
|
||||
FUNCTIONAL DESCRIPTION
|
||||
--------------------------------------------------------------------------------
|
||||
This class is a container for all utility classes used by the flight dynamics
|
||||
model.
|
||||
|
||||
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
|
||||
--------------------------------------------------------------------------------
|
||||
01/09/99 JSB Created
|
||||
04/07/2004 DPC 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"
|
||||
#include "FGElectric.h"
|
||||
#include "FGPropulsion.h"
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
static const char *IdSrc = "$Id$";
|
||||
static const char *IdHdr = ID_UTILITY;
|
||||
static const char *IdHdr = ID_ELECTRIC;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS IMPLEMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
FGUtility::FGUtility()
|
||||
FGElectric::FGElectric(FGFDMExec* exec, FGConfigFile* Eng_cfg) : FGEngine(exec)
|
||||
{
|
||||
Debug(0);
|
||||
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
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGUtility::~FGUtility()
|
||||
FGElectric::~FGElectric()
|
||||
{
|
||||
Debug(1);
|
||||
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
|
||||
|
@ -101,18 +128,21 @@ FGUtility::~FGUtility()
|
|||
// 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)
|
||||
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: FGUtility" << endl;
|
||||
if (from == 1) cout << "Destroyed: FGUtility" << endl;
|
||||
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
|
||||
}
|
||||
|
@ -127,4 +157,11 @@ void FGUtility::Debug(int from)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
double
|
||||
FGElectric::CalcFuelNeed(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace JSBSim
|
|
@ -1,10 +1,10 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
Header: FGUtility.h
|
||||
Author: Jon Berndt
|
||||
Date started: 01/09/99
|
||||
Header: FGElectric.h
|
||||
Author: David Culp
|
||||
Date started: 04/07/2004
|
||||
|
||||
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
|
||||
----- 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
|
||||
|
@ -25,26 +25,27 @@
|
|||
|
||||
HISTORY
|
||||
--------------------------------------------------------------------------------
|
||||
01/09/99 JSB Created
|
||||
04/07/2004 DPC Created
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
SENTRY
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#ifndef FGUTILITY_H
|
||||
#define FGUTILITY_H
|
||||
#ifndef FGELECTRIC_H
|
||||
#define FGELECTRIC_H
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGJSBBase.h"
|
||||
#include "FGEngine.h"
|
||||
#include "FGConfigFile.h"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINES
|
||||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_UTILITY "$Id$"
|
||||
#define ID_ELECTRIC "$Id$";
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -56,22 +57,49 @@ 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 FGFDMExec;
|
||||
class FGState;
|
||||
|
||||
class FGUtility : public FGJSBBase
|
||||
class FGElectric : public FGEngine
|
||||
{
|
||||
public:
|
||||
FGUtility(void);
|
||||
~FGUtility();
|
||||
/// 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:
|
||||
FGState* State;
|
||||
FGFDMExec* FDMExec;
|
||||
|
||||
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);
|
||||
};
|
||||
}
|
|
@ -55,6 +55,8 @@ INCLUDES
|
|||
|
||||
#include "FGEngine.h"
|
||||
#include "FGTank.h"
|
||||
#include "FGPropeller.h"
|
||||
#include "FGNozzle.h"
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
|
@ -93,9 +95,7 @@ FGEngine::FGEngine(FGFDMExec* exec)
|
|||
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();
|
||||
|
||||
|
@ -119,17 +119,27 @@ FGEngine::~FGEngine()
|
|||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -171,6 +181,102 @@ void FGEngine::AddFeedTank(int tkID)
|
|||
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
|
||||
|
|
|
@ -59,6 +59,7 @@ INCLUDES
|
|||
#endif
|
||||
|
||||
#include "FGJSBBase.h"
|
||||
#include "FGThruster.h"
|
||||
#include "FGPropertyManager.h"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -81,12 +82,12 @@ class FGState;
|
|||
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
|
||||
|
@ -109,7 +110,7 @@ public:
|
|||
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; }
|
||||
|
@ -138,11 +139,8 @@ public:
|
|||
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
|
||||
|
@ -174,6 +172,15 @@ public:
|
|||
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;
|
||||
|
@ -208,11 +215,10 @@ protected:
|
|||
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);
|
||||
|
@ -223,12 +229,12 @@ protected:
|
|||
#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
|
||||
|
|
|
@ -75,8 +75,6 @@ FGFCS::FGFCS(FGFDMExec* fdmex) : FGModel(fdmex)
|
|||
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;
|
||||
|
@ -117,26 +115,18 @@ bool FGFCS::Run(void)
|
|||
{
|
||||
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;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -297,9 +287,11 @@ bool FGFCS::Load(FGConfigFile* AC_cfg)
|
|||
}
|
||||
|
||||
# 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()) {
|
||||
|
@ -322,11 +314,9 @@ bool FGFCS::Load(FGConfigFile* AC_cfg)
|
|||
|
||||
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;
|
||||
|
@ -400,45 +390,11 @@ bool FGFCS::Load(FGConfigFile* AC_cfg)
|
|||
|
||||
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) {
|
||||
|
@ -484,7 +440,7 @@ string FGFCS::GetComponentValues(void)
|
|||
{
|
||||
unsigned int comp;
|
||||
string CompValues = "";
|
||||
char buffer[10];
|
||||
char buffer[12];
|
||||
bool firstime = true;
|
||||
|
||||
for (comp = 0; comp < FCSComponents.size(); comp++) {
|
||||
|
|
|
@ -83,40 +83,24 @@ CLASS DOCUMENTATION
|
|||
the configuration file. For instance, for the X-15:
|
||||
|
||||
<pre>
|
||||
< FLIGHT_CONTROL NAME="X-15 SAS">
|
||||
\<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 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">
|
||||
ID 1
|
||||
INPUT 0
|
||||
\<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>
|
||||
|
@ -125,17 +109,30 @@ CLASS DOCUMENTATION
|
|||
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
|
||||
|
@ -420,16 +417,6 @@ public:
|
|||
@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);
|
||||
|
||||
|
@ -622,8 +609,6 @@ private:
|
|||
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;
|
||||
|
|
|
@ -64,9 +64,7 @@ INCLUDES
|
|||
#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"
|
||||
|
@ -122,9 +120,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root)
|
|||
Inertial = 0;
|
||||
GroundReactions = 0;
|
||||
Aircraft = 0;
|
||||
Translation = 0;
|
||||
Rotation = 0;
|
||||
Position = 0;
|
||||
Propagate = 0;
|
||||
Auxiliary = 0;
|
||||
Output = 0;
|
||||
IC = 0;
|
||||
|
@ -194,9 +190,7 @@ bool FGFDMExec::Allocate(void)
|
|||
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);
|
||||
|
||||
|
@ -230,15 +224,9 @@ bool FGFDMExec::Allocate(void)
|
|||
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;}
|
||||
|
@ -263,9 +251,7 @@ bool FGFDMExec::Allocate(void)
|
|||
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);
|
||||
|
||||
|
@ -286,9 +272,7 @@ bool FGFDMExec::DeAllocate(void)
|
|||
delete Inertial;
|
||||
delete GroundReactions;
|
||||
delete Aircraft;
|
||||
delete Translation;
|
||||
delete Rotation;
|
||||
delete Position;
|
||||
delete Propagate;
|
||||
delete Auxiliary;
|
||||
delete Output;
|
||||
delete State;
|
||||
|
@ -308,9 +292,7 @@ bool FGFDMExec::DeAllocate(void)
|
|||
Inertial = 0;
|
||||
GroundReactions = 0;
|
||||
Aircraft = 0;
|
||||
Translation = 0;
|
||||
Rotation = 0;
|
||||
Position = 0;
|
||||
Propagate = 0;
|
||||
Auxiliary = 0;
|
||||
Output = 0;
|
||||
|
||||
|
@ -425,9 +407,9 @@ bool FGFDMExec::LoadModel(string model)
|
|||
}
|
||||
|
||||
# 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);
|
||||
|
|
|
@ -27,7 +27,7 @@ HISTORY
|
|||
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
|
||||
|
@ -79,24 +79,23 @@ CLASS DOCUMENTATION
|
|||
|
||||
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$
|
||||
|
@ -185,7 +184,7 @@ public:
|
|||
@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
|
||||
|
@ -208,12 +207,8 @@ public:
|
|||
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.
|
||||
|
@ -228,8 +223,8 @@ public:
|
|||
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; }
|
||||
|
||||
|
@ -273,7 +268,7 @@ private:
|
|||
|
||||
string AircraftPath;
|
||||
string EnginePath;
|
||||
string ControlPath;
|
||||
// string ControlPath;
|
||||
|
||||
string CFGVersion;
|
||||
string Release;
|
||||
|
@ -287,9 +282,7 @@ private:
|
|||
FGInertial* Inertial;
|
||||
FGGroundReactions* GroundReactions;
|
||||
FGAircraft* Aircraft;
|
||||
FGTranslation* Translation;
|
||||
FGRotation* Rotation;
|
||||
FGPosition* Position;
|
||||
FGPropagate* Propagate;
|
||||
FGAuxiliary* Auxiliary;
|
||||
FGOutput* Output;
|
||||
|
||||
|
|
|
@ -69,9 +69,7 @@ class FGState;
|
|||
class FGAtmosphere;
|
||||
class FGFCS;
|
||||
class FGAircraft;
|
||||
class FGTranslation;
|
||||
class FGRotation;
|
||||
class FGPosition;
|
||||
class FGPropagate;
|
||||
class FGAuxiliary;
|
||||
class FGOutput;
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ and the cg.
|
|||
|
||||
#include "FGFDMExec.h"
|
||||
#include "FGAircraft.h"
|
||||
#include "FGTranslation.h"
|
||||
#include "FGPropagate.h"
|
||||
#include "FGMassBalance.h"
|
||||
#include "FGState.h"
|
||||
#include "FGForce.h"
|
||||
|
@ -97,7 +97,7 @@ FGMatrix33 FGForce::Transform(void)
|
|||
case tWindBody:
|
||||
return fdmex->GetState()->GetTs2b();
|
||||
case tLocalBody:
|
||||
return fdmex->GetState()->GetTl2b();
|
||||
return fdmex->GetPropagate()->GetTl2b();
|
||||
case tCustom:
|
||||
case tNone:
|
||||
return mT;
|
||||
|
|
|
@ -331,7 +331,7 @@ private:
|
|||
|
||||
FGMatrix33 mT;
|
||||
|
||||
virtual void Debug(int from);
|
||||
void Debug(int from);
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -35,6 +35,9 @@ HISTORY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "FGGroundReactions.h"
|
||||
#include "FGPropertyManager.h"
|
||||
|
||||
|
@ -43,15 +46,6 @@ namespace JSBSim {
|
|||
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
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
@ -84,7 +78,7 @@ bool FGGroundReactions::Run(void)
|
|||
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.
|
||||
|
@ -126,70 +120,62 @@ bool FGGroundReactions::Load(FGConfigFile* AC_cfg)
|
|||
|
||||
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();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -36,7 +36,7 @@ INCLUDES
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include "FGInertial.h"
|
||||
#include "FGPosition.h"
|
||||
#include "FGPropagate.h"
|
||||
#include "FGState.h"
|
||||
#include "FGMassBalance.h"
|
||||
|
||||
|
@ -60,12 +60,6 @@ FGInertial::FGInertial(FGFDMExec* fgex) : FGModel(fgex)
|
|||
RadiusReference = 20925650.00;
|
||||
gAccelReference = GM/(RadiusReference*RadiusReference);
|
||||
gAccel = GM/(RadiusReference*RadiusReference);
|
||||
vRadius.InitMatrix();
|
||||
vCoriolis.InitMatrix();
|
||||
vCentrifugal.InitMatrix();
|
||||
vGravity.InitMatrix();
|
||||
|
||||
bind();
|
||||
|
||||
Debug(0);
|
||||
}
|
||||
|
@ -74,7 +68,6 @@ FGInertial::FGInertial(FGFDMExec* fgex) : FGModel(fgex)
|
|||
|
||||
FGInertial::~FGInertial(void)
|
||||
{
|
||||
unbind();
|
||||
Debug(1);
|
||||
}
|
||||
|
||||
|
@ -82,42 +75,14 @@ FGInertial::~FGInertial(void)
|
|||
|
||||
bool FGInertial::Run(void)
|
||||
{
|
||||
if (!FGModel::Run()) {
|
||||
// Fast return if we have nothing to do ...
|
||||
if (FGModel::Run()) return true;
|
||||
|
||||
gAccel = GM / (Position->GetRadius()*Position->GetRadius());
|
||||
// Gravitation accel
|
||||
double r = Propagate->GetRadius();
|
||||
gAccel = GetGAccel(r);
|
||||
|
||||
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());
|
||||
|
||||
vOmegaLocal(eX) += Position->GetVe() / Position->GetRadius();
|
||||
vOmegaLocal(eY) += -Position->GetVn() / Position->GetRadius();
|
||||
vOmegaLocal(eZ) += 0.00;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -129,27 +94,6 @@ bool FGInertial::LoadInertial(FGConfigFile* AC_cfg)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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
|
||||
|
|
|
@ -83,27 +83,14 @@ public:
|
|||
~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;
|
||||
|
@ -114,4 +101,3 @@ private:
|
|||
}
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
#endif
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ INCLUDES
|
|||
#include "FGInertial.h"
|
||||
#include "FGAtmosphere.h"
|
||||
#include "FGAerodynamics.h"
|
||||
#include "FGPosition.h"
|
||||
#include "FGPropagate.h"
|
||||
#include "FGConfigFile.h"
|
||||
#include "FGPropertyManager.h"
|
||||
|
||||
|
@ -67,6 +67,7 @@ FGInitialCondition::FGInitialCondition(FGFDMExec *FDMExec)
|
|||
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;
|
||||
|
@ -83,7 +84,7 @@ FGInitialCondition::FGInitialCondition(FGFDMExec *FDMExec)
|
|||
|
||||
if(FDMExec != NULL ) {
|
||||
fdmex=FDMExec;
|
||||
fdmex->GetPosition()->Seth(altitude);
|
||||
fdmex->GetPropagate()->Seth(altitude);
|
||||
fdmex->GetAtmosphere()->Run();
|
||||
PropertyManager=fdmex->GetPropertyManager();
|
||||
bind();
|
||||
|
@ -265,7 +266,7 @@ void FGInitialCondition::SetWBodyFpsIC(double tt) {
|
|||
|
||||
//******************************************************************************
|
||||
|
||||
double FGInitialCondition::GetUBodyFpsIC(void) {
|
||||
double FGInitialCondition::GetUBodyFpsIC(void) const {
|
||||
if(lastSpeedSet == setvg )
|
||||
return u;
|
||||
else
|
||||
|
@ -274,7 +275,7 @@ double FGInitialCondition::GetUBodyFpsIC(void) {
|
|||
|
||||
//******************************************************************************
|
||||
|
||||
double FGInitialCondition::GetVBodyFpsIC(void) {
|
||||
double FGInitialCondition::GetVBodyFpsIC(void) const {
|
||||
if( lastSpeedSet == setvg )
|
||||
return v;
|
||||
else {
|
||||
|
@ -284,7 +285,7 @@ double FGInitialCondition::GetVBodyFpsIC(void) {
|
|||
|
||||
//******************************************************************************
|
||||
|
||||
double FGInitialCondition::GetWBodyFpsIC(void) {
|
||||
double FGInitialCondition::GetWBodyFpsIC(void) const {
|
||||
if( lastSpeedSet == setvg )
|
||||
return w;
|
||||
else
|
||||
|
@ -394,7 +395,7 @@ void FGInitialCondition::calcWindUVW(void) {
|
|||
|
||||
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
|
||||
|
||||
|
@ -422,8 +423,8 @@ void FGInitialCondition::SetAltitudeFtIC(double tt) {
|
|||
//******************************************************************************
|
||||
|
||||
void FGInitialCondition::SetAltitudeAGLFtIC(double tt) {
|
||||
fdmex->GetPosition()->SetDistanceAGL(tt);
|
||||
altitude=fdmex->GetPosition()->Geth();
|
||||
fdmex->GetPropagate()->SetDistanceAGL(tt);
|
||||
altitude=fdmex->GetPropagate()->Geth();
|
||||
SetAltitudeFtIC(altitude);
|
||||
}
|
||||
|
||||
|
@ -925,6 +926,19 @@ void FGInitialCondition::bind(void){
|
|||
&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);
|
||||
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
|
@ -973,6 +987,10 @@ void FGInitialCondition::unbind(void){
|
|||
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");
|
||||
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -192,6 +192,9 @@ public:
|
|||
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);
|
||||
|
||||
|
@ -215,9 +218,12 @@ public:
|
|||
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);
|
||||
|
@ -253,6 +259,7 @@ private:
|
|||
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;
|
||||
|
|
|
@ -78,7 +78,7 @@ const double FGJSBBase::SHRatio = 1.40;
|
|||
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;
|
||||
|
@ -90,12 +90,6 @@ short FGJSBBase::debug_lvl = 1;
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGJSBBase::FGJSBBase()
|
||||
{
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGJSBBase::Message* FGJSBBase::PutMessage(Message* msg)
|
||||
{
|
||||
Messages.push(msg);
|
||||
|
@ -104,7 +98,7 @@ FGJSBBase::Message* FGJSBBase::PutMessage(Message* msg)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGJSBBase::Message* FGJSBBase::PutMessage(string text)
|
||||
FGJSBBase::Message* FGJSBBase::PutMessage(const string& text)
|
||||
{
|
||||
Message *msg = new Message();
|
||||
msg->text = text;
|
||||
|
@ -117,7 +111,7 @@ FGJSBBase::Message* FGJSBBase::PutMessage(string 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;
|
||||
|
@ -131,7 +125,7 @@ FGJSBBase::Message* FGJSBBase::PutMessage(string text, bool bVal)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGJSBBase::Message* FGJSBBase::PutMessage(string text, int iVal)
|
||||
FGJSBBase::Message* FGJSBBase::PutMessage(const string& text, int iVal)
|
||||
{
|
||||
Message *msg = new Message();
|
||||
msg->text = text;
|
||||
|
@ -145,7 +139,7 @@ FGJSBBase::Message* FGJSBBase::PutMessage(string text, int iVal)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
FGJSBBase::Message* FGJSBBase::PutMessage(string text, double dVal)
|
||||
FGJSBBase::Message* FGJSBBase::PutMessage(const string& text, double dVal)
|
||||
{
|
||||
Message *msg = new Message();
|
||||
msg->text = text;
|
||||
|
|
|
@ -38,6 +38,8 @@ SENTRY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <limits>
|
||||
|
||||
#ifdef FGFS
|
||||
# include <simgear/compiler.h>
|
||||
# include <math.h>
|
||||
|
@ -73,17 +75,6 @@ using std::string;
|
|||
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
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
@ -112,10 +103,10 @@ CLASS DECLARATION
|
|||
class FGJSBBase {
|
||||
public:
|
||||
/// Constructor for FGJSBBase.
|
||||
FGJSBBase();
|
||||
FGJSBBase() {};
|
||||
|
||||
/// Destructor for FGJSBBase.
|
||||
virtual ~FGJSBBase() {};
|
||||
~FGJSBBase() {};
|
||||
|
||||
/// JSBSim Message structure
|
||||
typedef struct Msg {
|
||||
|
@ -129,26 +120,6 @@ public:
|
|||
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
|
||||
|
@ -184,22 +155,22 @@ public:
|
|||
/** 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);
|
||||
|
@ -212,20 +183,63 @@ public:
|
|||
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;
|
||||
|
@ -245,6 +259,28 @@ protected:
|
|||
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
|
||||
|
|
|
@ -100,8 +100,8 @@ FGLGear::FGLGear(FGConfigFile* AC_cfg, FGFDMExec* fdmex) : Exec(fdmex)
|
|||
|
||||
State = Exec->GetState();
|
||||
Aircraft = Exec->GetAircraft();
|
||||
Position = Exec->GetPosition();
|
||||
Rotation = Exec->GetRotation();
|
||||
Propagate = Exec->GetPropagate();
|
||||
Auxiliary = Exec->GetAuxiliary();
|
||||
FCS = Exec->GetFCS();
|
||||
MassBalance = Exec->GetMassBalance();
|
||||
|
||||
|
@ -117,7 +117,7 @@ FGLGear::FGLGear(FGConfigFile* AC_cfg, FGFDMExec* fdmex) : Exec(fdmex)
|
|||
|
||||
vWhlBodyVec = MassBalance->StructuralToBody(vXYZ);
|
||||
|
||||
vLocalGear = State->GetTb2l() * vWhlBodyVec;
|
||||
vLocalGear = Propagate->GetTb2l() * vWhlBodyVec;
|
||||
|
||||
compressLength = 0.0;
|
||||
compressSpeed = 0.0;
|
||||
|
@ -142,8 +142,8 @@ FGLGear::FGLGear(const FGLGear& lgear)
|
|||
{
|
||||
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;
|
||||
|
@ -206,7 +206,6 @@ FGLGear::~FGLGear()
|
|||
|
||||
FGColumnVector3& FGLGear::Force(void)
|
||||
{
|
||||
double SteerGain = 0;
|
||||
double SinWheel, CosWheel;
|
||||
double deltaSlip;
|
||||
double deltaT = State->Getdt()*Aircraft->GetRate();
|
||||
|
@ -236,11 +235,11 @@ FGColumnVector3& FGLGear::Force(void)
|
|||
|
||||
// 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
|
||||
|
@ -262,8 +261,8 @@ FGColumnVector3& FGLGear::Force(void)
|
|||
// (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
|
||||
|
@ -272,13 +271,13 @@ FGColumnVector3& FGLGear::Force(void)
|
|||
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)
|
||||
|
@ -344,8 +343,8 @@ FGColumnVector3& FGLGear::Force(void)
|
|||
// 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;
|
||||
|
||||
|
@ -388,7 +387,7 @@ FGColumnVector3& FGLGear::Force(void)
|
|||
// 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;
|
||||
|
@ -441,14 +440,14 @@ FGColumnVector3& FGLGear::Force(void)
|
|||
|
||||
// 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;
|
||||
|
@ -459,19 +458,19 @@ FGColumnVector3& FGLGear::Force(void)
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -44,9 +44,9 @@ INCLUDES
|
|||
|
||||
#include "FGJSBBase.h"
|
||||
#include "FGFDMExec.h"
|
||||
#include <string>
|
||||
#include "FGConfigFile.h"
|
||||
#include "FGColumnVector3.h"
|
||||
#include <string>
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
|
@ -61,11 +61,11 @@ FORWARD DECLARATIONS
|
|||
namespace JSBSim {
|
||||
|
||||
class FGAircraft;
|
||||
class FGPosition;
|
||||
class FGRotation;
|
||||
class FGPropagate;
|
||||
class FGFCS;
|
||||
class FGState;
|
||||
class FGMassBalance;
|
||||
class FGAuxiliary;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DOCUMENTATION
|
||||
|
@ -160,9 +160,9 @@ 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
|
||||
*/
|
||||
|
@ -293,12 +293,12 @@ private:
|
|||
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);
|
||||
|
@ -306,13 +306,12 @@ private:
|
|||
};
|
||||
}
|
||||
#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
|
||||
|
|
216
src/FDM/JSBSim/FGLocation.cpp
Normal file
216
src/FDM/JSBSim/FGLocation.cpp
Normal file
|
@ -0,0 +1,216 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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
|
437
src/FDM/JSBSim/FGLocation.h
Normal file
437
src/FDM/JSBSim/FGLocation.h
Normal file
|
@ -0,0 +1,437 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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
|
|
@ -27,7 +27,7 @@
|
|||
|
||||
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
|
||||
|
@ -49,9 +49,7 @@ INCLUDES
|
|||
#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"
|
||||
|
||||
|
@ -82,9 +80,7 @@ FGModel::FGModel(FGFDMExec* fdmex)
|
|||
Inertial = 0;
|
||||
GroundReactions = 0;
|
||||
Aircraft = 0;
|
||||
Translation = 0;
|
||||
Rotation = 0;
|
||||
Position = 0;
|
||||
Propagate = 0;
|
||||
Auxiliary = 0;
|
||||
Output = 0;
|
||||
|
||||
|
@ -119,9 +115,7 @@ bool FGModel::InitModel(void)
|
|||
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();
|
||||
|
||||
|
@ -134,9 +128,7 @@ bool FGModel::InitModel(void)
|
|||
!Inertial ||
|
||||
!GroundReactions ||
|
||||
!Aircraft ||
|
||||
!Translation ||
|
||||
!Rotation ||
|
||||
!Position ||
|
||||
!Propagate ||
|
||||
!Auxiliary ||
|
||||
!Output) return(false);
|
||||
else return(true);
|
||||
|
|
|
@ -82,9 +82,7 @@ class FGAerodynamics;
|
|||
class FGInertial;
|
||||
class FGGroundReactions;
|
||||
class FGAircraft;
|
||||
class FGTranslation;
|
||||
class FGRotation;
|
||||
class FGPosition;
|
||||
class FGPropagate;
|
||||
class FGAuxiliary;
|
||||
class FGOutput;
|
||||
class FGConfigFile;
|
||||
|
@ -144,9 +142,7 @@ protected:
|
|||
FGInertial* Inertial;
|
||||
FGGroundReactions* GroundReactions;
|
||||
FGAircraft* Aircraft;
|
||||
FGTranslation* Translation;
|
||||
FGRotation* Rotation;
|
||||
FGPosition* Position;
|
||||
FGPropagate* Propagate;
|
||||
FGAuxiliary* Auxiliary;
|
||||
FGOutput* Output;
|
||||
FGPropertyManager* PropertyManager;
|
||||
|
|
|
@ -35,12 +35,7 @@ HISTORY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#ifdef FGFS
|
||||
# include <simgear/compiler.h>
|
||||
# include STL_ALGORITHM
|
||||
#else
|
||||
# include <algorithm>
|
||||
#endif
|
||||
#include <sstream>
|
||||
|
||||
#include "FGNozzle.h"
|
||||
#include "FGAtmosphere.h"
|
||||
|
@ -104,6 +99,28 @@ double FGNozzle::GetPowerRequired(void)
|
|||
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
|
||||
|
|
|
@ -75,6 +75,8 @@ public:
|
|||
|
||||
double Calculate(double CfPc);
|
||||
double GetPowerRequired(void);
|
||||
string GetThrusterLabels(int id);
|
||||
string GetThrusterValues(int id);
|
||||
|
||||
private:
|
||||
double ReverserAngle;
|
||||
|
|
|
@ -47,12 +47,12 @@ INCLUDES
|
|||
#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$";
|
||||
|
@ -91,22 +91,17 @@ FGOutput::~FGOutput()
|
|||
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;
|
||||
|
@ -180,10 +175,7 @@ void FGOutput::DelimitedOutput(string fname)
|
|||
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 << ", ";
|
||||
|
@ -208,14 +200,14 @@ void FGOutput::DelimitedOutput(string fname)
|
|||
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";
|
||||
}
|
||||
|
@ -262,25 +254,22 @@ void FGOutput::DelimitedOutput(string fname)
|
|||
}
|
||||
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 << ", ";
|
||||
|
@ -297,16 +286,16 @@ void FGOutput::DelimitedOutput(string fname)
|
|||
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();
|
||||
|
@ -373,8 +362,8 @@ void FGOutput::SocketOutput(void)
|
|||
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");
|
||||
|
@ -391,37 +380,37 @@ void FGOutput::SocketOutput(void)
|
|||
|
||||
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));
|
||||
|
@ -456,6 +445,7 @@ bool FGOutput::Load(FGConfigFile* AC_cfg)
|
|||
int OutRate = 0;
|
||||
FGConfigFile* Output_cfg;
|
||||
string property;
|
||||
unsigned int port;
|
||||
|
||||
# ifndef macintosh
|
||||
separator = "/";
|
||||
|
@ -466,13 +456,13 @@ bool FGOutput::Load(FGConfigFile* AC_cfg)
|
|||
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
|
||||
|
@ -526,7 +516,7 @@ bool FGOutput::Load(FGConfigFile* AC_cfg)
|
|||
}
|
||||
if (parameter == "POSITION") {
|
||||
*Output_cfg >> parameter;
|
||||
if (parameter == "ON") SubSystems += ssPosition;
|
||||
if (parameter == "ON") SubSystems += ssPropagate;
|
||||
}
|
||||
if (parameter == "COEFFICIENTS") {
|
||||
*Output_cfg >> parameter;
|
||||
|
@ -618,10 +608,14 @@ void FGOutput::Debug(int from)
|
|||
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
|
||||
|
|
|
@ -73,7 +73,50 @@ CLASS DOCUMENTATION
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
/** 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
|
||||
|
@ -109,7 +152,7 @@ public:
|
|||
/** 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
|
||||
|
|
|
@ -39,8 +39,11 @@ HISTORY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "FGPiston.h"
|
||||
#include "FGPropulsion.h"
|
||||
#include "FGPropeller.h"
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
|
@ -67,6 +70,9 @@ FGPiston::FGPiston(FGFDMExec* exec, FGConfigFile* Eng_cfg) : FGEngine(exec),
|
|||
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;
|
||||
|
@ -78,6 +84,25 @@ FGPiston::FGPiston(FGFDMExec* exec, FGConfigFile* Eng_cfg) : FGEngine(exec),
|
|||
|
||||
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
|
||||
|
||||
|
@ -123,9 +148,79 @@ FGPiston::FGPiston(FGFDMExec* exec, FGConfigFile* Eng_cfg) : FGEngine(exec),
|
|||
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
|
||||
}
|
||||
|
||||
|
@ -138,7 +233,7 @@ FGPiston::~FGPiston()
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGPiston::Calculate(double PowerRequired)
|
||||
double FGPiston::Calculate(void)
|
||||
{
|
||||
if (FuelFlow_gph > 0.0) ConsumeFuel();
|
||||
|
||||
|
@ -149,19 +244,19 @@ double FGPiston::Calculate(double PowerRequired)
|
|||
// 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
|
||||
|
@ -171,13 +266,18 @@ double FGPiston::Calculate(double PowerRequired)
|
|||
Running = false;
|
||||
|
||||
doEnginePower();
|
||||
doEGT();
|
||||
doCHT();
|
||||
doOilTemperature();
|
||||
doOilPressure();
|
||||
doEGT();
|
||||
doCHT();
|
||||
doOilTemperature();
|
||||
doOilPressure();
|
||||
|
||||
PowerAvailable = (HP * hptoftlbssec) - PowerRequired;
|
||||
return PowerAvailable;
|
||||
if (Thruster->GetType() == FGThruster::ttPropeller) {
|
||||
((FGPropeller*)Thruster)->SetAdvance(FCS->GetPropAdvance(EngineNumber));
|
||||
}
|
||||
|
||||
PowerAvailable = (HP * hptoftlbssec) - Thruster->GetPowerRequired();
|
||||
|
||||
return Thruster->Calculate(PowerAvailable);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -250,50 +350,119 @@ void FGPiston::doEngineStartup(void)
|
|||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
@ -337,26 +506,44 @@ void FGPiston::doFuelFlow(void)
|
|||
|
||||
void FGPiston::doEnginePower(void)
|
||||
{
|
||||
ManifoldPressure_inHg *= p_amb / p_amb_sea_level;
|
||||
|
||||
if (Running) {
|
||||
double ManXRPM = ManifoldPressure_inHg * RPM;
|
||||
double T_amb_degF = KelvinToFahrenheit(T_amb);
|
||||
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 {
|
||||
|
||||
|
@ -380,6 +567,7 @@ void FGPiston::doEnginePower(void)
|
|||
HP = 0.0;
|
||||
}
|
||||
}
|
||||
//cout << "Power = " << HP << '\n';
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -508,6 +696,29 @@ void FGPiston::doOilPressure(void)
|
|||
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:
|
||||
|
|
|
@ -48,6 +48,7 @@ DEFINITIONS
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_PISTON "$Id$";
|
||||
#define FG_MAX_BOOST_SPEEDS 3
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -59,11 +60,78 @@ namespace JSBSim {
|
|||
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$
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -78,7 +146,10 @@ public:
|
|||
/// Destructor
|
||||
~FGPiston();
|
||||
|
||||
double Calculate(double PowerRequired);
|
||||
string GetEngineLabels(void);
|
||||
string GetEngineValues(void);
|
||||
|
||||
double Calculate(void);
|
||||
double GetPowerAvailable(void) {return PowerAvailable;}
|
||||
double CalcFuelNeed(void);
|
||||
|
||||
|
@ -107,7 +178,8 @@ private:
|
|||
double dt;
|
||||
|
||||
void doEngineStartup(void);
|
||||
void doManifoldPressure(void);
|
||||
void doBoostControl(void);
|
||||
void doMAP(void);
|
||||
void doAirFlow(void);
|
||||
void doFuelFlow(void);
|
||||
void doEnginePower(void);
|
||||
|
@ -138,6 +210,31 @@ private:
|
|||
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).
|
||||
|
|
|
@ -1,367 +0,0 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,154 +0,0 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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
|
||||
|
380
src/FDM/JSBSim/FGPropagate.cpp
Normal file
380
src/FDM/JSBSim/FGPropagate.cpp
Normal file
|
@ -0,0 +1,380 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
176
src/FDM/JSBSim/FGPropagate.h
Normal file
176
src/FDM/JSBSim/FGPropagate.h
Normal file
|
@ -0,0 +1,176 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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
|
|
@ -35,11 +35,12 @@ HISTORY
|
|||
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 {
|
||||
|
||||
|
@ -60,7 +61,7 @@ FGPropeller::FGPropeller(FGFDMExec* exec, FGConfigFile* Prop_cfg) : FGThruster(e
|
|||
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");
|
||||
|
@ -135,7 +136,7 @@ FGPropeller::~FGPropeller()
|
|||
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;
|
||||
|
@ -153,8 +154,8 @@ double FGPropeller::Calculate(double PowerAvailable)
|
|||
}
|
||||
|
||||
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) {
|
||||
|
@ -164,12 +165,6 @@ double FGPropeller::Calculate(double PowerAvailable)
|
|||
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
|
||||
|
@ -185,13 +180,13 @@ double FGPropeller::Calculate(double PowerAvailable)
|
|||
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
|
||||
}
|
||||
|
@ -204,17 +199,16 @@ double FGPropeller::GetPowerRequired(void)
|
|||
|
||||
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;
|
||||
|
@ -223,7 +217,7 @@ double FGPropeller::GetPowerRequired(void)
|
|||
else if (Pitch > MaxPitch) Pitch = MaxPitch;
|
||||
|
||||
} else {
|
||||
Pitch = MinPitch + (MaxPitch - MinPitch) * advance;
|
||||
Pitch = MinPitch + (MaxPitch - MinPitch) * Advance;
|
||||
}
|
||||
cPReq = cPower->GetValue(J, Pitch);
|
||||
}
|
||||
|
@ -247,6 +241,41 @@ FGColumnVector3 FGPropeller::GetPFactor()
|
|||
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
|
||||
|
|
|
@ -114,6 +114,8 @@ public:
|
|||
@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;}
|
||||
|
||||
|
@ -151,6 +153,8 @@ public:
|
|||
@return the thrust in pounds */
|
||||
double Calculate(double PowerAvailable);
|
||||
FGColumnVector3 GetPFactor(void);
|
||||
string GetThrusterLabels(int id);
|
||||
string GetThrusterValues(int id);
|
||||
|
||||
private:
|
||||
int numBlades;
|
||||
|
@ -164,6 +168,7 @@ private:
|
|||
double P_Factor;
|
||||
double Sense;
|
||||
double Pitch;
|
||||
double Advance;
|
||||
double ExcessTorque;
|
||||
FGColumnVector3 vTorque;
|
||||
FGTable *cThrust;
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
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) -------------
|
||||
|
@ -28,21 +28,13 @@
|
|||
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
|
||||
--------------------------------------------------------------------------------
|
||||
|
@ -54,22 +46,11 @@ INCLUDES
|
|||
|
||||
#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$";
|
||||
|
@ -87,11 +68,11 @@ FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)
|
|||
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();
|
||||
|
||||
|
@ -112,34 +93,33 @@ FGPropulsion::~FGPropulsion()
|
|||
|
||||
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;
|
||||
|
||||
|
@ -149,13 +129,12 @@ bool FGPropulsion::GetSteadyState(void)
|
|||
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; }
|
||||
|
@ -164,8 +143,8 @@ bool FGPropulsion::GetSteadyState(void)
|
|||
}
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -179,24 +158,20 @@ bool FGPropulsion::GetSteadyState(void)
|
|||
|
||||
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;
|
||||
|
@ -206,20 +181,22 @@ bool FGPropulsion::ICEngineStart(void)
|
|||
|
||||
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();
|
||||
|
@ -230,25 +207,44 @@ bool FGPropulsion::Load(FGConfigFile* AC_cfg)
|
|||
|
||||
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;
|
||||
|
@ -262,7 +258,12 @@ bool FGPropulsion::Load(FGConfigFile* AC_cfg)
|
|||
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);
|
||||
|
@ -286,14 +287,14 @@ bool FGPropulsion::Load(FGConfigFile* AC_cfg)
|
|||
} 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++;
|
||||
|
@ -306,59 +307,6 @@ bool FGPropulsion::Load(FGConfigFile* AC_cfg)
|
|||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
@ -375,58 +323,12 @@ string FGPropulsion::GetPropulsionStrings(void)
|
|||
{
|
||||
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;
|
||||
|
@ -436,7 +338,6 @@ string FGPropulsion::GetPropulsionStrings(void)
|
|||
|
||||
string FGPropulsion::GetPropulsionValues(void)
|
||||
{
|
||||
char buff[20];
|
||||
string PropulsionValues = "";
|
||||
bool firstime = true;
|
||||
|
||||
|
@ -444,45 +345,7 @@ string FGPropulsion::GetPropulsionValues(void)
|
|||
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;
|
||||
|
@ -574,15 +437,15 @@ void FGPropulsion::SetCutoff(int setting)
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -598,6 +461,44 @@ void FGPropulsion::SetActiveEngine(int engine)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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;
|
||||
|
|
|
@ -55,7 +55,6 @@ INCLUDES
|
|||
#include "FGModel.h"
|
||||
#include "FGEngine.h"
|
||||
#include "FGTank.h"
|
||||
#include "FGThruster.h"
|
||||
#include "FGMatrix33.h"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -76,27 +75,18 @@ CLASS DOCUMENTATION
|
|||
|
||||
/** 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
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -113,22 +103,12 @@ public:
|
|||
|
||||
/** 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.
|
||||
|
@ -157,21 +137,13 @@ public:
|
|||
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
|
||||
|
@ -186,6 +158,11 @@ public:
|
|||
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);
|
||||
|
||||
|
@ -209,21 +186,20 @@ private:
|
|||
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);
|
||||
};
|
||||
}
|
||||
|
|
235
src/FDM/JSBSim/FGQuaternion.cpp
Normal file
235
src/FDM/JSBSim/FGQuaternion.cpp
Normal file
|
@ -0,0 +1,235 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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
|
499
src/FDM/JSBSim/FGQuaternion.h
Normal file
499
src/FDM/JSBSim/FGQuaternion.h
Normal file
|
@ -0,0 +1,499 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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
|
|
@ -38,6 +38,8 @@ HISTORY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "FGRocket.h"
|
||||
|
||||
namespace JSBSim {
|
||||
|
@ -88,7 +90,7 @@ FGRocket::~FGRocket(void)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGRocket::Calculate(double pe)
|
||||
double FGRocket::Calculate(void)
|
||||
{
|
||||
double Cf=0;
|
||||
|
||||
|
@ -103,11 +105,34 @@ double FGRocket::Calculate(double pe)
|
|||
} 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();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -110,11 +110,8 @@ public:
|
|||
~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. */
|
||||
|
@ -125,6 +122,8 @@ public:
|
|||
sustainable setting.
|
||||
@return true if engine has flamed out. */
|
||||
bool GetFlameout(void) {return Flameout;}
|
||||
string GetEngineLabels(void);
|
||||
string GetEngineValues(void);
|
||||
|
||||
private:
|
||||
double SHR;
|
||||
|
|
|
@ -1,267 +0,0 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,156 +0,0 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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
|
||||
|
|
@ -66,6 +66,20 @@ double FGRotor::Calculate(double PowerAvailable)
|
|||
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
|
||||
|
|
|
@ -70,6 +70,8 @@ public:
|
|||
~FGRotor();
|
||||
|
||||
double Calculate(double);
|
||||
string GetThrusterLabels(int id);
|
||||
string GetThrusterValues(int id);
|
||||
|
||||
private:
|
||||
void Debug(int from);
|
||||
|
|
|
@ -1,447 +0,0 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,243 +0,0 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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
|
||||
|
|
@ -47,8 +47,8 @@ INCLUDES
|
|||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define snprintf _snprintf
|
||||
#ifdef _WIN32
|
||||
//#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
#include "FGState.h"
|
||||
|
@ -74,9 +74,8 @@ FGState::FGState(FGFDMExec* fdex)
|
|||
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();
|
||||
|
@ -85,8 +84,6 @@ FGState::FGState(FGFDMExec* fdex)
|
|||
Propulsion = FDMExec->GetPropulsion();
|
||||
PropertyManager = FDMExec->GetPropertyManager();
|
||||
|
||||
for(int i=0;i<4;i++) vQdot_prev[i].InitMatrix();
|
||||
|
||||
bind();
|
||||
|
||||
Debug(0);
|
||||
|
@ -100,39 +97,23 @@ FGState::~FGState()
|
|||
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
|
||||
|
@ -142,148 +123,15 @@ void FGState::Initialize(double U, double V, double W,
|
|||
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);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -292,8 +140,8 @@ FGMatrix33& FGState::GetTs2b(void)
|
|||
{
|
||||
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);
|
||||
|
@ -320,8 +168,8 @@ FGMatrix33& FGState::GetTb2s(void)
|
|||
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);
|
||||
|
@ -345,6 +193,7 @@ FGMatrix33& FGState::GetTb2s(void)
|
|||
|
||||
void FGState::ReportState(void)
|
||||
{
|
||||
#if 0
|
||||
#if !defined(__BORLANDCPP__)
|
||||
char out[80], flap[10], gear[12];
|
||||
|
||||
|
@ -370,33 +219,33 @@ void FGState::ReportState(void)
|
|||
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,
|
||||
|
@ -408,15 +257,16 @@ void FGState::ReportState(void)
|
|||
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
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -62,14 +62,12 @@ INCLUDES
|
|||
#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"
|
||||
|
@ -110,33 +108,6 @@ public:
|
|||
/// 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.
|
||||
|
@ -175,115 +146,6 @@ public:
|
|||
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.
|
||||
*/
|
||||
|
@ -294,30 +156,6 @@ public:
|
|||
*/
|
||||
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,
|
||||
configuration, etc.)
|
||||
*/
|
||||
|
@ -331,29 +169,18 @@ private:
|
|||
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);
|
||||
|
|
|
@ -56,6 +56,22 @@ CLASS IMPLEMENTATION
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
|
||||
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) {
|
||||
|
@ -90,6 +106,31 @@ FGTable::FGTable(int NRows) : nRows(NRows), 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];
|
||||
|
@ -106,6 +147,7 @@ double** FGTable::Allocate(void)
|
|||
|
||||
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);
|
||||
|
@ -202,17 +244,68 @@ double FGTable::GetValue(double rowKey, double colKey)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -244,10 +337,11 @@ FGTable& FGTable::operator<<(const int n)
|
|||
|
||||
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);
|
||||
|
@ -256,14 +350,17 @@ void FGTable::Print(void)
|
|||
#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;
|
||||
|
|
|
@ -40,6 +40,7 @@ INCLUDES
|
|||
|
||||
#include "FGConfigFile.h"
|
||||
#include "FGJSBBase.h"
|
||||
#include <vector>
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
|
@ -51,6 +52,8 @@ DEFINITIONS
|
|||
FORWARD DECLARATIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
using std::vector;
|
||||
|
||||
namespace JSBSim {
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -58,7 +61,134 @@ CLASS DOCUMENTATION
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
/** 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
|
||||
|
@ -72,11 +202,21 @@ CLASS DECLARATION
|
|||
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
|
||||
|
@ -87,20 +227,32 @@ public:
|
|||
-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);
|
||||
};
|
||||
|
|
|
@ -53,10 +53,13 @@ static const char *IdHdr = ID_TANK;
|
|||
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");
|
||||
|
||||
|
@ -72,6 +75,7 @@ FGTank::FGTank(FGConfigFile* AC_cfg)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -86,6 +90,9 @@ FGTank::FGTank(FGConfigFile* AC_cfg)
|
|||
PctFull = 0;
|
||||
}
|
||||
|
||||
if (Temperature != -9999.0) Temperature = FahrenheitToCelsius(Temperature);
|
||||
Area = 40.0 * pow(Capacity/1975, 0.666666667);
|
||||
|
||||
Debug(0);
|
||||
}
|
||||
|
||||
|
@ -98,7 +105,7 @@ FGTank::~FGTank()
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGTank::Reduce(double used)
|
||||
double FGTank::Drain(double used)
|
||||
{
|
||||
double shortage = Contents - used;
|
||||
|
||||
|
@ -113,6 +120,53 @@ double FGTank::Reduce(double 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
|
||||
|
|
|
@ -47,6 +47,7 @@ INCLUDES
|
|||
#include "FGJSBBase.h"
|
||||
#include "FGConfigFile.h"
|
||||
#include "FGColumnVector3.h"
|
||||
#include "FGAuxiliary.h"
|
||||
|
||||
#ifdef FGFS
|
||||
# include <simgear/compiler.h>
|
||||
|
@ -82,6 +83,48 @@ CLASS DOCUMENTATION
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
/** 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>
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -91,18 +134,23 @@ CLASS DECLARATION
|
|||
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};
|
||||
|
||||
|
@ -114,7 +162,10 @@ private:
|
|||
double Radius;
|
||||
double PctFull;
|
||||
double Contents;
|
||||
double Area;
|
||||
double Temperature;
|
||||
bool Selected;
|
||||
FGAuxiliary* Auxiliary;
|
||||
void Debug(int from);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ HISTORY
|
|||
INCLUDES
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include "FGThruster.h"
|
||||
|
||||
namespace JSBSim {
|
||||
|
@ -47,8 +49,7 @@ CLASS IMPLEMENTATION
|
|||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
|
||||
FGThruster::FGThruster(FGFDMExec *FDMExec) : FGForce(FDMExec),
|
||||
ThrusterNumber(0)
|
||||
FGThruster::FGThruster(FGFDMExec *FDMExec) : FGForce(FDMExec)
|
||||
{
|
||||
Type = ttDirect;
|
||||
SetTransformType(FGForce::tCustom);
|
||||
|
@ -61,7 +62,6 @@ FGThruster::FGThruster(FGFDMExec *FDMExec) : FGForce(FDMExec),
|
|||
FGThruster::FGThruster(FGFDMExec *FDMExec,
|
||||
FGConfigFile *Eng_cfg ): FGForce(FDMExec)
|
||||
{
|
||||
ThrusterNumber = 0;
|
||||
Type = ttDirect;
|
||||
SetTransformType(FGForce::tCustom);
|
||||
Name = Eng_cfg->GetValue();
|
||||
|
@ -76,6 +76,28 @@ FGThruster::~FGThruster()
|
|||
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
|
||||
|
|
|
@ -40,6 +40,7 @@ INCLUDES
|
|||
|
||||
#include "FGForce.h"
|
||||
#include "FGConfigFile.h"
|
||||
#include <string>
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
DEFINITIONS
|
||||
|
@ -79,21 +80,20 @@ public:
|
|||
|
||||
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; }
|
||||
virtual string GetThrusterLabels(int id);
|
||||
virtual string GetThrusterValues(int id);
|
||||
|
||||
protected:
|
||||
eType Type;
|
||||
string Name;
|
||||
int ThrusterNumber;
|
||||
double Thrust;
|
||||
double PowerRequired;
|
||||
double deltaT;
|
||||
|
|
|
@ -1,320 +0,0 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,155 +0,0 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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
|
||||
|
|
@ -243,6 +243,10 @@ bool FGTrim::DoTrim(void) {
|
|||
|
||||
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++) {
|
||||
//cout << current_axis << " " << TrimAxes[current_axis]->GetStateName()
|
||||
|
@ -557,7 +561,7 @@ void FGTrim::setupPullup() {
|
|||
<< 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;
|
||||
|
||||
}
|
||||
|
@ -593,13 +597,15 @@ void FGTrim::updateRates(void){
|
|||
} 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -120,17 +120,17 @@ FGTrimAxis::FGTrimAxis(FGFDMExec* fdex, FGInitialCondition* ic, State st,
|
|||
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;
|
||||
|
@ -141,8 +141,8 @@ FGTrimAxis::FGTrimAxis(FGFDMExec* fdex, FGInitialCondition* ic, State st,
|
|||
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;
|
||||
}
|
||||
|
@ -162,12 +162,12 @@ FGTrimAxis::~FGTrimAxis(void)
|
|||
|
||||
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;
|
||||
|
@ -181,19 +181,19 @@ void FGTrimAxis::getState(void) {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -202,8 +202,8 @@ void FGTrimAxis::getControl(void) {
|
|||
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);
|
||||
|
@ -270,11 +270,11 @@ void FGTrimAxis::SetThetaOnGround(double ff) {
|
|||
}
|
||||
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);
|
||||
|
@ -289,7 +289,9 @@ void FGTrimAxis::SetThetaOnGround(double ff) {
|
|||
/*****************************************************************************/
|
||||
|
||||
bool FGTrimAxis::initTheta(void) {
|
||||
int i,N,iAft, iForward;
|
||||
int i,N;
|
||||
int iForward = 0;
|
||||
int iAft = 1;
|
||||
double zAft,zForward,zDiff,theta;
|
||||
double xAft,xForward,xDiff;
|
||||
bool level;
|
||||
|
@ -318,36 +320,31 @@ bool FGTrimAxis::initTheta(void) {
|
|||
}
|
||||
|
||||
// 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;
|
||||
|
||||
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;
|
||||
|
@ -366,18 +363,18 @@ void FGTrimAxis::SetPhiOnGround(double ff) {
|
|||
|
||||
i=0; ref=-1;
|
||||
//must have an off-center unit here
|
||||
while( (ref < 0) && (i < fdmex->GetGroundReactions()->GetNumGearUnits()) ) {
|
||||
if( (fdmex->GetGroundReactions()->GetGearUnit(i)->GetWOW()) &&
|
||||
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++;
|
||||
}
|
||||
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;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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
|
||||
|
@ -27,20 +27,22 @@
|
|||
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 {
|
||||
|
||||
|
@ -54,8 +56,9 @@ CLASS IMPLEMENTATION
|
|||
|
||||
FGTurbine::FGTurbine(FGFDMExec* exec, FGConfigFile* cfg) : FGEngine(exec)
|
||||
{
|
||||
SetDefaults();
|
||||
|
||||
Load(cfg);
|
||||
PowerCommand=0;
|
||||
Debug(0);
|
||||
}
|
||||
|
||||
|
@ -67,147 +70,367 @@ FGTurbine::~FGTurbine()
|
|||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// 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;
|
||||
|
||||
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 {
|
||||
PowerCommand=ThrottleToPowerCommand(throttle);
|
||||
AugmentCmd = 0.0;
|
||||
}
|
||||
|
||||
mil=MaxMilThrust*ThrustTables[1]->TotalValue();
|
||||
// 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( PowerCommand <= 50 ) {
|
||||
idle=MaxMilThrust*ThrustTables[0]->TotalValue();
|
||||
Thrust = idle + (mil-idle)*PowerCommand*0.02;
|
||||
} else {
|
||||
aug=MaxAugThrust*ThrustTables[2]->TotalValue();
|
||||
Thrust = mil + (aug-mil)*(PowerCommand-50)*0.02;
|
||||
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::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::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 {
|
||||
Augmentation = false;
|
||||
}
|
||||
|
||||
if ((Injected == 1) && Injection)
|
||||
thrust = thrust * ThrustTables[3]->TotalValue();
|
||||
|
||||
ConsumeFuel();
|
||||
if (Cutoff) phase = tpOff;
|
||||
if (Starved) phase = tpOff;
|
||||
|
||||
return Thrust;
|
||||
return thrust;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGTurbine::ThrottleToPowerCommand(double throttle) {
|
||||
if( throttle <= 0.77 )
|
||||
return 64.94*throttle;
|
||||
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;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGTurbine::CalcFuelNeed(void)
|
||||
{
|
||||
return FuelFlow_pph /3600 * State->Getdt() * Propulsion->GetRate();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGTurbine::GetPowerAvailable(void) {
|
||||
if( ThrottlePos <= 0.77 )
|
||||
return 64.94*ThrottlePos;
|
||||
else
|
||||
return 217.38*throttle - 117.38;
|
||||
return 217.38*ThrottlePos - 117.38;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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);
|
||||
}
|
||||
} else {
|
||||
if( actual_power >= 50 ) {
|
||||
t=5;
|
||||
p2=40;
|
||||
} else {
|
||||
p2=power_command;
|
||||
t=rtau(p2-actual_power);
|
||||
}
|
||||
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 t*(p2-actual_power);
|
||||
return v;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGTurbine::doInlet(void)
|
||||
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;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGTurbine::doCompressor(void)
|
||||
{
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGTurbine::doBleedDuct(void)
|
||||
{
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGTurbine::doCombustor(void)
|
||||
{
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGTurbine::doTurbine(void)
|
||||
{
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGTurbine::doConvergingNozzle(void)
|
||||
{
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGTurbine::doTransition(void)
|
||||
{
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
|
||||
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
|
||||
|
@ -235,6 +458,24 @@ void FGTurbine::Debug(int from)
|
|||
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;
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
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
|
||||
|
@ -25,7 +25,9 @@
|
|||
|
||||
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
|
||||
|
@ -51,6 +53,83 @@ 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_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
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
@ -58,38 +137,112 @@ 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;
|
||||
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 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);
|
||||
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);
|
||||
|
||||
};
|
||||
}
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -49,10 +49,8 @@
|
|||
#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>
|
||||
|
@ -63,11 +61,13 @@
|
|||
#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
|
||||
|
@ -117,9 +117,7 @@ FGJSBsim::FGJSBsim( double dt )
|
|||
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();
|
||||
|
@ -127,10 +125,9 @@ FGJSBsim::FGJSBsim( double dt )
|
|||
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 );
|
||||
|
||||
|
@ -157,9 +154,9 @@ FGJSBsim::FGJSBsim( double 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();
|
||||
|
@ -225,8 +222,8 @@ FGJSBsim::FGJSBsim( double dt )
|
|||
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -250,6 +247,9 @@ void FGJSBsim::init()
|
|||
// 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(
|
||||
|
@ -266,6 +266,7 @@ void FGJSBsim::init()
|
|||
} else {
|
||||
Atmosphere->UseInternal();
|
||||
}
|
||||
#endif
|
||||
|
||||
fgic->SetVnorthFpsIC( wind_from_north->getDoubleValue() );
|
||||
fgic->SetVeastFpsIC( wind_from_east->getDoubleValue() );
|
||||
|
@ -289,19 +290,19 @@ void FGJSBsim::init()
|
|||
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:
|
||||
|
@ -313,17 +314,17 @@ void FGJSBsim::init()
|
|||
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" );
|
||||
|
@ -441,16 +442,16 @@ bool FGJSBsim::copy_to_JSBsim()
|
|||
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);
|
||||
|
@ -466,9 +467,10 @@ bool FGJSBsim::copy_to_JSBsim()
|
|||
} // 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(
|
||||
|
@ -496,6 +498,8 @@ bool FGJSBsim::copy_to_JSBsim()
|
|||
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;
|
||||
}
|
||||
|
@ -534,72 +538,62 @@ bool FGJSBsim::copy_from_JSBsim()
|
|||
|
||||
// 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_V_ground_speed( Auxiliary->GetVground() );
|
||||
|
||||
_set_Omega_Body( Rotation->GetPQR(1),
|
||||
Rotation->GetPQR(2),
|
||||
Rotation->GetPQR(3) );
|
||||
_set_Omega_Body( Propagate->GetPQR(eP),
|
||||
Propagate->GetPQR(eQ),
|
||||
Propagate->GetPQR(eR) );
|
||||
|
||||
_set_Euler_Rates( Rotation->GetEulerRates(1),
|
||||
Rotation->GetEulerRates(2),
|
||||
Rotation->GetEulerRates(3) );
|
||||
_set_Euler_Rates( Auxiliary->GetEulerRates(ePhi),
|
||||
Auxiliary->GetEulerRates(eTht),
|
||||
Auxiliary->GetEulerRates(ePsi) );
|
||||
|
||||
_set_Geocentric_Rates(Position->GetLatitudeDot(),
|
||||
Position->GetLongitudeDot(),
|
||||
Position->Gethdot() );
|
||||
|
||||
_set_Mach_number( Translation->GetMach() );
|
||||
|
||||
// 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_Gamma_vert_rad( Auxiliary->GetGamma() );
|
||||
|
||||
_set_Earth_position_angle( Auxiliary->GetEarthPositionAngle() );
|
||||
|
||||
_set_Climb_Rate( Position->Gethdot() );
|
||||
|
||||
_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) );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -609,7 +603,7 @@ bool FGJSBsim::copy_from_JSBsim()
|
|||
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:
|
||||
|
@ -628,9 +622,9 @@ bool FGJSBsim::copy_from_JSBsim()
|
|||
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);
|
||||
|
@ -642,11 +636,18 @@ bool FGJSBsim::copy_from_JSBsim()
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -695,10 +696,12 @@ bool FGJSBsim::copy_from_JSBsim()
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -66,9 +66,7 @@ class FGMassBalance;
|
|||
class FGAerodynamics;
|
||||
class FGInertial;
|
||||
class FGAircraft;
|
||||
class FGTranslation;
|
||||
class FGRotation;
|
||||
class FGPosition;
|
||||
class FGPropagate;
|
||||
class FGAuxiliary;
|
||||
class FGOutput;
|
||||
class FGInitialCondition;
|
||||
|
@ -116,17 +114,17 @@ public:
|
|||
//@{
|
||||
/** 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
|
||||
//@}
|
||||
|
||||
|
@ -136,33 +134,33 @@ public:
|
|||
//@{
|
||||
/** 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
|
||||
|
@ -218,9 +216,7 @@ private:
|
|||
FGPropulsion* Propulsion;
|
||||
FGMassBalance* MassBalance;
|
||||
FGAircraft* Aircraft;
|
||||
FGTranslation* Translation;
|
||||
FGRotation* Rotation;
|
||||
FGPosition* Position;
|
||||
FGPropagate* Propagate;
|
||||
FGAuxiliary* Auxiliary;
|
||||
FGAerodynamics* Aerodynamics;
|
||||
FGGroundReactions *GroundReactions;
|
||||
|
|
|
@ -11,9 +11,7 @@ libJSBSim_a_SOURCES = \
|
|||
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 \
|
||||
|
@ -31,25 +29,24 @@ libJSBSim_a_SOURCES = \
|
|||
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
|
||||
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ FGFilter::FGFilter(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
|
|||
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;
|
||||
|
@ -182,7 +182,7 @@ bool FGFilter::Run(void)
|
|||
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;
|
||||
|
|
|
@ -64,6 +64,8 @@ FGGain::FGGain(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
|
|||
OutputPct = 0;
|
||||
invert = false;
|
||||
ScheduledBy = 0;
|
||||
clip = false;
|
||||
clipmin = clipmax = 0.0;
|
||||
|
||||
Type = AC_cfg->GetValue("TYPE");
|
||||
Name = AC_cfg->GetValue("NAME");
|
||||
|
@ -91,11 +93,16 @@ FGGain::FGGain(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
|
|||
*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);
|
||||
|
@ -106,8 +113,7 @@ FGGain::FGGain(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
|
|||
} else if (token == "OUTPUT") {
|
||||
IsOutput = true;
|
||||
*AC_cfg >> sOutputIdx;
|
||||
OutputNode = PropertyManager->GetNode( sOutputIdx );
|
||||
|
||||
OutputNode = PropertyManager->GetNode( sOutputIdx, true );
|
||||
} else {
|
||||
AC_cfg->ResetLineIndexToZero();
|
||||
*Table << *AC_cfg;
|
||||
|
@ -159,6 +165,11 @@ bool FGGain::Run(void )
|
|||
|
||||
}
|
||||
|
||||
if (clip) {
|
||||
if (Output > clipmax) Output = clipmax;
|
||||
else if (Output < clipmin) Output = clipmin;
|
||||
}
|
||||
|
||||
if (IsOutput) SetOutput();
|
||||
|
||||
return true;
|
||||
|
|
|
@ -94,6 +94,7 @@ CLASS DOCUMENTATION
|
|||
ROWS \<number_of_rows>
|
||||
\<lookup_value gain_value>
|
||||
?
|
||||
[CLIPTO \<min> \<max> 1]
|
||||
[OUTPUT \<property>]
|
||||
\</COMPONENT>
|
||||
</pre>
|
||||
|
@ -181,8 +182,9 @@ private:
|
|||
FGState* State;
|
||||
double Gain;
|
||||
double Min, Max;
|
||||
double clipmin, clipmax;
|
||||
double OutputPct;
|
||||
bool invert;
|
||||
bool invert, clip;
|
||||
int Rows;
|
||||
FGPropertyManager* ScheduledBy;
|
||||
|
||||
|
|
|
@ -121,7 +121,7 @@ bool FGKinemat::Run(void )
|
|||
|
||||
Input = InputNodes[0]->getDoubleValue();
|
||||
|
||||
if (DoScale) Input *= Detents[NumDetents-1];
|
||||
if (DoScale) Input *= Detents[NumDetents-1];
|
||||
|
||||
Output = OutputNode->getDoubleValue();
|
||||
|
||||
|
@ -132,7 +132,7 @@ bool FGKinemat::Run(void )
|
|||
|
||||
// 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;
|
||||
|
@ -154,16 +154,20 @@ bool FGKinemat::Run(void )
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -77,11 +77,29 @@ CLASS DECLARATION
|
|||
|
||||
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:
|
||||
|
|
|
@ -87,7 +87,7 @@ FGSummer::FGSummer(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
|
|||
} else if (token == "OUTPUT") {
|
||||
IsOutput = true;
|
||||
*AC_cfg >> sOutputIdx;
|
||||
OutputNode = PropertyManager->GetNode(sOutputIdx);
|
||||
OutputNode = PropertyManager->GetNode(sOutputIdx, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ FGSwitch::FGSwitch(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
|
|||
{
|
||||
string token, value;
|
||||
struct test *current_test;
|
||||
struct FGCondition *current_condition;
|
||||
string sOutputIdx;
|
||||
|
||||
Type = AC_cfg->GetValue("TYPE");
|
||||
Name = AC_cfg->GetValue("NAME");
|
||||
|
@ -124,8 +124,13 @@ FGSwitch::FGSwitch(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
|
|||
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();
|
||||
|
@ -178,6 +183,8 @@ bool FGSwitch::Run(void )
|
|||
*iTests++;
|
||||
}
|
||||
|
||||
if (IsOutput) SetOutput();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -256,6 +263,7 @@ void FGSwitch::Debug(int from)
|
|||
cout << endl;
|
||||
*iTests++;
|
||||
}
|
||||
if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
|
||||
}
|
||||
}
|
||||
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
||||
|
|
|
@ -86,7 +86,7 @@ additional conditions, as well as possibly additional CONDITION_GROUPs.
|
|||
|
||||
<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}
|
||||
|
@ -94,11 +94,12 @@ additional conditions, as well as possibly additional CONDITION_GROUPs.
|
|||
\</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>
|
||||
|
||||
|
|
Loading…
Reference in a new issue