Sync. with JSBSim CVS
This commit is contained in:
parent
98b3701655
commit
b7ebc7d78d
29 changed files with 640 additions and 610 deletions
|
@ -96,7 +96,7 @@ void FGState::Initialize(FGInitialCondition *FGIC)
|
|||
FGIC->GetWindDFpsIC() );
|
||||
|
||||
FGColumnVector3 vAeroUVW;
|
||||
vAeroUVW = Propagate->GetUVW() + Propagate->GetTl2b()*Atmosphere->GetWindNED();
|
||||
vAeroUVW = Propagate->GetUVW() + Propagate->GetTl2b()*Atmosphere->GetTotalWindNED();
|
||||
|
||||
double alpha, beta;
|
||||
if (vAeroUVW(eW) != 0.0)
|
||||
|
|
|
@ -750,6 +750,10 @@ bool FGJSBsim::copy_from_JSBsim()
|
|||
node->setDoubleValue("oil-temperature-degf", eng->getOilTemp_degF());
|
||||
node->setDoubleValue("oil-pressure-psi", eng->getOilPressure_psi());
|
||||
node->setDoubleValue("mp-osi", eng->getManifoldPressure_inHg());
|
||||
// NOTE: mp-osi is not in ounces per square inch.
|
||||
// This error is left for reasons of backwards compatibility with
|
||||
// existing FlightGear sound and instrument configurations.
|
||||
node->setDoubleValue("mp-inhg", eng->getManifoldPressure_inHg());
|
||||
node->setDoubleValue("cht-degf", eng->getCylinderHeadTemp_degF());
|
||||
node->setDoubleValue("rpm", eng->getRPM());
|
||||
} // end FGPiston code block
|
||||
|
|
|
@ -65,6 +65,8 @@ Element::Element(string nm)
|
|||
convert["FT2"]["M2"] = 1.0/convert["M2"]["FT2"];
|
||||
convert["M2"]["IN2"] = convert["M"]["IN"]*convert["M"]["IN"];
|
||||
convert["IN2"]["M2"] = 1.0/convert["M2"]["IN2"];
|
||||
convert["FT2"]["IN2"] = 144.0;
|
||||
convert["IN2"]["FT2"] = 1.0/convert["FT2"]["IN2"];
|
||||
// Volume
|
||||
convert["IN3"]["CC"] = 16.387064;
|
||||
convert["CC"]["IN3"] = 1.0/convert["IN3"]["CC"];
|
||||
|
@ -128,6 +130,9 @@ Element::Element(string nm)
|
|||
convert["PA"]["LBS/FT2"] = 1.0/convert["LBS/FT2"]["PA"];
|
||||
// Mass flow
|
||||
convert["KG/MIN"]["LBS/MIN"] = convert["KG"]["LBS"];
|
||||
// Fuel Consumption
|
||||
convert["LBS/HP*HR"]["KG/KW*HR"] = 0.6083;
|
||||
convert["KG/KW*HR"]["LBS/HP*HR"] = 1.0/convert["LBS/HP*HR"]["KG/KW*HR"];
|
||||
|
||||
// Length
|
||||
convert["M"]["M"] = 1.00;
|
||||
|
@ -187,6 +192,9 @@ Element::Element(string nm)
|
|||
convert["LBS/SEC"]["LBS/SEC"] = 1.00;
|
||||
convert["KG/MIN"]["KG/MIN"] = 1.0;
|
||||
convert["LBS/MIN"]["LBS/MIN"] = 1.0;
|
||||
// Fuel Consumption
|
||||
convert["LBS/HP*HR"]["LBS/HP*HR"] = 1.0;
|
||||
convert["KG/KW*HR"]["KG/KW*HR"] = 1.0;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -90,6 +90,8 @@ CLASS DOCUMENTATION
|
|||
- convert["LBS"]["N"] = 1.0/convert["N"]["LBS"];
|
||||
- convert["KTS"]["FT/SEC"] = ktstofps;
|
||||
- convert["KG/MIN"]["LBS/MIN"] = convert["KG"]["LBS"];
|
||||
- convert["LBS/HP*HR"]["KG/KW*HR"] = 0.6083;
|
||||
- convert["KG/KW*HR"]["LBS/HP*HR"] = 1/convert["LBS/HP*HR"]["KG/KW*HR"];
|
||||
|
||||
- convert["M"]["M"] = 1.00;
|
||||
- convert["FT"]["FT"] = 1.00;
|
||||
|
@ -115,6 +117,8 @@ CLASS DOCUMENTATION
|
|||
- convert["FT/SEC"]["FT/SEC"] = 1.0;
|
||||
- convert["KG/MIN"]["KG/MIN"] = 1.0;
|
||||
- convert["LBS/MIN"]["LBS/MIN"] = 1.0;
|
||||
- convert["LBS/HP*HR"]["LBS/HP*HR"] = 1.0;
|
||||
- convert["KG/KW*HR"]["KG/KW*HR"] = 1.0;
|
||||
|
||||
Where:
|
||||
- N = newtons
|
||||
|
@ -130,6 +134,8 @@ CLASS DOCUMENTATION
|
|||
- DEG = degrees
|
||||
- RAD = radians
|
||||
- WATTS = watts
|
||||
- HP = horsepower
|
||||
- HR = hour
|
||||
|
||||
@author Jon S. Berndt
|
||||
@version $Id$
|
||||
|
|
|
@ -90,8 +90,8 @@ FGAtmosphere::FGAtmosphere(FGFDMExec* fdmex) : FGModel(fdmex)
|
|||
T_dev_sl = T_dev = delta_T = 0.0;
|
||||
StandardTempOnly = false;
|
||||
first_pass = true;
|
||||
vGustNED(1) = vGustNED(2) = vGustNED(3) = 0.0; bgustSet = false;
|
||||
vTurbulence(1) = vTurbulence(2) = vTurbulence(3) = 0.0;
|
||||
vGustNED.InitMatrix();
|
||||
vTurbulenceNED.InitMatrix();
|
||||
|
||||
bind();
|
||||
Debug(0);
|
||||
|
@ -256,17 +256,18 @@ void FGAtmosphere::Calculate(double altitude)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// Calculate parameters derived from T, P and rho
|
||||
// Sum gust and turbulence values in NED frame into the wind vector.
|
||||
|
||||
void FGAtmosphere::CalculateDerived(void)
|
||||
{
|
||||
T_dev = (*temperature) - GetTemperature(h);
|
||||
density_altitude = h + T_dev * 66.7;
|
||||
|
||||
if (turbType == ttStandard || ttCulp) {
|
||||
Turbulence();
|
||||
vWindNED += vGustNED + vTurbulence;
|
||||
}
|
||||
if (vWindNED(1) != 0.0) psiw = atan2( vWindNED(2), vWindNED(1) );
|
||||
if (turbType == ttStandard || ttCulp) Turbulence();
|
||||
|
||||
vTotalWindNED = vWindNED + vGustNED + vTurbulenceNED;
|
||||
|
||||
if (vWindNED(eX) != 0.0) psiw = atan2( vWindNED(eY), vWindNED(eX) );
|
||||
if (psiw < 0) psiw += 2*M_PI;
|
||||
|
||||
soundspeed = sqrt(SHRatio*Reng*(*temperature));
|
||||
|
@ -326,6 +327,36 @@ static inline double square_signed (double value)
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGAtmosphere::SetWindspeed(double speed)
|
||||
{
|
||||
if (vWindNED.Magnitude() == 0.0) {
|
||||
psiw = 0.0;
|
||||
vWindNED(eNorth) = speed;
|
||||
} else {
|
||||
vWindNED(eNorth) = speed * cos(psiw);
|
||||
vWindNED(eEast) = speed * sin(psiw);
|
||||
vWindNED(eDown) = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGAtmosphere::GetWindspeed(void) const
|
||||
{
|
||||
return vWindNED.Magnitude();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGAtmosphere::SetWindPsi(double dir)
|
||||
{
|
||||
double mag = GetWindspeed();
|
||||
psiw = dir;
|
||||
SetWindspeed(mag);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGAtmosphere::Turbulence(void)
|
||||
{
|
||||
switch (turbType) {
|
||||
|
@ -359,10 +390,10 @@ void FGAtmosphere::Turbulence(void)
|
|||
|
||||
// Diminish turbulence within three wingspans
|
||||
// of the ground
|
||||
vTurbulence = TurbGain * Magnitude * vDirection;
|
||||
vTurbulenceNED = TurbGain * Magnitude * vDirection;
|
||||
double HOverBMAC = Auxiliary->GetHOverBMAC();
|
||||
if (HOverBMAC < 3.0)
|
||||
vTurbulence *= (HOverBMAC / 3.0) * (HOverBMAC / 3.0);
|
||||
vTurbulenceNED *= (HOverBMAC / 3.0) * (HOverBMAC / 3.0);
|
||||
|
||||
// I don't believe these next two statements calculate the proper gradient over
|
||||
// the aircraft body. One reason is because this has no relationship with the
|
||||
|
@ -395,8 +426,8 @@ void FGAtmosphere::Turbulence(void)
|
|||
// that we've used them to calculate
|
||||
// moments.
|
||||
// Why? (JSB)
|
||||
// vTurbulence(eX) = 0.0;
|
||||
// vTurbulence(eY) = 0.0;
|
||||
// vTurbulenceNED(eX) = 0.0;
|
||||
// vTurbulenceNED(eY) = 0.0;
|
||||
|
||||
break;
|
||||
}
|
||||
|
@ -426,7 +457,7 @@ void FGAtmosphere::Turbulence(void)
|
|||
|
||||
vDirection.Normalize();
|
||||
|
||||
vTurbulence = TurbGain*Magnitude * vDirection;
|
||||
vTurbulenceNED = TurbGain*Magnitude * vDirection;
|
||||
vTurbulenceGrad = TurbGain*MagnitudeAccel * vDirection;
|
||||
|
||||
vBodyTurbGrad = Propagate->GetTl2b()*vTurbulenceGrad;
|
||||
|
@ -473,19 +504,19 @@ void FGAtmosphere::Turbulence(void)
|
|||
// max vertical wind speed in fps, corresponds to TurbGain = 1.0
|
||||
double max_vs = 40;
|
||||
|
||||
vTurbulence(1) = vTurbulence(2) = vTurbulence(3) = 0.0;
|
||||
vTurbulenceNED(1) = vTurbulenceNED(2) = vTurbulenceNED(3) = 0.0;
|
||||
double delta = strength * max_vs * TurbGain * (1-Rhythmicity) * spike;
|
||||
|
||||
// Vertical component of turbulence.
|
||||
vTurbulence(3) = sinewave * max_vs * TurbGain * Rhythmicity;
|
||||
vTurbulence(3)+= delta;
|
||||
vTurbulenceNED(3) = sinewave * max_vs * TurbGain * Rhythmicity;
|
||||
vTurbulenceNED(3)+= delta;
|
||||
double HOverBMAC = Auxiliary->GetHOverBMAC();
|
||||
if (HOverBMAC < 3.0)
|
||||
vTurbulence(3) *= HOverBMAC * 0.3333;
|
||||
vTurbulenceNED(3) *= HOverBMAC * 0.3333;
|
||||
|
||||
// Yaw component of turbulence.
|
||||
vTurbulence(1) = sin( delta * 3.0 );
|
||||
vTurbulence(2) = cos( delta * 3.0 );
|
||||
vTurbulenceNED(1) = sin( delta * 3.0 );
|
||||
vTurbulenceNED(2) = cos( delta * 3.0 );
|
||||
|
||||
// Roll component of turbulence. Clockwise vortex causes left roll.
|
||||
vTurbPQR(eP) += delta * 0.04;
|
||||
|
@ -541,6 +572,28 @@ void FGAtmosphere::bind(void)
|
|||
PropertyManager->Tie("atmosphere/delta-T", this, &FGAtmosphere::GetDeltaT, &FGAtmosphere::SetDeltaT);
|
||||
PropertyManager->Tie("atmosphere/T-sl-dev-F", this, &FGAtmosphere::GetSLTempDev, &FGAtmosphere::SetSLTempDev);
|
||||
PropertyManager->Tie("atmosphere/density-altitude", this, &FGAtmosphere::GetDensityAltitude);
|
||||
|
||||
PropertyManager->Tie("atmosphere/wind-north-fps", this, eNorth, (PMF)&FGAtmosphere::GetWindNED,
|
||||
(PMFd)&FGAtmosphere::SetWindNED);
|
||||
PropertyManager->Tie("atmosphere/wind-east-fps", this, eEast, (PMF)&FGAtmosphere::GetWindNED,
|
||||
(PMFd)&FGAtmosphere::SetWindNED);
|
||||
PropertyManager->Tie("atmosphere/wind-down-fps", this, eDown, (PMF)&FGAtmosphere::GetWindNED,
|
||||
(PMFd)&FGAtmosphere::SetWindNED);
|
||||
PropertyManager->Tie("atmosphere/wind-from-cw", this, &FGAtmosphere::GetWindFromClockwise,
|
||||
&FGAtmosphere::SetWindFromClockwise);
|
||||
PropertyManager->Tie("atmosphere/wind-mag-fps", this, &FGAtmosphere::GetWindspeed,
|
||||
&FGAtmosphere::SetWindspeed);
|
||||
PropertyManager->Tie("atmosphere/total-wind-north-fps", this, eNorth, (PMF)&FGAtmosphere::GetTotalWindNED);
|
||||
PropertyManager->Tie("atmosphere/total-wind-east-fps", this, eEast, (PMF)&FGAtmosphere::GetTotalWindNED);
|
||||
PropertyManager->Tie("atmosphere/total-wind-down-fps", this, eDown, (PMF)&FGAtmosphere::GetTotalWindNED);
|
||||
|
||||
PropertyManager->Tie("atmosphere/gust-north-fps", this, eNorth, (PMF)&FGAtmosphere::GetGustNED,
|
||||
(PMFd)&FGAtmosphere::SetGustNED);
|
||||
PropertyManager->Tie("atmosphere/gust-east-fps", this, eEast, (PMF)&FGAtmosphere::GetGustNED,
|
||||
(PMFd)&FGAtmosphere::SetGustNED);
|
||||
PropertyManager->Tie("atmosphere/gust-down-fps", this, eDown, (PMF)&FGAtmosphere::GetGustNED,
|
||||
(PMFd)&FGAtmosphere::SetGustNED);
|
||||
|
||||
PropertyManager->Tie("atmosphere/p-turb-rad_sec", this,1, (PMF)&FGAtmosphere::GetTurbPQR);
|
||||
PropertyManager->Tie("atmosphere/q-turb-rad_sec", this,2, (PMF)&FGAtmosphere::GetTurbPQR);
|
||||
PropertyManager->Tie("atmosphere/r-turb-rad_sec", this,3, (PMF)&FGAtmosphere::GetTurbPQR);
|
||||
|
@ -548,14 +601,6 @@ void FGAtmosphere::bind(void)
|
|||
PropertyManager->Tie("atmosphere/turb-gain", this, &FGAtmosphere::GetTurbGain, &FGAtmosphere::SetTurbGain);
|
||||
PropertyManager->Tie("atmosphere/turb-rhythmicity", this, &FGAtmosphere::GetRhythmicity,
|
||||
&FGAtmosphere::SetRhythmicity);
|
||||
PropertyManager->Tie("atmosphere/gust-north-fps", this,1, (PMF)&FGAtmosphere::GetGustNED,
|
||||
(PMFd)&FGAtmosphere::SetGustNED);
|
||||
PropertyManager->Tie("atmosphere/gust-east-fps", this,2, (PMF)&FGAtmosphere::GetGustNED,
|
||||
(PMFd)&FGAtmosphere::SetGustNED);
|
||||
PropertyManager->Tie("atmosphere/gust-down-fps", this,3, (PMF)&FGAtmosphere::GetGustNED,
|
||||
(PMFd)&FGAtmosphere::SetGustNED);
|
||||
PropertyManager->Tie("atmosphere/wind-from-cw", this, &FGAtmosphere::GetWindFromClockwise,
|
||||
&FGAtmosphere::SetWindFromClockwise);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -598,14 +643,14 @@ void FGAtmosphere::Debug(int from)
|
|||
if (debug_lvl & 128) { // Turbulence
|
||||
if (first_pass && from == 2) {
|
||||
first_pass = false;
|
||||
cout << "vTurbulence(X), vTurbulence(Y), vTurbulence(Z), "
|
||||
cout << "vTurbulenceNED(X), vTurbulenceNED(Y), vTurbulenceNED(Z), "
|
||||
<< "vTurbulenceGrad(X), vTurbulenceGrad(Y), vTurbulenceGrad(Z), "
|
||||
<< "vDirection(X), vDirection(Y), vDirection(Z), "
|
||||
<< "Magnitude, "
|
||||
<< "vTurbPQR(P), vTurbPQR(Q), vTurbPQR(R), " << endl;
|
||||
}
|
||||
if (from == 2) {
|
||||
cout << vTurbulence << ", " << vTurbulenceGrad << ", " << vDirection << ", " << Magnitude << ", " << vTurbPQR << endl;
|
||||
cout << vTurbulenceNED << ", " << vTurbulenceGrad << ", " << vDirection << ", " << Magnitude << ", " << vTurbPQR << endl;
|
||||
}
|
||||
}
|
||||
if (debug_lvl & 64) {
|
||||
|
|
|
@ -86,10 +86,10 @@ public:
|
|||
enum tType {ttStandard, ttBerndt, ttCulp, ttNone} turbType;
|
||||
|
||||
/// Returns the temperature in degrees Rankine.
|
||||
inline double GetTemperature(void) const {return *temperature;}
|
||||
double GetTemperature(void) const {return *temperature;}
|
||||
/** Returns the density in slugs/ft^3.
|
||||
<i>This function may <b>only</b> be used if Run() is called first.</i> */
|
||||
inline double GetDensity(void) const {return *density;}
|
||||
double GetDensity(void) const {return *density;}
|
||||
/// Returns the pressure in psf.
|
||||
double GetPressure(void) const {return *pressure;}
|
||||
/// Returns the standard pressure at a specified altitude
|
||||
|
@ -99,25 +99,25 @@ public:
|
|||
/// Returns the standard density at a specified altitude
|
||||
double GetDensity(double altitude);
|
||||
/// Returns the speed of sound in ft/sec.
|
||||
inline double GetSoundSpeed(void) const {return soundspeed;}
|
||||
double GetSoundSpeed(void) const {return soundspeed;}
|
||||
|
||||
/// Returns the sea level temperature in degrees Rankine.
|
||||
inline double GetTemperatureSL(void) const { return SLtemperature; }
|
||||
double GetTemperatureSL(void) const { return SLtemperature; }
|
||||
/// Returns the sea level density in slugs/ft^3
|
||||
inline double GetDensitySL(void) const { return SLdensity; }
|
||||
double GetDensitySL(void) const { return SLdensity; }
|
||||
/// Returns the sea level pressure in psf.
|
||||
inline double GetPressureSL(void) const { return SLpressure; }
|
||||
double GetPressureSL(void) const { return SLpressure; }
|
||||
/// Returns the sea level speed of sound in ft/sec.
|
||||
inline double GetSoundSpeedSL(void) const { return SLsoundspeed; }
|
||||
double GetSoundSpeedSL(void) const { return SLsoundspeed; }
|
||||
|
||||
/// Returns the ratio of at-altitude temperature over the sea level value.
|
||||
inline double GetTemperatureRatio(void) const { return (*temperature)*rSLtemperature; }
|
||||
double GetTemperatureRatio(void) const { return (*temperature)*rSLtemperature; }
|
||||
/// Returns the ratio of at-altitude density over the sea level value.
|
||||
inline double GetDensityRatio(void) const { return (*density)*rSLdensity; }
|
||||
double GetDensityRatio(void) const { return (*density)*rSLdensity; }
|
||||
/// Returns the ratio of at-altitude pressure over the sea level value.
|
||||
inline double GetPressureRatio(void) const { return (*pressure)*rSLpressure; }
|
||||
double GetPressureRatio(void) const { return (*pressure)*rSLpressure; }
|
||||
/// Returns the ratio of at-altitude sound speed over the sea level value.
|
||||
inline double GetSoundSpeedRatio(void) const { return soundspeed*rSLsoundspeed; }
|
||||
double GetSoundSpeedRatio(void) const { return soundspeed*rSLsoundspeed; }
|
||||
|
||||
/// Tells the simulator to use an externally calculated atmosphere model.
|
||||
void UseExternal(void);
|
||||
|
@ -127,66 +127,100 @@ public:
|
|||
bool External(void) { return useExternal; }
|
||||
|
||||
/// Provides the external atmosphere model with an interface to set the temperature.
|
||||
inline void SetExTemperature(double t) { exTemperature=t; }
|
||||
void SetExTemperature(double t) { exTemperature=t; }
|
||||
/// Provides the external atmosphere model with an interface to set the density.
|
||||
inline void SetExDensity(double d) { exDensity=d; }
|
||||
void SetExDensity(double d) { exDensity=d; }
|
||||
/// Provides the external atmosphere model with an interface to set the pressure.
|
||||
inline void SetExPressure(double p) { exPressure=p; }
|
||||
void SetExPressure(double p) { exPressure=p; }
|
||||
|
||||
/// Sets the temperature deviation at sea-level in degrees Fahrenheit
|
||||
inline void SetSLTempDev(double d) { T_dev_sl = d; }
|
||||
void SetSLTempDev(double d) { T_dev_sl = d; }
|
||||
/// Gets the temperature deviation at sea-level in degrees Fahrenheit
|
||||
inline double GetSLTempDev(void) const { return T_dev_sl; }
|
||||
double GetSLTempDev(void) const { return T_dev_sl; }
|
||||
/// Sets the current delta-T in degrees Fahrenheit
|
||||
inline void SetDeltaT(double d) { delta_T = d; }
|
||||
void SetDeltaT(double d) { delta_T = d; }
|
||||
/// Gets the current delta-T in degrees Fahrenheit
|
||||
inline double GetDeltaT(void) const { return delta_T; }
|
||||
double GetDeltaT(void) const { return delta_T; }
|
||||
/// Gets the at-altitude temperature deviation in degrees Fahrenheit
|
||||
inline double GetTempDev(void) const { return T_dev; }
|
||||
double GetTempDev(void) const { return T_dev; }
|
||||
/// Gets the density altitude in feet
|
||||
inline double GetDensityAltitude(void) const { return density_altitude; }
|
||||
double GetDensityAltitude(void) const { return density_altitude; }
|
||||
|
||||
// TOTAL WIND access functions (wind + gust + turbulence)
|
||||
|
||||
/// Retrieves the total wind components in NED frame.
|
||||
FGColumnVector3& GetTotalWindNED(void) { return vTotalWindNED; }
|
||||
|
||||
/// Retrieves a total wind component in NED frame.
|
||||
double GetTotalWindNED(int idx) const {return vTotalWindNED(idx);}
|
||||
|
||||
// WIND access functions
|
||||
|
||||
/// Sets the wind components in NED frame.
|
||||
inline void SetWindNED(double wN, double wE, double wD) { vWindNED(1)=wN; vWindNED(2)=wE; vWindNED(3)=wD;}
|
||||
void SetWindNED(double wN, double wE, double wD) { vWindNED(1)=wN; vWindNED(2)=wE; vWindNED(3)=wD;}
|
||||
|
||||
/// Sets a wind component in NED frame.
|
||||
void SetWindNED(int idx, double wind) { vWindNED(idx)=wind;}
|
||||
|
||||
/// Retrieves the wind components in NED frame.
|
||||
inline FGColumnVector3& GetWindNED(void) { return vWindNED; }
|
||||
FGColumnVector3& GetWindNED(void) { return vWindNED; }
|
||||
|
||||
/// Sets gust components in NED frame.
|
||||
inline void SetGustNED(int idx, double gust) { vGustNED(idx)=gust;}
|
||||
/// Retrieves a wind component in NED frame.
|
||||
double GetWindNED(int idx) const {return vWindNED(idx);}
|
||||
|
||||
/** Retrieves the direction that the wind is coming from.
|
||||
The direction is defined as north=0 and increases counterclockwise.
|
||||
The wind heading is returned in radians.*/
|
||||
double GetWindPsi(void) const { return psiw; }
|
||||
|
||||
/** Sets the direction that the wind is coming from.
|
||||
The direction is defined as north=0 and increases counterclockwise to 2*pi (radians). The
|
||||
vertical component of wind is assumed to be zero - and is forcibly set to zero. This function
|
||||
sets the vWindNED vector components based on the supplied direction. The magnitude of
|
||||
the wind set in the vector is preserved (assuming the vertical component is non-zero).
|
||||
@param dir wind direction in the horizontal plane, in radians.*/
|
||||
void SetWindPsi(double dir);
|
||||
|
||||
void SetWindspeed(double speed);
|
||||
|
||||
double GetWindspeed(void) const;
|
||||
|
||||
// GUST access functions
|
||||
|
||||
/// Sets a gust component in NED frame.
|
||||
void SetGustNED(int idx, double gust) { vGustNED(idx)=gust;}
|
||||
|
||||
/// Sets the gust components in NED frame.
|
||||
void SetGustNED(double gN, double gE, double gD) { vGustNED(eNorth)=gN; vGustNED(eEast)=gE; vGustNED(eDown)=gD;}
|
||||
|
||||
/// Retrieves a gust component in NED frame.
|
||||
double GetGustNED(int idx) const {return vGustNED(idx);}
|
||||
|
||||
/// Retrieves the gust components in NED frame.
|
||||
inline double GetGustNED(int idx) const {return vGustNED(idx);}
|
||||
|
||||
/// Retrieves the gust components in NED frame.
|
||||
inline FGColumnVector3& GetGustNED(void) {return vGustNED;}
|
||||
|
||||
/** Retrieves the wind direction. The direction is defined as north=0 and
|
||||
increases counterclockwise. The wind heading is returned in radians.*/
|
||||
inline double GetWindPsi(void) const { return psiw; }
|
||||
FGColumnVector3& GetGustNED(void) {return vGustNED;}
|
||||
|
||||
/** Turbulence models available: ttStandard, ttBerndt, ttCulp, ttNone */
|
||||
inline void SetTurbType(tType tt) {turbType = tt;}
|
||||
inline tType GetTurbType() const {return turbType;}
|
||||
void SetTurbType(tType tt) {turbType = tt;}
|
||||
tType GetTurbType() const {return turbType;}
|
||||
|
||||
inline void SetTurbGain(double tg) {TurbGain = tg;}
|
||||
inline double GetTurbGain() const {return TurbGain;}
|
||||
void SetTurbGain(double tg) {TurbGain = tg;}
|
||||
double GetTurbGain() const {return TurbGain;}
|
||||
|
||||
inline void SetTurbRate(double tr) {TurbRate = tr;}
|
||||
inline double GetTurbRate() const {return TurbRate;}
|
||||
void SetTurbRate(double tr) {TurbRate = tr;}
|
||||
double GetTurbRate() const {return TurbRate;}
|
||||
|
||||
inline void SetRhythmicity(double r) {Rhythmicity=r;}
|
||||
inline double GetRhythmicity() const {return Rhythmicity;}
|
||||
void SetRhythmicity(double r) {Rhythmicity=r;}
|
||||
double GetRhythmicity() const {return Rhythmicity;}
|
||||
|
||||
/** Sets wind vortex, clockwise as seen from a point in front of aircraft,
|
||||
looking aft. Units are radians/second. */
|
||||
inline void SetWindFromClockwise(double wC) { wind_from_clockwise=wC; }
|
||||
inline double GetWindFromClockwise(void) const {return wind_from_clockwise;}
|
||||
void SetWindFromClockwise(double wC) { wind_from_clockwise=wC; }
|
||||
double GetWindFromClockwise(void) const {return wind_from_clockwise;}
|
||||
|
||||
inline double GetTurbPQR(int idx) const {return vTurbPQR(idx);}
|
||||
double GetTurbPQR(int idx) const {return vTurbPQR(idx);}
|
||||
double GetTurbMagnitude(void) const {return Magnitude;}
|
||||
FGColumnVector3& GetTurbDirection(void) {return vDirection;}
|
||||
inline FGColumnVector3& GetTurbPQR(void) {return vTurbPQR;}
|
||||
FGColumnVector3& GetTurbPQR(void) {return vTurbPQR;}
|
||||
|
||||
protected:
|
||||
double rho;
|
||||
|
@ -217,16 +251,15 @@ protected:
|
|||
FGColumnVector3 vDirectiondAccelDt;
|
||||
FGColumnVector3 vDirectionAccel;
|
||||
FGColumnVector3 vDirection;
|
||||
FGColumnVector3 vTurbulence;
|
||||
FGColumnVector3 vTurbulenceGrad;
|
||||
FGColumnVector3 vBodyTurbGrad;
|
||||
FGColumnVector3 vTurbPQR;
|
||||
|
||||
FGColumnVector3 vWindNED;
|
||||
double psiw;
|
||||
|
||||
FGColumnVector3 vTotalWindNED;
|
||||
FGColumnVector3 vWindNED;
|
||||
FGColumnVector3 vGustNED;
|
||||
bool bgustSet;
|
||||
FGColumnVector3 vTurbulenceNED;
|
||||
|
||||
/// Calculate the atmosphere for the given altitude, including effects of temperature deviation.
|
||||
void Calculate(double altitude);
|
||||
|
|
|
@ -169,10 +169,10 @@ bool FGAuxiliary::Run()
|
|||
} else if (GroundReactions->GetWOW() && vUVW(eU) < 30) {
|
||||
double factor = (vUVW(eU) - 10.0)/20.0;
|
||||
vAeroPQR = vPQR + factor*Atmosphere->GetTurbPQR();
|
||||
vAeroUVW = vUVW + factor*Propagate->GetTl2b()*(Atmosphere->GetWindNED()+Atmosphere->GetGustNED());
|
||||
vAeroUVW = vUVW + factor*Propagate->GetTl2b()*Atmosphere->GetTotalWindNED();
|
||||
} else {
|
||||
vAeroPQR = vPQR + Atmosphere->GetTurbPQR();
|
||||
vAeroUVW = vUVW + Propagate->GetTl2b()*(Atmosphere->GetWindNED()+Atmosphere->GetGustNED());
|
||||
vAeroUVW = vUVW + Propagate->GetTl2b()*Atmosphere->GetTotalWindNED();
|
||||
}
|
||||
|
||||
Vt = vAeroUVW.Magnitude();
|
||||
|
@ -291,7 +291,7 @@ double FGAuxiliary::GetHeadWind(void) const
|
|||
double psiw,vw;
|
||||
|
||||
psiw = Atmosphere->GetWindPsi();
|
||||
vw = Atmosphere->GetWindNED().Magnitude();
|
||||
vw = Atmosphere->GetTotalWindNED().Magnitude();
|
||||
|
||||
return vw*cos(psiw - Propagate->GetEuler(ePsi));
|
||||
}
|
||||
|
@ -303,7 +303,7 @@ double FGAuxiliary::GetCrossWind(void) const
|
|||
double psiw,vw;
|
||||
|
||||
psiw = Atmosphere->GetWindPsi();
|
||||
vw = Atmosphere->GetWindNED().Magnitude();
|
||||
vw = Atmosphere->GetTotalWindNED().Magnitude();
|
||||
|
||||
return vw*sin(psiw - Propagate->GetEuler(ePsi));
|
||||
}
|
||||
|
|
|
@ -557,7 +557,7 @@ bool FGFCS::Load(Element* el, SystemType systype)
|
|||
|
||||
if (!fname.empty()) {
|
||||
property_element = el->FindElement("property");
|
||||
if (property_element) cout << endl << " Declared properties" << endl << endl;
|
||||
if (property_element && debug_lvl > 0) cout << endl << " Declared properties" << endl << endl;
|
||||
while (property_element) {
|
||||
double value=0.0;
|
||||
if ( ! property_element->GetAttributeValue("value").empty())
|
||||
|
@ -573,6 +573,7 @@ bool FGFCS::Load(Element* el, SystemType systype)
|
|||
} else {
|
||||
interface_properties.push_back(new double(value));
|
||||
PropertyManager->Tie(interface_property_string, interface_properties.back());
|
||||
if (debug_lvl > 0)
|
||||
cout << " " << interface_property_string << " (initial value: " << value << ")" << endl;
|
||||
}
|
||||
|
||||
|
@ -600,6 +601,7 @@ bool FGFCS::Load(Element* el, SystemType systype)
|
|||
channel_element = document->FindElement("channel");
|
||||
while (channel_element) {
|
||||
|
||||
if (debug_lvl > 0)
|
||||
cout << endl << highint << fgblue << " Channel "
|
||||
<< normint << channel_element->GetAttributeValue("name") << reset << endl;
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ bool FGMassBalance::Load(Element* el)
|
|||
element = el->FindNextElement("pointmass");
|
||||
}
|
||||
|
||||
Weight = EmptyWeight + Propulsion->GetTanksWeight() + GetPointMassWeight()
|
||||
Weight = EmptyWeight + Propulsion->GetTanksWeight() + GetTotalPointMassWeight()
|
||||
+ BuoyantForces->GetGasMass()*slugtolb;
|
||||
|
||||
Mass = lbtoslug*Weight;
|
||||
|
@ -149,7 +149,7 @@ bool FGMassBalance::Run(void)
|
|||
if (FGModel::Run()) return true;
|
||||
if (FDMExec->Holding()) return false;
|
||||
|
||||
Weight = EmptyWeight + Propulsion->GetTanksWeight() + GetPointMassWeight()
|
||||
Weight = EmptyWeight + Propulsion->GetTanksWeight() + GetTotalPointMassWeight()
|
||||
+ BuoyantForces->GetGasMass()*slugtolb;
|
||||
|
||||
Mass = lbtoslug*Weight;
|
||||
|
@ -205,8 +205,6 @@ bool FGMassBalance::Run(void)
|
|||
|
||||
void FGMassBalance::AddPointMass(Element* el)
|
||||
{
|
||||
char tmp[80];
|
||||
|
||||
Element* loc_element = el->FindElement("location");
|
||||
string pointmass_name = el->GetAttributeValue("name");
|
||||
if (!loc_element) {
|
||||
|
@ -216,18 +214,14 @@ void FGMassBalance::AddPointMass(Element* el)
|
|||
|
||||
double w = el->FindElementValueAsNumberConvertTo("weight", "LBS");
|
||||
FGColumnVector3 vXYZ = loc_element->FindElementTripletConvertTo("IN");
|
||||
|
||||
PointMasses.push_back(new PointMass(w, vXYZ));
|
||||
|
||||
int num = PointMasses.size()-1;
|
||||
|
||||
snprintf(tmp, 80, "inertia/pointmass-weight-lbs[%u]", num);
|
||||
PropertyManager->Tie( tmp, this, num, &FGMassBalance::GetPointMassWeight,
|
||||
&FGMassBalance::SetPointMassWeight);
|
||||
PointMasses.back()->bind(PropertyManager, PointMasses.size()-1);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGMassBalance::GetPointMassWeight(void)
|
||||
double FGMassBalance::GetTotalPointMassWeight(void)
|
||||
{
|
||||
double PM_total_weight = 0.0;
|
||||
|
||||
|
|
|
@ -50,6 +50,10 @@ DEFINITIONS
|
|||
|
||||
#define ID_MASSBALANCE "$Id$"
|
||||
|
||||
#if defined(WIN32) && !defined(__CYGWIN__)
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONSS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
@ -150,17 +154,7 @@ public:
|
|||
inline void SetBaseCG(const FGColumnVector3& CG) {vbaseXYZcg = vXYZcg = CG;}
|
||||
|
||||
void AddPointMass(Element* el);
|
||||
double GetPointMassWeight(void);
|
||||
double GetPointMassWeight(int idx) const {
|
||||
if (idx < (int)PointMasses.size()) return(PointMasses[idx]->Weight);
|
||||
else return 0.0;
|
||||
}
|
||||
|
||||
void SetPointMassWeight(int idx, double pmw) {
|
||||
if (idx < (int)PointMasses.size()) {
|
||||
PointMasses[idx]->Weight = pmw;
|
||||
}
|
||||
}
|
||||
double GetTotalPointMassWeight(void);
|
||||
|
||||
FGColumnVector3& GetPointMassMoment(void);
|
||||
FGMatrix33& GetJ(void) {return mJ;}
|
||||
|
@ -183,12 +177,33 @@ private:
|
|||
FGMatrix33& CalculatePMInertias(void);
|
||||
|
||||
struct PointMass {
|
||||
char tmp[80];
|
||||
PointMass(double w, FGColumnVector3& vXYZ) {
|
||||
Weight = w;
|
||||
Location = vXYZ;
|
||||
}
|
||||
FGColumnVector3 Location;
|
||||
double Weight;
|
||||
double GetPointMassLocation(int axis) const {return Location(axis);}
|
||||
void SetPointMassLocation(int axis, double value) {Location(axis) = value;}
|
||||
void SetPointMassWeight(double wt) {Weight = wt;}
|
||||
double GetPointMassWeight(void) const {return Weight;}
|
||||
|
||||
void bind(FGPropertyManager* PropertyManager, int num) {
|
||||
snprintf(tmp, 80, "inertia/pointmass-weight-lbs[%u]", num);
|
||||
PropertyManager->Tie( tmp, this, &PointMass::GetPointMassWeight,
|
||||
&PointMass::SetPointMassWeight);
|
||||
|
||||
snprintf(tmp, 80, "inertia/pointmass-location-X-inches[%u]", num);
|
||||
PropertyManager->Tie( tmp, this, eX, &PointMass::GetPointMassLocation,
|
||||
&PointMass::SetPointMassLocation);
|
||||
snprintf(tmp, 80, "inertia/pointmass-location-Y-inches[%u]", num);
|
||||
PropertyManager->Tie( tmp, this, eY, &PointMass::GetPointMassLocation,
|
||||
&PointMass::SetPointMassLocation);
|
||||
snprintf(tmp, 80, "inertia/pointmass-location-Z-inches[%u]", num);
|
||||
PropertyManager->Tie( tmp, this, eZ, &PointMass::GetPointMassLocation,
|
||||
&PointMass::SetPointMassLocation);
|
||||
}
|
||||
};
|
||||
|
||||
vector <struct PointMass*> PointMasses;
|
||||
|
|
|
@ -371,7 +371,7 @@ void FGOutput::DelimitedOutput(string fname)
|
|||
outstream << Atmosphere->GetPressure() << delimeter;
|
||||
outstream << Atmosphere->GetTurbMagnitude() << delimeter;
|
||||
outstream << Atmosphere->GetTurbDirection().Dump(delimeter) << delimeter;
|
||||
outstream << Atmosphere->GetWindNED().Dump(delimeter);
|
||||
outstream << Atmosphere->GetTotalWindNED().Dump(delimeter);
|
||||
}
|
||||
if (SubSystems & ssMassProps) {
|
||||
outstream << delimeter;
|
||||
|
@ -809,7 +809,7 @@ void FGOutput::SocketOutput(void)
|
|||
socket->Append(Atmosphere->GetPressure());
|
||||
socket->Append(Atmosphere->GetTurbMagnitude());
|
||||
socket->Append(Atmosphere->GetTurbDirection().Dump(","));
|
||||
socket->Append(Atmosphere->GetWindNED().Dump(","));
|
||||
socket->Append(Atmosphere->GetTotalWindNED().Dump(","));
|
||||
}
|
||||
if (SubSystems & ssMassProps) {
|
||||
socket->Append(MassBalance->GetJ()(1,1));
|
||||
|
|
|
@ -462,9 +462,13 @@ FGMatrix33& FGPropulsion::CalculateTankInertias(void)
|
|||
|
||||
tankJ = FGMatrix33();
|
||||
|
||||
for (unsigned int i=0; i<size; i++)
|
||||
for (unsigned int i=0; i<size; i++) {
|
||||
tankJ += MassBalance->GetPointmassInertia( lbtoslug * Tanks[i]->GetContents(),
|
||||
Tanks[i]->GetXYZ() );
|
||||
tankJ(1,1) += Tanks[i]->GetIxx();
|
||||
tankJ(2,2) += Tanks[i]->GetIyy();
|
||||
tankJ(3,3) += Tanks[i]->GetIzz();
|
||||
}
|
||||
|
||||
return tankJ;
|
||||
}
|
||||
|
|
|
@ -181,7 +181,7 @@ bool MSIS::Run(void)
|
|||
|
||||
if (turbType != ttNone) {
|
||||
Turbulence();
|
||||
vWindNED += vTurbulence;
|
||||
vWindNED += vTurbulenceNED;
|
||||
}
|
||||
|
||||
if (vWindNED(1) != 0.0) psiw = atan2( vWindNED(2), vWindNED(1) );
|
||||
|
@ -1643,14 +1643,14 @@ void MSIS::Debug(int from)
|
|||
}
|
||||
if (debug_lvl & 32) { // Turbulence
|
||||
if (first_pass && from == 2) {
|
||||
cout << "vTurbulence(X), vTurbulence(Y), vTurbulence(Z), "
|
||||
cout << "vTurbulenceNED(X), vTurbulenceNED(Y), vTurbulenceNED(Z), "
|
||||
<< "vTurbulenceGrad(X), vTurbulenceGrad(Y), vTurbulenceGrad(Z), "
|
||||
<< "vDirection(X), vDirection(Y), vDirection(Z), "
|
||||
<< "Magnitude, "
|
||||
<< "vTurbPQR(P), vTurbPQR(Q), vTurbPQR(R), " << endl;
|
||||
}
|
||||
if (from == 2) {
|
||||
cout << vTurbulence << ", " << vTurbulenceGrad << ", " << vDirection << ", " << Magnitude << ", " << vTurbPQR << endl;
|
||||
cout << vTurbulenceNED << ", " << vTurbulenceGrad << ", " << vDirection << ", " << Magnitude << ", " << vTurbPQR << endl;
|
||||
}
|
||||
}
|
||||
if (debug_lvl & 64) {
|
||||
|
|
|
@ -59,83 +59,10 @@ FGMars::FGMars(FGFDMExec* fdmex) : FGAtmosphere(fdmex)
|
|||
Name = "FGMars";
|
||||
Reng = 53.5 * 44.01;
|
||||
|
||||
/*
|
||||
lastIndex = 0;
|
||||
h = 0.0;
|
||||
psiw = 0.0;
|
||||
|
||||
MagnitudedAccelDt = MagnitudeAccel = Magnitude = 0.0;
|
||||
// turbType = ttNone;
|
||||
turbType = ttStandard;
|
||||
// turbType = ttBerndt;
|
||||
TurbGain = 0.0;
|
||||
TurbRate = 1.0;
|
||||
*/
|
||||
|
||||
bind();
|
||||
Debug(0);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
/*
|
||||
FGMars::~FGMars()
|
||||
{
|
||||
Debug(1);
|
||||
}
|
||||
*/
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGMars::InitModel(void)
|
||||
{
|
||||
FGModel::InitModel();
|
||||
|
||||
Calculate(h);
|
||||
SLtemperature = intTemperature;
|
||||
SLpressure = intPressure;
|
||||
SLdensity = intDensity;
|
||||
SLsoundspeed = sqrt(SHRatio*Reng*intTemperature);
|
||||
rSLtemperature = 1.0/intTemperature;
|
||||
rSLpressure = 1.0/intPressure;
|
||||
rSLdensity = 1.0/intDensity;
|
||||
rSLsoundspeed = 1.0/SLsoundspeed;
|
||||
temperature = &intTemperature;
|
||||
pressure = &intPressure;
|
||||
density = &intDensity;
|
||||
|
||||
useExternal=false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
bool FGMars::Run(void)
|
||||
{
|
||||
if (FGModel::Run()) return true;
|
||||
if (FDMExec->Holding()) return false;
|
||||
|
||||
//do temp, pressure, and density first
|
||||
if (!useExternal) {
|
||||
h = Propagate->Geth();
|
||||
Calculate(h);
|
||||
}
|
||||
|
||||
if (turbType != ttNone) {
|
||||
Turbulence();
|
||||
vWindNED += vTurbulence;
|
||||
}
|
||||
|
||||
if (vWindNED(1) != 0.0) psiw = atan2( vWindNED(2), vWindNED(1) );
|
||||
|
||||
if (psiw < 0) psiw += 2*M_PI;
|
||||
|
||||
soundspeed = sqrt(SHRatio*Reng*(*temperature));
|
||||
|
||||
Debug(2);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
void FGMars::Calculate(double altitude)
|
||||
|
@ -155,122 +82,6 @@ void FGMars::Calculate(double altitude)
|
|||
//cout << "Atmosphere: h=" << altitude << " rho= " << intDensity << endl;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
// square a value, but preserve the original sign
|
||||
|
||||
static inline double
|
||||
square_signed (double value)
|
||||
{
|
||||
if (value < 0)
|
||||
return value * value * -1;
|
||||
else
|
||||
return value * value;
|
||||
}
|
||||
|
||||
void FGMars::Turbulence(void)
|
||||
{
|
||||
switch (turbType) {
|
||||
case ttStandard: {
|
||||
vDirectiondAccelDt(eX) = 1 - 2.0*(double(rand())/double(RAND_MAX));
|
||||
vDirectiondAccelDt(eY) = 1 - 2.0*(double(rand())/double(RAND_MAX));
|
||||
vDirectiondAccelDt(eZ) = 1 - 2.0*(double(rand())/double(RAND_MAX));
|
||||
|
||||
MagnitudedAccelDt = 1 - 2.0*(double(rand())/double(RAND_MAX)) - Magnitude;
|
||||
// Scale the magnitude so that it moves
|
||||
// away from the peaks
|
||||
MagnitudedAccelDt = ((MagnitudedAccelDt - Magnitude) /
|
||||
(1 + fabs(Magnitude)));
|
||||
MagnitudeAccel += MagnitudedAccelDt*rate*TurbRate*State->Getdt();
|
||||
Magnitude += MagnitudeAccel*rate*State->Getdt();
|
||||
|
||||
vDirectiondAccelDt.Normalize();
|
||||
|
||||
// deemphasise non-vertical forces
|
||||
vDirectiondAccelDt(eX) = square_signed(vDirectiondAccelDt(eX));
|
||||
vDirectiondAccelDt(eY) = square_signed(vDirectiondAccelDt(eY));
|
||||
|
||||
vDirectionAccel += vDirectiondAccelDt*rate*TurbRate*State->Getdt();
|
||||
vDirectionAccel.Normalize();
|
||||
vDirection += vDirectionAccel*rate*State->Getdt();
|
||||
|
||||
vDirection.Normalize();
|
||||
|
||||
// Diminish turbulence within three wingspans
|
||||
// of the ground
|
||||
vTurbulence = TurbGain * Magnitude * vDirection;
|
||||
double HOverBMAC = Auxiliary->GetHOverBMAC();
|
||||
if (HOverBMAC < 3.0)
|
||||
vTurbulence *= (HOverBMAC / 3.0) * (HOverBMAC / 3.0);
|
||||
|
||||
vTurbulenceGrad = TurbGain*MagnitudeAccel * vDirection;
|
||||
|
||||
vBodyTurbGrad = Propagate->GetTl2b()*vTurbulenceGrad;
|
||||
vTurbPQR(eP) = vBodyTurbGrad(eY)/Aircraft->GetWingSpan();
|
||||
// if (Aircraft->GetHTailArm() != 0.0)
|
||||
// vTurbPQR(eQ) = vBodyTurbGrad(eZ)/Aircraft->GetHTailArm();
|
||||
// else
|
||||
// vTurbPQR(eQ) = vBodyTurbGrad(eZ)/10.0;
|
||||
|
||||
if (Aircraft->GetVTailArm())
|
||||
vTurbPQR(eR) = vBodyTurbGrad(eX)/Aircraft->GetVTailArm();
|
||||
else
|
||||
vTurbPQR(eR) = vBodyTurbGrad(eX)/10.0;
|
||||
|
||||
// Clear the horizontal forces
|
||||
// actually felt by the plane, now
|
||||
// that we've used them to calculate
|
||||
// moments.
|
||||
vTurbulence(eX) = 0.0;
|
||||
vTurbulence(eY) = 0.0;
|
||||
|
||||
break;
|
||||
}
|
||||
case ttBerndt: {
|
||||
vDirectiondAccelDt(eX) = 1 - 2.0*(double(rand())/double(RAND_MAX));
|
||||
vDirectiondAccelDt(eY) = 1 - 2.0*(double(rand())/double(RAND_MAX));
|
||||
vDirectiondAccelDt(eZ) = 1 - 2.0*(double(rand())/double(RAND_MAX));
|
||||
|
||||
|
||||
MagnitudedAccelDt = 1 - 2.0*(double(rand())/double(RAND_MAX)) - Magnitude;
|
||||
MagnitudeAccel += MagnitudedAccelDt*rate*State->Getdt();
|
||||
Magnitude += MagnitudeAccel*rate*State->Getdt();
|
||||
|
||||
vDirectiondAccelDt.Normalize();
|
||||
vDirectionAccel += vDirectiondAccelDt*rate*State->Getdt();
|
||||
vDirectionAccel.Normalize();
|
||||
vDirection += vDirectionAccel*rate*State->Getdt();
|
||||
|
||||
// Diminish z-vector within two wingspans
|
||||
// of the ground
|
||||
double HOverBMAC = Auxiliary->GetHOverBMAC();
|
||||
if (HOverBMAC < 2.0)
|
||||
vDirection(eZ) *= HOverBMAC / 2.0;
|
||||
|
||||
vDirection.Normalize();
|
||||
|
||||
vTurbulence = TurbGain*Magnitude * vDirection;
|
||||
vTurbulenceGrad = TurbGain*MagnitudeAccel * vDirection;
|
||||
|
||||
vBodyTurbGrad = Propagate->GetTl2b()*vTurbulenceGrad;
|
||||
vTurbPQR(eP) = vBodyTurbGrad(eY)/Aircraft->GetWingSpan();
|
||||
if (Aircraft->GetHTailArm() != 0.0)
|
||||
vTurbPQR(eQ) = vBodyTurbGrad(eZ)/Aircraft->GetHTailArm();
|
||||
else
|
||||
vTurbPQR(eQ) = vBodyTurbGrad(eZ)/10.0;
|
||||
|
||||
if (Aircraft->GetVTailArm())
|
||||
vTurbPQR(eR) = vBodyTurbGrad(eX)/Aircraft->GetVTailArm();
|
||||
else
|
||||
vTurbPQR(eR) = vBodyTurbGrad(eX)/10.0;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// The bitmasked value choices are as follows:
|
||||
// unset: In this case (the default) JSBSim would only print
|
||||
|
@ -310,13 +121,13 @@ void FGMars::Debug(int from)
|
|||
}
|
||||
if (debug_lvl & 32) { // Turbulence
|
||||
if (first_pass && from == 2) {
|
||||
cout << "vTurbulence(X), vTurbulence(Y), vTurbulence(Z), "
|
||||
cout << "vTurbulenceNED(X), vTurbulenceNED(Y), vTurbulenceNED(Z), "
|
||||
<< "vTurbulenceGrad(X), vTurbulenceGrad(Y), vTurbulenceGrad(Z), "
|
||||
<< "vDirection(X), vDirection(Y), vDirection(Z), "
|
||||
<< "Magnitude, "
|
||||
<< "vTurbPQR(P), vTurbPQR(Q), vTurbPQR(R), " << endl;
|
||||
} else if (from == 2) {
|
||||
cout << vTurbulence << ", " << vTurbulenceGrad << ", " << vDirection << ", " << Magnitude << ", " << vTurbPQR << endl;
|
||||
cout << vTurbulenceNED << ", " << vTurbulenceGrad << ", " << vDirection << ", " << Magnitude << ", " << vTurbPQR << endl;
|
||||
}
|
||||
}
|
||||
if (debug_lvl & 64) {
|
||||
|
|
|
@ -67,111 +67,12 @@ CLASS DECLARATION
|
|||
|
||||
class FGMars : public FGAtmosphere {
|
||||
public:
|
||||
|
||||
/// Constructor
|
||||
FGMars(FGFDMExec*);
|
||||
/// Destructor
|
||||
//~FGMars();
|
||||
/** Runs the Martian atmosphere model; called by the Executive
|
||||
@return false if no error */
|
||||
bool Run(void);
|
||||
|
||||
bool InitModel(void);
|
||||
|
||||
/// Returns the temperature in degrees Rankine.
|
||||
inline double GetTemperature(void) const {return *temperature;}
|
||||
/** Returns the density in slugs/ft^3.
|
||||
<i>This function may <b>only</b> be used if Run() is called first.</i> */
|
||||
inline double GetDensity(void) const {return *density;}
|
||||
/// Returns the pressure in psf.
|
||||
inline double GetPressure(void) const {return *pressure;}
|
||||
/// Returns the speed of sound in ft/sec.
|
||||
inline double GetSoundSpeed(void) const {return soundspeed;}
|
||||
|
||||
/// Returns the sea level temperature in degrees Rankine.
|
||||
inline double GetTemperatureSL(void) const { return SLtemperature; }
|
||||
/// Returns the sea level density in slugs/ft^3
|
||||
inline double GetDensitySL(void) const { return SLdensity; }
|
||||
/// Returns the sea level pressure in psf.
|
||||
inline double GetPressureSL(void) const { return SLpressure; }
|
||||
/// Returns the sea level speed of sound in ft/sec.
|
||||
inline double GetSoundSpeedSL(void) const { return SLsoundspeed; }
|
||||
|
||||
/// Returns the ratio of at-altitude temperature over the sea level value.
|
||||
inline double GetTemperatureRatio(void) const { return (*temperature)*rSLtemperature; }
|
||||
/// Returns the ratio of at-altitude density over the sea level value.
|
||||
inline double GetDensityRatio(void) const { return (*density)*rSLdensity; }
|
||||
/// Returns the ratio of at-altitude pressure over the sea level value.
|
||||
inline double GetPressureRatio(void) const { return (*pressure)*rSLpressure; }
|
||||
/// Returns the ratio of at-altitude sound speed over the sea level value.
|
||||
inline double GetSoundSpeedRatio(void) const { return soundspeed*rSLsoundspeed; }
|
||||
|
||||
/// Tells the simulator to use an externally calculated atmosphere model.
|
||||
void UseExternal(void);
|
||||
/// Tells the simulator to use the internal atmosphere model.
|
||||
void UseInternal(void); //this is the default
|
||||
/// Gets the boolean that tells if the external atmosphere model is being used.
|
||||
bool External(void) { return useExternal; }
|
||||
|
||||
/// Provides the external atmosphere model with an interface to set the temperature.
|
||||
inline void SetExTemperature(double t) { exTemperature=t; }
|
||||
/// Provides the external atmosphere model with an interface to set the density.
|
||||
inline void SetExDensity(double d) { exDensity=d; }
|
||||
/// Provides the external atmosphere model with an interface to set the pressure.
|
||||
inline void SetExPressure(double p) { exPressure=p; }
|
||||
|
||||
/// Sets the wind components in NED frame.
|
||||
inline void SetWindNED(double wN, double wE, double wD) { vWindNED(1)=wN; vWindNED(2)=wE; vWindNED(3)=wD;}
|
||||
|
||||
/// Retrieves the wind components in NED frame.
|
||||
inline FGColumnVector3& GetWindNED(void) { return vWindNED; }
|
||||
|
||||
/** Retrieves the wind direction. The direction is defined as north=0 and
|
||||
increases counterclockwise. The wind heading is returned in radians.*/
|
||||
inline double GetWindPsi(void) const { return psiw; }
|
||||
|
||||
inline void SetTurbGain(double tt) {TurbGain = tt;}
|
||||
inline void SetTurbRate(double tt) {TurbRate = tt;}
|
||||
|
||||
inline double GetTurbPQR(int idx) const {return vTurbPQR(idx);}
|
||||
inline FGColumnVector3& GetTurbPQR(void) {return vTurbPQR;}
|
||||
|
||||
//void bind(void);
|
||||
void unbind(void);
|
||||
|
||||
|
||||
private:
|
||||
double rho;
|
||||
|
||||
enum tType {ttStandard, ttBerndt, ttNone} turbType;
|
||||
|
||||
int lastIndex;
|
||||
double h;
|
||||
double htab[8];
|
||||
double SLtemperature,SLdensity,SLpressure,SLsoundspeed;
|
||||
double rSLtemperature,rSLdensity,rSLpressure,rSLsoundspeed; //reciprocals
|
||||
double *temperature,*density,*pressure;
|
||||
double soundspeed;
|
||||
bool useExternal;
|
||||
double exTemperature,exDensity,exPressure;
|
||||
double intTemperature, intDensity, intPressure;
|
||||
|
||||
double MagnitudedAccelDt, MagnitudeAccel, Magnitude;
|
||||
double TurbGain;
|
||||
double TurbRate;
|
||||
FGColumnVector3 vDirectiondAccelDt;
|
||||
FGColumnVector3 vDirectionAccel;
|
||||
FGColumnVector3 vDirection;
|
||||
FGColumnVector3 vTurbulence;
|
||||
FGColumnVector3 vTurbulenceGrad;
|
||||
FGColumnVector3 vBodyTurbGrad;
|
||||
FGColumnVector3 vTurbPQR;
|
||||
|
||||
FGColumnVector3 vWindNED;
|
||||
double psiw;
|
||||
|
||||
void Calculate(double altitude);
|
||||
void Turbulence(void);
|
||||
|
||||
void Debug(int from);
|
||||
};
|
||||
|
||||
|
|
|
@ -82,13 +82,14 @@ public:
|
|||
|
||||
double Calculate(void);
|
||||
double GetPowerAvailable(void) {return PowerAvailable;}
|
||||
double CalcFuelNeed(void);
|
||||
double getRPM(void) {return RPM;}
|
||||
string GetEngineLabels(string delimeter);
|
||||
string GetEngineValues(string delimeter);
|
||||
|
||||
private:
|
||||
|
||||
double CalcFuelNeed(void);
|
||||
|
||||
double BrakeHorsePower;
|
||||
double PowerAvailable;
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number)
|
|||
Type = etUnknown;
|
||||
X = Y = Z = 0.0;
|
||||
EnginePitch = EngineYaw = 0.0;
|
||||
SLFuelFlowMax = SLOxiFlowMax = 0.0;
|
||||
SLFuelFlowMax = 0.0;
|
||||
MaxThrottle = 1.0;
|
||||
MinThrottle = 0.0;
|
||||
|
||||
|
@ -117,8 +117,11 @@ FGEngine::FGEngine(FGFDMExec* exec, Element* engine_element, int engine_number)
|
|||
|
||||
char property_name[80];
|
||||
snprintf(property_name, 80, "propulsion/engine[%d]/set-running", EngineNumber);
|
||||
PropertyManager->Tie( property_name, (FGEngine*)this, &FGEngine::GetRunning,
|
||||
&FGEngine::SetRunning );
|
||||
PropertyManager->Tie( property_name, this, &FGEngine::GetRunning, &FGEngine::SetRunning );
|
||||
snprintf(property_name, 80, "propulsion/engine[%u]/thrust-lbs", EngineNumber);
|
||||
PropertyManager->Tie( property_name, this, &FGEngine::GetThrust);
|
||||
snprintf(property_name, 80, "propulsion/engine[%u]/fuel-flow-rate-pps", EngineNumber);
|
||||
PropertyManager->Tie( property_name, this, &FGEngine::GetFuelFlowRate);
|
||||
|
||||
Debug(0);
|
||||
}
|
||||
|
@ -139,7 +142,7 @@ void FGEngine::ResetToIC(void)
|
|||
Throttle = 0.0;
|
||||
Mixture = 1.0;
|
||||
Starter = false;
|
||||
FuelNeed = OxidizerNeed = 0.0;
|
||||
FuelExpended = 0.0;
|
||||
Starved = Running = Cranking = false;
|
||||
PctPower = 0.0;
|
||||
TrimMode = false;
|
||||
|
@ -153,6 +156,7 @@ void FGEngine::ResetToIC(void)
|
|||
// derived class' Calculate() function before any other calculations are done.
|
||||
// This base class method removes fuel from the fuel tanks as appropriate,
|
||||
// and sets the starved flag if necessary.
|
||||
// This version of the fuel consumption code should never see an oxidizer tank.
|
||||
|
||||
void FGEngine::ConsumeFuel(void)
|
||||
{
|
||||
|
@ -160,22 +164,20 @@ void FGEngine::ConsumeFuel(void)
|
|||
if (TrimMode) return;
|
||||
|
||||
unsigned int i;
|
||||
double Fshortage, Oshortage, TanksWithFuel, TanksWithOxidizer;
|
||||
double Fshortage, TanksWithFuel;
|
||||
FGTank* Tank;
|
||||
bool haveOxTanks = false;
|
||||
Fshortage = Oshortage = TanksWithFuel = TanksWithOxidizer = 0.0;
|
||||
Fshortage = TanksWithFuel = 0.0;
|
||||
|
||||
// count how many assigned tanks have fuel
|
||||
for (i=0; i<SourceTanks.size(); i++) {
|
||||
Tank = Propulsion->GetTank(SourceTanks[i]);
|
||||
if (Tank->GetType() == FGTank::ttFUEL){
|
||||
if (Tank->GetContents() > 0.0) ++TanksWithFuel;
|
||||
} else if (Tank->GetType() == FGTank::ttOXIDIZER) {
|
||||
haveOxTanks = true;
|
||||
if (Tank->GetContents() > 0.0) ++TanksWithOxidizer;
|
||||
} else {
|
||||
cerr << "No oxidizer tanks should be used for this engine type." << endl;
|
||||
}
|
||||
}
|
||||
if (TanksWithFuel==0 || (haveOxTanks && TanksWithOxidizer==0)) {
|
||||
if (TanksWithFuel==0) {
|
||||
Starved = true;
|
||||
return;
|
||||
}
|
||||
|
@ -184,12 +186,12 @@ void FGEngine::ConsumeFuel(void)
|
|||
Tank = Propulsion->GetTank(SourceTanks[i]);
|
||||
if (Tank->GetType() == FGTank::ttFUEL) {
|
||||
Fshortage += Tank->Drain(CalcFuelNeed()/TanksWithFuel);
|
||||
} else if (Tank->GetType() == FGTank::ttOXIDIZER) {
|
||||
Oshortage += Tank->Drain(CalcOxidizerNeed()/TanksWithOxidizer);
|
||||
} else {
|
||||
cerr << "No oxidizer tanks should be used for this engine type." << endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (Fshortage < 0.00 || Oshortage < 0.00) Starved = true;
|
||||
if (Fshortage < 0.00) Starved = true;
|
||||
else Starved = false;
|
||||
}
|
||||
|
||||
|
@ -197,16 +199,10 @@ void FGEngine::ConsumeFuel(void)
|
|||
|
||||
double FGEngine::CalcFuelNeed(void)
|
||||
{
|
||||
FuelNeed = SLFuelFlowMax*PctPower*State->Getdt()*Propulsion->GetRate();
|
||||
return FuelNeed;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGEngine::CalcOxidizerNeed(void)
|
||||
{
|
||||
OxidizerNeed = SLOxiFlowMax*PctPower*State->Getdt()*Propulsion->GetRate();
|
||||
return OxidizerNeed;
|
||||
double dT = State->Getdt()*Propulsion->GetRate();
|
||||
FuelFlowRate = SLFuelFlowMax*PctPower;
|
||||
FuelExpended = FuelFlowRate*dT;
|
||||
return FuelExpended;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
@ -149,7 +149,8 @@ public:
|
|||
|
||||
virtual double getFuelFlow_gph () const {return FuelFlow_gph;}
|
||||
virtual double getFuelFlow_pph () const {return FuelFlow_pph;}
|
||||
virtual double GetThrust(void) { return Thrust; }
|
||||
virtual double GetFuelFlowRate(void) const {return FuelFlowRate;}
|
||||
virtual double GetThrust(void) const { return Thrust; }
|
||||
virtual bool GetStarved(void) { return Starved; }
|
||||
virtual bool GetRunning(void) const { return Running; }
|
||||
virtual bool GetCranking(void) { return Cranking; }
|
||||
|
@ -173,25 +174,6 @@ public:
|
|||
@return Thrust in pounds */
|
||||
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
|
||||
derived class' Calculate() function before any other calculations are
|
||||
done. This base class method removes fuel from the fuel tanks as
|
||||
appropriate, and sets the starved flag if necessary. */
|
||||
virtual void ConsumeFuel(void);
|
||||
|
||||
/** The fuel need is calculated based on power levels and flow rate for that
|
||||
power level. It is also turned from a rate into an actual amount (pounds)
|
||||
by multiplying it by the delta T and the rate.
|
||||
@return Total fuel requirement for this engine in pounds. */
|
||||
virtual double CalcFuelNeed(void);
|
||||
|
||||
/** The oxidizer need is calculated based on power levels and flow rate for that
|
||||
power level. It is also turned from a rate into an actual amount (pounds)
|
||||
by multiplying it by the delta T and the rate.
|
||||
@return Total oxidizer requirement for this engine in pounds. */
|
||||
virtual double CalcOxidizerNeed(void);
|
||||
|
||||
/// Sets engine placement information
|
||||
virtual void SetPlacement(FGColumnVector3& location, FGColumnVector3& orientation);
|
||||
|
||||
|
@ -210,6 +192,19 @@ public:
|
|||
virtual string GetEngineValues(string delimeter) = 0;
|
||||
|
||||
protected:
|
||||
/** Reduces the fuel in the active tanks by the amount required.
|
||||
This function should be called from within the
|
||||
derived class' Calculate() function before any other calculations are
|
||||
done. This base class method removes fuel from the fuel tanks as
|
||||
appropriate, and sets the starved flag if necessary. */
|
||||
virtual void ConsumeFuel(void);
|
||||
|
||||
/** The fuel need is calculated based on power levels and flow rate for that
|
||||
power level. It is also turned from a rate into an actual amount (pounds)
|
||||
by multiplying it by the delta T and the rate.
|
||||
@return Total fuel requirement for this engine in pounds. */
|
||||
virtual double CalcFuelNeed(void);
|
||||
|
||||
FGPropertyManager* PropertyManager;
|
||||
string Name;
|
||||
const int EngineNumber;
|
||||
|
@ -218,15 +213,14 @@ protected:
|
|||
double EnginePitch;
|
||||
double EngineYaw;
|
||||
double SLFuelFlowMax;
|
||||
double SLOxiFlowMax;
|
||||
double MaxThrottle;
|
||||
double MinThrottle;
|
||||
|
||||
double Thrust;
|
||||
double Throttle;
|
||||
double Mixture;
|
||||
double FuelNeed;
|
||||
double OxidizerNeed;
|
||||
double FuelExpended;
|
||||
double FuelFlowRate;
|
||||
double PctPower;
|
||||
bool Starter;
|
||||
bool Starved;
|
||||
|
|
|
@ -53,6 +53,12 @@ CLASS IMPLEMENTATION
|
|||
FGNozzle::FGNozzle(FGFDMExec* FDMExec, Element* nozzle_element, int num)
|
||||
: FGThruster(FDMExec, nozzle_element, num)
|
||||
{
|
||||
if (nozzle_element->FindElement("area"))
|
||||
Area = nozzle_element->FindElementValueAsNumberConvertTo("area", "FT2");
|
||||
else {
|
||||
cerr << "Fatal Error: Nozzle exit area must be given in nozzle config file." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (nozzle_element->FindElement("pe"))
|
||||
PE = nozzle_element->FindElementValueAsNumberConvertTo("pe", "PSF");
|
||||
|
@ -60,29 +66,9 @@ FGNozzle::FGNozzle(FGFDMExec* FDMExec, Element* nozzle_element, int num)
|
|||
cerr << "Fatal Error: Nozzle exit pressure must be given in nozzle config file." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
if (nozzle_element->FindElement("expr"))
|
||||
ExpR = nozzle_element->FindElementValueAsNumber("expr");
|
||||
else {
|
||||
cerr << "Fatal Error: Nozzle expansion ratio must be given in nozzle config file." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
if (nozzle_element->FindElement("nzl_eff"))
|
||||
nzlEff = nozzle_element->FindElementValueAsNumber("nzl_eff");
|
||||
else {
|
||||
cerr << "Fatal Error: Nozzle efficiency must be given in nozzle config file." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
if (nozzle_element->FindElement("diam"))
|
||||
Diameter = nozzle_element->FindElementValueAsNumberConvertTo("diam", "FT");
|
||||
else {
|
||||
cerr << "Fatal Error: Nozzle diameter must be given in nozzle config file." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
Thrust = 0;
|
||||
Type = ttNozzle;
|
||||
Area2 = (Diameter*Diameter/4.0)*M_PI;
|
||||
AreaT = Area2/ExpR;
|
||||
|
||||
Debug(0);
|
||||
}
|
||||
|
@ -96,30 +82,18 @@ FGNozzle::~FGNozzle()
|
|||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGNozzle::Calculate(double CfPc)
|
||||
double FGNozzle::Calculate(double vacThrust)
|
||||
{
|
||||
double pAtm = fdmex->GetAtmosphere()->GetPressure();
|
||||
if (CfPc > 0)
|
||||
Thrust = max((double)0.0, (CfPc * AreaT + (PE - pAtm)*Area2) * nzlEff);
|
||||
else
|
||||
Thrust = 0.0;
|
||||
Thrust = max((double)0.0, vacThrust - pAtm*Area);
|
||||
|
||||
vFn(1) = Thrust * cos(ReverserAngle);
|
||||
|
||||
ThrustCoeff = max((double)0.0, CfPc / ((pAtm - PE) * Area2));
|
||||
|
||||
return Thrust;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGNozzle::GetPowerRequired(void)
|
||||
{
|
||||
return PE;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
string FGNozzle::GetThrusterLabels(int id, string delimeter)
|
||||
{
|
||||
std::ostringstream buf;
|
||||
|
@ -166,10 +140,7 @@ void FGNozzle::Debug(int from)
|
|||
if (debug_lvl & 1) { // Standard console startup message output
|
||||
if (from == 0) { // Constructor
|
||||
cout << " Nozzle Name: " << Name << endl;
|
||||
cout << " Nozzle Exit Pressure = " << PE << endl;
|
||||
cout << " Nozzle Expansion Ratio = " << ExpR << endl;
|
||||
cout << " Nozzle Efficiency = " << nzlEff << endl;
|
||||
cout << " Nozzle Diameter = " << Diameter << endl;
|
||||
cout << " Nozzle Exit Area = " << Area << endl;
|
||||
}
|
||||
}
|
||||
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
||||
|
|
|
@ -63,18 +63,14 @@ CLASS DOCUMENTATION
|
|||
@code
|
||||
<nozzle name="{string}">
|
||||
<pe unit="{PSF}"> {number} </pe>
|
||||
<expr> {number} </expr>
|
||||
<nzl_eff> {number} </nzl_eff>
|
||||
<diam unit="{FT | M | IN}"> {number} </diam>
|
||||
<area unit="{FT2 | M2 | IN2}"> {number} </area>
|
||||
</nozzle>
|
||||
@endcode
|
||||
|
||||
<h3>Configuration parameters are:</h3>
|
||||
<pre>
|
||||
<b>pe</b> - Nozzle exit pressure.
|
||||
<b>expr</b> - Nozzle expansion ratio, Ae/At, sqft. dimensionless ratio.
|
||||
<b>nzl_eff</b> - Nozzle efficiency, 0.0 - 1.0.
|
||||
<b>diam</b> - Nozzle diameter.
|
||||
<b>pe</b> - Nozzle design exit pressure.
|
||||
<b>area</b> - Nozzle area at the exit plane.
|
||||
</pre>
|
||||
|
||||
All parameters MUST be specified.
|
||||
|
@ -94,18 +90,13 @@ public:
|
|||
/// Destructor
|
||||
~FGNozzle();
|
||||
|
||||
double Calculate(double CfPc);
|
||||
double GetPowerRequired(void);
|
||||
double Calculate(double vacThrust);
|
||||
string GetThrusterLabels(int id, string delimeter);
|
||||
string GetThrusterValues(int id, string delimeter);
|
||||
|
||||
private:
|
||||
double PE;
|
||||
double ExpR;
|
||||
double nzlEff;
|
||||
double Diameter;
|
||||
double AreaT;
|
||||
double Area2;
|
||||
double Area;
|
||||
void Debug(int from);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -82,6 +82,9 @@ FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number)
|
|||
MaxManifoldPressure_inHg = 28.5;
|
||||
BSFC = -1;
|
||||
|
||||
// Initialisation
|
||||
volumetric_efficiency = 0.8; // Actually f(speed, load) but this will get us running
|
||||
|
||||
// These are internal program variables
|
||||
|
||||
crank_counter = 0;
|
||||
|
@ -113,8 +116,6 @@ FGPiston::FGPiston(FGFDMExec* exec, Element* el, int engine_number)
|
|||
BoostSwitchAltitude[i] = 0.0;
|
||||
BoostSwitchPressure[i] = 0.0;
|
||||
}
|
||||
// Initialisation
|
||||
volumetric_efficiency = 0.8; // Actually f(speed, load) but this will get us running
|
||||
|
||||
// First column is thi, second is neta (combustion efficiency)
|
||||
Lookup_Combustion_Efficiency = new FGTable(12);
|
||||
|
@ -202,7 +203,9 @@ Manifold_Pressure_Lookup = new
|
|||
if (el->FindElement("minthrottle"))
|
||||
MinThrottle = el->FindElementValueAsNumber("minthrottle");
|
||||
if (el->FindElement("bsfc"))
|
||||
BSFC = el->FindElementValueAsNumber("bsfc");
|
||||
BSFC = el->FindElementValueAsNumberConvertTo("bsfc", "LBS/HP*HR");
|
||||
if (el->FindElement("volumetric-efficiency"))
|
||||
volumetric_efficiency = el->FindElementValueAsNumber("volumetric-efficiency");
|
||||
if (el->FindElement("numboostspeeds")) { // Turbo- and super-charging parameters
|
||||
BoostSpeeds = (int)el->FindElementValueAsNumber("numboostspeeds");
|
||||
if (el->FindElement("boostoverride"))
|
||||
|
@ -236,16 +239,16 @@ Manifold_Pressure_Lookup = new
|
|||
}
|
||||
|
||||
// Create a BSFC to match the engine if not provided
|
||||
// The 0.8 in the equation below is volumetric efficiency
|
||||
if (BSFC < 0) {
|
||||
BSFC = ( Displacement * MaxRPM * 0.8 ) / (9411 * MaxHP);
|
||||
BSFC = ( Displacement * MaxRPM * volumetric_efficiency ) / (9411 * MaxHP);
|
||||
}
|
||||
char property_name[80];
|
||||
snprintf(property_name, 80, "propulsion/engine[%d]/power_hp", EngineNumber);
|
||||
snprintf(property_name, 80, "propulsion/engine[%d]/power-hp", EngineNumber);
|
||||
PropertyManager->Tie(property_name, &HP);
|
||||
snprintf(property_name, 80, "propulsion/engine[%d]/bsfc", EngineNumber);
|
||||
snprintf(property_name, 80, "propulsion/engine[%d]/bsfc-lbs_hphr", EngineNumber);
|
||||
PropertyManager->Tie(property_name, &BSFC);
|
||||
|
||||
snprintf(property_name, 80, "propulsion/engine[%d]/volumetric-efficiency", EngineNumber);
|
||||
PropertyManager->Tie(property_name, &volumetric_efficiency);
|
||||
minMAP = MinManifoldPressure_inHg * inhgtopa; // inHg to Pa
|
||||
maxMAP = MaxManifoldPressure_inHg * inhgtopa;
|
||||
StarterHP = sqrt(MaxHP) * 0.4;
|
||||
|
@ -325,6 +328,7 @@ void FGPiston::ResetToIC(void)
|
|||
EGT_degC = ExhaustGasTemp_degK - 273;
|
||||
Thruster->SetRPM(0.0);
|
||||
RPM = 0.0;
|
||||
OilPressure_psi = 0.0;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -385,7 +389,11 @@ if(HP<0.1250)
|
|||
|
||||
double FGPiston::CalcFuelNeed(void)
|
||||
{
|
||||
return FuelFlow_gph / 3600 * 6 * State->Getdt() * Propulsion->GetRate();
|
||||
double dT = State->Getdt() * Propulsion->GetRate();
|
||||
FuelFlow_pph = FuelFlow_gph * 6.0; // Assumes 6 lbs / gallon
|
||||
FuelFlowRate = FuelFlow_pph / 3600.0;
|
||||
FuelExpended = FuelFlowRate * dT;
|
||||
return FuelExpended;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -541,7 +549,9 @@ void FGPiston::doMAP(void)
|
|||
}
|
||||
}
|
||||
// Boost the manifold pressure.
|
||||
MAP += MAP * BoostMul[BoostSpeed] * suction_loss * RPM/RatedRPM[BoostSpeed];
|
||||
double boost_factor = BoostMul[BoostSpeed] * suction_loss * RPM/RatedRPM[BoostSpeed];
|
||||
if (boost_factor < 1.0) boost_factor = 1.0; // boost will never reduce the MAP
|
||||
MAP *= boost_factor;
|
||||
// Now clip the manifold pressure to BCV or Wastegate setting.
|
||||
if(bTakeoffPos) {
|
||||
if(MAP > TakeoffMAP[BoostSpeed]) {
|
||||
|
@ -574,7 +584,6 @@ void FGPiston::doMAP(void)
|
|||
|
||||
void FGPiston::doAirFlow(void)
|
||||
{
|
||||
|
||||
rho_air = p_amb / (R_air * T_amb);
|
||||
double displacement_SI = Displacement * in3tom3;
|
||||
double swept_volume = (displacement_SI * (RPM/60)) / 2;
|
||||
|
@ -596,9 +605,10 @@ rho_air = p_amb / (R_air * T_amb);
|
|||
void FGPiston::doFuelFlow(void)
|
||||
{
|
||||
double thi_sea_level = 1.3 * Mixture; // Allows an AFR of infinity:1 to 11.3075:1
|
||||
equivalence_ratio = thi_sea_level; // * p_amb_sea_level / p_amb;
|
||||
double AFR = 10+(12*(1-Mixture));// mixture 10:1 to 22:1
|
||||
m_dot_fuel = m_dot_air / AFR;
|
||||
equivalence_ratio = thi_sea_level * 101325.0 / p_amb;
|
||||
// double AFR = 10+(12*(1-Mixture));// mixture 10:1 to 22:1
|
||||
// m_dot_fuel = m_dot_air / AFR;
|
||||
m_dot_fuel = (m_dot_air * equivalence_ratio) / 14.7;
|
||||
FuelFlow_gph = m_dot_fuel
|
||||
* 3600 // seconds to hours
|
||||
* 2.2046 // kg to lb
|
||||
|
@ -703,7 +713,7 @@ void FGPiston::doEGT(void)
|
|||
* Calculate the cylinder head temperature.
|
||||
*
|
||||
* Inputs: T_amb, IAS, rho_air, m_dot_fuel, calorific_value_fuel,
|
||||
* combustion_efficiency, RPM
|
||||
* combustion_efficiency, RPM, MaxRPM
|
||||
*
|
||||
* Outputs: CylinderHeadTemp_degK
|
||||
*/
|
||||
|
@ -712,7 +722,7 @@ void FGPiston::doCHT(void)
|
|||
{
|
||||
double h1 = -95.0;
|
||||
double h2 = -3.95;
|
||||
double h3 = -0.05;
|
||||
double h3 = -140.0; // -0.05 * 2800 (default maxrpm)
|
||||
|
||||
double arbitary_area = 1.0;
|
||||
double CpCylinderHead = 800.0;
|
||||
|
@ -725,7 +735,7 @@ void FGPiston::doCHT(void)
|
|||
double dqdt_from_combustion =
|
||||
m_dot_fuel * calorific_value_fuel * combustion_efficiency * 0.33;
|
||||
double dqdt_forced = (h2 * m_dot_cooling_air * temperature_difference) +
|
||||
(h3 * RPM * temperature_difference);
|
||||
(h3 * RPM * temperature_difference / MaxRPM);
|
||||
double dqdt_free = h1 * temperature_difference;
|
||||
double dqdt_cylinder_head = dqdt_from_combustion + dqdt_forced + dqdt_free;
|
||||
|
||||
|
@ -739,7 +749,7 @@ void FGPiston::doCHT(void)
|
|||
/**
|
||||
* Calculate the oil temperature.
|
||||
*
|
||||
* Inputs: Percentage_Power, running flag.
|
||||
* Inputs: CylinderHeadTemp_degK, T_amb, OilPressure_psi.
|
||||
*
|
||||
* Outputs: OilTemp_degK
|
||||
*/
|
||||
|
@ -749,15 +759,18 @@ void FGPiston::doOilTemperature(void)
|
|||
double idle_percentage_power = 0.023; // approximately
|
||||
double target_oil_temp; // Steady state oil temp at the current engine conditions
|
||||
double time_constant; // The time constant for the differential equation
|
||||
double efficiency = 0.667; // The aproximate oil cooling system efficiency // FIXME: may vary by engine
|
||||
|
||||
if (Running) {
|
||||
target_oil_temp = 363;
|
||||
time_constant = 500; // Time constant for engine-on idling.
|
||||
if (Percentage_Power > idle_percentage_power) {
|
||||
time_constant /= ((Percentage_Power / idle_percentage_power) / 10.0); // adjust for power
|
||||
}
|
||||
// Target oil temp is interpolated between ambient temperature and Cylinder Head Tempurature
|
||||
// target_oil_temp = ( T_amb * efficiency ) + (CylinderHeadTemp_degK *(1-efficiency)) ;
|
||||
target_oil_temp = CylinderHeadTemp_degK + efficiency * (T_amb - CylinderHeadTemp_degK) ;
|
||||
|
||||
if (OilPressure_psi > 5.0 ) {
|
||||
time_constant = 5000 / OilPressure_psi; // Guess at a time constant for circulated oil.
|
||||
// The higher the pressure the faster it reaches
|
||||
// target temperature. Oil pressure should be about
|
||||
// 60 PSI yielding a TC of about 80.
|
||||
} else {
|
||||
target_oil_temp = RankineToKelvin(Atmosphere->GetTemperature());
|
||||
time_constant = 1000; // Time constant for engine-off; reflects the fact
|
||||
// that oil is no longer getting circulated
|
||||
}
|
||||
|
@ -771,7 +784,7 @@ void FGPiston::doOilTemperature(void)
|
|||
/**
|
||||
* Calculate the oil pressure.
|
||||
*
|
||||
* Inputs: RPM
|
||||
* Inputs: RPM, MaxRPM, OilTemp_degK
|
||||
*
|
||||
* Outputs: OilPressure_psi
|
||||
*/
|
||||
|
|
|
@ -27,7 +27,7 @@ HISTORY
|
|||
--------------------------------------------------------------------------------
|
||||
09/12/2000 JSB Created
|
||||
10/01/2001 DPM Modified to use equations from Dave Luff's piston model.
|
||||
|
||||
11/01/2008 RKJ Modified piston engine model for more general use.
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
SENTRY
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
@ -66,15 +66,19 @@ CLASS DOCUMENTATION
|
|||
|
||||
@code
|
||||
<piston_engine name="{string}">
|
||||
<minmp unit="{INHG | PA | ATM}"> {number} </minmp>
|
||||
<maxmp unit="{INHG | PA | ATM}"> {number} </maxmp>
|
||||
<minmp unit="{INHG | PA | ATM}"> {number} </minmp> <!-- Depricated -->
|
||||
<maxmp unit="{INHG | PA | ATM}"> {number} </maxmp> <!-- Depricated -->
|
||||
<displacement unit="{IN3 | LTR | CC}"> {number} </displacement>
|
||||
<sparkfaildrop> {number} </sparkfaildrop>
|
||||
<maxhp unit="{HP | WATTS}"> {number} </maxhp>
|
||||
<cycles> {number} </cycles>
|
||||
<idlerpm> {number} </idlerpm>
|
||||
<maxrpm> {number} </maxrpm>
|
||||
<maxthrottle> {number} </maxthrottle>
|
||||
<minthrottle> {number} </minthrottle>
|
||||
<numboostspeeds> {number} </numboostspeeds>
|
||||
<bsfc unit="{LBS/HP*HR | "KG/KW*HR"}"> {number} </bsft>
|
||||
<volumetric_efficiency> {number} </volumetric_efficiency>
|
||||
<boostoverride> {0 | 1} </boostoverride>
|
||||
<ratedboost1 unit="{INHG | PA | ATM}"> {number} </ratedboost1>
|
||||
<ratedpower1 unit="{HP | WATTS}"> {number} </ratedpower1>
|
||||
|
@ -164,6 +168,7 @@ CLASS DOCUMENTATION
|
|||
@author Jon S. Berndt (Engine framework code and framework-related mods)
|
||||
@author Dave Luff (engine operational code)
|
||||
@author David Megginson (initial porting and additional code)
|
||||
@author Ron Jensen (additional engine code)
|
||||
@version $Id$
|
||||
*/
|
||||
|
||||
|
@ -279,7 +284,7 @@ private:
|
|||
double minMAP; // Pa
|
||||
double maxMAP; // Pa
|
||||
double MAP; // Pa
|
||||
double BSFC; // unitless
|
||||
double BSFC; // brake specific fuel consumption [lbs/horsepower*hour
|
||||
|
||||
//
|
||||
// Inputs (in addition to those in FGEngine).
|
||||
|
|
|
@ -57,18 +57,20 @@ FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number)
|
|||
Element* thrust_table_element = 0;
|
||||
ThrustTable = 0L;
|
||||
BurnTime = 0.0;
|
||||
previousFuelNeedPerTank = 0.0;
|
||||
previousOxiNeedPerTank = 0.0;
|
||||
PropellantFlowRate = 0.0;
|
||||
FuelFlowRate = 0.0;
|
||||
OxidizerFlowRate = 0.0;
|
||||
SLOxiFlowMax = 0.0;
|
||||
It = 0.0;
|
||||
|
||||
// Defaults
|
||||
Variance = 0.0;
|
||||
MinThrottle = 0.0;
|
||||
MaxThrottle = 1.0;
|
||||
|
||||
if (el->FindElement("shr"))
|
||||
SHR = el->FindElementValueAsNumber("shr");
|
||||
if (el->FindElement("max_pc"))
|
||||
maxPC = el->FindElementValueAsNumberConvertTo("max_pc", "PSF");
|
||||
if (el->FindElement("prop_eff"))
|
||||
propEff = el->FindElementValueAsNumber("prop_eff");
|
||||
if (el->FindElement("isp"))
|
||||
Isp = el->FindElementValueAsNumber("isp");
|
||||
if (el->FindElement("maxthrottle"))
|
||||
MaxThrottle = el->FindElementValueAsNumber("maxthrottle");
|
||||
if (el->FindElement("minthrottle"))
|
||||
|
@ -77,21 +79,19 @@ FGRocket::FGRocket(FGFDMExec* exec, Element *el, int engine_number)
|
|||
SLFuelFlowMax = el->FindElementValueAsNumberConvertTo("slfuelflowmax", "LBS/SEC");
|
||||
if (el->FindElement("sloxiflowmax"))
|
||||
SLOxiFlowMax = el->FindElementValueAsNumberConvertTo("sloxiflowmax", "LBS/SEC");
|
||||
if (el->FindElement("variance"))
|
||||
Variance = el->FindElementValueAsNumber("variance");
|
||||
|
||||
thrust_table_element = el->FindElement("thrust_table");
|
||||
if (thrust_table_element) {
|
||||
ThrustTable = new FGTable(PropertyManager, thrust_table_element);
|
||||
}
|
||||
|
||||
bindmodel();
|
||||
|
||||
Debug(0);
|
||||
|
||||
Type = etRocket;
|
||||
Flameout = false;
|
||||
|
||||
PC = 0.0;
|
||||
kFactor = (2.0*SHR*SHR/(SHR-1.0))*pow(2.0/(SHR+1), (SHR+1)/(SHR-1));
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -105,41 +105,143 @@ FGRocket::~FGRocket(void)
|
|||
|
||||
double FGRocket::Calculate(void)
|
||||
{
|
||||
double Cf=0;
|
||||
double dT = State->Getdt()*Propulsion->GetRate();
|
||||
|
||||
if (!Flameout && !Starved) ConsumeFuel();
|
||||
|
||||
PropellantFlowRate = (FuelExpended + OxidizerExpended)/dT;
|
||||
Throttle = FCS->GetThrottlePos(EngineNumber);
|
||||
|
||||
// If there is a thrust table, it is a function of elapsed burn time. The engine
|
||||
// is started when the throttle is advanced to 1.0. After that, it burns
|
||||
// without regard to throttle setting. The table returns a value between zero
|
||||
// and one, representing the percentage of maximum vacuum thrust being applied.
|
||||
// If there is a thrust table, it is a function of propellant remaining. The
|
||||
// engine is started when the throttle is advanced to 1.0. After that, it
|
||||
// burns without regard to throttle setting. The table returns a value between
|
||||
// zero and one, representing the percentage of maximum vacuum thrust being
|
||||
// applied.
|
||||
|
||||
if (ThrustTable != 0L) {
|
||||
if (Throttle == 1 || BurnTime > 0.0) {
|
||||
if (ThrustTable != 0L) { // Thrust table given -> Solid fuel used
|
||||
|
||||
if ((Throttle == 1 || BurnTime > 0.0 ) && !Starved) {
|
||||
BurnTime += State->Getdt();
|
||||
}
|
||||
Throttle = ThrustTable->GetValue(BurnTime);
|
||||
double TotalEngineFuelAvailable=0.0;
|
||||
for (int i=0; i<(int)SourceTanks.size(); i++)
|
||||
TotalEngineFuelAvailable += Propulsion->GetTank(SourceTanks[i])->GetContents();
|
||||
|
||||
VacThrust = ThrustTable->GetValue(TotalEngineFuelAvailable);
|
||||
} else {
|
||||
VacThrust = 0.0;
|
||||
}
|
||||
|
||||
if (Throttle < MinThrottle || Starved) {
|
||||
} else { // liquid fueled rocket assumed
|
||||
|
||||
if (Throttle < MinThrottle || Starved) { // Combustion not supported
|
||||
|
||||
PctPower = Thrust = 0.0; // desired thrust
|
||||
Flameout = true;
|
||||
PC = 0.0;
|
||||
} else {
|
||||
PctPower = Throttle / MaxThrottle;
|
||||
//todo: remove Variance?
|
||||
PC = maxPC*PctPower * (1.0 + Variance * ((double)rand()/(double)RAND_MAX - 0.5));
|
||||
// The Cf (below) is CF from Eqn. 3-30, "Rocket Propulsion Elements", Fifth Edition,
|
||||
// George P. Sutton. Note that the thruster function GetPowerRequired() might
|
||||
// be better called GetResistance() or something; this function returns the
|
||||
// nozzle exit pressure.
|
||||
Cf = sqrt(kFactor*(1 - pow(Thruster->GetPowerRequired()/(PC), (SHR-1)/SHR)));
|
||||
VacThrust = 0.0;
|
||||
|
||||
} else { // Calculate thrust
|
||||
|
||||
PctPower = Throttle / MaxThrottle; // Min and MaxThrottle range from 0.0 to 1.0, normally.
|
||||
Flameout = false;
|
||||
VacThrust = Isp * PropellantFlowRate;
|
||||
|
||||
}
|
||||
|
||||
return Thruster->Calculate(Cf*maxPC*PctPower*propEff);
|
||||
} // End thrust calculations
|
||||
|
||||
Thrust = Thruster->Calculate(VacThrust);
|
||||
It += Thrust * dT;
|
||||
|
||||
return Thrust;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// This overrides the base class ConsumeFuel() function, for special rocket
|
||||
// engine processing.
|
||||
|
||||
void FGRocket::ConsumeFuel(void)
|
||||
{
|
||||
unsigned int i;
|
||||
FGTank* Tank;
|
||||
bool haveOxTanks = false;
|
||||
double Fshortage=0, Oshortage=0, TanksWithFuel=0, TanksWithOxidizer=0;
|
||||
|
||||
if (FuelFreeze) return;
|
||||
if (TrimMode) return;
|
||||
|
||||
// Count how many assigned tanks have fuel for this engine at this time.
|
||||
// If there is/are fuel tanks but no oxidizer tanks, this indicates
|
||||
// a solid rocket is being modeled.
|
||||
|
||||
for (i=0; i<SourceTanks.size(); i++) {
|
||||
Tank = Propulsion->GetTank(SourceTanks[i]);
|
||||
switch(Tank->GetType()) {
|
||||
case FGTank::ttFUEL:
|
||||
if (Tank->GetContents() > 0.0 && Tank->GetSelected()) ++TanksWithFuel;
|
||||
break;
|
||||
case FGTank::ttOXIDIZER:
|
||||
haveOxTanks = true;
|
||||
if (Tank->GetContents() > 0.0 && Tank->GetSelected()) ++TanksWithOxidizer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If this engine has burned out, it is starved.
|
||||
|
||||
if (TanksWithFuel==0 || (haveOxTanks && TanksWithOxidizer==0)) {
|
||||
Starved = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Expend fuel from the engine's tanks if the tank is selected as a source
|
||||
// for this engine.
|
||||
|
||||
double fuelNeedPerTank = CalcFuelNeed()/TanksWithFuel;
|
||||
double oxiNeedPerTank = CalcOxidizerNeed()/TanksWithOxidizer;
|
||||
|
||||
for (i=0; i<SourceTanks.size(); i++) {
|
||||
Tank = Propulsion->GetTank(SourceTanks[i]);
|
||||
if ( ! Tank->GetSelected()) continue; // If this tank is not selected as a source, skip it.
|
||||
switch(Tank->GetType()) {
|
||||
case FGTank::ttFUEL:
|
||||
Fshortage += Tank->Drain(2.0*fuelNeedPerTank - previousFuelNeedPerTank);
|
||||
previousFuelNeedPerTank = fuelNeedPerTank;
|
||||
break;
|
||||
case FGTank::ttOXIDIZER:
|
||||
Oshortage += Tank->Drain(2.0*oxiNeedPerTank - previousOxiNeedPerTank);
|
||||
previousOxiNeedPerTank = oxiNeedPerTank;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Fshortage < 0.00 || (haveOxTanks && Oshortage < 0.00)) Starved = true;
|
||||
else Starved = false;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGRocket::CalcFuelNeed(void)
|
||||
{
|
||||
double dT = State->Getdt()*Propulsion->GetRate();
|
||||
|
||||
if (ThrustTable != 0L) { // Thrust table given - infers solid fuel
|
||||
FuelFlowRate = VacThrust/Isp; // This calculates wdot (weight flow rate in lbs/sec)
|
||||
} else {
|
||||
FuelFlowRate = SLFuelFlowMax*PctPower;
|
||||
}
|
||||
|
||||
FuelExpended = FuelFlowRate*dT; // For this time step ...
|
||||
return FuelExpended;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
double FGRocket::CalcOxidizerNeed(void)
|
||||
{
|
||||
double dT = State->Getdt()*Propulsion->GetRate();
|
||||
OxidizerFlowRate = SLOxiFlowMax*PctPower;
|
||||
OxidizerExpended = OxidizerFlowRate*dT;
|
||||
return OxidizerExpended;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -148,7 +250,7 @@ string FGRocket::GetEngineLabels(string delimeter)
|
|||
{
|
||||
std::ostringstream buf;
|
||||
|
||||
buf << Name << " Chamber Pressure (engine " << EngineNumber << " in psf)" << delimeter
|
||||
buf << Name << " Total Impulse (engine " << EngineNumber << " in psf)" << delimeter
|
||||
<< Thruster->GetThrusterLabels(EngineNumber, delimeter);
|
||||
|
||||
return buf.str();
|
||||
|
@ -160,11 +262,27 @@ string FGRocket::GetEngineValues(string delimeter)
|
|||
{
|
||||
std::ostringstream buf;
|
||||
|
||||
buf << PC << delimeter << Thruster->GetThrusterValues(EngineNumber, delimeter);
|
||||
buf << It << delimeter << Thruster->GetThrusterValues(EngineNumber, delimeter);
|
||||
|
||||
return buf.str();
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// This funciton should tie properties to rocket engine specific properties
|
||||
// that are not bound in the base class (FGEngine) code.
|
||||
//
|
||||
void FGRocket::bindmodel()
|
||||
{
|
||||
char property_name[80];
|
||||
|
||||
snprintf(property_name, 80, "propulsion/engine[%u]/total-impulse", EngineNumber);
|
||||
PropertyManager->Tie( property_name, this, &FGRocket::GetTotalImpulse);
|
||||
snprintf(property_name, 80, "propulsion/engine[%u]/oxi-flow-rate-pps", EngineNumber);
|
||||
PropertyManager->Tie( property_name, this, &FGRocket::GetOxiFlowRate);
|
||||
snprintf(property_name, 80, "propulsion/engine[%u]/vacuum-thrust_lbs", EngineNumber);
|
||||
PropertyManager->Tie( property_name, this, &FGRocket::GetVacThrust);
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// The bitmasked value choices are as follows:
|
||||
// unset: In this case (the default) JSBSim would only print
|
||||
|
@ -191,14 +309,12 @@ void FGRocket::Debug(int from)
|
|||
if (debug_lvl & 1) { // Standard console startup message output
|
||||
if (from == 0) { // Constructor
|
||||
cout << " Engine Name: " << Name << endl;
|
||||
cout << " Specific Heat Ratio = " << SHR << endl;
|
||||
cout << " Maximum Chamber Pressure = " << maxPC << endl;
|
||||
cout << " Propulsive Efficiency = " << propEff << endl;
|
||||
cout << " MaxThrottle = " << MaxThrottle << endl;
|
||||
cout << " MinThrottle = " << MinThrottle << endl;
|
||||
cout << " FuelFlowMax = " << SLFuelFlowMax << endl;
|
||||
cout << " OxiFlowMax = " << SLOxiFlowMax << endl;
|
||||
cout << " Variance = " << Variance << endl;
|
||||
cout << " Vacuum Isp = " << Isp << endl;
|
||||
cout << " Maximum Throttle = " << MaxThrottle << endl;
|
||||
cout << " Minimum Throttle = " << MinThrottle << endl;
|
||||
cout << " Fuel Flow (max) = " << SLFuelFlowMax << endl;
|
||||
cout << " Oxidizer Flow (max) = " << SLOxiFlowMax << endl;
|
||||
cout << " Mixture ratio = " << SLOxiFlowMax/SLFuelFlowMax << endl;
|
||||
}
|
||||
}
|
||||
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
||||
|
|
|
@ -61,10 +61,7 @@ CLASS DOCUMENTATION
|
|||
/** Models a generic rocket engine.
|
||||
The rocket engine is modeled given the following parameters:
|
||||
<ul>
|
||||
<li>Chamber pressure (in psf)</li>
|
||||
<li>Specific heat ratio (usually about 1.2 for hydrocarbon fuel and LOX)</li>
|
||||
<li>Propulsive efficiency (in percent, from 0 to 1.0)</li>
|
||||
<li>Variance (in percent, from 0 to 1.0, nominally 0.05)</li>
|
||||
<li>Specific Impulse (in sec)</li>
|
||||
</ul>
|
||||
Additionally, the following control inputs, operating characteristics, and
|
||||
location are required, as with all other engine types:
|
||||
|
@ -78,12 +75,8 @@ CLASS DOCUMENTATION
|
|||
<li>Pitch and Yaw</li>
|
||||
</ul>
|
||||
The nozzle exit pressure (p2) is returned via a
|
||||
call to FGNozzle::GetPowerRequired(). This exit pressure is used,
|
||||
along with chamber pressure and specific heat ratio, to get the
|
||||
thrust coefficient for the throttle setting. This thrust
|
||||
coefficient is multiplied by the chamber pressure and then passed
|
||||
to the nozzle Calculate() routine, where the thrust force is
|
||||
determined.
|
||||
call to FGNozzle::GetPowerRequired(). This exit pressure is used
|
||||
to get the at-altitude thrust level.
|
||||
|
||||
One can model the thrust of a solid rocket by providing a normalized thrust table
|
||||
as a function of time. For instance, the space shuttle solid rocket booster
|
||||
|
@ -150,30 +143,62 @@ public:
|
|||
/** Destructor */
|
||||
~FGRocket(void);
|
||||
|
||||
/** Determines the thrust coefficient.
|
||||
@return thrust coefficient times chamber pressure */
|
||||
/** Determines the thrust.
|
||||
@return thrust */
|
||||
double Calculate(void);
|
||||
|
||||
/** Gets the chamber pressure.
|
||||
@return chamber pressure in psf. */
|
||||
double GetChamberPressure(void) {return PC;}
|
||||
/** Gets the total impulse of the rocket.
|
||||
@return The cumulative total impulse of the rocket up to this time.*/
|
||||
double GetTotalImpulse(void) const {return It;}
|
||||
|
||||
/** Gets the flame-out status.
|
||||
The engine will "flame out" if the throttle is set below the minimum
|
||||
sustainable setting.
|
||||
sustainable-thrust setting.
|
||||
@return true if engine has flamed out. */
|
||||
bool GetFlameout(void) {return Flameout;}
|
||||
|
||||
double GetOxiFlowRate(void) const {return OxidizerFlowRate;}
|
||||
|
||||
string GetEngineLabels(string delimeter);
|
||||
string GetEngineValues(string delimeter);
|
||||
|
||||
private:
|
||||
double SHR;
|
||||
double maxPC;
|
||||
double propEff;
|
||||
double kFactor;
|
||||
double Variance;
|
||||
double PC;
|
||||
/** Reduces the fuel in the active tanks by the amount required.
|
||||
This function should be called from within the
|
||||
derived class' Calculate() function before any other calculations are
|
||||
done. This base class method removes fuel from the fuel tanks as
|
||||
appropriate, and sets the starved flag if necessary. */
|
||||
void ConsumeFuel(void);
|
||||
|
||||
/** The fuel need is calculated based on power levels and flow rate for that
|
||||
power level. It is also turned from a rate into an actual amount (pounds)
|
||||
by multiplying it by the delta T and the rate.
|
||||
@return Total fuel requirement for this engine in pounds. */
|
||||
double CalcFuelNeed(void);
|
||||
|
||||
/** The oxidizer need is calculated based on power levels and flow rate for that
|
||||
power level. It is also turned from a rate into an actual amount (pounds)
|
||||
by multiplying it by the delta T and the rate.
|
||||
@return Total oxidizer requirement for this engine in pounds. */
|
||||
double CalcOxidizerNeed(void);
|
||||
|
||||
/** Returns the vacuum thrust.
|
||||
@return The vacuum thrust in lbs. */
|
||||
double GetVacThrust(void) const {return VacThrust;}
|
||||
|
||||
void bindmodel(void);
|
||||
|
||||
double Isp; // Vacuum Isp
|
||||
double It;
|
||||
double MxR; // Mixture Ratio
|
||||
double BurnTime;
|
||||
double VacThrust;
|
||||
double previousFuelNeedPerTank;
|
||||
double previousOxiNeedPerTank;
|
||||
double OxidizerExpended;
|
||||
double SLOxiFlowMax;
|
||||
double OxidizerFlowRate;
|
||||
double PropellantFlowRate;
|
||||
bool Flameout;
|
||||
FGTable* ThrustTable;
|
||||
|
||||
|
|
|
@ -56,10 +56,11 @@ FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number)
|
|||
{
|
||||
string token;
|
||||
Element* element;
|
||||
Element* element_Grain;
|
||||
Area = 1.0;
|
||||
Temperature = -9999.0;
|
||||
Auxiliary = exec->GetAuxiliary();
|
||||
Radius = Capacity = Contents = Standpipe = 0.0;
|
||||
Radius = Capacity = Contents = Standpipe = Length = InnerRadius = 0.0;
|
||||
PropertyManager = exec->GetPropertyManager();
|
||||
vXYZ.InitMatrix();
|
||||
vXYZ_drain.InitMatrix();
|
||||
|
@ -100,6 +101,44 @@ FGTank::FGTank(FGFDMExec* exec, Element* el, int tank_number)
|
|||
PctFull = 0;
|
||||
}
|
||||
|
||||
// Check whether this is a solid propellant "tank". Initialize it if true.
|
||||
|
||||
grainType = gtUNKNOWN; // This is the default
|
||||
|
||||
element_Grain = el->FindElement("grain_config");
|
||||
if (element_Grain) {
|
||||
|
||||
strGType = element_Grain->GetAttributeValue("type");
|
||||
if (strGType == "CYLINDRICAL") grainType = gtCYLINDRICAL;
|
||||
else if (strGType == "ENDBURNING") grainType = gtENDBURNING;
|
||||
else cerr << "Unknown propellant grain type specified" << endl;
|
||||
|
||||
if (element_Grain->FindElement("length"))
|
||||
Length = element_Grain->FindElementValueAsNumberConvertTo("length", "IN");
|
||||
if (element_Grain->FindElement("bore_diameter"))
|
||||
InnerRadius = element_Grain->FindElementValueAsNumberConvertTo("bore_diameter", "IN")/2.0;
|
||||
|
||||
// Initialize solid propellant values for debug and runtime use.
|
||||
|
||||
switch (grainType) {
|
||||
case gtCYLINDRICAL:
|
||||
if (Radius <= InnerRadius) {
|
||||
cerr << "The bore diameter should be smaller than the total grain diameter!" << endl;
|
||||
exit(-1);
|
||||
}
|
||||
Volume = M_PI * Length * (Radius*Radius - InnerRadius*InnerRadius); // cubic inches
|
||||
break;
|
||||
case gtENDBURNING:
|
||||
Volume = M_PI * Length * Radius * Radius; // cubic inches
|
||||
break;
|
||||
case gtUNKNOWN:
|
||||
cerr << "Unknown grain type found in this rocket engine definition." << endl;
|
||||
exit(-1);
|
||||
}
|
||||
Density = (Contents*lbtoslug)/Volume; // slugs/in^3
|
||||
|
||||
}
|
||||
|
||||
char property_name[80];
|
||||
snprintf(property_name, 80, "propulsion/tank[%d]/contents-lbs", TankNumber);
|
||||
PropertyManager->Tie( property_name, (FGTank*)this, &FGTank::GetContents,
|
||||
|
@ -160,6 +199,9 @@ double FGTank::Drain(double used)
|
|||
PctFull = 0.0;
|
||||
Selected = false;
|
||||
}
|
||||
|
||||
if (grainType != gtUNKNOWN) CalculateInertias();
|
||||
|
||||
return remaining;
|
||||
}
|
||||
|
||||
|
@ -210,6 +252,35 @@ double FGTank::Calculate(double dt)
|
|||
return Temperature += (dTemp + dTemp); // For now, assume upper/lower the same
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// This function calculates the moments of inertia for a solid propellant
|
||||
// grain - either an end burning cylindrical grain or a bored cylindrical
|
||||
// grain.
|
||||
|
||||
void FGTank::CalculateInertias(void)
|
||||
{
|
||||
double Mass = Contents*lbtoslug;
|
||||
double RadSumSqr;
|
||||
double Rad2 = Radius*Radius;
|
||||
Volume = (Contents*lbtoslug)/Density; // in^3
|
||||
|
||||
switch (grainType) {
|
||||
case gtCYLINDRICAL:
|
||||
InnerRadius = sqrt(Rad2 - Volume/(M_PI * Length));
|
||||
RadSumSqr = (Rad2 + InnerRadius*InnerRadius)/144.0;
|
||||
Ixx = 0.5*Mass*RadSumSqr;
|
||||
Iyy = Mass*(3.0*RadSumSqr + Length*Length/144.0)/12.0;
|
||||
break;
|
||||
case gtENDBURNING:
|
||||
Length = Volume/(M_PI*Rad2);
|
||||
Ixx = 0.5*Mass*Rad2/144.0;
|
||||
Iyy = Mass*(3.0*Rad2 + Length*Length)/(144.0*12.0);
|
||||
break;
|
||||
}
|
||||
Izz = Iyy;
|
||||
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
// The bitmasked value choices are as follows:
|
||||
// unset: In this case (the default) JSBSim would only print
|
||||
|
|
|
@ -109,6 +109,9 @@ CLASS DOCUMENTATION
|
|||
|
||||
@code
|
||||
<tank type="{FUEL | OXIDIZER}">
|
||||
<grain_config type="{CYLINDRICAL | ENDBURNING}">
|
||||
<length unit="{IN | FT | M}"> {number} </radius>
|
||||
</grain_config>
|
||||
<location unit="{FT | M | IN}">
|
||||
<x> {number} </x>
|
||||
<y> {number} </y>
|
||||
|
@ -119,7 +122,7 @@ CLASS DOCUMENTATION
|
|||
<y> {number} </y>
|
||||
<z> {number} </z>
|
||||
</drain_location>
|
||||
<radius unit="{FT | M}"> {number} </radius>
|
||||
<radius unit="{IN | FT | M}"> {number} </radius>
|
||||
<capacity unit="{LBS | KG}"> {number} </capacity>
|
||||
<contents unit="{LBS | KG}"> {number} </contents>
|
||||
<temperature> {number} </temperature> <!-- must be degrees fahrenheit -->
|
||||
|
@ -131,6 +134,8 @@ CLASS DOCUMENTATION
|
|||
|
||||
- \b type - One of FUEL or OXIDIZER. This is required.
|
||||
- \b radius - Equivalent radius of tank for modeling slosh, defaults to inches.
|
||||
- \b grain_config type - One of CYLINDRICAL or ENDBURNING.
|
||||
- \b length - length of tank for modeling solid fuel propellant grain, defaults to inches.
|
||||
- \b capacity - Capacity, defaults to pounds.
|
||||
- \b contents - Initial contents, defaults to pounds.
|
||||
- \b temperature - Initial temperature, defaults to degrees Fahrenheit.
|
||||
|
@ -236,6 +241,10 @@ public:
|
|||
is given, otherwise 32 degrees F is returned. */
|
||||
double GetTemperature(void) {return CelsiusToFahrenheit(Temperature);}
|
||||
|
||||
double GetIxx(void) {return Ixx;}
|
||||
double GetIyy(void) {return Iyy;}
|
||||
double GetIzz(void) {return Izz;}
|
||||
|
||||
double GetStandpipe(void) {return Standpipe;}
|
||||
|
||||
const FGColumnVector3 GetXYZ(void);
|
||||
|
@ -247,15 +256,25 @@ public:
|
|||
void SetStandpipe(double amount) { Standpipe = amount; }
|
||||
|
||||
enum TankType {ttUNKNOWN, ttFUEL, ttOXIDIZER};
|
||||
enum GrainType {gtUNKNOWN, gtCYLINDRICAL, gtENDBURNING};
|
||||
|
||||
private:
|
||||
TankType Type;
|
||||
GrainType grainType;
|
||||
int TankNumber;
|
||||
string type;
|
||||
string strGType;
|
||||
FGColumnVector3 vXYZ;
|
||||
FGColumnVector3 vXYZ_drain;
|
||||
double Capacity;
|
||||
double Radius;
|
||||
double InnerRadius;
|
||||
double Length;
|
||||
double Volume;
|
||||
double Density;
|
||||
double Ixx;
|
||||
double Iyy;
|
||||
double Izz;
|
||||
double PctFull;
|
||||
double Contents, InitialContents;
|
||||
double Area;
|
||||
|
@ -264,6 +283,7 @@ private:
|
|||
bool Selected;
|
||||
FGAuxiliary* Auxiliary;
|
||||
FGPropertyManager* PropertyManager;
|
||||
void CalculateInertias(void);
|
||||
void Debug(int from);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -361,7 +361,10 @@ double FGTurbine::Trim()
|
|||
|
||||
double FGTurbine::CalcFuelNeed(void)
|
||||
{
|
||||
return FuelFlow_pph /3600 * State->Getdt() * Propulsion->GetRate();
|
||||
double dT = State->Getdt() * Propulsion->GetRate();
|
||||
FuelFlowRate = FuelFlow_pph / 3600.0; // Calculates flow in lbs/sec from lbs/hr
|
||||
FuelExpended = FuelFlowRate * dT; // Calculates fuel expended in this time step
|
||||
return FuelExpended;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -493,8 +496,6 @@ void FGTurbine::bindmodel()
|
|||
PropertyManager->Tie( property_name, &N1);
|
||||
snprintf(property_name, 80, "propulsion/engine[%u]/n2", EngineNumber);
|
||||
PropertyManager->Tie( property_name, &N2);
|
||||
snprintf(property_name, 80, "propulsion/engine[%u]/thrust", EngineNumber);
|
||||
PropertyManager->Tie( property_name, this, &FGTurbine::GetThrust);
|
||||
snprintf(property_name, 80, "propulsion/engine[%u]/injection_cmd", EngineNumber);
|
||||
PropertyManager->Tie( property_name, (FGTurbine*)this,
|
||||
&FGTurbine::GetInjection, &FGTurbine::SetInjection);
|
||||
|
|
|
@ -169,7 +169,7 @@ public:
|
|||
double Calculate(void);
|
||||
double CalcFuelNeed(void);
|
||||
double GetPowerAvailable(void);
|
||||
double GetThrust(void) const {return Thrust;}
|
||||
// double GetThrust(void) const {return Thrust;}
|
||||
/** A lag filter.
|
||||
Used to control the rate at which values are allowed to change.
|
||||
@param var a pointer to a variable of type double
|
||||
|
|
|
@ -398,7 +398,10 @@ double FGTurboProp::Start(void)
|
|||
|
||||
double FGTurboProp::CalcFuelNeed(void)
|
||||
{
|
||||
return FuelFlow_pph /3600 * State->Getdt() * Propulsion->GetRate();
|
||||
double dT = State->Getdt() * Propulsion->GetRate();
|
||||
FuelFlowRate = FuelFlow_pph / 3600.0;
|
||||
FuelExpended = FuelFlowRate * dT;
|
||||
return FuelExpended;
|
||||
}
|
||||
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
Loading…
Reference in a new issue