1
0
Fork 0

Sync w. JSBSim CVS

This commit is contained in:
ehofman 2004-06-14 11:40:45 +00:00
parent 56f085b6f1
commit 8e1482f746
86 changed files with 5305 additions and 4950 deletions

View file

@ -37,7 +37,7 @@ INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGAerodynamics.h" #include "FGAerodynamics.h"
#include "FGTranslation.h" #include "FGPropagate.h"
#include "FGAircraft.h" #include "FGAircraft.h"
#include "FGState.h" #include "FGState.h"
#include "FGMassBalance.h" #include "FGMassBalance.h"
@ -49,9 +49,9 @@ namespace JSBSim {
static const char *IdSrc = "$Id$"; static const char *IdSrc = "$Id$";
static const char *IdHdr = ID_AERODYNAMICS; static const char *IdHdr = ID_AERODYNAMICS;
const unsigned NAxes=6; const unsigned NAxes=6;
const char* AxisNames[] = { "drag", "side-force", "lift", "rolling-moment", const char* AxisNames[] = { "drag", "side-force", "lift", "rolling-moment",
"pitching-moment","yawing-moment" }; "pitching-moment","yawing-moment" };
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION CLASS IMPLEMENTATION
@ -70,12 +70,12 @@ FGAerodynamics::FGAerodynamics(FGFDMExec* FDMExec) : FGModel(FDMExec)
AxisIdx["YAW"] = 5; AxisIdx["YAW"] = 5;
Coeff = new CoeffArray[6]; Coeff = new CoeffArray[6];
impending_stall = stall_hyst = 0.0; impending_stall = stall_hyst = 0.0;
alphaclmin = alphaclmax = 0.0; alphaclmin = alphaclmax = 0.0;
alphahystmin = alphahystmax = 0.0; alphahystmin = alphahystmax = 0.0;
clsq = lod = 0.0; clsq = lod = 0.0;
alphaw = 0.0; alphaw = 0.0;
bi2vel = ci2vel = 0.0; bi2vel = ci2vel = 0.0;
bind(); bind();
@ -87,16 +87,16 @@ FGAerodynamics::FGAerodynamics(FGFDMExec* FDMExec) : FGModel(FDMExec)
FGAerodynamics::~FGAerodynamics() FGAerodynamics::~FGAerodynamics()
{ {
unsigned int i,j; unsigned int i,j;
unbind(); unbind();
for (i=0; i<6; i++) { for (i=0; i<6; i++) {
for (j=0; j<Coeff[i].size(); j++) { for (j=0; j<Coeff[i].size(); j++) {
delete Coeff[i][j]; delete Coeff[i][j];
} }
} }
delete[] Coeff; delete[] Coeff;
Debug(1); Debug(1);
} }
@ -109,16 +109,16 @@ bool FGAerodynamics::Run(void)
if (!FGModel::Run()) { if (!FGModel::Run()) {
twovel = 2*Translation->GetVt(); twovel = 2*Auxiliary->GetVt();
if (twovel != 0) { if (twovel != 0) {
bi2vel = Aircraft->GetWingSpan() / twovel; bi2vel = Aircraft->GetWingSpan() / twovel;
ci2vel = Aircraft->Getcbar() / twovel; ci2vel = Aircraft->Getcbar() / twovel;
} }
alphaw = Translation->Getalpha() + Aircraft->GetWingIncidence(); alphaw = Auxiliary->Getalpha() + Aircraft->GetWingIncidence();
alpha = Translation->Getalpha(); alpha = Auxiliary->Getalpha();
if (alphaclmax != 0) { if (alphaclmax != 0) {
if (alpha > 0.85*alphaclmax) { if (alpha > 0.85*alphaclmax) {
impending_stall = 10*(alpha/alphaclmax - 0.85); impending_stall = 10*(alpha/alphaclmax - 0.85);
@ -126,15 +126,15 @@ bool FGAerodynamics::Run(void)
impending_stall = 0; impending_stall = 0;
} }
} }
if (alphahystmax != 0.0 && alphahystmin != 0.0) { if (alphahystmax != 0.0 && alphahystmin != 0.0) {
if (alpha > alphahystmax) { if (alpha > alphahystmax) {
stall_hyst = 1; stall_hyst = 1;
} else if (alpha < alphahystmin) { } else if (alpha < alphahystmin) {
stall_hyst = 0; stall_hyst = 0;
} }
} }
vLastFs = vFs; vLastFs = vFs;
vFs.InitMatrix(); vFs.InitMatrix();
@ -146,14 +146,14 @@ bool FGAerodynamics::Run(void)
//correct signs of drag and lift to wind axes convention //correct signs of drag and lift to wind axes convention
//positive forward, right, down //positive forward, right, down
if ( Translation->Getqbar() > 0) { if ( Auxiliary->Getqbar() > 0) {
clsq = vFs(eLift) / (Aircraft->GetWingArea()*Translation->Getqbar()); clsq = vFs(eLift) / (Aircraft->GetWingArea()*Auxiliary->Getqbar());
clsq *= clsq; clsq *= clsq;
} }
if ( vFs(eDrag) > 0) { if ( vFs(eDrag) > 0) {
lod = vFs(eLift) / vFs(eDrag); lod = vFs(eLift) / vFs(eDrag);
} }
//correct signs of drag and lift to wind axes convention //correct signs of drag and lift to wind axes convention
//positive forward, right, down //positive forward, right, down
vFs(eDrag)*=-1; vFs(eLift)*=-1; vFs(eDrag)*=-1; vFs(eLift)*=-1;
@ -214,7 +214,7 @@ bool FGAerodynamics::Load(FGConfigFile* AC_cfg)
} }
bindModel(); bindModel();
return true; return true;
} }
@ -287,7 +287,7 @@ void FGAerodynamics::bind(void)
PropertyManager->Tie("forces/lod-norm", this, PropertyManager->Tie("forces/lod-norm", this,
&FGAerodynamics::GetLoD); &FGAerodynamics::GetLoD);
PropertyManager->Tie("aero/cl-squared-norm", this, PropertyManager->Tie("aero/cl-squared-norm", this,
&FGAerodynamics::GetClSquared); &FGAerodynamics::GetClSquared);
PropertyManager->Tie("aero/alpha-max-deg", this, PropertyManager->Tie("aero/alpha-max-deg", this,
&FGAerodynamics::GetAlphaCLMax, &FGAerodynamics::GetAlphaCLMax,
&FGAerodynamics::SetAlphaCLMax, &FGAerodynamics::SetAlphaCLMax,
@ -311,7 +311,7 @@ void FGAerodynamics::bind(void)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGAerodynamics::bindModel(void) void FGAerodynamics::bindModel(void)
{ {
unsigned i,j; unsigned i,j;
FGPropertyManager* node; FGPropertyManager* node;
string axis_node_name; string axis_node_name;
@ -320,8 +320,8 @@ void FGAerodynamics::bindModel(void)
node = node->GetNode( string(AxisNames[i]),true ); node = node->GetNode( string(AxisNames[i]),true );
for (j=0; j < Coeff[i].size(); j++) { for (j=0; j < Coeff[i].size(); j++) {
Coeff[i][j]->bind(node); Coeff[i][j]->bind(node);
} }
node = (FGPropertyManager*)node->getParent(); node = (FGPropertyManager*)node->getParent();
} }
} }
@ -341,7 +341,7 @@ void FGAerodynamics::unbind(void)
PropertyManager->Untie("forces/fwy-aero-lbs"); PropertyManager->Untie("forces/fwy-aero-lbs");
PropertyManager->Untie("forces/fwz-aero-lbs"); PropertyManager->Untie("forces/fwz-aero-lbs");
PropertyManager->Untie("forces/lod-norm"); PropertyManager->Untie("forces/lod-norm");
PropertyManager->Untie("aero/cl-squared-norm"); PropertyManager->Untie("aero/cl-squared-norm");
PropertyManager->Untie("aero/alpha-max-deg"); PropertyManager->Untie("aero/alpha-max-deg");
PropertyManager->Untie("aero/alpha-min-deg"); PropertyManager->Untie("aero/alpha-min-deg");
PropertyManager->Untie("aero/bi2vel"); PropertyManager->Untie("aero/bi2vel");
@ -353,7 +353,7 @@ void FGAerodynamics::unbind(void)
for ( i=0; i<NAxes; i++ ) { for ( i=0; i<NAxes; i++ ) {
for ( j=0; j < Coeff[i].size(); j++ ) { for ( j=0; j < Coeff[i].size(); j++ ) {
Coeff[i][j]->unbind(); Coeff[i][j]->unbind();
} }
} }
} }

View file

@ -75,7 +75,7 @@ INCLUDES
#include "FGAerodynamics.h" #include "FGAerodynamics.h"
#include "FGState.h" #include "FGState.h"
#include "FGFDMExec.h" #include "FGFDMExec.h"
#include "FGPosition.h" #include "FGPropagate.h"
#include "FGPropertyManager.h" #include "FGPropertyManager.h"
namespace JSBSim { namespace JSBSim {
@ -125,7 +125,6 @@ bool FGAircraft::Run(void)
if (!FGModel::Run()) { // if false then execute this Run() if (!FGModel::Run()) { // if false then execute this Run()
vForces.InitMatrix(); vForces.InitMatrix();
vForces += Aerodynamics->GetForces(); vForces += Aerodynamics->GetForces();
vForces += Inertial->GetForces();
vForces += Propulsion->GetForces(); vForces += Propulsion->GetForces();
vForces += GroundReactions->GetForces(); vForces += GroundReactions->GetForces();
@ -229,7 +228,6 @@ bool FGAircraft::Load(FGConfigFile* AC_cfg)
} else if (parameter == "AC_VRP") { } else if (parameter == "AC_VRP") {
*AC_cfg >> vXYZvrp(eX) >> vXYZvrp(eY) >> vXYZvrp(eZ); *AC_cfg >> vXYZvrp(eX) >> vXYZvrp(eY) >> vXYZvrp(eZ);
if (debug_lvl > 0) cout << " Visual Ref Pt (x, y, z): " << vXYZvrp << endl; if (debug_lvl > 0) cout << " Visual Ref Pt (x, y, z): " << vXYZvrp << endl;
Position->SetVRP(vXYZvrp);
} else if (parameter == "AC_POINTMASS") { } else if (parameter == "AC_POINTMASS") {
*AC_cfg >> pmWt >> pmX >> pmY >> pmZ; *AC_cfg >> pmWt >> pmX >> pmY >> pmZ;
MassBalance->AddPointMass(pmWt, pmX, pmY, pmZ); MassBalance->AddPointMass(pmWt, pmX, pmY, pmZ);

View file

@ -2,7 +2,7 @@
Module: FGAtmosphere.cpp Module: FGAtmosphere.cpp
Author: Jon Berndt Author: Jon Berndt
Implementation of 1959 Standard Atmosphere added by Tony Peden Implementation of 1959 Standard Atmosphere added by Tony Peden
Date started: 11/24/98 Date started: 11/24/98
Purpose: Models the atmosphere Purpose: Models the atmosphere
Called by: FGSimExec Called by: FGSimExec
@ -35,7 +35,7 @@ HISTORY
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
11/24/98 JSB Created 11/24/98 JSB Created
07/23/99 TP Added implementation of 1959 Standard Atmosphere 07/23/99 TP Added implementation of 1959 Standard Atmosphere
Moved calculation of Mach number to FGTranslation Moved calculation of Mach number to FGPropagate
Later updated to '76 model Later updated to '76 model
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
COMMENTS, REFERENCES, and NOTES COMMENTS, REFERENCES, and NOTES
@ -51,7 +51,7 @@ INCLUDES
#include "FGState.h" #include "FGState.h"
#include "FGFDMExec.h" #include "FGFDMExec.h"
#include "FGAircraft.h" #include "FGAircraft.h"
#include "FGPosition.h" #include "FGPropagate.h"
#include "FGInertial.h" #include "FGInertial.h"
#include "FGPropertyManager.h" #include "FGPropertyManager.h"
@ -86,7 +86,7 @@ FGAtmosphere::FGAtmosphere(FGFDMExec* fdmex) : FGModel(fdmex)
// turbType = ttBerndt; // turbType = ttBerndt;
TurbGain = 0.0; TurbGain = 0.0;
TurbRate = 1.0; TurbRate = 1.0;
bind(); bind();
Debug(0); Debug(0);
} }
@ -117,9 +117,9 @@ bool FGAtmosphere::InitModel(void)
temperature=&intTemperature; temperature=&intTemperature;
pressure=&intPressure; pressure=&intPressure;
density=&intDensity; density=&intDensity;
useExternal=false; useExternal=false;
return true; return true;
} }
@ -130,9 +130,9 @@ bool FGAtmosphere::Run(void)
if (!FGModel::Run()) { // if false then execute this Run() if (!FGModel::Run()) { // if false then execute this Run()
//do temp, pressure, and density first //do temp, pressure, and density first
if (!useExternal) { if (!useExternal) {
h = Position->Geth(); h = Propagate->Geth();
Calculate(h); Calculate(h);
} }
if (turbType != ttNone) { if (turbType != ttNone) {
Turbulence(); Turbulence();
@ -164,13 +164,13 @@ void FGAtmosphere::Calculate(double altitude)
i = lastIndex; i = lastIndex;
if (altitude < htab[lastIndex]) { if (altitude < htab[lastIndex]) {
if (altitude <= 0) { if (altitude <= 0) {
i = 0; i = 0;
altitude=0; altitude=0;
} else { } else {
i = lastIndex-1; i = lastIndex-1;
while (htab[i] > altitude) i--; while (htab[i] > altitude) i--;
} }
} else if (altitude > htab[lastIndex+1]) { } else if (altitude > htab[lastIndex+1]) {
if (altitude >= htab[7]) { if (altitude >= htab[7]) {
i = 7; i = 7;
@ -178,8 +178,8 @@ void FGAtmosphere::Calculate(double altitude)
} else { } else {
i = lastIndex+1; i = lastIndex+1;
while (htab[i+1] < altitude) i++; while (htab[i+1] < altitude) i++;
} }
} }
switch(i) { switch(i) {
case 1: // 36089 ft. case 1: // 36089 ft.
@ -231,9 +231,9 @@ void FGAtmosphere::Calculate(double altitude)
refpress = 2116.22; // psf refpress = 2116.22; // psf
//refdens = 0.00237767; // slugs/cubic ft. //refdens = 0.00237767; // slugs/cubic ft.
break; break;
} }
if (slope == 0) { if (slope == 0) {
intTemperature = reftemp; intTemperature = reftemp;
intPressure = refpress*exp(-Inertial->SLgravity()/(reftemp*Reng)*(altitude-htab[i])); intPressure = refpress*exp(-Inertial->SLgravity()/(reftemp*Reng)*(altitude-htab[i]));
@ -250,10 +250,20 @@ void FGAtmosphere::Calculate(double altitude)
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Return the pressure at an arbitrary altitude and then restore the internal state
double FGAtmosphere::GetPressure(double alt) {
Calculate(alt);
double p = *pressure;
// Reset the internal atmospheric state
Run();
return(p);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// square a value, but preserve the original sign // square a value, but preserve the original sign
static inline double
square_signed (double value) static inline double square_signed (double value)
{ {
if (value < 0) if (value < 0)
return value * value * -1; return value * value * -1;
@ -261,6 +271,8 @@ square_signed (double value)
return value * value; return value * value;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGAtmosphere::Turbulence(void) void FGAtmosphere::Turbulence(void)
{ {
switch (turbType) { switch (turbType) {
@ -288,18 +300,18 @@ void FGAtmosphere::Turbulence(void)
vDirection += vDirectionAccel*rate*State->Getdt(); vDirection += vDirectionAccel*rate*State->Getdt();
vDirection.Normalize(); vDirection.Normalize();
// Diminish turbulence within three wingspans // Diminish turbulence within three wingspans
// of the ground // of the ground
vTurbulence = TurbGain * Magnitude * vDirection; vTurbulence = TurbGain * Magnitude * vDirection;
double HOverBMAC = Position->GetHOverBMAC(); double HOverBMAC = Auxiliary->GetHOverBMAC();
if (HOverBMAC < 3.0) if (HOverBMAC < 3.0)
vTurbulence *= (HOverBMAC / 3.0) * (HOverBMAC / 3.0); vTurbulence *= (HOverBMAC / 3.0) * (HOverBMAC / 3.0);
vTurbulenceGrad = TurbGain*MagnitudeAccel * vDirection; vTurbulenceGrad = TurbGain*MagnitudeAccel * vDirection;
vBodyTurbGrad = State->GetTl2b()*vTurbulenceGrad; vBodyTurbGrad = Propagate->GetTl2b()*vTurbulenceGrad;
if (Aircraft->GetWingSpan() > 0) { if (Aircraft->GetWingSpan() > 0) {
vTurbPQR(eP) = vBodyTurbGrad(eY)/Aircraft->GetWingSpan(); vTurbPQR(eP) = vBodyTurbGrad(eY)/Aircraft->GetWingSpan();
} else { } else {
@ -329,7 +341,7 @@ void FGAtmosphere::Turbulence(void)
vDirectiondAccelDt(eY) = 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)); vDirectiondAccelDt(eZ) = 1 - 2.0*(double(rand())/double(RAND_MAX));
MagnitudedAccelDt = 1 - 2.0*(double(rand())/double(RAND_MAX)) - Magnitude; MagnitudedAccelDt = 1 - 2.0*(double(rand())/double(RAND_MAX)) - Magnitude;
MagnitudeAccel += MagnitudedAccelDt*rate*State->Getdt(); MagnitudeAccel += MagnitudedAccelDt*rate*State->Getdt();
Magnitude += MagnitudeAccel*rate*State->Getdt(); Magnitude += MagnitudeAccel*rate*State->Getdt();
@ -341,16 +353,16 @@ void FGAtmosphere::Turbulence(void)
// Diminish z-vector within two wingspans // Diminish z-vector within two wingspans
// of the ground // of the ground
double HOverBMAC = Position->GetHOverBMAC(); double HOverBMAC = Auxiliary->GetHOverBMAC();
if (HOverBMAC < 2.0) if (HOverBMAC < 2.0)
vDirection(eZ) *= HOverBMAC / 2.0; vDirection(eZ) *= HOverBMAC / 2.0;
vDirection.Normalize(); vDirection.Normalize();
vTurbulence = TurbGain*Magnitude * vDirection; vTurbulence = TurbGain*Magnitude * vDirection;
vTurbulenceGrad = TurbGain*MagnitudeAccel * vDirection; vTurbulenceGrad = TurbGain*MagnitudeAccel * vDirection;
vBodyTurbGrad = State->GetTl2b()*vTurbulenceGrad; vBodyTurbGrad = Propagate->GetTl2b()*vTurbulenceGrad;
vTurbPQR(eP) = vBodyTurbGrad(eY)/Aircraft->GetWingSpan(); vTurbPQR(eP) = vBodyTurbGrad(eY)/Aircraft->GetWingSpan();
if (Aircraft->GetHTailArm() > 0) if (Aircraft->GetHTailArm() > 0)
vTurbPQR(eQ) = vBodyTurbGrad(eZ)/Aircraft->GetHTailArm(); vTurbPQR(eQ) = vBodyTurbGrad(eZ)/Aircraft->GetHTailArm();
@ -386,7 +398,6 @@ void FGAtmosphere::UseInternal(void) {
density=&intDensity; density=&intDensity;
useExternal=false; useExternal=false;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -397,8 +408,8 @@ void FGAtmosphere::bind(void)
&FGAtmosphere::GetTemperature); &FGAtmosphere::GetTemperature);
PropertyManager->Tie("atmosphere/rho-slugs_ft3", this, PropertyManager->Tie("atmosphere/rho-slugs_ft3", this,
&FGAtmosphere::GetDensity); &FGAtmosphere::GetDensity);
PropertyManager->Tie("atmosphere/P-psf", this, // PropertyManager->Tie("atmosphere/P-psf", this,
&FGAtmosphere::GetPressure); // &FGAtmosphere::GetPressure);
PropertyManager->Tie("atmosphere/a-fps", this, PropertyManager->Tie("atmosphere/a-fps", this,
&FGAtmosphere::GetSoundSpeed); &FGAtmosphere::GetSoundSpeed);
PropertyManager->Tie("atmosphere/T-sl-R", this, PropertyManager->Tie("atmosphere/T-sl-R", this,
@ -433,7 +444,7 @@ void FGAtmosphere::unbind(void)
{ {
PropertyManager->Untie("atmosphere/T-R"); PropertyManager->Untie("atmosphere/T-R");
PropertyManager->Untie("atmosphere/rho-slugs_ft3"); PropertyManager->Untie("atmosphere/rho-slugs_ft3");
PropertyManager->Untie("atmosphere/P-psf"); // PropertyManager->Untie("atmosphere/P-psf");
PropertyManager->Untie("atmosphere/a-fps"); PropertyManager->Untie("atmosphere/a-fps");
PropertyManager->Untie("atmosphere/T-sl-R"); PropertyManager->Untie("atmosphere/T-sl-R");
PropertyManager->Untie("atmosphere/rho-sl-slugs_ft3"); PropertyManager->Untie("atmosphere/rho-sl-slugs_ft3");

View file

@ -28,7 +28,7 @@ HISTORY
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
11/24/98 JSB Created 11/24/98 JSB Created
07/23/99 TP Added implementation of 1959 Standard Atmosphere 07/23/99 TP Added implementation of 1959 Standard Atmosphere
Moved calculation of Mach number to FGTranslation Moved calculation of Mach number to FGPropagate
Updated to '76 model Updated to '76 model
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -92,6 +92,8 @@ public:
inline double GetDensity(void) const {return *density;} inline double GetDensity(void) const {return *density;}
/// Returns the pressure in psf. /// Returns the pressure in psf.
inline double GetPressure(void) const {return *pressure;} inline double GetPressure(void) const {return *pressure;}
/// Returns the pressure at an arbitrary altitude in psf
double GetPressure(double alt);
/// Returns the speed of sound in ft/sec. /// Returns the speed of sound in ft/sec.
inline double GetSoundSpeed(void) const {return soundspeed;} inline double GetSoundSpeed(void) const {return soundspeed;}

View file

@ -1,18 +1,18 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Module: FGAuxiliary.cpp Module: FGAuxiliary.cpp
Author: Tony Peden, Jon Berndt Author: Tony Peden, Jon Berndt
Date started: 01/26/99 Date started: 01/26/99
Purpose: Calculates additional parameters needed by the visual system, etc. Purpose: Calculates additional parameters needed by the visual system, etc.
Called by: FGSimExec Called by: FGSimExec
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------- ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later Foundation; either version 2 of the License, or (at your option) any later
version. version.
This program is distributed in the hope that it will be useful, but WITHOUT This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
@ -42,8 +42,7 @@ INCLUDES
#include "FGAuxiliary.h" #include "FGAuxiliary.h"
#include "FGAerodynamics.h" #include "FGAerodynamics.h"
#include "FGTranslation.h" #include "FGPropagate.h"
#include "FGRotation.h"
#include "FGAtmosphere.h" #include "FGAtmosphere.h"
#include "FGState.h" #include "FGState.h"
#include "FGFDMExec.h" #include "FGFDMExec.h"
@ -64,14 +63,29 @@ CLASS IMPLEMENTATION
FGAuxiliary::FGAuxiliary(FGFDMExec* fdmex) : FGModel(fdmex) FGAuxiliary::FGAuxiliary(FGFDMExec* fdmex) : FGModel(fdmex)
{ {
Name = "FGAuxiliary"; Name = "FGAuxiliary";
vcas = veas = mach = qbar = pt = tat = 0; vcas = veas = pt = tat = 0;
psl = rhosl = 1; psl = rhosl = 1;
earthPosAngle = 0.0; earthPosAngle = 0.0;
qbar = 0;
qbarUW = 0.0;
qbarUV = 0.0;
Mach = 0.0;
alpha = beta = 0.0;
adot = bdot = 0.0;
gamma = Vt = Vground = 0.0;
psigt = 0.0;
day_of_year = 1;
seconds_in_day = 0.0;
hoverbmac = hoverbcg = 0.0;
vPilotAccel.InitMatrix();
vPilotAccelN.InitMatrix(); vPilotAccelN.InitMatrix();
vToEyePt.InitMatrix();
vAeroPQR.InitMatrix();
vEulerRates.InitMatrix();
bind(); bind();
Debug(0); Debug(0);
} }
@ -87,93 +101,136 @@ FGAuxiliary::~FGAuxiliary()
bool FGAuxiliary::Run() bool FGAuxiliary::Run()
{ {
double A,B,D; double A,B,D, hdot_Vt;
const FGColumnVector3& vPQR = Propagate->GetPQR();
const FGColumnVector3& vUVW = Propagate->GetUVW();
const FGColumnVector3& vUVWdot = Propagate->GetUVWdot();
const FGColumnVector3& vVel = Propagate->GetVel();
if (!FGModel::Run()) { if (!FGModel::Run())
GetState(); {
p = Atmosphere->GetPressure();
//calculate total temperature assuming isentropic flow rhosl = Atmosphere->GetDensitySL();
tat=sat*(1 + 0.2*mach*mach); psl = Atmosphere->GetPressureSL();
tatc=RankineToCelsius(tat); sat = Atmosphere->GetTemperature();
if (mach < 1) { //calculate total pressure assuming isentropic flow // Rotation
pt = p*pow((1 + 0.2*machU*machU),3.5);
double cTht = Propagate->GetCostht();
double cPhi = Propagate->GetCosphi();
double sPhi = Propagate->GetSinphi();
vEulerRates(eTht) = vPQR(eQ)*cPhi - vPQR(eR)*sPhi;
if (cTht != 0.0) {
vEulerRates(ePsi) = (vPQR(eQ)*sPhi + vPQR(eR)*cPhi)/cTht;
vEulerRates(ePhi) = vPQR(eP) + vEulerRates(ePsi)*sPhi;
}
vAeroPQR = vPQR + Atmosphere->GetTurbPQR();
// Translation
vAeroUVW = vUVW + Propagate->GetTl2b()*Atmosphere->GetWindNED();
Vt = vAeroUVW.Magnitude();
if ( Vt > 0.05) {
if (vAeroUVW(eW) != 0.0)
alpha = vAeroUVW(eU)*vAeroUVW(eU) > 0.0 ? atan2(vAeroUVW(eW), vAeroUVW(eU)) : 0.0;
if (vAeroUVW(eV) != 0.0)
beta = vAeroUVW(eU)*vAeroUVW(eU)+vAeroUVW(eW)*vAeroUVW(eW) > 0.0 ? atan2(vAeroUVW(eV),
sqrt(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW))) : 0.0;
double mUW = (vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW));
double signU=1;
if (vAeroUVW(eU) != 0.0)
signU = vAeroUVW(eU)/fabs(vAeroUVW(eU));
if ( (mUW == 0.0) || (Vt == 0.0) ) {
adot = 0.0;
bdot = 0.0;
} else {
adot = (vAeroUVW(eU)*vUVWdot(eW) - vAeroUVW(eW)*vUVWdot(eU))/mUW;
bdot = (signU*mUW*vUVWdot(eV) - vAeroUVW(eV)*(vAeroUVW(eU)*vUVWdot(eU)
+ vAeroUVW(eW)*vUVWdot(eW)))/(Vt*Vt*sqrt(mUW));
}
} else { } else {
// shock in front of pitot tube, we'll assume its normal and use alpha = beta = adot = bdot = 0;
// the Rayleigh Pitot Tube Formula, i.e. the ratio of total }
// pressure behind the shock to the static pressure in front
B = 5.76*machU*machU/(5.6*machU*machU - 0.8); qbar = 0.5*Atmosphere->GetDensity()*Vt*Vt;
qbarUW = 0.5*Atmosphere->GetDensity()*(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW));
qbarUV = 0.5*Atmosphere->GetDensity()*(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eV)*vAeroUVW(eV));
Mach = Vt / Atmosphere->GetSoundSpeed();
MachU = vMachUVW(eU) = vAeroUVW(eU) / Atmosphere->GetSoundSpeed();
vMachUVW(eV) = vAeroUVW(eV) / Atmosphere->GetSoundSpeed();
vMachUVW(eW) = vAeroUVW(eW) / Atmosphere->GetSoundSpeed();
// The denominator above is zero for Mach ~ 0.38, for which // Position
// we'll never be here, so we're safe
D = (2.8*machU*machU-0.4)*0.4167; Vground = sqrt( vVel(eNorth)*vVel(eNorth) + vVel(eEast)*vVel(eEast) );
if (vVel(eNorth) == 0) psigt = 0;
else psigt = atan2(vVel(eEast), vVel(eNorth));
if (psigt < 0.0) psigt += 2*M_PI;
if (Vt != 0) {
hdot_Vt = -vVel(eDown)/Vt;
if (fabs(hdot_Vt) <= 1) gamma = asin(hdot_Vt);
} else {
gamma = 0.0;
}
tat = sat*(1 + 0.2*Mach*Mach); // Total Temperature, isentropic flow
tatc = RankineToCelsius(tat);
if (MachU < 1) { // Calculate total pressure assuming isentropic flow
pt = p*pow((1 + 0.2*MachU*MachU),3.5);
} else {
// Use Rayleigh pitot tube formula for normal shock in front of pitot tube
B = 5.76*MachU*MachU/(5.6*MachU*MachU - 0.8);
D = (2.8*MachU*MachU-0.4)*0.4167;
pt = p*pow(B,3.5)*D; pt = p*pow(B,3.5)*D;
} }
A = pow(((pt-p)/psl+1),0.28571); A = pow(((pt-p)/psl+1),0.28571);
if (machU > 0.0) { if (MachU > 0.0) {
vcas = sqrt(7*psl/rhosl*(A-1)); vcas = sqrt(7*psl/rhosl*(A-1));
veas = sqrt(2*qbar/rhosl); veas = sqrt(2*qbar/rhosl);
} else { } else {
vcas = veas = 0.0; vcas = veas = 0.0;
} }
// Pilot sensed accelerations are calculated here. This is used vPilotAccel.InitMatrix();
// for the coordinated turn ball instrument. Motion base platforms sometimes if ( Vt > 1.0 ) {
// use the derivative of pilot sensed accelerations as the driving parameter, vPilotAccel = Aerodynamics->GetForces()
// rather than straight accelerations.
//
// The theory behind pilot-sensed calculations is presented:
//
// For purposes of discussion and calculation, assume for a minute that the
// pilot is in space and motionless in inertial space. She will feel
// no accelerations. If the aircraft begins to accelerate along any axis or
// axes (without rotating), the pilot will sense those accelerations. If
// any rotational moment is applied, the pilot will sense an acceleration
// due to that motion in the amount:
//
// [wdot X R] + [w X (w X R)]
// Term I Term II
//
// where:
//
// wdot = omegadot, the rotational acceleration rate vector
// w = omega, the rotational rate vector
// R = the vector from the aircraft CG to the pilot eyepoint
//
// The sum total of these two terms plus the acceleration of the aircraft
// body axis gives the acceleration the pilot senses in inertial space.
// In the presence of a large body such as a planet, a gravity field also
// provides an accelerating attraction. This acceleration can be transformed
// from the reference frame of the planet so as to be expressed in the frame
// of reference of the aircraft. This gravity field accelerating attraction
// is felt by the pilot as a force on her tushie as she sits in her aircraft
// on the runway awaiting takeoff clearance.
//
// In JSBSim the acceleration of the body frame in inertial space is given
// by the F = ma relation. If the vForces vector is divided by the aircraft
// mass, the acceleration vector is calculated. The term wdot is equivalent
// to the JSBSim vPQRdot vector, and the w parameter is equivalent to vPQR.
// The radius R is calculated below in the vector vToEyePt.
vPilotAccel.InitMatrix();
if ( Translation->GetVt() > 1 ) {
vPilotAccel = Aerodynamics->GetForces()
+ Propulsion->GetForces() + Propulsion->GetForces()
+ GroundReactions->GetForces(); + GroundReactions->GetForces();
vPilotAccel /= MassBalance->GetMass(); vPilotAccel /= MassBalance->GetMass();
vToEyePt = MassBalance->StructuralToBody(Aircraft->GetXYZep()); vToEyePt = MassBalance->StructuralToBody(Aircraft->GetXYZep());
vPilotAccel += Rotation->GetPQRdot() * vToEyePt; vPilotAccel += Propagate->GetPQRdot() * vToEyePt;
vPilotAccel += Rotation->GetPQR() * (Rotation->GetPQR() * vToEyePt); vPilotAccel += vPQR * (vPQR * vToEyePt);
} else { } else {
vPilotAccel = -1*( State->GetTl2b() * Inertial->GetGravity() ); vPilotAccel = Propagate->GetTl2b() * FGColumnVector3( 0.0, 0.0, Inertial->gravity() );
} }
vPilotAccelN = vPilotAccel/Inertial->gravity(); vPilotAccelN = vPilotAccel/Inertial->gravity();
earthPosAngle += State->Getdt()*Inertial->omega(); earthPosAngle += State->Getdt()*Inertial->omega();
// VRP computation
const FGLocation& vLocation = Propagate->GetLocation();
FGColumnVector3 vrpStructural = Aircraft->GetXYZvrp();
FGColumnVector3 vrpBody = MassBalance->StructuralToBody( vrpStructural );
FGColumnVector3 vrpLocal = Propagate->GetTb2l() * vrpBody;
vLocationVRP = vLocation.LocalToLocation( vrpLocal );
// Recompute some derived values now that we know the dependent parameters values ...
hoverbcg = Propagate->GetDistanceAGL() / Aircraft->GetWingSpan();
FGColumnVector3 vMac = Propagate->GetTb2l()*MassBalance->StructuralToBody(Aircraft->GetXYZrp());
hoverbmac = (Propagate->GetDistanceAGL() + vMac(3)) / Aircraft->GetWingSpan();
return false; return false;
} else { } else {
return true; return true;
@ -184,26 +241,24 @@ bool FGAuxiliary::Run()
double FGAuxiliary::GetHeadWind(void) double FGAuxiliary::GetHeadWind(void)
{ {
double psiw,vw,psi; double psiw,vw;
psiw = Atmosphere->GetWindPsi(); psiw = Atmosphere->GetWindPsi();
psi = Rotation->Getpsi();
vw = Atmosphere->GetWindNED().Magnitude(); vw = Atmosphere->GetWindNED().Magnitude();
return vw*cos(psiw - psi); return vw*cos(psiw - Propagate->Getpsi());
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGAuxiliary::GetCrossWind(void) double FGAuxiliary::GetCrossWind(void)
{ {
double psiw,vw,psi; double psiw,vw;
psiw = Atmosphere->GetWindPsi(); psiw = Atmosphere->GetWindPsi();
psi = Rotation->Getpsi();
vw = Atmosphere->GetWindNED().Magnitude(); vw = Atmosphere->GetWindNED().Magnitude();
return vw*sin(psiw - psi); return vw*sin(psiw - Propagate->Getpsi());
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -211,43 +266,53 @@ double FGAuxiliary::GetCrossWind(void)
void FGAuxiliary::bind(void) void FGAuxiliary::bind(void)
{ {
typedef double (FGAuxiliary::*PMF)(int) const; typedef double (FGAuxiliary::*PMF)(int) const;
PropertyManager->Tie("velocities/vc-fps", this, typedef double (FGAuxiliary::*PF)(void) const;
&FGAuxiliary::GetVcalibratedFPS); PropertyManager->Tie("velocities/vc-fps", this, &FGAuxiliary::GetVcalibratedFPS);
PropertyManager->Tie("velocities/vc-kts", this, PropertyManager->Tie("velocities/vc-kts", this, &FGAuxiliary::GetVcalibratedKTS);
&FGAuxiliary::GetVcalibratedKTS); PropertyManager->Tie("velocities/ve-fps", this, &FGAuxiliary::GetVequivalentFPS);
PropertyManager->Tie("velocities/ve-fps", this, PropertyManager->Tie("velocities/ve-kts", this, &FGAuxiliary::GetVequivalentKTS);
&FGAuxiliary::GetVequivalentFPS); PropertyManager->Tie("velocities/machU", this, &FGAuxiliary::GetMachU);
PropertyManager->Tie("velocities/ve-kts", this, PropertyManager->Tie("velocities/tat-r", this, &FGAuxiliary::GetTotalTemperature);
&FGAuxiliary::GetVequivalentKTS); PropertyManager->Tie("velocities/tat-c", this, &FGAuxiliary::GetTAT_C);
PropertyManager->Tie("velocities/machU", this, PropertyManager->Tie("velocities/pt-lbs_sqft", this, &FGAuxiliary::GetTotalPressure);
&FGAuxiliary::GetMachU); PropertyManager->Tie("velocities/p-aero-rad_sec", this, eX, (PMF)&FGAuxiliary::GetAeroPQR);
PropertyManager->Tie("velocities/tat-r", this, PropertyManager->Tie("velocities/q-aero-rad_sec", this, eY, (PMF)&FGAuxiliary::GetAeroPQR);
&FGAuxiliary::GetTotalTemperature); PropertyManager->Tie("velocities/r-aero-rad_sec", this, eZ, (PMF)&FGAuxiliary::GetAeroPQR);
PropertyManager->Tie("velocities/tat-c", this, PropertyManager->Tie("velocities/phidot-rad_sec", this, ePhi, (PMF)&FGAuxiliary::GetEulerRates);
&FGAuxiliary::GetTAT_C); PropertyManager->Tie("velocities/thetadot-rad_sec", this, eTht, (PMF)&FGAuxiliary::GetEulerRates);
PropertyManager->Tie("velocities/pt-lbs_sqft", this, PropertyManager->Tie("velocities/psidot-rad_sec", this, ePsi, (PMF)&FGAuxiliary::GetEulerRates);
&FGAuxiliary::GetTotalPressure); PropertyManager->Tie("velocities/u-aero-fps", this, eU, (PMF)&FGAuxiliary::GetAeroUVW);
PropertyManager->Tie("velocities/v-aero-fps", this, eV, (PMF)&FGAuxiliary::GetAeroUVW);
PropertyManager->Tie("accelerations/a-pilot-x-ft_sec2", this,1, PropertyManager->Tie("velocities/w-aero-fps", this, eW, (PMF)&FGAuxiliary::GetAeroUVW);
(PMF)&FGAuxiliary::GetPilotAccel); PropertyManager->Tie("velocities/vt-fps", this, &FGAuxiliary::GetVt, &FGAuxiliary::SetVt, true);
PropertyManager->Tie("accelerations/a-pilot-y-ft_sec2", this,2, PropertyManager->Tie("velocities/mach-norm", this, &FGAuxiliary::GetMach, &FGAuxiliary::SetMach, true);
(PMF)&FGAuxiliary::GetPilotAccel); PropertyManager->Tie("velocities/vg-fps", this, &FGAuxiliary::GetVground);
PropertyManager->Tie("accelerations/a-pilot-z-ft_sec2", this,3, PropertyManager->Tie("accelerations/a-pilot-x-ft_sec2", this, eX, (PMF)&FGAuxiliary::GetPilotAccel);
(PMF)&FGAuxiliary::GetPilotAccel); PropertyManager->Tie("accelerations/a-pilot-y-ft_sec2", this, eY, (PMF)&FGAuxiliary::GetPilotAccel);
PropertyManager->Tie("accelerations/n-pilot-x-norm", this,1, PropertyManager->Tie("accelerations/a-pilot-z-ft_sec2", this, eZ, (PMF)&FGAuxiliary::GetPilotAccel);
(PMF)&FGAuxiliary::GetNpilot); PropertyManager->Tie("accelerations/n-pilot-x-norm", this, eX, (PMF)&FGAuxiliary::GetNpilot);
PropertyManager->Tie("accelerations/n-pilot-y-norm", this,2, PropertyManager->Tie("accelerations/n-pilot-y-norm", this, eY, (PMF)&FGAuxiliary::GetNpilot);
(PMF)&FGAuxiliary::GetNpilot); PropertyManager->Tie("accelerations/n-pilot-z-norm", this, eZ, (PMF)&FGAuxiliary::GetNpilot);
PropertyManager->Tie("accelerations/n-pilot-z-norm", this,3, PropertyManager->Tie("position/epa-rad", this, &FGAuxiliary::GetEarthPositionAngle);
(PMF)&FGAuxiliary::GetNpilot); /* PropertyManager->Tie("atmosphere/headwind-fps", this, &FGAuxiliary::GetHeadWind, true);
PropertyManager->Tie("position/epa-rad", this, PropertyManager->Tie("atmosphere/crosswind-fps", this, &FGAuxiliary::GetCrossWind, true); */
&FGAuxiliary::GetEarthPositionAngle); PropertyManager->Tie("aero/alpha-rad", this, (PF)&FGAuxiliary::Getalpha, &FGAuxiliary::Setalpha, true);
/* PropertyManager->Tie("atmosphere/headwind-fps", this, PropertyManager->Tie("aero/beta-rad", this, (PF)&FGAuxiliary::Getbeta, &FGAuxiliary::Setbeta, true);
&FGAuxiliary::GetHeadWind, PropertyManager->Tie("aero/mag-beta-rad", this, (PF)&FGAuxiliary::GetMagBeta);
true); PropertyManager->Tie("aero/alpha-deg", this, inDegrees, (PMF)&FGAuxiliary::Getalpha);
PropertyManager->Tie("atmosphere/crosswind-fps", this, PropertyManager->Tie("aero/beta-deg", this, inDegrees, (PMF)&FGAuxiliary::Getbeta);
&FGAuxiliary::GetCrossWind, PropertyManager->Tie("aero/mag-beta-deg", this, inDegrees, (PMF)&FGAuxiliary::GetMagBeta);
true); */ PropertyManager->Tie("aero/qbar-psf", this, &FGAuxiliary::Getqbar, &FGAuxiliary::Setqbar, true);
PropertyManager->Tie("aero/qbarUW-psf", this, &FGAuxiliary::GetqbarUW, &FGAuxiliary::SetqbarUW, true);
PropertyManager->Tie("aero/qbarUV-psf", this, &FGAuxiliary::GetqbarUV, &FGAuxiliary::SetqbarUV, true);
PropertyManager->Tie("aero/alphadot-rad_sec", this, (PF)&FGAuxiliary::Getadot, &FGAuxiliary::Setadot, true);
PropertyManager->Tie("aero/betadot-rad_sec", this, (PF)&FGAuxiliary::Getbdot, &FGAuxiliary::Setbdot, true);
PropertyManager->Tie("aero/alphadot-deg_sec", this, inDegrees, (PMF)&FGAuxiliary::Getadot);
PropertyManager->Tie("aero/betadot-deg_sec", this, inDegrees, (PMF)&FGAuxiliary::Getbdot);
PropertyManager->Tie("aero/h_b-cg-ft", this, &FGAuxiliary::GetHOverBCG);
PropertyManager->Tie("aero/h_b-mac-ft", this, &FGAuxiliary::GetHOverBMAC);
PropertyManager->Tie("flight-path/gamma-rad", this, &FGAuxiliary::GetGamma, &FGAuxiliary::SetGamma);
PropertyManager->Tie("flight-path/psi-gt-rad", this, &FGAuxiliary::GetGroundTrack);
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -261,6 +326,19 @@ void FGAuxiliary::unbind(void)
PropertyManager->Untie("velocities/machU"); PropertyManager->Untie("velocities/machU");
PropertyManager->Untie("velocities/tat-r"); PropertyManager->Untie("velocities/tat-r");
PropertyManager->Untie("velocities/tat-c"); PropertyManager->Untie("velocities/tat-c");
PropertyManager->Untie("velocities/p-aero-rad_sec");
PropertyManager->Untie("velocities/q-aero-rad_sec");
PropertyManager->Untie("velocities/r-aero-rad_sec");
PropertyManager->Untie("velocities/pt-lbs_sqft");
PropertyManager->Untie("velocities/phidot-rad_sec");
PropertyManager->Untie("velocities/thetadot-rad_sec");
PropertyManager->Untie("velocities/psidot-rad_sec");
PropertyManager->Untie("velocities/u-aero-fps");
PropertyManager->Untie("velocities/v-aero-fps");
PropertyManager->Untie("velocities/w-aero-fps");
PropertyManager->Untie("velocities/vt-fps");
PropertyManager->Untie("velocities/mach-norm");
PropertyManager->Untie("velocities/vg-fps");
PropertyManager->Untie("accelerations/a-pilot-x-ft_sec2"); PropertyManager->Untie("accelerations/a-pilot-x-ft_sec2");
PropertyManager->Untie("accelerations/a-pilot-y-ft_sec2"); PropertyManager->Untie("accelerations/a-pilot-y-ft_sec2");
PropertyManager->Untie("accelerations/a-pilot-z-ft_sec2"); PropertyManager->Untie("accelerations/a-pilot-z-ft_sec2");
@ -270,20 +348,23 @@ void FGAuxiliary::unbind(void)
PropertyManager->Untie("position/epa-rad"); PropertyManager->Untie("position/epa-rad");
/* PropertyManager->Untie("atmosphere/headwind-fps"); /* PropertyManager->Untie("atmosphere/headwind-fps");
PropertyManager->Untie("atmosphere/crosswind-fps"); */ PropertyManager->Untie("atmosphere/crosswind-fps"); */
PropertyManager->Untie("aero/qbar-psf");
} PropertyManager->Untie("aero/qbarUW-psf");
PropertyManager->Untie("aero/qbarUV-psf");
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% PropertyManager->Untie("aero/alpha-rad");
PropertyManager->Untie("aero/beta-rad");
void FGAuxiliary::GetState(void) PropertyManager->Untie("aero/alpha-deg");
{ PropertyManager->Untie("aero/beta-deg");
qbar = Translation->Getqbar(); PropertyManager->Untie("aero/alphadot-rad_sec");
mach = Translation->GetMach(); PropertyManager->Untie("aero/betadot-rad_sec");
machU= Translation->GetMachU(); PropertyManager->Untie("aero/mag-beta-rad");
p = Atmosphere->GetPressure(); PropertyManager->Untie("aero/alphadot-deg_sec");
rhosl = Atmosphere->GetDensitySL(); PropertyManager->Untie("aero/betadot-deg_sec");
psl = Atmosphere->GetPressureSL(); PropertyManager->Untie("aero/mag-beta-deg");
sat = Atmosphere->GetTemperature(); PropertyManager->Untie("aero/h_b-cg-ft");
PropertyManager->Untie("aero/h_b-mac-ft");
PropertyManager->Untie("flight-path/gamma-rad");
PropertyManager->Untie("flight-path/psi-gt-rad");
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -323,6 +404,10 @@ void FGAuxiliary::Debug(int from)
if (debug_lvl & 8 ) { // Runtime state variables if (debug_lvl & 8 ) { // Runtime state variables
} }
if (debug_lvl & 16) { // Sanity checking if (debug_lvl & 16) { // Sanity checking
if (Mach > 100 || Mach < 0.00)
cout << "FGPropagate::Mach is out of bounds: " << Mach << endl;
if (qbar > 1e6 || qbar < 0.00)
cout << "FGPropagate::qbar is out of bounds: " << qbar << endl;
} }
if (debug_lvl & 64) { if (debug_lvl & 64) {
if (from == 0) { // Constructor if (from == 0) { // Constructor

View file

@ -1,33 +1,33 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Header: FGAuxiliary.h Header: FGAuxiliary.h
Author: Jon Berndt Author: Jon Berndt
Date started: 01/26/99 Date started: 01/26/99
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------- ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later Foundation; either version 2 of the License, or (at your option) any later
version. version.
This program is distributed in the hope that it will be useful, but WITHOUT This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details. details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA. Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org. the world wide web at http://www.gnu.org.
HISTORY HISTORY
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
11/22/98 JSB Created 11/22/98 JSB Created
1/1/00 TP Added calcs and getters for VTAS, VCAS, VEAS, Vground, in knots 1/1/00 TP Added calcs and getters for VTAS, VCAS, VEAS, Vground, in knots
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
@ -41,6 +41,8 @@ INCLUDES
#include "FGModel.h" #include "FGModel.h"
#include "FGColumnVector3.h" #include "FGColumnVector3.h"
#include "FGLocation.h"
#include "FGPropagate.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS DEFINITIONS
@ -59,6 +61,44 @@ CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Encapsulates various uncategorized scheduled functions. /** Encapsulates various uncategorized scheduled functions.
Pilot sensed accelerations are calculated here. This is used
for the coordinated turn ball instrument. Motion base platforms sometimes
use the derivative of pilot sensed accelerations as the driving parameter,
rather than straight accelerations.
The theory behind pilot-sensed calculations is presented:
For purposes of discussion and calculation, assume for a minute that the
pilot is in space and motionless in inertial space. She will feel
no accelerations. If the aircraft begins to accelerate along any axis or
axes (without rotating), the pilot will sense those accelerations. If
any rotational moment is applied, the pilot will sense an acceleration
due to that motion in the amount:
[wdot X R] + [w X (w X R)]
Term I Term II
where:
wdot = omegadot, the rotational acceleration rate vector
w = omega, the rotational rate vector
R = the vector from the aircraft CG to the pilot eyepoint
The sum total of these two terms plus the acceleration of the aircraft
body axis gives the acceleration the pilot senses in inertial space.
In the presence of a large body such as a planet, a gravity field also
provides an accelerating attraction. This acceleration can be transformed
from the reference frame of the planet so as to be expressed in the frame
of reference of the aircraft. This gravity field accelerating attraction
is felt by the pilot as a force on her tushie as she sits in her aircraft
on the runway awaiting takeoff clearance.
In JSBSim the acceleration of the body frame in inertial space is given
by the F = ma relation. If the vForces vector is divided by the aircraft
mass, the acceleration vector is calculated. The term wdot is equivalent
to the JSBSim vPQRdot vector, and the w parameter is equivalent to vPQR.
The radius R is calculated below in the vector vToEyePt.
@author Tony Peden, Jon Berndt @author Tony Peden, Jon Berndt
@version $Id$ @version $Id$
*/ */
@ -72,6 +112,7 @@ public:
/** Constructor /** Constructor
@param Executive a pointer to the parent executive object */ @param Executive a pointer to the parent executive object */
FGAuxiliary(FGFDMExec* Executive); FGAuxiliary(FGFDMExec* Executive);
/// Destructor /// Destructor
~FGAuxiliary(); ~FGAuxiliary();
@ -79,49 +120,122 @@ public:
@return false if no error */ @return false if no error */
bool Run(void); bool Run(void);
// Use FGInitialCondition to set these speeds // GET functions
inline double GetVcalibratedFPS(void) const { return vcas; }
inline double GetVcalibratedKTS(void) const { return vcas*fpstokts; } // Atmospheric parameters GET functions
inline double GetVequivalentFPS(void) const { return veas; } double GetVcalibratedFPS(void) const { return vcas; }
inline double GetVequivalentKTS(void) const { return veas*fpstokts; } double GetVcalibratedKTS(void) const { return vcas*fpstokts; }
inline double GetMachU(void) const { return machU; } double GetVequivalentFPS(void) const { return veas; }
double GetVequivalentKTS(void) const { return veas*fpstokts; }
inline double GetTotalTemperature(void) const { return tat; }
inline double GetTAT_C(void) const { return tatc; }
// total pressure above is freestream total pressure for subsonic only // total pressure above is freestream total pressure for subsonic only
// for supersonic it is the 1D total pressure behind a normal shock // for supersonic it is the 1D total pressure behind a normal shock
inline double GetTotalPressure(void) const { return pt; } double GetTotalPressure(void) const { return pt; }
double GetTotalTemperature(void) const { return tat; }
inline FGColumnVector3& GetPilotAccel(void) { return vPilotAccel; } double GetTAT_C(void) const { return tatc; }
inline double GetPilotAccel(int idx) const { return vPilotAccel(idx); }
FGColumnVector3 GetNpilot(void) const { return vPilotAccelN; } double GetPilotAccel(int idx) const { return vPilotAccel(idx); }
double GetNpilot(int idx) const { return vPilotAccelN(idx); } double GetNpilot(int idx) const { return vPilotAccelN(idx); }
double GetAeroPQR(int axis) const { return vAeroPQR(axis); }
double GetEulerRates(int axis) const { return vEulerRates(axis); }
const FGColumnVector3& GetPilotAccel (void) const { return vPilotAccel; }
const FGColumnVector3& GetNpilot (void) const { return vPilotAccelN; }
const FGColumnVector3& GetAeroPQR (void) const { return vAeroPQR; }
const FGColumnVector3& GetEulerRates (void) const { return vEulerRates; }
const FGColumnVector3& GetAeroUVW (void) const { return vAeroUVW; }
const FGLocation& GetLocationVRP(void) const { return vLocationVRP; }
double GethVRP(void) const { return vLocationVRP.GetRadius() - Propagate->GetSeaLevelRadius(); }
double GetAeroUVW (int idx) const { return vAeroUVW(idx); }
double Getalpha (void) const { return alpha; }
double Getbeta (void) const { return beta; }
double Getadot (void) const { return adot; }
double Getbdot (void) const { return bdot; }
double GetMagBeta (void) const { return fabs(beta); }
double Getalpha (int unit) const { if (unit == inDegrees) return alpha*radtodeg;
else cerr << "Bad units" << endl; return 0.0;}
double Getbeta (int unit) const { if (unit == inDegrees) return beta*radtodeg;
else cerr << "Bad units" << endl; return 0.0;}
double Getadot (int unit) const { if (unit == inDegrees) return adot*radtodeg;
else cerr << "Bad units" << endl; return 0.0;}
double Getbdot (int unit) const { if (unit == inDegrees) return bdot*radtodeg;
else cerr << "Bad units" << endl; return 0.0;}
double GetMagBeta (int unit) const { if (unit == inDegrees) return fabs(beta)*radtodeg;
else cerr << "Bad units" << endl; return 0.0;}
double Getqbar (void) const { return qbar; }
double GetqbarUW (void) const { return qbarUW; }
double GetqbarUV (void) const { return qbarUV; }
double GetVt (void) const { return Vt; }
double GetVground (void) const { return Vground; }
double GetMach (void) const { return Mach; }
double GetMachU (void) const { return MachU; }
double GetHOverBCG(void) const { return hoverbcg; }
double GetHOverBMAC(void) const { return hoverbmac; }
double GetGamma(void) const { return gamma; }
double GetGroundTrack(void) const { return psigt; }
double GetEarthPositionAngle(void) const { return earthPosAngle; }
inline double GetEarthPositionAngle(void) const { return earthPosAngle; }
double GetHeadWind(void); double GetHeadWind(void);
double GetCrossWind(void); double GetCrossWind(void);
// SET functions
void SetAeroUVW(FGColumnVector3 tt) { vAeroUVW = tt; }
void Setalpha (double tt) { alpha = tt; }
void Setbeta (double tt) { beta = tt; }
void Setqbar (double tt) { qbar = tt; }
void SetqbarUW (double tt) { qbarUW = tt; }
void SetqbarUV (double tt) { qbarUV = tt; }
void SetVt (double tt) { Vt = tt; }
void SetMach (double tt) { Mach=tt; }
void Setadot (double tt) { adot = tt; }
void Setbdot (double tt) { bdot = tt; }
void SetAB (double t1, double t2) { alpha=t1; beta=t2; }
void SetGamma (double tt) { gamma = tt; }
// Time routines, SET and GET functions
void SetDayOfYear (int doy) { day_of_year = doy; }
void SetSecondsInDay (double sid) { seconds_in_day = sid; }
int GetDayOfYear (void) const { return day_of_year; }
double GetSecondsInDay (void) const { return seconds_in_day; }
void bind(void); void bind(void);
void unbind(void); void unbind(void);
private: private:
double vcas; double vcas, veas;
double veas; double rhosl, rho, p, psl, pt, tat, sat, tatc; // Don't add a getter for pt!
double mach;
double machU;
double qbar,rhosl,rho,p,psl,pt,tat,sat,tatc;
// Don't add a getter for pt!
FGColumnVector3 vPilotAccel; FGColumnVector3 vPilotAccel;
FGColumnVector3 vPilotAccelN; FGColumnVector3 vPilotAccelN;
FGColumnVector3 vToEyePt; FGColumnVector3 vToEyePt;
FGColumnVector3 vAeroPQR;
double earthPosAngle; FGColumnVector3 vAeroUVW;
FGColumnVector3 vEuler;
FGColumnVector3 vEulerRates;
FGColumnVector3 vMachUVW;
FGLocation vLocationVRP;
double Vt, Vground, Mach, MachU;
double qbar, qbarUW, qbarUV;
double alpha, beta;
double adot,bdot;
double psigt, gamma;
double seconds_in_day; // seconds since current GMT day began
int day_of_year; // GMT day, 1 .. 366
double earthPosAngle;
double hoverbcg, hoverbmac;
void GetState(void);
void Debug(int from); void Debug(int from);
}; };
@ -129,4 +243,3 @@ private:
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif #endif

View file

@ -75,13 +75,13 @@ FGCoefficient::FGCoefficient( FGFDMExec* fdex )
FDMExec = fdex; FDMExec = fdex;
State = FDMExec->GetState(); State = FDMExec->GetState();
Table = 0; Table = 0;
PropertyManager = FDMExec->GetPropertyManager(); PropertyManager = FDMExec->GetPropertyManager();
Table = (FGTable*)0L; Table = (FGTable*)0L;
LookupR = LookupC = 0; LookupR = LookupC = 0;
numInstances = 0; numInstances = 0;
rows = columns = 0; rows = columns = tables = 0;
StaticValue = 0.0; StaticValue = 0.0;
totalValue = 0.0; totalValue = 0.0;
@ -122,31 +122,37 @@ bool FGCoefficient::Load(FGConfigFile *AC_cfg)
*AC_cfg >> description; *AC_cfg >> description;
if (method == "EQUATION") type = EQUATION; if (method == "EQUATION") type = EQUATION;
else if (method == "TABLE") type = TABLE; else if (method == "TABLE") type = TABLE;
else if (method == "TABLE3D") type = TABLE3D;
else if (method == "VECTOR") type = VECTOR; else if (method == "VECTOR") type = VECTOR;
else if (method == "VALUE") type = VALUE; else if (method == "VALUE") type = VALUE;
else type = UNKNOWN; else type = UNKNOWN;
if (type == VECTOR || type == TABLE) { if (type == VECTOR || type == TABLE || type == TABLE3D) {
*AC_cfg >> rows;
if (type == TABLE) { if (type == TABLE3D) {
*AC_cfg >> columns; *AC_cfg >> rows >> columns >> tables;
Table = new FGTable(rows, columns, tables);
*AC_cfg >> multparmsRow >> multparmsCol >> multparmsTable;
LookupR = PropertyManager->GetNode( multparmsRow );
LookupC = PropertyManager->GetNode( multparmsCol );
LookupT = PropertyManager->GetNode( multparmsTable );
} else if (type == TABLE) {
*AC_cfg >> rows >> columns;
Table = new FGTable(rows, columns); Table = new FGTable(rows, columns);
*AC_cfg >> multparmsRow >> multparmsCol;
LookupR = PropertyManager->GetNode( multparmsRow );
LookupC = PropertyManager->GetNode( multparmsCol );
} else { } else {
*AC_cfg >> rows;
Table = new FGTable(rows); Table = new FGTable(rows);
*AC_cfg >> multparmsRow;
LookupR = PropertyManager->GetNode( multparmsRow );
} }
*AC_cfg >> multparmsRow;
LookupR = PropertyManager->GetNode( multparmsRow );
} }
if (type == TABLE) { // Here, read in the line of the form:
*AC_cfg >> multparmsCol; // {property1} | {property2} | {property3}
// where each non-dimensionalizing property for this coefficient is
LookupC = PropertyManager->GetNode( multparmsCol );
}
// Here, read in the line of the form (e.g.) FG_MACH|FG_QBAR|FG_ALPHA
// where each non-dimensionalizing parameter for this coefficient is
// separated by a | character // separated by a | character
string line=AC_cfg->GetCurrentLine(); string line=AC_cfg->GetCurrentLine();
@ -157,11 +163,11 @@ bool FGCoefficient::Load(FGConfigFile *AC_cfg)
tmp[j]=line[i]; tmp[j]=line[i];
j++; j++;
} }
} }
tmp[j]='\0'; multparms=tmp; tmp[j]='\0'; multparms=tmp;
end = multparms.length(); end = multparms.length();
n = multparms.find("|"); n = multparms.find("|");
start = 0; start = 0;
if (multparms != string("none")) { if (multparms != string("none")) {
while (n < end && n >= 0) { while (n < end && n >= 0) {
@ -176,9 +182,10 @@ bool FGCoefficient::Load(FGConfigFile *AC_cfg)
// End of non-dimensionalizing parameter read-in // End of non-dimensionalizing parameter read-in
} }
AC_cfg->GetNextConfigLine(); AC_cfg->GetNextConfigLine();
if (type == VALUE) { if (type == VALUE) {
*AC_cfg >> StaticValue; *AC_cfg >> StaticValue;
} else if (type == VECTOR || type == TABLE) { } else if (type == VECTOR || type == TABLE || type == TABLE3D) {
*Table << *AC_cfg; *Table << *AC_cfg;
} else { } else {
cerr << "Unimplemented coefficient type: " << type << endl; cerr << "Unimplemented coefficient type: " << type << endl;
@ -190,11 +197,26 @@ bool FGCoefficient::Load(FGConfigFile *AC_cfg)
return true; return true;
} else { } else {
return false; return false;
} }
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGCoefficient::Value(double rVal, double cVal, double tVal)
{
double Value;
unsigned int midx;
SD = Value = gain*Table->GetValue(rVal, cVal, tVal) + bias;
for (midx=0; midx < multipliers.size(); midx++) {
Value *= multipliers[midx]->getDoubleValue();
}
return Value;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGCoefficient::Value(double rVal, double cVal) double FGCoefficient::Value(double rVal, double cVal)
@ -215,12 +237,12 @@ double FGCoefficient::Value(double rVal, double cVal)
double FGCoefficient::Value(double Val) double FGCoefficient::Value(double Val)
{ {
double Value; double Value;
SD = Value = gain*Table->GetValue(Val) + bias; SD = Value = gain*Table->GetValue(Val) + bias;
for (unsigned int midx=0; midx < multipliers.size(); midx++) for (unsigned int midx=0; midx < multipliers.size(); midx++)
Value *= multipliers[midx]->getDoubleValue(); Value *= multipliers[midx]->getDoubleValue();
return Value; return Value;
} }
@ -228,7 +250,7 @@ double FGCoefficient::Value(double Val)
double FGCoefficient::Value(void) double FGCoefficient::Value(void)
{ {
double Value; double Value;
SD = Value = gain*StaticValue + bias; SD = Value = gain*StaticValue + bias;
@ -258,7 +280,13 @@ double FGCoefficient::TotalValue(void)
case TABLE: case TABLE:
totalValue = Value( LookupR->getDoubleValue(), totalValue = Value( LookupR->getDoubleValue(),
LookupC->getDoubleValue() ); LookupC->getDoubleValue() );
break;
case TABLE3D:
totalValue = Value( LookupR->getDoubleValue(),
LookupC->getDoubleValue(),
LookupT->getDoubleValue() );
break; break;
case EQUATION: case EQUATION:
@ -279,7 +307,7 @@ void FGCoefficient::DisplayCoeffFactors(void)
if (multipliers.size() == 0) { if (multipliers.size() == 0) {
cout << "none" << endl; cout << "none" << endl;
} else { } else {
for (i=0; i<multipliers.size(); i++) for (i=0; i<multipliers.size(); i++)
cout << multipliers[i]->getName() << " "; cout << multipliers[i]->getName() << " ";
} }
cout << endl; cout << endl;
@ -289,7 +317,7 @@ void FGCoefficient::DisplayCoeffFactors(void)
string FGCoefficient::GetSDstring(void) string FGCoefficient::GetSDstring(void)
{ {
char buffer[16]; char buffer[20];
string value; string value;
sprintf(buffer,"%9.6f",SD); sprintf(buffer,"%9.6f",SD);
@ -303,29 +331,29 @@ void FGCoefficient::bind(FGPropertyManager *parent)
{ {
string mult; string mult;
unsigned i; unsigned i;
node = parent->GetNode(name,true); node = parent->GetNode(name,true);
node->SetString("description",description); node->SetString("description",description);
if (LookupR) node->SetString("row-parm",LookupR->getName() ); if (LookupR) node->SetString("row-parm",LookupR->getName() );
if (LookupC) node->SetString("column-parm",LookupC->getName() ); if (LookupC) node->SetString("column-parm",LookupC->getName() );
mult=""; mult="";
if (multipliers.size() == 0) if (multipliers.size() == 0)
mult="none"; mult="none";
for (i=0; i<multipliers.size(); i++) { for (i=0; i<multipliers.size(); i++) {
mult += multipliers[i]->getName(); mult += multipliers[i]->getName();
if ( i < multipliers.size()-1 ) mult += " "; if ( i < multipliers.size()-1 ) mult += " ";
} }
node->SetString("multipliers",mult); node->SetString("multipliers",mult);
node->Tie("SD-norm",this,&FGCoefficient::GetSD ); node->Tie("SD-norm",this,&FGCoefficient::GetSD );
node->Tie("value-lbs",this,&FGCoefficient::GetValue ); node->Tie("value-lbs",this,&FGCoefficient::GetValue );
node->Tie("bias", this, &FGCoefficient::getBias, node->Tie("bias", this, &FGCoefficient::getBias,
&FGCoefficient::setBias ); &FGCoefficient::setBias );
node->Tie("gain", this, &FGCoefficient::getGain, node->Tie("gain", this, &FGCoefficient::getGain,
&FGCoefficient::setGain ); &FGCoefficient::setGain );
@ -336,8 +364,8 @@ void FGCoefficient::bind(FGPropertyManager *parent)
void FGCoefficient::unbind(void) void FGCoefficient::unbind(void)
{ {
node->Untie("SD-norm"); node->Untie("SD-norm");
node->Untie("value-lbs"); node->Untie("value-lbs");
node->Untie("bias"); node->Untie("bias");
node->Untie("gain"); node->Untie("gain");
} }
@ -351,8 +379,8 @@ FGPropertyManager* FGCoefficient::resolveSymbol(string name)
if ( !tmpn ) { if ( !tmpn ) {
cerr << "Coefficient multipliers cannot create properties, check spelling?" << endl; cerr << "Coefficient multipliers cannot create properties, check spelling?" << endl;
exit(1); exit(1);
} }
return tmpn; return tmpn;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -379,28 +407,23 @@ void FGCoefficient::Debug(int from)
if (debug_lvl <= 0) return; if (debug_lvl <= 0) return;
if (debug_lvl & 1) { // Standard console startup message output if (debug_lvl & 1) { // Standard console startup message output
if (from == 2) { // Loading if (from == 2) { // Loading
cout << "\n " << highint << underon << name << underoff << normint << endl; cout << "\n " << highint << underon << name << underoff << normint << endl;
cout << " " << description << endl; cout << " " << description << endl;
cout << " " << method << endl; cout << " " << method << endl;
if (type == VECTOR || type == TABLE) { if (type == VECTOR || type == TABLE || type == TABLE3D) {
cout << " Rows: " << rows << " "; cout << " Rows: " << rows << " indexed by: " << LookupR->getName() << endl;
if (type == TABLE) { if (type == TABLE || type == TABLE3D) {
cout << "Cols: " << columns; cout << " Cols: " << columns << " indexed by: " << LookupC->getName() << endl;
if (type == TABLE3D) {
cout << " Tables: " << tables << " indexed by: " << LookupT->getName() << endl;
}
} }
cout << endl << " Row indexing parameter: " << LookupR->getName() << endl;
}
if (type == TABLE) {
cout << " Column indexing parameter: " << LookupC->getName() << endl;
}
if (type == VALUE) {
cout << " Value = " << StaticValue << endl;
} else if (type == VECTOR || type == TABLE) {
Table->Print(); Table->Print();
} else if (type == VALUE) {
cout << " Value = " << StaticValue << endl;
} }
DisplayCoeffFactors(); DisplayCoeffFactors();

View file

@ -68,9 +68,7 @@ class FGState;
class FGAtmosphere; class FGAtmosphere;
class FGFCS; class FGFCS;
class FGAircraft; class FGAircraft;
class FGTranslation; class FGPropagate;
class FGRotation;
class FGPosition;
class FGAuxiliary; class FGAuxiliary;
class FGOutput; class FGOutput;
@ -99,19 +97,19 @@ public:
FGCoefficient(FGFDMExec* exec); FGCoefficient(FGFDMExec* exec);
/// Destructor. /// Destructor.
virtual ~FGCoefficient(); virtual ~FGCoefficient();
/** Loads the stability derivative/aero coefficient data from the config file /** Loads the stability derivative/aero coefficient data from the config file
as directed by the FGAerodynamics instance. as directed by the FGAerodynamics instance.
@param AC_cfg a pointer to the current config file instance. */ @param AC_cfg a pointer to the current config file instance. */
virtual bool Load(FGConfigFile* AC_cfg); virtual bool Load(FGConfigFile* AC_cfg);
typedef vector <FGPropertyManager*> MultVec; typedef vector <FGPropertyManager*> MultVec;
enum Type {UNKNOWN, VALUE, VECTOR, TABLE, EQUATION}; enum Type {UNKNOWN, VALUE, VECTOR, TABLE, TABLE3D, EQUATION};
/** Returns the value for this coefficient. /** Returns the value for this coefficient.
Each instance of FGCoefficient stores a value for the "type" of coefficient Each instance of FGCoefficient stores a value for the "type" of coefficient
it is, one of: VALUE, VECTOR, TABLE, or EQUATION. This TotalValue function it is, one of: VALUE, VECTOR, TABLE, or EQUATION. This TotalValue function
is called when the value for a coefficient needs to be known. When it is called, is called when the value for a coefficient needs to be known. When it is called,
depending on what type of coefficient is represented by the FGCoefficient depending on what type of coefficient is represented by the FGCoefficient
instance, TotalValue() directs the appropriate Value() function to be called. instance, TotalValue() directs the appropriate Value() function to be called.
@ -149,7 +147,7 @@ public:
inline void setGain(double g) { gain=g; }; inline void setGain(double g) { gain=g; };
inline double getBias(void) const { return bias; } inline double getBias(void) const { return bias; }
inline double getGain(void) const { return gain; } inline double getGain(void) const { return gain; }
virtual void bind(FGPropertyManager *parent); virtual void bind(FGPropertyManager *parent);
virtual void unbind(void); virtual void unbind(void);
@ -165,18 +163,20 @@ private:
string multparms; string multparms;
string multparmsRow; string multparmsRow;
string multparmsCol; string multparmsCol;
string multparmsTable;
double Value(double, double, double);
double Value(double, double); double Value(double, double);
double Value(double); double Value(double);
double Value(void); double Value(void);
double StaticValue; double StaticValue;
double totalValue; double totalValue;
double bias,gain; double bias,gain;
FGPropertyManager *LookupR, *LookupC; FGPropertyManager *LookupR, *LookupC, *LookupT;
FGPropertyManager *node; // must be private!! FGPropertyManager *node; // must be private!!
MultVec multipliers; MultVec multipliers;
int rows, columns; int rows, columns, tables;
Type type; Type type;
double SD; // Actual stability derivative (or other coefficient) value double SD; // Actual stability derivative (or other coefficient) value
FGTable *Table; FGTable *Table;
@ -185,13 +185,11 @@ private:
FGAtmosphere* Atmosphere; FGAtmosphere* Atmosphere;
FGFCS* FCS; FGFCS* FCS;
FGAircraft* Aircraft; FGAircraft* Aircraft;
FGTranslation* Translation; FGPropagate* Propagate;
FGRotation* Rotation;
FGPosition* Position;
FGAuxiliary* Auxiliary; FGAuxiliary* Auxiliary;
FGOutput* Output; FGOutput* Output;
FGPropertyManager* PropertyManager; FGPropertyManager* PropertyManager;
FGPropertyManager* resolveSymbol(string name); FGPropertyManager* resolveSymbol(string name);
virtual void Debug(int from); virtual void Debug(int from);

View file

@ -66,7 +66,7 @@ FGColumnVector3& FGColumnVector3::operator/=(const double scalar)
double FGColumnVector3::Magnitude(void) const double FGColumnVector3::Magnitude(void) const
{ {
if (data[1] == 0.0 && data[2] == 0.0 && data[3] == 0.0) if (Entry(1) == 0.0 && Entry(2) == 0.0 && Entry(3) == 0.0)
return 0.0; return 0.0;
else else
return sqrt( Entry(1)*Entry(1) + Entry(2)*Entry(2) + Entry(3)*Entry(3) ); return sqrt( Entry(1)*Entry(1) + Entry(2)*Entry(2) + Entry(3)*Entry(3) );

View file

@ -95,11 +95,11 @@ public:
FGColumnVector3(void); FGColumnVector3(void);
/** Initialization by given values. /** Initialization by given values.
@param X value of the x-conponent. @param X value of the x-conponent.
@param Y value of the y-conponent. @param Y value of the y-conponent.
@param Z value of the z-conponent. @param Z value of the z-conponent.
Create a vector from the doubles given in the arguments. Create a vector from the doubles given in the arguments.
*/ */
FGColumnVector3(double X, double Y, double Z) { FGColumnVector3(double X, double Y, double Z) {
@ -110,9 +110,9 @@ public:
} }
/** Copy constructor. /** Copy constructor.
@param v Vector which is used for initialization. @param v Vector which is used for initialization.
Create copy of the vector given in the argument. Create copy of the vector given in the argument.
*/ */
FGColumnVector3(const FGColumnVector3& v) { FGColumnVector3(const FGColumnVector3& v) {
@ -128,61 +128,61 @@ public:
/** Read access the entries of the vector. /** Read access the entries of the vector.
@param idx the component index. @param idx the component index.
Return the value of the matrix entry at the given index. Return the value of the matrix entry at the given index.
Indices are counted starting with 1. Indices are counted starting with 1.
Note that the index given in the argument is unchecked. Note that the index given in the argument is unchecked.
*/ */
double operator()(unsigned int idx) const { return Entry(idx); } double operator()(unsigned int idx) const { return Entry(idx); }
/** Write access the entries of the vector. /** Write access the entries of the vector.
@param idx the component index. @param idx the component index.
Return a reference to the vector entry at the given index. Return a reference to the vector entry at the given index.
Indices are counted starting with 1. Indices are counted starting with 1.
Note that the index given in the argument is unchecked. Note that the index given in the argument is unchecked.
*/ */
double& operator()(unsigned int idx) { return Entry(idx); } double& operator()(unsigned int idx) { return Entry(idx); }
/** Read access the entries of the vector. /** Read access the entries of the vector.
@param idx the component index. @param idx the component index.
Return the value of the matrix entry at the given index. Return the value of the matrix entry at the given index.
Indices are counted starting with 1. Indices are counted starting with 1.
This function is just a shortcut for the @ref double This function is just a shortcut for the @ref double
operator()(unsigned int idx) const function. It is operator()(unsigned int idx) const function. It is
used internally to access the elements in a more convenient way. used internally to access the elements in a more convenient way.
Note that the index given in the argument is unchecked. Note that the index given in the argument is unchecked.
*/ */
double Entry(unsigned int idx) const { return data[idx-1]; } double Entry(unsigned int idx) const { return data[idx-1]; }
/** Write access the entries of the vector. /** Write access the entries of the vector.
@param idx the component index. @param idx the component index.
Return a reference to the vector entry at the given index. Return a reference to the vector entry at the given index.
Indices are counted starting with 1. Indices are counted starting with 1.
This function is just a shortcut for the @ref double& This function is just a shortcut for the @ref double&
operator()(unsigned int idx) function. It is operator()(unsigned int idx) function. It is
used internally to access the elements in a more convenient way. used internally to access the elements in a more convenient way.
Note that the index given in the argument is unchecked. Note that the index given in the argument is unchecked.
*/ */
double& Entry(unsigned int idx) { return data[idx-1]; } double& Entry(unsigned int idx) { return data[idx-1]; }
/** Assignment operator. /** Assignment operator.
@param b source vector. @param b source vector.
Copy the content of the vector given in the argument into *this. Copy the content of the vector given in the argument into *this.
*/ */
FGColumnVector3& operator=(const FGColumnVector3& b) { FGColumnVector3& operator=(const FGColumnVector3& b) {
@ -192,11 +192,29 @@ public:
return *this; return *this;
} }
/** Comparison operator.
@param b other vector.
Returns true if both vectors are exactly the same.
*/
bool operator==(const FGColumnVector3& b) const {
return data[0] == b.data[0] && data[1] == b.data[1] && data[2] == b.data[2];
}
/** Comparison operator.
@param b other vector.
Returns false if both vectors are exactly the same.
*/
bool operator!=(const FGColumnVector3& b) const { return ! operator==(b); }
/** Multiplication by a scalar. /** Multiplication by a scalar.
@param scalar scalar value to multiply the vector with. @param scalar scalar value to multiply the vector with.
@return The resulting vector from the multiplication with that scalar. @return The resulting vector from the multiplication with that scalar.
Multiply the vector with the scalar given in the argument. Multiply the vector with the scalar given in the argument.
*/ */
FGColumnVector3 operator*(const double scalar) const { FGColumnVector3 operator*(const double scalar) const {
@ -204,19 +222,19 @@ public:
} }
/** Multiply by 1/scalar. /** Multiply by 1/scalar.
@param scalar scalar value to devide the vector through. @param scalar scalar value to devide the vector through.
@return The resulting vector from the division through that scalar. @return The resulting vector from the division through that scalar.
Multiply the vector with the 1/scalar given in the argument. Multiply the vector with the 1/scalar given in the argument.
*/ */
FGColumnVector3 operator/(const double scalar) const; FGColumnVector3 operator/(const double scalar) const;
/** Cross product multiplication. /** Cross product multiplication.
@param v vector to multiply with. @param v vector to multiply with.
@return The resulting vector from the cross product multiplication. @return The resulting vector from the cross product multiplication.
Compute and return the cross product of the current vector with Compute and return the cross product of the current vector with
the given argument. the given argument.
*/ */
@ -276,13 +294,13 @@ public:
} }
/** Length of the vector. /** Length of the vector.
Compute and return the euclidean norm of this vector. Compute and return the euclidean norm of this vector.
*/ */
double Magnitude(void) const; double Magnitude(void) const;
/** Normialze. /** Normalize.
Normalize the vector to have the Magnitude() == 1.0. If the vector Normalize the vector to have the Magnitude() == 1.0. If the vector
is equal to zero it is left untouched. is equal to zero it is left untouched.
*/ */

View file

@ -1,317 +0,0 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Module: FGMatrix33.cpp
Author: Originally by Tony Peden [formatted here (and broken??) by JSB]
Date started: 1998
Purpose: FGMatrix33 class
Called by: Various
FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------
HISTORY
--------------------------------------------------------------------------------
??/??/?? TP Created
03/16/2000 JSB Added exception throwing
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGColumnVector4.h"
namespace JSBSim {
static const char *IdSrc = "$Id$";
static const char *IdHdr = ID_COLUMNVECTOR4;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
FGColumnVector4::FGColumnVector4(void)
{
rowCtr = 1;
data[1]=0;data[2]=0;data[3]=0;data[4]=0;
Debug(0);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGColumnVector4::FGColumnVector4(double A, double B, double C, double D)
{
rowCtr = 1;
data[1]=A;
data[2]=B;
data[3]=C;
data[4]=D;
Debug(0);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGColumnVector4::~FGColumnVector4(void)
{
Debug(1);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGColumnVector4::FGColumnVector4(const FGColumnVector4& b)
{
data[1] = b.data[1];
data[2] = b.data[2];
data[3] = b.data[3];
data[4] = b.data[4];
rowCtr = 1;
Debug(0);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGColumnVector4 FGColumnVector4::operator=(const FGColumnVector4& b)
{
data[1] = b.data[1];
data[2] = b.data[2];
data[3] = b.data[3];
data[4] = b.data[4];
rowCtr = 1;
return *this;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGColumnVector4 FGColumnVector4::operator+(const FGColumnVector4& C)
{
FGColumnVector4 Sum;
Sum(1) = C(1) + data[1];
Sum(2) = C(2) + data[2];
Sum(3) = C(3) + data[3];
Sum(4) = C(4) + data[4];
return Sum;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGColumnVector4::operator+=(const FGColumnVector4& C)
{
data[1] += C(1);
data[2] += C(2);
data[3] += C(3);
data[4] += C(4);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGColumnVector4 FGColumnVector4::operator*(const double scalar)
{
FGColumnVector4 Product;
Product(1) = scalar * data[1];
Product(2) = scalar * data[2];
Product(3) = scalar * data[3];
Product(4) = scalar * data[4];
return Product;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGColumnVector4::operator*=(const double scalar)
{
data[1] *= scalar;
data[2] *= scalar;
data[3] *= scalar;
data[4] *= scalar;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGColumnVector4 FGColumnVector4::operator-(const FGColumnVector4& V)
{
FGColumnVector4 Diff;
Diff(1) = data[1] - V(1);
Diff(2) = data[2] - V(2);
Diff(3) = data[3] - V(3);
Diff(4) = data[4] - V(4);
return Diff;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGColumnVector4::operator-=(const FGColumnVector4& V)
{
data[1] -= V(1);
data[2] -= V(2);
data[3] -= V(3);
data[4] -= V(4);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGColumnVector4 FGColumnVector4::operator/(const double scalar)
{
FGColumnVector4 Quotient;
if (scalar != 0) {
double tmp = 1.0/scalar;
Quotient(1) = data[1] * tmp;
Quotient(2) = data[2] * tmp;
Quotient(3) = data[3] * tmp;
Quotient(4) = data[4] * tmp;
} else {
cerr << "Attempt to divide by zero in method FGColumnVector4::operator/(const double scalar), object " << this << endl;
}
return Quotient;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGColumnVector4::operator/=(const double scalar)
{
FGColumnVector4 Quotient;
if (scalar != 0) {
double tmp = 1.0/scalar;
data[1] *= tmp;
data[2] *= tmp;
data[3] *= tmp;
data[4] *= tmp;
} else {
cerr << "Attempt to divide by zero in method FGColumnVector4::operator/=(const double scalar), object " << this << endl;
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGColumnVector4 operator*(const double scalar, const FGColumnVector4& C)
{
FGColumnVector4 Product;
Product(1) = scalar * C(1);
Product(2) = scalar * C(2);
Product(3) = scalar * C(3);
Product(4) = scalar * C(4);
return Product;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGColumnVector4::Magnitude(void)
{
double num;
if ((data[1] == 0.00) &&
(data[2] == 0.00) &&
(data[3] == 0.00) &&
(data[4] == 0.00))
{
return 0.00;
} else {
num = data[1]*data[1];
num += data[2]*data[2];
num += data[3]*data[3];
num += data[4]*data[4];
return sqrt(num);
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGColumnVector4 FGColumnVector4::Normalize(void)
{
double Mag = Magnitude();
if (Mag != 0) {
Mag = 1.0/Mag;
data[1] *= Mag;
data[2] *= Mag;
data[3] *= Mag;
data[4] *= Mag;
}
return *this;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGColumnVector4 FGColumnVector4::multElementWise(const FGColumnVector4& V)
{
FGColumnVector4 Product;
Product(1) = data[1] * V(1);
Product(2) = data[2] * V(2);
Product(3) = data[3] * V(3);
Product(4) = data[4] * V(4);
return Product;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
ostream& operator<<(ostream& os, FGColumnVector4& col)
{
os << col(1) << " , " << col(2) << " , " << col(3) << " , " << col(4);
return os;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGColumnVector4& FGColumnVector4::operator<<(const double ff)
{
data[rowCtr] = ff;
if (++rowCtr > 4) rowCtr = 1;
return *this;
}
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
// out the normally expected messages, essentially echoing
// the config files as they are read. If the environment
// variable is not set, debug_lvl is set to 1 internally
// 0: This requests JSBSim not to output any messages
// whatsoever.
// 1: This value explicity requests the normal JSBSim
// startup messages
// 2: This value asks for a message to be printed out when
// a class is instantiated
// 4: When this value is set, a message is displayed when a
// FGModel object executes its Run() method
// 8: When this value is set, various runtime state variables
// are printed out periodically
// 16: When set various parameters are sanity checked and
// a message is printed out when they go out of bounds
void FGColumnVector4::Debug(int from)
{
if (debug_lvl <= 0) return;
if (debug_lvl & 1) { // Standard console startup message output
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
if (from == 0) cout << "Instantiated: FGColumnVector4" << endl;
if (from == 1) cout << "Destroyed: FGColumnVector4" << endl;
}
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
}
if (debug_lvl & 8 ) { // Runtime state variables
}
if (debug_lvl & 16) { // Sanity checking
}
if (debug_lvl & 64) { // Sanity checking
if (from == 0) { // Constructor
cout << IdSrc << endl;
cout << IdHdr << endl;
}
}
}
}

View file

@ -1,132 +0,0 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Header: FGColumnVector4.h
Author: Originally by Tony Peden [formatted and adapted here by Jon Berndt]
Date started: Unknown
HISTORY
--------------------------------------------------------------------------------
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifndef FGCOLUMNVECTOR4_H
#define FGCOLUMNVECTOR4_H
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include <stdlib.h>
#ifdef FGFS
# include <math.h>
# include <simgear/compiler.h>
# include STL_STRING
# include STL_FSTREAM
# include STL_IOSTREAM
SG_USING_STD(string);
SG_USING_STD(ostream);
SG_USING_STD(istream);
SG_USING_STD(cerr);
SG_USING_STD(cout);
SG_USING_STD(endl);
// SG_USING_STD(sqrt);
#else
# include <string>
# if defined (sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
# include <fstream.h>
# include <iostream.h>
# include <math.h>
# else
# include <fstream>
# if defined (sgi) && !defined(__GNUC__)
# include <math.h>
# else
# include <cmath>
# endif
# include <iostream>
using std::ostream;
using std::istream;
using std::cerr;
using std::cout;
using std::endl;
using std::sqrt;
# endif
using std::string;
#endif
#include "FGJSBBase.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_COLUMNVECTOR4 "$Id$"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
namespace JSBSim {
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** This class implements a 4 dimensional vector.
@author Jon S. Berndt, Tony Peden, et. al.
@version $Id$
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGColumnVector4 : public FGJSBBase
{
public:
FGColumnVector4(void);
FGColumnVector4(double A, double B, double C, double D);
FGColumnVector4(const FGColumnVector4& b);
~FGColumnVector4(void);
FGColumnVector4 operator=(const FGColumnVector4& b);
FGColumnVector4 operator*(const double scalar);
FGColumnVector4 operator/(const double scalar);
FGColumnVector4 operator+(const FGColumnVector4& B); // must not return reference
FGColumnVector4 operator-(const FGColumnVector4& B);
void operator-=(const FGColumnVector4 &B);
void operator+=(const FGColumnVector4 &B);
void operator*=(const double scalar);
void operator/=(const double scalar);
inline double operator()(int m) const { return data[m]; }
inline double& operator()(int m) { return data[m]; }
FGColumnVector4& operator<<(const double ff);
inline void InitMatrix(void) { data[1]=0; data[2]=0; data[3]=0; data[4]=0; }
inline void InitMatrix(double ff) { data[1]=ff; data[2]=ff; data[3]=ff; data[4]=ff;}
double Magnitude(void);
FGColumnVector4 Normalize(void);
friend FGColumnVector4 operator*(const double scalar, const FGColumnVector4& A);
friend ostream& operator<<(ostream& os, FGColumnVector4& col);
FGColumnVector4 multElementWise(const FGColumnVector4& V);
private:
double data[5];
int rowCtr;
void Debug(int from);
};
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif

View file

@ -1,131 +0,0 @@
/*******************************************************************************
Header: FGDefs.h
Author: Jon S. Berndt
Date started: 02/01/99
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org.
HISTORY
--------------------------------------------------------------------------------
02/01/99 JSB Created
********************************************************************************
SENTRY
*******************************************************************************/
#ifndef FGDEFS_H
#define FGDEFS_H
#define GRAVITY 32.174
#define INVGRAVITY 0.031081
#define EARTHRAD 20925650.00 // feet, equatorial
#define EARTHRADSQRD 437882827922500.0
#define ONESECOND 4.848136811E-6
#define Reng 1716 //Specific Gas Constant,ft^2/(sec^2*R)
#define SHRATIO 1.4 //Specific Heat Ratio
#define RADTODEG 57.29578
#define DEGTORAD 1.745329E-2
#define KTSTOFPS 1.68781
#define FPSTOKTS 0.592484
#define INCHTOFT 0.08333333
#define OMEGA_EARTH .00007272205217
#define NEEDED_CFG_VERSION "1.50"
#define JSBSIM_VERSION "0.9.0"
#define HPTOFTLBSSEC 550
#define METERS_TO_FEET 3.2808
#if defined ( sgi ) && !defined( __GNUC__ )
#define __STL_FUNCTION_TMPL_PARTIAL_ORDER
#endif
enum eParam {
FG_UNDEF = 0,
FG_TIME,
FG_QBAR,
FG_WINGAREA,
FG_WINGSPAN,
FG_CBAR,
FG_ALPHA,
FG_ALPHADOT,
FG_BETA,
FG_BETADOT,
FG_PHI,
FG_THT,
FG_PSI,
FG_PITCHRATE,
FG_ROLLRATE,
FG_YAWRATE,
FG_CL_SQRD,
FG_MACH,
FG_ALTITUDE,
FG_BI2VEL,
FG_CI2VEL,
FG_ELEVATOR_POS,
FG_AILERON_POS,
FG_RUDDER_POS,
FG_SPDBRAKE_POS,
FG_SPOILERS_POS,
FG_FLAPS_POS,
FG_ELEVATOR_CMD,
FG_AILERON_CMD,
FG_RUDDER_CMD,
FG_SPDBRAKE_CMD,
FG_SPOILERS_CMD,
FG_FLAPS_CMD,
FG_THROTTLE_CMD,
FG_THROTTLE_POS,
FG_MIXTURE_CMD,
FG_MIXTURE_POS,
FG_MAGNETO_CMD,
FG_STARTER_CMD,
FG_ACTIVE_ENGINE,
FG_HOVERB,
FG_PITCH_TRIM_CMD,
FG_LEFT_BRAKE_CMD,
FG_CENTER_BRAKE_CMD,
FG_RIGHT_BRAKE_CMD,
FG_SET_LOGGING,
FG_ALPHAH,
FG_ALPHAW,
FG_LBARH, //normalized horizontal tail arm
FG_LBARV, //normalized vertical tail arm
FG_HTAILAREA,
FG_VTAILAREA,
FG_VBARH, //horizontal tail volume
FG_VBARV //vertical tail volume
};
enum eAction {
FG_RAMP = 1,
FG_STEP = 2,
FG_EXP = 3
};
enum eType {
FG_VALUE = 1,
FG_DELTA = 2,
FG_BOOL = 3
};
/******************************************************************************/
#endif

View file

@ -1,12 +1,11 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Module: FGUtility.cpp Module: FGElectric.cpp
Author: Jon Berndt Author: David Culp
Date started: 01/09/99 Date started: 04/07/2004
Purpose: Contains utility classes for the FG FDM Purpose: This module models an electric motor
Called by: FGPosition, et. al.
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------- --------- Copyright (C) 2004 David Culp (davidculp2@comcast.net) -------------
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
@ -27,62 +26,90 @@
FUNCTIONAL DESCRIPTION FUNCTIONAL DESCRIPTION
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
This class is a container for all utility classes used by the flight dynamics
model. This class descends from the FGEngine class and models an electric motor based on
parameters given in the engine config file for this class
HISTORY HISTORY
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
01/09/99 JSB Created 04/07/2004 DPC Created
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifdef FGFS #include "FGElectric.h"
# include <simgear/compiler.h> #include "FGPropulsion.h"
# ifdef SG_HAVE_STD_INCLUDES
# include <cmath>
# else
# include <math.h>
# endif
#else
# if defined(sgi) && !defined(__GNUC__)
# include <math.h>
# else
# include <cmath>
# endif
#endif
#include "FGUtility.h"
#include "FGState.h"
#include "FGFDMExec.h"
namespace JSBSim { namespace JSBSim {
static const char *IdSrc = "$Id$"; static const char *IdSrc = "$Id$";
static const char *IdHdr = ID_UTILITY; static const char *IdHdr = ID_ELECTRIC;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
FGUtility::FGUtility() FGElectric::FGElectric(FGFDMExec* exec, FGConfigFile* Eng_cfg) : FGEngine(exec)
{ {
Debug(0); string token;
Type = etElectric;
EngineNumber = 0;
PowerWatts = 745.7;
hptowatts = 745.7;
dt = State->Getdt();
Name = Eng_cfg->GetValue("NAME");
Eng_cfg->GetNextConfigLine();
while (Eng_cfg->GetValue() != string("/FG_ELECTRIC")) {
*Eng_cfg >> token;
if (token == "POWER_WATTS") *Eng_cfg >> PowerWatts;
else cerr << "Unhandled token in Engine config file: " << token << endl;
}
Debug(0); // Call Debug() routine from constructor if needed
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGUtility::~FGUtility() FGElectric::~FGElectric()
{ {
Debug(1); Debug(1); // Call Debug() routine from constructor if needed
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGElectric::Calculate(void)
{
Throttle = FCS->GetThrottlePos(EngineNumber);
RPM = Thruster->GetRPM() * Thruster->GetGearRatio();
HP = PowerWatts * Throttle / hptowatts;
PowerAvailable = (HP * hptoftlbssec) - Thruster->GetPowerRequired();
return Thruster->Calculate(PowerAvailable);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGElectric::GetEngineLabels(void)
{
return ""; // currently no labels are returned for this engine
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGElectric::GetEngineValues(void)
{
return ""; // currently no values are returned for this engine
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
// The bitmasked value choices are as follows: // The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print // unset: In this case (the default) JSBSim would only print
// out the normally expected messages, essentially echoing // out the normally expected messages, essentially echoing
@ -101,18 +128,21 @@ FGUtility::~FGUtility()
// 16: When set various parameters are sanity checked and // 16: When set various parameters are sanity checked and
// a message is printed out when they go out of bounds // a message is printed out when they go out of bounds
void FGUtility::Debug(int from) void FGElectric::Debug(int from)
{ {
if (debug_lvl <= 0) return; if (debug_lvl <= 0) return;
if (debug_lvl & 1) { // Standard console startup message output if (debug_lvl & 1) { // Standard console startup message output
if (from == 0) { // Constructor if (from == 0) { // Constructor
cout << "\n Engine Name: " << Name << endl;
cout << " Power Watts: " << PowerWatts << endl;
} }
} }
if (debug_lvl & 2 ) { // Instantiation/Destruction notification if (debug_lvl & 2 ) { // Instantiation/Destruction notification
if (from == 0) cout << "Instantiated: FGUtility" << endl; if (from == 0) cout << "Instantiated: FGElectric" << endl;
if (from == 1) cout << "Destroyed: FGUtility" << endl; if (from == 1) cout << "Destroyed: FGElectric" << endl;
} }
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
} }
@ -127,4 +157,11 @@ void FGUtility::Debug(int from)
} }
} }
} }
double
FGElectric::CalcFuelNeed(void)
{
return 0;
} }
} // namespace JSBSim

View file

@ -1,10 +1,10 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Header: FGUtility.h Header: FGElectric.h
Author: Jon Berndt Author: David Culp
Date started: 01/09/99 Date started: 04/07/2004
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------- ----- Copyright (C) 2004 David P. Culp (davidculp2@comcast.net) --------------
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
@ -25,26 +25,27 @@
HISTORY HISTORY
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
01/09/99 JSB Created 04/07/2004 DPC Created
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifndef FGUTILITY_H #ifndef FGELECTRIC_H
#define FGUTILITY_H #define FGELECTRIC_H
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGJSBBase.h" #include "FGEngine.h"
#include "FGConfigFile.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINES DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_UTILITY "$Id$" #define ID_ELECTRIC "$Id$";
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS FORWARD DECLARATIONS
@ -56,22 +57,49 @@ namespace JSBSim {
CLASS DOCUMENTATION CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Models and electric motor.
FGElectric models an electric motor based on the configuration file
POWER_WATTS parameter. The throttle controls motor output linearly from
zero to POWER_WATTS. This power value (converted internally to horsepower)
is then used by FGPropeller to apply torque to the propeller.
@author David Culp
@version "$Id$"
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DECLARATION CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGFDMExec; class FGElectric : public FGEngine
class FGState;
class FGUtility : public FGJSBBase
{ {
public: public:
FGUtility(void); /// Constructor
~FGUtility(); FGElectric(FGFDMExec* exec, FGConfigFile* Eng_cfg);
/// Destructor
~FGElectric();
double Calculate(void);
double GetPowerAvailable(void) {return PowerAvailable;}
double CalcFuelNeed(void);
double getRPM(void) {return RPM;}
string GetEngineLabels(void);
string GetEngineValues(void);
private: private:
FGState* State;
FGFDMExec* FDMExec; double BrakeHorsePower;
double PowerAvailable;
// timestep
double dt;
// constants
double hptowatts;
double PowerWatts; // maximum engine power
double RPM; // revolutions per minute
double HP;
void Debug(int from); void Debug(int from);
}; };
} }

View file

@ -1,39 +1,39 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Module: FGEngine.cpp Module: FGEngine.cpp
Author: Jon Berndt Author: Jon Berndt
Date started: 01/21/99 Date started: 01/21/99
Called by: FGAircraft Called by: FGAircraft
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------- ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later Foundation; either version 2 of the License, or (at your option) any later
version. version.
This program is distributed in the hope that it will be useful, but WITHOUT This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details. details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA. Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org. the world wide web at http://www.gnu.org.
FUNCTIONAL DESCRIPTION FUNCTIONAL DESCRIPTION
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
See header file. See header file.
HISTORY HISTORY
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
01/21/99 JSB Created 01/21/99 JSB Created
09/03/99 JSB Changed Rocket thrust equation to correct -= Thrust instead of 09/03/99 JSB Changed Rocket thrust equation to correct -= Thrust instead of
+= Thrust (thanks to Tony Peden) += Thrust (thanks to Tony Peden)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
@ -55,6 +55,8 @@ INCLUDES
#include "FGEngine.h" #include "FGEngine.h"
#include "FGTank.h" #include "FGTank.h"
#include "FGPropeller.h"
#include "FGNozzle.h"
namespace JSBSim { namespace JSBSim {
@ -93,12 +95,10 @@ FGEngine::FGEngine(FGFDMExec* exec)
FCS = FDMExec->GetFCS(); FCS = FDMExec->GetFCS();
Propulsion = FDMExec->GetPropulsion(); Propulsion = FDMExec->GetPropulsion();
Aircraft = FDMExec->GetAircraft(); Aircraft = FDMExec->GetAircraft();
Translation = FDMExec->GetTranslation(); Propagate = FDMExec->GetPropagate();
Rotation = FDMExec->GetRotation();
Position = FDMExec->GetPosition();
Auxiliary = FDMExec->GetAuxiliary(); Auxiliary = FDMExec->GetAuxiliary();
Output = FDMExec->GetOutput(); Output = FDMExec->GetOutput();
PropertyManager = FDMExec->GetPropertyManager(); PropertyManager = FDMExec->GetPropertyManager();
Debug(0); Debug(0);
@ -119,17 +119,27 @@ FGEngine::~FGEngine()
void FGEngine::ConsumeFuel(void) void FGEngine::ConsumeFuel(void)
{ {
double Fshortage, Oshortage; double Fshortage, Oshortage, TanksWithFuel;
FGTank* Tank; FGTank* Tank;
if (TrimMode) return; if (TrimMode) return;
Fshortage = Oshortage = 0.0; Fshortage = Oshortage = TanksWithFuel = 0.0;
// count how many assigned tanks have fuel
for (unsigned int i=0; i<SourceTanks.size(); i++) {
Tank = Propulsion->GetTank(SourceTanks[i]);
if (Tank->GetContents() > 0.0) {
++TanksWithFuel;
}
}
if (!TanksWithFuel) return;
for (unsigned int i=0; i<SourceTanks.size(); i++) { for (unsigned int i=0; i<SourceTanks.size(); i++) {
Tank = Propulsion->GetTank(SourceTanks[i]); Tank = Propulsion->GetTank(SourceTanks[i]);
if (Tank->GetType() == FGTank::ttFUEL) { if (Tank->GetType() == FGTank::ttFUEL) {
Fshortage += Tank->Reduce(CalcFuelNeed()/Propulsion->GetnumSelectedFuelTanks()); Fshortage += Tank->Drain(CalcFuelNeed()/TanksWithFuel);
} else { } else {
Oshortage += Tank->Reduce(CalcOxidizerNeed()/Propulsion->GetnumSelectedOxiTanks()); Oshortage += Tank->Drain(CalcOxidizerNeed()/TanksWithFuel);
} }
} }
@ -171,6 +181,102 @@ void FGEngine::AddFeedTank(int tkID)
SourceTanks.push_back(tkID); SourceTanks.push_back(tkID);
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGColumnVector3& FGEngine::GetBodyForces(void)
{
return Thruster->GetBodyForces();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGColumnVector3& FGEngine::GetMoments(void)
{
return Thruster->GetMoments();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGEngine::LoadThruster(FGConfigFile* AC_cfg)
{
string token, fullpath, localpath;
string thrusterFileName, thrType, engineFileName;
FGConfigFile* Cfg_ptr = 0;
double xLoc, yLoc, zLoc, Pitch, Yaw;
double P_Factor = 0, Sense = 0.0;
string enginePath = FDMExec->GetEnginePath();
string aircraftPath = FDMExec->GetAircraftPath();
thrusterFileName = AC_cfg->GetValue("FILE");
# ifndef macintosh
fullpath = enginePath + "/";
localpath = aircraftPath + "/" + "/Engines/";
# else
fullpath = enginePath + ";";
localpath = aircraftPath + ";" + ";Engines;";
# endif
// Look in the Aircraft/Engines directory first
FGConfigFile Local_Thruster_cfg(localpath + thrusterFileName + ".xml");
FGConfigFile Thruster_cfg(fullpath + thrusterFileName + ".xml");
if (Local_Thruster_cfg.IsOpen()) {
Cfg_ptr = &Local_Thruster_cfg;
if (debug_lvl > 0) cout << "\n Reading thruster from file: " << localpath
+ thrusterFileName + ".xml"<< endl;
} else {
if (Thruster_cfg.IsOpen()) {
Cfg_ptr = &Thruster_cfg;
if (debug_lvl > 0) cout << "\n Reading thruster from file: " << fullpath
+ thrusterFileName + ".xml"<< endl;
}
}
if (Cfg_ptr) {
Cfg_ptr->GetNextConfigLine();
thrType = Cfg_ptr->GetValue();
if (thrType == "FG_PROPELLER") {
Thruster = new FGPropeller(FDMExec, Cfg_ptr);
} else if (thrType == "FG_NOZZLE") {
Thruster = new FGNozzle(FDMExec, Cfg_ptr);
} else if (thrType == "FG_DIRECT") {
Thruster = new FGThruster( FDMExec, Cfg_ptr);
}
AC_cfg->GetNextConfigLine();
while ((token = AC_cfg->GetValue()) != string("/AC_THRUSTER")) {
*AC_cfg >> token;
if (token == "XLOC") *AC_cfg >> xLoc;
else if (token == "YLOC") *AC_cfg >> yLoc;
else if (token == "ZLOC") *AC_cfg >> zLoc;
else if (token == "PITCH") *AC_cfg >> Pitch;
else if (token == "YAW") *AC_cfg >> Yaw;
else if (token == "P_FACTOR") *AC_cfg >> P_Factor;
else if (token == "SENSE") *AC_cfg >> Sense;
else cerr << "Unknown identifier: " << token << " in engine file: "
<< engineFileName << endl;
}
Thruster->SetLocation(xLoc, yLoc, zLoc);
Thruster->SetAnglesToBody(0, Pitch, Yaw);
if (thrType == "FG_PROPELLER" && P_Factor > 0.001) {
((FGPropeller*)Thruster)->SetPFactor(P_Factor);
if (debug_lvl > 0) cout << " P-Factor: " << P_Factor << endl;
((FGPropeller*)Thruster)->SetSense(fabs(Sense)/Sense);
if (debug_lvl > 0) cout << " Sense: " << Sense << endl;
}
Thruster->SetdeltaT(State->Getdt() * Propulsion->GetRate());
return true;
} else {
cerr << "Could not read thruster config file: " << fullpath
+ thrusterFileName + ".xml" << endl;
return false;
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows: // The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print // unset: In this case (the default) JSBSim would only print

View file

@ -59,6 +59,7 @@ INCLUDES
#endif #endif
#include "FGJSBBase.h" #include "FGJSBBase.h"
#include "FGThruster.h"
#include "FGPropertyManager.h" #include "FGPropertyManager.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -81,12 +82,12 @@ class FGState;
class FGAtmosphere; class FGAtmosphere;
class FGFCS; class FGFCS;
class FGAircraft; class FGAircraft;
class FGTranslation; class FGPropagate;
class FGRotation;
class FGPropulsion; class FGPropulsion;
class FGPosition;
class FGAuxiliary; class FGAuxiliary;
class FGOutput; class FGOutput;
class FGThruster;
class FGConfigFile;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DOCUMENTATION CLASS DOCUMENTATION
@ -96,7 +97,7 @@ CLASS DOCUMENTATION
This base class contains methods and members common to all engines, such as This base class contains methods and members common to all engines, such as
logic to drain fuel from the appropriate tank, etc. logic to drain fuel from the appropriate tank, etc.
@author Jon S. Berndt @author Jon S. Berndt
@version $Id$ @version $Id$
*/ */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -109,7 +110,7 @@ public:
FGEngine(FGFDMExec* exec); FGEngine(FGFDMExec* exec);
virtual ~FGEngine(); virtual ~FGEngine();
enum EngineType {etUnknown, etRocket, etPiston, etTurbine, etSimTurbine}; enum EngineType {etUnknown, etRocket, etPiston, etTurbine, etElectric};
EngineType GetType(void) { return Type; } EngineType GetType(void) { return Type; }
virtual string GetName(void) { return Name; } virtual string GetName(void) { return Name; }
@ -138,11 +139,8 @@ public:
virtual void SetStarter(bool s) { Starter = s; } virtual void SetStarter(bool s) { Starter = s; }
/** Calculates the thrust of the engine, and other engine functions. /** Calculates the thrust of the engine, and other engine functions.
@param PowerRequired this is the power required to run the thrusting device
such as a propeller. This resisting effect must be provided to the
engine model.
@return Thrust in pounds */ @return Thrust in pounds */
virtual double Calculate(double PowerRequired) {return 0.0;}; virtual double Calculate(void) {return 0.0;}
/** Reduces the fuel in the active tanks by the amount required. /** Reduces the fuel in the active tanks by the amount required.
This function should be called from within the This function should be called from within the
@ -174,6 +172,15 @@ public:
virtual bool GetTrimMode(void) {return TrimMode;} virtual bool GetTrimMode(void) {return TrimMode;}
virtual void SetTrimMode(bool state) {TrimMode = state;} virtual void SetTrimMode(bool state) {TrimMode = state;}
virtual FGColumnVector3& GetBodyForces(void);
virtual FGColumnVector3& GetMoments(void);
bool LoadThruster(FGConfigFile* AC_cfg);
FGThruster* GetThruster(void) {return Thruster;}
virtual string GetEngineLabels(void) = 0;
virtual string GetEngineValues(void) = 0;
protected: protected:
FGPropertyManager* PropertyManager; FGPropertyManager* PropertyManager;
string Name; string Name;
@ -208,11 +215,10 @@ protected:
FGFCS* FCS; FGFCS* FCS;
FGPropulsion* Propulsion; FGPropulsion* Propulsion;
FGAircraft* Aircraft; FGAircraft* Aircraft;
FGTranslation* Translation; FGPropagate* Propagate;
FGRotation* Rotation;
FGPosition* Position;
FGAuxiliary* Auxiliary; FGAuxiliary* Auxiliary;
FGOutput* Output; FGOutput* Output;
FGThruster* Thruster;
vector <int> SourceTanks; vector <int> SourceTanks;
void Debug(int from); void Debug(int from);
@ -223,12 +229,12 @@ protected:
#include "FGAtmosphere.h" #include "FGAtmosphere.h"
#include "FGFCS.h" #include "FGFCS.h"
#include "FGAircraft.h" #include "FGAircraft.h"
#include "FGTranslation.h" #include "FGPropagate.h"
#include "FGRotation.h"
#include "FGPropulsion.h" #include "FGPropulsion.h"
#include "FGPosition.h"
#include "FGAuxiliary.h" #include "FGAuxiliary.h"
#include "FGOutput.h" #include "FGOutput.h"
#include "FGThruster.h"
#include "FGConfigFile.h"
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif #endif

View file

@ -75,8 +75,6 @@ FGFCS::FGFCS(FGFDMExec* fdmex) : FGModel(fdmex)
APAttitudeSetPt = APAltitudeSetPt = APHeadingSetPt = APAirspeedSetPt = 0.0; APAttitudeSetPt = APAltitudeSetPt = APHeadingSetPt = APAirspeedSetPt = 0.0;
DoNormalize=true; DoNormalize=true;
eMode = mNone;
bind(); bind();
for (i=0;i<=NForms;i++) { for (i=0;i<=NForms;i++) {
DePos[i] = DaLPos[i] = DaRPos[i] = DrPos[i] = 0.0; DePos[i] = DaLPos[i] = DaRPos[i] = DrPos[i] = 0.0;
@ -117,26 +115,18 @@ bool FGFCS::Run(void)
{ {
unsigned int i; unsigned int i;
if (!FGModel::Run()) { if (FGModel::Run()) return true; // fast exit if nothing to do
for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = ThrottleCmd[i];
for (i=0; i<MixturePos.size(); i++) MixturePos[i] = MixtureCmd[i];
for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i];
for (i=0; i<APComponents.size(); i++) {
eMode = mAP;
APComponents[i]->Run();
eMode = mNone;
}
for (i=0; i<FCSComponents.size(); i++) {
eMode = mFCS;
FCSComponents[i]->Run();
eMode = mNone;
}
if (DoNormalize) Normalize();
return false; for (i=0; i<ThrottlePos.size(); i++) ThrottlePos[i] = ThrottleCmd[i];
} else { for (i=0; i<MixturePos.size(); i++) MixturePos[i] = MixtureCmd[i];
return true; for (i=0; i<PropAdvance.size(); i++) PropAdvance[i] = PropAdvanceCmd[i];
}
for (i=0; i<APComponents.size(); i++) APComponents[i]->Run(); // cycle AP components
for (i=0; i<FCSComponents.size(); i++) FCSComponents[i]->Run(); // cycle FCS components
if (DoNormalize) Normalize();
return false;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -297,9 +287,11 @@ bool FGFCS::Load(FGConfigFile* AC_cfg)
} }
# ifndef macintosh # ifndef macintosh
file = "control/" + fname + ".xml"; // file = "control/" + fname + ".xml";
file = FDMExec->GetAircraftPath() + "/" + FDMExec->GetModelName() + "/" + fname + ".xml";
# else # else
file = "control;" + fname + ".xml"; // file = "control;" + fname + ".xml";
file = FDMExec->GetAircraftPath() + ";" + FDMExec->GetModelName() + ";" + fname + ".xml";
# endif # endif
if (name.empty()) { if (name.empty()) {
@ -322,11 +314,9 @@ bool FGFCS::Load(FGConfigFile* AC_cfg)
if (delimiter == "AUTOPILOT") { if (delimiter == "AUTOPILOT") {
Components = &APComponents; Components = &APComponents;
eMode = mAP;
Name = "Autopilot: " + name; Name = "Autopilot: " + name;
} else if (delimiter == "FLIGHT_CONTROL") { } else if (delimiter == "FLIGHT_CONTROL") {
Components = &FCSComponents; Components = &FCSComponents;
eMode = mFCS;
Name = "FCS: " + name; Name = "FCS: " + name;
} else { } else {
cerr << endl << "Unknown FCS delimiter" << endl << endl; cerr << endl << "Unknown FCS delimiter" << endl << endl;
@ -400,45 +390,11 @@ bool FGFCS::Load(FGConfigFile* AC_cfg)
if (delimiter == "FLIGHT_CONTROL") bindModel(); if (delimiter == "FLIGHT_CONTROL") bindModel();
eMode = mNone;
return true; return true;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGFCS::GetComponentOutput(int idx)
{
switch (eMode) {
case mFCS:
return FCSComponents[idx]->GetOutput();
case mAP:
return APComponents[idx]->GetOutput();
case mNone:
cerr << "Unknown FCS mode" << endl;
break;
}
return 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGFCS::GetComponentName(int idx)
{
switch (eMode) {
case mFCS:
return FCSComponents[idx]->GetName();
case mAP:
return APComponents[idx]->GetName();
case mNone:
cerr << "Unknown FCS mode" << endl;
break;
}
return string("");
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGFCS::GetBrake(FGLGear::BrakeGroup bg) double FGFCS::GetBrake(FGLGear::BrakeGroup bg)
{ {
switch (bg) { switch (bg) {
@ -484,7 +440,7 @@ string FGFCS::GetComponentValues(void)
{ {
unsigned int comp; unsigned int comp;
string CompValues = ""; string CompValues = "";
char buffer[10]; char buffer[12];
bool firstime = true; bool firstime = true;
for (comp = 0; comp < FCSComponents.size(); comp++) { for (comp = 0; comp < FCSComponents.size(); comp++) {

View file

@ -3,30 +3,30 @@
Header: FGGFCS.h Header: FGGFCS.h
Author: Jon S. Berndt Author: Jon S. Berndt
Date started: 12/12/98 Date started: 12/12/98
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------- ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later Foundation; either version 2 of the License, or (at your option) any later
version. version.
This program is distributed in the hope that it will be useful, but WITHOUT This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details. details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA. Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org. the world wide web at http://www.gnu.org.
HISTORY HISTORY
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
12/12/98 JSB Created 12/12/98 JSB Created
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
@ -81,61 +81,58 @@ CLASS DOCUMENTATION
or command and ends at an effector, e.g. an aerosurface. The FCS components or command and ends at an effector, e.g. an aerosurface. The FCS components
which comprise the control laws for an axis are defined sequentially in which comprise the control laws for an axis are defined sequentially in
the configuration file. For instance, for the X-15: the configuration file. For instance, for the X-15:
<pre> <pre>
&lt FLIGHT_CONTROL NAME="X-15 SAS"&gt \<FLIGHT_CONTROL NAME="X-15 SAS">
&lt COMPONENT NAME="Pitch Trim Sum" TYPE="SUMMER"&gt \<COMPONENT NAME="Pitch Trim Sum" TYPE="SUMMER">
ID 0 INPUT fcs/elevator-cmd-norm
INPUT FG_ELEVATOR_CMD INPUT fcs/pitch-trim-cmd-norm
INPUT FG_PITCH_TRIM_CMD CLIPTO -1 1
CLIPTO -1 1 \</COMPONENT>
&lt/COMPONENT&gt
&lt COMPONENT NAME="Pitch Command Scale" TYPE="AEROSURFACE_SCALE"&gt \<COMPONENT NAME="Pitch Command Scale" TYPE="AEROSURFACE_SCALE">
ID 1 INPUT fcs/pitch-trim-sum
INPUT 0
MIN -50 MIN -50
MAX 50 MAX 50
&lt/COMPONENT&gt \</COMPONENT>
&lt COMPONENT NAME="Pitch Gain 1" TYPE="PURE_GAIN"&gt \<COMPONENT NAME="Pitch Gain 1" TYPE="PURE_GAIN">
ID 2 INPUT fcs/pitch-command-scale
INPUT 1
GAIN -0.36 GAIN -0.36
&lt/COMPONENT&gt \</COMPONENT>
&lt COMPONENT NAME="Pitch Scheduled Gain 1" TYPE="SCHEDULED_GAIN"&gt
ID 3
INPUT 2
GAIN 0.017
SCHEDULED_BY FG_ELEVATOR_POS
-0.35 -6.0
-0.17 -3.0
0.00 -2.0
0.09 -3.0
0.17 -5.0
0.60 -12.0
&lt/COMPONENT&gt
... etc. ... etc.
</pre> </pre>
In the above case we can see the first few components of the pitch channel In the above case we can see the first few components of the pitch channel
defined. The input to the first component, as can be seen in the "Pitch trim defined. The input to the first component, as can be seen in the "Pitch trim
sum" component, is really the sum of two parameters: elevator command (from sum" component, is really the sum of two parameters: elevator command (from
the stick - a pilot input), and pitch trim. The type of this component is the stick - a pilot input), and pitch trim. The type of this component is
"Summer". Its ID is 0 - the ID is used by other components to reference it. "Summer".
The next component created is an aerosurface scale component - a type of The next component created is an aerosurface scale component - a type of
gain (see the LoadFCS() method for insight on how the various types of gain (see the LoadFCS() method for insight on how the various types of
components map into the actual component classes). You can see the input of components map into the actual component classes). This continues until the
the "Pitch Command Scale" component takes "0" as input. When a number is final component for an axis when the
specified as an input, it refers to the ID of another FCS component. In this
case, ID 0 refers to the previously defined and discussed "Pitch Trim Sum"
component. This continues until the final component for an axis when the
OUTPUT keyword specifies where the output is supposed to go. See the OUTPUT keyword specifies where the output is supposed to go. See the
individual components for more information on how they are mechanized. individual components for more information on how they are mechanized.
Another option for the flight controls portion of the config file is that in
addition to using the "NAME" attribute in,
<pre>
\<FLIGHT_CONTROL NAME="X-15 SAS">
</pre>
one can also supply a filename:
<pre>
\<FLIGHT_CONTROL NAME="X-15 SAS" FILE="X15.xml">
\</FLIGHT_CONTROL>
</pre>
In this case, the FCS would be read in from another file.
@author Jon S. Berndt @author Jon S. Berndt
@version $Id$ @version $Id$
@see FGFCSComponent @see FGFCSComponent
@ -170,7 +167,7 @@ public:
/** Gets the aileron command. /** Gets the aileron command.
@return aileron command in percent */ @return aileron command in percent */
inline double GetDaCmd(void) const { return DaCmd; } inline double GetDaCmd(void) const { return DaCmd; }
/** Gets the elevator command. /** Gets the elevator command.
@return elevator command in percent */ @return elevator command in percent */
inline double GetDeCmd(void) const { return DeCmd; } inline double GetDeCmd(void) const { return DeCmd; }
@ -209,19 +206,19 @@ public:
/** Gets the pitch trim command. /** Gets the pitch trim command.
@return pitch trim command in percent */ @return pitch trim command in percent */
inline double GetPitchTrimCmd(void) const { return PTrimCmd; } inline double GetPitchTrimCmd(void) const { return PTrimCmd; }
/** Gets the rudder trim command. /** Gets the rudder trim command.
@return rudder trim command in percent */ @return rudder trim command in percent */
inline double GetYawTrimCmd(void) const { return YTrimCmd; } inline double GetYawTrimCmd(void) const { return YTrimCmd; }
/** Gets the aileron trim command. /** Gets the aileron trim command.
@return aileron trim command in percent */ @return aileron trim command in percent */
inline double GetRollTrimCmd(void) const { return RTrimCmd; } inline double GetRollTrimCmd(void) const { return RTrimCmd; }
/** Get the gear extend/retract command. 0 commands gear up, 1 down. /** Get the gear extend/retract command. 0 commands gear up, 1 down.
defaults to down. defaults to down.
@return the current value of the gear extend/retract command*/ @return the current value of the gear extend/retract command*/
inline double GetGearCmd(void) const { return GearCmd; } inline double GetGearCmd(void) const { return GearCmd; }
//@} //@}
/// @name AUTOPilot -> FCS effectors command retrieval /// @name AUTOPilot -> FCS effectors command retrieval
@ -229,7 +226,7 @@ public:
/** Gets the AUTOPilot aileron command. /** Gets the AUTOPilot aileron command.
@return aileron command in radians */ @return aileron command in radians */
inline double GetAPDaCmd(void) const { return AP_DaCmd; } inline double GetAPDaCmd(void) const { return AP_DaCmd; }
/** Gets the AUTOPilot elevator command. /** Gets the AUTOPilot elevator command.
@return elevator command in radians */ @return elevator command in radians */
inline double GetAPDeCmd(void) const { return AP_DeCmd; } inline double GetAPDeCmd(void) const { return AP_DeCmd; }
@ -237,7 +234,7 @@ public:
/** Gets the AUTOPilot rudder command. /** Gets the AUTOPilot rudder command.
@return rudder command in radians */ @return rudder command in radians */
inline double GetAPDrCmd(void) const { return AP_DrCmd; } inline double GetAPDrCmd(void) const { return AP_DrCmd; }
/** Gets the AUTOPilot throttle (all engines) command. /** Gets the AUTOPilot throttle (all engines) command.
@return throttle command in percent */ @return throttle command in percent */
inline double GetAPThrottleCmd(void) const { return AP_ThrottleCmd; } inline double GetAPThrottleCmd(void) const { return AP_ThrottleCmd; }
@ -283,19 +280,19 @@ public:
/** Turns on/off the attitude-seeking autopilot. /** Turns on/off the attitude-seeking autopilot.
@param set true turns the mode on, false turns it off **/ @param set true turns the mode on, false turns it off **/
inline void SetAPAcquireAttitude(bool set) {APAcquireAttitude = set;} inline void SetAPAcquireAttitude(bool set) {APAcquireAttitude = set;}
/** Turns on/off the altitude-seeking autopilot. /** Turns on/off the altitude-seeking autopilot.
@param set true turns the mode on, false turns it off **/ @param set true turns the mode on, false turns it off **/
inline void SetAPAcquireAltitude(bool set) {APAcquireAltitude = set;} inline void SetAPAcquireAltitude(bool set) {APAcquireAltitude = set;}
/** Turns on/off the heading-seeking autopilot. /** Turns on/off the heading-seeking autopilot.
@param set true turns the mode on, false turns it off **/ @param set true turns the mode on, false turns it off **/
inline void SetAPAcquireHeading(bool set) {APAcquireHeading = set;} inline void SetAPAcquireHeading(bool set) {APAcquireHeading = set;}
/** Turns on/off the airspeed-seeking autopilot. /** Turns on/off the airspeed-seeking autopilot.
@param set true turns the mode on, false turns it off **/ @param set true turns the mode on, false turns it off **/
inline void SetAPAcquireAirspeed(bool set) {APAcquireAirspeed = set;} inline void SetAPAcquireAirspeed(bool set) {APAcquireAirspeed = set;}
/** Turns on/off the attitude-holding autopilot. /** Turns on/off the attitude-holding autopilot.
@param set true turns the mode on, false turns it off **/ @param set true turns the mode on, false turns it off **/
inline void SetAPAttitudeHold(bool set) {APAttitudeHold = set;} inline void SetAPAttitudeHold(bool set) {APAttitudeHold = set;}
@ -316,7 +313,7 @@ public:
@param set true turns the mode on, false turns it off **/ @param set true turns the mode on, false turns it off **/
inline void SetAPWingsLevelHold(bool set) {APWingsLevelHold = set;} inline void SetAPWingsLevelHold(bool set) {APWingsLevelHold = set;}
//@} //@}
/// @name AUTOPilot mode retrieval /// @name AUTOPilot mode retrieval
//@{ //@{
/** Retrieves the on/off mode of the autopilot AcquireAttitude mode /** Retrieves the on/off mode of the autopilot AcquireAttitude mode
@ -360,41 +357,41 @@ public:
//@{ //@{
/** Gets the left aileron position. /** Gets the left aileron position.
@return aileron position in radians */ @return aileron position in radians */
inline double GetDaLPos( int form = ofRad ) inline double GetDaLPos( int form = ofRad )
const { return DaLPos[form]; } const { return DaLPos[form]; }
/// @name Aerosurface position retrieval /// @name Aerosurface position retrieval
//@{ //@{
/** Gets the right aileron position. /** Gets the right aileron position.
@return aileron position in radians */ @return aileron position in radians */
inline double GetDaRPos( int form = ofRad ) inline double GetDaRPos( int form = ofRad )
const { return DaRPos[form]; } const { return DaRPos[form]; }
/** Gets the elevator position. /** Gets the elevator position.
@return elevator position in radians */ @return elevator position in radians */
inline double GetDePos( int form = ofRad ) inline double GetDePos( int form = ofRad )
const { return DePos[form]; } const { return DePos[form]; }
/** Gets the rudder position. /** Gets the rudder position.
@return rudder position in radians */ @return rudder position in radians */
inline double GetDrPos( int form = ofRad ) inline double GetDrPos( int form = ofRad )
const { return DrPos[form]; } const { return DrPos[form]; }
/** Gets the speedbrake position. /** Gets the speedbrake position.
@return speedbrake position in radians */ @return speedbrake position in radians */
inline double GetDsbPos( int form = ofRad ) inline double GetDsbPos( int form = ofRad )
const { return DsbPos[form]; } const { return DsbPos[form]; }
/** Gets the spoiler position. /** Gets the spoiler position.
@return spoiler position in radians */ @return spoiler position in radians */
inline double GetDspPos( int form = ofRad ) inline double GetDspPos( int form = ofRad )
const { return DspPos[form]; } const { return DspPos[form]; }
/** Gets the flaps position. /** Gets the flaps position.
@return flaps position in radians */ @return flaps position in radians */
inline double GetDfPos( int form = ofRad ) inline double GetDfPos( int form = ofRad )
const { return DfPos[form]; } const { return DfPos[form]; }
/** Gets the throttle position. /** Gets the throttle position.
@param engine engine ID number @param engine engine ID number
@return throttle position for the given engine in percent ( 0 - 100)*/ @return throttle position for the given engine in percent ( 0 - 100)*/
@ -404,10 +401,10 @@ public:
@param engine engine ID number @param engine engine ID number
@return mixture position for the given engine in percent ( 0 - 100)*/ @return mixture position for the given engine in percent ( 0 - 100)*/
inline double GetMixturePos(int engine) const { return MixturePos[engine]; } inline double GetMixturePos(int engine) const { return MixturePos[engine]; }
/** Gets the gear position (0 up, 1 down), defaults to down /** Gets the gear position (0 up, 1 down), defaults to down
@return gear position (0 up, 1 down) */ @return gear position (0 up, 1 down) */
inline double GetGearPos(void) const { return GearPos; } inline double GetGearPos(void) const { return GearPos; }
/** Gets the prop pitch position. /** Gets the prop pitch position.
@param engine engine ID number @param engine engine ID number
@ -420,16 +417,6 @@ public:
@return pointer to the State object */ @return pointer to the State object */
inline FGState* GetState(void) { return State; } inline FGState* GetState(void) { return State; }
/** Retrieves a components output value
@param idx the index of the component (the component ID)
@return output value from the component */
double GetComponentOutput(int idx);
/** Retrieves the component name
@param idx the index of the component (the component ID)
@return name of the component */
string GetComponentName(int idx);
/** Retrieves all component names for inclusion in output stream */ /** Retrieves all component names for inclusion in output stream */
string GetComponentStrings(void); string GetComponentStrings(void);
@ -483,10 +470,10 @@ public:
@param engine engine ID number @param engine engine ID number
@param cmd mixture command in percent (0 - 100)*/ @param cmd mixture command in percent (0 - 100)*/
void SetMixtureCmd(int engine, double cmd); void SetMixtureCmd(int engine, double cmd);
/** Set the gear extend/retract command, defaults to down /** Set the gear extend/retract command, defaults to down
@param gear command 0 for up, 1 for down */ @param gear command 0 for up, 1 for down */
void SetGearCmd(double gearcmd) { GearCmd = gearcmd; } void SetGearCmd(double gearcmd) { GearCmd = gearcmd; }
/** Sets the propeller pitch command for the specified engine /** Sets the propeller pitch command for the specified engine
@param engine engine ID number @param engine engine ID number
@ -517,39 +504,39 @@ public:
//@{ //@{
/** Sets the left aileron position /** Sets the left aileron position
@param cmd left aileron position in radians*/ @param cmd left aileron position in radians*/
inline void SetDaLPos( int form , double pos ) inline void SetDaLPos( int form , double pos )
{ DaLPos[form] = pos; } { DaLPos[form] = pos; }
/** Sets the right aileron position /** Sets the right aileron position
@param cmd right aileron position in radians*/ @param cmd right aileron position in radians*/
inline void SetDaRPos( int form , double pos ) inline void SetDaRPos( int form , double pos )
{ DaRPos[form] = pos; } { DaRPos[form] = pos; }
/** Sets the elevator position /** Sets the elevator position
@param cmd elevator position in radians*/ @param cmd elevator position in radians*/
inline void SetDePos( int form , double pos ) inline void SetDePos( int form , double pos )
{ DePos[form] = pos; } { DePos[form] = pos; }
/** Sets the rudder position /** Sets the rudder position
@param cmd rudder position in radians*/ @param cmd rudder position in radians*/
inline void SetDrPos( int form , double pos ) inline void SetDrPos( int form , double pos )
{ DrPos[form] = pos; } { DrPos[form] = pos; }
/** Sets the flaps position /** Sets the flaps position
@param cmd flaps position in radians*/ @param cmd flaps position in radians*/
inline void SetDfPos( int form , double pos ) inline void SetDfPos( int form , double pos )
{ DfPos[form] = pos; } { DfPos[form] = pos; }
/** Sets the speedbrake position /** Sets the speedbrake position
@param cmd speedbrake position in radians*/ @param cmd speedbrake position in radians*/
inline void SetDsbPos( int form , double pos ) inline void SetDsbPos( int form , double pos )
{ DsbPos[form] = pos; } { DsbPos[form] = pos; }
/** Sets the spoiler position /** Sets the spoiler position
@param cmd spoiler position in radians*/ @param cmd spoiler position in radians*/
inline void SetDspPos( int form , double pos ) inline void SetDspPos( int form , double pos )
{ DspPos[form] = pos; } { DspPos[form] = pos; }
/** Sets the actual throttle setting for the specified engine /** Sets the actual throttle setting for the specified engine
@param engine engine ID number @param engine engine ID number
@param cmd throttle setting in percent (0 - 100)*/ @param cmd throttle setting in percent (0 - 100)*/
@ -559,10 +546,10 @@ public:
@param engine engine ID number @param engine engine ID number
@param cmd mixture setting in percent (0 - 100)*/ @param cmd mixture setting in percent (0 - 100)*/
void SetMixturePos(int engine, double cmd); void SetMixturePos(int engine, double cmd);
/** Set the gear extend/retract position, defaults to down /** Set the gear extend/retract position, defaults to down
@param gear position 0 up, 1 down */ @param gear position 0 up, 1 down */
void SetGearPos(double gearpos) { GearPos = gearpos; } void SetGearPos(double gearpos) { GearPos = gearpos; }
/** Sets the actual prop pitch setting for the specified engine /** Sets the actual prop pitch setting for the specified engine
@ -600,17 +587,17 @@ public:
bool Load(FGConfigFile* AC_cfg); bool Load(FGConfigFile* AC_cfg);
void AddThrottle(void); void AddThrottle(void);
FGPropertyManager* GetPropertyManager(void) { return PropertyManager; } FGPropertyManager* GetPropertyManager(void) { return PropertyManager; }
void bind(void); void bind(void);
void bindModel(void); void bindModel(void);
void unbind(FGPropertyManager *node); void unbind(FGPropertyManager *node);
private: private:
double DaCmd, DeCmd, DrCmd, DfCmd, DsbCmd, DspCmd; double DaCmd, DeCmd, DrCmd, DfCmd, DsbCmd, DspCmd;
double AP_DaCmd, AP_DeCmd, AP_DrCmd, AP_ThrottleCmd; double AP_DaCmd, AP_DeCmd, AP_DrCmd, AP_ThrottleCmd;
double DePos[NForms], DaLPos[NForms], DaRPos[NForms], DrPos[NForms]; double DePos[NForms], DaLPos[NForms], DaRPos[NForms], DrPos[NForms];
double DfPos[NForms], DsbPos[NForms], DspPos[NForms]; double DfPos[NForms], DsbPos[NForms], DspPos[NForms];
double PTrimCmd, YTrimCmd, RTrimCmd; double PTrimCmd, YTrimCmd, RTrimCmd;
vector <double> ThrottleCmd; vector <double> ThrottleCmd;
@ -622,8 +609,6 @@ private:
double LeftBrake, RightBrake, CenterBrake; // Brake settings double LeftBrake, RightBrake, CenterBrake; // Brake settings
double GearCmd,GearPos; double GearCmd,GearPos;
enum Mode {mAP, mFCS, mNone} eMode;
double APAttitudeSetPt, APAltitudeSetPt, APHeadingSetPt, APAirspeedSetPt; double APAttitudeSetPt, APAltitudeSetPt, APHeadingSetPt, APAirspeedSetPt;
bool APAcquireAttitude, APAcquireAltitude, APAcquireHeading, APAcquireAirspeed; bool APAcquireAttitude, APAcquireAltitude, APAcquireHeading, APAcquireAirspeed;
bool APAttitudeHold, APAltitudeHold, APHeadingHold, APAirspeedHold, APWingsLevelHold; bool APAttitudeHold, APAltitudeHold, APHeadingHold, APAirspeedHold, APWingsLevelHold;

View file

@ -64,9 +64,7 @@ INCLUDES
#include "FGAerodynamics.h" #include "FGAerodynamics.h"
#include "FGInertial.h" #include "FGInertial.h"
#include "FGAircraft.h" #include "FGAircraft.h"
#include "FGTranslation.h" #include "FGPropagate.h"
#include "FGRotation.h"
#include "FGPosition.h"
#include "FGAuxiliary.h" #include "FGAuxiliary.h"
#include "FGOutput.h" #include "FGOutput.h"
#include "FGConfigFile.h" #include "FGConfigFile.h"
@ -100,16 +98,16 @@ void checkTied ( FGPropertyManager *node )
} else if ( node->getChild(i)->isTied() ) { } else if ( node->getChild(i)->isTied() ) {
name = ((FGPropertyManager*)node->getChild(i))->GetFullyQualifiedName(); name = ((FGPropertyManager*)node->getChild(i))->GetFullyQualifiedName();
cerr << name << " is tied" << endl; cerr << name << " is tied" << endl;
} }
} }
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Constructor // Constructor
FGFDMExec::FGFDMExec(FGPropertyManager* root) FGFDMExec::FGFDMExec(FGPropertyManager* root)
{ {
Frame = 0; Frame = 0;
FirstModel = 0; FirstModel = 0;
Error = 0; Error = 0;
@ -122,9 +120,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root)
Inertial = 0; Inertial = 0;
GroundReactions = 0; GroundReactions = 0;
Aircraft = 0; Aircraft = 0;
Translation = 0; Propagate = 0;
Rotation = 0;
Position = 0;
Auxiliary = 0; Auxiliary = 0;
Output = 0; Output = 0;
IC = 0; IC = 0;
@ -150,9 +146,9 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root)
instance = master->GetNode("/fdm/jsbsim",IdFDM,true); instance = master->GetNode("/fdm/jsbsim",IdFDM,true);
Debug(0); Debug(0);
// this is here to catch errors in binding member functions // this is here to catch errors in binding member functions
// to the property tree. // to the property tree.
try { try {
@ -160,7 +156,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root)
} catch ( string msg ) { } catch ( string msg ) {
cout << "Caught error: " << msg << endl; cout << "Caught error: " << msg << endl;
exit(1); exit(1);
} }
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -172,11 +168,11 @@ FGFDMExec::~FGFDMExec()
checkTied( instance ); checkTied( instance );
} catch ( string msg ) { } catch ( string msg ) {
cout << "Caught error: " << msg << endl; cout << "Caught error: " << msg << endl;
} }
for (unsigned int i=1; i<SlaveFDMList.size(); i++) delete SlaveFDMList[i]->exec; for (unsigned int i=1; i<SlaveFDMList.size(); i++) delete SlaveFDMList[i]->exec;
SlaveFDMList.clear(); SlaveFDMList.clear();
Debug(1); Debug(1);
} }
@ -194,16 +190,14 @@ bool FGFDMExec::Allocate(void)
Inertial = new FGInertial(this); Inertial = new FGInertial(this);
GroundReactions = new FGGroundReactions(this); GroundReactions = new FGGroundReactions(this);
Aircraft = new FGAircraft(this); Aircraft = new FGAircraft(this);
Translation = new FGTranslation(this); Propagate = new FGPropagate(this);
Rotation = new FGRotation(this);
Position = new FGPosition(this);
Auxiliary = new FGAuxiliary(this); Auxiliary = new FGAuxiliary(this);
Output = new FGOutput(this); Output = new FGOutput(this);
State = new FGState(this); // This must be done here, as the FGState State = new FGState(this); // This must be done here, as the FGState
// class needs valid pointers to the above // class needs valid pointers to the above
// model classes // model classes
// Initialize models so they can communicate with each other // Initialize models so they can communicate with each other
if (!Atmosphere->InitModel()) { if (!Atmosphere->InitModel()) {
@ -230,15 +224,9 @@ bool FGFDMExec::Allocate(void)
if (!Aircraft->InitModel()) { if (!Aircraft->InitModel()) {
cerr << fgred << "Aircraft model init failed" << fgdef << endl; cerr << fgred << "Aircraft model init failed" << fgdef << endl;
Error+=128;} Error+=128;}
if (!Translation->InitModel()) { if (!Propagate->InitModel()) {
cerr << fgred << "Translation model init failed" << fgdef << endl; cerr << fgred << "Propagate model init failed" << fgdef << endl;
Error+=256;}
if (!Rotation->InitModel()) {
cerr << fgred << "Rotation model init failed" << fgdef << endl;
Error+=512;} Error+=512;}
if (!Position->InitModel()) {
cerr << fgred << "Position model init failed" << fgdef << endl;
Error+=1024;}
if (!Auxiliary->InitModel()) { if (!Auxiliary->InitModel()) {
cerr << fgred << "Auxiliary model init failed" << fgdef << endl; cerr << fgred << "Auxiliary model init failed" << fgdef << endl;
Error+=2058;} Error+=2058;}
@ -247,9 +235,9 @@ bool FGFDMExec::Allocate(void)
Error+=4096;} Error+=4096;}
if (Error > 0) result = false; if (Error > 0) result = false;
IC = new FGInitialCondition(this); IC = new FGInitialCondition(this);
// Schedule a model. The second arg (the integer) is the pass number. For // Schedule a model. The second arg (the integer) is the pass number. For
// instance, the atmosphere model gets executed every fifth pass it is called // instance, the atmosphere model gets executed every fifth pass it is called
// by the executive. Everything else here gets executed each pass. // by the executive. Everything else here gets executed each pass.
@ -263,9 +251,7 @@ bool FGFDMExec::Allocate(void)
Schedule(Inertial, 1); Schedule(Inertial, 1);
Schedule(GroundReactions, 1); Schedule(GroundReactions, 1);
Schedule(Aircraft, 1); Schedule(Aircraft, 1);
Schedule(Rotation, 1); Schedule(Propagate, 1);
Schedule(Translation, 1);
Schedule(Position, 1);
Schedule(Auxiliary, 1); Schedule(Auxiliary, 1);
Schedule(Output, 1); Schedule(Output, 1);
@ -286,16 +272,14 @@ bool FGFDMExec::DeAllocate(void)
delete Inertial; delete Inertial;
delete GroundReactions; delete GroundReactions;
delete Aircraft; delete Aircraft;
delete Translation; delete Propagate;
delete Rotation;
delete Position;
delete Auxiliary; delete Auxiliary;
delete Output; delete Output;
delete State; delete State;
delete IC; delete IC;
delete Trim; delete Trim;
FirstModel = 0L; FirstModel = 0L;
Error = 0; Error = 0;
@ -308,9 +292,7 @@ bool FGFDMExec::DeAllocate(void)
Inertial = 0; Inertial = 0;
GroundReactions = 0; GroundReactions = 0;
Aircraft = 0; Aircraft = 0;
Translation = 0; Propagate = 0;
Rotation = 0;
Position = 0;
Auxiliary = 0; Auxiliary = 0;
Output = 0; Output = 0;
@ -341,7 +323,7 @@ int FGFDMExec::Schedule(FGModel* model, int rate)
model_iterator->NextModel->SetRate(rate); model_iterator->NextModel->SetRate(rate);
} }
return 0; return 0;
} }
@ -408,7 +390,7 @@ bool FGFDMExec::LoadModel(string AircraftPath, string EnginePath, string model)
FGFDMExec::EnginePath = EnginePath; FGFDMExec::EnginePath = EnginePath;
return LoadModel(model); return LoadModel(model);
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -423,18 +405,18 @@ bool FGFDMExec::LoadModel(string model)
cerr << "aircraft and engine paths" << endl; cerr << "aircraft and engine paths" << endl;
return false; return false;
} }
# ifndef macintosh # ifndef macintosh
aircraftCfgFileName = AircraftPath + "/" + model + "/" + model + ".xml"; aircraftCfgFileName = AircraftPath + "/" + model + ".xml";
# else # else
aircraftCfgFileName = AircraftPath + ";" + model + ";" + model + ".xml"; aircraftCfgFileName = AircraftPath + ";" + model + ".xml";
# endif # endif
FGConfigFile AC_cfg(aircraftCfgFileName); FGConfigFile AC_cfg(aircraftCfgFileName);
if (!AC_cfg.IsOpen()) return false; if (!AC_cfg.IsOpen()) return false;
modelName = model; modelName = model;
if (modelLoaded) { if (modelLoaded) {
DeAllocate(); DeAllocate();
Allocate(); Allocate();
@ -512,7 +494,7 @@ bool FGFDMExec::ReadPrologue(FGConfigFile* AC_cfg)
cerr << " You have version: " << CFGVersion << endl << fgdef << endl; cerr << " You have version: " << CFGVersion << endl << fgdef << endl;
return false; return false;
} }
if (Release == "ALPHA") { if (Release == "ALPHA") {
system("banner ALPHA"); system("banner ALPHA");
cout << endl << endl cout << endl << endl
@ -557,7 +539,7 @@ bool FGFDMExec::ReadSlave(FGConfigFile* AC_cfg)
string AircraftName = AC_cfg->GetValue("FILE"); string AircraftName = AC_cfg->GetValue("FILE");
debug_lvl = 0; // turn off debug output for slave vehicle debug_lvl = 0; // turn off debug output for slave vehicle
SlaveFDMList.back()->exec->SetAircraftPath( AircraftPath ); SlaveFDMList.back()->exec->SetAircraftPath( AircraftPath );
SlaveFDMList.back()->exec->SetEnginePath( EnginePath ); SlaveFDMList.back()->exec->SetEnginePath( EnginePath );
SlaveFDMList.back()->exec->LoadModel(AircraftName); SlaveFDMList.back()->exec->LoadModel(AircraftName);
@ -655,18 +637,18 @@ bool FGFDMExec::ReadOutput(FGConfigFile* AC_cfg)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGPropertyManager* FGFDMExec::GetPropertyManager(void) { FGPropertyManager* FGFDMExec::GetPropertyManager(void) {
return instance; return instance;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGTrim* FGFDMExec::GetTrim(void) { FGTrim* FGFDMExec::GetTrim(void) {
delete Trim; delete Trim;
Trim = new FGTrim(this,tNone); Trim = new FGTrim(this,tNone);
return Trim; return Trim;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows: // The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print // unset: In this case (the default) JSBSim would only print

View file

@ -27,7 +27,7 @@ HISTORY
11/17/98 JSB Created 11/17/98 JSB Created
7/31/99 TP Added RunIC function that runs the sim so that every frame 7/31/99 TP Added RunIC function that runs the sim so that every frame
begins with the IC values from the given FGInitialCondition begins with the IC values from the given FGInitialCondition
object and dt=0. object and dt=0.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY SENTRY
@ -72,31 +72,30 @@ CLASS DOCUMENTATION
When an aircraft model is loaded the config file is parsed and for each of the When an aircraft model is loaded the config file is parsed and for each of the
sections of the config file (propulsion, flight control, etc.) the sections of the config file (propulsion, flight control, etc.) the
corresponding "ReadXXX()" method is called. From within this method the corresponding "ReadXXX()" method is called. From within this method the
"Load()" method of that system is called (e.g. LoadFCS). "Load()" method of that system is called (e.g. LoadFCS).
<h4>JSBSim Debugging Directives</h4> <h4>JSBSim Debugging Directives</h4>
This describes to any interested entity the debug level This describes to any interested entity the debug level
requested by setting the JSBSIM_DEBUG environment variable. requested by setting the JSBSIM_DEBUG environment variable.
The bitmasked value choices are as follows:<ol> The bitmasked value choices are as follows:
<li><b>unset</b>: In this case (the default) JSBSim would only print - <b>unset</b>: In this case (the default) JSBSim would only print
out the normally expected messages, essentially echoing out the normally expected messages, essentially echoing
the config files as they are read. If the environment the config files as they are read. If the environment
variable is not set, debug_lvl is set to 1 internally</li> variable is not set, debug_lvl is set to 1 internally
<li><b>0</b>: This requests JSBSim not to output any messages - <b>0</b>: This requests JSBSim not to output any messages
whatsoever.</li> whatsoever
<li><b>1</b>: This value explicity requests the normal JSBSim - <b>1</b>: This value explicity requests the normal JSBSim
startup messages</li> startup messages
<li><b>2</b>: This value asks for a message to be printed out when - <b>2</b>: This value asks for a message to be printed out when
a class is instantiated</li> a class is instantiated
<li><b>4</b>: When this value is set, a message is displayed when a - <b>4</b>: When this value is set, a message is displayed when a
FGModel object executes its Run() method</li> FGModel object executes its Run() method
<li><b>8</b>: When this value is set, various runtime state variables - <b>8</b>: When this value is set, various runtime state variables
are printed out periodically</li> are printed out periodically
<li><b>16</b>: When set various parameters are sanity checked and - <b>16</b>: When set various parameters are sanity checked and
a message is printed out when they go out of bounds</li> a message is printed out when they go out of bounds
</ol>
@author Jon S. Berndt @author Jon S. Berndt
@version $Id$ @version $Id$
@ -112,7 +111,7 @@ public:
/// Default constructor /// Default constructor
FGFDMExec(FGPropertyManager* root = 0); FGFDMExec(FGPropertyManager* root = 0);
/// Default destructor /// Default destructor
~FGFDMExec(); ~FGFDMExec();
@ -142,8 +141,8 @@ public:
/// Resumes the sim /// Resumes the sim
void Resume(void) {frozen = false;} void Resume(void) {frozen = false;}
/** Loads an aircraft model. /** Loads an aircraft model.
@param AircraftPath path to the aircraft directory. For instance: @param AircraftPath path to the aircraft directory. For instance:
"aircraft". Under aircraft, then, would be directories for various "aircraft". Under aircraft, then, would be directories for various
modeled aircraft such as C172/, x15/, etc. modeled aircraft such as C172/, x15/, etc.
@ -155,7 +154,7 @@ public:
instance: "aircraft/x15/x15.xml" instance: "aircraft/x15/x15.xml"
@return true if successful*/ @return true if successful*/
bool LoadModel(string AircraftPath, string EnginePath, string model); bool LoadModel(string AircraftPath, string EnginePath, string model);
/** Loads an aircraft model. The paths to the aircraft and engine /** Loads an aircraft model. The paths to the aircraft and engine
config file directories must be set prior to calling this. See config file directories must be set prior to calling this. See
@ -166,7 +165,7 @@ public:
instance: "aircraft/x15/x15.xml" instance: "aircraft/x15/x15.xml"
@return true if successful*/ @return true if successful*/
bool LoadModel(string model); bool LoadModel(string model);
/** Sets the path to the engine config file directories. /** Sets the path to the engine config file directories.
@param path path to the directory under which engine config @param path path to the directory under which engine config
@ -180,14 +179,14 @@ public:
modeled aircraft such as C172/, x15/, etc. modeled aircraft such as C172/, x15/, etc.
*/ */
bool SetAircraftPath(string path) { AircraftPath = path; return true; } bool SetAircraftPath(string path) { AircraftPath = path; return true; }
/** Sets the path to the autopilot config file directories. /** Sets the path to the autopilot config file directories.
@param path path to the control directory. For instance: @param path path to the control directory. For instance:
"control". "control".
*/ */
bool SetControlPath(string path) { ControlPath = path; return true; } // bool SetControlPath(string path) { ControlPath = path; return true; }
/// @name Top-level executive State and Model retrieval mechanism /// @name Top-level executive State and Model retrieval mechanism
//@{ //@{
/// Returns the FGState pointer. /// Returns the FGState pointer.
@ -208,12 +207,8 @@ public:
inline FGGroundReactions* GetGroundReactions(void) {return GroundReactions;} inline FGGroundReactions* GetGroundReactions(void) {return GroundReactions;}
/// Returns the FGAircraft pointer. /// Returns the FGAircraft pointer.
inline FGAircraft* GetAircraft(void) {return Aircraft;} inline FGAircraft* GetAircraft(void) {return Aircraft;}
/// Returns the FGTranslation pointer. /// Returns the FGPropagate pointer.
inline FGTranslation* GetTranslation(void) {return Translation;} inline FGPropagate* GetPropagate(void) {return Propagate;}
/// Returns the FGRotation pointer.
inline FGRotation* GetRotation(void) {return Rotation;}
/// Returns the FGPosition pointer.
inline FGPosition* GetPosition(void) {return Position;}
/// Returns the FGAuxiliary pointer. /// Returns the FGAuxiliary pointer.
inline FGAuxiliary* GetAuxiliary(void) {return Auxiliary;} inline FGAuxiliary* GetAuxiliary(void) {return Auxiliary;}
/// Returns the FGOutput pointer. /// Returns the FGOutput pointer.
@ -223,20 +218,20 @@ public:
// Returns a pointer to the FGTrim object // Returns a pointer to the FGTrim object
FGTrim* GetTrim(void); FGTrim* GetTrim(void);
//@} //@}
/// Retrieves the engine path. /// Retrieves the engine path.
inline string GetEnginePath(void) {return EnginePath;} inline string GetEnginePath(void) {return EnginePath;}
/// Retrieves the aircraft path. /// Retrieves the aircraft path.
inline string GetAircraftPath(void) {return AircraftPath;} inline string GetAircraftPath(void) {return AircraftPath;}
/// Retrieves the control path. // /// Retrieves the control path.
inline string GetControlPath(void) {return ControlPath;} // inline string GetControlPath(void) {return ControlPath;}
string GetModelName(void) { return modelName; } string GetModelName(void) { return modelName; }
FGPropertyManager* GetPropertyManager(void); FGPropertyManager* GetPropertyManager(void);
vector <string> EnumerateFDMs(void); vector <string> EnumerateFDMs(void);
void SetSlave(void) {IsSlave = true;} void SetSlave(void) {IsSlave = true;}
private: private:
FGModel* FirstModel; FGModel* FirstModel;
@ -251,7 +246,7 @@ private:
bool IsSlave; bool IsSlave;
static FGPropertyManager *master; static FGPropertyManager *master;
FGPropertyManager *instance; FGPropertyManager *instance;
struct slaveData { struct slaveData {
FGFDMExec* exec; FGFDMExec* exec;
string info; string info;
@ -273,8 +268,8 @@ private:
string AircraftPath; string AircraftPath;
string EnginePath; string EnginePath;
string ControlPath; // string ControlPath;
string CFGVersion; string CFGVersion;
string Release; string Release;
@ -287,12 +282,10 @@ private:
FGInertial* Inertial; FGInertial* Inertial;
FGGroundReactions* GroundReactions; FGGroundReactions* GroundReactions;
FGAircraft* Aircraft; FGAircraft* Aircraft;
FGTranslation* Translation; FGPropagate* Propagate;
FGRotation* Rotation;
FGPosition* Position;
FGAuxiliary* Auxiliary; FGAuxiliary* Auxiliary;
FGOutput* Output; FGOutput* Output;
FGInitialCondition* IC; FGInitialCondition* IC;
FGTrim *Trim; FGTrim *Trim;

View file

@ -69,9 +69,7 @@ class FGState;
class FGAtmosphere; class FGAtmosphere;
class FGFCS; class FGFCS;
class FGAircraft; class FGAircraft;
class FGTranslation; class FGPropagate;
class FGRotation;
class FGPosition;
class FGAuxiliary; class FGAuxiliary;
class FGOutput; class FGOutput;
@ -93,13 +91,13 @@ class FGFactorGroup: public FGCoefficient
public: public:
FGFactorGroup(FGFDMExec* fdmex); FGFactorGroup(FGFDMExec* fdmex);
~FGFactorGroup(); ~FGFactorGroup();
bool Load(FGConfigFile *AC_cfg); bool Load(FGConfigFile *AC_cfg);
double TotalValue(void); double TotalValue(void);
inline double GetValue(void) const { return totalValue; } inline double GetValue(void) const { return totalValue; }
inline double GetSD(void) { return SDtotal; } inline double GetSD(void) { return SDtotal; }
inline double GetFactorSD(void) { return FGCoefficient::GetSD(); } inline double GetFactorSD(void) { return FGCoefficient::GetSD(); }
void bind(FGPropertyManager* parent); void bind(FGPropertyManager* parent);
void unbind(void); void unbind(void);
@ -113,5 +111,5 @@ private:
FGPropertyManager *node; FGPropertyManager *node;
void Debug(int from); void Debug(int from);
}; };
} }
#endif #endif

View file

@ -42,7 +42,7 @@ and the cg.
#include "FGFDMExec.h" #include "FGFDMExec.h"
#include "FGAircraft.h" #include "FGAircraft.h"
#include "FGTranslation.h" #include "FGPropagate.h"
#include "FGMassBalance.h" #include "FGMassBalance.h"
#include "FGState.h" #include "FGState.h"
#include "FGForce.h" #include "FGForce.h"
@ -97,7 +97,7 @@ FGMatrix33 FGForce::Transform(void)
case tWindBody: case tWindBody:
return fdmex->GetState()->GetTs2b(); return fdmex->GetState()->GetTs2b();
case tLocalBody: case tLocalBody:
return fdmex->GetState()->GetTl2b(); return fdmex->GetPropagate()->GetTl2b();
case tCustom: case tCustom:
case tNone: case tNone:
return mT; return mT;

View file

@ -261,7 +261,7 @@ public:
vXYZn(eZ) = z; vXYZn(eZ) = z;
SetActingLocation(x, y, z); SetActingLocation(x, y, z);
} }
/** Acting point of application. /** Acting point of application.
JSBsim structural coords used (inches, x +back, y +right, z +up). JSBsim structural coords used (inches, x +back, y +right, z +up).
This function sets the point at which the force acts - this may This function sets the point at which the force acts - this may
@ -283,7 +283,7 @@ public:
inline double SetActingLocationZ(double z) {vActingXYZn(eZ) = z; return z;} inline double SetActingLocationZ(double z) {vActingXYZn(eZ) = z; return z;}
inline void SetLocation(FGColumnVector3 vv) { vXYZn = vv; SetActingLocation(vv);} inline void SetLocation(FGColumnVector3 vv) { vXYZn = vv; SetActingLocation(vv);}
inline void SetActingLocation(FGColumnVector3 vv) { vActingXYZn = vv; } inline void SetActingLocation(FGColumnVector3 vv) { vActingXYZn = vv; }
inline double GetLocationX( void ) { return vXYZn(eX);} inline double GetLocationX( void ) { return vXYZn(eX);}
inline double GetLocationY( void ) { return vXYZn(eY);} inline double GetLocationY( void ) { return vXYZn(eY);}
inline double GetLocationZ( void ) { return vXYZn(eZ);} inline double GetLocationZ( void ) { return vXYZn(eZ);}
@ -320,7 +320,7 @@ protected:
FGColumnVector3 vFn; FGColumnVector3 vFn;
FGColumnVector3 vMn; FGColumnVector3 vMn;
FGColumnVector3 vH; FGColumnVector3 vH;
private: private:
FGColumnVector3 vFb; FGColumnVector3 vFb;
FGColumnVector3 vM; FGColumnVector3 vM;
@ -331,7 +331,7 @@ private:
FGMatrix33 mT; FGMatrix33 mT;
virtual void Debug(int from); void Debug(int from);
}; };
} }
#endif #endif

View file

@ -35,6 +35,9 @@ HISTORY
INCLUDES INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include <sstream>
#include <iomanip>
#include "FGGroundReactions.h" #include "FGGroundReactions.h"
#include "FGPropertyManager.h" #include "FGPropertyManager.h"
@ -43,15 +46,6 @@ namespace JSBSim {
static const char *IdSrc = "$Id$"; static const char *IdSrc = "$Id$";
static const char *IdHdr = ID_GROUNDREACTIONS; static const char *IdHdr = ID_GROUNDREACTIONS;
#if defined (__APPLE__)
/* Not all systems have the gcvt function */
inline char* gcvt (double value, int ndigits, char *buf) {
/* note that this is not exactly what gcvt is supposed to do! */
snprintf (buf, ndigits+1, "%f", value);
return buf;
}
#endif
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
@ -60,7 +54,7 @@ CLASS IMPLEMENTATION
FGGroundReactions::FGGroundReactions(FGFDMExec* fgex) : FGModel(fgex) FGGroundReactions::FGGroundReactions(FGFDMExec* fgex) : FGModel(fgex)
{ {
Name = "FGGroundReactions"; Name = "FGGroundReactions";
bind(); bind();
Debug(0); Debug(0);
@ -84,7 +78,7 @@ bool FGGroundReactions::Run(void)
vMoments.InitMatrix(); vMoments.InitMatrix();
// Only execute gear force code below 300 feet // Only execute gear force code below 300 feet
if ( Position->GetDistanceAGL() < 300.0 ) { if ( Propagate->GetDistanceAGL() < 300.0 ) {
vector <FGLGear>::iterator iGear = lGear.begin(); vector <FGLGear>::iterator iGear = lGear.begin();
// Sum forces and moments for all gear, here. // Sum forces and moments for all gear, here.
// Some optimizations may be made here - or rather in the gear code itself. // Some optimizations may be made here - or rather in the gear code itself.
@ -126,79 +120,71 @@ bool FGGroundReactions::Load(FGConfigFile* AC_cfg)
string FGGroundReactions::GetGroundReactionStrings(void) string FGGroundReactions::GetGroundReactionStrings(void)
{ {
string GroundReactionStrings = ""; std::ostringstream buf;
bool firstime = true;
for (unsigned int i=0;i<lGear.size();i++) { for (unsigned int i=0;i<lGear.size();i++) {
if (!firstime) GroundReactionStrings += ", "; string name = lGear[i].GetName();
GroundReactionStrings += (lGear[i].GetName() + "_WOW, "); buf << name << "_WOW, "
GroundReactionStrings += (lGear[i].GetName() + "_stroke, "); << name << "_stroke, "
GroundReactionStrings += (lGear[i].GetName() + "_strokeVel, "); << name << "_strokeVel, "
GroundReactionStrings += (lGear[i].GetName() + "_CompressForce, "); << name << "_CompressForce, "
GroundReactionStrings += (lGear[i].GetName() + "_WhlSideForce, "); << name << "_WhlSideForce, "
GroundReactionStrings += (lGear[i].GetName() + "_WhlVelVecX, "); << name << "_WhlVelVecX, "
GroundReactionStrings += (lGear[i].GetName() + "_WhlVelVecY, "); << name << "_WhlVelVecY, "
GroundReactionStrings += (lGear[i].GetName() + "_WhlRollForce, "); << name << "_WhlRollForce, "
GroundReactionStrings += (lGear[i].GetName() + "_BodyXForce, "); << name << "_BodyXForce, "
GroundReactionStrings += (lGear[i].GetName() + "_BodyYForce, "); << name << "_BodyYForce, "
GroundReactionStrings += (lGear[i].GetName() + "_WhlSlipDegrees"); << name << "_WhlSlipDegrees, ";
firstime = false;
} }
GroundReactionStrings += ", TotalGearForce_X, "; buf << "TotalGearForce_X, "
GroundReactionStrings += "TotalGearForce_Y, "; << "TotalGearForce_Y, "
GroundReactionStrings += "TotalGearForce_Z, "; << "TotalGearForce_Z, "
GroundReactionStrings += "TotalGearMoment_L, "; << "TotalGearMoment_L, "
GroundReactionStrings += "TotalGearMoment_M, "; << "TotalGearMoment_M, "
GroundReactionStrings += "TotalGearMoment_N"; << "TotalGearMoment_N";
return GroundReactionStrings; return buf.str();
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGGroundReactions::GetGroundReactionValues(void) string FGGroundReactions::GetGroundReactionValues(void)
{ {
char buff[20]; std::ostringstream buf;
string GroundReactionValues = "";
bool firstime = true;
for (unsigned int i=0;i<lGear.size();i++) { for (unsigned int i=0;i<lGear.size();i++) {
if (!firstime) GroundReactionValues += ", "; FGLGear& gear = lGear[i];
GroundReactionValues += string( lGear[i].GetWOW()?"1":"0" ) + ", "; buf << (gear.GetWOW() ? "1, " : "0, ")
GroundReactionValues += (string(gcvt(lGear[i].GetCompLen(), 5, buff)) + ", "); << setprecision(5) << gear.GetCompLen() << ", "
GroundReactionValues += (string(gcvt(lGear[i].GetCompVel(), 6, buff)) + ", "); << setprecision(6) << gear.GetCompVel() << ", "
GroundReactionValues += (string(gcvt(lGear[i].GetCompForce(), 10, buff)) + ", "); << setprecision(10) << gear.GetCompForce() << ", "
GroundReactionValues += (string(gcvt(lGear[i].GetWheelVel(eX), 6, buff)) + ", "); << setprecision(6) << gear.GetWheelVel(eX) << ", "
GroundReactionValues += (string(gcvt(lGear[i].GetWheelVel(eY), 6, buff)) + ", "); << gear.GetWheelVel(eY) << ", "
GroundReactionValues += (string(gcvt(lGear[i].GetWheelSideForce(), 6, buff)) + ", "); << gear.GetWheelSideForce() << ", "
GroundReactionValues += (string(gcvt(lGear[i].GetWheelRollForce(), 6, buff)) + ", "); << gear.GetWheelRollForce() << ", "
GroundReactionValues += (string(gcvt(lGear[i].GetBodyXForce(), 6, buff)) + ", "); << gear.GetBodyXForce() << ", "
GroundReactionValues += (string(gcvt(lGear[i].GetBodyYForce(), 6, buff)) + ", "); << gear.GetBodyYForce() << ", "
GroundReactionValues += (string(gcvt(lGear[i].GetWheelSlipAngle(), 6, buff))); << gear.GetWheelSlipAngle() << ", ";
firstime = false;
} }
GroundReactionValues += (", " + string(gcvt(vForces(eX), 6, buff)) + ", "); buf << vForces(eX) << ", "
GroundReactionValues += (string(gcvt(vForces(eY), 6, buff)) + ", "); << vForces(eY) << ", "
GroundReactionValues += (string(gcvt(vForces(eZ), 6, buff)) + ", "); << vForces(eZ) << ", "
GroundReactionValues += (string(gcvt(vMoments(eX), 6, buff)) + ", "); << vMoments(eX) << ", "
GroundReactionValues += (string(gcvt(vMoments(eY), 6, buff)) + ", "); << vMoments(eY) << ", "
GroundReactionValues += (string(gcvt(vMoments(eZ), 6, buff))); << vMoments(eZ);
return GroundReactionValues; return buf.str();
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGGroundReactions::bind(void) void FGGroundReactions::bind(void)
{ {
typedef double (FGGroundReactions::*PMF)(int) const; typedef double (FGGroundReactions::*PMF)(int) const;
PropertyManager->Tie("gear/num-units", this, PropertyManager->Tie("gear/num-units", this,
&FGGroundReactions::GetNumGearUnits); &FGGroundReactions::GetNumGearUnits);
PropertyManager->Tie("moments/l-gear-lbsft", this,1, PropertyManager->Tie("moments/l-gear-lbsft", this,1,
(PMF)&FGGroundReactions::GetMoments); (PMF)&FGGroundReactions::GetMoments);
PropertyManager->Tie("moments/m-gear-lbsft", this,2, PropertyManager->Tie("moments/m-gear-lbsft", this,2,

View file

@ -36,7 +36,7 @@ INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGInertial.h" #include "FGInertial.h"
#include "FGPosition.h" #include "FGPropagate.h"
#include "FGState.h" #include "FGState.h"
#include "FGMassBalance.h" #include "FGMassBalance.h"
@ -60,12 +60,6 @@ FGInertial::FGInertial(FGFDMExec* fgex) : FGModel(fgex)
RadiusReference = 20925650.00; RadiusReference = 20925650.00;
gAccelReference = GM/(RadiusReference*RadiusReference); gAccelReference = GM/(RadiusReference*RadiusReference);
gAccel = GM/(RadiusReference*RadiusReference); gAccel = GM/(RadiusReference*RadiusReference);
vRadius.InitMatrix();
vCoriolis.InitMatrix();
vCentrifugal.InitMatrix();
vGravity.InitMatrix();
bind();
Debug(0); Debug(0);
} }
@ -74,7 +68,6 @@ FGInertial::FGInertial(FGFDMExec* fgex) : FGModel(fgex)
FGInertial::~FGInertial(void) FGInertial::~FGInertial(void)
{ {
unbind();
Debug(1); Debug(1);
} }
@ -82,42 +75,14 @@ FGInertial::~FGInertial(void)
bool FGInertial::Run(void) bool FGInertial::Run(void)
{ {
if (!FGModel::Run()) { // Fast return if we have nothing to do ...
if (FGModel::Run()) return true;
gAccel = GM / (Position->GetRadius()*Position->GetRadius()); // Gravitation accel
double r = Propagate->GetRadius();
gAccel = GetGAccel(r);
vGravity(eDown) = gAccel; return false;
// The following equation for vOmegaLocal terms shows the angular velocity
// calculation _for_the_local_frame_ given the earth's rotation (first set)
// at the current latitude, and also the component due to the aircraft
// motion over the curved surface of the earth (second set).
vOmegaLocal(eX) = omega() * cos(Position->GetLatitude());
vOmegaLocal(eY) = 0.0;
vOmegaLocal(eZ) = omega() * -sin(Position->GetLatitude());
vOmegaLocal(eX) += Position->GetVe() / Position->GetRadius();
vOmegaLocal(eY) += -Position->GetVn() / Position->GetRadius();
vOmegaLocal(eZ) += 0.00;
// Coriolis acceleration is normally written: -2w*dr/dt, but due to the axis
// conventions used here the sign is reversed: 2w*dr/dt. The same is true for
// Centrifugal acceleration.
vCoriolis(eEast) = 2.0*omega() * (Position->GetVd()*cos(Position->GetLatitude()) +
Position->GetVn()*sin(Position->GetLatitude()));
vRadius(eDown) = Position->GetRadius();
vCentrifugal(eDown) = -vOmegaLocal.Magnitude() * vOmegaLocal.Magnitude() * vRadius(eDown);
// vForces = State->GetTl2b() * MassBalance->GetMass() * (vCoriolis + vCentrifugal + vGravity);
vForces = State->GetTl2b() * MassBalance->GetMass() * vGravity;
return false;
} else {
return true;
}
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -129,27 +94,6 @@ bool FGInertial::LoadInertial(FGConfigFile* AC_cfg)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGInertial::bind(void)
{
typedef double (FGInertial::*PMF)(int) const;
PropertyManager->Tie("forces/fbx-inertial-lbs", this,1,
(PMF)&FGInertial::GetForces);
PropertyManager->Tie("forces/fby-inertial-lbs", this,2,
(PMF)&FGInertial::GetForces);
PropertyManager->Tie("forces/fbz-inertial-lbs", this,3,
(PMF)&FGInertial::GetForces);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGInertial::unbind(void)
{
PropertyManager->Untie("forces/fbx-inertial-lbs");
PropertyManager->Untie("forces/fby-inertial-lbs");
PropertyManager->Untie("forces/fbz-inertial-lbs");
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows: // The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print // unset: In this case (the default) JSBSim would only print
// out the normally expected messages, essentially echoing // out the normally expected messages, essentially echoing

View file

@ -83,27 +83,14 @@ public:
~FGInertial(void); ~FGInertial(void);
bool Run(void); bool Run(void);
FGColumnVector3& GetForces(void) {return vForces;}
FGColumnVector3& GetGravity(void) {return vGravity;}
FGColumnVector3& GetCoriolis(void) {return vCoriolis;}
FGColumnVector3& GetCentrifugal(void) {return vCentrifugal;}
double GetForces(int n) const {return vForces(n);}
bool LoadInertial(FGConfigFile* AC_cfg); bool LoadInertial(FGConfigFile* AC_cfg);
double SLgravity(void) const {return gAccelReference;} double SLgravity(void) const {return gAccelReference;}
double gravity(void) const {return gAccel;} double gravity(void) const {return gAccel;}
double omega(void) const {return RotationRate;} double omega(void) const {return RotationRate;}
double GetGAccel(double r) const { return GM/(r*r); }
double RefRadius(void) const {return RadiusReference;} double RefRadius(void) const {return RadiusReference;}
void bind(void);
void unbind(void);
private: private:
FGColumnVector3 vOmegaLocal;
FGColumnVector3 vForces;
FGColumnVector3 vRadius;
FGColumnVector3 vGravity;
FGColumnVector3 vCoriolis;
FGColumnVector3 vCentrifugal;
double gAccel; double gAccel;
double gAccelReference; double gAccelReference;
double RadiusReference; double RadiusReference;
@ -114,4 +101,3 @@ private:
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif #endif

View file

@ -47,7 +47,7 @@ INCLUDES
#include "FGInertial.h" #include "FGInertial.h"
#include "FGAtmosphere.h" #include "FGAtmosphere.h"
#include "FGAerodynamics.h" #include "FGAerodynamics.h"
#include "FGPosition.h" #include "FGPropagate.h"
#include "FGConfigFile.h" #include "FGConfigFile.h"
#include "FGPropertyManager.h" #include "FGPropertyManager.h"
@ -67,6 +67,7 @@ FGInitialCondition::FGInitialCondition(FGFDMExec *FDMExec)
altitude=hdot=0; altitude=hdot=0;
latitude=longitude=0; latitude=longitude=0;
u=v=w=0; u=v=w=0;
p=q=r=0;
uw=vw=ww=0; uw=vw=ww=0;
vnorth=veast=vdown=0; vnorth=veast=vdown=0;
wnorth=weast=wdown=0; wnorth=weast=wdown=0;
@ -83,7 +84,7 @@ FGInitialCondition::FGInitialCondition(FGFDMExec *FDMExec)
if(FDMExec != NULL ) { if(FDMExec != NULL ) {
fdmex=FDMExec; fdmex=FDMExec;
fdmex->GetPosition()->Seth(altitude); fdmex->GetPropagate()->Seth(altitude);
fdmex->GetAtmosphere()->Run(); fdmex->GetAtmosphere()->Run();
PropertyManager=fdmex->GetPropertyManager(); PropertyManager=fdmex->GetPropertyManager();
bind(); bind();
@ -265,7 +266,7 @@ void FGInitialCondition::SetWBodyFpsIC(double tt) {
//****************************************************************************** //******************************************************************************
double FGInitialCondition::GetUBodyFpsIC(void) { double FGInitialCondition::GetUBodyFpsIC(void) const {
if(lastSpeedSet == setvg ) if(lastSpeedSet == setvg )
return u; return u;
else else
@ -274,7 +275,7 @@ double FGInitialCondition::GetUBodyFpsIC(void) {
//****************************************************************************** //******************************************************************************
double FGInitialCondition::GetVBodyFpsIC(void) { double FGInitialCondition::GetVBodyFpsIC(void) const {
if( lastSpeedSet == setvg ) if( lastSpeedSet == setvg )
return v; return v;
else { else {
@ -284,7 +285,7 @@ double FGInitialCondition::GetVBodyFpsIC(void) {
//****************************************************************************** //******************************************************************************
double FGInitialCondition::GetWBodyFpsIC(void) { double FGInitialCondition::GetWBodyFpsIC(void) const {
if( lastSpeedSet == setvg ) if( lastSpeedSet == setvg )
return w; return w;
else else
@ -394,7 +395,7 @@ void FGInitialCondition::calcWindUVW(void) {
void FGInitialCondition::SetAltitudeFtIC(double tt) { void FGInitialCondition::SetAltitudeFtIC(double tt) {
altitude=tt; altitude=tt;
fdmex->GetPosition()->Seth(altitude); fdmex->GetPropagate()->Seth(altitude);
fdmex->GetAtmosphere()->Run(); fdmex->GetAtmosphere()->Run();
//lets try to make sure the user gets what they intended //lets try to make sure the user gets what they intended
@ -422,8 +423,8 @@ void FGInitialCondition::SetAltitudeFtIC(double tt) {
//****************************************************************************** //******************************************************************************
void FGInitialCondition::SetAltitudeAGLFtIC(double tt) { void FGInitialCondition::SetAltitudeAGLFtIC(double tt) {
fdmex->GetPosition()->SetDistanceAGL(tt); fdmex->GetPropagate()->SetDistanceAGL(tt);
altitude=fdmex->GetPosition()->Geth(); altitude=fdmex->GetPropagate()->Geth();
SetAltitudeFtIC(altitude); SetAltitudeFtIC(altitude);
} }
@ -925,6 +926,19 @@ void FGInitialCondition::bind(void){
&FGInitialCondition::GetLongitudeRadIC, &FGInitialCondition::GetLongitudeRadIC,
&FGInitialCondition::SetLongitudeRadIC, &FGInitialCondition::SetLongitudeRadIC,
true); true);
PropertyManager->Tie("ic/p-rad_sec", this,
&FGInitialCondition::GetPRadpsIC,
&FGInitialCondition::SetPRadpsIC,
true);
PropertyManager->Tie("ic/q-rad_sec", this,
&FGInitialCondition::GetQRadpsIC,
&FGInitialCondition::SetQRadpsIC,
true);
PropertyManager->Tie("ic/r-rad_sec", this,
&FGInitialCondition::GetRRadpsIC,
&FGInitialCondition::SetRRadpsIC,
true);
} }
//****************************************************************************** //******************************************************************************
@ -973,6 +987,10 @@ void FGInitialCondition::unbind(void){
PropertyManager->Untie("ic/psi-true-rad"); PropertyManager->Untie("ic/psi-true-rad");
PropertyManager->Untie("ic/lat-gc-rad"); PropertyManager->Untie("ic/lat-gc-rad");
PropertyManager->Untie("ic/long-gc-rad"); PropertyManager->Untie("ic/long-gc-rad");
PropertyManager->Untie("ic/p-rad_sec");
PropertyManager->Untie("ic/q-rad_sec");
PropertyManager->Untie("ic/r-rad_sec");
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View file

@ -192,6 +192,9 @@ public:
void SetVnorthFpsIC(double tt); void SetVnorthFpsIC(double tt);
void SetVeastFpsIC(double tt); void SetVeastFpsIC(double tt);
void SetVdownFpsIC(double tt); void SetVdownFpsIC(double tt);
void SetPRadpsIC(double tt) { p = tt; }
void SetQRadpsIC(double tt) { q = tt; }
void SetRRadpsIC(double tt) { r = tt; }
void SetWindNEDFpsIC(double wN, double wE, double wD); void SetWindNEDFpsIC(double wN, double wE, double wD);
@ -215,9 +218,12 @@ public:
inline double GetWindFpsIC(void) const { return sqrt(wnorth*wnorth + weast*weast); } inline double GetWindFpsIC(void) const { return sqrt(wnorth*wnorth + weast*weast); }
double GetWindDirDegIC(void); double GetWindDirDegIC(void);
inline double GetClimbRateFpsIC(void) const { return hdot; } inline double GetClimbRateFpsIC(void) const { return hdot; }
double GetUBodyFpsIC(void); double GetUBodyFpsIC(void) const;
double GetVBodyFpsIC(void); double GetVBodyFpsIC(void) const;
double GetWBodyFpsIC(void); double GetWBodyFpsIC(void) const;
double GetPRadpsIC() const { return p; }
double GetQRadpsIC() const { return q; }
double GetRRadpsIC() const { return r; }
void SetFlightPathAngleRadIC(double tt); void SetFlightPathAngleRadIC(double tt);
void SetAlphaRadIC(double tt); void SetAlphaRadIC(double tt);
void SetPitchAngleRadIC(double tt); void SetPitchAngleRadIC(double tt);
@ -253,6 +259,7 @@ private:
double altitude,hdot; double altitude,hdot;
double latitude,longitude; double latitude,longitude;
double u,v,w; double u,v,w;
double p,q,r;
double uw,vw,ww; double uw,vw,ww;
double vnorth,veast,vdown; double vnorth,veast,vdown;
double wnorth,weast,wdown; double wnorth,weast,wdown;

View file

@ -78,7 +78,7 @@ const double FGJSBBase::SHRatio = 1.40;
const double FGJSBBase::slugtolb = 32.174049; const double FGJSBBase::slugtolb = 32.174049;
const double FGJSBBase::lbtoslug = 1.0/slugtolb; const double FGJSBBase::lbtoslug = 1.0/slugtolb;
const string FGJSBBase::needed_cfg_version = "1.61"; const string FGJSBBase::needed_cfg_version = "1.65";
const string FGJSBBase::JSBSim_version = "0.9.5"; const string FGJSBBase::JSBSim_version = "0.9.5";
std::queue <FGJSBBase::Message*> FGJSBBase::Messages; std::queue <FGJSBBase::Message*> FGJSBBase::Messages;
@ -90,12 +90,6 @@ short FGJSBBase::debug_lvl = 1;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGJSBBase::FGJSBBase()
{
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGJSBBase::Message* FGJSBBase::PutMessage(Message* msg) FGJSBBase::Message* FGJSBBase::PutMessage(Message* msg)
{ {
Messages.push(msg); Messages.push(msg);
@ -104,7 +98,7 @@ FGJSBBase::Message* FGJSBBase::PutMessage(Message* msg)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGJSBBase::Message* FGJSBBase::PutMessage(string text) FGJSBBase::Message* FGJSBBase::PutMessage(const string& text)
{ {
Message *msg = new Message(); Message *msg = new Message();
msg->text = text; msg->text = text;
@ -117,7 +111,7 @@ FGJSBBase::Message* FGJSBBase::PutMessage(string text)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGJSBBase::Message* FGJSBBase::PutMessage(string text, bool bVal) FGJSBBase::Message* FGJSBBase::PutMessage(const string& text, bool bVal)
{ {
Message *msg = new Message(); Message *msg = new Message();
msg->text = text; msg->text = text;
@ -131,7 +125,7 @@ FGJSBBase::Message* FGJSBBase::PutMessage(string text, bool bVal)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGJSBBase::Message* FGJSBBase::PutMessage(string text, int iVal) FGJSBBase::Message* FGJSBBase::PutMessage(const string& text, int iVal)
{ {
Message *msg = new Message(); Message *msg = new Message();
msg->text = text; msg->text = text;
@ -145,7 +139,7 @@ FGJSBBase::Message* FGJSBBase::PutMessage(string text, int iVal)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGJSBBase::Message* FGJSBBase::PutMessage(string text, double dVal) FGJSBBase::Message* FGJSBBase::PutMessage(const string& text, double dVal)
{ {
Message *msg = new Message(); Message *msg = new Message();
msg->text = text; msg->text = text;

View file

@ -38,6 +38,8 @@ SENTRY
INCLUDES INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include <limits>
#ifdef FGFS #ifdef FGFS
# include <simgear/compiler.h> # include <simgear/compiler.h>
# include <math.h> # include <math.h>
@ -73,17 +75,6 @@ using std::string;
using std::max; using std::max;
#endif #endif
#ifdef __FreeBSD__ // define gcvt on FreeBSD
#include <stdio.h>
static char *gcvt(double number, size_t ndigit, char *buf)
{
sprintf(buf, "%f", number);
return buf;
}
#endif
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
@ -112,10 +103,10 @@ CLASS DECLARATION
class FGJSBBase { class FGJSBBase {
public: public:
/// Constructor for FGJSBBase. /// Constructor for FGJSBBase.
FGJSBBase(); FGJSBBase() {};
/// Destructor for FGJSBBase. /// Destructor for FGJSBBase.
virtual ~FGJSBBase() {}; ~FGJSBBase() {};
/// JSBSim Message structure /// JSBSim Message structure
typedef struct Msg { typedef struct Msg {
@ -129,26 +120,6 @@ public:
double dVal; double dVal;
} Message; } Message;
///@name JSBSim Enums.
//@{
/// Moments L, M, N
enum {eL = 1, eM, eN };
/// Rates P, Q, R
enum {eP = 1, eQ, eR };
/// Velocities U, V, W
enum {eU = 1, eV, eW };
/// Positions X, Y, Z
enum {eX = 1, eY, eZ };
/// Euler angles Phi, Theta, Psi
enum {ePhi = 1, eTht, ePsi };
/// Stability axis forces, Drag, Side force, Lift
enum {eDrag = 1, eSide, eLift };
/// Local frame orientation Roll, Pitch, Yaw
enum {eRoll = 1, ePitch, eYaw };
/// Local frame position North, East, Down
enum {eNorth = 1, eEast, eDown };
//@}
///@name JSBSim console output highlighting terms. ///@name JSBSim console output highlighting terms.
//@{ //@{
/// highlights text /// highlights text
@ -184,22 +155,22 @@ public:
/** Creates a message with the given text and places it on the queue. /** Creates a message with the given text and places it on the queue.
@param text message text @param text message text
@return pointer to a Message structure */ @return pointer to a Message structure */
Message* PutMessage(string text); Message* PutMessage(const string& text);
/** Creates a message with the given text and boolean value and places it on the queue. /** Creates a message with the given text and boolean value and places it on the queue.
@param text message text @param text message text
@param bVal boolean value associated with the message @param bVal boolean value associated with the message
@return pointer to a Message structure */ @return pointer to a Message structure */
Message* PutMessage(string text, bool bVal); Message* PutMessage(const string& text, bool bVal);
/** Creates a message with the given text and integer value and places it on the queue. /** Creates a message with the given text and integer value and places it on the queue.
@param text message text @param text message text
@param iVal integer value associated with the message @param iVal integer value associated with the message
@return pointer to a Message structure */ @return pointer to a Message structure */
Message* PutMessage(string text, int iVal); Message* PutMessage(const string& text, int iVal);
/** Creates a message with the given text and double value and places it on the queue. /** Creates a message with the given text and double value and places it on the queue.
@param text message text @param text message text
@param dVal double value associated with the message @param dVal double value associated with the message
@return pointer to a Message structure */ @return pointer to a Message structure */
Message* PutMessage(string text, double dVal); Message* PutMessage(const string& text, double dVal);
/** Reads the message on the queue (but does not delete it). /** Reads the message on the queue (but does not delete it).
@return pointer to a Message structure (or NULL if no mesage) */ @return pointer to a Message structure (or NULL if no mesage) */
Message* ReadMessage(void); Message* ReadMessage(void);
@ -208,28 +179,71 @@ public:
Message* ProcessMessage(void); Message* ProcessMessage(void);
//@} //@}
string GetVersion(void) {return JSBSim_version;} string GetVersion(void) {return JSBSim_version;}
void disableHighLighting(void); void disableHighLighting(void);
static short debug_lvl; static short debug_lvl;
double KelvinToFahrenheit (double kelvin) { static double KelvinToFahrenheit (double kelvin) {
return 1.8*kelvin - 459.4; return 1.8*kelvin - 459.4;
} }
double RankineToCelsius (double rankine) { static double RankineToCelsius (double rankine) {
return (rankine - 491.67)/1.8; return (rankine - 491.67)/1.8;
} }
static double FahrenheitToCelsius (double fahrenheit) {
return (fahrenheit - 32.0)/1.8;
}
static double CelsiusToFahrenheit (double celsius) {
return celsius * 1.8 + 32.0;
}
/** Finite precision comparison.
@param a first value to compare
@param b second value to compare
@return if the two values can be considered equal up to roundoff */
static bool EqualToRoundoff(double a, double b) {
double eps = 2.0*std::numeric_limits<double>::epsilon();
return fabs(a - b) <= eps*max(fabs(a), fabs(b));
}
/** Finite precision comparison.
@param a first value to compare
@param b second value to compare
@return if the two values can be considered equal up to roundoff */
static bool EqualToRoundoff(float a, float b) {
float eps = 2.0*std::numeric_limits<float>::epsilon();
return fabs(a - b) <= eps*max(fabs(a), fabs(b));
}
/** Finite precision comparison.
@param a first value to compare
@param b second value to compare
@return if the two values can be considered equal up to roundoff */
static bool EqualToRoundoff(float a, double b) {
return EqualToRoundoff(a, (float)b);
}
/** Finite precision comparison.
@param a first value to compare
@param b second value to compare
@return if the two values can be considered equal up to roundoff */
static bool EqualToRoundoff(double a, float b) {
return EqualToRoundoff((float)a, b);
}
protected: protected:
static Message localMsg; static Message localMsg;
static std::queue <Message*> Messages; static std::queue <Message*> Messages;
virtual void Debug(int from) {}; void Debug(int from) {};
static unsigned int frame; static unsigned int frame;
static unsigned int messageId; static unsigned int messageId;
static const double radtodeg; static const double radtodeg;
static const double degtorad; static const double degtorad;
static const double hptoftlbssec; static const double hptoftlbssec;
@ -245,6 +259,28 @@ protected:
static const string needed_cfg_version; static const string needed_cfg_version;
static const string JSBSim_version; static const string JSBSim_version;
}; };
/// Moments L, M, N
enum {eL = 1, eM, eN };
/// Rates P, Q, R
enum {eP = 1, eQ, eR };
/// Velocities U, V, W
enum {eU = 1, eV, eW };
/// Positions X, Y, Z
enum {eX = 1, eY, eZ };
/// Euler angles Phi, Theta, Psi
enum {ePhi = 1, eTht, ePsi };
/// Stability axis forces, Drag, Side force, Lift
enum {eDrag = 1, eSide, eLift };
/// Local frame orientation Roll, Pitch, Yaw
enum {eRoll = 1, ePitch, eYaw };
/// Local frame position North, East, Down
enum {eNorth = 1, eEast, eDown };
/// Locations Radius, Latitude, Longitude
enum {eLat = 1, eLong, eRad };
/// Conversion specifiers
enum {inNone = 0, inDegrees, inRadians, inMeters, inFeet };
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif #endif

View file

@ -60,10 +60,10 @@ CLASS IMPLEMENTATION
FGLGear::FGLGear(FGConfigFile* AC_cfg, FGFDMExec* fdmex) : Exec(fdmex) FGLGear::FGLGear(FGConfigFile* AC_cfg, FGFDMExec* fdmex) : Exec(fdmex)
{ {
string tmp; string tmp;
*AC_cfg >> tmp >> name >> vXYZ(1) >> vXYZ(2) >> vXYZ(3) *AC_cfg >> tmp >> name >> vXYZ(1) >> vXYZ(2) >> vXYZ(3)
>> kSpring >> bDamp>> dynamicFCoeff >> staticFCoeff >> kSpring >> bDamp>> dynamicFCoeff >> staticFCoeff
>> rollingFCoeff >> sSteerType >> sBrakeGroup >> rollingFCoeff >> sSteerType >> sBrakeGroup
>> maxSteerAngle >> sRetractable; >> maxSteerAngle >> sRetractable;
if (sBrakeGroup == "LEFT" ) eBrakeGrp = bgLeft; if (sBrakeGroup == "LEFT" ) eBrakeGrp = bgLeft;
@ -84,13 +84,13 @@ FGLGear::FGLGear(FGConfigFile* AC_cfg, FGFDMExec* fdmex) : Exec(fdmex)
cerr << "Improper steering type specification in config file: " cerr << "Improper steering type specification in config file: "
<< sSteerType << " is undefined." << endl; << sSteerType << " is undefined." << endl;
} }
if ( sRetractable == "RETRACT" ) { if ( sRetractable == "RETRACT" ) {
isRetractable = true; isRetractable = true;
} else { } else {
isRetractable = false; isRetractable = false;
} }
GearUp = false; GearUp = false;
GearDown = true; GearDown = true;
Servicable = true; Servicable = true;
@ -100,8 +100,8 @@ FGLGear::FGLGear(FGConfigFile* AC_cfg, FGFDMExec* fdmex) : Exec(fdmex)
State = Exec->GetState(); State = Exec->GetState();
Aircraft = Exec->GetAircraft(); Aircraft = Exec->GetAircraft();
Position = Exec->GetPosition(); Propagate = Exec->GetPropagate();
Rotation = Exec->GetRotation(); Auxiliary = Exec->GetAuxiliary();
FCS = Exec->GetFCS(); FCS = Exec->GetFCS();
MassBalance = Exec->GetMassBalance(); MassBalance = Exec->GetMassBalance();
@ -116,8 +116,8 @@ FGLGear::FGLGear(FGConfigFile* AC_cfg, FGFDMExec* fdmex) : Exec(fdmex)
SinkRate = GroundSpeed = 0.0; SinkRate = GroundSpeed = 0.0;
vWhlBodyVec = MassBalance->StructuralToBody(vXYZ); vWhlBodyVec = MassBalance->StructuralToBody(vXYZ);
vLocalGear = State->GetTb2l() * vWhlBodyVec; vLocalGear = Propagate->GetTb2l() * vWhlBodyVec;
compressLength = 0.0; compressLength = 0.0;
compressSpeed = 0.0; compressSpeed = 0.0;
@ -142,8 +142,8 @@ FGLGear::FGLGear(const FGLGear& lgear)
{ {
State = lgear.State; State = lgear.State;
Aircraft = lgear.Aircraft; Aircraft = lgear.Aircraft;
Position = lgear.Position; Propagate = lgear.Propagate;
Rotation = lgear.Rotation; Auxiliary = lgear.Auxiliary;
Exec = lgear.Exec; Exec = lgear.Exec;
FCS = lgear.FCS; FCS = lgear.FCS;
MassBalance = lgear.MassBalance; MassBalance = lgear.MassBalance;
@ -206,7 +206,6 @@ FGLGear::~FGLGear()
FGColumnVector3& FGLGear::Force(void) FGColumnVector3& FGLGear::Force(void)
{ {
double SteerGain = 0;
double SinWheel, CosWheel; double SinWheel, CosWheel;
double deltaSlip; double deltaSlip;
double deltaT = State->Getdt()*Aircraft->GetRate(); double deltaT = State->Getdt()*Aircraft->GetRate();
@ -228,19 +227,19 @@ FGColumnVector3& FGLGear::Force(void)
} else { } else {
GearUp = false; GearUp = false;
GearDown = true; GearDown = true;
} }
if (GearDown) { if (GearDown) {
vWhlBodyVec = MassBalance->StructuralToBody(vXYZ); vWhlBodyVec = MassBalance->StructuralToBody(vXYZ);
// vWhlBodyVec now stores the vector from the cg to this wheel // vWhlBodyVec now stores the vector from the cg to this wheel
vLocalGear = State->GetTb2l() * vWhlBodyVec; vLocalGear = Propagate->GetTb2l() * vWhlBodyVec;
// vLocalGear now stores the vector from the cg to the wheel in local coords. // vLocalGear now stores the vector from the cg to the wheel in local coords.
compressLength = vLocalGear(eZ) - Position->GetDistanceAGL(); compressLength = vLocalGear(eZ) - Propagate->GetDistanceAGL();
// The compression length is currently measured in the Z-axis, only, at this time. // The compression length is currently measured in the Z-axis, only, at this time.
// It should be measured along the strut axis. If the local-frame gear position // It should be measured along the strut axis. If the local-frame gear position
@ -262,8 +261,8 @@ FGColumnVector3& FGLGear::Force(void)
// (used for calculating damping force) is found by taking the Z-component of the // (used for calculating damping force) is found by taking the Z-component of the
// wheel velocity. // wheel velocity.
vWhlVelVec = State->GetTb2l() * (Rotation->GetPQR() * vWhlBodyVec); vWhlVelVec = Propagate->GetTb2l() * (Propagate->GetPQR() * vWhlBodyVec);
vWhlVelVec += Position->GetVel(); vWhlVelVec += Propagate->GetVel();
compressSpeed = vWhlVelVec(eZ); compressSpeed = vWhlVelVec(eZ);
// If this is the first time the wheel has made contact, remember some values // If this is the first time the wheel has made contact, remember some values
@ -272,13 +271,13 @@ FGColumnVector3& FGLGear::Force(void)
if (!FirstContact) { if (!FirstContact) {
FirstContact = true; FirstContact = true;
SinkRate = compressSpeed; SinkRate = compressSpeed;
GroundSpeed = Position->GetVel().Magnitude(); GroundSpeed = Propagate->GetVel().Magnitude();
TakeoffReported = false; TakeoffReported = false;
} }
// If the takeoff run is starting, initialize. // If the takeoff run is starting, initialize.
if ((Position->GetVel().Magnitude() > 0.1) && if ((Propagate->GetVel().Magnitude() > 0.1) &&
(FCS->GetBrake(bgLeft) == 0) && (FCS->GetBrake(bgLeft) == 0) &&
(FCS->GetBrake(bgRight) == 0) && (FCS->GetBrake(bgRight) == 0) &&
(FCS->GetThrottlePos(0) == 1) && !StartedGroundRun) (FCS->GetThrottlePos(0) == 1) && !StartedGroundRun)
@ -326,7 +325,7 @@ FGColumnVector3& FGLGear::Force(void)
switch (eSteerType) { switch (eSteerType) {
case stSteer: case stSteer:
SteerAngle = -maxSteerAngle * FCS->GetDrCmd() * 0.01745; SteerAngle = -maxSteerAngle * FCS->GetDrCmd() * 0.01745;
break; break;
case stFixed: case stFixed:
SteerAngle = 0.0; SteerAngle = 0.0;
@ -344,8 +343,8 @@ FGColumnVector3& FGLGear::Force(void)
// For now, steering angle is assumed to happen in the Local Z axis, // For now, steering angle is assumed to happen in the Local Z axis,
// not the strut axis as it should be. Will fix this later. // not the strut axis as it should be. Will fix this later.
SinWheel = sin(Rotation->Getpsi() + SteerAngle); SinWheel = sin(Propagate->Getpsi() + SteerAngle);
CosWheel = cos(Rotation->Getpsi() + SteerAngle); CosWheel = cos(Propagate->Getpsi() + SteerAngle);
RollingWhlVel = vWhlVelVec(eX)*CosWheel + vWhlVelVec(eY)*SinWheel; RollingWhlVel = vWhlVelVec(eX)*CosWheel + vWhlVelVec(eY)*SinWheel;
SideWhlVel = vWhlVelVec(eY)*CosWheel - vWhlVelVec(eX)*SinWheel; SideWhlVel = vWhlVelVec(eY)*CosWheel - vWhlVelVec(eX)*SinWheel;
@ -382,19 +381,19 @@ FGColumnVector3& FGLGear::Force(void)
{ {
WheelSlip = 0.0; WheelSlip = 0.0;
} }
*/ */
lastWheelSlip = WheelSlip; lastWheelSlip = WheelSlip;
// Compute the sideforce coefficients using similar assumptions to LaRCSim for now. // Compute the sideforce coefficients using similar assumptions to LaRCSim for now.
// Allow a maximum of 10 degrees tire slip angle before wheel slides. At that point, // Allow a maximum of 10 degrees tire slip angle before wheel slides. At that point,
// transition from static to dynamic friction. There are more complicated formulations // transition from static to dynamic friction. There are more complicated formulations
// of this that avoid the discrete jump. Will fix this later. // of this that avoid the discrete jump (similar to Pacejka). Will fix this later.
if (fabs(WheelSlip) <= 20.0) { if (fabs(WheelSlip) <= 20.0) {
FCoeff = staticFCoeff*WheelSlip/20.0; FCoeff = staticFCoeff*WheelSlip/20.0;
} else if (fabs(WheelSlip) <= 40.0) { } else if (fabs(WheelSlip) <= 40.0) {
// FCoeff = dynamicFCoeff*fabs(WheelSlip)/WheelSlip; // FCoeff = dynamicFCoeff*fabs(WheelSlip)/WheelSlip;
FCoeff = (dynamicFCoeff*(fabs(WheelSlip) - 20.0)/20.0 + FCoeff = (dynamicFCoeff*(fabs(WheelSlip) - 20.0)/20.0 +
staticFCoeff*(40.0 - fabs(WheelSlip))/20.0)*fabs(WheelSlip)/WheelSlip; staticFCoeff*(40.0 - fabs(WheelSlip))/20.0)*fabs(WheelSlip)/WheelSlip;
} else { } else {
FCoeff = dynamicFCoeff*fabs(WheelSlip)/WheelSlip; FCoeff = dynamicFCoeff*fabs(WheelSlip)/WheelSlip;
@ -441,14 +440,14 @@ FGColumnVector3& FGLGear::Force(void)
// Transform the forces back to the body frame and compute the moment. // Transform the forces back to the body frame and compute the moment.
vForce = State->GetTl2b() * vLocalForce; vForce = Propagate->GetTl2b() * vLocalForce;
vMoment = vWhlBodyVec * vForce; vMoment = vWhlBodyVec * vForce;
} else { // Gear is NOT compressed } else { // Gear is NOT compressed
WOW = false; WOW = false;
if (Position->GetDistanceAGL() > 200.0) { if (Propagate->GetDistanceAGL() > 200.0) {
FirstContact = false; FirstContact = false;
StartedGroundRun = false; StartedGroundRun = false;
LandingReported = false; LandingReported = false;
@ -459,19 +458,19 @@ FGColumnVector3& FGLGear::Force(void)
compressLength = 0.0; // reset compressLength to zero for data output validity compressLength = 0.0; // reset compressLength to zero for data output validity
} }
if (FirstContact) LandingDistanceTraveled += Position->GetVground()*deltaT; if (FirstContact) LandingDistanceTraveled += Auxiliary->GetVground()*deltaT;
if (StartedGroundRun) { if (StartedGroundRun) {
TakeoffDistanceTraveled50ft += Position->GetVground()*deltaT; TakeoffDistanceTraveled50ft += Auxiliary->GetVground()*deltaT;
if (WOW) TakeoffDistanceTraveled += Position->GetVground()*deltaT; if (WOW) TakeoffDistanceTraveled += Auxiliary->GetVground()*deltaT;
} }
if (ReportEnable && Position->GetVground() <= 0.05 && !LandingReported) { if (ReportEnable && Auxiliary->GetVground() <= 0.05 && !LandingReported) {
if (debug_lvl > 0) Report(erLand); if (debug_lvl > 0) Report(erLand);
} }
if (ReportEnable && !TakeoffReported && if (ReportEnable && !TakeoffReported &&
(vLocalGear(eZ) - Position->GetDistanceAGL()) < -50.0) (vLocalGear(eZ) - Propagate->GetDistanceAGL()) < -50.0)
{ {
if (debug_lvl > 0) Report(erTakeoff); if (debug_lvl > 0) Report(erTakeoff);
} }
@ -492,8 +491,8 @@ FGColumnVector3& FGLGear::Force(void)
PutMessage("Crash Detected: Simulation FREEZE."); PutMessage("Crash Detected: Simulation FREEZE.");
Exec->Freeze(); Exec->Freeze();
} }
} }
return vForce; return vForce;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View file

@ -44,9 +44,9 @@ INCLUDES
#include "FGJSBBase.h" #include "FGJSBBase.h"
#include "FGFDMExec.h" #include "FGFDMExec.h"
#include <string>
#include "FGConfigFile.h" #include "FGConfigFile.h"
#include "FGColumnVector3.h" #include "FGColumnVector3.h"
#include <string>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS DEFINITIONS
@ -61,11 +61,11 @@ FORWARD DECLARATIONS
namespace JSBSim { namespace JSBSim {
class FGAircraft; class FGAircraft;
class FGPosition; class FGPropagate;
class FGRotation;
class FGFCS; class FGFCS;
class FGState; class FGState;
class FGMassBalance; class FGMassBalance;
class FGAuxiliary;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DOCUMENTATION CLASS DOCUMENTATION
@ -160,9 +160,9 @@ CLASS DOCUMENTATION
@author Jon S. Berndt @author Jon S. Berndt
@version $Id$ @version $Id$
@see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at @see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
NASA-Ames", NASA CR-2497, January 1975 NASA-Ames", NASA CR-2497, January 1975
@see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics", @see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
Wiley & Sons, 1979 ISBN 0-471-03032-5 Wiley & Sons, 1979 ISBN 0-471-03032-5
@see W. A. Ragsdale, "A Generic Landing Gear Dynamics Model for LASRS++", @see W. A. Ragsdale, "A Generic Landing Gear Dynamics Model for LASRS++",
AIAA-2000-4303 AIAA-2000-4303
*/ */
@ -219,7 +219,7 @@ public:
inline double GetTirePressure(void) { return TirePressureNorm; } inline double GetTirePressure(void) { return TirePressureNorm; }
/// Sets the new normalized tire pressure /// Sets the new normalized tire pressure
inline void SetTirePressure(double p) { TirePressureNorm = p; } inline void SetTirePressure(double p) { TirePressureNorm = p; }
/// Sets the brake value in percent (0 - 100) /// Sets the brake value in percent (0 - 100)
inline void SetBrake(double bp) {brakePct = bp;} inline void SetBrake(double bp) {brakePct = bp;}
@ -231,10 +231,10 @@ public:
inline bool GetReport(void) { return ReportEnable; } inline bool GetReport(void) { return ReportEnable; }
inline double GetSteerAngle(void) { return SteerAngle;} inline double GetSteerAngle(void) { return SteerAngle;}
inline double GetstaticFCoeff(void) { return staticFCoeff;} inline double GetstaticFCoeff(void) { return staticFCoeff;}
inline int GetBrakeGroup(void) { return (int)eBrakeGrp; } inline int GetBrakeGroup(void) { return (int)eBrakeGrp; }
inline int GetSteerType(void) { return (int)eSteerType; } inline int GetSteerType(void) { return (int)eSteerType; }
inline bool GetRetractable(void) { return isRetractable; } inline bool GetRetractable(void) { return isRetractable; }
inline bool GetGearUnitUp(void) { return GearUp; } inline bool GetGearUnitUp(void) { return GearUp; }
inline bool GetGearUnitDown(void) { return GearDown; } inline bool GetGearUnitDown(void) { return GearDown; }
@ -244,7 +244,7 @@ public:
inline double GetBodyYForce(void) { return vLocalForce(eY); } inline double GetBodyYForce(void) { return vLocalForce(eY); }
inline double GetWheelSlipAngle(void) { return WheelSlip; } inline double GetWheelSlipAngle(void) { return WheelSlip; }
double GetWheelVel(int axis) { return vWhlVelVec(axis);} double GetWheelVel(int axis) { return vWhlVelVec(axis);}
private: private:
FGColumnVector3 vXYZ; FGColumnVector3 vXYZ;
FGColumnVector3 vMoment; FGColumnVector3 vMoment;
@ -288,17 +288,17 @@ private:
string sSteerType; string sSteerType;
string sBrakeGroup; string sBrakeGroup;
string sRetractable; string sRetractable;
BrakeGroup eBrakeGrp; BrakeGroup eBrakeGrp;
SteerType eSteerType; SteerType eSteerType;
double maxSteerAngle; double maxSteerAngle;
FGFDMExec* Exec; FGFDMExec* Exec;
FGState* State; FGState* State;
FGAircraft* Aircraft; FGAircraft* Aircraft;
FGPosition* Position; FGPropagate* Propagate;
FGRotation* Rotation; FGAuxiliary* Auxiliary;
FGFCS* FCS; FGFCS* FCS;
FGMassBalance* MassBalance; FGMassBalance* MassBalance;
void Report(ReportType rt); void Report(ReportType rt);
@ -306,13 +306,12 @@ private:
}; };
} }
#include "FGAircraft.h" #include "FGAircraft.h"
#include "FGPosition.h" #include "FGPropagate.h"
#include "FGRotation.h" #include "FGAuxiliary.h"
#include "FGFCS.h" #include "FGFCS.h"
#include "FGMassBalance.h" #include "FGMassBalance.h"
#include "FGState.h"
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#include "FGState.h"
#endif #endif

View file

@ -0,0 +1,216 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Module: FGLocation.cpp
Author: Jon S. Berndt
Date started: 04/04/2004
Purpose: Store an arbitrary location on the globe
------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------------
------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org.
FUNCTIONAL DESCRIPTION
------------------------------------------------------------------------------
This class encapsulates an arbitrary position in the globe with its accessors.
It has vector properties, so you can add multiply ....
HISTORY
------------------------------------------------------------------------------
04/04/2004 MF Created
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifdef FGFS
# include <simgear/compiler.h>
# ifdef SG_HAVE_STD_INCLUDES
# include <cmath>
# else
# include <math.h>
# endif
#else
# if defined(sgi) && !defined(__GNUC__)
# include <math.h>
# else
# include <cmath>
# endif
#endif
#include "FGLocation.h"
#include "FGPropertyManager.h"
namespace JSBSim {
static const char *IdSrc = "$Id$";
static const char *IdHdr = ID_LOCATION;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
FGLocation::FGLocation(double lon, double lat, double radius)
{
mCacheValid = false;
double sinLat = sin(lat);
double cosLat = cos(lat);
double sinLon = sin(lon);
double cosLon = cos(lon);
mECLoc = FGColumnVector3( radius*cosLat*cosLon,
radius*cosLat*sinLon,
radius*sinLat );
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGLocation::SetLongitude(double longitude)
{
double rtmp = sqrt(mECLoc(eX)*mECLoc(eX) + mECLoc(eY)*mECLoc(eY));
// Fast return if we are on the north or south pole ...
if (rtmp == 0.0)
return;
mCacheValid = false;
mECLoc(eX) = rtmp*sin(longitude);
mECLoc(eY) = rtmp*cos(longitude);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGLocation::SetLatitude(double latitude)
{
mCacheValid = false;
double r = mECLoc.Magnitude();
if (r == 0.0) {
mECLoc(eX) = 1.0;
r = 1.0;
}
double rtmp = sqrt(mECLoc(eX)*mECLoc(eX) + mECLoc(eY)*mECLoc(eY));
if (rtmp != 0.0) {
double fac = r/rtmp*cos(latitude);
mECLoc(eX) *= fac;
mECLoc(eY) *= fac;
} else {
mECLoc(eX) = r*cos(latitude);
mECLoc(eY) = 0.0;
}
mECLoc(eZ) = r*sin(latitude);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGLocation::SetRadius(double radius)
{
mCacheValid = false;
double rold = mECLoc.Magnitude();
if (rold == 0.0)
mECLoc(eX) = radius;
else
mECLoc *= radius/rold;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGLocation::ComputeDerivedUnconditional(void) const
{
// The radius is just the Euclidean norm of the vector.
mRadius = mECLoc.Magnitude();
// The distance of the location to the y-axis, which is the axis
// through the poles.
double rxy = sqrt(mECLoc(eX)*mECLoc(eX) + mECLoc(eY)*mECLoc(eY));
// Compute the sin/cos values of the longitude
double sinLon, cosLon;
if (rxy == 0.0) {
sinLon = 0.0;
cosLon = 1.0;
} else {
sinLon = mECLoc(eY)/rxy;
cosLon = mECLoc(eX)/rxy;
}
// Compute the sin/cos values of the latitude
double sinLat, cosLat;
if (mRadius == 0.0) {
sinLat = 0.0;
cosLat = 1.0;
} else {
sinLat = mECLoc(eZ)/mRadius;
cosLat = rxy/mRadius;
}
// Compute the longitude and latitude itself
if ( mECLoc( eX ) == 0.0 && mECLoc( eY ) == 0.0 )
mLon = 0.0;
else
mLon = atan2( mECLoc( eY ), mECLoc( eX ) );
if ( rxy == 0.0 && mECLoc( eZ ) == 0.0 )
mLat = 0.0;
else
mLat = atan2( mECLoc(eZ), rxy );
// Compute the transform matrices from and to the earth centered frame.
// see Durham Chapter 4, problem 1, page 52
mTec2l = FGMatrix33( -cosLon*sinLat, -sinLon*sinLat, cosLat,
-sinLon , cosLon , 0.0 ,
-cosLon*cosLat, -sinLon*cosLat, -sinLat );
mTl2ec = mTec2l.Transposed();
// Mark the cached values as valid
mCacheValid = true;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGLocation::bind(FGPropertyManager* PropertyManager, const string& prefix) const
{
PropertyManager->Tie(prefix + "lat-gc-rad", (FGLocation*)this,
&FGLocation::GetLatitude);
PropertyManager->Tie(prefix + "lat-gc-deg", (FGLocation*)this,
&FGLocation::GetLatitudeDeg);
PropertyManager->Tie(prefix + "long-gc-rad", (FGLocation*)this,
&FGLocation::GetLongitude);
PropertyManager->Tie(prefix + "long-gc-deg", (FGLocation*)this,
&FGLocation::GetLongitudeDeg);
PropertyManager->Tie(prefix + "radius-ft", (FGLocation*)this,
&FGLocation::GetRadius);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGLocation::unbind(FGPropertyManager* PropertyManager, const string& prefix) const
{
PropertyManager->Untie(prefix + "lat-gc-rad");
PropertyManager->Untie(prefix + "lat-gc-deg");
PropertyManager->Untie(prefix + "long-gc-rad");
PropertyManager->Untie(prefix + "long-gc-deg");
PropertyManager->Untie(prefix + "radius-ft");
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
} // namespace JSBSim

437
src/FDM/JSBSim/FGLocation.h Normal file
View file

@ -0,0 +1,437 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Header: FGLocation.h
Author: Jon S. Berndt, Mathias Froehlich
Date started: 04/04/2004
------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------------
------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org.
HISTORY
-------------------------------------------------------------------------------
04/04/2004 MF Created from code previously in the old positions class.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifndef FGLOCATION_H
#define FGLOCATION_H
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGJSBBase.h"
#include "FGPropertyManager.h"
#include "FGColumnVector3.h"
#include "FGMatrix33.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_LOCATION "$Id$"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
namespace JSBSim {
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Holds an arbitrary location in the earth centered reference frame.
This coordinate frame has its center in the middle of the earth.
Its x-axis points from the center of the earth towards a location
with zero latitude and longitude on the earths surface. The y-axis
points from the center of the earth towards a location with zero
latitude and 90deg longitude on the earths surface. The z-axis
points from the earths center to the geographic north pole.
This class provides access functions to set and get the location as
either the simple x, y and z values in ft or longitude/latitude and
the radial distance of the location from the earth center.
It is common to associate a parent frame with a location. This
frame is usually called the local horizontal frame or simply the local
frame. This frame has its x/y plane parallel to the surface of the earth
(with the assumption of a spherical earth). The x-axis points
towards north, the y-axis points towards east and the z-axis
points to the center of the earth.
Since this frame is determined by the location, this class also
provides the rotation matrices required to transform from the
earth centered frame to the local horizontal frame and back. There
are also conversion functions for conversion of position vectors
given in the one frame to positions in the other frame.
The earth centered reference frame is *NOT* an inertial frame
since it rotates with the earth.
The coordinates in the earth centered frame are the master values.
All other values are computed from these master values and are
cached as long as the location is changed by access through a
non-const member function. Values are cached to improve performance.
It is best practice to work with a natural set of master values.
Other parameters that are derived from these master values are calculated
only when needed, and IF they are needed and calculated, then they are
cached (stored and remembered) so they do not need to be re-calculated
until the master values they are derived from are themselves changed
(and become stale).
Accuracy and round off:
Given that we model a vehicle near the earth, the earths surface
radius is about 2*10^7, ft and that we use double values for the
representation of the location, we have an accuracy of about
1e-16*2e7ft/1=2e-9ft left. This should be sufficient for our needs.
Note that this is the same relative accuracy we would have when we
compute directly with lon/lat/radius. For the radius value this
is clear. For the lon/lat pair this is easy to see. Take for
example KSFO located at about 37.61deg north 122.35deg west, which
corresponds to 0.65642rad north and 2.13541rad west. Both values
are of magnitude of about 1. But 1ft corresponds to about
1/(2e7*2*pi)=7.9577e-09rad. So the left accuracy with this
representation is also about 1*1e-16/7.9577e-09=1.2566e-08 which
is of the same magnitude as the representation chosen here.
The advantage of this representation is that it is a linear space
without singularities. The singularities are the north and south
pole and most notably the non-steady jump at -pi to pi. It is
harder to track this jump correctly especially when we need to
work with error norms and derivatives of the equations of motion
within the time-stepping code. Also, the rate of change is of the
same magnitude for all components in this representation which is
an advantage for numerical stability in implicit time-stepping too.
@see W. C. Durham "Aircraft Dynamics & Control", section 2.2
@author Mathias Froehlich
@version $Id$
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGLocation : virtual FGJSBBase
{
public:
/** Default constructor. */
FGLocation() { mCacheValid = false; }
/** Constructor to set the longitude, latitude and the distance
from the center of the earth. */
FGLocation(double lon, double lat, double radius);
/** Copy constructor. */
FGLocation(const FGColumnVector3& lv)
: mECLoc(lv), mCacheValid(false) {}
/** Copy constructor. */
FGLocation(const FGLocation& l)
: mECLoc(l.mECLoc), mCacheValid(l.mCacheValid) {
if (!mCacheValid)
return;
mLon = l.mLon;
mLat = l.mLat;
mRadius = l.mRadius;
mTl2ec = l.mTl2ec;
mTec2l = l.mTec2l;
}
/** Get the longitude.
@return the longitude in rad of the location represented with this
class instance. The returned values are in the range between
-pi <= lon <= pi. Longitude is positive east and negative west. */
double GetLongitude() const { ComputeDerived(); return mLon; }
/** Get the longitude.
@return the longitude in deg of the location represented with this
class instance. The returned values are in the range between
-180 <= lon <= 180. Longitude is positive east and negative west. */
double GetLongitudeDeg() const { ComputeDerived(); return radtodeg*mLon; }
/** Set the longitude.
@param longitude Longitude in rad to set.
Sets the longitude of the location represented with this class
instance to the value of the given argument. The value is meant
to be in rad. The latitude and the radius value are preserved
with this call with the exception of radius being equal to
zero. If the radius is previously set to zero it is changed to be
equal to 1.0 past this call. Longitude is positive east and negative west. */
void SetLongitude(double longitude);
/** Get the sine of Longitude. */
double GetSinLongitude() const { ComputeDerived(); return -mTec2l(2,1); }
/** Get the cosine of Longitude. */
double GetCosLongitude() const { ComputeDerived(); return mTec2l(2,2); }
/** Get the latitude.
@return the latitude in rad of the location represented with this
class instance. The returned values are in the range between
-pi/2 <= lon <= pi/2. Latitude is positive north and negative south. */
double GetLatitude() const { ComputeDerived(); return mLat; }
/** Get the latitude.
@return the latitude in deg of the location represented with this
class instance. The returned values are in the range between
-90 <= lon <= 90. Latitude is positive north and negative south. */
double GetLatitudeDeg() const { ComputeDerived(); return radtodeg*mLat; }
/** Set the latitude.
@param latitude Latitude in rad to set.
Sets the latitude of the location represented with this class
instance to the value of the given argument. The value is meant
to be in rad. The longitude and the radius value are preserved
with this call with the exception of radius being equal to
zero. If the radius is previously set to zero it is changed to be
equal to 1.0 past this call.
Latitude is positive north and negative south.
The arguments should be within the bounds of -pi/2 <= lat <= pi/2.
The behavior of this function with arguments outside this range is
left as an exercise to the gentle reader ... */
void SetLatitude(double latitude);
/** Get the sine of Latitude. */
double GetSinLatitude() const { ComputeDerived(); return -mTec2l(3,3); }
/** Get the cosine of Latitude. */
double GetCosLatitude() const { ComputeDerived(); return mTec2l(1,3); }
/** Get the cosine of Latitude. */
double GetTanLatitude() const {
ComputeDerived();
double cLat = mTec2l(1,3);
if (cLat == 0.0)
return 0.0;
else
return -mTec2l(3,3)/cLat;
}
/** Get the distance from the center of the earth.
@return the distance of the location represented with this class
instance to the center of the earth in ft. The radius value is
always positive. */
double GetRadius() const { ComputeDerived(); return mRadius; }
/** Set the distance from the center of the earth.
@param radius Radius in ft to set.
Sets the radius of the location represented with this class
instance to the value of the given argument. The value is meant
to be in ft. The latitude and longitude values are preserved
with this call with the exception of radius being equal to
zero. If the radius is previously set to zero, latitude and
longitude is set equal to zero past this call.
The argument should be positive.
The behavior of this function called with a negative argument is
left as an exercise to the gentle reader ... */
void SetRadius(double radius);
/** Transform matrix from local horizontal to earth centered frame.
Returns a const reference to the rotation matrix of the transform from
the local horizontal frame to the earth centered frame. */
const FGMatrix33& GetTl2ec(void) const { ComputeDerived(); return mTl2ec; }
/** Transform matrix from the earth centered to local horizontal frame.
Returns a const reference to the rotation matrix of the transform from
the earth centered frame to the local horizontal frame. */
const FGMatrix33& GetTec2l(void) const { ComputeDerived(); return mTec2l; }
/** Conversion from Local frame coordinates to a location in the
earth centered and fixed frame.
@parm lvec Vector in the local horizontal coordinate frame
@return The location in the earth centered and fixed frame */
FGLocation LocalToLocation(const FGColumnVector3& lvec) const {
ComputeDerived(); return mTl2ec*lvec + mECLoc;
}
/** Conversion from a location in the earth centered and fixed frame
to local horizontal frame coordinates.
@parm ecvec Vector in the earth centered and fixed frame
@return The vector in the local horizontal coordinate frame */
FGColumnVector3 LocationToLocal(const FGColumnVector3& ecvec) const {
ComputeDerived(); return mTec2l*(ecvec - mECLoc);
}
// For time-stepping, locations have vector properties...
/** Read access the entries of the vector.
@param idx the component index.
Return the value of the matrix entry at the given index.
Indices are counted starting with 1.
Note that the index given in the argument is unchecked. */
double operator()(unsigned int idx) const { return Entry(idx); }
/** Write access the entries of the vector.
@param idx the component index.
@return a reference to the vector entry at the given index.
Indices are counted starting with 1.
Note that the index given in the argument is unchecked. */
double& operator()(unsigned int idx) { return Entry(idx); }
/** Read access the entries of the vector.
@param idx the component index.
@return the value of the matrix entry at the given index.
Indices are counted starting with 1.
This function is just a shortcut for the @ref double
operator()(unsigned int idx) const function. It is
used internally to access the elements in a more convenient way.
Note that the index given in the argument is unchecked. */
double Entry(unsigned int idx) const { return mECLoc.Entry(idx); }
/** Write access the entries of the vector.
@param idx the component index.
@return a reference to the vector entry at the given index.
Indices are counted starting with 1.
This function is just a shortcut for the double&
operator()(unsigned int idx) function. It is
used internally to access the elements in a more convenient way.
Note that the index given in the argument is unchecked. */
double& Entry(unsigned int idx) {
mCacheValid = false; return mECLoc.Entry(idx);
}
const FGLocation& operator=(const FGLocation& l) {
mECLoc = l.mECLoc;
mCacheValid = l.mCacheValid;
if (!mCacheValid)
return *this;
mLon = l.mLon;
mLat = l.mLat;
mRadius = l.mRadius;
mTl2ec = l.mTl2ec;
mTec2l = l.mTec2l;
return *this;
}
bool operator==(const FGLocation& l) const {
return mECLoc == l.mECLoc;
}
bool operator!=(const FGLocation& l) const { return ! operator==(l); }
const FGLocation& operator+=(const FGLocation &l) {
mCacheValid = false;
mECLoc += l.mECLoc;
return *this;
}
const FGLocation& operator-=(const FGLocation &l) {
mCacheValid = false;
mECLoc -= l.mECLoc;
return *this;
}
const FGLocation& operator*=(double scalar) {
mCacheValid = false;
mECLoc *= scalar;
return *this;
}
const FGLocation& operator/=(double scalar) {
return operator*=(1.0/scalar);
}
FGLocation operator+(const FGLocation& l) const {
return FGLocation(mECLoc + l.mECLoc);
}
FGLocation operator-(const FGLocation& l) const {
return FGLocation(mECLoc - l.mECLoc);
}
FGLocation operator*(double scalar) const {
return FGLocation(scalar*mECLoc);
}
/** Cast to a simple 3d vector */
operator const FGColumnVector3&() const {
return mECLoc;
}
/** Ties into the property tree.
Ties the variables represented by this class into the property tree. */
void bind(FGPropertyManager*, const string&) const;
/** Remove from property tree.
Unties the variables represented by this class into the property tree. */
void unbind(FGPropertyManager*, const string&) const;
private:
/** Computation of derived values.
This function re-computes the derived values like lat/lon and
transformation matrices. It does this unconditionally. */
void ComputeDerivedUnconditional(void) const;
/** Computation of derived values.
This function checks if the derived values like lat/lon and
transformation matrices are already computed. If so, it
returns. If they need to be computed this is done here. */
void ComputeDerived(void) const {
if (!mCacheValid)
ComputeDerivedUnconditional();
}
/** The coordinates in the earth centered frame. This is the master copy.
The coordinate frame has its center in the middle of the earth.
Its x-axis points from the center of the earth towards a
location with zero latitude and longitude on the earths
surface. The y-axis points from the center of the earth towards a
location with zero latitude and 90deg longitude on the earths
surface. The z-axis points from the earths center to the
geographic north pole.
@see W. C. Durham "Aircraft Dynamics & Control", section 2.2 */
FGColumnVector3 mECLoc;
/** The cached lon/lat/radius values. */
mutable double mLon;
mutable double mLat;
mutable double mRadius;
/** The cached rotation matrices from and to the associated frames. */
mutable FGMatrix33 mTl2ec;
mutable FGMatrix33 mTec2l;
/** A data validity flag.
This class implements caching of the derived values like the
orthogonal rotation matrices or the lon/lat/radius values. For caching we
carry a flag which signals if the values are valid or not.
The C++ keyword "mutable" tells the compiler that the data member is
allowed to change during a const member function. */
mutable bool mCacheValid;
};
/** Scalar multiplication.
@param scalar scalar value to multiply with.
@param l Vector to multiply.
Multiply the Vector with a scalar value. */
inline FGLocation operator*(double scalar, const FGLocation& l)
{
return l.operator*(scalar);
}
} // namespace JSBSim
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif

View file

@ -27,7 +27,7 @@
FUNCTIONAL DESCRIPTION FUNCTIONAL DESCRIPTION
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
This base class for the FGAero, FGRotational, etc. classes defines methods This base class for the FGAerodynamics, FGPropagate, etc. classes defines methods
common to all models. common to all models.
HISTORY HISTORY
@ -49,9 +49,7 @@ INCLUDES
#include "FGInertial.h" #include "FGInertial.h"
#include "FGGroundReactions.h" #include "FGGroundReactions.h"
#include "FGAircraft.h" #include "FGAircraft.h"
#include "FGTranslation.h" #include "FGPropagate.h"
#include "FGRotation.h"
#include "FGPosition.h"
#include "FGAuxiliary.h" #include "FGAuxiliary.h"
#include "FGOutput.h" #include "FGOutput.h"
@ -82,17 +80,15 @@ FGModel::FGModel(FGFDMExec* fdmex)
Inertial = 0; Inertial = 0;
GroundReactions = 0; GroundReactions = 0;
Aircraft = 0; Aircraft = 0;
Translation = 0; Propagate = 0;
Rotation = 0;
Position = 0;
Auxiliary = 0; Auxiliary = 0;
Output = 0; Output = 0;
//in order for FGModel derived classes to self-bind (that is, call //in order for FGModel derived classes to self-bind (that is, call
//their bind function in the constructor, the PropertyManager pointer //their bind function in the constructor, the PropertyManager pointer
//must be brought up now. //must be brought up now.
PropertyManager = FDMExec->GetPropertyManager(); PropertyManager = FDMExec->GetPropertyManager();
exe_ctr = 1; exe_ctr = 1;
rate = 1; rate = 1;
@ -119,12 +115,10 @@ bool FGModel::InitModel(void)
Inertial = FDMExec->GetInertial(); Inertial = FDMExec->GetInertial();
GroundReactions = FDMExec->GetGroundReactions(); GroundReactions = FDMExec->GetGroundReactions();
Aircraft = FDMExec->GetAircraft(); Aircraft = FDMExec->GetAircraft();
Translation = FDMExec->GetTranslation(); Propagate = FDMExec->GetPropagate();
Rotation = FDMExec->GetRotation();
Position = FDMExec->GetPosition();
Auxiliary = FDMExec->GetAuxiliary(); Auxiliary = FDMExec->GetAuxiliary();
Output = FDMExec->GetOutput(); Output = FDMExec->GetOutput();
if (!State || if (!State ||
!Atmosphere || !Atmosphere ||
!FCS || !FCS ||
@ -134,9 +128,7 @@ bool FGModel::InitModel(void)
!Inertial || !Inertial ||
!GroundReactions || !GroundReactions ||
!Aircraft || !Aircraft ||
!Translation || !Propagate ||
!Rotation ||
!Position ||
!Auxiliary || !Auxiliary ||
!Output) return(false); !Output) return(false);
else return(true); else return(true);

View file

@ -82,9 +82,7 @@ class FGAerodynamics;
class FGInertial; class FGInertial;
class FGGroundReactions; class FGGroundReactions;
class FGAircraft; class FGAircraft;
class FGTranslation; class FGPropagate;
class FGRotation;
class FGPosition;
class FGAuxiliary; class FGAuxiliary;
class FGOutput; class FGOutput;
class FGConfigFile; class FGConfigFile;
@ -114,7 +112,7 @@ public:
@param Config a pointer to the config file instance @param Config a pointer to the config file instance
@return true if model is successfully loaded*/ @return true if model is successfully loaded*/
virtual bool Load(FGConfigFile* Config) {return true;} virtual bool Load(FGConfigFile* Config) {return true;}
FGModel* NextModel; FGModel* NextModel;
string Name; string Name;
@ -125,13 +123,13 @@ public:
virtual bool InitModel(void); virtual bool InitModel(void);
virtual void SetRate(int tt) {rate = tt;} virtual void SetRate(int tt) {rate = tt;}
virtual int GetRate(void) {return rate;} virtual int GetRate(void) {return rate;}
void SetPropertyManager(FGPropertyManager *fgpm) { PropertyManager=fgpm;} void SetPropertyManager(FGPropertyManager *fgpm) { PropertyManager=fgpm;}
protected: protected:
int exe_ctr; int exe_ctr;
int rate; int rate;
virtual void Debug(int from); virtual void Debug(int from);
FGFDMExec* FDMExec; FGFDMExec* FDMExec;
@ -144,9 +142,7 @@ protected:
FGInertial* Inertial; FGInertial* Inertial;
FGGroundReactions* GroundReactions; FGGroundReactions* GroundReactions;
FGAircraft* Aircraft; FGAircraft* Aircraft;
FGTranslation* Translation; FGPropagate* Propagate;
FGRotation* Rotation;
FGPosition* Position;
FGAuxiliary* Auxiliary; FGAuxiliary* Auxiliary;
FGOutput* Output; FGOutput* Output;
FGPropertyManager* PropertyManager; FGPropertyManager* PropertyManager;

View file

@ -35,12 +35,7 @@ HISTORY
INCLUDES INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifdef FGFS #include <sstream>
# include <simgear/compiler.h>
# include STL_ALGORITHM
#else
# include <algorithm>
#endif
#include "FGNozzle.h" #include "FGNozzle.h"
#include "FGAtmosphere.h" #include "FGAtmosphere.h"
@ -104,6 +99,28 @@ double FGNozzle::GetPowerRequired(void)
return PE; return PE;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGNozzle::GetThrusterLabels(int id)
{
std::ostringstream buf;
buf << Name << "_Thrust[" << id << ']';
return buf.str();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGNozzle::GetThrusterValues(int id)
{
std::ostringstream buf;
buf << Thrust;
return buf.str();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows: // The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print // unset: In this case (the default) JSBSim would only print

View file

@ -75,7 +75,9 @@ public:
double Calculate(double CfPc); double Calculate(double CfPc);
double GetPowerRequired(void); double GetPowerRequired(void);
string GetThrusterLabels(int id);
string GetThrusterValues(int id);
private: private:
double ReverserAngle; double ReverserAngle;
double PE; double PE;

View file

@ -47,12 +47,12 @@ INCLUDES
#include "FGGroundReactions.h" #include "FGGroundReactions.h"
#include "FGAircraft.h" #include "FGAircraft.h"
#include "FGMassBalance.h" #include "FGMassBalance.h"
#include "FGTranslation.h" #include "FGPropagate.h"
#include "FGRotation.h"
#include "FGPosition.h"
#include "FGAuxiliary.h" #include "FGAuxiliary.h"
#include "FGInertial.h" #include "FGInertial.h"
#include <iomanip>
namespace JSBSim { namespace JSBSim {
static const char *IdSrc = "$Id$"; static const char *IdSrc = "$Id$";
@ -91,22 +91,17 @@ FGOutput::~FGOutput()
bool FGOutput::Run(void) bool FGOutput::Run(void)
{ {
if (enabled) { if (enabled) {
if (!FGModel::Run()) { if (FGModel::Run()) return true;
if (Type == otSocket) {
if (Type == otSocket) { SocketOutput();
SocketOutput(); } else if (Type == otCSV) {
} else if (Type == otCSV) { DelimitedOutput(Filename);
DelimitedOutput(Filename); } else if (Type == otTerminal) {
} else if (Type == otTerminal) { // Not done yet
// Not done yet } else if (Type == otNone) {
} else if (Type == otNone) { // Do nothing
// Do nothing
} else {
// Not a valid type of output
}
return false;
} else { } else {
return true; // Not a valid type of output
} }
} }
return false; return false;
@ -180,10 +175,7 @@ void FGOutput::DelimitedOutput(string fname)
outstream << ", "; outstream << ", ";
outstream << "Drag, Side, Lift, "; outstream << "Drag, Side, Lift, ";
outstream << "L/D, "; outstream << "L/D, ";
outstream << "Xforce, Yforce, Zforce, "; outstream << "Xforce, Yforce, Zforce";
outstream << "xGravity, yGravity, zGravity, ";
outstream << "xCoriolis, yCoriolis, zCoriolis, ";
outstream << "xCentrifugal, yCentrifugal, zCentrifugal";
} }
if (SubSystems & ssMoments) { if (SubSystems & ssMoments) {
outstream << ", "; outstream << ", ";
@ -208,14 +200,14 @@ void FGOutput::DelimitedOutput(string fname)
outstream << "Mass, "; outstream << "Mass, ";
outstream << "Xcg, Ycg, Zcg"; outstream << "Xcg, Ycg, Zcg";
} }
if (SubSystems & ssPosition) { if (SubSystems & ssPropagate) {
outstream << ", "; outstream << ", ";
outstream << "Altitude, "; outstream << "Altitude, ";
outstream << "Phi, Tht, Psi, "; outstream << "Phi, Tht, Psi, ";
outstream << "Alpha, "; outstream << "Alpha, ";
outstream << "Beta, "; outstream << "Beta, ";
outstream << "Latitude, "; outstream << "Latitude (Deg), ";
outstream << "Longitude, "; outstream << "Longitude (Deg), ";
outstream << "Distance AGL, "; outstream << "Distance AGL, ";
outstream << "Runway Radius"; outstream << "Runway Radius";
} }
@ -262,25 +254,22 @@ void FGOutput::DelimitedOutput(string fname)
} }
if (SubSystems & ssRates) { if (SubSystems & ssRates) {
outstream << ", "; outstream << ", ";
outstream << Rotation->GetPQR() << ", "; outstream << Propagate->GetPQR() << ", ";
outstream << Rotation->GetPQRdot(); outstream << Propagate->GetPQRdot();
} }
if (SubSystems & ssVelocities) { if (SubSystems & ssVelocities) {
outstream << ", "; outstream << ", ";
outstream << Translation->Getqbar() << ", "; outstream << Auxiliary->Getqbar() << ", ";
outstream << Translation->GetVt() << ", "; outstream << setprecision(12) << Auxiliary->GetVt() << ", ";
outstream << Translation->GetUVW() << ", "; outstream << setprecision(12) << Propagate->GetUVW() << ", ";
outstream << Translation->GetAeroUVW() << ", "; outstream << Auxiliary->GetAeroUVW() << ", ";
outstream << Position->GetVel(); outstream << Propagate->GetVel();
} }
if (SubSystems & ssForces) { if (SubSystems & ssForces) {
outstream << ", "; outstream << ", ";
outstream << Aerodynamics->GetvFs() << ", "; outstream << Aerodynamics->GetvFs() << ", ";
outstream << Aerodynamics->GetLoD() << ", "; outstream << Aerodynamics->GetLoD() << ", ";
outstream << Aircraft->GetForces() << ", "; outstream << Aircraft->GetForces();
outstream << Inertial->GetGravity() << ", ";
outstream << Inertial->GetCoriolis() << ", ";
outstream << Inertial->GetCentrifugal();
} }
if (SubSystems & ssMoments) { if (SubSystems & ssMoments) {
outstream << ", "; outstream << ", ";
@ -297,16 +286,16 @@ void FGOutput::DelimitedOutput(string fname)
outstream << MassBalance->GetMass() << ", "; outstream << MassBalance->GetMass() << ", ";
outstream << MassBalance->GetXYZcg(); outstream << MassBalance->GetXYZcg();
} }
if (SubSystems & ssPosition) { if (SubSystems & ssPropagate) {
outstream << ", "; outstream << ", ";
outstream << Position->Geth() << ", "; outstream << Propagate->Geth() << ", ";
outstream << Rotation->GetEuler() << ", "; outstream << Propagate->GetEuler() << ", ";
outstream << Translation->Getalpha() << ", "; outstream << Auxiliary->Getalpha(inDegrees) << ", ";
outstream << Translation->Getbeta() << ", "; outstream << Auxiliary->Getbeta(inDegrees) << ", ";
outstream << Position->GetLatitude() << ", "; outstream << Propagate->GetLocation().GetLatitudeDeg() << ", ";
outstream << Position->GetLongitude() << ", "; outstream << Propagate->GetLocation().GetLongitudeDeg() << ", ";
outstream << Position->GetDistanceAGL() << ", "; outstream << Propagate->GetDistanceAGL() << ", ";
outstream << Position->GetRunwayRadius(); outstream << Propagate->GetRunwayRadius();
} }
if (SubSystems & ssCoefficients) { if (SubSystems & ssCoefficients) {
scratch = Aerodynamics->GetCoefficientValues(); scratch = Aerodynamics->GetCoefficientValues();
@ -373,8 +362,8 @@ void FGOutput::SocketOutput(void)
socket->Append("Fx"); socket->Append("Fx");
socket->Append("Fy"); socket->Append("Fy");
socket->Append("Fz"); socket->Append("Fz");
socket->Append("Latitude"); socket->Append("Latitude (Deg)");
socket->Append("Longitude"); socket->Append("Longitude (Deg)");
socket->Append("QBar"); socket->Append("QBar");
socket->Append("Alpha"); socket->Append("Alpha");
socket->Append("L"); socket->Append("L");
@ -391,37 +380,37 @@ void FGOutput::SocketOutput(void)
socket->Clear(); socket->Clear();
socket->Append(State->Getsim_time()); socket->Append(State->Getsim_time());
socket->Append(Position->Geth()); socket->Append(Propagate->Geth());
socket->Append(Rotation->Getphi()); socket->Append(Propagate->Getphi());
socket->Append(Rotation->Gettht()); socket->Append(Propagate->Gettht());
socket->Append(Rotation->Getpsi()); socket->Append(Propagate->Getpsi());
socket->Append(Atmosphere->GetDensity()); socket->Append(Atmosphere->GetDensity());
socket->Append(Translation->GetVt()); socket->Append(Auxiliary->GetVt());
socket->Append(Translation->GetUVW(eU)); socket->Append(Propagate->GetUVW(eU));
socket->Append(Translation->GetUVW(eV)); socket->Append(Propagate->GetUVW(eV));
socket->Append(Translation->GetUVW(eW)); socket->Append(Propagate->GetUVW(eW));
socket->Append(Translation->GetAeroUVW(eU)); socket->Append(Auxiliary->GetAeroUVW(eU));
socket->Append(Translation->GetAeroUVW(eV)); socket->Append(Auxiliary->GetAeroUVW(eV));
socket->Append(Translation->GetAeroUVW(eW)); socket->Append(Auxiliary->GetAeroUVW(eW));
socket->Append(Position->GetVn()); socket->Append(Propagate->GetVel(eNorth));
socket->Append(Position->GetVe()); socket->Append(Propagate->GetVel(eEast));
socket->Append(Position->GetVd()); socket->Append(Propagate->GetVel(eDown));
socket->Append(Translation->GetUVWdot(eU)); socket->Append(Propagate->GetUVWdot(eU));
socket->Append(Translation->GetUVWdot(eV)); socket->Append(Propagate->GetUVWdot(eV));
socket->Append(Translation->GetUVWdot(eW)); socket->Append(Propagate->GetUVWdot(eW));
socket->Append(Rotation->GetPQR(eP)); socket->Append(Propagate->GetPQR(eP));
socket->Append(Rotation->GetPQR(eQ)); socket->Append(Propagate->GetPQR(eQ));
socket->Append(Rotation->GetPQR(eR)); socket->Append(Propagate->GetPQR(eR));
socket->Append(Rotation->GetPQRdot(eP)); socket->Append(Propagate->GetPQRdot(eP));
socket->Append(Rotation->GetPQRdot(eQ)); socket->Append(Propagate->GetPQRdot(eQ));
socket->Append(Rotation->GetPQRdot(eR)); socket->Append(Propagate->GetPQRdot(eR));
socket->Append(Aircraft->GetForces(eX)); socket->Append(Aircraft->GetForces(eX));
socket->Append(Aircraft->GetForces(eY)); socket->Append(Aircraft->GetForces(eY));
socket->Append(Aircraft->GetForces(eZ)); socket->Append(Aircraft->GetForces(eZ));
socket->Append(Position->GetLatitude()); socket->Append(Propagate->GetLocation().GetLatitudeDeg());
socket->Append(Position->GetLongitude()); socket->Append(Propagate->GetLocation().GetLongitudeDeg());
socket->Append(Translation->Getqbar()); socket->Append(Auxiliary->Getqbar());
socket->Append(Translation->Getalpha()); socket->Append(Auxiliary->Getalpha(inDegrees));
socket->Append(Aircraft->GetMoments(eL)); socket->Append(Aircraft->GetMoments(eL));
socket->Append(Aircraft->GetMoments(eM)); socket->Append(Aircraft->GetMoments(eM));
socket->Append(Aircraft->GetMoments(eN)); socket->Append(Aircraft->GetMoments(eN));
@ -456,6 +445,7 @@ bool FGOutput::Load(FGConfigFile* AC_cfg)
int OutRate = 0; int OutRate = 0;
FGConfigFile* Output_cfg; FGConfigFile* Output_cfg;
string property; string property;
unsigned int port;
# ifndef macintosh # ifndef macintosh
separator = "/"; separator = "/";
@ -466,13 +456,13 @@ bool FGOutput::Load(FGConfigFile* AC_cfg)
name = AC_cfg->GetValue("NAME"); name = AC_cfg->GetValue("NAME");
fname = AC_cfg->GetValue("FILE"); fname = AC_cfg->GetValue("FILE");
token = AC_cfg->GetValue("TYPE"); token = AC_cfg->GetValue("TYPE");
port = atoi(AC_cfg->GetValue("PORT").c_str());
Output->SetType(token); Output->SetType(token);
#if defined( FG_WITH_JSBSIM_SOCKET ) || !defined( FGFS )
if (token == "SOCKET") { if (token == "SOCKET") {
socket = new FGfdmSocket("localhost",1138); socket = new FGfdmSocket(name,port);
} }
#endif
if (!fname.empty()) { if (!fname.empty()) {
outputInFileName = FDMExec->GetAircraftPath() + separator outputInFileName = FDMExec->GetAircraftPath() + separator
@ -526,7 +516,7 @@ bool FGOutput::Load(FGConfigFile* AC_cfg)
} }
if (parameter == "POSITION") { if (parameter == "POSITION") {
*Output_cfg >> parameter; *Output_cfg >> parameter;
if (parameter == "ON") SubSystems += ssPosition; if (parameter == "ON") SubSystems += ssPropagate;
} }
if (parameter == "COEFFICIENTS") { if (parameter == "COEFFICIENTS") {
*Output_cfg >> parameter; *Output_cfg >> parameter;
@ -618,10 +608,14 @@ void FGOutput::Debug(int from)
if (SubSystems & ssAtmosphere) cout << " Atmosphere parameters logged" << endl; if (SubSystems & ssAtmosphere) cout << " Atmosphere parameters logged" << endl;
if (SubSystems & ssMassProps) cout << " Mass parameters logged" << endl; if (SubSystems & ssMassProps) cout << " Mass parameters logged" << endl;
if (SubSystems & ssCoefficients) cout << " Coefficient parameters logged" << endl; if (SubSystems & ssCoefficients) cout << " Coefficient parameters logged" << endl;
if (SubSystems & ssPosition) cout << " Position parameters logged" << endl; if (SubSystems & ssPropagate) cout << " Propagate parameters logged" << endl;
if (SubSystems & ssGroundReactions) cout << " Ground parameters logged" << endl; if (SubSystems & ssGroundReactions) cout << " Ground parameters logged" << endl;
if (SubSystems & ssFCS) cout << " FCS parameters logged" << endl; if (SubSystems & ssFCS) cout << " FCS parameters logged" << endl;
if (SubSystems & ssPropulsion) cout << " Propulsion parameters logged" << endl; if (SubSystems & ssPropulsion) cout << " Propulsion parameters logged" << endl;
if (OutputProperties.size() > 0) cout << " Properties logged:" << endl;
for (unsigned int i=0;i<OutputProperties.size();i++) {
cout << " - " << OutputProperties[i]->GetName() << endl;
}
} }
} }
if (debug_lvl & 2 ) { // Instantiation/Destruction notification if (debug_lvl & 2 ) { // Instantiation/Destruction notification

View file

@ -73,7 +73,50 @@ CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Handles simulation output. /** Handles simulation output.
*/ OUTPUT section definition
The following specifies the way that JSBSim writes out data.
NAME is the filename you want the output to go to
TYPE can be:
CSV Comma separated data. If a filename is supplied then the data
goes to that file. If COUT or cout is specified, the data goes
to stdout. If the filename is a null filename the data goes to
stdout, as well.
SOCKET Will eventually send data to a socket output, where NAME
would then be the IP address of the machine the data should be
sent to. DON'T USE THIS YET!
TABULAR Columnar data. NOT IMPLEMENTED YET!
TERMINAL Output to terminal. NOT IMPLEMENTED YET!
NONE Specifies to do nothing. THis setting makes it easy to turn on and
off the data output without having to mess with anything else.
The arguments that can be supplied, currently, are
RATE_IN_HZ An integer rate in times-per-second that the data is output. This
value may not be *exactly* what you want, due to the dependence
on dt, the cycle rate for the FDM.
The following parameters tell which subsystems of data to output:
SIMULATION ON|OFF
ATMOSPHERE ON|OFF
MASSPROPS ON|OFF
AEROSURFACES ON|OFF
RATES ON|OFF
VELOCITIES ON|OFF
FORCES ON|OFF
MOMENTS ON|OFF
POSITION ON|OFF
COEFFICIENTS ON|OFF
GROUND_REACTIONS ON|OFF
FCS ON|OFF
PROPULSION ON|OFF
NOTE that Time is always output with the data.
@version $Id$
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DECLARATION CLASS DECLARATION
@ -109,7 +152,7 @@ public:
/** Subsystem: Atmosphere (= 64) */ ssAtmosphere = 64, /** Subsystem: Atmosphere (= 64) */ ssAtmosphere = 64,
/** Subsystem: Mass Properties (= 128) */ ssMassProps = 128, /** Subsystem: Mass Properties (= 128) */ ssMassProps = 128,
/** Subsystem: Coefficients (= 256) */ ssCoefficients = 256, /** Subsystem: Coefficients (= 256) */ ssCoefficients = 256,
/** Subsystem: Position (= 512) */ ssPosition = 512, /** Subsystem: Propagate (= 512) */ ssPropagate = 512,
/** Subsystem: Ground Reactions (= 1024) */ ssGroundReactions = 1024, /** Subsystem: Ground Reactions (= 1024) */ ssGroundReactions = 1024,
/** Subsystem: FCS (= 2048) */ ssFCS = 2048, /** Subsystem: FCS (= 2048) */ ssFCS = 2048,
/** Subsystem: Propulsion (= 4096) */ ssPropulsion = 4096 /** Subsystem: Propulsion (= 4096) */ ssPropulsion = 4096

View file

@ -39,8 +39,11 @@ HISTORY
INCLUDES INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include <sstream>
#include "FGPiston.h" #include "FGPiston.h"
#include "FGPropulsion.h" #include "FGPropulsion.h"
#include "FGPropeller.h"
namespace JSBSim { namespace JSBSim {
@ -67,6 +70,9 @@ FGPiston::FGPiston(FGFDMExec* exec, FGConfigFile* Eng_cfg) : FGEngine(exec),
MinManifoldPressure_inHg = 6.5; MinManifoldPressure_inHg = 6.5;
MaxManifoldPressure_inHg = 28.5; MaxManifoldPressure_inHg = 28.5;
ManifoldPressure_inHg = Atmosphere->GetPressure() * psftoinhg; // psf to in Hg ManifoldPressure_inHg = Atmosphere->GetPressure() * psftoinhg; // psf to in Hg
minMAP = 21950;
maxMAP = 96250;
MAP = Atmosphere->GetPressure() * 47.88; // psf to Pa
CylinderHeadTemp_degK = 0.0; CylinderHeadTemp_degK = 0.0;
Displacement = 360; Displacement = 360;
MaxHP = 200; MaxHP = 200;
@ -78,6 +84,25 @@ FGPiston::FGPiston(FGFDMExec* exec, FGConfigFile* Eng_cfg) : FGEngine(exec),
dt = State->Getdt(); dt = State->Getdt();
// Supercharging
BoostSpeeds = 0; // Default to no supercharging
BoostSpeed = 0;
Boosted = false;
BoostOverride = 0;
bBoostOverride = false;
bTakeoffBoost = false;
TakeoffBoost = 0.0; // Default to no extra takeoff-boost
int i;
for(i=0; i<FG_MAX_BOOST_SPEEDS; ++i) {
RatedBoost[i] = 0.0;
RatedPower[i] = 0.0;
RatedAltitude[i] = 0.0;
BoostMul[i] = 1.0;
RatedMAP[i] = 100000;
RatedRPM[i] = 2500;
TakeoffMAP[i] = 100000;
}
// Initialisation // Initialisation
volumetric_efficiency = 0.8; // Actually f(speed, load) but this will get us running volumetric_efficiency = 0.8; // Actually f(speed, load) but this will get us running
@ -123,9 +148,79 @@ FGPiston::FGPiston(FGFDMExec* exec, FGConfigFile* Eng_cfg) : FGEngine(exec),
else if (token == "IDLERPM") *Eng_cfg >> IdleRPM; else if (token == "IDLERPM") *Eng_cfg >> IdleRPM;
else if (token == "MAXTHROTTLE") *Eng_cfg >> MaxThrottle; else if (token == "MAXTHROTTLE") *Eng_cfg >> MaxThrottle;
else if (token == "MINTHROTTLE") *Eng_cfg >> MinThrottle; else if (token == "MINTHROTTLE") *Eng_cfg >> MinThrottle;
else if (token == "NUMBOOSTSPEEDS") *Eng_cfg >> BoostSpeeds;
else if (token == "BOOSTOVERRIDE") *Eng_cfg >> BoostOverride;
else if (token == "TAKEOFFBOOST") *Eng_cfg >> TakeoffBoost;
else if (token == "RATEDBOOST1") *Eng_cfg >> RatedBoost[0];
else if (token == "RATEDBOOST2") *Eng_cfg >> RatedBoost[1];
else if (token == "RATEDBOOST3") *Eng_cfg >> RatedBoost[2];
else if (token == "RATEDPOWER1") *Eng_cfg >> RatedPower[0];
else if (token == "RATEDPOWER2") *Eng_cfg >> RatedPower[1];
else if (token == "RATEDPOWER3") *Eng_cfg >> RatedPower[2];
else if (token == "RATEDRPM1") *Eng_cfg >> RatedRPM[0];
else if (token == "RATEDRPM2") *Eng_cfg >> RatedRPM[1];
else if (token == "RATEDRPM3") *Eng_cfg >> RatedRPM[2];
else if (token == "RATEDALTITUDE1") *Eng_cfg >> RatedAltitude[0];
else if (token == "RATEDALTITUDE2") *Eng_cfg >> RatedAltitude[1];
else if (token == "RATEDALTITUDE3") *Eng_cfg >> RatedAltitude[2];
else cerr << "Unhandled token in Engine config file: " << token << endl; else cerr << "Unhandled token in Engine config file: " << token << endl;
} }
minMAP = MinManifoldPressure_inHg * 3376.85; // inHg to Pa
maxMAP = MaxManifoldPressure_inHg * 3376.85;
// Set up and sanity-check the turbo/supercharging configuration based on the input values.
if(TakeoffBoost > RatedBoost[0]) bTakeoffBoost = true;
for(i=0; i<BoostSpeeds; ++i) {
bool bad = false;
if(RatedBoost[i] <= 0.0) bad = true;
if(RatedPower[i] <= 0.0) bad = true;
if(RatedAltitude[i] < 0.0) bad = true; // 0.0 is deliberately allowed - this corresponds to unregulated supercharging.
if(i > 0 && RatedAltitude[i] < RatedAltitude[i - 1]) bad = true;
if(bad) {
// We can't recover from the above - don't use this supercharger speed.
BoostSpeeds--;
// TODO - put out a massive error message!
break;
}
// Now sanity-check stuff that is recoverable.
if(i < BoostSpeeds - 1) {
if(BoostSwitchAltitude[i] < RatedAltitude[i]) {
// TODO - put out an error message
// But we can also make a reasonable estimate, as below.
BoostSwitchAltitude[i] = RatedAltitude[i] + 1000;
}
BoostSwitchPressure[i] = Atmosphere->GetPressure(BoostSwitchAltitude[i]) * 47.88;
//cout << "BoostSwitchAlt = " << BoostSwitchAltitude[i] << ", pressure = " << BoostSwitchPressure[i] << '\n';
// Assume there is some hysteresis on the supercharger gear switch, and guess the value for now
BoostSwitchHysteresis = 1000;
}
// Now work out the supercharger pressure multiplier of this speed from the rated boost and altitude.
RatedMAP[i] = Atmosphere->GetPressureSL() * 47.88 + RatedBoost[i] * 6895; // psf*47.88 = Pa, psi*6895 = Pa.
// Sometimes a separate BCV setting for takeoff or extra power is fitted.
if(TakeoffBoost > RatedBoost[0]) {
// Assume that the effect on the BCV is the same whichever speed is in use.
TakeoffMAP[i] = RatedMAP[i] + ((TakeoffBoost - RatedBoost[0]) * 6895);
bTakeoffBoost = true;
} else {
TakeoffMAP[i] = RatedMAP[i];
bTakeoffBoost = false;
}
BoostMul[i] = RatedMAP[i] / (Atmosphere->GetPressure(RatedAltitude[i]) * 47.88);
// TODO - get rid of the debugging output before sending it to Jon
//cout << "Speed " << i+1 << '\n';
//cout << "BoostMul = " << BoostMul[i] << ", RatedMAP = " << RatedMAP[i] << ", TakeoffMAP = " << TakeoffMAP[i] << '\n';
}
if(BoostSpeeds > 0) {
Boosted = true;
BoostSpeed = 0;
}
bBoostOverride = (BoostOverride == 1 ? true : false);
//cout << "Engine is " << (Boosted ? "supercharged" : "naturally aspirated") << '\n';
Debug(0); // Call Debug() routine from constructor if needed Debug(0); // Call Debug() routine from constructor if needed
} }
@ -138,7 +233,7 @@ FGPiston::~FGPiston()
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGPiston::Calculate(double PowerRequired) double FGPiston::Calculate(void)
{ {
if (FuelFlow_gph > 0.0) ConsumeFuel(); if (FuelFlow_gph > 0.0) ConsumeFuel();
@ -149,19 +244,19 @@ double FGPiston::Calculate(double PowerRequired)
// Input values. // Input values.
// //
p_amb = Atmosphere->GetPressure() * 48; // convert from lbs/ft2 to Pa p_amb = Atmosphere->GetPressure() * 47.88; // convert from lbs/ft2 to Pa
p_amb_sea_level = Atmosphere->GetPressureSL() * 48; p_amb_sea_level = Atmosphere->GetPressureSL() * 47.88;
T_amb = Atmosphere->GetTemperature() * (5.0 / 9.0); // convert from Rankine to Kelvin T_amb = Atmosphere->GetTemperature() * (5.0 / 9.0); // convert from Rankine to Kelvin
RPM = Propulsion->GetThruster(EngineNumber)->GetRPM() * RPM = Thruster->GetRPM() * Thruster->GetGearRatio();
Propulsion->GetThruster(EngineNumber)->GetGearRatio();
IAS = Auxiliary->GetVcalibratedKTS(); IAS = Auxiliary->GetVcalibratedKTS();
doEngineStartup(); doEngineStartup();
doManifoldPressure(); if(Boosted) doBoostControl();
doAirFlow(); doMAP();
doFuelFlow(); doAirFlow();
doFuelFlow();
//Now that the fuel flow is done check if the mixture is too lean to run the engine //Now that the fuel flow is done check if the mixture is too lean to run the engine
//Assume lean limit at 22 AFR for now - thats a thi of 0.668 //Assume lean limit at 22 AFR for now - thats a thi of 0.668
@ -171,13 +266,18 @@ double FGPiston::Calculate(double PowerRequired)
Running = false; Running = false;
doEnginePower(); doEnginePower();
doEGT(); doEGT();
doCHT(); doCHT();
doOilTemperature(); doOilTemperature();
doOilPressure(); doOilPressure();
PowerAvailable = (HP * hptoftlbssec) - PowerRequired; if (Thruster->GetType() == FGThruster::ttPropeller) {
return PowerAvailable; ((FGPropeller*)Thruster)->SetAdvance(FCS->GetPropAdvance(EngineNumber));
}
PowerAvailable = (HP * hptoftlbssec) - Thruster->GetPowerRequired();
return Thruster->Calculate(PowerAvailable);
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -187,7 +287,7 @@ double FGPiston::Calculate(double PowerRequired)
void FGPiston::doEngineStartup(void) void FGPiston::doEngineStartup(void)
{ {
// Check parameters that may alter the operating state of the engine. // Check parameters that may alter the operating state of the engine.
// (spark, fuel, starter motor etc) // (spark, fuel, starter motor etc)
bool spark; bool spark;
bool fuel; bool fuel;
@ -205,7 +305,7 @@ void FGPiston::doEngineStartup(void)
} else { } else {
spark = false; spark = false;
} // neglects battery voltage, master on switch, etc for now. } // neglects battery voltage, master on switch, etc for now.
if ((Magnetos == 1) || (Magnetos > 2)) Magneto_Left = true; if ((Magnetos == 1) || (Magnetos > 2)) Magneto_Left = true;
if (Magnetos > 1) Magneto_Right = true; if (Magnetos > 1) Magneto_Right = true;
@ -221,7 +321,7 @@ void FGPiston::doEngineStartup(void)
} }
if (Cranking) crank_counter++; //Check mode of engine operation if (Cranking) crank_counter++; //Check mode of engine operation
if (!Running && spark && fuel) { // start the engine if revs high enough if (!Running && spark && fuel) { // start the engine if revs high enough
if (Cranking) { if (Cranking) {
if ((RPM > 450) && (crank_counter > 175)) // Add a little delay to startup if ((RPM > 450) && (crank_counter > 175)) // Add a little delay to startup
@ -238,7 +338,7 @@ void FGPiston::doEngineStartup(void)
if ( Running && (!spark || !fuel) ) Running = false; if ( Running && (!spark || !fuel) ) Running = false;
// Check for stalling (RPM = 0). // Check for stalling (RPM = 0).
if (Running) { if (Running) {
if (RPM == 0) { if (RPM == 0) {
Running = false; Running = false;
} else if ((RPM <= 480) && (Cranking)) { } else if ((RPM <= 480) && (Cranking)) {
@ -250,50 +350,119 @@ void FGPiston::doEngineStartup(void)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/** /**
* Calculate the nominal manifold pressure in inches hg * Calculate the Current Boost Speed
* *
* This function calculates nominal manifold pressure directly * This function calculates the current turbo/supercharger boost speed
* from the throttle position, and does not adjust it for the * based on altitude and the (automatic) boost-speed control valve configuration.
* difference between the pressure at sea level and the pressure *
* at the current altitude (that adjustment takes place in * Inputs: p_amb, BoostSwitchPressure, BoostSwitchHysteresis
* {@link #doEnginePower}). *
* Outputs: BoostSpeed
*/
void FGPiston::doBoostControl(void)
{
if(BoostSpeed < BoostSpeeds - 1) {
// Check if we need to change to a higher boost speed
if(p_amb < BoostSwitchPressure[BoostSpeed] - BoostSwitchHysteresis) {
BoostSpeed++;
}
} else if(BoostSpeed > 0) {
// Check if we need to change to a lower boost speed
if(p_amb > BoostSwitchPressure[BoostSpeed - 1] + BoostSwitchHysteresis) {
BoostSpeed--;
}
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/**
* Calculate the manifold absolute pressure (MAP) in inches hg
*
* This function calculates manifold absolute pressure (MAP)
* from the throttle position, turbo/supercharger boost control
* system, engine speed and local ambient air density.
* *
* TODO: changes in MP should not be instantaneous -- introduce * TODO: changes in MP should not be instantaneous -- introduce
* a lag between throttle changes and MP changes, to allow pressure * a lag between throttle changes and MP changes, to allow pressure
* to build up or disperse. * to build up or disperse.
* *
* Inputs: MinManifoldPressure_inHg, MaxManifoldPressure_inHg, Throttle * Inputs: minMAP, maxMAP, p_amb, Throttle
* *
* Outputs: ManifoldPressure_inHg * Outputs: MAP, ManifoldPressure_inHg
*/ */
void FGPiston::doManifoldPressure(void) void FGPiston::doMAP(void)
{ {
if (Running || Cranking) { if(RPM > 10) {
ManifoldPressure_inHg = MinManifoldPressure_inHg + // Naturally aspirated
(Throttle * (MaxManifoldPressure_inHg - MinManifoldPressure_inHg)); MAP = minMAP + (Throttle * (maxMAP - minMAP));
MAP *= p_amb / p_amb_sea_level;
if(Boosted) {
// If takeoff boost is fitted, we currently assume the following throttle map:
// (In throttle % - actual input is 0 -> 1)
// 99 / 100 - Takeoff boost
// 96 / 97 / 98 - Rated boost
// 0 - 95 - Idle to Rated boost (MinManifoldPressure to MaxManifoldPressure)
// In real life, most planes would be fitted with a mechanical 'gate' between
// the rated boost and takeoff boost positions.
double T = Throttle; // processed throttle value.
bool bTakeoffPos = false;
if(bTakeoffBoost) {
if(Throttle > 0.98) {
//cout << "Takeoff Boost!!!!\n";
bTakeoffPos = true;
} else if(Throttle <= 0.95) {
bTakeoffPos = false;
T *= 1.0 / 0.95;
} else {
bTakeoffPos = false;
//cout << "Rated Boost!!\n";
T = 1.0;
}
}
// Boost the manifold pressure.
MAP *= BoostMul[BoostSpeed];
// Now clip the manifold pressure to BCV or Wastegate setting.
if(bTakeoffPos) {
if(MAP > TakeoffMAP[BoostSpeed]) {
MAP = TakeoffMAP[BoostSpeed];
}
} else {
if(MAP > RatedMAP[BoostSpeed]) {
MAP = RatedMAP[BoostSpeed];
}
}
}
} else { } else {
ManifoldPressure_inHg = Atmosphere->GetPressure() * psftoinhg; // psf to in Hg // rpm < 10 - effectively stopped.
} // TODO - add a better variation of MAP with engine speed
MAP = Atmosphere->GetPressure() * 47.88; // psf to Pa
}
// And set the value in American units as well
ManifoldPressure_inHg = MAP / 3376.85;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/** /**
* Calculate the air flow through the engine. * Calculate the air flow through the engine.
* Also calculates ambient air density
* (used in CHT calculation for air-cooled engines).
* *
* At this point, ManifoldPressure_inHg still represents the sea-level * Inputs: p_amb, R_air, T_amb, MAP, Displacement,
* MP, not adjusted for altitude.
*
* Inputs: p_amb, R_air, T_amb, ManifoldPressure_inHg, Displacement,
* RPM, volumetric_efficiency * RPM, volumetric_efficiency
* *
* TODO: Model inlet manifold air temperature.
*
* Outputs: rho_air, m_dot_air * Outputs: rho_air, m_dot_air
*/ */
void FGPiston::doAirFlow(void) void FGPiston::doAirFlow(void)
{ {
rho_air = p_amb / (R_air * T_amb); rho_air = p_amb / (R_air * T_amb);
double rho_air_manifold = rho_air * ManifoldPressure_inHg / 29.6; double rho_air_manifold = MAP / (R_air * T_amb);
double displacement_SI = Displacement * in3tom3; double displacement_SI = Displacement * in3tom3;
double swept_volume = (displacement_SI * (RPM/60)) / 2; double swept_volume = (displacement_SI * (RPM/60)) / 2;
double v_dot_air = swept_volume * volumetric_efficiency; double v_dot_air = swept_volume * volumetric_efficiency;
@ -329,7 +498,7 @@ void FGPiston::doFuelFlow(void)
* When tested with sufficient RPM, it has no trouble reaching * When tested with sufficient RPM, it has no trouble reaching
* 200HP. * 200HP.
* *
* Inputs: ManifoldPressure_inHg, p_amb, p_amb_sea_level, RPM, T_amb, * Inputs: ManifoldPressure_inHg, p_amb, p_amb_sea_level, RPM, T_amb,
* equivalence_ratio, Cycles, MaxHP * equivalence_ratio, Cycles, MaxHP
* *
* Outputs: Percentage_Power, HP * Outputs: Percentage_Power, HP
@ -337,26 +506,44 @@ void FGPiston::doFuelFlow(void)
void FGPiston::doEnginePower(void) void FGPiston::doEnginePower(void)
{ {
ManifoldPressure_inHg *= p_amb / p_amb_sea_level; if (Running) {
if (Running) {
double ManXRPM = ManifoldPressure_inHg * RPM;
double T_amb_degF = KelvinToFahrenheit(T_amb); double T_amb_degF = KelvinToFahrenheit(T_amb);
double T_amb_sea_lev_degF = KelvinToFahrenheit(288); double T_amb_sea_lev_degF = KelvinToFahrenheit(288);
// FIXME: this needs to be generalized // FIXME: this needs to be generalized
Percentage_Power = (6e-9 * ManXRPM * ManXRPM) + (8e-4 * ManXRPM) - 1.0; double ManXRPM; // Convienience term for use in the calculations
Percentage_Power += ((T_amb_sea_lev_degF - T_amb_degF) * 7 /120); if(Boosted) {
// Currently a simple linear fit.
// The zero crossing is moved up the speed-load range to reduce the idling power.
// This will change!
double zeroOffset = (minMAP / 2.0) * (IdleRPM / 2.0);
ManXRPM = MAP * (RPM > RatedRPM[BoostSpeed] ? RatedRPM[BoostSpeed] : RPM);
// The speed clip in the line above is deliberate.
Percentage_Power = ((ManXRPM - zeroOffset) / ((RatedMAP[BoostSpeed] * RatedRPM[BoostSpeed]) - zeroOffset)) * 107.0;
Percentage_Power -= 7.0; // Another idle power reduction offset - see line above with 107.
if (Percentage_Power < 0.0) Percentage_Power = 0.0;
// Note that %power is allowed to go over 100 for boosted powerplants
// such as for the BCV-override or takeoff power settings.
// TODO - currently no altitude effect (temperature & exhaust back-pressure) modelled
// for boosted engines.
} else {
ManXRPM = ManifoldPressure_inHg * RPM; // Note that inHg must be used for the following correlation.
Percentage_Power = (6e-9 * ManXRPM * ManXRPM) + (8e-4 * ManXRPM) - 1.0;
Percentage_Power += ((T_amb_sea_lev_degF - T_amb_degF) * 7 /120);
if (Percentage_Power < 0.0) Percentage_Power = 0.0;
else if (Percentage_Power > 100.0) Percentage_Power = 100.0;
}
double Percentage_of_best_power_mixture_power = double Percentage_of_best_power_mixture_power =
Power_Mixture_Correlation->GetValue(14.7 / equivalence_ratio); Power_Mixture_Correlation->GetValue(14.7 / equivalence_ratio);
Percentage_Power *= Percentage_of_best_power_mixture_power / 100.0; Percentage_Power *= Percentage_of_best_power_mixture_power / 100.0;
if (Percentage_Power < 0.0) Percentage_Power = 0.0; if(Boosted) {
else if (Percentage_Power > 100.0) Percentage_Power = 100.0; HP = Percentage_Power * RatedPower[BoostSpeed] / 100.0;
} else {
HP = Percentage_Power * MaxHP / 100.0; HP = Percentage_Power * MaxHP / 100.0;
}
} else { } else {
@ -367,7 +554,7 @@ void FGPiston::doEnginePower(void)
// the first time step. It may possibly need to be changed // the first time step. It may possibly need to be changed
// if the prop model is changed. // if the prop model is changed.
} else if (RPM < 480) { } else if (RPM < 480) {
HP = 3.0 + ((480 - RPM) / 10.0); HP = 3.0 + ((480 - RPM) / 10.0);
// This is a guess - would be nice to find a proper starter moter torque curve // This is a guess - would be nice to find a proper starter moter torque curve
} else { } else {
HP = 3.0; HP = 3.0;
@ -380,13 +567,14 @@ void FGPiston::doEnginePower(void)
HP = 0.0; HP = 0.0;
} }
} }
//cout << "Power = " << HP << '\n';
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/** /**
* Calculate the exhaust gas temperature. * Calculate the exhaust gas temperature.
* *
* Inputs: equivalence_ratio, m_dot_fuel, calorific_value_fuel, * Inputs: equivalence_ratio, m_dot_fuel, calorific_value_fuel,
* Cp_air, m_dot_air, Cp_fuel, m_dot_fuel, T_amb, Percentage_Power * Cp_air, m_dot_air, Cp_fuel, m_dot_fuel, T_amb, Percentage_Power
* *
* Outputs: combustion_efficiency, ExhaustGasTemp_degK * Outputs: combustion_efficiency, ExhaustGasTemp_degK
@ -401,7 +589,7 @@ void FGPiston::doEGT(void)
if ((Running) && (m_dot_air > 0.0)) { // do the energy balance if ((Running) && (m_dot_air > 0.0)) { // do the energy balance
combustion_efficiency = Lookup_Combustion_Efficiency->GetValue(equivalence_ratio); combustion_efficiency = Lookup_Combustion_Efficiency->GetValue(equivalence_ratio);
enthalpy_exhaust = m_dot_fuel * calorific_value_fuel * enthalpy_exhaust = m_dot_fuel * calorific_value_fuel *
combustion_efficiency * 0.33; combustion_efficiency * 0.33;
heat_capacity_exhaust = (Cp_air * m_dot_air) + (Cp_fuel * m_dot_fuel); heat_capacity_exhaust = (Cp_air * m_dot_air) + (Cp_fuel * m_dot_fuel);
delta_T_exhaust = enthalpy_exhaust / heat_capacity_exhaust; delta_T_exhaust = enthalpy_exhaust / heat_capacity_exhaust;
@ -438,15 +626,15 @@ void FGPiston::doCHT(void)
double v_apparent = IAS * 0.5144444; double v_apparent = IAS * 0.5144444;
double v_dot_cooling_air = arbitary_area * v_apparent; double v_dot_cooling_air = arbitary_area * v_apparent;
double m_dot_cooling_air = v_dot_cooling_air * rho_air; double m_dot_cooling_air = v_dot_cooling_air * rho_air;
double dqdt_from_combustion = double dqdt_from_combustion =
m_dot_fuel * calorific_value_fuel * combustion_efficiency * 0.33; m_dot_fuel * calorific_value_fuel * combustion_efficiency * 0.33;
double dqdt_forced = (h2 * m_dot_cooling_air * temperature_difference) + double dqdt_forced = (h2 * m_dot_cooling_air * temperature_difference) +
(h3 * RPM * temperature_difference); (h3 * RPM * temperature_difference);
double dqdt_free = h1 * temperature_difference; double dqdt_free = h1 * temperature_difference;
double dqdt_cylinder_head = dqdt_from_combustion + dqdt_forced + dqdt_free; double dqdt_cylinder_head = dqdt_from_combustion + dqdt_forced + dqdt_free;
double HeatCapacityCylinderHead = CpCylinderHead * MassCylinderHead; double HeatCapacityCylinderHead = CpCylinderHead * MassCylinderHead;
CylinderHeadTemp_degK += CylinderHeadTemp_degK +=
(dqdt_cylinder_head / HeatCapacityCylinderHead) * dt; (dqdt_cylinder_head / HeatCapacityCylinderHead) * dt;
} }
@ -470,7 +658,7 @@ void FGPiston::doOilTemperature(void)
target_oil_temp = 363; target_oil_temp = 363;
time_constant = 500; // Time constant for engine-on idling. time_constant = 500; // Time constant for engine-on idling.
if (Percentage_Power > idle_percentage_power) { if (Percentage_Power > idle_percentage_power) {
time_constant /= ((Percentage_Power / idle_percentage_power) / 10.0); // adjust for power time_constant /= ((Percentage_Power / idle_percentage_power) / 10.0); // adjust for power
} }
} else { } else {
target_oil_temp = 298; target_oil_temp = 298;
@ -508,6 +696,29 @@ void FGPiston::doOilPressure(void)
OilPressure_psi += (Design_Oil_Temp - OilTemp_degK) * Oil_Viscosity_Index; OilPressure_psi += (Design_Oil_Temp - OilTemp_degK) * Oil_Viscosity_Index;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGPiston::GetEngineLabels(void)
{
std::ostringstream buf;
buf << Name << "_PwrAvail[" << EngineNumber << "], "
<< Thruster->GetThrusterLabels(EngineNumber);
return buf.str();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGPiston::GetEngineValues(void)
{
std::ostringstream buf;
buf << PowerAvailable << ", " << Thruster->GetThrusterValues(EngineNumber);
return buf.str();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// //
// The bitmasked value choices are as follows: // The bitmasked value choices are as follows:

View file

@ -48,6 +48,7 @@ DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_PISTON "$Id$"; #define ID_PISTON "$Id$";
#define FG_MAX_BOOST_SPEEDS 3
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS FORWARD DECLARATIONS
@ -59,11 +60,78 @@ namespace JSBSim {
CLASS DOCUMENTATION CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Models Dave Luff's engine model as ported into JSBSim by David Megginson. /** Models Dave Luff's Turbo/Supercharged Piston engine model.
Additional elements are required for a supercharged engine. These can be
left off a non-supercharged engine, ie. the changes are all backward
compatible at present.
- NUMBOOSTSPEEDS - zero (or not present) for a naturally-aspirated engine,
either 1, 2 or 3 for a boosted engine. This corresponds to the number of
supercharger speeds. Merlin XII had 1 speed, Merlin 61 had 2, a late
Griffon engine apparently had 3. No known engine more than 3, although
some German engines apparently had a continuously variable-speed
supercharger.
- BOOSTOVERRIDE - whether the boost pressure control system (either a boost
control valve for superchargers or wastegate for turbochargers) can be
overriden by the pilot. During wartime this was commonly possible, and
known as "War Emergency Power" by the Brits. 1 or 0 in the config file.
This isn't implemented in the model yet though, there would need to be
some way of getting the boost control cutout lever position (on or off)
from FlightGear first.
- The next items are all appended with either 1, 2 or 3 depending on which
boost speed they refer to, eg RATEDBOOST1. The rated values seems to have
been a common convention at the time to express the maximum continuously
available power, and the conditions to attain that power.
- RATEDBOOST[123] - the absolute rated boost above sea level ambient for a
given boost speed, in psi. Eg the Merlin XII had a rated boost of 9psi,
giving approximately 42inHg manifold pressure up to the rated altitude.
- RATEDALTITUDE[123] - The altitude up to which rated boost can be
maintained. Up to this altitude the boost is maintained constant for a
given throttle position by the BCV or wastegate. Beyond this altitude the
manifold pressure must drop, since the supercharger is now at maximum
unregulated output. The actual pressure multiplier of the supercharger
system is calculated at initialisation from this value.
- RATEDPOWER[123] - The power developed at rated boost at rated altitude at
rated rpm.
- RATEDRPM[123] - The rpm at which rated power is developed.
- TAKEOFFBOOST - Takeoff boost in psi above ambient. Many aircraft had an
extra boost setting beyond rated boost, but not totally uncontrolled as in
the already mentioned boost-control-cutout, typically attained by pushing
the throttle past a mechanical 'gate' preventing its inadvertant use. This
was typically used for takeoff, and emergency situations, generally for
not more than five minutes. This is a change in the boost control
setting, not the actual supercharger speed, and so would only give extra
power below the rated altitude. When TAKEOFFBOOST is specified in the
config file (and is above RATEDBOOST1), then the throttle position is
interpreted as:
- 0 to 0.95 : idle manifold pressure to rated boost (where attainable)
- 0.96, 0.97, 0.98 : rated boost (where attainable).
- 0.99, 1.0 : takeoff boost (where attainable).
A typical takeoff boost for an earlyish Merlin was about 12psi, compared
with a rated boost of 9psi.
It is quite possible that other boost control settings could have been used
on some aircraft, or that takeoff/extra boost could have activated by other
means than pushing the throttle full forward through a gate, but this will
suffice for now.
Note that MAXMP is still the non-boosted max manifold pressure even for
boosted engines - effectively this is simply a measure of the pressure drop
through the fully open throttle.
@author Jon S. Berndt (Engine framework code and framework-related mods) @author Jon S. Berndt (Engine framework code and framework-related mods)
@author Dave Luff (engine operational code) @author Dave Luff (engine operational code)
@author David Megginson (porting and additional code) @author David Megginson (initial porting and additional code)
@version "$Id$" @version $Id$
*/ */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -78,7 +146,10 @@ public:
/// Destructor /// Destructor
~FGPiston(); ~FGPiston();
double Calculate(double PowerRequired); string GetEngineLabels(void);
string GetEngineValues(void);
double Calculate(void);
double GetPowerAvailable(void) {return PowerAvailable;} double GetPowerAvailable(void) {return PowerAvailable;}
double CalcFuelNeed(void); double CalcFuelNeed(void);
@ -92,7 +163,7 @@ public:
double getCylinderHeadTemp_degF(void) {return KelvinToFahrenheit(CylinderHeadTemp_degK);} double getCylinderHeadTemp_degF(void) {return KelvinToFahrenheit(CylinderHeadTemp_degK);}
double getOilPressure_psi(void) const {return OilPressure_psi;} double getOilPressure_psi(void) const {return OilPressure_psi;}
double getOilTemp_degF (void) {return KelvinToFahrenheit(OilTemp_degK);} double getOilTemp_degF (void) {return KelvinToFahrenheit(OilTemp_degK);}
double getRPM(void) {return RPM;} double getRPM(void) {return RPM;}
private: private:
int crank_counter; int crank_counter;
@ -107,7 +178,8 @@ private:
double dt; double dt;
void doEngineStartup(void); void doEngineStartup(void);
void doManifoldPressure(void); void doBoostControl(void);
void doMAP(void);
void doAirFlow(void); void doAirFlow(void);
void doFuelFlow(void); void doFuelFlow(void);
void doEnginePower(void); void doEnginePower(void);
@ -138,6 +210,31 @@ private:
double MaxHP; // horsepower double MaxHP; // horsepower
double Cycles; // cycles/power stroke double Cycles; // cycles/power stroke
double IdleRPM; // revolutions per minute double IdleRPM; // revolutions per minute
int BoostSpeeds; // Number of super/turbocharger boost speeds - zero implies no turbo/supercharging.
int BoostSpeed; // The current boost-speed (zero-based).
bool Boosted; // Set true for boosted engine.
int BoostOverride; // The raw value read in from the config file - should be 1 or 0 - see description below.
bool bBoostOverride; // Set true if pilot override of the boost regulator was fitted.
// (Typically called 'war emergency power').
bool bTakeoffBoost; // Set true if extra takeoff / emergency boost above rated boost could be attained.
// (Typically by extra throttle movement past a mechanical 'gate').
double TakeoffBoost; // Sea-level takeoff boost in psi. (if fitted).
double RatedBoost[FG_MAX_BOOST_SPEEDS]; // Sea-level rated boost in psi.
double RatedAltitude[FG_MAX_BOOST_SPEEDS]; // Altitude at which full boost is reached (boost regulation ends)
// and at which power starts to fall with altitude [ft].
double RatedRPM[FG_MAX_BOOST_SPEEDS]; // Engine speed at which the rated power for each boost speed is delivered [rpm].
double RatedPower[FG_MAX_BOOST_SPEEDS]; // Power at rated throttle position at rated altitude [HP].
double BoostSwitchAltitude[FG_MAX_BOOST_SPEEDS - 1]; // Altitude at which switchover (currently assumed automatic)
// from one boost speed to next occurs [ft].
double BoostSwitchPressure[FG_MAX_BOOST_SPEEDS - 1]; // Pressure at which boost speed switchover occurs [Pa]
double BoostMul[FG_MAX_BOOST_SPEEDS]; // Pressure multipier of unregulated supercharger
double RatedMAP[FG_MAX_BOOST_SPEEDS]; // Rated manifold absolute pressure [Pa] (BCV clamp)
double TakeoffMAP[FG_MAX_BOOST_SPEEDS]; // Takeoff setting manifold absolute pressure [Pa] (BCV clamp)
double BoostSwitchHysteresis; // Pa.
double minMAP; // Pa
double maxMAP; // Pa
double MAP; // Pa
// //
// Inputs (in addition to those in FGEngine). // Inputs (in addition to those in FGEngine).

View file

@ -1,367 +0,0 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Module: FGPosition.cpp
Author: Jon S. Berndt
Date started: 01/05/99
Purpose: Integrate the EOM to determine instantaneous position
Called by: FGFDMExec
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org.
FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------
This class encapsulates the integration of rates and accelerations to get the
current position of the aircraft.
HISTORY
--------------------------------------------------------------------------------
01/05/99 JSB Created
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
COMMENTS, REFERENCES, and NOTES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[1] Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
School, January 1994
[2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
JSC 12960, July 1977
[3] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
NASA-Ames", NASA CR-2497, January 1975
[4] Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
Wiley & Sons, 1979 ISBN 0-471-03032-5
[5] Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
1982 ISBN 0-471-08936-2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifdef FGFS
# include <simgear/compiler.h>
# ifdef SG_HAVE_STD_INCLUDES
# include <cmath>
# include <iomanip>
# else
# include <math.h>
# include <iomanip.h>
# endif
#else
# if defined(sgi) && !defined(__GNUC__)
# include <math.h>
# if (_COMPILER_VERSION < 740)
# include <iomanip.h>
# else
# include <iomanip>
# endif
# else
# include <cmath>
# include <iomanip>
# endif
#endif
#include "FGPosition.h"
#include "FGState.h"
#include "FGFDMExec.h"
#include "FGAircraft.h"
#include "FGMassBalance.h"
#include "FGTranslation.h"
#include "FGRotation.h"
#include "FGInertial.h"
#include "FGPropertyManager.h"
namespace JSBSim {
static const char *IdSrc = "$Id$";
static const char *IdHdr = ID_POSITION;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
FGPosition::FGPosition(FGFDMExec* fdmex) : FGModel(fdmex)
{
Name = "FGPosition";
LongitudeDot = LatitudeDot = RadiusDot = 0.0;
for (int i=0;i<4;i++) {
LatitudeDot_prev[i] = 0.0;
LongitudeDot_prev[i] = 0.0;
RadiusDot_prev[i] = 0.0;
}
vVRPoffset.InitMatrix();
Longitude = Latitude = 0.0;
LongitudeVRP = LatitudeVRP = 0.0;
gamma = Vt = Vground = 0.0;
hoverbmac = hoverbcg = 0.0;
psigt = 0.0;
bind();
Debug(0);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGPosition::~FGPosition(void)
{
unbind();
Debug(1);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGPosition::InitModel(void)
{
FGModel::InitModel();
h = 3.0; // Est. height of aircraft cg off runway
SeaLevelRadius = Inertial->RefRadius(); // For initialization ONLY
Radius = SeaLevelRadius + h;
RunwayRadius = SeaLevelRadius;
DistanceAGL = Radius - RunwayRadius; // Geocentric
vRunwayNormal(3) = -1.0; // Initialized for standalone mode
b = 1;
return true;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/*
Purpose: Called on a schedule to perform Positioning algorithms
Notes: [TP] Make sure that -Vt <= hdot <= Vt, which, of course, should always
be the case
[JB] Run in standalone mode, SeaLevelRadius will be reference radius.
In FGFS, SeaLevelRadius is stuffed from FGJSBSim in JSBSim.cxx each pass.
*/
bool FGPosition::Run(void)
{
double cosLat;
double hdot_Vt;
if (!FGModel::Run()) {
GetState();
Vground = sqrt( vVel(eNorth)*vVel(eNorth) + vVel(eEast)*vVel(eEast) );
if (vVel(eNorth) == 0) psigt = 0;
else psigt = atan2(vVel(eEast), vVel(eNorth));
if (psigt < 0.0) psigt += 2*M_PI;
Radius = h + SeaLevelRadius;
cosLat = cos(Latitude);
if (cosLat != 0) LongitudeDot = vVel(eEast) / (Radius * cosLat);
LatitudeDot = vVel(eNorth) / Radius;
RadiusDot = -vVel(eDown);
Longitude += State->Integrate(FGState::TRAPZ, dt*rate, LongitudeDot, LongitudeDot_prev);
Latitude += State->Integrate(FGState::TRAPZ, dt*rate, LatitudeDot, LatitudeDot_prev);
Radius += State->Integrate(FGState::TRAPZ, dt*rate, RadiusDot, RadiusDot_prev);
h = Radius - SeaLevelRadius; // Geocentric
vVRPoffset = State->GetTb2l() * MassBalance->StructuralToBody(Aircraft->GetXYZvrp());
// vVRP - the vector to the Visual Reference Point - now contains the
// offset from the CG to the VRP, in units of feet, in the Local coordinate
// frame, where X points north, Y points East, and Z points down. This needs
// to be converted to Lat/Lon/Alt, now.
if (cosLat != 0)
LongitudeVRP = vVRPoffset(eEast) / (Radius * cosLat) + Longitude;
LatitudeVRP = vVRPoffset(eNorth) / Radius + Latitude;
hVRP = h - vVRPoffset(eDown);
/*
cout << "Lat/Lon/Alt : " << Latitude << " / " << Longitude << " / " << h << endl;
cout << "Lat/Lon/Alt VRP: " << LatitudeVRP << " / " << LongitudeVRP << " / " << hVRP << endl << endl;
*/
DistanceAGL = Radius - RunwayRadius; // Geocentric
hoverbcg = DistanceAGL/b;
vMac = State->GetTb2l()*MassBalance->StructuralToBody(Aircraft->GetXYZrp());
hoverbmac = (DistanceAGL + vMac(3)) / b;
if (Vt > 0) {
hdot_Vt = RadiusDot/Vt;
if (fabs(hdot_Vt) <= 1) gamma = asin(hdot_Vt);
} else {
gamma = 0.0;
}
return false;
} else {
return true;
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGPosition::GetState(void)
{
dt = State->Getdt();
Vt = Translation->GetVt();
vVel = State->GetTb2l() * Translation->GetUVW();
vVelDot = State->GetTb2l() * Translation->GetUVWdot();
b = Aircraft->GetWingSpan();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGPosition::Seth(double tt)
{
h = tt;
Radius = h + SeaLevelRadius;
DistanceAGL = Radius - RunwayRadius; // Geocentric
hoverbcg = DistanceAGL/b;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGPosition::SetDistanceAGL(double tt)
{
DistanceAGL=tt;
Radius = RunwayRadius + DistanceAGL;
h = Radius - SeaLevelRadius;
hoverbcg = DistanceAGL/b;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGPosition::bind(void)
{
PropertyManager->Tie("velocities/v-north-fps", this,
&FGPosition::GetVn);
PropertyManager->Tie("velocities/v-east-fps", this,
&FGPosition::GetVe);
PropertyManager->Tie("velocities/v-down-fps", this,
&FGPosition::GetVd);
PropertyManager->Tie("velocities/vg-fps", this,
&FGPosition::GetVground);
PropertyManager->Tie("flight-path/psi-gt-rad", this,
&FGPosition::GetGroundTrack);
PropertyManager->Tie("position/h-sl-ft", this,
&FGPosition::Geth,
&FGPosition::Seth,
true);
PropertyManager->Tie("velocities/h-dot-fps", this,
&FGPosition::Gethdot);
PropertyManager->Tie("position/lat-gc-rad", this,
&FGPosition::GetLatitude,
&FGPosition::SetLatitude);
PropertyManager->Tie("position/lat-dot-gc-rad", this,
&FGPosition::GetLatitudeDot);
PropertyManager->Tie("position/long-gc-rad", this,
&FGPosition::GetLongitude,
&FGPosition::SetLongitude,
true);
PropertyManager->Tie("position/long-dot-gc-rad", this,
&FGPosition::GetLongitudeDot);
PropertyManager->Tie("metrics/runway-radius", this,
&FGPosition::GetRunwayRadius,
&FGPosition::SetRunwayRadius);
PropertyManager->Tie("position/h-agl-ft", this,
&FGPosition::GetDistanceAGL,
&FGPosition::SetDistanceAGL);
PropertyManager->Tie("position/radius-to-vehicle-ft", this,
&FGPosition::GetRadius);
PropertyManager->Tie("flight-path/gamma-rad", this,
&FGPosition::GetGamma,
&FGPosition::SetGamma);
PropertyManager->Tie("aero/h_b-cg-ft", this,
&FGPosition::GetHOverBCG);
PropertyManager->Tie("aero/h_b-mac-ft", this,
&FGPosition::GetHOverBMAC);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGPosition::unbind(void)
{
PropertyManager->Untie("velocities/v-north-fps");
PropertyManager->Untie("velocities/v-east-fps");
PropertyManager->Untie("velocities/v-down-fps");
PropertyManager->Untie("velocities/vg-fps");
PropertyManager->Untie("flight-path/psi-gt-rad");
PropertyManager->Untie("position/h-sl-ft");
PropertyManager->Untie("velocities/h-dot-fps");
PropertyManager->Untie("position/lat-gc-rad");
PropertyManager->Untie("position/lat-dot-gc-rad");
PropertyManager->Untie("position/long-gc-rad");
PropertyManager->Untie("position/long-dot-gc-rad");
PropertyManager->Untie("metrics/runway-radius");
PropertyManager->Untie("position/h-agl-ft");
PropertyManager->Untie("position/radius-to-vehicle-ft");
PropertyManager->Untie("flight-path/gamma-rad");
PropertyManager->Untie("aero/h_b-cg-ft");
PropertyManager->Untie("aero/h_b-mac-ft");
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
// out the normally expected messages, essentially echoing
// the config files as they are read. If the environment
// variable is not set, debug_lvl is set to 1 internally
// 0: This requests JSBSim not to output any messages
// whatsoever.
// 1: This value explicity requests the normal JSBSim
// startup messages
// 2: This value asks for a message to be printed out when
// a class is instantiated
// 4: When this value is set, a message is displayed when a
// FGModel object executes its Run() method
// 8: When this value is set, various runtime state variables
// are printed out periodically
// 16: When set various parameters are sanity checked and
// a message is printed out when they go out of bounds
void FGPosition::Debug(int from)
{
if (debug_lvl <= 0) return;
if (debug_lvl & 1) { // Standard console startup message output
if (from == 0) { // Constructor
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
if (from == 0) cout << "Instantiated: FGPosition" << endl;
if (from == 1) cout << "Destroyed: FGPosition" << endl;
}
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
}
if (debug_lvl & 8 ) { // Runtime state variables
}
if (debug_lvl & 16) { // Sanity checking
}
if (debug_lvl & 64) {
if (from == 0) { // Constructor
cout << IdSrc << endl;
cout << IdHdr << endl;
}
}
}
}

View file

@ -1,154 +0,0 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Header: FGPosition.h
Author: Jon S. Berndt
Date started: 1/5/99
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org.
HISTORY
--------------------------------------------------------------------------------
01/05/99 JSB Created
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifndef FGPOSITION_H
#define FGPOSITION_H
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGModel.h"
#include "FGColumnVector3.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_POSITION "$Id$"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
namespace JSBSim {
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Models the lateral and longitudinal translational EOM.
@author Jon S. Berndt
@version $Id$
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGPosition : public FGModel {
public:
/** Constructor
@param Executive a pointer to the parent executive object */
FGPosition(FGFDMExec* Executive);
/// Destructor
~FGPosition();
bool InitModel(void);
/** Runs the Position model; called by the Executive
@see JSBSim.cpp documentation
@return false if no error */
bool Run(void);
inline FGColumnVector3& GetVel(void) { return vVel; }
inline FGColumnVector3& GetVelDot(void) { return vVelDot; }
inline double GetVn(void) const { return vVel(eX); }
inline double GetVe(void) const { return vVel(eY); }
inline double GetVd(void) const { return vVel(eZ); }
inline double GetVground(void) const { return Vground; }
inline double GetGroundTrack(void) const { return psigt; }
inline double Geth(void) const { return h; }
inline double GethVRP(void) const { return hVRP; }
inline double Gethdot(void) const { return RadiusDot; }
inline double GetLatitude(void) const { return Latitude; }
inline double GetLatitudeVRP(void) const { return LatitudeVRP; }
inline double GetLatitudeDot(void) const { return LatitudeDot; }
inline double GetLongitude(void) const { return Longitude; }
inline double GetLongitudeVRP(void) const { return LongitudeVRP; }
inline double GetLongitudeDot(void) const { return LongitudeDot; }
inline double GetRunwayRadius(void) const { return RunwayRadius; }
inline double GetDistanceAGL(void) const { return DistanceAGL; }
inline double GetRadius(void) const { return Radius; }
inline FGColumnVector3& GetRunwayNormal(void) { return vRunwayNormal; }
inline double GetGamma(void) const { return gamma; }
inline void SetGamma(double tt) { gamma = tt; }
inline double GetHOverBCG(void) const { return hoverbcg; }
inline double GetHOverBMAC(void) const { return hoverbmac; }
void SetvVel(const FGColumnVector3& v) { vVel = v; }
void SetLatitude(double tt) { Latitude = tt; }
void SetLongitude(double tt) { Longitude = tt; }
void Seth(double tt);
void SetRunwayRadius(double tt) { RunwayRadius = tt; }
void SetSeaLevelRadius(double tt) { SeaLevelRadius = tt;}
void SetDistanceAGL(double tt);
inline void SetRunwayNormal(double fgx, double fgy, double fgz ) {
vRunwayNormal << fgx << fgy << fgz;
}
void SetVRP(FGColumnVector3& vrp) {vVRP = vrp;}
void bind(void);
void unbind(void);
private:
FGColumnVector3 vVel;
FGColumnVector3 vVelDot;
FGColumnVector3 vRunwayNormal;
FGColumnVector3 vVRP;
FGColumnVector3 vVRPoffset;
FGColumnVector3 vMac;
double Radius, h, hVRP;
double LatitudeDot, LongitudeDot, RadiusDot;
double LatitudeDot_prev[4], LongitudeDot_prev[4], RadiusDot_prev[4];
double Longitude, Latitude;
double LongitudeVRP, LatitudeVRP;
double dt;
double RunwayRadius;
double DistanceAGL;
double SeaLevelRadius;
double gamma;
double Vt, Vground;
double hoverbcg,hoverbmac,b;
double psigt;
void GetState(void);
void Debug(int from);
};
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif

View file

@ -0,0 +1,380 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Module: FGPropagate.cpp
Author: Jon S. Berndt
Date started: 01/05/99
Purpose: Integrate the EOM to determine instantaneous position
Called by: FGFDMExec
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org.
FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------
This class encapsulates the integration of rates and accelerations to get the
current position of the aircraft.
HISTORY
--------------------------------------------------------------------------------
01/05/99 JSB Created
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
COMMENTS, REFERENCES, and NOTES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[1] Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
School, January 1994
[2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
JSC 12960, July 1977
[3] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
NASA-Ames", NASA CR-2497, January 1975
[4] Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
Wiley & Sons, 1979 ISBN 0-471-03032-5
[5] Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
1982 ISBN 0-471-08936-2
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifdef FGFS
# include <simgear/compiler.h>
# ifdef SG_HAVE_STD_INCLUDES
# include <cmath>
# include <iomanip>
# else
# include <math.h>
# include <iomanip.h>
# endif
#else
# if defined(sgi) && !defined(__GNUC__)
# include <math.h>
# if (_COMPILER_VERSION < 740)
# include <iomanip.h>
# else
# include <iomanip>
# endif
# else
# include <cmath>
# include <iomanip>
# endif
#endif
#include "FGPropagate.h"
#include "FGState.h"
#include "FGFDMExec.h"
#include "FGAircraft.h"
#include "FGMassBalance.h"
#include "FGInertial.h"
#include "FGPropertyManager.h"
namespace JSBSim {
static const char *IdSrc = "$Id$";
static const char *IdHdr = ID_PROPAGATE;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
FGPropagate::FGPropagate(FGFDMExec* fdmex) : FGModel(fdmex)
{
Name = "FGPropagate";
bind();
Debug(0);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGPropagate::~FGPropagate(void)
{
unbind();
Debug(1);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGPropagate::InitModel(void)
{
FGModel::InitModel();
SeaLevelRadius = Inertial->RefRadius(); // For initialization ONLY
RunwayRadius = SeaLevelRadius;
VState.vLocation.SetRadius( SeaLevelRadius + 4.0 );
return true;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
{
SeaLevelRadius = FGIC->GetSeaLevelRadiusFtIC();
RunwayRadius = FGIC->GetSeaLevelRadiusFtIC() + FGIC->GetTerrainAltitudeFtIC();
// Set the position lat/lon/radius
VState.vLocation = FGLocation( FGIC->GetLongitudeRadIC(),
FGIC->GetLatitudeRadIC(),
FGIC->GetAltitudeFtIC() + FGIC->GetSeaLevelRadiusFtIC() );
// Set the Orientation from the euler angles
VState.vQtrn = FGQuaternion( FGIC->GetPhiRadIC(),
FGIC->GetThetaRadIC(),
FGIC->GetPsiRadIC() );
// Set the velocities in the instantaneus body frame
VState.vUVW = FGColumnVector3( FGIC->GetUBodyFpsIC(),
FGIC->GetVBodyFpsIC(),
FGIC->GetWBodyFpsIC() );
// Set the angular velocities in the instantaneus body frame.
VState.vPQR = FGColumnVector3( FGIC->GetPRadpsIC(),
FGIC->GetQRadpsIC(),
FGIC->GetRRadpsIC() );
// Compute some derived values.
vVel = VState.vQtrn.GetTInv()*VState.vUVW;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/*
Purpose: Called on a schedule to perform EOM integration
Notes: [JB] Run in standalone mode, SeaLevelRadius will be reference radius.
In FGFS, SeaLevelRadius is stuffed from FGJSBSim in JSBSim.cxx each pass.
At the top of this Run() function, see several "shortcuts" (or, aliases) being
set up for use later, rather than using the longer class->function() notation.
Here, propagation of state is done using a simple explicit Euler scheme (see the
bottom of the function). This propagation is done using the current state values
and current derivatives. Based on these values we compute an approximation to the
state values for (now + dt).
*/
bool FGPropagate::Run(void)
{
if (FGModel::Run()) return true; // Fast return if we have nothing to do ...
double dt = State->Getdt()*rate; // The 'stepsize'
const FGColumnVector3 omega( 0.0, 0.0, Inertial->omega() ); // earth rotation
const FGColumnVector3& vForces = Aircraft->GetForces(); // current forces
const FGColumnVector3& vMoments = Aircraft->GetMoments(); // current moments
double mass = MassBalance->GetMass(); // mass
const FGMatrix33& J = MassBalance->GetJ(); // inertia matrix
const FGMatrix33& Jinv = MassBalance->GetJinv(); // inertia matrix inverse
double r = GetRadius(); // radius
if (r == 0.0) {cerr << "radius = 0 !" << endl; r = 1e-16;} // radius check
double rInv = 1.0/r;
FGColumnVector3 gAccel( 0.0, 0.0, Inertial->GetGAccel(r) );
// The rotation matrices:
const FGMatrix33& Tl2b = GetTl2b(); // local to body frame
const FGMatrix33& Tb2l = GetTb2l(); // body to local frame
const FGMatrix33& Tec2l = VState.vLocation.GetTec2l(); // earth centered to local frame
const FGMatrix33& Tl2ec = VState.vLocation.GetTl2ec(); // local to earth centered frame
// Inertial angular velocity measured in the body frame.
const FGColumnVector3 pqri = VState.vPQR + Tl2b*(Tec2l*omega);
// Compute vehicle velocity wrt EC frame, expressed in Local horizontal frame.
vVel = Tb2l * VState.vUVW;
// First compute the time derivatives of the vehicle state values:
// Compute body frame rotational accelerations based on the current body moments
vPQRdot = Jinv*(vMoments - pqri*(J*pqri));
// Compute body frame accelerations based on the current body forces
vUVWdot = VState.vUVW*VState.vPQR + vForces/mass;
// Centrifugal acceleration.
FGColumnVector3 ecVel = Tl2ec*vVel;
FGColumnVector3 ace = 2.0*omega*ecVel;
vUVWdot -= Tl2b*(Tec2l*ace);
// Coriolis acceleration.
FGColumnVector3 aeec = omega*(omega*VState.vLocation);
vUVWdot -= Tl2b*(Tec2l*aeec);
// Gravitation accel
vUVWdot += Tl2b*gAccel;
// Compute vehicle velocity wrt EC frame, expressed in EC frame
FGColumnVector3 vLocationDot = Tl2ec * vVel;
FGColumnVector3 omegaLocal( rInv*vVel(eEast),
-rInv*vVel(eNorth),
-rInv*vVel(eEast)*VState.vLocation.GetTanLatitude() );
// Compute quaternion orientation derivative on current body rates
FGQuaternion vQtrndot = VState.vQtrn.GetQDot( VState.vPQR - Tl2b*omegaLocal );
// Propagate velocities
VState.vPQR += dt*vPQRdot;
VState.vUVW += dt*vUVWdot;
// Propagate positions
VState.vQtrn += dt*vQtrndot;
VState.vLocation += dt*vLocationDot;
return false;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGPropagate::Seth(double tt)
{
VState.vLocation.SetRadius( tt + SeaLevelRadius );
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGPropagate::SetDistanceAGL(double tt)
{
VState.vLocation.SetRadius( tt + RunwayRadius );
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGPropagate::bind(void)
{
typedef double (FGPropagate::*PMF)(int) const;
PropertyManager->Tie("velocities/h-dot-fps", this, &FGPropagate::Gethdot);
PropertyManager->Tie("velocities/v-north-fps", this, eNorth, (PMF)&FGPropagate::GetVel);
PropertyManager->Tie("velocities/v-east-fps", this, eEast, (PMF)&FGPropagate::GetVel);
PropertyManager->Tie("velocities/v-down-fps", this, eDown, (PMF)&FGPropagate::GetVel);
PropertyManager->Tie("velocities/u-fps", this, eU, (PMF)&FGPropagate::GetUVW);
PropertyManager->Tie("velocities/v-fps", this, eV, (PMF)&FGPropagate::GetUVW);
PropertyManager->Tie("velocities/w-fps", this, eW, (PMF)&FGPropagate::GetUVW);
PropertyManager->Tie("velocities/p-rad_sec", this, eP, (PMF)&FGPropagate::GetPQR);
PropertyManager->Tie("velocities/q-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQR);
PropertyManager->Tie("velocities/r-rad_sec", this, eR, (PMF)&FGPropagate::GetPQR);
PropertyManager->Tie("accelerations/pdot-rad_sec", this, eP, (PMF)&FGPropagate::GetPQRdot);
PropertyManager->Tie("accelerations/qdot-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQRdot);
PropertyManager->Tie("accelerations/rdot-rad_sec", this, eR, (PMF)&FGPropagate::GetPQRdot);
PropertyManager->Tie("accelerations/udot-fps", this, eU, (PMF)&FGPropagate::GetUVWdot);
PropertyManager->Tie("accelerations/vdot-fps", this, eV, (PMF)&FGPropagate::GetUVWdot);
PropertyManager->Tie("accelerations/wdot-fps", this, eW, (PMF)&FGPropagate::GetUVWdot);
PropertyManager->Tie("position/h-sl-ft", this, &FGPropagate::Geth, &FGPropagate::Seth, true);
PropertyManager->Tie("position/lat-gc-rad", this, &FGPropagate::GetLatitude, &FGPropagate::SetLatitude);
PropertyManager->Tie("position/long-gc-rad", this, &FGPropagate::GetLongitude, &FGPropagate::SetLongitude);
PropertyManager->Tie("position/h-agl-ft", this, &FGPropagate::GetDistanceAGL, &FGPropagate::SetDistanceAGL);
PropertyManager->Tie("position/radius-to-vehicle-ft", this, &FGPropagate::GetRadius);
PropertyManager->Tie("metrics/runway-radius", this, &FGPropagate::GetRunwayRadius, &FGPropagate::SetRunwayRadius);
PropertyManager->Tie("attitude/phi-rad", this, &FGPropagate::Getphi);
PropertyManager->Tie("attitude/theta-rad", this, &FGPropagate::Gettht);
PropertyManager->Tie("attitude/psi-rad", this, &FGPropagate::Getpsi);
PropertyManager->Tie("attitude/roll-rad", this, &FGPropagate::Getphi);
PropertyManager->Tie("attitude/pitch-rad", this, &FGPropagate::Gettht);
PropertyManager->Tie("attitude/heading-true-rad", this, &FGPropagate::Getpsi);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGPropagate::unbind(void)
{
PropertyManager->Untie("velocities/v-north-fps");
PropertyManager->Untie("velocities/v-east-fps");
PropertyManager->Untie("velocities/v-down-fps");
PropertyManager->Untie("velocities/h-dot-fps");
PropertyManager->Untie("velocities/u-fps");
PropertyManager->Untie("velocities/v-fps");
PropertyManager->Untie("velocities/w-fps");
PropertyManager->Untie("velocities/p-rad_sec");
PropertyManager->Untie("velocities/q-rad_sec");
PropertyManager->Untie("velocities/r-rad_sec");
PropertyManager->Untie("accelerations/udot-fps");
PropertyManager->Untie("accelerations/vdot-fps");
PropertyManager->Untie("accelerations/wdot-fps");
PropertyManager->Untie("accelerations/pdot-rad_sec");
PropertyManager->Untie("accelerations/qdot-rad_sec");
PropertyManager->Untie("accelerations/rdot-rad_sec");
PropertyManager->Untie("position/h-sl-ft");
PropertyManager->Untie("position/lat-gc-rad");
PropertyManager->Untie("position/long-gc-rad");
PropertyManager->Untie("position/h-agl-ft");
PropertyManager->Untie("position/radius-to-vehicle-ft");
PropertyManager->Untie("metrics/runway-radius");
PropertyManager->Untie("attitude/phi-rad");
PropertyManager->Untie("attitude/theta-rad");
PropertyManager->Untie("attitude/psi-rad");
PropertyManager->Untie("attitude/roll-rad");
PropertyManager->Untie("attitude/pitch-rad");
PropertyManager->Untie("attitude/heading-true-rad");
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
// out the normally expected messages, essentially echoing
// the config files as they are read. If the environment
// variable is not set, debug_lvl is set to 1 internally
// 0: This requests JSBSim not to output any messages
// whatsoever.
// 1: This value explicity requests the normal JSBSim
// startup messages
// 2: This value asks for a message to be printed out when
// a class is instantiated
// 4: When this value is set, a message is displayed when a
// FGModel object executes its Run() method
// 8: When this value is set, various runtime state variables
// are printed out periodically
// 16: When set various parameters are sanity checked and
// a message is printed out when they go out of bounds
void FGPropagate::Debug(int from)
{
if (debug_lvl <= 0) return;
if (debug_lvl & 1) { // Standard console startup message output
if (from == 0) { // Constructor
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
if (from == 0) cout << "Instantiated: FGPropagate" << endl;
if (from == 1) cout << "Destroyed: FGPropagate" << endl;
}
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
}
if (debug_lvl & 8 ) { // Runtime state variables
}
if (debug_lvl & 16) { // Sanity checking
}
if (debug_lvl & 64) {
if (from == 0) { // Constructor
cout << IdSrc << endl;
cout << IdHdr << endl;
}
}
}
}

View file

@ -0,0 +1,176 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Header: FGPropagate.h
Author: Jon S. Berndt
Date started: 1/5/99
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org.
HISTORY
--------------------------------------------------------------------------------
01/05/99 JSB Created
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifndef FGPROPAGATE_H
#define FGPROPAGATE_H
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGModel.h"
#include "FGColumnVector3.h"
#include "FGInitialCondition.h"
#include "FGLocation.h"
#include "FGQuaternion.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_PROPAGATE "$Id$"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
namespace JSBSim {
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Models the EOM and integration/propagation of state
@author Jon S. Berndt, Mathias Froehlich
@version $Id$
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
// state vector
struct VehicleState {
FGLocation vLocation;
FGColumnVector3 vUVW;
FGColumnVector3 vPQR;
FGQuaternion vQtrn;
};
class FGPropagate : public FGModel {
public:
/** Constructor
@param Executive a pointer to the parent executive object */
FGPropagate(FGFDMExec* Executive);
/// Destructor
~FGPropagate();
bool InitModel(void);
/** Runs the Propagate model; called by the Executive
@return false if no error */
bool Run(void);
const FGColumnVector3& GetVel(void) const { return vVel; }
const FGColumnVector3& GetUVW(void) const { return VState.vUVW; }
const FGColumnVector3& GetUVWdot(void) const { return vUVWdot; }
const FGColumnVector3& GetPQR(void) const {return VState.vPQR;}
const FGColumnVector3& GetPQRdot(void) const {return vPQRdot;}
const FGColumnVector3& GetEuler(void) const { return VState.vQtrn.GetEuler(); }
double GetUVW (int idx) const { return VState.vUVW(idx); }
double GetUVWdot(int idx) const { return vUVWdot(idx); }
double GetVel(int idx) const { return vVel(idx); }
double Geth(void) const { return VState.vLocation.GetRadius() - SeaLevelRadius; }
double GetPQR(int axis) const {return VState.vPQR(axis);}
double GetPQRdot(int idx) const {return vPQRdot(idx);}
double GetEuler(int axis) const { return VState.vQtrn.GetEuler()(axis); }
double Gethdot(void) const { return -vVel(eDown); }
/** Returns the "constant" RunwayRadius.
The RunwayRadius parameter is set by the calling application or set to
zero if JSBSim is running in standalone mode.
@return distance of the runway from the center of the earth.
@units feet */
double GetRunwayRadius(void) const { return RunwayRadius; }
double GetSeaLevelRadius(void) const { return SeaLevelRadius; }
double GetDistanceAGL(void) const { return VState.vLocation.GetRadius()-RunwayRadius; }
double GetRadius(void) const { return VState.vLocation.GetRadius(); }
double GetLongitude(void) const { return VState.vLocation.GetLongitude(); }
double GetLatitude(void) const { return VState.vLocation.GetLatitude(); }
const FGLocation& GetLocation(void) const { return VState.vLocation; }
double Getphi(void) const { return VState.vQtrn.GetEulerPhi(); }
double Gettht(void) const { return VState.vQtrn.GetEulerTheta(); }
double Getpsi(void) const { return VState.vQtrn.GetEulerPsi(); }
double GetCosphi(void) const { return VState.vQtrn.GetCosEulerPhi(); }
double GetCostht(void) const { return VState.vQtrn.GetCosEulerTheta(); }
double GetCospsi(void) const { return VState.vQtrn.GetCosEulerPsi(); }
double GetSinphi(void) const { return VState.vQtrn.GetSinEulerPhi(); }
double GetSintht(void) const { return VState.vQtrn.GetSinEulerTheta(); }
double GetSinpsi(void) const { return VState.vQtrn.GetSinEulerPsi(); }
/** Retrieves the local-to-body transformation matrix.
@return a reference to the local-to-body transformation matrix. */
const FGMatrix33& GetTl2b(void) const { return VState.vQtrn.GetT(); }
/** Retrieves the body-to-local transformation matrix.
@return a reference to the body-to-local matrix. */
const FGMatrix33& GetTb2l(void) const { return VState.vQtrn.GetTInv(); }
// SET functions
void SetLongitude(double lon) { VState.vLocation.SetLongitude(lon); }
void SetLatitude(double lat) { VState.vLocation.SetLatitude(lat); }
void SetRadius(double r) { VState.vLocation.SetRadius(r); }
void SetLocation(const FGLocation& l) { VState.vLocation = l; }
void Seth(double tt);
void SetRunwayRadius(double tt) { RunwayRadius = tt; }
void SetSeaLevelRadius(double tt) { SeaLevelRadius = tt; }
void SetDistanceAGL(double tt);
void SetInitialState(const FGInitialCondition *);
void bind(void);
void unbind(void);
private:
// state vector
struct VehicleState VState;
FGColumnVector3 vVel;
FGColumnVector3 vPQRdot;
FGColumnVector3 vUVWdot;
double RunwayRadius, SeaLevelRadius;
void Debug(int from);
};
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif

View file

@ -35,11 +35,12 @@ HISTORY
INCLUDES INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include <sstream>
#include "FGPropeller.h" #include "FGPropeller.h"
#include "FGTranslation.h" #include "FGPropagate.h"
#include "FGRotation.h"
#include "FGFCS.h"
#include "FGAtmosphere.h" #include "FGAtmosphere.h"
#include "FGAuxiliary.h"
namespace JSBSim { namespace JSBSim {
@ -50,9 +51,9 @@ static const char *IdHdr = ID_PROPELLER;
CLASS IMPLEMENTATION CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
// This class currently makes certain assumptions when calculating torque and // This class currently makes certain assumptions when calculating torque and
// p-factor. That is, that the axis of rotation is the X axis of the aircraft - // p-factor. That is, that the axis of rotation is the X axis of the aircraft -
// not just the X-axis of the engine/propeller. This may or may not work for a // not just the X-axis of the engine/propeller. This may or may not work for a
// helicopter. // helicopter.
FGPropeller::FGPropeller(FGFDMExec* exec, FGConfigFile* Prop_cfg) : FGThruster(exec) FGPropeller::FGPropeller(FGFDMExec* exec, FGConfigFile* Prop_cfg) : FGThruster(exec)
@ -60,7 +61,7 @@ FGPropeller::FGPropeller(FGFDMExec* exec, FGConfigFile* Prop_cfg) : FGThruster(e
string token; string token;
int rows, cols; int rows, cols;
MaxPitch = MinPitch = P_Factor = Sense = Pitch = 0.0; MaxPitch = MinPitch = P_Factor = Sense = Pitch = Advance = 0.0;
GearRatio = 1.0; GearRatio = 1.0;
Name = Prop_cfg->GetValue("NAME"); Name = Prop_cfg->GetValue("NAME");
@ -135,7 +136,7 @@ FGPropeller::~FGPropeller()
double FGPropeller::Calculate(double PowerAvailable) double FGPropeller::Calculate(double PowerAvailable)
{ {
double J, C_Thrust, omega; double J, C_Thrust, omega;
double Vel = fdmex->GetTranslation()->GetAeroUVW(eU); double Vel = fdmex->GetAuxiliary()->GetAeroUVW(eU);
double rho = fdmex->GetAtmosphere()->GetDensity(); double rho = fdmex->GetAtmosphere()->GetDensity();
double RPS = RPM/60.0; double RPS = RPM/60.0;
double alpha, beta; double alpha, beta;
@ -153,8 +154,8 @@ double FGPropeller::Calculate(double PowerAvailable)
} }
if (P_Factor > 0.0001) { if (P_Factor > 0.0001) {
alpha = fdmex->GetTranslation()->Getalpha(); alpha = fdmex->GetAuxiliary()->Getalpha();
beta = fdmex->GetTranslation()->Getbeta(); beta = fdmex->GetAuxiliary()->Getbeta();
SetActingLocationY( GetLocationY() + P_Factor*alpha*Sense); SetActingLocationY( GetLocationY() + P_Factor*alpha*Sense);
SetActingLocationZ( GetLocationZ() + P_Factor*beta*Sense); SetActingLocationZ( GetLocationZ() + P_Factor*beta*Sense);
} else if (P_Factor < 0.000) { } else if (P_Factor < 0.000) {
@ -164,12 +165,6 @@ double FGPropeller::Calculate(double PowerAvailable)
Thrust = C_Thrust*RPS*RPS*Diameter*Diameter*Diameter*Diameter*rho; Thrust = C_Thrust*RPS*RPS*Diameter*Diameter*Diameter*Diameter*rho;
omega = RPS*2.0*M_PI; omega = RPS*2.0*M_PI;
// Check for windmilling.
double radius = Diameter * 0.375; // 75% of radius
double windmill_cutoff = tan(Pitch * 1.745329E-2) * omega * radius;
if (Vel > windmill_cutoff)
Thrust = -Thrust;
vFn(1) = Thrust; vFn(1) = Thrust;
// The Ixx value and rotation speed given below are for rotation about the // The Ixx value and rotation speed given below are for rotation about the
@ -185,13 +180,13 @@ double FGPropeller::Calculate(double PowerAvailable)
ExcessTorque = PowerAvailable / omega * GearRatio; ExcessTorque = PowerAvailable / omega * GearRatio;
RPM = (RPS + ((ExcessTorque / Ixx) / (2.0 * M_PI)) * deltaT) * 60.0; RPM = (RPS + ((ExcessTorque / Ixx) / (2.0 * M_PI)) * deltaT) * 60.0;
// The friction from the engine should // The friction from the engine should
// stop it somewhere; I chose an // stop it somewhere; I chose an
// arbitrary point. // arbitrary point.
if (RPM < 5.0) if (RPM < 5.0)
RPM = 0; RPM = 0;
vMn = fdmex->GetRotation()->GetPQR()*vH + vTorque*Sense; vMn = fdmex->GetPropagate()->GetPQR()*vH + vTorque*Sense;
return Thrust; // return thrust in pounds return Thrust; // return thrust in pounds
} }
@ -204,17 +199,16 @@ double FGPropeller::GetPowerRequired(void)
double cPReq, RPS = RPM / 60.0; double cPReq, RPS = RPM / 60.0;
double J = fdmex->GetTranslation()->GetAeroUVW(eU) / (Diameter * RPS); double J = fdmex->GetAuxiliary()->GetAeroUVW(eU) / (Diameter * RPS);
double rho = fdmex->GetAtmosphere()->GetDensity(); double rho = fdmex->GetAtmosphere()->GetDensity();
if (MaxPitch == MinPitch) { // Fixed pitch prop if (MaxPitch == MinPitch) { // Fixed pitch prop
Pitch = MinPitch; Pitch = MinPitch;
cPReq = cPower->GetValue(J); cPReq = cPower->GetValue(J);
} else { // Variable pitch prop } else { // Variable pitch prop
double advance = fdmex->GetFCS()->GetPropAdvance(ThrusterNumber);
if (MaxRPM != MinRPM) { // fixed-speed prop if (MaxRPM != MinRPM) { // fixed-speed prop
double rpmReq = MinRPM + (MaxRPM - MinRPM) * advance; double rpmReq = MinRPM + (MaxRPM - MinRPM) * Advance;
double dRPM = rpmReq - RPM; double dRPM = rpmReq - RPM;
Pitch -= dRPM / 10; Pitch -= dRPM / 10;
@ -223,7 +217,7 @@ double FGPropeller::GetPowerRequired(void)
else if (Pitch > MaxPitch) Pitch = MaxPitch; else if (Pitch > MaxPitch) Pitch = MaxPitch;
} else { } else {
Pitch = MinPitch + (MaxPitch - MinPitch) * advance; Pitch = MinPitch + (MaxPitch - MinPitch) * Advance;
} }
cPReq = cPower->GetValue(J, Pitch); cPReq = cPower->GetValue(J, Pitch);
} }
@ -247,6 +241,41 @@ FGColumnVector3 FGPropeller::GetPFactor()
return FGColumnVector3(px, py, pz); return FGColumnVector3(px, py, pz);
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGPropeller::GetThrusterLabels(int id)
{
std::ostringstream buf;
buf << Name << "_Torque[" << id << "], "
<< Name << "_PFactor_Pitch[" << id << "], "
<< Name << "_PFactor_Yaw[" << id << "], "
<< Name << "_Thrust[" << id << "], ";
if (IsVPitch())
buf << Name << "_Pitch[" << id << "], ";
buf << Name << "_RPM[" << id << "]";
return buf.str();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGPropeller::GetThrusterValues(int id)
{
std::ostringstream buf;
FGColumnVector3 vPFactor = GetPFactor();
buf << vTorque(eX) << ", "
<< vPFactor(ePitch) << ", "
<< vPFactor(eYaw) << ", "
<< Thrust << ", ";
if (IsVPitch())
buf << Pitch << ", ";
buf << RPM;
return buf.str();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows: // The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print // unset: In this case (the default) JSBSim would only print

View file

@ -114,6 +114,8 @@ public:
@param pitch the pitch of the blade in degrees. */ @param pitch the pitch of the blade in degrees. */
void SetPitch(double pitch) {Pitch = pitch;} void SetPitch(double pitch) {Pitch = pitch;}
void SetAdvance(double advance) {Advance = advance;}
/// Sets the P-Factor constant /// Sets the P-Factor constant
void SetPFactor(double pf) {P_Factor = pf;} void SetPFactor(double pf) {P_Factor = pf;}
@ -125,21 +127,21 @@ public:
/// Retrieves the pitch of the propeller in degrees. /// Retrieves the pitch of the propeller in degrees.
double GetPitch(void) { return Pitch; } double GetPitch(void) { return Pitch; }
/// Retrieves the RPMs of the propeller /// Retrieves the RPMs of the propeller
double GetRPM(void) { return RPM; } double GetRPM(void) { return RPM; }
/// Retrieves the propeller moment of inertia /// Retrieves the propeller moment of inertia
double GetIxx(void) { return Ixx; } double GetIxx(void) { return Ixx; }
/// Retrieves the Torque in foot-pounds (Don't you love the English system?) /// Retrieves the Torque in foot-pounds (Don't you love the English system?)
double GetTorque(void) { return vTorque(eX); } double GetTorque(void) { return vTorque(eX); }
/** Retrieves the power required (or "absorbed") by the propeller - /** Retrieves the power required (or "absorbed") by the propeller -
i.e. the power required to keep spinning the propeller at the current i.e. the power required to keep spinning the propeller at the current
velocity, air density, and rotational rate. */ velocity, air density, and rotational rate. */
double GetPowerRequired(void); double GetPowerRequired(void);
/** Calculates and returns the thrust produced by this propeller. /** Calculates and returns the thrust produced by this propeller.
Given the excess power available from the engine (in foot-pounds), the thrust is Given the excess power available from the engine (in foot-pounds), the thrust is
calculated, as well as the current RPM. The RPM is calculated by integrating calculated, as well as the current RPM. The RPM is calculated by integrating
@ -151,6 +153,8 @@ public:
@return the thrust in pounds */ @return the thrust in pounds */
double Calculate(double PowerAvailable); double Calculate(double PowerAvailable);
FGColumnVector3 GetPFactor(void); FGColumnVector3 GetPFactor(void);
string GetThrusterLabels(int id);
string GetThrusterValues(int id);
private: private:
int numBlades; int numBlades;
@ -164,6 +168,7 @@ private:
double P_Factor; double P_Factor;
double Sense; double Sense;
double Pitch; double Pitch;
double Advance;
double ExcessTorque; double ExcessTorque;
FGColumnVector3 vTorque; FGColumnVector3 vTorque;
FGTable *cThrust; FGTable *cThrust;

View file

@ -3,7 +3,7 @@
Module: FGPropulsion.cpp Module: FGPropulsion.cpp
Author: Jon S. Berndt Author: Jon S. Berndt
Date started: 08/20/00 Date started: 08/20/00
Purpose: Encapsulates the set of engines, tanks, and thrusters associated Purpose: Encapsulates the set of engines and tanks associated
with this aircraft with this aircraft
------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) ------------- ------------- Copyright (C) 2000 Jon S. Berndt (jsb@hal-pc.org) -------------
@ -28,21 +28,13 @@
FUNCTIONAL DESCRIPTION FUNCTIONAL DESCRIPTION
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
The Propulsion class is the container for the entire propulsion system, which is The Propulsion class is the container for the entire propulsion system, which is
comprised of engines, tanks, and "thrusters" (the device that transforms the comprised of engines and tanks. Once the Propulsion class gets the config file,
engine power into a force that acts on the aircraft, such as a nozzle or it reads in information which is specific to a type of engine. Then:
propeller). Once the Propulsion class gets the config file, it reads in
information which is specific to a type of engine. Then:
1) The appropriate engine type instance is created 1) The appropriate engine type instance is created
2) A thruster object is instantiated, and is linked to the engine 2) At least one tank object is created, and is linked to an engine.
3) At least one tank object is created, and is linked to an engine.
At Run time each engines Calculate() method is called to return the excess power At Run time each engines Calculate() method is called.
generated during that iteration. The drag from the previous iteration is sub-
tracted to give the excess power available for thrust this pass. That quantity
is passed to the thrusters associated with a particular engine - perhaps with a
scaling mechanism (gearing?) to allow the engine to give its associated thrust-
ers specific distributed portions of the excess power.
HISTORY HISTORY
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
@ -54,22 +46,11 @@ INCLUDES
#include "FGPropulsion.h" #include "FGPropulsion.h"
#include "FGRocket.h" #include "FGRocket.h"
#include "FGSimTurbine.h"
#include "FGTurbine.h" #include "FGTurbine.h"
#include "FGPropeller.h"
#include "FGNozzle.h"
#include "FGPiston.h" #include "FGPiston.h"
#include "FGElectric.h"
#include "FGPropertyManager.h" #include "FGPropertyManager.h"
#if defined (__APPLE__)
/* Not all systems have the gcvt function */
inline char* gcvt (double value, int ndigits, char *buf) {
/* note that this is not exactly what gcvt is supposed to do! */
snprintf (buf, ndigits+1, "%f", value);
return buf;
}
#endif
namespace JSBSim { namespace JSBSim {
static const char *IdSrc = "$Id$"; static const char *IdSrc = "$Id$";
@ -87,11 +68,11 @@ FGPropulsion::FGPropulsion(FGFDMExec* exec) : FGModel(exec)
Name = "FGPropulsion"; Name = "FGPropulsion";
numSelectedFuelTanks = numSelectedOxiTanks = 0; numSelectedFuelTanks = numSelectedOxiTanks = 0;
numTanks = numEngines = numThrusters = 0; numTanks = numEngines = 0;
numOxiTanks = numFuelTanks = 0; numOxiTanks = numFuelTanks = 0;
dt = 0.0;
ActiveEngine = -1; // -1: ALL, 0: Engine 1, 1: Engine 2 ... ActiveEngine = -1; // -1: ALL, 0: Engine 1, 1: Engine 2 ...
tankJ.InitMatrix(); tankJ.InitMatrix();
refuel = false;
bind(); bind();
@ -112,34 +93,33 @@ FGPropulsion::~FGPropulsion()
bool FGPropulsion::Run(void) bool FGPropulsion::Run(void)
{ {
double PowerAvailable; if (FGModel::Run()) return true;
dt = State->Getdt();
double dt = State->Getdt();
vForces.InitMatrix(); vForces.InitMatrix();
vMoments.InitMatrix(); vMoments.InitMatrix();
if (!FGModel::Run()) { for (unsigned int i=0; i<numEngines; i++) {
for (unsigned int i=0; i<numEngines; i++) { Engines[i]->Calculate();
Thrusters[i]->SetdeltaT(dt*rate); vForces += Engines[i]->GetBodyForces(); // sum body frame forces
PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired()); vMoments += Engines[i]->GetMoments(); // sum body frame moments
Thrusters[i]->Calculate(PowerAvailable);
vForces += Thrusters[i]->GetBodyForces(); // sum body frame forces
vMoments += Thrusters[i]->GetMoments(); // sum body frame moments
}
return false;
} else {
return true;
} }
for (unsigned int i=0; i<numTanks; i++) {
Tanks[i]->Calculate( dt * rate );
}
if (refuel) DoRefuel( dt * rate );
return false;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGPropulsion::GetSteadyState(void) bool FGPropulsion::GetSteadyState(void)
{ {
double PowerAvailable;
double currentThrust = 0, lastThrust=-1; double currentThrust = 0, lastThrust=-1;
dt = State->Getdt();
int steady_count,j=0; int steady_count,j=0;
bool steady=false; bool steady=false;
@ -149,13 +129,12 @@ bool FGPropulsion::GetSteadyState(void)
if (!FGModel::Run()) { if (!FGModel::Run()) {
for (unsigned int i=0; i<numEngines; i++) { for (unsigned int i=0; i<numEngines; i++) {
Engines[i]->SetTrimMode(true); Engines[i]->SetTrimMode(true);
Thrusters[i]->SetdeltaT(dt*rate);
steady=false; steady=false;
steady_count=0; steady_count=0;
while (!steady && j < 6000) { while (!steady && j < 6000) {
PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired()); Engines[i]->Calculate();
lastThrust = currentThrust; lastThrust = currentThrust;
currentThrust = Thrusters[i]->Calculate(PowerAvailable); currentThrust = Engines[i]->GetThrust();
if (fabs(lastThrust-currentThrust) < 0.0001) { if (fabs(lastThrust-currentThrust) < 0.0001) {
steady_count++; steady_count++;
if (steady_count > 120) { steady=true; } if (steady_count > 120) { steady=true; }
@ -164,8 +143,8 @@ bool FGPropulsion::GetSteadyState(void)
} }
j++; j++;
} }
vForces += Thrusters[i]->GetBodyForces(); // sum body frame forces vForces += Engines[i]->GetBodyForces(); // sum body frame forces
vMoments += Thrusters[i]->GetMoments(); // sum body frame moments vMoments += Engines[i]->GetMoments(); // sum body frame moments
Engines[i]->SetTrimMode(false); Engines[i]->SetTrimMode(false);
} }
@ -179,24 +158,20 @@ bool FGPropulsion::GetSteadyState(void)
bool FGPropulsion::ICEngineStart(void) bool FGPropulsion::ICEngineStart(void)
{ {
double PowerAvailable;
int j; int j;
dt = State->Getdt();
vForces.InitMatrix(); vForces.InitMatrix();
vMoments.InitMatrix(); vMoments.InitMatrix();
for (unsigned int i=0; i<numEngines; i++) { for (unsigned int i=0; i<numEngines; i++) {
Engines[i]->SetTrimMode(true); Engines[i]->SetTrimMode(true);
Thrusters[i]->SetdeltaT(dt*rate);
j=0; j=0;
while (!Engines[i]->GetRunning() && j < 2000) { while (!Engines[i]->GetRunning() && j < 2000) {
PowerAvailable = Engines[i]->Calculate(Thrusters[i]->GetPowerRequired()); Engines[i]->Calculate();
Thrusters[i]->Calculate(PowerAvailable);
j++; j++;
} }
vForces += Thrusters[i]->GetBodyForces(); // sum body frame forces vForces += Engines[i]->GetBodyForces(); // sum body frame forces
vMoments += Thrusters[i]->GetMoments(); // sum body frame moments vMoments += Engines[i]->GetMoments(); // sum body frame moments
Engines[i]->SetTrimMode(false); Engines[i]->SetTrimMode(false);
} }
return true; return true;
@ -206,20 +181,22 @@ bool FGPropulsion::ICEngineStart(void)
bool FGPropulsion::Load(FGConfigFile* AC_cfg) bool FGPropulsion::Load(FGConfigFile* AC_cfg)
{ {
string token, fullpath; string token, fullpath, localpath;
string engineFileName, engType; string engineFileName, engType;
string thrusterFileName, thrType;
string parameter; string parameter;
string enginePath = FDMExec->GetEnginePath(); string enginePath = FDMExec->GetEnginePath();
string aircraftPath = FDMExec->GetAircraftPath();
double xLoc, yLoc, zLoc, Pitch, Yaw; double xLoc, yLoc, zLoc, Pitch, Yaw;
double P_Factor = 0, Sense = 0.0;
int Feed; int Feed;
bool ThrottleAdded = false; bool ThrottleAdded = false;
FGConfigFile* Cfg_ptr = 0;
# ifndef macintosh # ifndef macintosh
fullpath = enginePath + "/"; fullpath = enginePath + "/";
localpath = aircraftPath + "/Engines/";
# else # else
fullpath = enginePath + ";"; fullpath = enginePath + ";";
localpath = aircraftPath + ";Engines;";
# endif # endif
AC_cfg->GetNextConfigLine(); AC_cfg->GetNextConfigLine();
@ -230,25 +207,44 @@ bool FGPropulsion::Load(FGConfigFile* AC_cfg)
engineFileName = AC_cfg->GetValue("FILE"); engineFileName = AC_cfg->GetValue("FILE");
if (debug_lvl > 0) cout << "\n Reading engine from file: " << fullpath // Look in the Aircraft/Engines directory first
+ engineFileName + ".xml"<< endl; Cfg_ptr = 0;
FGConfigFile Local_cfg(localpath + engineFileName + ".xml");
FGConfigFile Eng_cfg(fullpath + engineFileName + ".xml"); FGConfigFile Eng_cfg(fullpath + engineFileName + ".xml");
if (Local_cfg.IsOpen()) {
Cfg_ptr = &Local_cfg;
if (debug_lvl > 0) cout << "\n Reading engine from file: " << localpath
+ engineFileName + ".xml"<< endl;
} else {
if (Eng_cfg.IsOpen()) {
Cfg_ptr = &Eng_cfg;
if (debug_lvl > 0) cout << "\n Reading engine from file: " << fullpath
+ engineFileName + ".xml"<< endl;
}
}
if (Eng_cfg.IsOpen()) { if (Cfg_ptr) {
Eng_cfg.GetNextConfigLine(); Cfg_ptr->GetNextConfigLine();
engType = Eng_cfg.GetValue(); engType = Cfg_ptr->GetValue();
FCS->AddThrottle(); FCS->AddThrottle();
ThrottleAdded = true; ThrottleAdded = true;
if (engType == "FG_ROCKET") { if (engType == "FG_ROCKET") {
Engines.push_back(new FGRocket(FDMExec, &Eng_cfg)); Engines.push_back(new FGRocket(FDMExec, Cfg_ptr));
} else if (engType == "FG_PISTON") { } else if (engType == "FG_PISTON") {
Engines.push_back(new FGPiston(FDMExec, &Eng_cfg)); Engines.push_back(new FGPiston(FDMExec, Cfg_ptr));
} else if (engType == "FG_TURBINE") { } else if (engType == "FG_TURBINE") {
Engines.push_back(new FGTurbine(FDMExec, &Eng_cfg)); Engines.push_back(new FGTurbine(FDMExec, Cfg_ptr));
} else if (engType == "FG_SIMTURBINE") { } else if (engType == "FG_SIMTURBINE") {
Engines.push_back(new FGSimTurbine(FDMExec, &Eng_cfg)); cerr << endl;
cerr << "The FG_SIMTURBINE engine type has been renamed to FG_TURBINE." << endl;
cerr << "To fix this problem, simply replace the FG_SIMTURBINE name " << endl;
cerr << "in your engine file to FG_TURBINE." << endl;
cerr << endl;
Engines.push_back(new FGTurbine(FDMExec, Cfg_ptr));
} else if (engType == "FG_ELECTRIC") {
Engines.push_back(new FGElectric(FDMExec, Cfg_ptr));
} else { } else {
cerr << fgred << " Unrecognized engine type: " << underon << engType cerr << fgred << " Unrecognized engine type: " << underon << engType
<< underoff << " found in config file." << fgdef << endl; << underoff << " found in config file." << fgdef << endl;
@ -262,7 +258,12 @@ bool FGPropulsion::Load(FGConfigFile* AC_cfg)
else if (token == "YLOC") { *AC_cfg >> yLoc; } else if (token == "YLOC") { *AC_cfg >> yLoc; }
else if (token == "ZLOC") { *AC_cfg >> zLoc; } else if (token == "ZLOC") { *AC_cfg >> zLoc; }
else if (token == "PITCH") { *AC_cfg >> Pitch;} else if (token == "PITCH") { *AC_cfg >> Pitch;}
else if (token == "YAW") { *AC_cfg >> Yaw;} else if (token == "YAW") { *AC_cfg >> Yaw; }
else if (token.find("AC_THRUSTER") != string::npos) {
if (debug_lvl > 0) cout << "\n Reading thruster definition" << endl;
Engines.back()->LoadThruster(AC_cfg);
AC_cfg->GetNextConfigLine();
}
else if (token == "FEED") { else if (token == "FEED") {
*AC_cfg >> Feed; *AC_cfg >> Feed;
Engines[numEngines]->AddFeedTank(Feed); Engines[numEngines]->AddFeedTank(Feed);
@ -286,14 +287,14 @@ bool FGPropulsion::Load(FGConfigFile* AC_cfg)
} else { } else {
cerr << fgred << "\n Could not read engine config file: " << underon << cerr << fgred << "\n Could not read engine config file: " << underon <<
fullpath + engineFileName + ".xml" << underoff << fgdef << endl; engineFileName + ".xml" << underoff << fgdef << endl;
return false; return false;
} }
} else if (token == "AC_TANK") { // ============== READING TANKS } else if (token == "AC_TANK") { // ============== READING TANKS
if (debug_lvl > 0) cout << "\n Reading tank definition" << endl; if (debug_lvl > 0) cout << "\n Reading tank definition" << endl;
Tanks.push_back(new FGTank(AC_cfg)); Tanks.push_back(new FGTank(AC_cfg, FDMExec));
switch(Tanks[numTanks]->GetType()) { switch(Tanks[numTanks]->GetType()) {
case FGTank::ttFUEL: case FGTank::ttFUEL:
numSelectedFuelTanks++; numSelectedFuelTanks++;
@ -306,59 +307,6 @@ bool FGPropulsion::Load(FGConfigFile* AC_cfg)
} }
numTanks++; numTanks++;
} else if (token == "AC_THRUSTER") { // ========== READING THRUSTERS
thrusterFileName = AC_cfg->GetValue("FILE");
if (debug_lvl > 0) cout << "\n Reading thruster from file: " <<
fullpath + thrusterFileName + ".xml" << endl;
FGConfigFile Thruster_cfg(fullpath + thrusterFileName + ".xml");
if (Thruster_cfg.IsOpen()) {
Thruster_cfg.GetNextConfigLine();
thrType = Thruster_cfg.GetValue();
if (thrType == "FG_PROPELLER") {
Thrusters.push_back(new FGPropeller(FDMExec, &Thruster_cfg));
} else if (thrType == "FG_NOZZLE") {
Thrusters.push_back(new FGNozzle(FDMExec, &Thruster_cfg ));
} else if (thrType == "FG_DIRECT") {
Thrusters.push_back(new FGThruster( FDMExec, &Thruster_cfg) );
}
AC_cfg->GetNextConfigLine();
while ((token = AC_cfg->GetValue()) != string("/AC_THRUSTER")) {
*AC_cfg >> token;
if (token == "XLOC") *AC_cfg >> xLoc;
else if (token == "YLOC") *AC_cfg >> yLoc;
else if (token == "ZLOC") *AC_cfg >> zLoc;
else if (token == "PITCH") *AC_cfg >> Pitch;
else if (token == "YAW") *AC_cfg >> Yaw;
else if (token == "P_FACTOR") *AC_cfg >> P_Factor;
else if (token == "SENSE") *AC_cfg >> Sense;
else cerr << "Unknown identifier: " << token << " in engine file: "
<< engineFileName << endl;
}
Thrusters[numThrusters]->SetLocation(xLoc, yLoc, zLoc);
Thrusters[numThrusters]->SetAnglesToBody(0, Pitch, Yaw);
if (thrType == "FG_PROPELLER" && P_Factor > 0.001) {
((FGPropeller*)Thrusters[numThrusters])->SetPFactor(P_Factor);
if (debug_lvl > 0) cout << " P-Factor: " << P_Factor << endl;
((FGPropeller*)Thrusters[numThrusters])->SetSense(fabs(Sense)/Sense);
if (debug_lvl > 0) cout << " Sense: " << Sense << endl;
}
Thrusters[numThrusters]->SetdeltaT(dt*rate);
Thrusters[numThrusters]->SetThrusterNumber(numThrusters);
numThrusters++;
} else {
cerr << "Could not read thruster config file: " << fullpath
+ thrusterFileName + ".xml" << endl;
return false;
}
} }
AC_cfg->GetNextConfigLine(); AC_cfg->GetNextConfigLine();
} }
@ -375,58 +323,12 @@ string FGPropulsion::GetPropulsionStrings(void)
{ {
string PropulsionStrings = ""; string PropulsionStrings = "";
bool firstime = true; bool firstime = true;
char buffer[5];
for (unsigned int i=0;i<Engines.size();i++) { for (unsigned int i=0;i<Engines.size();i++) {
if (firstime) firstime = false; if (firstime) firstime = false;
else PropulsionStrings += ", "; else PropulsionStrings += ", ";
sprintf(buffer, "%d", i); PropulsionStrings += Engines[i]->GetEngineLabels() + ", ";
switch(Engines[i]->GetType()) {
case FGEngine::etPiston:
PropulsionStrings += (Engines[i]->GetName() + "_PwrAvail[" + buffer + "]");
break;
case FGEngine::etRocket:
PropulsionStrings += (Engines[i]->GetName() + "_ChamberPress[" + buffer + "]");
break;
case FGEngine::etTurbine:
break;
case FGEngine::etSimTurbine:
PropulsionStrings += (Engines[i]->GetName() + "_N1[" + buffer + "], ");
PropulsionStrings += (Engines[i]->GetName() + "_N2[" + buffer + "]");
break;
default:
PropulsionStrings += "INVALID ENGINE TYPE";
break;
}
PropulsionStrings += ", ";
FGPropeller* Propeller = (FGPropeller*)Thrusters[i];
switch(Thrusters[i]->GetType()) {
case FGThruster::ttNozzle:
PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "]");
break;
case FGThruster::ttRotor:
break;
case FGThruster::ttPropeller:
PropulsionStrings += (Thrusters[i]->GetName() + "_Torque[" + buffer + "], ");
PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Roll[" + buffer + "], ");
PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Pitch[" + buffer + "], ");
PropulsionStrings += (Thrusters[i]->GetName() + "_PFactor_Yaw[" + buffer + "], ");
PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "], ");
if (Propeller->IsVPitch())
PropulsionStrings += (Thrusters[i]->GetName() + "_Pitch[" + buffer + "], ");
PropulsionStrings += (Thrusters[i]->GetName() + "_RPM[" + buffer + "]");
break;
case FGThruster::ttDirect:
PropulsionStrings += (Thrusters[i]->GetName() + "_Thrust[" + buffer + "]");
break;
default:
PropulsionStrings += "INVALID THRUSTER TYPE";
break;
}
} }
return PropulsionStrings; return PropulsionStrings;
@ -436,7 +338,6 @@ string FGPropulsion::GetPropulsionStrings(void)
string FGPropulsion::GetPropulsionValues(void) string FGPropulsion::GetPropulsionValues(void)
{ {
char buff[20];
string PropulsionValues = ""; string PropulsionValues = "";
bool firstime = true; bool firstime = true;
@ -444,45 +345,7 @@ string FGPropulsion::GetPropulsionValues(void)
if (firstime) firstime = false; if (firstime) firstime = false;
else PropulsionValues += ", "; else PropulsionValues += ", ";
switch(Engines[i]->GetType()) { PropulsionValues += Engines[i]->GetEngineValues() + ", ";
case FGEngine::etPiston:
PropulsionValues += (string(gcvt(((FGPiston*)Engines[i])->GetPowerAvailable(), 10, buff)));
break;
case FGEngine::etRocket:
PropulsionValues += (string(gcvt(((FGRocket*)Engines[i])->GetChamberPressure(), 10, buff)));
break;
case FGEngine::etTurbine:
break;
case FGEngine::etSimTurbine:
PropulsionValues += (string(gcvt(((FGSimTurbine*)Engines[i])->GetN1(), 10, buff))) + ", ";
PropulsionValues += (string(gcvt(((FGSimTurbine*)Engines[i])->GetN2(), 10, buff)));
break;
}
PropulsionValues += ", ";
switch(Thrusters[i]->GetType()) {
case FGThruster::ttNozzle:
PropulsionValues += (string(gcvt(((FGNozzle*)Thrusters[i])->GetThrust(), 10, buff)));
break;
case FGThruster::ttRotor:
break;
case FGThruster::ttDirect:
PropulsionValues += (string(gcvt(((FGThruster*)Thrusters[i])->GetThrust(), 10, buff)));
break;
case FGThruster::ttPropeller:
FGPropeller* Propeller = (FGPropeller*)Thrusters[i];
FGColumnVector3 vPFactor = Propeller->GetPFactor();
PropulsionValues += string(gcvt(Propeller->GetTorque(), 10, buff)) + ", ";
PropulsionValues += string(gcvt(vPFactor(eRoll), 10, buff)) + ", ";
PropulsionValues += string(gcvt(vPFactor(ePitch), 10, buff)) + ", ";
PropulsionValues += string(gcvt(vPFactor(eYaw), 10, buff)) + ", ";
PropulsionValues += string(gcvt(Propeller->GetThrust(), 10, buff)) + ", ";
if (Propeller->IsVPitch())
PropulsionValues += string(gcvt(Propeller->GetPitch(), 10, buff)) + ", ";
PropulsionValues += string(gcvt(Propeller->GetRPM(), 10, buff));
break;
}
} }
return PropulsionValues; return PropulsionValues;
@ -574,15 +437,15 @@ void FGPropulsion::SetCutoff(int setting)
if (ActiveEngine < 0) { if (ActiveEngine < 0) {
for (unsigned i=0; i<Engines.size(); i++) { for (unsigned i=0; i<Engines.size(); i++) {
if (setting == 0) if (setting == 0)
((FGSimTurbine*)Engines[i])->SetCutoff(false); ((FGTurbine*)Engines[i])->SetCutoff(false);
else else
((FGSimTurbine*)Engines[i])->SetCutoff(true); ((FGTurbine*)Engines[i])->SetCutoff(true);
} }
} else { } else {
if (setting == 0) if (setting == 0)
((FGSimTurbine*)Engines[ActiveEngine])->SetCutoff(false); ((FGTurbine*)Engines[ActiveEngine])->SetCutoff(false);
else else
((FGSimTurbine*)Engines[ActiveEngine])->SetCutoff(true); ((FGTurbine*)Engines[ActiveEngine])->SetCutoff(true);
} }
} }
@ -598,6 +461,44 @@ void FGPropulsion::SetActiveEngine(int engine)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGPropulsion::Transfer(int source, int target, double amount)
{
double shortage, overage;
if (source == -1) {
shortage = 0.0;
} else {
shortage = Tanks[source]->Drain(amount);
}
if (target == -1) {
overage = 0.0;
} else {
overage = Tanks[target]->Fill(amount - shortage);
}
return overage;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGPropulsion::DoRefuel(double time_slice)
{
double fillrate = 100 * time_slice; // 100 lbs/sec = 6000 lbs/min
int TanksNotFull = 0;
for (unsigned int i=0; i<numTanks; i++) {
if (Tanks[i]->GetPctFull() < 99.99) ++TanksNotFull;
}
if (TanksNotFull) {
for (unsigned int i=0; i<numTanks; i++) {
if (Tanks[i]->GetPctFull() < 99.99)
Transfer(-1, i, fillrate/TanksNotFull);
}
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGPropulsion::bind(void) void FGPropulsion::bind(void)
{ {
typedef double (FGPropulsion::*PMF)(int) const; typedef double (FGPropulsion::*PMF)(int) const;

View file

@ -55,7 +55,6 @@ INCLUDES
#include "FGModel.h" #include "FGModel.h"
#include "FGEngine.h" #include "FGEngine.h"
#include "FGTank.h" #include "FGTank.h"
#include "FGThruster.h"
#include "FGMatrix33.h" #include "FGMatrix33.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -76,27 +75,18 @@ CLASS DOCUMENTATION
/** Propulsion management class. /** Propulsion management class.
The Propulsion class is the container for the entire propulsion system, which is The Propulsion class is the container for the entire propulsion system, which is
comprised of engines, tanks, and "thrusters" (the device that transforms the comprised of engines, and tanks. Once the Propulsion class gets the config file,
engine power into a force that acts on the aircraft, such as a nozzle or it reads in information which is specific to a type of engine. Then:
propeller). Once the Propulsion class gets the config file, it reads in
information which is specific to a type of engine. Then:
-# The appropriate engine type instance is created -# The appropriate engine type instance is created
-# A thruster object is instantiated, and is linked to the engine
-# At least one tank object is created, and is linked to an engine. -# At least one tank object is created, and is linked to an engine.
At Run time each engines Calculate() method is called to return the excess power At Run time each engines Calculate() method is called.
generated during that iteration. The drag from the previous iteration is sub-
tracted to give the excess power available for thrust this pass. That quantity
is passed to the thrusters associated with a particular engine - perhaps with a
scaling mechanism (gearing?) to allow the engine to give its associated thrust-
ers specific distributed portions of the excess power.
@author Jon S. Berndt @author Jon S. Berndt
@version $Id$ @version $Id$
@see @see
FGEngine FGEngine
FGTank FGTank
FGThruster
*/ */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -113,22 +103,12 @@ public:
/** Executes the propulsion model. /** Executes the propulsion model.
The initial plan for the FGPropulsion class calls for Run() to be executed, The initial plan for the FGPropulsion class calls for Run() to be executed,
performing the following tasks: calculating the power available from the engine.
<ol>
<li>Determine the drag - or power required - for the attached thrust effector
for this engine so that any feedback to the engine can be performed. This
is done by calling FGThruster::CalculatePReq()</li>
<li>Given 1, above, calculate the power available from the engine. This is
done by calling FGEngine::CalculatePAvail()</li>
<li>Next, calculate the thrust output from the thruster model given the power
available and the power required. This may also result in new performance
numbers for the thruster in the case of the propeller, at least. This
result is returned from a call to Calculate().</li></ol>
[Note: Should we be checking the Starved flag here?] */ [Note: Should we be checking the Starved flag here?] */
bool Run(void); bool Run(void);
/** Loads the propulsion system (engine[s], tank[s], thruster[s]). /** Loads the propulsion system (engine[s] and tank[s]).
Characteristics of the propulsion system are read in from the config file. Characteristics of the propulsion system are read in from the config file.
@param AC_cfg pointer to the config file instance that describes the @param AC_cfg pointer to the config file instance that describes the
aircraft being modeled. aircraft being modeled.
@ -157,21 +137,13 @@ public:
if (index <= Tanks.size()-1) return Tanks[index]; if (index <= Tanks.size()-1) return Tanks[index];
else return 0L; } else return 0L; }
/** Retrieves a thruster object pointer from the list of thrusters.
@param index the thruster index within the vector container
@return the address of the specific thruster, or zero if no such thruster is
available */
inline FGThruster* GetThruster(unsigned int index) {
if (index <= Thrusters.size()-1) return Thrusters[index];
else return 0L; }
/** Returns the number of fuel tanks currently actively supplying fuel */ /** Returns the number of fuel tanks currently actively supplying fuel */
inline int GetnumSelectedFuelTanks(void) const {return numSelectedFuelTanks;} inline int GetnumSelectedFuelTanks(void) const {return numSelectedFuelTanks;}
/** Returns the number of oxidizer tanks currently actively supplying oxidizer */ /** Returns the number of oxidizer tanks currently actively supplying oxidizer */
inline int GetnumSelectedOxiTanks(void) const {return numSelectedOxiTanks;} inline int GetnumSelectedOxiTanks(void) const {return numSelectedOxiTanks;}
/** Loops the engines/thrusters until thrust output steady (used for trimming) */ /** Loops the engines until thrust output steady (used for trimming) */
bool GetSteadyState(void); bool GetSteadyState(void);
/** starts the engines in IC mode (dt=0). All engine-specific setup must /** starts the engines in IC mode (dt=0). All engine-specific setup must
@ -186,6 +158,11 @@ public:
inline FGColumnVector3& GetMoments(void) {return vMoments;} inline FGColumnVector3& GetMoments(void) {return vMoments;}
inline double GetMoments(int n) const {return vMoments(n);} inline double GetMoments(int n) const {return vMoments(n);}
inline bool GetRefuel(void) {return refuel;}
inline void SetRefuel(bool setting) {refuel = setting;}
double Transfer(int source, int target, double amount);
void DoRefuel(double time_slice);
FGColumnVector3& GetTanksMoment(void); FGColumnVector3& GetTanksMoment(void);
double GetTanksWeight(void); double GetTanksWeight(void);
@ -209,21 +186,20 @@ private:
vector <FGEngine*> Engines; vector <FGEngine*> Engines;
vector <FGTank*> Tanks; vector <FGTank*> Tanks;
vector <FGTank*>::iterator iTank; vector <FGTank*>::iterator iTank;
vector <FGThruster*> Thrusters;
unsigned int numSelectedFuelTanks; unsigned int numSelectedFuelTanks;
unsigned int numSelectedOxiTanks; unsigned int numSelectedOxiTanks;
unsigned int numFuelTanks; unsigned int numFuelTanks;
unsigned int numOxiTanks; unsigned int numOxiTanks;
unsigned int numEngines; unsigned int numEngines;
unsigned int numTanks; unsigned int numTanks;
unsigned int numThrusters;
int ActiveEngine; int ActiveEngine;
double dt;
FGColumnVector3 vForces; FGColumnVector3 vForces;
FGColumnVector3 vMoments; FGColumnVector3 vMoments;
FGColumnVector3 vTankXYZ; FGColumnVector3 vTankXYZ;
FGColumnVector3 vXYZtank_arm; FGColumnVector3 vXYZtank_arm;
FGMatrix33 tankJ; FGMatrix33 tankJ;
bool refuel;
void Debug(int from); void Debug(int from);
}; };
} }

View file

@ -0,0 +1,235 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Module: FGQuaternion.cpp
Author: Jon Berndt, Mathias Froehlich
Date started: 12/02/98
------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------------
------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org.
HISTORY
-------------------------------------------------------------------------------
12/02/98 JSB Created
15/01/04 Mathias Froehlich implemented a quaternion class from many places
in JSBSim.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifdef FGFS
# include <math.h>
# include <simgear/compiler.h>
# include STL_IOSTREAM
SG_USING_STD(cerr);
SG_USING_STD(cout);
SG_USING_STD(endl);
#else
# include <string>
# if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
# include <iostream.h>
# include <math.h>
# else
# include <iostream>
# if defined(sgi) && !defined(__GNUC__)
# include <math.h>
# else
# include <cmath>
# endif
using std::cerr;
using std::cout;
using std::endl;
# endif
#endif
#include "FGMatrix33.h"
#include "FGColumnVector3.h"
#include "FGQuaternion.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
namespace JSBSim {
static const char *IdSrc = "$Id$";
static const char *IdHdr = ID_QUATERNION;
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Initialize from q
FGQuaternion::FGQuaternion(const FGQuaternion& q)
: mCacheValid(q.mCacheValid) {
Entry(1) = q(1);
Entry(2) = q(2);
Entry(3) = q(3);
Entry(4) = q(4);
if (mCacheValid) {
mT = q.mT;
mTInv = q.mTInv;
mEulerAngles = q.mEulerAngles;
mEulerSines = q.mEulerSines;
mEulerCosines = q.mEulerCosines;
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Initialize with the three euler angles
FGQuaternion::FGQuaternion(double phi, double tht, double psi)
: mCacheValid(false) {
double thtd2 = 0.5*tht;
double psid2 = 0.5*psi;
double phid2 = 0.5*phi;
double Sthtd2 = sin(thtd2);
double Spsid2 = sin(psid2);
double Sphid2 = sin(phid2);
double Cthtd2 = cos(thtd2);
double Cpsid2 = cos(psid2);
double Cphid2 = cos(phid2);
double Cphid2Cthtd2 = Cphid2*Cthtd2;
double Cphid2Sthtd2 = Cphid2*Sthtd2;
double Sphid2Sthtd2 = Sphid2*Sthtd2;
double Sphid2Cthtd2 = Sphid2*Cthtd2;
Entry(1) = Cphid2Cthtd2*Cpsid2 + Sphid2Sthtd2*Spsid2;
Entry(2) = Sphid2Cthtd2*Cpsid2 - Cphid2Sthtd2*Spsid2;
Entry(3) = Cphid2Sthtd2*Cpsid2 + Sphid2Cthtd2*Spsid2;
Entry(4) = Cphid2Cthtd2*Spsid2 - Sphid2Sthtd2*Cpsid2;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
/**
Returns the derivative of the quaternion coresponding to the
angular velocities PQR.
*/
FGQuaternion FGQuaternion::GetQDot(const FGColumnVector3& PQR) const {
FGQuaternion QDot;
QDot(1) = -0.5*(Entry(2)*PQR(eP) + Entry(3)*PQR(eQ) + Entry(4)*PQR(eR));
QDot(2) = 0.5*(Entry(1)*PQR(eP) + Entry(3)*PQR(eR) - Entry(4)*PQR(eQ));
QDot(3) = 0.5*(Entry(1)*PQR(eQ) + Entry(4)*PQR(eP) - Entry(2)*PQR(eR));
QDot(4) = 0.5*(Entry(1)*PQR(eR) + Entry(2)*PQR(eQ) - Entry(3)*PQR(eP));
return QDot;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGQuaternion::Normalize()
{
// Note: this does not touch the cache
// since it does not change the orientation ...
double norm = Magnitude();
if (norm == 0.0)
return;
double rnorm = 1.0/norm;
Entry(1) *= rnorm;
Entry(2) *= rnorm;
Entry(3) *= rnorm;
Entry(4) *= rnorm;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// Compute the derived values if required ...
void FGQuaternion::ComputeDerivedUnconditional(void) const
{
mCacheValid = true;
// First normalize the 4-vector
double norm = Magnitude();
if (norm == 0.0)
return;
double rnorm = 1.0/norm;
double q1 = rnorm*Entry(1);
double q2 = rnorm*Entry(2);
double q3 = rnorm*Entry(3);
double q4 = rnorm*Entry(4);
// Now compute the transformation matrix.
double q1q1 = q1*q1;
double q2q2 = q2*q2;
double q3q3 = q3*q3;
double q4q4 = q4*q4;
double q1q2 = q1*q2;
double q1q3 = q1*q3;
double q1q4 = q1*q4;
double q2q3 = q2*q3;
double q2q4 = q2*q4;
double q3q4 = q3*q4;
mT(1,1) = q1q1 + q2q2 - q3q3 - q4q4;
mT(1,2) = 2.0*(q2q3 + q1q4);
mT(1,3) = 2.0*(q2q4 - q1q3);
mT(2,1) = 2.0*(q2q3 - q1q4);
mT(2,2) = q1q1 - q2q2 + q3q3 - q4q4;
mT(2,3) = 2.0*(q3q4 + q1q2);
mT(3,1) = 2.0*(q2q4 + q1q3);
mT(3,2) = 2.0*(q3q4 - q1q2);
mT(3,3) = q1q1 - q2q2 - q3q3 + q4q4;
// Since this is an orthogonal matrix, the inverse is simply
// the transpose.
mTInv = mT;
mTInv.T();
// Compute the Euler-angles
if (mT(3,3) == 0.0)
mEulerAngles(ePhi) = 0.5*M_PI;
else
mEulerAngles(ePhi) = atan2(mT(2,3), mT(3,3));
if (mT(1,3) < -1.0)
mEulerAngles(eTht) = 0.5*M_PI;
else if (1.0 < mT(1,3))
mEulerAngles(eTht) = -0.5*M_PI;
else
mEulerAngles(eTht) = asin(-mT(1,3));
if (mT(1,1) == 0.0)
mEulerAngles(ePsi) = 0.5*M_PI;
else {
double psi = atan2(mT(1,2), mT(1,1));
if (psi < 0.0)
psi += 2*M_PI;
mEulerAngles(ePsi) = psi;
}
// FIXME: may be one can compute those values easier ???
mEulerSines(ePhi) = sin(mEulerAngles(ePhi));
// mEulerSines(eTht) = sin(mEulerAngles(eTht));
mEulerSines(eTht) = -mT(1,3);
mEulerSines(ePsi) = sin(mEulerAngles(ePsi));
mEulerCosines(ePhi) = cos(mEulerAngles(ePhi));
mEulerCosines(eTht) = cos(mEulerAngles(eTht));
mEulerCosines(ePsi) = cos(mEulerAngles(ePsi));
}
} // namespace JSBSim

View file

@ -0,0 +1,499 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Header: FGQuaternion.h
Author: Jon Berndt, Mathis Froehlich
Date started: 12/02/98
------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------------
------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org.
HISTORY
-------------------------------------------------------------------------------
12/02/98 JSB Created
15/01/04 MF Quaternion class from old FGColumnVector4
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifndef FGQUATERNION_H
#define FGQUATERNION_H
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGJSBBase.h"
#include "FGMatrix33.h"
#include "FGColumnVector3.h"
#include "FGPropertyManager.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_QUATERNION "$Id$"
namespace JSBSim {
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Models the Quaternion representation of rotations.
FGQuaternion is a representation of an arbitrary rotation through a
quaternion. It has vector properties. This class also contains access
functions to the euler angle representation of rotations and access to
transformation matrices for 3D vectors. Transformations and euler angles are
therefore computed once they are requested for the first time. Then they are
cached for later usage as long as the class is not accessed trough
a nonconst member function.
Note: The order of rotations used in this class corresponds to a 3-2-1 sequence,
or Y-P-R, or Z-Y-X, if you prefer.
@see Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
School, January 1994
@see D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
JSC 12960, July 1977
@see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
NASA-Ames", NASA CR-2497, January 1975
@see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
Wiley & Sons, 1979 ISBN 0-471-03032-5
@see Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
1982 ISBN 0-471-08936-2
@author Mathias Froehlich, extended FGColumnVector4 originally by Tony Peden
and Jon Berndt
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGQuaternion
: virtual FGJSBBase {
public:
/** Default initializer.
Default initializer, initializes the class with the identity rotation. */
FGQuaternion() : mCacheValid(false) {
Entry(1) = 1.0;
Entry(2) = Entry(3) = Entry(4) = 0.0;
}
/** Copy constructor.
Copy constructor, initializes the quaternion.
@param q a constant reference to another FGQuaternion instance */
FGQuaternion(const FGQuaternion& q);
/** Initializer by euler angles.
Initialize the quaternion with the euler angles.
@param phi The euler X axis (roll) angle in radians
@param tht The euler Y axis (attitude) angle in radians
@param psi The euler Z axis (heading) angle in radians */
FGQuaternion(double phi, double tht, double psi);
/// Destructor.
~FGQuaternion() {}
/** Quaternion 'velocity' for given angular rates.
Computes the quaternion derivative which results from the given
angular velocities
@param PQR a constant reference to the body rate vector
@return the quaternion derivative */
FGQuaternion GetQDot(const FGColumnVector3& PQR) const;
/** Transformation matrix.
@return a reference to the transformation/rotation matrix
corresponding to this quaternion rotation. */
const FGMatrix33& GetT() const { ComputeDerived(); return mT; }
/** Backward transformation matrix.
@return a reference to the inverse transformation/rotation matrix
corresponding to this quaternion rotation. */
const FGMatrix33& GetTInv() const { ComputeDerived(); return mTInv; }
/** Retrieves the Euler angles.
@return a reference to the triad of euler angles corresponding
to this quaternion rotation.
@units radians */
const FGColumnVector3& GetEuler() const {
ComputeDerived();
return mEulerAngles;
}
/** Euler angle theta.
@return the euler angle theta (pitch attitude) corresponding to this
quaternion rotation.
@units radians */
double GetEulerTheta() const {
ComputeDerived();
return mEulerAngles(eTht);
}
/** Euler angle theta.
@return the euler angle theta (pitch attitude) corresponding to
this quaternion rotation.
@units degrees */
double GetEulerThetaDeg() const {
ComputeDerived();
return radtodeg*mEulerAngles(eTht);
}
/** Euler angle psi.
@return the heading euler angle (psi) corresponding to this quaternion
rotation.
@units radians */
double GetEulerPsi() const {
ComputeDerived();
return mEulerAngles(ePsi);
}
/** Retrieves the heading angle.
@return the Euler angle psi (heading) corresponding to this quaternion
rotation.
@units degrees */
double GetEulerPsiDeg() const {
ComputeDerived();
return radtodeg*mEulerAngles(ePsi);
}
/** Retrieves the roll angle.
@return the euler angle phi (roll) corresponding to this quaternion
rotation.
@units radians */
double GetEulerPhi() const {
ComputeDerived();
return mEulerAngles(ePhi);
}
/** Retrieves the roll angle.
Returns the Euler angle phi (roll) corresponding to this quaternion rotation.
@units degrees */
double GetEulerPhiDeg() const {
ComputeDerived();
return radtodeg*mEulerAngles(ePhi);
}
/** Retrieves sine theta.
@return the sine of the Euler angle theta (pitch attitude) corresponding
to this quaternion rotation. */
double GetSinEulerTheta() const {
ComputeDerived();
return mEulerSines(eTht);
}
/** Retrieves sine psi.
@return the sine of the Euler angle psi (heading) corresponding to this
quaternion rotation. */
double GetSinEulerPsi() const {
ComputeDerived();
return mEulerSines(ePsi);
}
/** Sine of euler angle phi.
@return the sine of the Euler angle phi (roll) corresponding to this
quaternion rotation. */
double GetSinEulerPhi() const {
ComputeDerived();
return mEulerSines(ePhi);
}
/** Cosine of euler angle theta.
@return the cosine of the Euler angle theta (pitch) corresponding to this
quaternion rotation. */
double GetCosEulerTheta() const {
ComputeDerived();
return mEulerCosines(eTht);
}
/** Cosine of euler angle psi.
@return the cosine of the Euler angle psi (heading) corresponding to this
quaternion rotation. */
double GetCosEulerPsi() const {
ComputeDerived();
return mEulerCosines(ePsi);
}
/** Cosine of euler angle phi.
@return the cosine of the Euler angle phi (roll) corresponding to this
quaternion rotation. */
double GetCosEulerPhi() const {
ComputeDerived();
return mEulerCosines(ePhi);
}
/** Read access the entries of the vector.
@param idx the component index.
Return the value of the matrix entry at the given index.
Indices are counted starting with 1.
Note that the index given in the argument is unchecked.
*/
double operator()(unsigned int idx) const { return Entry(idx); }
/** Write access the entries of the vector.
@param idx the component index.
Return a reference to the vector entry at the given index.
Indices are counted starting with 1.
Note that the index given in the argument is unchecked.
*/
double& operator()(unsigned int idx) { return Entry(idx); }
/** Read access the entries of the vector.
@param idx the component index.
Return the value of the matrix entry at the given index.
Indices are counted starting with 1.
This function is just a shortcut for the @ref double
operator()(unsigned int idx) const function. It is
used internally to access the elements in a more convenient way.
Note that the index given in the argument is unchecked.
*/
double Entry(unsigned int idx) const { return mData[idx-1]; }
/** Write access the entries of the vector.
@param idx the component index.
Return a reference to the vector entry at the given index.
Indices are counted starting with 1.
This function is just a shortcut for the @ref double&
operator()(unsigned int idx) function. It is
used internally to access the elements in a more convenient way.
Note that the index given in the argument is unchecked.
*/
double& Entry(unsigned int idx) { mCacheValid = false; return mData[idx-1]; }
/** Assignment operator "=".
Assign the value of q to the current object. Cached values are
conserved.
@param q reference to an FGQuaternion instance
@return reference to a quaternion object */
const FGQuaternion& operator=(const FGQuaternion& q) {
// Copy the master values ...
Entry(1) = q(1);
Entry(2) = q(2);
Entry(3) = q(3);
Entry(4) = q(4);
// .. and copy the derived values if they are valid
mCacheValid = q.mCacheValid;
if (mCacheValid) {
mT = q.mT;
mTInv = q.mTInv;
mEulerAngles = q.mEulerAngles;
mEulerSines = q.mEulerSines;
mEulerCosines = q.mEulerCosines;
}
return *this;
}
/** Comparison operator "==".
@param q a quaternion reference
@return true if both quaternions represent the same rotation. */
bool operator==(const FGQuaternion& q) const {
return Entry(1) == q(1) && Entry(2) == q(2)
&& Entry(3) == q(3) && Entry(4) == q(4);
}
/** Comparison operator "!=".
@param q a quaternion reference
@return true if both quaternions do not represent the same rotation. */
bool operator!=(const FGQuaternion& q) const { return ! operator==(q); }
const FGQuaternion& operator+=(const FGQuaternion& q) {
// Copy the master values ...
Entry(1) += q(1);
Entry(2) += q(2);
Entry(3) += q(3);
Entry(4) += q(4);
mCacheValid = false;
return *this;
}
/** Arithmetic operator "-=".
@param q a quaternion reference.
@return a quaternion reference representing Q, where Q = Q - q. */
const FGQuaternion& operator-=(const FGQuaternion& q) {
// Copy the master values ...
Entry(1) -= q(1);
Entry(2) -= q(2);
Entry(3) -= q(3);
Entry(4) -= q(4);
mCacheValid = false;
return *this;
}
/** Arithmetic operator "*=".
@param scalar a multiplicative value.
@return a quaternion reference representing Q, where Q = Q * scalar. */
const FGQuaternion& operator*=(double scalar) {
Entry(1) *= scalar;
Entry(2) *= scalar;
Entry(3) *= scalar;
Entry(4) *= scalar;
mCacheValid = false;
return *this;
}
/** Arithmetic operator "/=".
@param scalar a divisor value.
@return a quaternion reference representing Q, where Q = Q / scalar. */
const FGQuaternion& operator/=(double scalar) {
return operator*=(1.0/scalar);
}
/** Arithmetic operator "+".
@param q a quaternion to be summed.
@return a quaternion representing Q, where Q = Q + q. */
FGQuaternion operator+(const FGQuaternion& q) const {
return FGQuaternion(Entry(1)+q(1), Entry(2)+q(2),
Entry(3)+q(3), Entry(4)+q(4));
}
/** Arithmetic operator "-".
@param q a quaternion to be subtracted.
@return a quaternion representing Q, where Q = Q - q. */
FGQuaternion operator-(const FGQuaternion& q) const {
return FGQuaternion(Entry(1)-q(1), Entry(2)-q(2),
Entry(3)-q(3), Entry(4)-q(4));
}
/** Arithmetic operator "*".
Multiplication of two quaternions is like performing successive rotations.
@param q a quaternion to be multiplied.
@return a quaternion representing Q, where Q = Q * q. */
FGQuaternion operator*(const FGQuaternion& q) const {
return FGQuaternion(Entry(1)*q(1)-Entry(2)*q(2)-Entry(3)*q(3)-Entry(4)*q(4),
Entry(1)*q(2)+Entry(2)*q(1)+Entry(3)*q(4)-Entry(4)*q(3),
Entry(1)*q(3)-Entry(2)*q(4)+Entry(3)*q(1)+Entry(4)*q(2),
Entry(1)*q(4)+Entry(2)*q(3)-Entry(3)*q(2)+Entry(4)*q(1));
}
/** Arithmetic operator "*=".
Multiplication of two quaternions is like performing successive rotations.
@param q a quaternion to be multiplied.
@return a quaternion reference representing Q, where Q = Q * q. */
const FGQuaternion& operator*=(const FGQuaternion& q) {
double q0 = Entry(1)*q(1)-Entry(2)*q(2)-Entry(3)*q(3)-Entry(4)*q(4);
double q1 = Entry(1)*q(2)+Entry(2)*q(1)+Entry(3)*q(4)-Entry(4)*q(3);
double q2 = Entry(1)*q(3)-Entry(2)*q(4)+Entry(3)*q(1)+Entry(4)*q(2);
double q3 = Entry(1)*q(4)+Entry(2)*q(3)-Entry(3)*q(2)+Entry(4)*q(1);
Entry(1) = q0;
Entry(2) = q1;
Entry(3) = q2;
Entry(4) = q3;
mCacheValid = false;
return *this;
}
friend FGQuaternion operator*(double, const FGQuaternion&);
/** Length of the vector.
Compute and return the euclidean norm of this vector.
*/
double Magnitude() const { return sqrt(SqrMagnitude()); }
/** Square of the length of the vector.
Compute and return the square of the euclidean norm of this vector.
*/
double SqrMagnitude() const {
return Entry(1)*Entry(1)+Entry(2)*Entry(2)
+Entry(3)*Entry(3)+Entry(4)*Entry(4);
}
/** Normialze.
Normalize the vector to have the Magnitude() == 1.0. If the vector
is equal to zero it is left untouched.
*/
void Normalize();
/** Zero quaternion vector. Does not represent any orientation.
Useful for initialization of increments */
static FGQuaternion zero(void) { return FGQuaternion( 0.0, 0.0, 0.0, 0.0 ); }
private:
/** Copying by assigning the vector valued components. */
FGQuaternion(double q1, double q2, double q3, double q4) : mCacheValid(false)
{ Entry(1) = q1; Entry(2) = q2; Entry(3) = q3; Entry(4) = q4; }
/** Computation of derived values.
This function recomputes the derived values like euler angles and
transformation matrices. It does this unconditionally. */
void ComputeDerivedUnconditional(void) const;
/** Computation of derived values.
This function checks if the derived values like euler angles and
transformation matrices are already computed. If so, it
returns. If they need to be computed this is done here. */
void ComputeDerived(void) const {
if (!mCacheValid)
ComputeDerivedUnconditional();
}
/** The quaternion values itself. This is the master copy. */
double mData[4];
/** A data validity flag.
This class implements caching of the derived values like the
orthogonal rotation matrices or the Euler angles. For caching we
carry a flag which signals if the values are valid or not.
The C++ keyword "mutable" tells the compiler that the data member is
allowed to change during a const member function. */
mutable bool mCacheValid;
/** This stores the transformation matrices. */
mutable FGMatrix33 mT;
mutable FGMatrix33 mTInv;
/** The cached euler angles. */
mutable FGColumnVector3 mEulerAngles;
/** The cached sines and cosines of the euler angles. */
mutable FGColumnVector3 mEulerSines;
mutable FGColumnVector3 mEulerCosines;
};
/** Scalar multiplication.
@param scalar scalar value to multiply with.
@param p Vector to multiply.
Multiply the Vector with a scalar value.
*/
inline FGQuaternion operator*(double scalar, const FGQuaternion& q) {
return FGQuaternion(scalar*q(1), scalar*q(2), scalar*q(3), scalar*q(4));
}
} // namespace JSBSim
#endif

View file

@ -38,6 +38,8 @@ HISTORY
INCLUDES INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include <sstream>
#include "FGRocket.h" #include "FGRocket.h"
namespace JSBSim { namespace JSBSim {
@ -88,7 +90,7 @@ FGRocket::~FGRocket(void)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGRocket::Calculate(double pe) double FGRocket::Calculate(void)
{ {
double Cf=0; double Cf=0;
@ -103,11 +105,34 @@ double FGRocket::Calculate(double pe)
} else { } else {
PctPower = Throttle / MaxThrottle; PctPower = Throttle / MaxThrottle;
PC = maxPC*PctPower * (1.0 + Variance * ((double)rand()/(double)RAND_MAX - 0.5)); PC = maxPC*PctPower * (1.0 + Variance * ((double)rand()/(double)RAND_MAX - 0.5));
Cf = sqrt(kFactor*(1 - pow(pe/(PC), (SHR-1)/SHR))); Cf = sqrt(kFactor*(1 - pow(Thruster->GetPowerRequired()/(PC), (SHR-1)/SHR)));
Flameout = false; Flameout = false;
} }
return Cf*maxPC*PctPower*propEff; return Thruster->Calculate(Cf*maxPC*PctPower*propEff);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGRocket::GetEngineLabels(void)
{
std::ostringstream buf;
buf << Name << "_ChamberPress[" << EngineNumber << "], "
<< Thruster->GetThrusterLabels(EngineNumber);
return buf.str();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGRocket::GetEngineValues(void)
{
std::ostringstream buf;
buf << PC << ", " << Thruster->GetThrusterValues(EngineNumber);
return buf.str();
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View file

@ -110,21 +110,20 @@ public:
~FGRocket(void); ~FGRocket(void);
/** Determines the thrust coefficient. /** Determines the thrust coefficient.
This routine takes the nozzle exit pressure and calculates the thrust
coefficient times the chamber pressure.
@param pe nozzle exit pressure
@return thrust coefficient times chamber pressure */ @return thrust coefficient times chamber pressure */
double Calculate(double pe); double Calculate(void);
/** Gets the chamber pressure. /** Gets the chamber pressure.
@return chamber pressure in psf. */ @return chamber pressure in psf. */
double GetChamberPressure(void) {return PC;} double GetChamberPressure(void) {return PC;}
/** Gets the flame-out status. /** Gets the flame-out status.
The engine will "flame out" if the throttle is set below the minimum The engine will "flame out" if the throttle is set below the minimum
sustainable setting. sustainable setting.
@return true if engine has flamed out. */ @return true if engine has flamed out. */
bool GetFlameout(void) {return Flameout;} bool GetFlameout(void) {return Flameout;}
string GetEngineLabels(void);
string GetEngineValues(void);
private: private:
double SHR; double SHR;

View file

@ -1,267 +0,0 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Module: FGRotation.cpp
Author: Jon Berndt
Date started: 12/02/98
Purpose: Integrates the rotational EOM
Called by: FGFDMExec
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org.
FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------
This class integrates the rotational EOM.
HISTORY
--------------------------------------------------------------------------------
12/02/98 JSB Created
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
COMMENTS, REFERENCES, and NOTES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[1] Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
School, January 1994
[2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
JSC 12960, July 1977
[3] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
NASA-Ames", NASA CR-2497, January 1975
[4] Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
Wiley & Sons, 1979 ISBN 0-471-03032-5
[5] Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
1982 ISBN 0-471-08936-2
The order of rotations used in this class corresponds to a 3-2-1 sequence,
or Y-P-R, or Z-Y-X, if you prefer.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGRotation.h"
#include "FGAtmosphere.h"
#include "FGState.h"
#include "FGFDMExec.h"
#include "FGAircraft.h"
#include "FGMassBalance.h"
#include "FGPropertyManager.h"
namespace JSBSim {
static const char *IdSrc = "$Id$";
static const char *IdHdr = ID_ROTATION;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
FGRotation::FGRotation(FGFDMExec* fdmex) : FGModel(fdmex)
{
Name = "FGRotation";
cTht = cPhi = cPsi = 1.0;
sTht = sPhi = sPsi = 0.0;
vPQRdot.InitMatrix();
vPQRdot_prev[0].InitMatrix();
vPQRdot_prev[1].InitMatrix();
vPQRdot_prev[2].InitMatrix();
vPQRdot_prev[3].InitMatrix();
bind();
Debug(0);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGRotation::~FGRotation()
{
unbind();
Debug(1);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGRotation::Run(void)
{
double tTheta;
if (!FGModel::Run()) {
GetState();
vPQRdot = MassBalance->GetJinv()*(vMoments - vPQR*(MassBalance->GetJ()*vPQR));
vPQR += State->Integrate(FGState::TRAPZ, dt*rate, vPQRdot, vPQRdot_prev);
vAeroPQR = vPQR + Atmosphere->GetTurbPQR();
State->IntegrateQuat(vPQR, rate);
State->CalcMatrices();
vEuler = State->CalcEuler();
cTht = cos(vEuler(eTht)); sTht = sin(vEuler(eTht));
cPhi = cos(vEuler(ePhi)); sPhi = sin(vEuler(ePhi));
cPsi = cos(vEuler(ePsi)); sPsi = sin(vEuler(ePsi));
vEulerRates(eTht) = vPQR(2)*cPhi - vPQR(3)*sPhi;
if (cTht != 0.0) {
tTheta = sTht/cTht; // what's cheaper: / or tan() ?
vEulerRates(ePhi) = vPQR(1) + (vPQR(2)*sPhi + vPQR(3)*cPhi)*tTheta;
vEulerRates(ePsi) = (vPQR(2)*sPhi + vPQR(3)*cPhi)/cTht;
}
if (debug_lvl > 1) Debug(2);
return false;
} else {
return true;
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGRotation::GetState(void)
{
dt = State->Getdt();
vMoments = Aircraft->GetMoments();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGRotation::bind(void)
{
typedef double (FGRotation::*PMF)(int) const;
PropertyManager->Tie("velocities/p-rad_sec", this,1,
(PMF)&FGRotation::GetPQR);
PropertyManager->Tie("velocities/q-rad_sec", this,2,
(PMF)&FGRotation::GetPQR);
PropertyManager->Tie("velocities/r-rad_sec", this,3,
(PMF)&FGRotation::GetPQR);
PropertyManager->Tie("velocities/p-aero-rad_sec", this,1,
(PMF)&FGRotation::GetAeroPQR);
PropertyManager->Tie("velocities/q-aero-rad_sec", this,2,
(PMF)&FGRotation::GetAeroPQR);
PropertyManager->Tie("velocities/r-aero-rad_sec", this,3,
(PMF)&FGRotation::GetAeroPQR);
PropertyManager->Tie("accelerations/pdot-rad_sec", this,1,
(PMF)&FGRotation::GetPQRdot);
PropertyManager->Tie("accelerations/qdot-rad_sec", this,2,
(PMF)&FGRotation::GetPQRdot);
PropertyManager->Tie("accelerations/rdot-rad_sec", this,3,
(PMF)&FGRotation::GetPQRdot);
PropertyManager->Tie("attitude/roll-rad", this,1,
(PMF)&FGRotation::GetEuler);
PropertyManager->Tie("attitude/pitch-rad", this,2,
(PMF)&FGRotation::GetEuler);
PropertyManager->Tie("attitude/heading-true-rad", this,3,
(PMF)&FGRotation::GetEuler);
PropertyManager->Tie("velocities/phidot-rad_sec", this,1,
(PMF)&FGRotation::GetEulerRates);
PropertyManager->Tie("velocities/thetadot-rad_sec", this,2,
(PMF)&FGRotation::GetEulerRates);
PropertyManager->Tie("velocities/psidot-rad_sec", this,3,
(PMF)&FGRotation::GetEulerRates);
PropertyManager->Tie("attitude/phi-rad", this,
&FGRotation::Getphi);
PropertyManager->Tie("attitude/theta-rad", this,
&FGRotation::Gettht);
PropertyManager->Tie("attitude/psi-true-rad", this,
&FGRotation::Getpsi);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGRotation::unbind(void)
{
PropertyManager->Untie("velocities/p-rad_sec");
PropertyManager->Untie("velocities/q-rad_sec");
PropertyManager->Untie("velocities/r-rad_sec");
PropertyManager->Untie("velocities/p-aero-rad_sec");
PropertyManager->Untie("velocities/q-aero-rad_sec");
PropertyManager->Untie("velocities/r-aero-rad_sec");
PropertyManager->Untie("accelerations/pdot-rad_sec");
PropertyManager->Untie("accelerations/qdot-rad_sec");
PropertyManager->Untie("accelerations/rdot-rad_sec");
PropertyManager->Untie("attitude/roll-rad");
PropertyManager->Untie("attitude/pitch-rad");
PropertyManager->Untie("attitude/heading-true-rad");
PropertyManager->Untie("velocities/phidot-rad_sec");
PropertyManager->Untie("velocities/thetadot-rad_sec");
PropertyManager->Untie("velocities/psidot-rad_sec");
PropertyManager->Untie("attitude/phi-rad");
PropertyManager->Untie("attitude/theta-rad");
PropertyManager->Untie("attitude/psi-true-rad");
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
// out the normally expected messages, essentially echoing
// the config files as they are read. If the environment
// variable is not set, debug_lvl is set to 1 internally
// 0: This requests JSBSim not to output any messages
// whatsoever.
// 1: This value explicity requests the normal JSBSim
// startup messages
// 2: This value asks for a message to be printed out when
// a class is instantiated
// 4: When this value is set, a message is displayed when a
// FGModel object executes its Run() method
// 8: When this value is set, various runtime state variables
// are printed out periodically
// 16: When set various parameters are sanity checked and
// a message is printed out when they go out of bounds
void FGRotation::Debug(int from)
{
if (debug_lvl <= 0) return;
if (debug_lvl & 1) { // Standard console startup message output
if (from == 0) { // Constructor
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
if (from == 0) cout << "Instantiated: FGRotation" << endl;
if (from == 1) cout << "Destroyed: FGRotation" << endl;
}
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
}
if (debug_lvl & 8 ) { // Runtime state variables
}
if (debug_lvl & 16) { // Sanity check variables
if (from == 2) {
if (fabs(vPQR(eP)) > 100)
cout << "FGRotation::P (Roll Rate) out of bounds: " << vPQR(eP) << endl;
if (fabs(vPQR(eQ)) > 100)
cout << "FGRotation::Q (Pitch Rate) out of bounds: " << vPQR(eQ) << endl;
if (fabs(vPQR(eR)) > 100)
cout << "FGRotation::R (Yaw Rate) out of bounds: " << vPQR(eR) << endl;
}
}
if (debug_lvl & 64) {
if (from == 0) { // Constructor
cout << IdSrc << endl;
cout << IdHdr << endl;
}
}
}
}

View file

@ -1,156 +0,0 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Header: FGRotation.h
Author: Jon Berndt
Date started: 12/02/98
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org.
HISTORY
--------------------------------------------------------------------------------
12/02/98 JSB Created
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifndef FGROTATION_H
#define FGROTATION_H
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifdef FGFS
# include <simgear/compiler.h>
# include <math.h>
#else
# if defined (sgi) && !defined(__GNUC__)
# include <math.h>
# else
# include <cmath>
# endif
#endif
#include "FGModel.h"
#include "FGColumnVector3.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_ROTATION "$Id$"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
namespace JSBSim {
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Models the rotational portion of the Equations of Motion.
Note: The order of rotations used in this class corresponds to a 3-2-1 sequence,
or Y-P-R, or Z-Y-X, if you prefer.
@see Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
School, January 1994
@see D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
JSC 12960, July 1977
@see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
NASA-Ames", NASA CR-2497, January 1975
@see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
Wiley & Sons, 1979 ISBN 0-471-03032-5
@see Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
1982 ISBN 0-471-08936-2
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGRotation : public FGModel
{
public:
FGRotation(FGFDMExec*);
~FGRotation();
bool Run(void);
inline FGColumnVector3& GetPQR(void) {return vPQR;}
inline double GetPQR(int axis) const {return vPQR(axis);}
inline FGColumnVector3& GetAeroPQR(void) {return vAeroPQR;}
inline double GetAeroPQR(int axis) const {return vAeroPQR(axis);}
inline FGColumnVector3& GetPQRdot(void) {return vPQRdot;}
inline double GetPQRdot(int idx) const {return vPQRdot(idx);}
inline FGColumnVector3& GetEuler(void) {return vEuler;}
inline double GetEuler(int axis) const {return vEuler(axis);}
inline FGColumnVector3& GetEulerRates(void) { return vEulerRates; }
inline double GetEulerRates(int axis) const { return vEulerRates(axis); }
inline void SetPQR(FGColumnVector3 tt) {vPQR = tt;}
inline void SetPQR(double p, double q, double r) {vPQR(eP)=p;
vPQR(eQ)=q;
vPQR(eR)=r;}
inline void SetAeroPQR(FGColumnVector3 tt) {vAeroPQR = tt;}
inline void SetAeroPQR(double p, double q, double r) {vAeroPQR(eP)=p;
vAeroPQR(eQ)=q;
vAeroPQR(eR)=r;}
inline void SetEuler(FGColumnVector3 tt) {vEuler = tt;}
inline double Getphi(void) const {return vEuler(1);}
inline double Gettht(void) const {return vEuler(2);}
inline double Getpsi(void) const {return vEuler(3);}
inline double GetCosphi(void) const {return cPhi;}
inline double GetCostht(void) const {return cTht;}
inline double GetCospsi(void) const {return cPsi;}
inline double GetSinphi(void) const {return sPhi;}
inline double GetSintht(void) const {return sTht;}
inline double GetSinpsi(void) const {return sPsi;}
void bind(void);
void unbind(void);
private:
FGColumnVector3 vPQR;
FGColumnVector3 vAeroPQR;
FGColumnVector3 vPQRdot;
FGColumnVector3 vPQRdot_prev[4];
FGColumnVector3 vMoments;
FGColumnVector3 vEuler;
FGColumnVector3 vEulerRates;
double cTht,sTht;
double cPhi,sPhi;
double cPsi,sPsi;
double dt;
void GetState(void);
void Debug(int from);
};
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif

View file

@ -66,6 +66,20 @@ double FGRotor::Calculate(double PowerAvailable)
return 0.0; return 0.0;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGRotor::GetThrusterLabels(int id)
{
return "";
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGRotor::GetThrusterValues(int id)
{
return "";
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows: // The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print // unset: In this case (the default) JSBSim would only print

View file

@ -70,6 +70,8 @@ public:
~FGRotor(); ~FGRotor();
double Calculate(double); double Calculate(double);
string GetThrusterLabels(int id);
string GetThrusterValues(int id);
private: private:
void Debug(int from); void Debug(int from);

View file

@ -1,447 +0,0 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Module: FGSimTurbine.cpp
Author: David Culp
Date started: 03/11/2003
Purpose: This module models a turbine engine.
------------- Copyright (C) 2003 David Culp (davidculp2@comcast.net) ---------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org.
FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------
This class descends from the FGEngine class and models a Turbine engine based
on parameters given in the engine config file for this class
HISTORY
--------------------------------------------------------------------------------
03/11/2003 DPC Created
09/08/2003 DPC Changed Calculate() and added engine phases
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include <vector>
#include "FGSimTurbine.h"
namespace JSBSim {
static const char *IdSrc = "$Id$";
static const char *IdHdr = ID_SIMTURBINE;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
FGSimTurbine::FGSimTurbine(FGFDMExec* exec, FGConfigFile* cfg) : FGEngine(exec)
{
SetDefaults();
Load(cfg);
Debug(0);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGSimTurbine::~FGSimTurbine()
{
Debug(1);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The main purpose of Calculate() is to determine what phase the engine should
// be in, then call the corresponding function.
double FGSimTurbine::Calculate(double dummy)
{
TAT = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556;
dt = State->Getdt() * Propulsion->GetRate();
ThrottleCmd = FCS->GetThrottleCmd(EngineNumber);
// When trimming is finished check if user wants engine OFF or RUNNING
if ((phase == tpTrim) && (dt > 0)) {
if (Running && !Starved) {
phase = tpRun;
N2 = IdleN2;
N1 = IdleN1;
OilTemp_degK = 366.0;
Cutoff = false;
}
else {
phase = tpOff;
Cutoff = true;
EGT_degC = TAT;
}
}
if (!Running && Cutoff && Starter) {
if (phase == tpOff) phase = tpSpinUp;
}
if (!Running && !Cutoff && (N2 > 15.0)) phase = tpStart;
if (Cutoff && (phase != tpSpinUp)) phase = tpOff;
if (dt == 0) phase = tpTrim;
if (Starved) phase = tpOff;
if (Stalled) phase = tpStall;
if (Seized) phase = tpSeize;
switch (phase) {
case tpOff: Thrust = Off(); break;
case tpRun: Thrust = Run(); break;
case tpSpinUp: Thrust = SpinUp(); break;
case tpStart: Thrust = Start(); break;
case tpStall: Thrust = Stall(); break;
case tpSeize: Thrust = Seize(); break;
case tpTrim: Thrust = Trim(); break;
default: Thrust = Off();
}
return Thrust;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGSimTurbine::Off(void)
{
double qbar = Translation->Getqbar();
Running = false;
FuelFlow_pph = Seek(&FuelFlow_pph, 0, 1000.0, 10000.0);
N1 = Seek(&N1, qbar/10.0, N1/2.0, N1/2.0);
N2 = Seek(&N2, qbar/15.0, N2/2.0, N2/2.0);
EGT_degC = Seek(&EGT_degC, TAT, 11.7, 7.3);
OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0.2, 0.2);
OilPressure_psi = N2 * 0.62;
NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
EPR = Seek(&EPR, 1.0, 0.2, 0.2);
Augmentation = false;
return 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGSimTurbine::Run(void)
{
double idlethrust, milthrust, thrust;
double N2norm; // 0.0 = idle N2, 1.0 = maximum N2
idlethrust = MilThrust * ThrustTables[0]->TotalValue();
milthrust = (MilThrust - idlethrust) * ThrustTables[1]->TotalValue();
Running = true;
Starter = false;
N2 = Seek(&N2, IdleN2 + ThrottleCmd * N2_factor, delay, delay * 3.0);
N1 = Seek(&N1, IdleN1 + ThrottleCmd * N1_factor, delay, delay * 2.4);
N2norm = (N2 - IdleN2) / N2_factor;
thrust = idlethrust + (milthrust * N2norm * N2norm);
thrust = thrust * (1.0 - BleedDemand);
EGT_degC = TAT + 363.1 + ThrottleCmd * 357.1;
OilPressure_psi = N2 * 0.62;
OilTemp_degK = Seek(&OilTemp_degK, 366.0, 1.2, 0.1);
EPR = 1.0 + thrust/MilThrust;
if (!Augmentation) {
FuelFlow_pph = Seek(&FuelFlow_pph, thrust * TSFC, 1000.0, 100000);
if (FuelFlow_pph < IdleFF) FuelFlow_pph = IdleFF;
NozzlePosition = Seek(&NozzlePosition, 1.0 - N2norm, 0.8, 0.8);
}
if (AugMethod == 1) {
if ((ThrottleCmd > 0.99) && (N2 > 97.0)) {Augmentation = true;}
else {Augmentation = false;}
}
if ((Augmented == 1) && Augmentation) {
thrust = MaxThrust * ThrustTables[2]->TotalValue();
FuelFlow_pph = Seek(&FuelFlow_pph, thrust * ATSFC, 5000.0, 10000.0);
NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
}
if ((Injected == 1) && Injection)
thrust = thrust * ThrustTables[3]->TotalValue();
ConsumeFuel();
if (Cutoff) phase = tpOff;
if (Starved) phase = tpOff;
return thrust;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGSimTurbine::SpinUp(void)
{
Running = false;
FuelFlow_pph = 0.0;
N2 = Seek(&N2, 25.18, 3.0, N2/2.0);
N1 = Seek(&N1, 5.21, 1.0, N1/2.0);
EGT_degC = Seek(&EGT_degC, TAT, 11.7, 7.3);
OilPressure_psi = N2 * 0.62;
OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0.2, 0.2);
EPR = 1.0;
NozzlePosition = 1.0;
return 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGSimTurbine::Start(void)
{
if ((N2 > 15.0) && !Starved) { // minimum 15% N2 needed for start
Cranking = true; // provided for sound effects signal
if (N2 < IdleN2) {
N2 = Seek(&N2, IdleN2, 2.0, N2/2.0);
N1 = Seek(&N1, IdleN1, 1.4, N1/2.0);
EGT_degC = Seek(&EGT_degC, TAT + 363.1, 21.3, 7.3);
FuelFlow_pph = Seek(&FuelFlow_pph, IdleFF, 103.7, 103.7);
OilPressure_psi = N2 * 0.62;
}
else {
phase = tpRun;
Running = true;
Starter = false;
Cranking = false;
}
}
else { // no start if N2 < 15%
phase = tpOff;
Starter = false;
}
return 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGSimTurbine::Stall(void)
{
double qbar = Translation->Getqbar();
EGT_degC = TAT + 903.14;
FuelFlow_pph = IdleFF;
N1 = Seek(&N1, qbar/10.0, 0, N1/10.0);
N2 = Seek(&N2, qbar/15.0, 0, N2/10.0);
if (ThrottleCmd == 0) phase = tpRun; // clear the stall with throttle
return 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGSimTurbine::Seize(void)
{
double qbar = Translation->Getqbar();
N2 = 0.0;
N1 = Seek(&N1, qbar/20.0, 0, N1/15.0);
FuelFlow_pph = IdleFF;
OilPressure_psi = 0.0;
OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0, 0.2);
Running = false;
return 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGSimTurbine::Trim(void)
{
double idlethrust, milthrust, thrust;
idlethrust = MilThrust * ThrustTables[0]->TotalValue();
milthrust = (MilThrust - idlethrust) * ThrustTables[1]->TotalValue();
thrust = idlethrust + (milthrust * ThrottleCmd * ThrottleCmd);
return thrust;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGSimTurbine::CalcFuelNeed(void)
{
return FuelFlow_pph /3600 * State->Getdt() * Propulsion->GetRate();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGSimTurbine::GetPowerAvailable(void) {
if( ThrottleCmd <= 0.77 )
return 64.94*ThrottleCmd;
else
return 217.38*ThrottleCmd - 117.38;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGSimTurbine::Seek(double *var, double target, double accel, double decel) {
double v = *var;
if (v > target) {
v -= dt * decel;
if (v < target) v = target;
} else if (v < target) {
v += dt * accel;
if (v > target) v = target;
}
return v;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGSimTurbine::SetDefaults(void)
{
Name = "Not defined";
N1 = N2 = 0.0;
Type = etSimTurbine;
MilThrust = 10000.0;
MaxThrust = 10000.0;
BypassRatio = 0.0;
TSFC = 0.8;
ATSFC = 1.7;
IdleN1 = 30.0;
IdleN2 = 60.0;
MaxN1 = 100.0;
MaxN2 = 100.0;
Augmented = 0;
AugMethod = 0;
Injected = 0;
BleedDemand = 0.0;
ThrottleCmd = 0.0;
InletPosition = 1.0;
NozzlePosition = 1.0;
Augmentation = false;
Injection = false;
Reversed = false;
Cutoff = true;
phase = tpOff;
Stalled = false;
Seized = false;
Overtemp = false;
Fire = false;
EGT_degC = 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGSimTurbine::Load(FGConfigFile *Eng_cfg)
{
string token;
Name = Eng_cfg->GetValue("NAME");
Eng_cfg->GetNextConfigLine();
int counter=0;
while (Eng_cfg->GetValue() != string("/FG_SIMTURBINE")) {
*Eng_cfg >> token;
if (token[0] == '<') token.erase(0,1); // Tables are read "<TABLE"
if (token == "MILTHRUST") *Eng_cfg >> MilThrust;
else if (token == "MAXTHRUST") *Eng_cfg >> MaxThrust;
else if (token == "BYPASSRATIO") *Eng_cfg >> BypassRatio;
else if (token == "TSFC") *Eng_cfg >> TSFC;
else if (token == "ATSFC") *Eng_cfg >> ATSFC;
else if (token == "IDLEN1") *Eng_cfg >> IdleN1;
else if (token == "IDLEN2") *Eng_cfg >> IdleN2;
else if (token == "MAXN1") *Eng_cfg >> MaxN1;
else if (token == "MAXN2") *Eng_cfg >> MaxN2;
else if (token == "AUGMENTED") *Eng_cfg >> Augmented;
else if (token == "AUGMETHOD") *Eng_cfg >> AugMethod;
else if (token == "INJECTED") *Eng_cfg >> Injected;
else if (token == "MINTHROTTLE") *Eng_cfg >> MinThrottle;
else if (token == "TABLE") {
if (counter++ == 0) Debug(2); // print engine specs prior to table read
ThrustTables.push_back( new FGCoefficient(FDMExec) );
ThrustTables.back()->Load(Eng_cfg);
}
else cerr << "Unhandled token in Engine config file: " << token << endl;
}
// Pre-calculations and initializations
delay = 60.0 / (BypassRatio + 3.0);
N1_factor = MaxN1 - IdleN1;
N2_factor = MaxN2 - IdleN2;
OilTemp_degK = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556 + 273.0;
IdleFF = pow(MilThrust, 0.2) * 107.0; // just an estimate
return true;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
// out the normally expected messages, essentially echoing
// the config files as they are read. If the environment
// variable is not set, debug_lvl is set to 1 internally
// 0: This requests JSBSim not to output any messages
// whatsoever.
// 1: This value explicity requests the normal JSBSim
// startup messages
// 2: This value asks for a message to be printed out when
// a class is instantiated
// 4: When this value is set, a message is displayed when a
// FGModel object executes its Run() method
// 8: When this value is set, various runtime state variables
// are printed out periodically
// 16: When set various parameters are sanity checked and
// a message is printed out when they go out of bounds
void FGSimTurbine::Debug(int from)
{
if (debug_lvl <= 0) return;
if (debug_lvl & 1) { // Standard console startup message output
if (from == 0) { // Constructor
}
if (from == 2) { // called from Load()
cout << "\n Engine Name: " << Name << endl;
cout << " MilThrust: " << MilThrust << endl;
cout << " MaxThrust: " << MaxThrust << endl;
cout << " BypassRatio: " << BypassRatio << endl;
cout << " TSFC: " << TSFC << endl;
cout << " ATSFC: " << ATSFC << endl;
cout << " IdleN1: " << IdleN1 << endl;
cout << " IdleN2: " << IdleN2 << endl;
cout << " MaxN1: " << MaxN1 << endl;
cout << " MaxN2: " << MaxN2 << endl;
cout << " Augmented: " << Augmented << endl;
cout << " AugMethod: " << AugMethod << endl;
cout << " Injected: " << Injected << endl;
cout << " MinThrottle: " << MinThrottle << endl;
cout << endl;
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
if (from == 0) cout << "Instantiated: FGSimTurbine" << endl;
if (from == 1) cout << "Destroyed: FGSimTurbine" << endl;
}
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
}
if (debug_lvl & 8 ) { // Runtime state variables
}
if (debug_lvl & 16) { // Sanity checking
}
if (debug_lvl & 64) {
if (from == 0) { // Constructor
cout << IdSrc << endl;
cout << IdHdr << endl;
}
}
}
}

View file

@ -1,243 +0,0 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Header: FGSimTurbine.h
Author: David Culp
Date started: 03/11/2003
------------- Copyright (C) 2003 David Culp (davidculp2@comcast.net)----------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org.
HISTORY
--------------------------------------------------------------------------------
03/11/2003 DPC Created, based on FGTurbine
09/22/2003 DPC Added starting, stopping, new framework
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifndef FGSIMTURBINE_H
#define FGSIMTURBINE_H
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include <vector>
#include "FGEngine.h"
#include "FGConfigFile.h"
#include "FGCoefficient.h"
#define ID_SIMTURBINE "$Id$"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
namespace JSBSim {
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** This class models a turbine engine. Based on Jon Berndt's FGTurbine module.
Here the term "phase" signifies the engine's mode of operation. At any given
time the engine is in only one phase. At simulator startup the engine will be
placed in the Trim phase in order to provide a simplified thrust value without
throttle lag. When trimming is complete the engine will go to the Off phase,
unless the value FGEngine::Running has been previously set to true, in which
case the engine will go to the Run phase. Once an engine is in the Off phase
the full starting procedure (or airstart) must be used to get it running.
<P>
- STARTING (on ground):
-# Set the control FGEngine::Starter to true. The engine will spin up to
a maximum of about %25 N2 (%5.2 N1). This simulates the action of a
pneumatic starter.
-# After reaching %15 N2 set the control FGEngine::Cutoff to false. If fuel
is available the engine will now accelerate to idle. The starter will
automatically be set to false after the start cycle.
<P>
- STARTING (in air):
-# Increase speed to obtain a minimum of %15 N2. If this is not possible,
the starter may be used to assist.
-# Place the control FGEngine::Cutoff to false.
<P>
Ignition is assumed to be on anytime the Cutoff control is set to false,
therefore a seperate ignition system is not modeled.
Configuration File Format
<pre>
\<FG_SIMTURBINE NAME="<name>">
MILTHRUST \<thrust>
MAXTHRUST \<thrust>
BYPASSRATIO \<bypass ratio>
TSFC \<thrust specific fuel consumption>
ATSFC \<afterburning thrust specific fuel consumption>
IDLEN1 \<idle N1>
IDLEN2 \<idle N2>
MAXN1 \<max N1>
MAXN2 \<max N2>
AUGMENTED \<0|1>
AUGMETHOD \<0|1>
INJECTED \<0|1>
...
\</FG_SIMTURBINE>
</pre>
Definition of the turbine engine configuration file parameters:
<pre>
<b>MILTHRUST</b> - Maximum thrust, static, at sea level, lbf.
<b>MAXTHRUST</b> - Afterburning thrust, static, at sea level, lbf
[this value will be ignored when AUGMENTED is zero (false)].
<b>BYPASSRATIO</b> - Ratio of bypass air flow to core air flow.
<b>TSFC</b> - Thrust-specific fuel consumption, lbm/hr/lbf
[i.e. fuel flow divided by thrust].
<b>ATSFC</b> - Afterburning TSFC, lbm/hr/lbf
[this value will be ignored when AUGMENTED is zero (false)]
<b>IDLEN1</b> - Fan rotor rpm (% of max) at idle
<b>IDLEN2</b> - Core rotor rpm (% of max) at idle
<b>MAXN1</b> - Fan rotor rpm (% of max) at full throttle [not always 100!]
<b>MAXN2</b> - Core rotor rpm (% of max) at full throttle [not always 100!]
<b>AUGMENTED</b>
0 == afterburner not installed
1 == afterburner installed
<b>AUGMETHOD</b>
0 == afterburner activated by property /engines/engine[n]/augmentation
1 == afterburner activated by pushing throttle above 99% position
[this item will be ignored when AUGMENTED == 0]
<b>INJECTED</b>
0 == Water injection not installed
1 == Water injection installed
</pre>
@author David P. Culp
@version "$Id$"
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGSimTurbine : public FGEngine
{
public:
/** Constructor
@param Executive pointer to executive structure
@param Eng_cfg pointer to engine config file instance */
FGSimTurbine(FGFDMExec* Executive, FGConfigFile* Eng_cfg);
/// Destructor
~FGSimTurbine();
enum phaseType { tpOff, tpRun, tpSpinUp, tpStart, tpStall, tpSeize, tpTrim };
double Calculate(double PowerRequired);
double CalcFuelNeed(void);
double GetPowerAvailable(void);
double Seek(double* var, double target, double accel, double decel);
phaseType GetPhase(void) { return phase; }
bool GetOvertemp(void) {return Overtemp; }
bool GetInjection(void) {return Injection;}
bool GetFire(void) { return Fire; }
bool GetAugmentation(void) {return Augmentation;}
bool GetReversed(void) { return Reversed; }
bool GetCutoff(void) { return Cutoff; }
int GetIgnition(void) {return Ignition;}
double GetInlet(void) { return InletPosition; }
double GetNozzle(void) { return NozzlePosition; }
double GetBleedDemand(void) {return BleedDemand;}
double GetN1(void) {return N1;}
double GetN2(void) {return N2;}
double GetEPR(void) {return EPR;}
double GetEGT(void) {return EGT_degC;}
double getOilPressure_psi () const {return OilPressure_psi;}
double getOilTemp_degF (void) {return KelvinToFahrenheit(OilTemp_degK);}
void SetInjection(bool injection) {Injection = injection;}
void SetIgnition(int ignition) {Ignition = ignition;}
void SetAugmentation(bool augmentation) {Augmentation = augmentation;}
void SetPhase( phaseType p ) { phase = p; }
void SetEPR(double epr) {EPR = epr;}
void SetBleedDemand(double bleedDemand) {BleedDemand = bleedDemand;}
void SetReverse(bool reversed) { Reversed = reversed; }
void SetCutoff(bool cutoff) { Cutoff = cutoff; }
private:
typedef vector<FGCoefficient*> CoeffArray;
CoeffArray ThrustTables;
phaseType phase; ///< Operating mode, or "phase"
double MilThrust; ///< Maximum Unaugmented Thrust, static @ S.L. (lbf)
double MaxThrust; ///< Maximum Augmented Thrust, static @ S.L. (lbf)
double BypassRatio; ///< Bypass Ratio
double TSFC; ///< Thrust Specific Fuel Consumption (lbm/hr/lbf)
double ATSFC; ///< Augmented TSFC (lbm/hr/lbf)
double IdleN1; ///< Idle N1
double IdleN2; ///< Idle N2
double N1; ///< N1
double N2; ///< N2
double MaxN1; ///< N1 at 100% throttle
double MaxN2; ///< N2 at 100% throttle
double IdleFF; ///< Idle Fuel Flow (lbm/hr)
double delay; ///< Inverse spool-up time from idle to 100% (seconds)
double dt; ///< Simulator time slice
double N1_factor; ///< factor to tie N1 and throttle
double N2_factor; ///< factor to tie N2 and throttle
double ThrottleCmd; ///< FCS-supplied throttle position
double TAT; ///< total air temperature (deg C)
bool Stalled; ///< true if engine is compressor-stalled
bool Seized; ///< true if inner spool is seized
bool Overtemp; ///< true if EGT exceeds limits
bool Fire; ///< true if engine fire detected
bool Injection;
bool Augmentation;
bool Reversed;
bool Cutoff;
int Injected; ///< = 1 if water injection installed
int Ignition;
int Augmented; ///< = 1 if augmentation installed
int AugMethod; ///< = 0 if using property /engine[n]/augmentation
///< = 1 if using last 1% of throttle movement
double EGT_degC;
double EPR;
double OilPressure_psi;
double OilTemp_degK;
double BleedDemand;
double InletPosition;
double NozzlePosition;
double Off(void);
double Run(void);
double SpinUp(void);
double Start(void);
double Stall(void);
double Seize(void);
double Trim(void);
void SetDefaults(void);
bool Load(FGConfigFile *ENG_cfg);
void Debug(int from);
};
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif

View file

@ -47,8 +47,8 @@ INCLUDES
# endif # endif
#endif #endif
#ifdef _MSC_VER #ifdef _WIN32
#define snprintf _snprintf //#define snprintf _snprintf
#endif #endif
#include "FGState.h" #include "FGState.h"
@ -74,9 +74,8 @@ FGState::FGState(FGFDMExec* fdex)
dt = 1.0/120.0; dt = 1.0/120.0;
Aircraft = FDMExec->GetAircraft(); Aircraft = FDMExec->GetAircraft();
Translation = FDMExec->GetTranslation(); Propagate = FDMExec->GetPropagate();
Rotation = FDMExec->GetRotation(); Auxiliary = FDMExec->GetAuxiliary();
Position = FDMExec->GetPosition();
FCS = FDMExec->GetFCS(); FCS = FDMExec->GetFCS();
Output = FDMExec->GetOutput(); Output = FDMExec->GetOutput();
Atmosphere = FDMExec->GetAtmosphere(); Atmosphere = FDMExec->GetAtmosphere();
@ -85,8 +84,6 @@ FGState::FGState(FGFDMExec* fdex)
Propulsion = FDMExec->GetPropulsion(); Propulsion = FDMExec->GetPropulsion();
PropertyManager = FDMExec->GetPropertyManager(); PropertyManager = FDMExec->GetPropertyManager();
for(int i=0;i<4;i++) vQdot_prev[i].InitMatrix();
bind(); bind();
Debug(0); Debug(0);
@ -100,39 +97,23 @@ FGState::~FGState()
Debug(1); Debug(1);
} }
//*************************************************************************** //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
//
// Initialize: Assume all angles GIVEN IN RADIANS !!
//
void FGState::Initialize(double U, double V, double W, void FGState::Initialize(FGInitialCondition *FGIC)
double phi, double tht, double psi,
double Latitude, double Longitude, double H,
double wnorth, double weast, double wdown)
{ {
double alpha, beta; sim_time = 0.0;
double qbar, Vt;
FGColumnVector3 vAeroUVW;
FGColumnVector3 vUVW;
Position->SetLatitude(Latitude); Propagate->SetInitialState( FGIC );
Position->SetLongitude(Longitude);
Position->Seth(H);
Atmosphere->Run(); Atmosphere->Run();
Atmosphere->SetWindNED( FGIC->GetWindNFpsIC(),
FGIC->GetWindEFpsIC(),
FGIC->GetWindDFpsIC() );
vLocalEuler << phi << tht << psi; FGColumnVector3 vAeroUVW;
Rotation->SetEuler(vLocalEuler); vAeroUVW = Propagate->GetUVW() + Propagate->GetTl2b()*Atmosphere->GetWindNED();
InitMatrices(phi, tht, psi);
vUVW << U << V << W;
Translation->SetUVW(vUVW);
Atmosphere->SetWindNED(wnorth, weast, wdown);
vAeroUVW = vUVW + mTl2b*Atmosphere->GetWindNED();
double alpha, beta;
if (vAeroUVW(eW) != 0.0) if (vAeroUVW(eW) != 0.0)
alpha = vAeroUVW(eU)*vAeroUVW(eU) > 0.0 ? atan2(vAeroUVW(eW), vAeroUVW(eU)) : 0.0; alpha = vAeroUVW(eU)*vAeroUVW(eU) > 0.0 ? atan2(vAeroUVW(eW), vAeroUVW(eU)) : 0.0;
else else
@ -142,148 +123,15 @@ void FGState::Initialize(double U, double V, double W,
else else
beta = 0.0; beta = 0.0;
Translation->SetAB(alpha, beta); Auxiliary->SetAB(alpha, beta);
Vt = sqrt(U*U + V*V + W*W); double Vt = vAeroUVW.Magnitude();
Translation->SetVt(Vt); Auxiliary->SetVt(Vt);
Translation->SetMach(Vt/Atmosphere->GetSoundSpeed()); Auxiliary->SetMach(Vt/Atmosphere->GetSoundSpeed());
qbar = 0.5*(U*U + V*V + W*W)*Atmosphere->GetDensity(); double qbar = 0.5*Vt*Vt*Atmosphere->GetDensity();
Translation->Setqbar(qbar); Auxiliary->Setqbar(qbar);
vLocalVelNED = mTb2l*vUVW;
Position->SetvVel(vLocalVelNED);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGState::Initialize(FGInitialCondition *FGIC)
{
double tht,psi,phi;
double U, V, W, h;
double latitude, longitude;
double wnorth,weast, wdown;
latitude = FGIC->GetLatitudeRadIC();
longitude = FGIC->GetLongitudeRadIC();
h = FGIC->GetAltitudeFtIC();
U = FGIC->GetUBodyFpsIC();
V = FGIC->GetVBodyFpsIC();
W = FGIC->GetWBodyFpsIC();
tht = FGIC->GetThetaRadIC();
phi = FGIC->GetPhiRadIC();
psi = FGIC->GetPsiRadIC();
wnorth = FGIC->GetWindNFpsIC();
weast = FGIC->GetWindEFpsIC();
wdown = FGIC->GetWindDFpsIC();
Position->SetSeaLevelRadius( FGIC->GetSeaLevelRadiusFtIC() );
Position->SetRunwayRadius( FGIC->GetSeaLevelRadiusFtIC() +
FGIC->GetTerrainAltitudeFtIC() );
// need to fix the wind speed args, here.
Initialize(U, V, W, phi, tht, psi, latitude, longitude, h, wnorth, weast, wdown);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGState::InitMatrices(double phi, double tht, double psi)
{
double thtd2, psid2, phid2;
double Sthtd2, Spsid2, Sphid2;
double Cthtd2, Cpsid2, Cphid2;
double Cphid2Cthtd2;
double Cphid2Sthtd2;
double Sphid2Sthtd2;
double Sphid2Cthtd2;
thtd2 = tht/2.0;
psid2 = psi/2.0;
phid2 = phi/2.0;
Sthtd2 = sin(thtd2);
Spsid2 = sin(psid2);
Sphid2 = sin(phid2);
Cthtd2 = cos(thtd2);
Cpsid2 = cos(psid2);
Cphid2 = cos(phid2);
Cphid2Cthtd2 = Cphid2*Cthtd2;
Cphid2Sthtd2 = Cphid2*Sthtd2;
Sphid2Sthtd2 = Sphid2*Sthtd2;
Sphid2Cthtd2 = Sphid2*Cthtd2;
vQtrn(1) = Cphid2Cthtd2*Cpsid2 + Sphid2Sthtd2*Spsid2;
vQtrn(2) = Sphid2Cthtd2*Cpsid2 - Cphid2Sthtd2*Spsid2;
vQtrn(3) = Cphid2Sthtd2*Cpsid2 + Sphid2Cthtd2*Spsid2;
vQtrn(4) = Cphid2Cthtd2*Spsid2 - Sphid2Sthtd2*Cpsid2;
CalcMatrices();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGState::CalcMatrices(void)
{
double Q0Q0, Q1Q1, Q2Q2, Q3Q3;
double Q0Q1, Q0Q2, Q0Q3, Q1Q2;
double Q1Q3, Q2Q3;
Q0Q0 = vQtrn(1)*vQtrn(1);
Q1Q1 = vQtrn(2)*vQtrn(2);
Q2Q2 = vQtrn(3)*vQtrn(3);
Q3Q3 = vQtrn(4)*vQtrn(4);
Q0Q1 = vQtrn(1)*vQtrn(2);
Q0Q2 = vQtrn(1)*vQtrn(3);
Q0Q3 = vQtrn(1)*vQtrn(4);
Q1Q2 = vQtrn(2)*vQtrn(3);
Q1Q3 = vQtrn(2)*vQtrn(4);
Q2Q3 = vQtrn(3)*vQtrn(4);
mTl2b(1,1) = Q0Q0 + Q1Q1 - Q2Q2 - Q3Q3;
mTl2b(1,2) = 2*(Q1Q2 + Q0Q3);
mTl2b(1,3) = 2*(Q1Q3 - Q0Q2);
mTl2b(2,1) = 2*(Q1Q2 - Q0Q3);
mTl2b(2,2) = Q0Q0 - Q1Q1 + Q2Q2 - Q3Q3;
mTl2b(2,3) = 2*(Q2Q3 + Q0Q1);
mTl2b(3,1) = 2*(Q1Q3 + Q0Q2);
mTl2b(3,2) = 2*(Q2Q3 - Q0Q1);
mTl2b(3,3) = Q0Q0 - Q1Q1 - Q2Q2 + Q3Q3;
mTb2l = mTl2b;
mTb2l.T();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGState::IntegrateQuat(FGColumnVector3 vPQR, int rate)
{
vQdot(1) = -0.5*(vQtrn(2)*vPQR(eP) + vQtrn(3)*vPQR(eQ) + vQtrn(4)*vPQR(eR));
vQdot(2) = 0.5*(vQtrn(1)*vPQR(eP) + vQtrn(3)*vPQR(eR) - vQtrn(4)*vPQR(eQ));
vQdot(3) = 0.5*(vQtrn(1)*vPQR(eQ) + vQtrn(4)*vPQR(eP) - vQtrn(2)*vPQR(eR));
vQdot(4) = 0.5*(vQtrn(1)*vPQR(eR) + vQtrn(2)*vPQR(eQ) - vQtrn(3)*vPQR(eP));
vQtrn += Integrate(TRAPZ, dt*rate, vQdot, vQdot_prev);
vQtrn.Normalize();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGColumnVector3& FGState::CalcEuler(void)
{
if (mTl2b(3,3) == 0.0) mTl2b(3,3) = 0.0000001;
if (mTl2b(1,1) == 0.0) mTl2b(1,1) = 0.0000001;
vEuler(ePhi) = atan2(mTl2b(2,3), mTl2b(3,3));
vEuler(eTht) = asin(-mTl2b(1,3));
vEuler(ePsi) = atan2(mTl2b(1,2), mTl2b(1,1));
if (vEuler(ePsi) < 0.0) vEuler(ePsi) += 2*M_PI;
return vEuler;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -292,8 +140,8 @@ FGMatrix33& FGState::GetTs2b(void)
{ {
double ca, cb, sa, sb; double ca, cb, sa, sb;
double alpha = Translation->Getalpha(); double alpha = Auxiliary->Getalpha();
double beta = Translation->Getbeta(); double beta = Auxiliary->Getbeta();
ca = cos(alpha); ca = cos(alpha);
sa = sin(alpha); sa = sin(alpha);
@ -320,8 +168,8 @@ FGMatrix33& FGState::GetTb2s(void)
float alpha,beta; float alpha,beta;
float ca, cb, sa, sb; float ca, cb, sa, sb;
alpha = Translation->Getalpha(); alpha = Auxiliary->Getalpha();
beta = Translation->Getbeta(); beta = Auxiliary->Getbeta();
ca = cos(alpha); ca = cos(alpha);
sa = sin(alpha); sa = sin(alpha);
@ -345,6 +193,7 @@ FGMatrix33& FGState::GetTb2s(void)
void FGState::ReportState(void) void FGState::ReportState(void)
{ {
#if 0
#if !defined(__BORLANDCPP__) #if !defined(__BORLANDCPP__)
char out[80], flap[10], gear[12]; char out[80], flap[10], gear[12];
@ -370,33 +219,33 @@ void FGState::ReportState(void)
snprintf(out,80, " Flaps: %3s Gear: %12s\n",flap,gear); snprintf(out,80, " Flaps: %3s Gear: %12s\n",flap,gear);
cout << out; cout << out;
snprintf(out,80, " Speed: %4.0f KCAS Mach: %5.2f\n", snprintf(out,80, " Speed: %4.0f KCAS Mach: %5.2f\n",
FDMExec->GetAuxiliary()->GetVcalibratedKTS(), Auxiliary->GetVcalibratedKTS(),
Translation->GetMach() ); Auxiliary->GetMach() );
cout << out; cout << out;
snprintf(out,80, " Altitude: %7.0f ft. AGL Altitude: %7.0f ft.\n", snprintf(out,80, " Altitude: %7.0f ft. AGL Altitude: %7.0f ft.\n",
Position->Geth(), Propagate->Geth(),
Position->GetDistanceAGL() ); Propagate->GetDistanceAGL() );
cout << out; cout << out;
snprintf(out,80, " Angle of Attack: %6.2f deg Pitch Angle: %6.2f deg\n", snprintf(out,80, " Angle of Attack: %6.2f deg Pitch Angle: %6.2f deg\n",
Translation->Getalpha()*radtodeg, Auxiliary->Getalpha()*radtodeg,
Rotation->Gettht()*radtodeg ); Propagate->Gettht()*radtodeg );
cout << out; cout << out;
snprintf(out,80, " Flight Path Angle: %6.2f deg Climb Rate: %5.0f ft/min\n", snprintf(out,80, " Flight Path Angle: %6.2f deg Climb Rate: %5.0f ft/min\n",
Position->GetGamma()*radtodeg, Auxiliary->GetGamma()*radtodeg,
Position->Gethdot()*60 ); Propagate->Gethdot()*60 );
cout << out; cout << out;
snprintf(out,80, " Normal Load Factor: %4.2f g's Pitch Rate: %5.2f deg/s\n", snprintf(out,80, " Normal Load Factor: %4.2f g's Pitch Rate: %5.2f deg/s\n",
Aircraft->GetNlf(), Aircraft->GetNlf(),
Rotation->GetPQR(2)*radtodeg ); Propagate->GetPQR(2)*radtodeg );
cout << out; cout << out;
snprintf(out,80, " Heading: %3.0f deg true Sideslip: %5.2f deg Yaw Rate: %5.2f deg/s\n", snprintf(out,80, " Heading: %3.0f deg true Sideslip: %5.2f deg Yaw Rate: %5.2f deg/s\n",
Rotation->Getpsi()*radtodeg, Propagate->Getpsi()*radtodeg,
Translation->Getbeta()*radtodeg, Auxiliary->Getbeta()*radtodeg,
Rotation->GetPQR(3)*radtodeg ); Propagate->GetPQR(3)*radtodeg );
cout << out; cout << out;
snprintf(out,80, " Bank Angle: %5.2f deg Roll Rate: %5.2f deg/s\n", snprintf(out,80, " Bank Angle: %5.2f deg Roll Rate: %5.2f deg/s\n",
Rotation->Getphi()*radtodeg, Propagate->Getphi()*radtodeg,
Rotation->GetPQR(1)*radtodeg ); Propagate->GetPQR(1)*radtodeg );
cout << out; cout << out;
snprintf(out,80, " Elevator: %5.2f deg Left Aileron: %5.2f deg Rudder: %5.2f deg\n", snprintf(out,80, " Elevator: %5.2f deg Left Aileron: %5.2f deg Rudder: %5.2f deg\n",
FCS->GetDePos(ofRad)*radtodeg, FCS->GetDePos(ofRad)*radtodeg,
@ -408,15 +257,16 @@ void FGState::ReportState(void)
cout << out; cout << out;
snprintf(out,80, " Wind Components: %5.2f kts head wind, %5.2f kts cross wind\n", snprintf(out,80, " Wind Components: %5.2f kts head wind, %5.2f kts cross wind\n",
FDMExec->GetAuxiliary()->GetHeadWind()*fpstokts, Auxiliary->GetHeadWind()*fpstokts,
FDMExec->GetAuxiliary()->GetCrossWind()*fpstokts ); Auxiliary->GetCrossWind()*fpstokts );
cout << out; cout << out;
snprintf(out,80, " Ground Speed: %4.0f knots , Ground Track: %3.0f deg true\n", snprintf(out,80, " Ground Speed: %4.0f knots , Ground Track: %3.0f deg true\n",
Position->GetVground()*fpstokts, Auxiliary->GetVground()*fpstokts,
Position->GetGroundTrack()*radtodeg ); Auxiliary->GetGroundTrack()*radtodeg );
cout << out; cout << out;
#endif #endif
#endif
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View file

@ -1,35 +1,35 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Header: FGState.h Header: FGState.h
Author: Jon S. Berndt Author: Jon S. Berndt
Date started: 11/17/98 Date started: 11/17/98
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------- ------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later Foundation; either version 2 of the License, or (at your option) any later
version. version.
This program is distributed in the hope that it will be useful, but WITHOUT This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details. details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA. Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org. the world wide web at http://www.gnu.org.
FUNCTIONAL DESCRIPTION FUNCTIONAL DESCRIPTION
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
HISTORY HISTORY
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
11/17/98 JSB Created 11/17/98 JSB Created
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
@ -62,14 +62,12 @@ INCLUDES
#include "FGInitialCondition.h" #include "FGInitialCondition.h"
#include "FGMatrix33.h" #include "FGMatrix33.h"
#include "FGColumnVector3.h" #include "FGColumnVector3.h"
#include "FGColumnVector4.h" #include "FGQuaternion.h"
#include "FGFDMExec.h" #include "FGFDMExec.h"
#include "FGAtmosphere.h" #include "FGAtmosphere.h"
#include "FGFCS.h" #include "FGFCS.h"
#include "FGTranslation.h" #include "FGPropagate.h"
#include "FGRotation.h" #include "FGAuxiliary.h"
#include "FGPosition.h"
#include "FGAerodynamics.h" #include "FGAerodynamics.h"
#include "FGOutput.h" #include "FGOutput.h"
#include "FGAircraft.h" #include "FGAircraft.h"
@ -110,33 +108,6 @@ public:
/// Destructor /// Destructor
~FGState(); ~FGState();
/** Initializes the simulation state based on the passed-in parameters.
@param U the body X-Axis velocity in fps.
@param V the body Y-Axis velocity in fps.
@param W the body Z-Axis velocity in fps.
@param lat latitude measured in radians from the equator, negative values are south.
@param lon longitude, measured in radians from the Greenwich meridian, negative values are west.
@param phi the roll angle in radians.
@param tht the pitch angle in radians.
@param psi the heading angle in radians measured clockwise from north.
@param h altitude in feet.
@param wnorth north velocity in feet per second
@param weast eastward velocity in feet per second
@param wdown downward velocity in feet per second
*/
void Initialize(double U,
double V,
double W,
double lat,
double lon,
double phi,
double tht,
double psi,
double h,
double wnorth,
double weast,
double wdown);
/** Initializes the simulation state based on parameters from an Initial Conditions object. /** Initializes the simulation state based on parameters from an Initial Conditions object.
@param FGIC pointer to an initial conditions object. @param FGIC pointer to an initial conditions object.
@see FGInitialConditions. @see FGInitialConditions.
@ -161,7 +132,7 @@ public:
sim_time = cur_time; sim_time = cur_time;
return sim_time; return sim_time;
} }
/** Sets the integration time step for the simulation executive. /** Sets the integration time step for the simulation executive.
@param delta_t the time step in seconds. @param delta_t the time step in seconds.
*/ */
@ -175,154 +146,21 @@ public:
return sim_time; return sim_time;
} }
/** Initializes the transformation matrices.
@param phi the roll angle in radians.
@param tht the pitch angle in radians.
@param psi the heading angle in radians
*/
void InitMatrices(double phi, double tht, double psi);
/** Calculates the local-to-body and body-to-local conversion matrices.
*/
void CalcMatrices(void);
/** Integrates the quaternion.
Given the supplied rotational rate vector and integration rate, the quaternion
is integrated. The quaternion is later used to update the transformation
matrices.
@param vPQR the body rotational rate column vector.
@param rate the integration rate in seconds.
*/
void IntegrateQuat(FGColumnVector3 vPQR, int rate);
// ======================================= General Purpose INTEGRATOR
enum iType {AB4, AB3, AB2, AM3, AM4, EULER, TRAPZ};
/** Multi-method integrator.
@param type Type of intergation scheme to use. Can be one of:
<ul>
<li>AB4 - Adams-Bashforth, fourth order</li>
<li>AB3 - Adams-Bashforth, third order</li>
<li>AB2 - Adams-Bashforth, second order</li>
<li>AM3 - Adams Moulton, third order</li>
<li>AM4 - Adams Moulton, fourth order</li>
<li>EULER - Euler</li>
<li>TRAPZ - Trapezoidal</li>
</ul>
@param delta_t the integration time step in seconds
@param vTDeriv a reference to the current value of the time derivative of
the quantity being integrated (i.e. if vUVW is being integrated
vTDeriv is the current value of vUVWdot)
@param vLastArray an array of previously calculated and saved values of
the quantity being integrated (i.e. if vUVW is being integrated
vLastArray[0] is the past value of vUVWdot, vLastArray[1] is the value of
vUVWdot prior to that, etc.)
@return the current, incremental value of the item integrated to add to the
previous value. */
template <class T> T Integrate(iType type, double delta_t, T& vTDeriv, T *vLastArray)
{
T vResult;
switch (type) {
case AB4:
vResult = (delta_t/24.0)*( 55.0 * vLastArray[0]
- 59.0 * vLastArray[1]
+ 37.0 * vLastArray[2]
- 9.0 * vLastArray[3] );
vLastArray[3] = vLastArray[2];
vLastArray[2] = vLastArray[1];
vLastArray[1] = vLastArray[0];
vLastArray[0] = vTDeriv;
break;
case AB3:
vResult = (delta_t/12.0)*( 23.0 * vLastArray[0]
- 16.0 * vLastArray[1]
+ 5.0 * vLastArray[2] );
vLastArray[2] = vLastArray[1];
vLastArray[1] = vLastArray[0];
vLastArray[0] = vTDeriv;
break;
case AB2:
vResult = (delta_t/2.0)*( 3.0 * vLastArray[0] - vLastArray[1] );
vLastArray[1] = vLastArray[0];
vLastArray[0] = vTDeriv;
break;
case AM4:
vResult = (delta_t/24.0)*( 9.0 * vTDeriv
+ 19.0 * vLastArray[0]
- 5.0 * vLastArray[1]
+ 1.0 * vLastArray[2] );
vLastArray[2] = vLastArray[1];
vLastArray[1] = vLastArray[0];
vLastArray[0] = vTDeriv;
break;
case AM3:
vResult = (delta_t/12.0)*( 5.0 * vTDeriv
+ 8.0 * vLastArray[0]
- 1.0 * vLastArray[1] );
vLastArray[1] = vLastArray[0];
vLastArray[0] = vTDeriv;
break;
case EULER:
vResult = delta_t * vTDeriv;
break;
case TRAPZ:
vResult = (delta_t*0.5) * (vTDeriv + vLastArray[0]);
vLastArray[0] = vTDeriv;
break;
}
return vResult;
}
// =======================================
/** Calculates Euler angles from the local-to-body matrix.
@return a reference to the vEuler column vector.
*/
FGColumnVector3& CalcEuler(void);
/** Calculates and returns the stability-to-body axis transformation matrix. /** Calculates and returns the stability-to-body axis transformation matrix.
@return a reference to the stability-to-body transformation matrix. @return a reference to the stability-to-body transformation matrix.
*/ */
FGMatrix33& GetTs2b(void); FGMatrix33& GetTs2b(void);
/** Calculates and returns the body-to-stability axis transformation matrix. /** Calculates and returns the body-to-stability axis transformation matrix.
@return a reference to the stability-to-body transformation matrix. @return a reference to the stability-to-body transformation matrix.
*/ */
FGMatrix33& GetTb2s(void); FGMatrix33& GetTb2s(void);
/** Retrieves the local-to-body transformation matrix. /** Prints a summary of simulator state (speed, altitude,
@return a reference to the local-to-body transformation matrix.
*/
FGMatrix33& GetTl2b(void) { return mTl2b; }
/** Retrieves a specific local-to-body matrix element.
@param r matrix row index.
@param c matrix column index.
@return the matrix element described by the row and column supplied.
*/
double GetTl2b(int r, int c) { return mTl2b(r,c);}
/** Retrieves the body-to-local transformation matrix.
@return a reference to the body-to-local matrix.
*/
FGMatrix33& GetTb2l(void) { return mTb2l; }
/** Retrieves a specific body-to-local matrix element.
@param r matrix row index.
@param c matrix column index.
@return the matrix element described by the row and column supplied.
*/
double GetTb2l(int i, int j) { return mTb2l(i,j);}
/** Prints a summary of simulator state (speed, altitude,
configuration, etc.) configuration, etc.)
*/ */
void ReportState(void); void ReportState(void);
void bind(); void bind();
void unbind(); void unbind();
@ -331,29 +169,18 @@ private:
double saved_dt; double saved_dt;
FGFDMExec* FDMExec; FGFDMExec* FDMExec;
FGMatrix33 mTb2l;
FGMatrix33 mTl2b;
FGMatrix33 mTs2b; FGMatrix33 mTs2b;
FGMatrix33 mTb2s; FGMatrix33 mTb2s;
FGColumnVector4 vQtrn;
FGColumnVector4 vQdot_prev[4];
FGColumnVector4 vQdot;
FGColumnVector3 vLocalVelNED;
FGColumnVector3 vLocalEuler;
FGColumnVector4 vTmp;
FGColumnVector3 vEuler;
FGAircraft* Aircraft; FGAircraft* Aircraft;
FGPosition* Position; FGPropagate* Propagate;
FGTranslation* Translation;
FGRotation* Rotation;
FGOutput* Output; FGOutput* Output;
FGAtmosphere* Atmosphere; FGAtmosphere* Atmosphere;
FGFCS* FCS; FGFCS* FCS;
FGAerodynamics* Aerodynamics; FGAerodynamics* Aerodynamics;
FGGroundReactions* GroundReactions; FGGroundReactions* GroundReactions;
FGPropulsion* Propulsion; FGPropulsion* Propulsion;
FGAuxiliary* Auxiliary;
FGPropertyManager* PropertyManager; FGPropertyManager* PropertyManager;
void Debug(int from); void Debug(int from);

View file

@ -56,6 +56,22 @@ CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
FGTable::FGTable(int NRows, int NCols, int NTables)
: nRows(NTables), nCols(1), nTables(NTables)
{
Type = tt3D;
colCounter = 1;
rowCounter = 1;
Data = Allocate(); // this data array will contain the keys for the associated tables
Tables.reserve(nTables);
for (int i=0; i<nTables; i++) Tables.push_back(FGTable(NRows, NCols));
Debug(0);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGTable::FGTable(int NRows, int NCols) : nRows(NRows), nCols(NCols) FGTable::FGTable(int NRows, int NCols) : nRows(NRows), nCols(NCols)
{ {
if (NCols > 1) { if (NCols > 1) {
@ -90,6 +106,31 @@ FGTable::FGTable(int NRows) : nRows(NRows), nCols(1)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGTable::FGTable(const FGTable& t)
{
Type = t.Type;
colCounter = t.colCounter;
rowCounter = t.rowCounter;
tableCounter = t.tableCounter;
nRows = t.nRows;
nCols = t.nCols;
nTables = t.nTables;
Tables = t.Tables;
Data = Allocate();
for (int r=0; r<=nRows; r++) {
for (int c=0; c<=nCols; c++) {
Data[r][c] = t.Data[r][c];
}
}
lastRowIndex = t.lastRowIndex;
lastColumnIndex = t.lastColumnIndex;
lastTableIndex = t.lastTableIndex;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double** FGTable::Allocate(void) double** FGTable::Allocate(void)
{ {
Data = new double*[nRows+1]; Data = new double*[nRows+1];
@ -106,6 +147,7 @@ double** FGTable::Allocate(void)
FGTable::~FGTable() FGTable::~FGTable()
{ {
if (nTables > 0) Tables.clear();
for (int r=0; r<=nRows; r++) if (Data[r]) delete[] Data[r]; for (int r=0; r<=nRows; r++) if (Data[r]) delete[] Data[r];
if (Data) delete[] Data; if (Data) delete[] Data;
Debug(1); Debug(1);
@ -117,8 +159,8 @@ double FGTable::GetValue(double key)
{ {
double Factor, Value, Span; double Factor, Value, Span;
int r=lastRowIndex; int r=lastRowIndex;
//if the key is off the end of the table, just return the //if the key is off the end of the table, just return the
//end-of-table value, do not extrapolate //end-of-table value, do not extrapolate
if( key <= Data[1][0] ) { if( key <= Data[1][0] ) {
lastRowIndex=2; lastRowIndex=2;
@ -128,21 +170,21 @@ double FGTable::GetValue(double key)
lastRowIndex=nRows; lastRowIndex=nRows;
//cout << "Key over table: " << key << endl; //cout << "Key over table: " << key << endl;
return Data[nRows][1]; return Data[nRows][1];
} }
// the key is somewhere in the middle, search for the right breakpoint // the key is somewhere in the middle, search for the right breakpoint
// assume the correct breakpoint has not changed since last frame or // assume the correct breakpoint has not changed since last frame or
// has only changed very little // has only changed very little
if ( r > 2 && Data[r-1][0] > key ) { if ( r > 2 && Data[r-1][0] > key ) {
while( Data[r-1][0] > key && r > 2) { r--; } while( Data[r-1][0] > key && r > 2) { r--; }
} else if ( Data[r][0] < key ) { } else if ( Data[r][0] < key ) {
while( Data[r][0] <= key && r <= nRows) { r++; } while( Data[r][0] <= key && r <= nRows) { r++; }
} }
lastRowIndex=r; lastRowIndex=r;
// make sure denominator below does not go to zero. // make sure denominator below does not go to zero.
Span = Data[r][0] - Data[r-1][0]; Span = Data[r][0] - Data[r-1][0];
if (Span != 0.0) { if (Span != 0.0) {
Factor = (key - Data[r-1][0]) / Span; Factor = (key - Data[r-1][0]) / Span;
@ -164,25 +206,25 @@ double FGTable::GetValue(double rowKey, double colKey)
double rFactor, cFactor, col1temp, col2temp, Value; double rFactor, cFactor, col1temp, col2temp, Value;
int r=lastRowIndex; int r=lastRowIndex;
int c=lastColumnIndex; int c=lastColumnIndex;
if ( r > 2 && Data[r-1][0] > rowKey ) { if ( r > 2 && Data[r-1][0] > rowKey ) {
while ( Data[r-1][0] > rowKey && r > 2) { r--; } while ( Data[r-1][0] > rowKey && r > 2) { r--; }
} else if ( Data[r][0] < rowKey ) { } else if ( Data[r][0] < rowKey ) {
// cout << Data[r][0] << endl; // cout << Data[r][0] << endl;
while ( r <= nRows && Data[r][0] <= rowKey ) { r++; } while ( r <= nRows && Data[r][0] <= rowKey ) { r++; }
if ( r > nRows ) r = nRows; if ( r > nRows ) r = nRows;
} }
if ( c > 2 && Data[0][c-1] > colKey ) { if ( c > 2 && Data[0][c-1] > colKey ) {
while( Data[0][c-1] > colKey && c > 2) { c--; } while( Data[0][c-1] > colKey && c > 2) { c--; }
} else if ( Data[0][c] < colKey ) { } else if ( Data[0][c] < colKey ) {
while( Data[0][c] <= colKey && c <= nCols) { c++; } while( Data[0][c] <= colKey && c <= nCols) { c++; }
if ( c > nCols ) c = nCols; if ( c > nCols ) c = nCols;
} }
lastRowIndex=r; lastRowIndex=r;
lastColumnIndex=c; lastColumnIndex=c;
rFactor = (rowKey - Data[r-1][0]) / (Data[r][0] - Data[r-1][0]); rFactor = (rowKey - Data[r-1][0]) / (Data[r][0] - Data[r-1][0]);
cFactor = (colKey - Data[0][c-1]) / (Data[0][c] - Data[0][c-1]); cFactor = (colKey - Data[0][c-1]) / (Data[0][c] - Data[0][c-1]);
@ -202,17 +244,68 @@ double FGTable::GetValue(double rowKey, double colKey)
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGTable::GetValue(double rowKey, double colKey, double tableKey)
{
double Factor, Value, Span;
int r=lastRowIndex;
//if the key is off the end (or before the beginning) of the table,
// just return the boundary-table value, do not extrapolate
if( tableKey <= Data[1][1] ) {
lastRowIndex=2;
return Tables[0].GetValue(rowKey, colKey);
} else if ( tableKey >= Data[nRows][1] ) {
lastRowIndex=nRows;
return Tables[nRows-1].GetValue(rowKey, colKey);
}
// the key is somewhere in the middle, search for the right breakpoint
// assume the correct breakpoint has not changed since last frame or
// has only changed very little
if ( r > 2 && Data[r-1][1] > tableKey ) {
while( Data[r-1][1] > tableKey && r > 2) { r--; }
} else if ( Data[r][1] < tableKey ) {
while( Data[r][1] <= tableKey && r <= nRows) { r++; }
}
lastRowIndex=r;
// make sure denominator below does not go to zero.
Span = Data[r][1] - Data[r-1][1];
if (Span != 0.0) {
Factor = (tableKey - Data[r-1][1]) / Span;
if (Factor > 1.0) Factor = 1.0;
} else {
Factor = 1.0;
}
Value = Factor*(Tables[r-1].GetValue(rowKey, colKey) - Tables[r-2].GetValue(rowKey, colKey))
+ Tables[r-1].GetValue(rowKey, colKey);
return Value;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGTable::operator<<(FGConfigFile& infile) void FGTable::operator<<(FGConfigFile& infile)
{ {
int startRow; int startRow=0;
int startCol=0;
int tableCtr=0;
if (Type == tt1D) startRow = 1; if (Type == tt1D || Type == tt3D) startRow = 1;
else startRow = 0; if (Type == tt3D) startCol = 1;
for (int r=startRow; r<=nRows; r++) { for (int r=startRow; r<=nRows; r++) {
for (int c=0; c<=nCols; c++) { for (int c=startCol; c<=nCols; c++) {
if (r != 0 || c != 0) { if (r != 0 || c != 0) {
infile >> Data[r][c]; infile >> Data[r][c];
if (Type == tt3D) {
Tables[tableCtr] << infile;
tableCtr++;
}
} }
} }
} }
@ -244,10 +337,11 @@ FGTable& FGTable::operator<<(const int n)
void FGTable::Print(void) void FGTable::Print(void)
{ {
int startRow; int startRow=0;
int startCol=0;
if (Type == tt1D) startRow = 1; if (Type == tt1D || Type == tt3D) startRow = 1;
else startRow = 0; if (Type == tt3D) startCol = 1;
#if defined (sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740) #if defined (sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
unsigned long flags = cout.setf(ios::fixed); unsigned long flags = cout.setf(ios::fixed);
@ -256,14 +350,17 @@ void FGTable::Print(void)
#endif #endif
cout.precision(4); cout.precision(4);
for (int r=startRow; r<=nRows; r++) { for (int r=startRow; r<=nRows; r++) {
cout << " "; cout << " ";
for (int c=0; c<=nCols; c++) { for (int c=startCol; c<=nCols; c++) {
if (r == 0 && c == 0) { if (r == 0 && c == 0) {
cout << " "; cout << " ";
} else { } else {
cout << Data[r][c] << " "; cout << Data[r][c] << " ";
if (Type == tt3D) {
cout << endl;
Tables[r-1].Print();
}
} }
} }
cout << endl; cout << endl;

View file

@ -40,6 +40,7 @@ INCLUDES
#include "FGConfigFile.h" #include "FGConfigFile.h"
#include "FGJSBBase.h" #include "FGJSBBase.h"
#include <vector>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS DEFINITIONS
@ -51,6 +52,8 @@ DEFINITIONS
FORWARD DECLARATIONS FORWARD DECLARATIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
using std::vector;
namespace JSBSim { namespace JSBSim {
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -58,7 +61,134 @@ CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Lookup table class. /** Lookup table class.
Models a lookup table for use in FGCoefficient, FGPropeller, etc. Models a one, two, or three dimensional lookup table for use in FGCoefficient,
FGPropeller, etc. A one-dimensional table is called a "VECTOR" in a coefficient
definition. For example:
<pre>
\<COEFFICIENT NAME="{short name}" TYPE="VECTOR">
{name}
{number of rows}
{row lookup property}
{non-dimensionalizing properties}
{row_1_key} {col_1_data}
{row_2_key} {... }
{ ... } {... }
{row_n_key} {... }
\</COEFFICIENT>
</pre>
A "real life" example is as shown here:
<pre>
\<COEFFICIENT NAME="CLDf" TYPE="VECTOR">
Delta_lift_due_to_flap_deflection
4
fcs/flap-pos-deg
aero/qbar-psf | metrics/Sw-sqft
0 0
10 0.20
20 0.30
30 0.35
\</COEFFICIENT>
</pre>
The first column in the data table represents the lookup index (or "key"). In
this case, the lookup index is fcs/flap-pos-deg (flap extension in degrees).
If the flap position is 10 degrees, the value returned from the lookup table
would be 0.20. This value would be multiplied by qbar (aero/qbar-psf) and wing
area (metrics/Sw-sqft) to get the total lift force that is a result of flap
deflection (measured in pounds force). If the value of the flap-pos-deg property
was 15 (degrees), the value output by the table routine would be 0.25 - an
interpolation. If the flap position in degrees ever went below 0.0, or above
30 (degrees), the output from the table routine would be 0 and 0.35, respectively.
That is, there is no _extrapolation_ to values outside the range of the lookup
index. This is why it is important to chose the data for the table wisely.
The definition for a 2D table - referred to simply as a TABLE, is as follows:
<pre>
\<COEFFICIENT NAME="{short name}" TYPE="TABLE">
{name}
{number of rows}
{number of columns}
{row lookup property}
{column lookup property}
{non-dimensionalizing}
{col_1_key col_2_key ... col_n_key }
{row_1_key} {col_1_data col_2_data ... col_n_data}
{row_2_key} {... ... ... ... }
{ ... } {... ... ... ... }
{row_n_key} {... ... ... ... }
\</COEFFICIENT>
</pre>
A "real life" example is as shown here:
<pre>
\<COEFFICIENT NAME="CYb" TYPE="TABLE">
Side_force_due_to_beta
3
2
aero/beta-rad
fcs/flap-pos-deg
aero/qbar-psf | metrics/Sw-sqft
0 30
-0.349 0.137 0.106
0 0 0
0.349 -0.137 -0.106
\</COEFFICIENT>
</pre>
The definition for a 3D table in a coefficient would be (for example):
<pre>
\<COEFFICIENT NAME="{short name}" TYPE="TABLE3D">
{name}
{number of rows}
{number of columns}
{number of tables}
{row lookup property}
{column lookup property}
{table lookup property}
{non-dimensionalizing}
{first table key}
{col_1_key col_2_key ... col_n_key }
{row_1_key} {col_1_data col_2_data ... col_n_data}
{row_2_key} {... ... ... ... }
{ ... } {... ... ... ... }
{row_n_key} {... ... ... ... }
{second table key}
{col_1_key col_2_key ... col_n_key }
{row_1_key} {col_1_data col_2_data ... col_n_data}
{row_2_key} {... ... ... ... }
{ ... } {... ... ... ... }
{row_n_key} {... ... ... ... }
...
\</COEFFICIENT>
</pre>
[At the present time, all rows and columns for each table must have the
same dimension.]
In addition to using a Table for something like a coefficient, where all the
row and column elements are read in from a file, a Table could be created
and populated completely within program code:
<pre>
// First column is thi, second is neta (combustion efficiency)
Lookup_Combustion_Efficiency = new FGTable(12);
*Lookup_Combustion_Efficiency << 0.00 << 0.980;
*Lookup_Combustion_Efficiency << 0.90 << 0.980;
*Lookup_Combustion_Efficiency << 1.00 << 0.970;
*Lookup_Combustion_Efficiency << 1.05 << 0.950;
*Lookup_Combustion_Efficiency << 1.10 << 0.900;
*Lookup_Combustion_Efficiency << 1.15 << 0.850;
*Lookup_Combustion_Efficiency << 1.20 << 0.790;
*Lookup_Combustion_Efficiency << 1.30 << 0.700;
*Lookup_Combustion_Efficiency << 1.40 << 0.630;
*Lookup_Combustion_Efficiency << 1.50 << 0.570;
*Lookup_Combustion_Efficiency << 1.60 << 0.525;
*Lookup_Combustion_Efficiency << 2.00 << 0.345;
</pre>
The first column in the table, above, is thi (the lookup index, or key). The
second column is the output data - in this case, "neta" (the Greek letter
referring to combustion efficiency). Later on, the table is used like this:
combustion_efficiency = Lookup_Combustion_Efficiency->GetValue(equivalence_ratio);
@author Jon S. Berndt @author Jon S. Berndt
@version $Id$ @version $Id$
@see FGCoefficient @see FGCoefficient
@ -72,11 +202,21 @@ CLASS DECLARATION
class FGTable : public FGJSBBase class FGTable : public FGJSBBase
{ {
public: public:
/// Destructor
~FGTable(); ~FGTable();
/** This is the very important copy constructor.
@param table a const reference to a table.*/
FGTable(const FGTable& table);
/** The constructor for a VECTOR table
@param nRows the number of rows in this VECTOR table. */
FGTable(int nRows); FGTable(int nRows);
FGTable(int nRows, int nCols); FGTable(int nRows, int nCols);
FGTable(int nRows, int nCols, int numTables);
double GetValue(double key); double GetValue(double key);
double GetValue(double rowKey, double colKey); double GetValue(double rowKey, double colKey);
double GetValue(double rowKey, double colKey, double TableKey);
/** Read the table in. /** Read the table in.
Data in the config file should be in matrix format with the row Data in the config file should be in matrix format with the row
independents as the first column and the column independents in independents as the first column and the column independents in
@ -87,20 +227,32 @@ public:
-5 1 2 3 4 ... -5 1 2 3 4 ...
... ...
</pre> </pre>
For multiple-table (i.e. 3D) data sets there is an additional number
key in the table definition. For example:
<pre>
0.0
0 10 20 30 ...
-5 1 2 3 4 ...
...
</pre>
*/ */
void operator<<(FGConfigFile&); void operator<<(FGConfigFile&);
FGTable& operator<<(const double n); FGTable& operator<<(const double n);
FGTable& operator<<(const int n); FGTable& operator<<(const int n);
inline double GetElement(int r, int c) {return Data[r][c];} inline double GetElement(int r, int c) {return Data[r][c];}
inline double GetElement(int r, int c, int t);
void Print(void); void Print(void);
private: private:
enum type {tt1D, tt2D} Type; enum type {tt1D, tt2D, tt3D} Type;
double** Data; double** Data;
int nRows, nCols; vector <FGTable> Tables;
int colCounter; int nRows, nCols, nTables;
int rowCounter; int colCounter, rowCounter, tableCounter;
int lastRowIndex, lastColumnIndex; int lastRowIndex, lastColumnIndex, lastTableIndex;
double** Allocate(void); double** Allocate(void);
void Debug(int from); void Debug(int from);
}; };

View file

@ -53,10 +53,13 @@ static const char *IdHdr = ID_TANK;
CLASS IMPLEMENTATION CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
FGTank::FGTank(FGConfigFile* AC_cfg) FGTank::FGTank(FGConfigFile* AC_cfg, FGFDMExec* exec)
{ {
string token; string token;
double X, Y, Z; double X, Y, Z;
Area = 1.0;
Temperature = -9999.0;
Auxiliary = exec->GetAuxiliary();
type = AC_cfg->GetValue("TYPE"); type = AC_cfg->GetValue("TYPE");
@ -72,6 +75,7 @@ FGTank::FGTank(FGConfigFile* AC_cfg)
else if (token == "RADIUS") *AC_cfg >> Radius; else if (token == "RADIUS") *AC_cfg >> Radius;
else if (token == "CAPACITY") *AC_cfg >> Capacity; else if (token == "CAPACITY") *AC_cfg >> Capacity;
else if (token == "CONTENTS") *AC_cfg >> Contents; else if (token == "CONTENTS") *AC_cfg >> Contents;
else if (token == "TEMPERATURE") *AC_cfg >> Temperature;
else cerr << "Unknown identifier: " << token << " in tank definition." << endl; else cerr << "Unknown identifier: " << token << " in tank definition." << endl;
} }
@ -86,6 +90,9 @@ FGTank::FGTank(FGConfigFile* AC_cfg)
PctFull = 0; PctFull = 0;
} }
if (Temperature != -9999.0) Temperature = FahrenheitToCelsius(Temperature);
Area = 40.0 * pow(Capacity/1975, 0.666666667);
Debug(0); Debug(0);
} }
@ -98,7 +105,7 @@ FGTank::~FGTank()
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGTank::Reduce(double used) double FGTank::Drain(double used)
{ {
double shortage = Contents - used; double shortage = Contents - used;
@ -113,6 +120,53 @@ double FGTank::Reduce(double used)
return shortage; return shortage;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGTank::Fill(double amount)
{
double overage = 0.0;
Contents += amount;
if (Contents > Capacity) {
overage = Contents - Capacity;
Contents = Capacity;
PctFull = 100.0;
} else {
PctFull = Contents/Capacity*100.0;
}
return overage;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGTank::SetContents(double amount)
{
Contents = amount;
if (Contents > Capacity) {
Contents = Capacity;
PctFull = 100.0;
} else {
PctFull = Contents/Capacity*100.0;
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGTank::Calculate(double dt)
{
if (Temperature == -9999.0) return 0.0;
double HeatCapacity = 900.0; // Joules/lbm/C
double TempFlowFactor = 1.115; // Watts/sqft/C
double TAT = Auxiliary->GetTAT_C();
double Tdiff = TAT - Temperature;
double dT = 0.0; // Temp change due to one surface
if (fabs(Tdiff) > 0.1) {
dT = (TempFlowFactor * Area * Tdiff * dt) / (Contents * HeatCapacity);
}
return Temperature += (dT + dT); // For now, assume upper/lower the same
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows: // The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print // unset: In this case (the default) JSBSim would only print

View file

@ -47,6 +47,7 @@ INCLUDES
#include "FGJSBBase.h" #include "FGJSBBase.h"
#include "FGConfigFile.h" #include "FGConfigFile.h"
#include "FGColumnVector3.h" #include "FGColumnVector3.h"
#include "FGAuxiliary.h"
#ifdef FGFS #ifdef FGFS
# include <simgear/compiler.h> # include <simgear/compiler.h>
@ -82,6 +83,48 @@ CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Models a fuel tank. /** Models a fuel tank.
@author Jon Berndt
@see Akbar, Raza et al. "A Simple Analysis of Fuel Addition to the CWT of
747", California Institute of Technology, 1998
<P>
Fuel temperature is calculated using the following assumptions:
<P>
Fuel temperature will only be calculated for tanks which have an initial fuel
temperature specified in the configuration file.
<P>
The surface area of the tank is estimated from the capacity in pounds. It
is assumed that the tank is a wing tank with dimensions h by 4h by 10h. The
volume of the tank is then 40(h)(h)(h). The area of the upper or lower
surface is then 40(h)(h). The volume is also equal to the capacity divided
by 49.368 lbs/cu-ft, for jet fuel. The surface area of one side can then be
derived from the tank's capacity.
<P>
The heat capacity of jet fuel is assumed to be 900 Joules/lbm/K, and the
heat transfer factor of the tank is 1.115 Watts/sq-ft/K.
<P>
Configuration File Format
<pre>
\<AC_TANK TYPE="\<FUEL | OXIDIZER>" NUMBER="\<n>">
XLOC \<x location>
YLOC \<y location>
ZLOC \<z location>
RADIUS \<radius>
CAPACITY \<capacity>
CONTENTS \<contents>
TEMPERATURE \<fuel temperature>
\</AC_TANK>
</pre>
Definition of the tank configuration file parameters:
<pre>
<b>TYPE</b> - One of FUEL or OXIDIZER.
<b>XLOC</b> - Location of tank on aircraft's x-axis, inches.
<b>YLOC</b> - Location of tank on aircraft's y-axis, inches.
<b>ZLOC</b> - Location of tank on aircraft's z-axis, inches.
<b>RADIUS</b> - Equivalent radius of tank, inches, for modeling slosh.
<b>CAPACITY</b> - Capacity in pounds.
<b>CONTENTS</b> - Initial contents in pounds.
<b>TEMPERATURE</b> - Initial temperature in degrees Fahrenheit.
</pre>
*/ */
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -91,18 +134,23 @@ CLASS DECLARATION
class FGTank : public FGJSBBase class FGTank : public FGJSBBase
{ {
public: public:
FGTank(FGConfigFile*); FGTank(FGConfigFile*, FGFDMExec*);
~FGTank(); ~FGTank();
double Reduce(double); double Drain(double);
double Calculate(double dt);
int GetType(void) {return Type;} int GetType(void) {return Type;}
bool GetSelected(void) {return Selected;} bool GetSelected(void) {return Selected;}
double GetPctFull(void) {return PctFull;} double GetPctFull(void) {return PctFull;}
double GetContents(void) {return Contents;} double GetContents(void) {return Contents;}
double GetTemperature_degC(void) {return Temperature;}
double GetTemperature(void) {return CelsiusToFahrenheit(Temperature);}
const FGColumnVector3& GetXYZ(void) {return vXYZ;} const FGColumnVector3& GetXYZ(void) {return vXYZ;}
double GetXYZ(int idx) {return vXYZ(idx);} double GetXYZ(int idx) {return vXYZ(idx);}
void SetContents(double contents) { Contents = contents; } double Fill(double amount);
void SetContents(double amount);
void SetTemperature(double temp) { Temperature = temp; }
enum TankType {ttUNKNOWN, ttFUEL, ttOXIDIZER}; enum TankType {ttUNKNOWN, ttFUEL, ttOXIDIZER};
@ -114,7 +162,10 @@ private:
double Radius; double Radius;
double PctFull; double PctFull;
double Contents; double Contents;
double Area;
double Temperature;
bool Selected; bool Selected;
FGAuxiliary* Auxiliary;
void Debug(int from); void Debug(int from);
}; };
} }

View file

@ -35,6 +35,8 @@ HISTORY
INCLUDES INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include <sstream>
#include "FGThruster.h" #include "FGThruster.h"
namespace JSBSim { namespace JSBSim {
@ -47,8 +49,7 @@ CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
FGThruster::FGThruster(FGFDMExec *FDMExec) : FGForce(FDMExec), FGThruster::FGThruster(FGFDMExec *FDMExec) : FGForce(FDMExec)
ThrusterNumber(0)
{ {
Type = ttDirect; Type = ttDirect;
SetTransformType(FGForce::tCustom); SetTransformType(FGForce::tCustom);
@ -61,13 +62,12 @@ FGThruster::FGThruster(FGFDMExec *FDMExec) : FGForce(FDMExec),
FGThruster::FGThruster(FGFDMExec *FDMExec, FGThruster::FGThruster(FGFDMExec *FDMExec,
FGConfigFile *Eng_cfg ): FGForce(FDMExec) FGConfigFile *Eng_cfg ): FGForce(FDMExec)
{ {
ThrusterNumber = 0;
Type = ttDirect; Type = ttDirect;
SetTransformType(FGForce::tCustom); SetTransformType(FGForce::tCustom);
Name = Eng_cfg->GetValue(); Name = Eng_cfg->GetValue();
GearRatio = 1.0; GearRatio = 1.0;
Debug(0); Debug(0);
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@ -76,6 +76,28 @@ FGThruster::~FGThruster()
Debug(1); Debug(1);
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGThruster::GetThrusterLabels(int id)
{
std::ostringstream buf;
buf << Name << "_Thrust[" << id << "]";
return buf.str();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGThruster::GetThrusterValues(int id)
{
std::ostringstream buf;
buf << Thrust;
return buf.str();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows: // The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print // unset: In this case (the default) JSBSim would only print

View file

@ -40,6 +40,7 @@ INCLUDES
#include "FGForce.h" #include "FGForce.h"
#include "FGConfigFile.h" #include "FGConfigFile.h"
#include <string>
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS DEFINITIONS
@ -79,21 +80,20 @@ public:
virtual double Calculate(double tt) { Thrust = tt; vFn(1) = Thrust; return 0.0; } virtual double Calculate(double tt) { Thrust = tt; vFn(1) = Thrust; return 0.0; }
void SetName(string name) {Name = name;} void SetName(string name) {Name = name;}
void SetThrusterNumber(int nn) {ThrusterNumber = nn;}
virtual void SetRPM(double rpm) {}; virtual void SetRPM(double rpm) {};
virtual double GetPowerRequired(void) {return 0.0;} virtual double GetPowerRequired(void) {return 0.0;}
virtual void SetdeltaT(double dt) {deltaT = dt;} virtual void SetdeltaT(double dt) {deltaT = dt;}
double GetThrust(void) {return Thrust;} double GetThrust(void) {return Thrust;}
eType GetType(void) {return Type;} eType GetType(void) {return Type;}
string GetName(void) {return Name;} string GetName(void) {return Name;}
int GetThrusterNumber(void) {return ThrusterNumber;}
virtual double GetRPM(void) { return 0.0; }; virtual double GetRPM(void) { return 0.0; };
double GetGearRatio(void) {return GearRatio; } double GetGearRatio(void) {return GearRatio; }
virtual string GetThrusterLabels(int id);
virtual string GetThrusterValues(int id);
protected: protected:
eType Type; eType Type;
string Name; string Name;
int ThrusterNumber;
double Thrust; double Thrust;
double PowerRequired; double PowerRequired;
double deltaT; double deltaT;

View file

@ -1,320 +0,0 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Module: FGTranslation.cpp
Author: Jon Berndt
Date started: 12/02/98
Purpose: Integrates the translational EOM
Called by: FDMExec
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org.
FUNCTIONAL DESCRIPTION
--------------------------------------------------------------------------------
This class integrates the translational EOM.
HISTORY
--------------------------------------------------------------------------------
12/02/98 JSB Created
7/23/99 TP Added data member and modified Run and PutState to calcuate
Mach number
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
COMMENTS, REFERENCES, and NOTES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
[1] Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
School, January 1994
[2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
JSC 12960, July 1977
[3] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
NASA-Ames", NASA CR-2497, January 1975
[4] Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
Wiley & Sons, 1979 ISBN 0-471-03032-5
[5] Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
1982 ISBN 0-471-08936-2
The order of rotations used in this class corresponds to a 3-2-1 sequence,
or Y-P-R, or Z-Y-X, if you prefer.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGTranslation.h"
#include "FGRotation.h"
#include "FGAtmosphere.h"
#include "FGState.h"
#include "FGFDMExec.h"
#include "FGFCS.h"
#include "FGMassBalance.h"
#include "FGAircraft.h"
#include "FGPosition.h"
#include "FGAuxiliary.h"
#include "FGOutput.h"
#include "FGPropertyManager.h"
namespace JSBSim {
static const char *IdSrc = "$Id$";
static const char *IdHdr = ID_TRANSLATION;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
FGTranslation::FGTranslation(FGFDMExec* fdmex) : FGModel(fdmex)
{
Name = "FGTranslation";
qbar = 0;
qbarUW = 0.0;
qbarUV = 0.0;
Vt = 0.0;
Mach = 0.0;
alpha = beta = 0.0;
adot = bdot = 0.0;
vUVWdot.InitMatrix();
vUVWdot_prev[0].InitMatrix();
vUVWdot_prev[1].InitMatrix();
vUVWdot_prev[2].InitMatrix();
vUVWdot_prev[3].InitMatrix();
bind();
Debug(0);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FGTranslation::~FGTranslation(void)
{
unbind();
Debug(1);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGTranslation::Run(void)
{
if (!FGModel::Run()) {
vUVWdot = vUVW*Rotation->GetPQR() + Aircraft->GetBodyAccel();
vUVW += State->Integrate(FGState::TRAPZ, State->Getdt()*rate, vUVWdot, vUVWdot_prev);
vAeroUVW = vUVW + State->GetTl2b()*Atmosphere->GetWindNED();
Vt = vAeroUVW.Magnitude();
if ( Vt > 1) {
if (vAeroUVW(eW) != 0.0)
alpha = vAeroUVW(eU)*vAeroUVW(eU) > 0.0 ? atan2(vAeroUVW(eW), vAeroUVW(eU)) : 0.0;
if (vAeroUVW(eV) != 0.0)
beta = vAeroUVW(eU)*vAeroUVW(eU)+vAeroUVW(eW)*vAeroUVW(eW) > 0.0 ? atan2(vAeroUVW(eV),
sqrt(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW))) : 0.0;
double mUW = (vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW));
double signU=1;
if (vAeroUVW(eU) != 0.0)
signU = vAeroUVW(eU)/fabs(vAeroUVW(eU));
if ( (mUW == 0.0) || (Vt == 0.0) ) {
adot = 0.0;
bdot = 0.0;
} else {
adot = (vAeroUVW(eU)*vAeroUVW(eW) - vAeroUVW(eW)*vUVWdot(eU))/mUW;
bdot = (signU*mUW*vUVWdot(eV) - vAeroUVW(eV)*(vAeroUVW(eU)*vUVWdot(eU)
+ vAeroUVW(eW)*vUVWdot(eW)))/(Vt*Vt*sqrt(mUW));
}
} else {
alpha = beta = adot = bdot = 0;
}
qbar = 0.5*Atmosphere->GetDensity()*Vt*Vt;
qbarUW = 0.5*Atmosphere->GetDensity()*(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW));
qbarUV = 0.5*Atmosphere->GetDensity()*(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eV)*vAeroUVW(eV));
Mach = Vt / Atmosphere->GetSoundSpeed();
vMachUVW(eU) = vAeroUVW(eU) / Atmosphere->GetSoundSpeed();
vMachUVW(eV) = vAeroUVW(eV) / Atmosphere->GetSoundSpeed();
vMachUVW(eW) = vAeroUVW(eW) / Atmosphere->GetSoundSpeed();
if (debug_lvl > 1) Debug(1);
return false;
} else {
return true;
}
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGTranslation::bind(void)
{
typedef double (FGTranslation::*PMF)(int) const;
PropertyManager->Tie("velocities/u-fps", this,1,
(PMF)&FGTranslation::GetUVW /*,
&FGTranslation::SetUVW,
true */);
PropertyManager->Tie("velocities/v-fps", this,2,
(PMF)&FGTranslation::GetUVW /*,
&FGTranslation::SetUVW,
true*/);
PropertyManager->Tie("velocities/w-fps", this,3,
(PMF)&FGTranslation::GetUVW /*,
&FGTranslation::SetUVW,
true*/);
PropertyManager->Tie("accelerations/udot-fps", this,1,
(PMF)&FGTranslation::GetUVWdot);
PropertyManager->Tie("accelerations/vdot-fps", this,2,
(PMF)&FGTranslation::GetUVWdot);
PropertyManager->Tie("accelerations/wdot-fps", this,3,
(PMF)&FGTranslation::GetUVWdot);
PropertyManager->Tie("velocities/u-aero-fps", this,1,
(PMF)&FGTranslation::GetAeroUVW);
PropertyManager->Tie("velocities/v-aero-fps", this,2,
(PMF)&FGTranslation::GetAeroUVW);
PropertyManager->Tie("velocities/w-aero-fps", this,3,
(PMF)&FGTranslation::GetAeroUVW);
PropertyManager->Tie("aero/alpha-rad", this,
&FGTranslation::Getalpha,
&FGTranslation::Setalpha,
true);
PropertyManager->Tie("aero/beta-rad", this,
&FGTranslation::Getbeta,
&FGTranslation::Setbeta,
true);
PropertyManager->Tie("aero/mag-beta-rad", this,
&FGTranslation::GetMagBeta);
PropertyManager->Tie("aero/qbar-psf", this,
&FGTranslation::Getqbar,
&FGTranslation::Setqbar,
true);
PropertyManager->Tie("aero/qbarUW-psf", this,
&FGTranslation::GetqbarUW,
&FGTranslation::SetqbarUW,
true);
PropertyManager->Tie("aero/qbarUV-psf", this,
&FGTranslation::GetqbarUV,
&FGTranslation::SetqbarUV,
true);
PropertyManager->Tie("velocities/vt-fps", this,
&FGTranslation::GetVt,
&FGTranslation::SetVt,
true);
PropertyManager->Tie("velocities/mach-norm", this,
&FGTranslation::GetMach,
&FGTranslation::SetMach,
true);
PropertyManager->Tie("aero/alphadot-rad_sec", this,
&FGTranslation::Getadot,
&FGTranslation::Setadot,
true);
PropertyManager->Tie("aero/betadot-rad_sec", this,
&FGTranslation::Getbdot,
&FGTranslation::Setbdot,
true);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGTranslation::unbind(void)
{
PropertyManager->Untie("velocities/u-fps");
PropertyManager->Untie("velocities/v-fps");
PropertyManager->Untie("velocities/w-fps");
PropertyManager->Untie("accelerations/udot-fps");
PropertyManager->Untie("accelerations/vdot-fps");
PropertyManager->Untie("accelerations/wdot-fps");
PropertyManager->Untie("velocities/u-aero-fps");
PropertyManager->Untie("velocities/v-aero-fps");
PropertyManager->Untie("velocities/w-aero-fps");
PropertyManager->Untie("aero/alpha-rad");
PropertyManager->Untie("aero/beta-rad");
PropertyManager->Untie("aero/qbar-psf");
PropertyManager->Untie("aero/qbarUW-psf");
PropertyManager->Untie("aero/qbarUV-psf");
PropertyManager->Untie("velocities/vt-fps");
PropertyManager->Untie("velocities/mach-norm");
PropertyManager->Untie("aero/alphadot-rad_sec");
PropertyManager->Untie("aero/betadot-rad_sec");
PropertyManager->Untie("aero/mag-beta-rad");
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print
// out the normally expected messages, essentially echoing
// the config files as they are read. If the environment
// variable is not set, debug_lvl is set to 1 internally
// 0: This requests JSBSim not to output any messages
// whatsoever.
// 1: This value explicity requests the normal JSBSim
// startup messages
// 2: This value asks for a message to be printed out when
// a class is instantiated
// 4: When this value is set, a message is displayed when a
// FGModel object executes its Run() method
// 8: When this value is set, various runtime state variables
// are printed out periodically
// 16: When set various parameters are sanity checked and
// a message is printed out when they go out of bounds
void FGTranslation::Debug(int from)
{
if (debug_lvl <= 0) return;
if (debug_lvl & 1) { // Standard console startup message output
if (from == 0) { // Constructor
}
}
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
if (from == 0) cout << "Instantiated: FGTranslation" << endl;
if (from == 1) cout << "Destroyed: FGTranslation" << endl;
}
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
}
if (debug_lvl & 8 ) { // Runtime state variables
}
if (debug_lvl & 16) { // Sanity checking
if (fabs(vUVW(eU)) > 1e6)
cout << "FGTranslation::U velocity out of bounds: " << vUVW(eU) << endl;
if (fabs(vUVW(eV)) > 1e6)
cout << "FGTranslation::V velocity out of bounds: " << vUVW(eV) << endl;
if (fabs(vUVW(eW)) > 1e6)
cout << "FGTranslation::W velocity out of bounds: " << vUVW(eW) << endl;
if (fabs(vUVWdot(eU)) > 1e4)
cout << "FGTranslation::U acceleration out of bounds: " << vUVWdot(eU) << endl;
if (fabs(vUVWdot(eV)) > 1e4)
cout << "FGTranslation::V acceleration out of bounds: " << vUVWdot(eV) << endl;
if (fabs(vUVWdot(eW)) > 1e4)
cout << "FGTranslation::W acceleration out of bounds: " << vUVWdot(eW) << endl;
if (Mach > 100 || Mach < 0.00)
cout << "FGTranslation::Mach is out of bounds: " << Mach << endl;
if (qbar > 1e6 || qbar < 0.00)
cout << "FGTranslation::qbar is out of bounds: " << qbar << endl;
}
if (debug_lvl & 64) {
if (from == 0) { // Constructor
cout << IdSrc << endl;
cout << IdHdr << endl;
}
}
}
}

View file

@ -1,155 +0,0 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Header: FGTranslation.h
Author: Jon Berndt
Date started: 12/02/98
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org.
HISTORY
--------------------------------------------------------------------------------
12/02/98 JSB Created
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifndef FGTRANSLATION_H
#define FGTRANSLATION_H
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#ifdef FGFS
# include <simgear/compiler.h>
# ifdef SG_HAVE_STD_INCLUDES
# include <cmath>
# else
# include <math.h>
# endif
#else
# if defined(sgi) && !defined(__GNUC__)
# include <math.h>
# else
# include <cmath>
# endif
#endif
#include "FGModel.h"
#include "FGColumnVector3.h"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
DEFINITIONS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#define ID_TRANSLATION "$Id$"
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
FORWARD DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
namespace JSBSim {
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** Models the translation aspects of the EOM.
Note: The order of rotations used in this class corresponds to a 3-2-1 sequence,
or Y-P-R, or Z-Y-X, if you prefer.
@see Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
School, January 1994
@see D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
JSC 12960, July 1977
@see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
NASA-Ames", NASA CR-2497, January 1975
@see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
Wiley & Sons, 1979 ISBN 0-471-03032-5
@see Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
1982 ISBN 0-471-08936-2
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
class FGTranslation : public FGModel {
public:
FGTranslation(FGFDMExec*);
~FGTranslation();
inline double GetUVW (int idx) const { return vUVW(idx); }
inline FGColumnVector3& GetUVW (void) { return vUVW; }
inline FGColumnVector3& GetUVWdot(void) { return vUVWdot; }
inline double GetUVWdot(int idx) const { return vUVWdot(idx); }
inline FGColumnVector3& GetAeroUVW (void) { return vAeroUVW; }
inline double GetAeroUVW (int idx) const { return vAeroUVW(idx); }
double Getalpha(void) const { return alpha; }
double Getbeta (void) const { return beta; }
inline double GetMagBeta(void) const { return fabs(beta); }
double Getqbar (void) const { return qbar; }
double GetqbarUW (void) const { return qbarUW; }
double GetqbarUV (void) const { return qbarUV; }
inline double GetVt (void) const { return Vt; }
double GetMach (void) const { return Mach; }
double GetMachU(void) const { return vMachUVW(eU); }
double Getadot (void) const { return adot; }
double Getbdot (void) const { return bdot; }
void SetUVW(FGColumnVector3 tt) { vUVW = tt; }
void SetAeroUVW(FGColumnVector3 tt) { vAeroUVW = tt; }
inline void Setalpha(double tt) { alpha = tt; }
inline void Setbeta (double tt) { beta = tt; }
inline void Setqbar (double tt) { qbar = tt; }
inline void SetqbarUW (double tt) { qbarUW = tt; }
inline void SetqbarUV (double tt) { qbarUV = tt; }
inline void SetVt (double tt) { Vt = tt; }
inline void SetMach (double tt) { Mach=tt; }
inline void Setadot (double tt) { adot = tt; }
inline void Setbdot (double tt) { bdot = tt; }
inline void SetAB(double t1, double t2) { alpha=t1; beta=t2; }
bool Run(void);
void bind(void);
void unbind(void);
private:
FGColumnVector3 vUVW;
FGColumnVector3 vUVWdot;
FGColumnVector3 vUVWdot_prev[4];
FGColumnVector3 vAeroUVW;
FGColumnVector3 vMachUVW;
double Vt, Mach;
double qbar, qbarUW, qbarUV;
double alpha, beta;
double adot,bdot;
void Debug(int from);
};
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#endif

View file

@ -242,6 +242,10 @@ bool FGTrim::DoTrim(void) {
} }
fdmex->GetOutput()->Disable(); fdmex->GetOutput()->Disable();
fgic->SetPRadpsIC(0.0);
fgic->SetQRadpsIC(0.0);
fgic->SetRRadpsIC(0.0);
//clear the sub iterations counts & zero out the controls //clear the sub iterations counts & zero out the controls
for(current_axis=0;current_axis<TrimAxes.size();current_axis++) { for(current_axis=0;current_axis<TrimAxes.size();current_axis++) {
@ -557,7 +561,7 @@ void FGTrim::setupPullup() {
<< fgic->GetVtrueFpsIC() << endl; << fgic->GetVtrueFpsIC() << endl;
q=g*(targetNlf-cgamma)/fgic->GetVtrueFpsIC(); q=g*(targetNlf-cgamma)/fgic->GetVtrueFpsIC();
cout << targetNlf << ", " << q << endl; cout << targetNlf << ", " << q << endl;
fdmex->GetRotation()->SetPQR(0,q,0); fgic->SetQRadpsIC(q);
cout << "setPitchRateInPullup() complete" << endl; cout << "setPitchRateInPullup() complete" << endl;
} }
@ -593,13 +597,15 @@ void FGTrim::updateRates(void){
} else { } else {
p=q=r=0; p=q=r=0;
} }
fdmex->GetRotation()->SetPQR(p,q,r); fgic->SetPRadpsIC(p);
fgic->SetQRadpsIC(q);
fgic->SetRRadpsIC(r);
} else if( mode == tPullup && fabs(targetNlf-1) > 0.01) { } else if( mode == tPullup && fabs(targetNlf-1) > 0.01) {
float g,q,cgamma; float g,q,cgamma;
g=fdmex->GetInertial()->gravity(); g=fdmex->GetInertial()->gravity();
cgamma=cos(fgic->GetFlightPathAngleRadIC()); cgamma=cos(fgic->GetFlightPathAngleRadIC());
q=g*(targetNlf-cgamma)/fgic->GetVtrueFpsIC(); q=g*(targetNlf-cgamma)/fgic->GetVtrueFpsIC();
fdmex->GetRotation()->SetPQR(0,q,0); fgic->SetQRadpsIC(q);
} }
} }

View file

@ -1,33 +1,33 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Header: FGTrimAxis.cpp Header: FGTrimAxis.cpp
Author: Tony Peden Author: Tony Peden
Date started: 7/3/00 Date started: 7/3/00
--------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) --------- --------- Copyright (C) 1999 Anthony K. Peden (apeden@earthlink.net) ---------
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later Foundation; either version 2 of the License, or (at your option) any later
version. version.
This program is distributed in the hope that it will be useful, but WITHOUT This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details. details.
You should have received a copy of the GNU General Public License along with You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place - Suite 330, Boston, MA 02111-1307, USA. Place - Suite 330, Boston, MA 02111-1307, USA.
Further information about the GNU General Public License can also be found on Further information about the GNU General Public License can also be found on
the world wide web at http://www.gnu.org. the world wide web at http://www.gnu.org.
HISTORY HISTORY
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
7/3/00 TP Created 7/3/00 TP Created
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
@ -81,8 +81,8 @@ FGTrimAxis::FGTrimAxis(FGFDMExec* fdex, FGInitialCondition* ic, State st,
case tHmgt: tolerance = 0.01; break; case tHmgt: tolerance = 0.01; break;
case tNlf: state_target=1.0; tolerance = 1E-5; break; case tNlf: state_target=1.0; tolerance = 1E-5; break;
case tAll: break; case tAll: break;
} }
solver_eps=tolerance; solver_eps=tolerance;
switch(control) { switch(control) {
case tThrottle: case tThrottle:
@ -120,17 +120,17 @@ FGTrimAxis::FGTrimAxis(FGFDMExec* fdex, FGInitialCondition* ic, State st,
case tAltAGL: case tAltAGL:
control_min=0; control_min=0;
control_max=30; control_max=30;
control_value=fdmex->GetPosition()->GetDistanceAGL(); control_value=fdmex->GetPropagate()->GetDistanceAGL();
solver_eps=tolerance/100; solver_eps=tolerance/100;
break; break;
case tTheta: case tTheta:
control_min=fdmex->GetRotation()->Gettht() - 5*degtorad; control_min=fdmex->GetPropagate()->Gettht() - 5*degtorad;
control_max=fdmex->GetRotation()->Gettht() + 5*degtorad; control_max=fdmex->GetPropagate()->Gettht() + 5*degtorad;
state_convert=radtodeg; state_convert=radtodeg;
break; break;
case tPhi: case tPhi:
control_min=fdmex->GetRotation()->Getphi() - 30*degtorad; control_min=fdmex->GetPropagate()->Getphi() - 30*degtorad;
control_max=fdmex->GetRotation()->Getphi() + 30*degtorad; control_max=fdmex->GetPropagate()->Getphi() + 30*degtorad;
state_convert=radtodeg; state_convert=radtodeg;
control_convert=radtodeg; control_convert=radtodeg;
break; break;
@ -141,13 +141,13 @@ FGTrimAxis::FGTrimAxis(FGFDMExec* fdex, FGInitialCondition* ic, State st,
control_convert=radtodeg; control_convert=radtodeg;
break; break;
case tHeading: case tHeading:
control_min=fdmex->GetRotation()->Getpsi() - 30*degtorad; control_min=fdmex->GetPropagate()->Getpsi() - 30*degtorad;
control_max=fdmex->GetRotation()->Getpsi() + 30*degtorad; control_max=fdmex->GetPropagate()->Getpsi() + 30*degtorad;
state_convert=radtodeg; state_convert=radtodeg;
break; break;
} }
Debug(0); Debug(0);
} }
@ -162,12 +162,12 @@ FGTrimAxis::~FGTrimAxis(void)
void FGTrimAxis::getState(void) { void FGTrimAxis::getState(void) {
switch(state) { switch(state) {
case tUdot: state_value=fdmex->GetTranslation()->GetUVWdot(1)-state_target; break; case tUdot: state_value=fdmex->GetPropagate()->GetUVWdot(1)-state_target; break;
case tVdot: state_value=fdmex->GetTranslation()->GetUVWdot(2)-state_target; break; case tVdot: state_value=fdmex->GetPropagate()->GetUVWdot(2)-state_target; break;
case tWdot: state_value=fdmex->GetTranslation()->GetUVWdot(3)-state_target; break; case tWdot: state_value=fdmex->GetPropagate()->GetUVWdot(3)-state_target; break;
case tQdot: state_value=fdmex->GetRotation()->GetPQRdot(2)-state_target;break; case tQdot: state_value=fdmex->GetPropagate()->GetPQRdot(2)-state_target;break;
case tPdot: state_value=fdmex->GetRotation()->GetPQRdot(1)-state_target; break; case tPdot: state_value=fdmex->GetPropagate()->GetPQRdot(1)-state_target; break;
case tRdot: state_value=fdmex->GetRotation()->GetPQRdot(3)-state_target; break; case tRdot: state_value=fdmex->GetPropagate()->GetPQRdot(3)-state_target; break;
case tHmgt: state_value=computeHmgt()-state_target; break; case tHmgt: state_value=computeHmgt()-state_target; break;
case tNlf: state_value=fdmex->GetAircraft()->GetNlf()-state_target; break; case tNlf: state_value=fdmex->GetAircraft()->GetNlf()-state_target; break;
case tAll: break; case tAll: break;
@ -181,19 +181,19 @@ void FGTrimAxis::getState(void) {
void FGTrimAxis::getControl(void) { void FGTrimAxis::getControl(void) {
switch(control) { switch(control) {
case tThrottle: control_value=fdmex->GetFCS()->GetThrottleCmd(0); break; case tThrottle: control_value=fdmex->GetFCS()->GetThrottleCmd(0); break;
case tBeta: control_value=fdmex->GetTranslation()->Getalpha(); break; case tBeta: control_value=fdmex->GetAuxiliary()->Getalpha(); break;
case tAlpha: control_value=fdmex->GetTranslation()->Getbeta(); break; case tAlpha: control_value=fdmex->GetAuxiliary()->Getbeta(); break;
case tPitchTrim: control_value=fdmex->GetFCS() -> GetPitchTrimCmd(); break; case tPitchTrim: control_value=fdmex->GetFCS() -> GetPitchTrimCmd(); break;
case tElevator: control_value=fdmex->GetFCS() -> GetDeCmd(); break; case tElevator: control_value=fdmex->GetFCS() -> GetDeCmd(); break;
case tRollTrim: case tRollTrim:
case tAileron: control_value=fdmex->GetFCS() -> GetDaCmd(); break; case tAileron: control_value=fdmex->GetFCS() -> GetDaCmd(); break;
case tYawTrim: case tYawTrim:
case tRudder: control_value=fdmex->GetFCS() -> GetDrCmd(); break; case tRudder: control_value=fdmex->GetFCS() -> GetDrCmd(); break;
case tAltAGL: control_value=fdmex->GetPosition()->GetDistanceAGL();break; case tAltAGL: control_value=fdmex->GetPropagate()->GetDistanceAGL();break;
case tTheta: control_value=fdmex->GetRotation()->Gettht(); break; case tTheta: control_value=fdmex->GetPropagate()->Gettht(); break;
case tPhi: control_value=fdmex->GetRotation()->Getphi(); break; case tPhi: control_value=fdmex->GetPropagate()->Getphi(); break;
case tGamma: control_value=fdmex->GetPosition()->GetGamma();break; case tGamma: control_value=fdmex->GetAuxiliary()->GetGamma();break;
case tHeading: control_value=fdmex->GetRotation()->Getpsi(); break; case tHeading: control_value=fdmex->GetPropagate()->Getpsi(); break;
} }
} }
@ -201,10 +201,10 @@ void FGTrimAxis::getControl(void) {
double FGTrimAxis::computeHmgt(void) { double FGTrimAxis::computeHmgt(void) {
double diff; double diff;
diff = fdmex->GetRotation()->Getpsi() - diff = fdmex->GetPropagate()->Getpsi() -
fdmex->GetPosition()->GetGroundTrack(); fdmex->GetAuxiliary()->GetGroundTrack();
if( diff < -M_PI ) { if( diff < -M_PI ) {
return (diff + 2*M_PI); return (diff + 2*M_PI);
} else if( diff > M_PI ) { } else if( diff > M_PI ) {
@ -214,7 +214,7 @@ double FGTrimAxis::computeHmgt(void) {
} }
} }
/*****************************************************************************/ /*****************************************************************************/
@ -238,22 +238,22 @@ void FGTrimAxis::setControl(void) {
} }
/*****************************************************************************/ /*****************************************************************************/
// the aircraft center of rotation is no longer the cg once the gear // the aircraft center of rotation is no longer the cg once the gear
// contact the ground so the altitude needs to be changed when pitch // contact the ground so the altitude needs to be changed when pitch
// and roll angle are adjusted. Instead of attempting to calculate the // and roll angle are adjusted. Instead of attempting to calculate the
// new center of rotation, pick a gear unit as a reference and use its // new center of rotation, pick a gear unit as a reference and use its
// location vector to calculate the new height change. i.e. new altitude = // location vector to calculate the new height change. i.e. new altitude =
// earth z component of that vector (which is in body axes ) // earth z component of that vector (which is in body axes )
void FGTrimAxis::SetThetaOnGround(double ff) { void FGTrimAxis::SetThetaOnGround(double ff) {
int center,i,ref; int center,i,ref;
// favor an off-center unit so that the same one can be used for both // favor an off-center unit so that the same one can be used for both
// pitch and roll. An on-center unit is used (for pitch)if that's all // pitch and roll. An on-center unit is used (for pitch)if that's all
// that's in contact with the ground. // that's in contact with the ground.
i=0; ref=-1; center=-1; i=0; ref=-1; center=-1;
while( (ref < 0) && (i < fdmex->GetGroundReactions()->GetNumGearUnits()) ) { while( (ref < 0) && (i < fdmex->GetGroundReactions()->GetNumGearUnits()) ) {
@ -262,45 +262,47 @@ void FGTrimAxis::SetThetaOnGround(double ff) {
ref=i; ref=i;
else else
center=i; center=i;
} }
i++; i++;
} }
if((ref < 0) && (center >= 0)) { if((ref < 0) && (center >= 0)) {
ref=center; ref=center;
} }
cout << "SetThetaOnGround ref gear: " << ref << endl; cout << "SetThetaOnGround ref gear: " << ref << endl;
if(ref >= 0) { if(ref >= 0) {
double sp=fdmex->GetRotation()->GetSinphi(); double sp = fdmex->GetPropagate()->GetSinphi();
double cp=fdmex->GetRotation()->GetCosphi(); double cp = fdmex->GetPropagate()->GetCosphi();
double lx=fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(1); double lx = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(1);
double ly=fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(2); double ly = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(2);
double lz=fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(3); double lz = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(3);
double hagl = -1*lx*sin(ff) + double hagl = -1*lx*sin(ff) +
ly*sp*cos(ff) + ly*sp*cos(ff) +
lz*cp*cos(ff); lz*cp*cos(ff);
fgic->SetAltitudeAGLFtIC(hagl); fgic->SetAltitudeAGLFtIC(hagl);
cout << "SetThetaOnGround new alt: " << hagl << endl; cout << "SetThetaOnGround new alt: " << hagl << endl;
} }
fgic->SetPitchAngleRadIC(ff); fgic->SetPitchAngleRadIC(ff);
cout << "SetThetaOnGround new theta: " << ff << endl; cout << "SetThetaOnGround new theta: " << ff << endl;
} }
/*****************************************************************************/ /*****************************************************************************/
bool FGTrimAxis::initTheta(void) { bool FGTrimAxis::initTheta(void) {
int i,N,iAft, iForward; int i,N;
double zAft,zForward,zDiff,theta; int iForward = 0;
int iAft = 1;
double zAft,zForward,zDiff,theta;
double xAft,xForward,xDiff; double xAft,xForward,xDiff;
bool level; bool level;
double saveAlt; double saveAlt;
saveAlt=fgic->GetAltitudeAGLFtIC(); saveAlt=fgic->GetAltitudeAGLFtIC();
fgic->SetAltitudeAGLFtIC(100); fgic->SetAltitudeAGLFtIC(100);
N=fdmex->GetGroundReactions()->GetNumGearUnits(); N=fdmex->GetGroundReactions()->GetNumGearUnits();
//find the first wheel unit forward of the cg //find the first wheel unit forward of the cg
//the list is short so a simple linear search is fine //the list is short so a simple linear search is fine
for( i=0; i<N; i++ ) { for( i=0; i<N; i++ ) {
@ -316,48 +318,43 @@ bool FGTrimAxis::initTheta(void) {
break; break;
} }
} }
// now adjust theta till the wheels are the same distance from the ground
xAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(1);
xForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(1);
xDiff = xForward - xAft;
zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
zDiff = zForward - zAft;
level=false;
theta=fgic->GetPitchAngleDegIC();
while(!level && (i < 100)) {
theta+=180.0/M_PI*zDiff/fabs(xDiff);
fgic->SetPitchAngleDegIC(theta);
fdmex->RunIC();
xAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(1);
xForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(1);
xDiff = xForward - xAft;
zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
zDiff = zForward - zAft;
// now adjust theta till the wheels are the same distance from the ground
xAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetBodyLocation(1);
xForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetBodyLocation(1);
xDiff = xForward - xAft;
zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
zDiff = zForward - zAft;
level=false;
theta=fgic->GetPitchAngleDegIC();
while(!level && (i < 100)) {
theta+=radtodeg*atan(zDiff/xDiff);
fgic->SetPitchAngleDegIC(theta);
fdmex->RunIC();
zAft=fdmex->GetGroundReactions()->GetGearUnit(iAft)->GetLocalGear(3);
zForward=fdmex->GetGroundReactions()->GetGearUnit(iForward)->GetLocalGear(3);
zDiff = zForward - zAft; zDiff = zForward - zAft;
//cout << endl << theta << " " << zDiff << endl; //cout << endl << theta << " " << zDiff << endl;
//cout << "0: " << fdmex->GetGroundReactions()->GetGearUnit(0)->GetLocalGear() << endl; //cout << "0: " << fdmex->GetGroundReactions()->GetGearUnit(0)->GetLocalGear() << endl;
//cout << "1: " << fdmex->GetGroundReactions()->GetGearUnit(1)->GetLocalGear() << endl; //cout << "1: " << fdmex->GetGroundReactions()->GetGearUnit(1)->GetLocalGear() << endl;
if(fabs(zDiff ) < 0.1) if(fabs(zDiff ) < 0.1)
level=true; level=true;
i++; i++;
} }
//cout << i << endl; //cout << i << endl;
if (debug_lvl > 0) { if (debug_lvl > 0) {
cout << " Initial Theta: " << fdmex->GetRotation()->Gettht()*radtodeg << endl; cout << " Initial Theta: " << fdmex->GetPropagate()->Gettht()*radtodeg << endl;
cout << " Used gear unit " << iAft << " as aft and " << iForward << " as forward" << endl; cout << " Used gear unit " << iAft << " as aft and " << iForward << " as forward" << endl;
} }
control_min=(theta+5)*degtorad; control_min=(theta+5)*degtorad;
control_max=(theta-5)*degtorad; control_max=(theta-5)*degtorad;
fgic->SetAltitudeAGLFtIC(saveAlt); fgic->SetAltitudeAGLFtIC(saveAlt);
if(i < 100) if(i < 100)
return true; return true;
else else
return false; return false;
} }
/*****************************************************************************/ /*****************************************************************************/
@ -365,28 +362,28 @@ void FGTrimAxis::SetPhiOnGround(double ff) {
int i,ref; int i,ref;
i=0; ref=-1; i=0; ref=-1;
//must have an off-center unit here //must have an off-center unit here
while( (ref < 0) && (i < fdmex->GetGroundReactions()->GetNumGearUnits()) ) { while ( (ref < 0) && (i < fdmex->GetGroundReactions()->GetNumGearUnits()) ) {
if( (fdmex->GetGroundReactions()->GetGearUnit(i)->GetWOW()) && if ( (fdmex->GetGroundReactions()->GetGearUnit(i)->GetWOW()) &&
(fabs(fdmex->GetGroundReactions()->GetGearUnit(i)->GetBodyLocation(2)) > 0.01)) (fabs(fdmex->GetGroundReactions()->GetGearUnit(i)->GetBodyLocation(2)) > 0.01))
ref=i; ref=i;
i++; i++;
} }
if(ref >= 0) { if (ref >= 0) {
double st=fdmex->GetRotation()->GetSintht(); double st = sin(fdmex->GetPropagate()->Gettht());
double ct=fdmex->GetRotation()->GetCostht(); double ct = cos(fdmex->GetPropagate()->Gettht());
double lx=fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(1); double lx = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(1);
double ly=fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(2); double ly = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(2);
double lz=fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(3); double lz = fdmex->GetGroundReactions()->GetGearUnit(ref)->GetBodyLocation(3);
double hagl = -1*lx*st + double hagl = -1*lx*st +
ly*sin(ff)*ct + ly*sin(ff)*ct +
lz*cos(ff)*ct; lz*cos(ff)*ct;
fgic->SetAltitudeAGLFtIC(hagl); fgic->SetAltitudeAGLFtIC(hagl);
} }
fgic->SetRollAngleRadIC(ff); fgic->SetRollAngleRadIC(ff);
} }
/*****************************************************************************/ /*****************************************************************************/
@ -432,11 +429,11 @@ void FGTrimAxis::setThrottlesPct(void) {
/*****************************************************************************/ /*****************************************************************************/
void FGTrimAxis::AxisReport(void) { void FGTrimAxis::AxisReport(void) {
char out[80]; char out[80];
sprintf(out," %20s: %6.2f %5s: %9.2e Tolerance: %3.0e\n", sprintf(out," %20s: %6.2f %5s: %9.2e Tolerance: %3.0e\n",
GetControlName().c_str(), GetControl()*control_convert, GetControlName().c_str(), GetControl()*control_convert,
GetStateName().c_str(), GetState()+state_target, GetTolerance()); GetStateName().c_str(), GetState()+state_target, GetTolerance());
cout << out; cout << out;
} }

View file

@ -1,11 +1,11 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Module: FGTurbine.cpp Module: FGTurbine.cpp
Author: Jon S. Berndt Author: David Culp
Date started: 08/23/2002 Date started: 03/11/2003
Purpose: This module models a turbine engine. Purpose: This module models a turbine engine.
------------- Copyright (C) 2002 Jon S. Berndt (jsb@hal-pc.org) -------------- ------------- Copyright (C) 2003 David Culp (davidculp2@comcast.net) ---------
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
@ -27,20 +27,22 @@
FUNCTIONAL DESCRIPTION FUNCTIONAL DESCRIPTION
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
This class descends from the FGEngine class and models a Turbine engine based This class descends from the FGEngine class and models a turbine engine based
on parameters given in the engine config file for this class on parameters given in the engine config file for this class
HISTORY HISTORY
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
08/23/2002 JSB Created 03/11/2003 DPC Created
09/08/2003 DPC Changed Calculate() and added engine phases
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
INCLUDES INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include <vector> #include <vector>
#include "FGTurbine.h" #include <sstream>
#include "FGTurbine.h"
namespace JSBSim { namespace JSBSim {
@ -54,8 +56,9 @@ CLASS IMPLEMENTATION
FGTurbine::FGTurbine(FGFDMExec* exec, FGConfigFile* cfg) : FGEngine(exec) FGTurbine::FGTurbine(FGFDMExec* exec, FGConfigFile* cfg) : FGEngine(exec)
{ {
SetDefaults();
Load(cfg); Load(cfg);
PowerCommand=0;
Debug(0); Debug(0);
} }
@ -67,147 +70,367 @@ FGTurbine::~FGTurbine()
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The main purpose of Calculate() is to determine what phase the engine should
// be in, then call the corresponding function.
double FGTurbine::Calculate(double dummy) double FGTurbine::Calculate(void)
{ {
double idle,mil,aug; TAT = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556;
double throttle=FCS->GetThrottlePos(EngineNumber); dt = State->Getdt() * Propulsion->GetRate();
double dt=State->Getdt(); ThrottlePos = FCS->GetThrottlePos(EngineNumber);
if( dt > 0 ) { if (ThrottlePos > 1.0) {
PowerCommand+=dt*PowerLag( PowerCommand, AugmentCmd = ThrottlePos - 1.0;
ThrottleToPowerCommand(throttle) ); ThrottlePos -= AugmentCmd;
if(PowerCommand > 100 )
PowerCommand=100;
else if(PowerCommand < 0 )
PowerCommand=0;
} else { } else {
PowerCommand=ThrottleToPowerCommand(throttle); AugmentCmd = 0.0;
}
mil=MaxMilThrust*ThrustTables[1]->TotalValue();
if( PowerCommand <= 50 ) {
idle=MaxMilThrust*ThrustTables[0]->TotalValue();
Thrust = idle + (mil-idle)*PowerCommand*0.02;
} else {
aug=MaxAugThrust*ThrustTables[2]->TotalValue();
Thrust = mil + (aug-mil)*(PowerCommand-50)*0.02;
}
ConsumeFuel();
return Thrust;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGTurbine::ThrottleToPowerCommand(double throttle) {
if( throttle <= 0.77 )
return 64.94*throttle;
else
return 217.38*throttle - 117.38;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGTurbine::PowerLag(double actual_power, double power_command) {
double t, p2;
if( power_command >= 50 ) {
if( actual_power >= 50 ) {
t=5;
p2=power_command;
} else {
p2=60;
t=rtau(p2-actual_power);
}
} else {
if( actual_power >= 50 ) {
t=5;
p2=40;
} else {
p2=power_command;
t=rtau(p2-actual_power);
}
} }
return t*(p2-actual_power);
} // When trimming is finished check if user wants engine OFF or RUNNING
if ((phase == tpTrim) && (dt > 0)) {
if (Running && !Starved) {
phase = tpRun;
N2 = IdleN2 + ThrottlePos * N2_factor;
N1 = IdleN1 + ThrottlePos * N1_factor;
OilTemp_degK = 366.0;
Cutoff = false;
}
else {
phase = tpOff;
Cutoff = true;
EGT_degC = TAT;
}
}
if (!Running && Cutoff && Starter) {
if (phase == tpOff) phase = tpSpinUp;
}
if (!Running && !Cutoff && (N2 > 15.0)) phase = tpStart;
if (Cutoff && (phase != tpSpinUp)) phase = tpOff;
if (dt == 0) phase = tpTrim;
if (Starved) phase = tpOff;
if (Stalled) phase = tpStall;
if (Seized) phase = tpSeize;
switch (phase) {
case tpOff: Thrust = Off(); break;
case tpRun: Thrust = Run(); break;
case tpSpinUp: Thrust = SpinUp(); break;
case tpStart: Thrust = Start(); break;
case tpStall: Thrust = Stall(); break;
case tpSeize: Thrust = Seize(); break;
case tpTrim: Thrust = Trim(); break;
default: Thrust = Off();
}
return Thruster->Calculate(Thrust);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGTurbine::rtau(double delta_power) { double FGTurbine::Off(void)
if( delta_power <= 25 ) {
return 1.0; double qbar = Auxiliary->Getqbar();
else if ( delta_power >= 50) Running = false;
return 0.1; FuelFlow_pph = Seek(&FuelFlow_pph, 0, 1000.0, 10000.0);
N1 = Seek(&N1, qbar/10.0, N1/2.0, N1/2.0);
N2 = Seek(&N2, qbar/15.0, N2/2.0, N2/2.0);
EGT_degC = Seek(&EGT_degC, TAT, 11.7, 7.3);
OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0.2, 0.2);
OilPressure_psi = N2 * 0.62;
NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
EPR = Seek(&EPR, 1.0, 0.2, 0.2);
Augmentation = false;
return 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGTurbine::Run(void)
{
double idlethrust, milthrust, thrust;
double N2norm; // 0.0 = idle N2, 1.0 = maximum N2
idlethrust = MilThrust * ThrustTables[0]->TotalValue();
milthrust = (MilThrust - idlethrust) * ThrustTables[1]->TotalValue();
Running = true;
Starter = false;
N2 = Seek(&N2, IdleN2 + ThrottlePos * N2_factor, delay, delay * 3.0);
N1 = Seek(&N1, IdleN1 + ThrottlePos * N1_factor, delay, delay * 2.4);
N2norm = (N2 - IdleN2) / N2_factor;
thrust = idlethrust + (milthrust * N2norm * N2norm);
EGT_degC = TAT + 363.1 + ThrottlePos * 357.1;
OilPressure_psi = N2 * 0.62;
OilTemp_degK = Seek(&OilTemp_degK, 366.0, 1.2, 0.1);
if (!Augmentation) {
double correctedTSFC = TSFC + TSFC - (N2norm * TSFC);
FuelFlow_pph = Seek(&FuelFlow_pph, thrust * correctedTSFC, 1000.0, 100000);
if (FuelFlow_pph < IdleFF) FuelFlow_pph = IdleFF;
NozzlePosition = Seek(&NozzlePosition, 1.0 - N2norm, 0.8, 0.8);
thrust = thrust * (1.0 - BleedDemand);
EPR = 1.0 + thrust/MilThrust;
}
if (AugMethod == 1) {
if ((ThrottlePos > 0.99) && (N2 > 97.0)) {Augmentation = true;}
else {Augmentation = false;}
}
if ((Augmented == 1) && Augmentation && (AugMethod < 2)) {
thrust = MaxThrust * ThrustTables[2]->TotalValue();
FuelFlow_pph = Seek(&FuelFlow_pph, thrust * ATSFC, 5000.0, 10000.0);
NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
}
if ((AugmentCmd > 0.0) && (AugMethod == 2)) {
Augmentation = true;
double tdiff = (MaxThrust * ThrustTables[2]->TotalValue()) - thrust;
thrust += (tdiff * AugmentCmd);
FuelFlow_pph = Seek(&FuelFlow_pph, thrust * ATSFC, 5000.0, 10000.0);
NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
} else {
Augmentation = false;
}
if ((Injected == 1) && Injection)
thrust = thrust * ThrustTables[3]->TotalValue();
ConsumeFuel();
if (Cutoff) phase = tpOff;
if (Starved) phase = tpOff;
return thrust;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGTurbine::SpinUp(void)
{
Running = false;
FuelFlow_pph = 0.0;
N2 = Seek(&N2, 25.18, 3.0, N2/2.0);
N1 = Seek(&N1, 5.21, 1.0, N1/2.0);
EGT_degC = Seek(&EGT_degC, TAT, 11.7, 7.3);
OilPressure_psi = N2 * 0.62;
OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0.2, 0.2);
EPR = 1.0;
NozzlePosition = 1.0;
return 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGTurbine::Start(void)
{
if ((N2 > 15.0) && !Starved) { // minimum 15% N2 needed for start
Cranking = true; // provided for sound effects signal
if (N2 < IdleN2) {
N2 = Seek(&N2, IdleN2, 2.0, N2/2.0);
N1 = Seek(&N1, IdleN1, 1.4, N1/2.0);
EGT_degC = Seek(&EGT_degC, TAT + 363.1, 21.3, 7.3);
FuelFlow_pph = Seek(&FuelFlow_pph, IdleFF, 103.7, 103.7);
OilPressure_psi = N2 * 0.62;
}
else {
phase = tpRun;
Running = true;
Starter = false;
Cranking = false;
}
}
else { // no start if N2 < 15%
phase = tpOff;
Starter = false;
}
return 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGTurbine::Stall(void)
{
double qbar = Auxiliary->Getqbar();
EGT_degC = TAT + 903.14;
FuelFlow_pph = IdleFF;
N1 = Seek(&N1, qbar/10.0, 0, N1/10.0);
N2 = Seek(&N2, qbar/15.0, 0, N2/10.0);
if (ThrottlePos < 0.01) phase = tpRun; // clear the stall with throttle
return 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGTurbine::Seize(void)
{
double qbar = Auxiliary->Getqbar();
N2 = 0.0;
N1 = Seek(&N1, qbar/20.0, 0, N1/15.0);
FuelFlow_pph = IdleFF;
OilPressure_psi = 0.0;
OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0, 0.2);
Running = false;
return 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGTurbine::Trim(void)
{
double idlethrust, milthrust, thrust, tdiff;
idlethrust = MilThrust * ThrustTables[0]->TotalValue();
milthrust = (MilThrust - idlethrust) * ThrustTables[1]->TotalValue();
thrust = (idlethrust + (milthrust * ThrottlePos * ThrottlePos)) * (1.0 - BleedDemand);
if (AugmentCmd > 0.0) {
tdiff = (MaxThrust * ThrustTables[2]->TotalValue()) - thrust;
thrust += (tdiff * AugmentCmd);
}
return thrust;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGTurbine::CalcFuelNeed(void)
{
return FuelFlow_pph /3600 * State->Getdt() * Propulsion->GetRate();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGTurbine::GetPowerAvailable(void) {
if( ThrottlePos <= 0.77 )
return 64.94*ThrottlePos;
else else
return 1.9-0.036*delta_power; return 217.38*ThrottlePos - 117.38;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGTurbine::doInlet(void) double FGTurbine::Seek(double *var, double target, double accel, double decel) {
double v = *var;
if (v > target) {
v -= dt * decel;
if (v < target) v = target;
} else if (v < target) {
v += dt * accel;
if (v > target) v = target;
}
return v;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGTurbine::SetDefaults(void)
{ {
Name = "Not defined";
N1 = N2 = 0.0;
Type = etTurbine;
MilThrust = 10000.0;
MaxThrust = 10000.0;
BypassRatio = 0.0;
TSFC = 0.8;
ATSFC = 1.7;
IdleN1 = 30.0;
IdleN2 = 60.0;
MaxN1 = 100.0;
MaxN2 = 100.0;
Augmented = 0;
AugMethod = 0;
Injected = 0;
BleedDemand = 0.0;
ThrottlePos = 0.0;
AugmentCmd = 0.0;
InletPosition = 1.0;
NozzlePosition = 1.0;
Augmentation = false;
Injection = false;
Reversed = false;
Cutoff = true;
phase = tpOff;
Stalled = false;
Seized = false;
Overtemp = false;
Fire = false;
EGT_degC = 0.0;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGTurbine::doCompressor(void)
{
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGTurbine::doBleedDuct(void)
{
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGTurbine::doCombustor(void)
{
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGTurbine::doTurbine(void)
{
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGTurbine::doConvergingNozzle(void)
{
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
void FGTurbine::doTransition(void)
{
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
bool FGTurbine::Load(FGConfigFile *Eng_cfg) bool FGTurbine::Load(FGConfigFile *Eng_cfg)
{ {
int i;
string token; string token;
Name = Eng_cfg->GetValue("NAME"); Name = Eng_cfg->GetValue("NAME");
cout << Name << endl;
Eng_cfg->GetNextConfigLine(); Eng_cfg->GetNextConfigLine();
*Eng_cfg >> token >> MaxMilThrust; int counter=0;
*Eng_cfg >> token >> MaxAugThrust;
i=0; while ( ((token = Eng_cfg->GetValue()) != string("/FG_TURBINE")) &&
while( Eng_cfg->GetValue() != string("/FG_TURBINE") && i < 10){ (token != string("/FG_SIMTURBINE")) ) {
ThrustTables.push_back( new FGCoefficient(FDMExec) ); *Eng_cfg >> token;
ThrustTables.back()->Load(Eng_cfg);
i++; if (token[0] == '<') token.erase(0,1); // Tables are read "<TABLE"
if (token == "MILTHRUST") *Eng_cfg >> MilThrust;
else if (token == "MAXTHRUST") *Eng_cfg >> MaxThrust;
else if (token == "BYPASSRATIO") *Eng_cfg >> BypassRatio;
else if (token == "BLEED") *Eng_cfg >> BleedDemand;
else if (token == "TSFC") *Eng_cfg >> TSFC;
else if (token == "ATSFC") *Eng_cfg >> ATSFC;
else if (token == "IDLEN1") *Eng_cfg >> IdleN1;
else if (token == "IDLEN2") *Eng_cfg >> IdleN2;
else if (token == "MAXN1") *Eng_cfg >> MaxN1;
else if (token == "MAXN2") *Eng_cfg >> MaxN2;
else if (token == "AUGMENTED") *Eng_cfg >> Augmented;
else if (token == "AUGMETHOD") *Eng_cfg >> AugMethod;
else if (token == "INJECTED") *Eng_cfg >> Injected;
else if (token == "MINTHROTTLE") *Eng_cfg >> MinThrottle;
else if (token == "TABLE") {
if (counter++ == 0) Debug(2); // print engine specs prior to table read
ThrustTables.push_back( new FGCoefficient(FDMExec) );
ThrustTables.back()->Load(Eng_cfg);
}
else cerr << "Unhandled token in Engine config file: " << token << endl;
} }
// Pre-calculations and initializations
delay = 60.0 / (BypassRatio + 3.0);
N1_factor = MaxN1 - IdleN1;
N2_factor = MaxN2 - IdleN2;
OilTemp_degK = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556 + 273.0;
IdleFF = pow(MilThrust, 0.2) * 107.0; // just an estimate
return true; return true;
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGTurbine::GetEngineLabels(void)
{
std::ostringstream buf;
buf << Name << "_N1[" << EngineNumber << "], "
<< Name << "_N2[" << EngineNumber << "], "
<< Thruster->GetThrusterLabels(EngineNumber);
return buf.str();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
string FGTurbine::GetEngineValues(void)
{
std::ostringstream buf;
buf << N1 << ", "
<< N2 << ", "
<< Thruster->GetThrusterValues(EngineNumber);
return buf.str();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
// The bitmasked value choices are as follows: // The bitmasked value choices are as follows:
// unset: In this case (the default) JSBSim would only print // unset: In this case (the default) JSBSim would only print
@ -235,6 +458,24 @@ void FGTurbine::Debug(int from)
if (from == 0) { // Constructor if (from == 0) { // Constructor
} }
if (from == 2) { // called from Load()
cout << "\n Engine Name: " << Name << endl;
cout << " MilThrust: " << MilThrust << endl;
cout << " MaxThrust: " << MaxThrust << endl;
cout << " BypassRatio: " << BypassRatio << endl;
cout << " TSFC: " << TSFC << endl;
cout << " ATSFC: " << ATSFC << endl;
cout << " IdleN1: " << IdleN1 << endl;
cout << " IdleN2: " << IdleN2 << endl;
cout << " MaxN1: " << MaxN1 << endl;
cout << " MaxN2: " << MaxN2 << endl;
cout << " Augmented: " << Augmented << endl;
cout << " AugMethod: " << AugMethod << endl;
cout << " Injected: " << Injected << endl;
cout << " MinThrottle: " << MinThrottle << endl;
cout << endl;
}
} }
if (debug_lvl & 2 ) { // Instantiation/Destruction notification if (debug_lvl & 2 ) { // Instantiation/Destruction notification
if (from == 0) cout << "Instantiated: FGTurbine" << endl; if (from == 0) cout << "Instantiated: FGTurbine" << endl;

View file

@ -1,10 +1,10 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Header: FGTurbine.h Header: FGTurbine.h
Author: Jon S. Berndt Author: David Culp
Date started: 08/23/2002 Date started: 03/11/2003
------------- Copyright (C) 2002 Jon S. Berndt (jsb@hal-pc.org) -------------- ------------- Copyright (C) 2003 David Culp (davidculp2@comcast.net)----------
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software the terms of the GNU General Public License as published by the Free Software
@ -25,7 +25,9 @@
HISTORY HISTORY
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
08/23/2002 JSB Created 03/11/2003 DPC Created, based on FGTurbine
09/22/2003 DPC Added starting, stopping, new framework
04/29/2004 DPC Renamed from FGSimTurbine to FGTurbine
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
SENTRY SENTRY
@ -51,6 +53,83 @@ FORWARD DECLARATIONS
namespace JSBSim { namespace JSBSim {
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DOCUMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
/** This class models a turbine engine. Based on Jon Berndt's FGTurbine module.
Here the term "phase" signifies the engine's mode of operation. At any given
time the engine is in only one phase. At simulator startup the engine will be
placed in the Trim phase in order to provide a simplified thrust value without
throttle lag. When trimming is complete the engine will go to the Off phase,
unless the value FGEngine::Running has been previously set to true, in which
case the engine will go to the Run phase. Once an engine is in the Off phase
the full starting procedure (or airstart) must be used to get it running.
<P>
- STARTING (on ground):
-# Set the control FGEngine::Starter to true. The engine will spin up to
a maximum of about %25 N2 (%5.2 N1). This simulates the action of a
pneumatic starter.
-# After reaching %15 N2 set the control FGEngine::Cutoff to false. If fuel
is available the engine will now accelerate to idle. The starter will
automatically be set to false after the start cycle.
<P>
- STARTING (in air):
-# Increase speed to obtain a minimum of %15 N2. If this is not possible,
the starter may be used to assist.
-# Place the control FGEngine::Cutoff to false.
<P>
Ignition is assumed to be on anytime the Cutoff control is set to false,
therefore a seperate ignition system is not modeled.
Configuration File Format
<pre>
\<FG_TURBINE NAME="<name>">
MILTHRUST \<thrust>
MAXTHRUST \<thrust>
BYPASSRATIO \<bypass ratio>
TSFC \<thrust specific fuel consumption>
ATSFC \<afterburning thrust specific fuel consumption>
IDLEN1 \<idle N1>
IDLEN2 \<idle N2>
MAXN1 \<max N1>
MAXN2 \<max N2>
AUGMENTED \<0|1>
AUGMETHOD \<0|1>
INJECTED \<0|1>
...
\</FG_TURBINE>
</pre>
Definition of the turbine engine configuration file parameters:
<pre>
<b>MILTHRUST</b> - Maximum thrust, static, at sea level, lbf.
<b>MAXTHRUST</b> - Afterburning thrust, static, at sea level, lbf
[this value will be ignored when AUGMENTED is zero (false)].
<b>BYPASSRATIO</b> - Ratio of bypass air flow to core air flow.
<b>TSFC</b> - Thrust-specific fuel consumption, lbm/hr/lbf
[i.e. fuel flow divided by thrust].
<b>ATSFC</b> - Afterburning TSFC, lbm/hr/lbf
[this value will be ignored when AUGMENTED is zero (false)]
<b>IDLEN1</b> - Fan rotor rpm (% of max) at idle
<b>IDLEN2</b> - Core rotor rpm (% of max) at idle
<b>MAXN1</b> - Fan rotor rpm (% of max) at full throttle [not always 100!]
<b>MAXN2</b> - Core rotor rpm (% of max) at full throttle [not always 100!]
<b>AUGMENTED</b>
0 == afterburner not installed
1 == afterburner installed
<b>AUGMETHOD</b>
0 == afterburner activated by property /engines/engine[n]/augmentation
1 == afterburner activated by pushing throttle above 99% position
2 == throttle range is expanded in the FCS, and values above 1.0 are afterburner range
[this item will be ignored when AUGMENTED == 0]
<b>INJECTED</b>
0 == Water injection not installed
1 == Water injection installed
</pre>
@author David P. Culp
@version "$Id$"
*/
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS DECLARATION CLASS DECLARATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
@ -58,38 +137,112 @@ CLASS DECLARATION
class FGTurbine : public FGEngine class FGTurbine : public FGEngine
{ {
public: public:
FGTurbine(FGFDMExec* exec, FGConfigFile* Eng_cfg); /** Constructor
@param Executive pointer to executive structure
@param Eng_cfg pointer to engine config file instance */
FGTurbine(FGFDMExec* Executive, FGConfigFile* Eng_cfg);
/// Destructor
~FGTurbine(); ~FGTurbine();
double Calculate(double); enum phaseType { tpOff, tpRun, tpSpinUp, tpStart, tpStall, tpSeize, tpTrim };
double GetPowerAvailable(void) { return PowerCommand; }
double Calculate(void);
double CalcFuelNeed(void);
double GetPowerAvailable(void);
double Seek(double* var, double target, double accel, double decel);
phaseType GetPhase(void) { return phase; }
bool GetOvertemp(void) {return Overtemp; }
bool GetInjection(void) {return Injection;}
bool GetFire(void) { return Fire; }
bool GetAugmentation(void) {return Augmentation;}
bool GetReversed(void) { return Reversed; }
bool GetCutoff(void) { return Cutoff; }
int GetIgnition(void) {return Ignition;}
double GetInlet(void) { return InletPosition; }
double GetNozzle(void) { return NozzlePosition; }
double GetBleedDemand(void) {return BleedDemand;}
double GetN1(void) {return N1;}
double GetN2(void) {return N2;}
double GetEPR(void) {return EPR;}
double GetEGT(void) {return EGT_degC;}
double getOilPressure_psi () const {return OilPressure_psi;}
double getOilTemp_degF (void) {return KelvinToFahrenheit(OilTemp_degK);}
void SetInjection(bool injection) {Injection = injection;}
void SetIgnition(int ignition) {Ignition = ignition;}
void SetAugmentation(bool augmentation) {Augmentation = augmentation;}
void SetPhase( phaseType p ) { phase = p; }
void SetEPR(double epr) {EPR = epr;}
void SetBleedDemand(double bleedDemand) {BleedDemand = bleedDemand;}
void SetReverse(bool reversed) { Reversed = reversed; }
void SetCutoff(bool cutoff) { Cutoff = cutoff; }
string GetEngineLabels(void);
string GetEngineValues(void);
private: private:
typedef vector<FGCoefficient*> CoeffArray; typedef vector<FGCoefficient*> CoeffArray;
CoeffArray ThrustTables; CoeffArray ThrustTables;
string name; phaseType phase; ///< Operating mode, or "phase"
double MaxMilThrust; double MilThrust; ///< Maximum Unaugmented Thrust, static @ S.L. (lbf)
double MaxAugThrust; double MaxThrust; ///< Maximum Augmented Thrust, static @ S.L. (lbf)
double BypassRatio; ///< Bypass Ratio
double PowerCommand; double TSFC; ///< Thrust Specific Fuel Consumption (lbm/hr/lbf)
double ATSFC; ///< Augmented TSFC (lbm/hr/lbf)
double ThrottleToPowerCommand(double throttle); double IdleN1; ///< Idle N1
double PowerLag(double actual_power, double power_command); double IdleN2; ///< Idle N2
double rtau(double delta_power); double N1; ///< N1
double N2; ///< N2
double MaxN1; ///< N1 at 100% throttle
double MaxN2; ///< N2 at 100% throttle
double IdleFF; ///< Idle Fuel Flow (lbm/hr)
double delay; ///< Inverse spool-up time from idle to 100% (seconds)
double dt; ///< Simulator time slice
double N1_factor; ///< factor to tie N1 and throttle
double N2_factor; ///< factor to tie N2 and throttle
double ThrottlePos; ///< FCS-supplied throttle position
double AugmentCmd; ///< modulated afterburner command (0.0 to 1.0)
double TAT; ///< total air temperature (deg C)
bool Stalled; ///< true if engine is compressor-stalled
bool Seized; ///< true if inner spool is seized
bool Overtemp; ///< true if EGT exceeds limits
bool Fire; ///< true if engine fire detected
bool Injection;
bool Augmentation;
bool Reversed;
bool Cutoff;
int Injected; ///< = 1 if water injection installed
int Ignition;
int Augmented; ///< = 1 if augmentation installed
int AugMethod; ///< = 0 if using property /engine[n]/augmentation
///< = 1 if using last 1% of throttle movement
///< = 2 if using FCS-defined throttle
double EGT_degC;
double EPR;
double OilPressure_psi;
double OilTemp_degK;
double BleedDemand;
double InletPosition;
double NozzlePosition;
void doInlet(void); double Off(void);
void doCompressor(void); double Run(void);
void doBleedDuct(void); double SpinUp(void);
void doCombustor(void); double Start(void);
void doTurbine(void); double Stall(void);
void doConvergingNozzle(void); double Seize(void);
double Trim(void);
void doTransition(void);
void SetDefaults(void);
bool Load(FGConfigFile *ENG_cfg); bool Load(FGConfigFile *ENG_cfg);
void Debug(int from); void Debug(int from);
}; };
} }
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

View file

@ -49,10 +49,8 @@
#include <FDM/JSBSim/FGFDMExec.h> #include <FDM/JSBSim/FGFDMExec.h>
#include <FDM/JSBSim/FGAircraft.h> #include <FDM/JSBSim/FGAircraft.h>
#include <FDM/JSBSim/FGFCS.h> #include <FDM/JSBSim/FGFCS.h>
#include <FDM/JSBSim/FGPosition.h> #include <FDM/JSBSim/FGPropagate.h>
#include <FDM/JSBSim/FGRotation.h>
#include <FDM/JSBSim/FGState.h> #include <FDM/JSBSim/FGState.h>
#include <FDM/JSBSim/FGTranslation.h>
#include <FDM/JSBSim/FGAuxiliary.h> #include <FDM/JSBSim/FGAuxiliary.h>
#include <FDM/JSBSim/FGInitialCondition.h> #include <FDM/JSBSim/FGInitialCondition.h>
#include <FDM/JSBSim/FGTrim.h> #include <FDM/JSBSim/FGTrim.h>
@ -63,11 +61,13 @@
#include <FDM/JSBSim/FGPropertyManager.h> #include <FDM/JSBSim/FGPropertyManager.h>
#include <FDM/JSBSim/FGEngine.h> #include <FDM/JSBSim/FGEngine.h>
#include <FDM/JSBSim/FGPiston.h> #include <FDM/JSBSim/FGPiston.h>
#include <FDM/JSBSim/FGSimTurbine.h> #include <FDM/JSBSim/FGTurbine.h>
#include <FDM/JSBSim/FGRocket.h> #include <FDM/JSBSim/FGRocket.h>
#include <FDM/JSBSim/FGElectric.h>
#include <FDM/JSBSim/FGNozzle.h> #include <FDM/JSBSim/FGNozzle.h>
#include <FDM/JSBSim/FGPropeller.h> #include <FDM/JSBSim/FGPropeller.h>
#include <FDM/JSBSim/FGRotor.h> #include <FDM/JSBSim/FGRotor.h>
#include <FDM/JSBSim/FGTank.h>
#include "JSBSim.hxx" #include "JSBSim.hxx"
static inline double static inline double
@ -117,9 +117,7 @@ FGJSBsim::FGJSBsim( double dt )
MassBalance = fdmex->GetMassBalance(); MassBalance = fdmex->GetMassBalance();
Propulsion = fdmex->GetPropulsion(); Propulsion = fdmex->GetPropulsion();
Aircraft = fdmex->GetAircraft(); Aircraft = fdmex->GetAircraft();
Translation = fdmex->GetTranslation(); Propagate = fdmex->GetPropagate();
Rotation = fdmex->GetRotation();
Position = fdmex->GetPosition();
Auxiliary = fdmex->GetAuxiliary(); Auxiliary = fdmex->GetAuxiliary();
Aerodynamics = fdmex->GetAerodynamics(); Aerodynamics = fdmex->GetAerodynamics();
GroundReactions = fdmex->GetGroundReactions(); GroundReactions = fdmex->GetGroundReactions();
@ -127,10 +125,9 @@ FGJSBsim::FGJSBsim( double dt )
fgic=fdmex->GetIC(); fgic=fdmex->GetIC();
needTrim=true; needTrim=true;
SGPath aircraft_path( globals->get_fg_root() ); SGPath aircraft_path( fgGetString("/sim/aircraft-dir") );
aircraft_path.append( "Aircraft" );
SGPath engine_path( globals->get_fg_root() ); SGPath engine_path( fgGetString("/sim/aircraft-dir") );
engine_path.append( "Engine" ); engine_path.append( "Engine" );
State->Setdt( dt ); State->Setdt( dt );
@ -157,9 +154,9 @@ FGJSBsim::FGJSBsim( double dt )
SG_LOG( SG_FLIGHT, SG_ALERT, "num gear units = " SG_LOG( SG_FLIGHT, SG_ALERT, "num gear units = "
<< GroundReactions->GetNumGearUnits() ); << GroundReactions->GetNumGearUnits() );
SG_LOG( SG_FLIGHT, SG_ALERT, "This is a very bad thing because with 0 gear units, the ground trimming"); SG_LOG( SG_FLIGHT, SG_ALERT, "This is a very bad thing because with 0 gear units, the ground trimming");
SG_LOG( SG_FLIGHT, SG_ALERT, "routine (coming up later in the code) will core dump."); SG_LOG( SG_FLIGHT, SG_ALERT, "routine (coming up later in the code) will core dump.");
SG_LOG( SG_FLIGHT, SG_ALERT, "Halting the sim now, and hoping a solution will present itself soon!"); SG_LOG( SG_FLIGHT, SG_ALERT, "Halting the sim now, and hoping a solution will present itself soon!");
exit(-1); exit(-1);
} }
init_gear(); init_gear();
@ -225,8 +222,8 @@ FGJSBsim::FGJSBsim( double dt )
for (unsigned int i = 0; i < Propulsion->GetNumEngines(); i++) { for (unsigned int i = 0; i < Propulsion->GetNumEngines(); i++) {
SGPropertyNode * node = fgGetNode("engines/engine", i, true); SGPropertyNode * node = fgGetNode("engines/engine", i, true);
Propulsion->GetThruster(i)->SetRPM(node->getDoubleValue("rpm") / Propulsion->GetEngine(i)->GetThruster()->SetRPM(node->getDoubleValue("rpm") /
Propulsion->GetThruster(i)->GetGearRatio()); Propulsion->GetEngine(i)->GetThruster()->GetGearRatio());
} }
} }
@ -250,6 +247,9 @@ void FGJSBsim::init()
// Explicitly call the superclass's // Explicitly call the superclass's
// init method first. // init method first.
#ifdef FG_WEATHERCM
Atmosphere->UseInternal();
#else
if (fgGetBool("/environment/params/control-fdm-atmosphere")) { if (fgGetBool("/environment/params/control-fdm-atmosphere")) {
Atmosphere->UseExternal(); Atmosphere->UseExternal();
Atmosphere->SetExTemperature( Atmosphere->SetExTemperature(
@ -266,6 +266,7 @@ void FGJSBsim::init()
} else { } else {
Atmosphere->UseInternal(); Atmosphere->UseInternal();
} }
#endif
fgic->SetVnorthFpsIC( wind_from_north->getDoubleValue() ); fgic->SetVnorthFpsIC( wind_from_north->getDoubleValue() );
fgic->SetVeastFpsIC( wind_from_east->getDoubleValue() ); fgic->SetVeastFpsIC( wind_from_east->getDoubleValue() );
@ -289,19 +290,19 @@ void FGJSBsim::init()
switch(fgic->GetSpeedSet()) { switch(fgic->GetSpeedSet()) {
case setned: case setned:
SG_LOG(SG_FLIGHT,SG_INFO, " Vn,Ve,Vd= " SG_LOG(SG_FLIGHT,SG_INFO, " Vn,Ve,Vd= "
<< Position->GetVn() << ", " << Propagate->GetVel(eNorth) << ", "
<< Position->GetVe() << ", " << Propagate->GetVel(eEast) << ", "
<< Position->GetVd() << " ft/s"); << Propagate->GetVel(eDown) << " ft/s");
break; break;
case setuvw: case setuvw:
SG_LOG(SG_FLIGHT,SG_INFO, " U,V,W= " SG_LOG(SG_FLIGHT,SG_INFO, " U,V,W= "
<< Translation->GetUVW(1) << ", " << Propagate->GetUVW(1) << ", "
<< Translation->GetUVW(2) << ", " << Propagate->GetUVW(2) << ", "
<< Translation->GetUVW(3) << " ft/s"); << Propagate->GetUVW(3) << " ft/s");
break; break;
case setmach: case setmach:
SG_LOG(SG_FLIGHT,SG_INFO, " Mach: " SG_LOG(SG_FLIGHT,SG_INFO, " Mach: "
<< Translation->GetMach() ); << Auxiliary->GetMach() );
break; break;
case setvc: case setvc:
default: default:
@ -313,17 +314,17 @@ void FGJSBsim::init()
stall_warning->setDoubleValue(0); stall_warning->setDoubleValue(0);
SG_LOG( SG_FLIGHT, SG_INFO, " Bank Angle: " SG_LOG( SG_FLIGHT, SG_INFO, " Bank Angle: "
<< Rotation->Getphi()*RADTODEG << " deg" ); << Propagate->Getphi()*RADTODEG << " deg" );
SG_LOG( SG_FLIGHT, SG_INFO, " Pitch Angle: " SG_LOG( SG_FLIGHT, SG_INFO, " Pitch Angle: "
<< Rotation->Gettht()*RADTODEG << " deg" ); << Propagate->Gettht()*RADTODEG << " deg" );
SG_LOG( SG_FLIGHT, SG_INFO, " True Heading: " SG_LOG( SG_FLIGHT, SG_INFO, " True Heading: "
<< Rotation->Getpsi()*RADTODEG << " deg" ); << Propagate->Getpsi()*RADTODEG << " deg" );
SG_LOG( SG_FLIGHT, SG_INFO, " Latitude: " SG_LOG( SG_FLIGHT, SG_INFO, " Latitude: "
<< Position->GetLatitude() << " deg" ); << Propagate->GetLocation().GetLatitudeDeg() << " deg" );
SG_LOG( SG_FLIGHT, SG_INFO, " Longitude: " SG_LOG( SG_FLIGHT, SG_INFO, " Longitude: "
<< Position->GetLongitude() << " deg" ); << Propagate->GetLocation().GetLongitudeDeg() << " deg" );
SG_LOG( SG_FLIGHT, SG_INFO, " Altitude: " SG_LOG( SG_FLIGHT, SG_INFO, " Altitude: "
<< Position->Geth() << " feet" ); << Propagate->Geth() << " feet" );
SG_LOG( SG_FLIGHT, SG_INFO, " loaded initial conditions" ); SG_LOG( SG_FLIGHT, SG_INFO, " loaded initial conditions" );
SG_LOG( SG_FLIGHT, SG_INFO, " set dt" ); SG_LOG( SG_FLIGHT, SG_INFO, " set dt" );
@ -441,16 +442,16 @@ bool FGJSBsim::copy_to_JSBsim()
eng->SetMagnetos( globals->get_controls()->get_magnetos(i) ); eng->SetMagnetos( globals->get_controls()->get_magnetos(i) );
break; break;
} // end FGPiston code block } // end FGPiston code block
case FGEngine::etSimTurbine: case FGEngine::etTurbine:
{ // FGSimTurbine code block { // FGTurbine code block
FGSimTurbine* eng = (FGSimTurbine*)Propulsion->GetEngine(i); FGTurbine* eng = (FGTurbine*)Propulsion->GetEngine(i);
eng->SetAugmentation( globals->get_controls()->get_augmentation(i) ); eng->SetAugmentation( globals->get_controls()->get_augmentation(i) );
eng->SetReverse( globals->get_controls()->get_reverser(i) ); eng->SetReverse( globals->get_controls()->get_reverser(i) );
eng->SetInjection( globals->get_controls()->get_water_injection(i) ); eng->SetInjection( globals->get_controls()->get_water_injection(i) );
eng->SetCutoff( globals->get_controls()->get_cutoff(i) ); eng->SetCutoff( globals->get_controls()->get_cutoff(i) );
eng->SetIgnition( globals->get_controls()->get_ignition(i) ); eng->SetIgnition( globals->get_controls()->get_ignition(i) );
break; break;
} // end FGSimTurbine code block } // end FGTurbine code block
case FGEngine::etRocket: case FGEngine::etRocket:
{ // FGRocket code block { // FGRocket code block
FGRocket* eng = (FGRocket*)Propulsion->GetEngine(i); FGRocket* eng = (FGRocket*)Propulsion->GetEngine(i);
@ -466,9 +467,10 @@ bool FGJSBsim::copy_to_JSBsim()
} // end FGEngine code block } // end FGEngine code block
} }
_set_Runway_altitude( cur_fdm_state->get_Runway_altitude() ); _set_Runway_altitude( cur_fdm_state->get_Runway_altitude() );
Position->SetSeaLevelRadius( get_Sea_level_radius() ); Propagate->SetSeaLevelRadius( get_Sea_level_radius() );
Position->SetRunwayRadius( get_Runway_altitude() Propagate->SetRunwayRadius( get_Runway_altitude()
+ get_Sea_level_radius() ); + get_Sea_level_radius() );
Atmosphere->SetExTemperature( Atmosphere->SetExTemperature(
@ -496,6 +498,8 @@ bool FGJSBsim::copy_to_JSBsim()
tank->SetContents(node->getDoubleValue("level-gal_us") * 6.6); tank->SetContents(node->getDoubleValue("level-gal_us") * 6.6);
// tank->SetContents(node->getDoubleValue("level-lb")); // tank->SetContents(node->getDoubleValue("level-lb"));
} }
SGPropertyNode* node = fgGetNode("/systems/refuel", true);
Propulsion->SetRefuel(node->getDoubleValue("contact"));
return true; return true;
} }
@ -534,72 +538,62 @@ bool FGJSBsim::copy_from_JSBsim()
// Velocities // Velocities
_set_Velocities_Local( Position->GetVn(), _set_Velocities_Local( Propagate->GetVel(eNorth),
Position->GetVe(), Propagate->GetVel(eEast),
Position->GetVd() ); Propagate->GetVel(eDown) );
_set_Velocities_Wind_Body( Translation->GetUVW(1), _set_Velocities_Wind_Body( Propagate->GetUVW(1),
Translation->GetUVW(2), Propagate->GetUVW(2),
Translation->GetUVW(3) ); Propagate->GetUVW(3) );
// Make the HUD work ... // Make the HUD work ...
_set_Velocities_Ground( Position->GetVn(), _set_Velocities_Ground( Propagate->GetVel(eNorth),
Position->GetVe(), Propagate->GetVel(eEast),
-Position->GetVd() ); -Propagate->GetVel(eDown) );
_set_V_rel_wind( Translation->GetVt() ); _set_V_rel_wind( Auxiliary->GetVt() );
_set_V_equiv_kts( Auxiliary->GetVequivalentKTS() ); _set_V_equiv_kts( Auxiliary->GetVequivalentKTS() );
_set_V_calibrated_kts( Auxiliary->GetVcalibratedKTS() ); _set_V_calibrated_kts( Auxiliary->GetVcalibratedKTS() );
_set_V_ground_speed( Position->GetVground() ); _set_V_ground_speed( Auxiliary->GetVground() );
_set_Omega_Body( Rotation->GetPQR(1), _set_Omega_Body( Propagate->GetPQR(eP),
Rotation->GetPQR(2), Propagate->GetPQR(eQ),
Rotation->GetPQR(3) ); Propagate->GetPQR(eR) );
_set_Euler_Rates( Rotation->GetEulerRates(1), _set_Euler_Rates( Auxiliary->GetEulerRates(ePhi),
Rotation->GetEulerRates(2), Auxiliary->GetEulerRates(eTht),
Rotation->GetEulerRates(3) ); Auxiliary->GetEulerRates(ePsi) );
_set_Geocentric_Rates(Position->GetLatitudeDot(), _set_Mach_number( Auxiliary->GetMach() );
Position->GetLongitudeDot(),
Position->Gethdot() );
_set_Mach_number( Translation->GetMach() );
// Positions
_updateGeocentricPosition( Position->GetLatitude(),
Position->GetLongitude(),
Position->Geth() );
// Positions of Visual Reference Point // Positions of Visual Reference Point
/* _updateGeocentricPosition( Auxiliary->GetLocationVRP().GetLatitude(),
_updateGeocentricPosition( Position->GetLatitudeVRP(), Auxiliary->GetLocationVRP().GetLongitude(),
Position->GetLongitudeVRP(), Auxiliary->GethVRP() );
Position->GethVRP() );
*/
_set_Altitude_AGL( Position->GetDistanceAGL() );
_set_Euler_Angles( Rotation->Getphi(), _set_Altitude_AGL( Propagate->GetDistanceAGL() );
Rotation->Gettht(),
Rotation->Getpsi() );
_set_Alpha( Translation->Getalpha() ); _set_Euler_Angles( Propagate->Getphi(),
_set_Beta( Translation->Getbeta() ); Propagate->Gettht(),
Propagate->Getpsi() );
_set_Alpha( Auxiliary->Getalpha() );
_set_Beta( Auxiliary->Getbeta() );
_set_Gamma_vert_rad( Position->GetGamma() ); _set_Gamma_vert_rad( Auxiliary->GetGamma() );
_set_Earth_position_angle( Auxiliary->GetEarthPositionAngle() ); _set_Earth_position_angle( Auxiliary->GetEarthPositionAngle() );
_set_Climb_Rate( Position->Gethdot() ); _set_Climb_Rate( Propagate->Gethdot() );
const FGMatrix33& Tl2b = Propagate->GetTl2b();
for ( i = 1; i <= 3; i++ ) { for ( i = 1; i <= 3; i++ ) {
for ( j = 1; j <= 3; j++ ) { for ( j = 1; j <= 3; j++ ) {
_set_T_Local_to_Body( i, j, State->GetTl2b(i,j) ); _set_T_Local_to_Body( i, j, Tl2b(i,j) );
} }
} }
@ -609,7 +603,7 @@ bool FGJSBsim::copy_from_JSBsim()
char buf[30]; char buf[30];
sprintf(buf, "engines/engine[%d]/thruster", i); sprintf(buf, "engines/engine[%d]/thruster", i);
SGPropertyNode * tnode = fgGetNode(buf, true); SGPropertyNode * tnode = fgGetNode(buf, true);
FGThruster * thruster = Propulsion->GetThruster(i); FGThruster * thruster = Propulsion->GetEngine(i)->GetThruster();
switch (Propulsion->GetEngine(i)->GetType()) { switch (Propulsion->GetEngine(i)->GetType()) {
case FGEngine::etPiston: case FGEngine::etPiston:
@ -628,9 +622,9 @@ bool FGJSBsim::copy_from_JSBsim()
FGRocket* eng = (FGRocket*)Propulsion->GetEngine(i); FGRocket* eng = (FGRocket*)Propulsion->GetEngine(i);
} // end FGRocket code block } // end FGRocket code block
break; break;
case FGEngine::etSimTurbine: case FGEngine::etTurbine:
{ // FGSimTurbine code block { // FGTurbine code block
FGSimTurbine* eng = (FGSimTurbine*)Propulsion->GetEngine(i); FGTurbine* eng = (FGTurbine*)Propulsion->GetEngine(i);
node->setDoubleValue("n1", eng->GetN1()); node->setDoubleValue("n1", eng->GetN1());
node->setDoubleValue("n2", eng->GetN2()); node->setDoubleValue("n2", eng->GetN2());
node->setDoubleValue("egt_degf", 32 + eng->GetEGT()*9/5); node->setDoubleValue("egt_degf", 32 + eng->GetEGT()*9/5);
@ -642,11 +636,18 @@ bool FGJSBsim::copy_from_JSBsim()
node->setDoubleValue("oil-pressure-psi", eng->getOilPressure_psi()); node->setDoubleValue("oil-pressure-psi", eng->getOilPressure_psi());
node->setBoolValue("reversed", eng->GetReversed()); node->setBoolValue("reversed", eng->GetReversed());
node->setBoolValue("cutoff", eng->GetCutoff()); node->setBoolValue("cutoff", eng->GetCutoff());
node->setDoubleValue("epr", eng->GetEPR());
globals->get_controls()->set_reverser(i, eng->GetReversed() ); globals->get_controls()->set_reverser(i, eng->GetReversed() );
globals->get_controls()->set_cutoff(i, eng->GetCutoff() ); globals->get_controls()->set_cutoff(i, eng->GetCutoff() );
globals->get_controls()->set_water_injection(i, eng->GetInjection() ); globals->get_controls()->set_water_injection(i, eng->GetInjection() );
globals->get_controls()->set_augmentation(i, eng->GetAugmentation() ); globals->get_controls()->set_augmentation(i, eng->GetAugmentation() );
} // end FGSimTurbine code block } // end FGTurbine code block
break;
case FGEngine::etElectric:
{ // FGElectric code block
FGElectric* eng = (FGElectric*)Propulsion->GetEngine(i);
node->setDoubleValue("rpm", eng->getRPM());
} // end FGElectric code block
break; break;
} }
@ -695,10 +696,12 @@ bool FGJSBsim::copy_from_JSBsim()
if ( ! fuel_freeze->getBoolValue() ) { if ( ! fuel_freeze->getBoolValue() ) {
for (i = 0; i < Propulsion->GetNumTanks(); i++) { for (i = 0; i < Propulsion->GetNumTanks(); i++) {
SGPropertyNode * node = fgGetNode("/consumables/fuel/tank", i, true); SGPropertyNode * node = fgGetNode("/consumables/fuel/tank", i, true);
double contents = Propulsion->GetTank(i)->GetContents(); FGTank* tank = Propulsion->GetTank(i);
double contents = tank->GetContents();
double temp = tank->GetTemperature_degC();
node->setDoubleValue("level-gal_us", contents/6.6); node->setDoubleValue("level-gal_us", contents/6.6);
node->setDoubleValue("level-lb", contents); node->setDoubleValue("level-lb", contents);
// node->setDoubleValue("temperature_degC", if (temp != -9999.0) node->setDoubleValue("temperature_degC", temp);
} }
} }

View file

@ -66,9 +66,7 @@ class FGMassBalance;
class FGAerodynamics; class FGAerodynamics;
class FGInertial; class FGInertial;
class FGAircraft; class FGAircraft;
class FGTranslation; class FGPropagate;
class FGRotation;
class FGPosition;
class FGAuxiliary; class FGAuxiliary;
class FGOutput; class FGOutput;
class FGInitialCondition; class FGInitialCondition;
@ -116,17 +114,17 @@ public:
//@{ //@{
/** Set geocentric latitude /** Set geocentric latitude
@param lat latitude in radians measured from the 0 meridian where @param lat latitude in radians measured from the 0 meridian where
the westerly direction is positive and east is negative */ the westerly direction is positive and east is negative */
void set_Latitude(double lat); // geocentric void set_Latitude(double lat); // geocentric
/** Set longitude /** Set longitude
@param lon longitude in radians measured from the equator where @param lon longitude in radians measured from the equator where
the northerly direction is positive and south is negative */ the northerly direction is positive and south is negative */
void set_Longitude(double lon); void set_Longitude(double lon);
/** Set altitude /** Set altitude
Note: this triggers a recalculation of AGL altitude Note: this triggers a recalculation of AGL altitude
@param alt altitude in feet */ @param alt altitude in feet */
void set_Altitude(double alt); // triggers re-calc of AGL altitude void set_Altitude(double alt); // triggers re-calc of AGL altitude
//@} //@}
@ -136,33 +134,33 @@ public:
//@{ //@{
/** Sets calibrated airspeed /** Sets calibrated airspeed
Setting this will trigger a recalc of the other velocity terms. Setting this will trigger a recalc of the other velocity terms.
@param vc Calibrated airspeed in ft/sec */ @param vc Calibrated airspeed in ft/sec */
void set_V_calibrated_kts(double vc); void set_V_calibrated_kts(double vc);
/** Sets Mach number. /** Sets Mach number.
Setting this will trigger a recalc of the other velocity terms. Setting this will trigger a recalc of the other velocity terms.
@param mach Mach number */ @param mach Mach number */
void set_Mach_number(double mach); void set_Mach_number(double mach);
/** Sets velocity in N-E-D coordinates. /** Sets velocity in N-E-D coordinates.
Setting this will trigger a recalc of the other velocity terms. Setting this will trigger a recalc of the other velocity terms.
@param north velocity northward in ft/sec @param north velocity northward in ft/sec
@param east velocity eastward in ft/sec @param east velocity eastward in ft/sec
@param down velocity downward in ft/sec */ @param down velocity downward in ft/sec */
void set_Velocities_Local( double north, double east, double down ); void set_Velocities_Local( double north, double east, double down );
/** Sets aircraft velocity in stability frame. /** Sets aircraft velocity in stability frame.
Setting this will trigger a recalc of the other velocity terms. Setting this will trigger a recalc of the other velocity terms.
@param u X velocity in ft/sec @param u X velocity in ft/sec
@param v Y velocity in ft/sec @param v Y velocity in ft/sec
@param w Z velocity in ft/sec */ @param w Z velocity in ft/sec */
void set_Velocities_Wind_Body( double u, double v, double w); void set_Velocities_Wind_Body( double u, double v, double w);
//@} //@}
/** Euler Angle Parameter Set /** Euler Angle Parameter Set
@param phi roll angle in radians @param phi roll angle in radians
@param theta pitch angle in radians @param theta pitch angle in radians
@param psi heading angle in radians */ @param psi heading angle in radians */
void set_Euler_Angles( double phi, double theta, double psi ); void set_Euler_Angles( double phi, double theta, double psi );
/// @name Flight Path Parameter Set /// @name Flight Path Parameter Set
@ -218,9 +216,7 @@ private:
FGPropulsion* Propulsion; FGPropulsion* Propulsion;
FGMassBalance* MassBalance; FGMassBalance* MassBalance;
FGAircraft* Aircraft; FGAircraft* Aircraft;
FGTranslation* Translation; FGPropagate* Propagate;
FGRotation* Rotation;
FGPosition* Position;
FGAuxiliary* Auxiliary; FGAuxiliary* Auxiliary;
FGAerodynamics* Aerodynamics; FGAerodynamics* Aerodynamics;
FGGroundReactions *GroundReactions; FGGroundReactions *GroundReactions;
@ -228,7 +224,7 @@ private:
int runcount; int runcount;
float trim_elev; float trim_elev;
float trim_throttle; float trim_throttle;
SGPropertyNode *startup_trim; SGPropertyNode *startup_trim;
SGPropertyNode *trimmed; SGPropertyNode *trimmed;
SGPropertyNode *pitch_trim; SGPropertyNode *pitch_trim;
@ -236,14 +232,14 @@ private:
SGPropertyNode *aileron_trim; SGPropertyNode *aileron_trim;
SGPropertyNode *rudder_trim; SGPropertyNode *rudder_trim;
SGPropertyNode *stall_warning; SGPropertyNode *stall_warning;
/* SGPropertyNode *elevator_pos_deg; /* SGPropertyNode *elevator_pos_deg;
SGPropertyNode *left_aileron_pos_deg; SGPropertyNode *left_aileron_pos_deg;
SGPropertyNode *right_aileron_pos_deg; SGPropertyNode *right_aileron_pos_deg;
SGPropertyNode *rudder_pos_deg; SGPropertyNode *rudder_pos_deg;
SGPropertyNode *flap_pos_deg; */ SGPropertyNode *flap_pos_deg; */
SGPropertyNode *elevator_pos_pct; SGPropertyNode *elevator_pos_pct;
SGPropertyNode *left_aileron_pos_pct; SGPropertyNode *left_aileron_pos_pct;
SGPropertyNode *right_aileron_pos_pct; SGPropertyNode *right_aileron_pos_pct;
@ -251,22 +247,22 @@ private:
SGPropertyNode *flap_pos_pct; SGPropertyNode *flap_pos_pct;
SGPropertyNode *speedbrake_pos_pct; SGPropertyNode *speedbrake_pos_pct;
SGPropertyNode *spoilers_pos_pct; SGPropertyNode *spoilers_pos_pct;
SGPropertyNode *gear_pos_pct; SGPropertyNode *gear_pos_pct;
SGPropertyNode *temperature; SGPropertyNode *temperature;
SGPropertyNode *pressure; SGPropertyNode *pressure;
SGPropertyNode *density; SGPropertyNode *density;
SGPropertyNode *turbulence_gain; SGPropertyNode *turbulence_gain;
SGPropertyNode *turbulence_rate; SGPropertyNode *turbulence_rate;
SGPropertyNode *wind_from_north; SGPropertyNode *wind_from_north;
SGPropertyNode *wind_from_east; SGPropertyNode *wind_from_east;
SGPropertyNode *wind_from_down; SGPropertyNode *wind_from_down;
void init_gear(void); void init_gear(void);
void update_gear(void); void update_gear(void);
}; };

View file

@ -11,9 +11,7 @@ libJSBSim_a_SOURCES = \
FGAuxiliary.cpp FGAuxiliary.h \ FGAuxiliary.cpp FGAuxiliary.h \
FGCoefficient.cpp FGCoefficient.h \ FGCoefficient.cpp FGCoefficient.h \
FGColumnVector3.cpp FGColumnVector3.h \ FGColumnVector3.cpp FGColumnVector3.h \
FGColumnVector4.cpp FGColumnVector4.h \
FGConfigFile.cpp FGConfigFile.h \ FGConfigFile.cpp FGConfigFile.h \
FGDefs.h \
FGFCS.cpp FGFCS.h \ FGFCS.cpp FGFCS.h \
FGFDMExec.cpp FGFDMExec.h \ FGFDMExec.cpp FGFDMExec.h \
FGFactorGroup.cpp FGFactorGroup.h \ FGFactorGroup.cpp FGFactorGroup.h \
@ -31,25 +29,24 @@ libJSBSim_a_SOURCES = \
FGPiston.cpp FGPiston.h \ FGPiston.cpp FGPiston.h \
FGPropeller.cpp FGPropeller.h \ FGPropeller.cpp FGPropeller.h \
FGPropulsion.cpp FGPropulsion.h \ FGPropulsion.cpp FGPropulsion.h \
FGPosition.cpp FGPosition.h \
FGRotation.cpp FGRotation.h \
FGRotor.cpp FGRotor.h \ FGRotor.cpp FGRotor.h \
FGRocket.cpp FGRocket.h \ FGRocket.cpp FGRocket.h \
FGScript.cpp FGScript.h \ FGScript.cpp FGScript.h \
FGState.cpp FGState.h \ FGState.cpp FGState.h \
FGTable.cpp FGTable.h \ FGTable.cpp FGTable.h \
FGThruster.cpp FGThruster.h \ FGThruster.cpp FGThruster.h \
FGTranslation.cpp FGTranslation.h \
FGTrim.cpp FGTrim.h \ FGTrim.cpp FGTrim.h \
FGTrimAxis.cpp FGTrimAxis.h \ FGTrimAxis.cpp FGTrimAxis.h \
FGTurbine.cpp FGTurbine.h \ FGTurbine.cpp FGTurbine.h \
FGUtility.cpp FGUtility.h \
FGEngine.cpp FGEngine.h \ FGEngine.cpp FGEngine.h \
FGTank.cpp FGTank.h \ FGTank.cpp FGTank.h \
FGfdmSocket.cpp FGfdmSocket.h \ FGfdmSocket.cpp FGfdmSocket.h \
FGTurbine.cpp FGTurbine.h \ FGTurbine.cpp FGTurbine.h \
FGPropertyManager.cpp FGPropertyManager.h \ FGPropertyManager.cpp FGPropertyManager.h \
FGSimTurbine.cpp FGSimTurbine.h \ FGPropagate.cpp FGPropagate.h \
FGLocation.cpp FGLocation.h \
FGQuaternion.cpp FGQuaternion.h \
FGElectric.cpp FGElectric.h \
JSBSim.cxx JSBSim.hxx JSBSim.cxx JSBSim.hxx

View file

@ -3,7 +3,7 @@
Module: FGFilter.cpp Module: FGFilter.cpp
Author: Jon S. Berndt Author: Jon S. Berndt
Date started: 11/2000 Date started: 11/2000
------------- Copyright (C) 2000 ------------- ------------- Copyright (C) 2000 -------------
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
@ -92,7 +92,7 @@ FGFilter::FGFilter(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
} else { } else {
*AC_cfg >> token; *AC_cfg >> token;
InputNodes.push_back( resolveSymbol(token) ); InputNodes.push_back( resolveSymbol(token) );
} }
} }
else if (token == "OUTPUT") else if (token == "OUTPUT")
{ {
@ -115,7 +115,7 @@ FGFilter::FGFilter(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
denom = 2.00*C3 + dt*C4; denom = 2.00*C3 + dt*C4;
ca = (2.00*C1 + dt*C2) / denom; ca = (2.00*C1 + dt*C2) / denom;
cb = (dt*C2 - 2.00*C1) / denom; cb = (dt*C2 - 2.00*C1) / denom;
cc = (2.00*C3 - dt*C2) / denom; cc = (2.00*C3 - dt*C4) / denom;
break; break;
case eOrder2: case eOrder2:
denom = 4.0*C4 + 2.0*C5*dt + C6*dt*dt; denom = 4.0*C4 + 2.0*C5*dt + C6*dt*dt;
@ -182,7 +182,7 @@ bool FGFilter::Run(void)
break; break;
case eOrder2: case eOrder2:
Output = Input * ca + PreviousInput1 * cb + PreviousInput2 * cc Output = Input * ca + PreviousInput1 * cb + PreviousInput2 * cc
- PreviousOutput1 * cd - PreviousOutput2 * ce; - PreviousOutput1 * cd - PreviousOutput2 * ce;
break; break;
case eWashout: case eWashout:
Output = Input * ca - PreviousInput1 * ca + PreviousOutput1 * cb; Output = Input * ca - PreviousInput1 * ca + PreviousOutput1 * cb;

View file

@ -3,7 +3,7 @@
Module: FGGain.cpp Module: FGGain.cpp
Author: Jon S. Berndt Author: Jon S. Berndt
Date started: 4/2000 Date started: 4/2000
------------- Copyright (C) 2000 ------------- ------------- Copyright (C) 2000 -------------
This program is free software; you can redistribute it and/or modify it under This program is free software; you can redistribute it and/or modify it under
@ -37,7 +37,7 @@ COMMENTS, REFERENCES, and NOTES
INCLUDES INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
#include "FGGain.h" #include "FGGain.h"
namespace JSBSim { namespace JSBSim {
@ -64,6 +64,8 @@ FGGain::FGGain(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
OutputPct = 0; OutputPct = 0;
invert = false; invert = false;
ScheduledBy = 0; ScheduledBy = 0;
clip = false;
clipmin = clipmax = 0.0;
Type = AC_cfg->GetValue("TYPE"); Type = AC_cfg->GetValue("TYPE");
Name = AC_cfg->GetValue("NAME"); Name = AC_cfg->GetValue("NAME");
@ -91,23 +93,27 @@ FGGain::FGGain(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
*AC_cfg >> Min; *AC_cfg >> Min;
} else if (token == "MAX") { } else if (token == "MAX") {
*AC_cfg >> Max; *AC_cfg >> Max;
} else if (token == "CLIPTO") {
*AC_cfg >> clipmin >> clipmax;
if (clipmax > clipmin) {
clip = true;
}
} else if (token == "INVERT") { } else if (token == "INVERT") {
invert = true; invert = true;
cerr << endl << "The INVERT keyword is being deprecated and will not be " cerr << endl << "The INVERT keyword is being deprecated and will not be "
"supported in the future. Please use a minus sign in front " "supported in the future. Please use a minus sign in front "
"of an input property in the future." << endl << endl; "of an input property in the future." << endl << endl;
} else if (token == "ROWS") { } else if (token == "ROWS") {
*AC_cfg >> Rows; *AC_cfg >> Rows;
Table = new FGTable(Rows); Table = new FGTable(Rows);
} else if (token == "SCHEDULED_BY") { } else if (token == "SCHEDULED_BY") {
token = AC_cfg->GetValue("SCHEDULED_BY"); token = AC_cfg->GetValue("SCHEDULED_BY");
*AC_cfg >> strScheduledBy; *AC_cfg >> strScheduledBy;
ScheduledBy = PropertyManager->GetNode( strScheduledBy ); ScheduledBy = PropertyManager->GetNode( strScheduledBy );
} else if (token == "OUTPUT") { } else if (token == "OUTPUT") {
IsOutput = true; IsOutput = true;
*AC_cfg >> sOutputIdx; *AC_cfg >> sOutputIdx;
OutputNode = PropertyManager->GetNode( sOutputIdx ); OutputNode = PropertyManager->GetNode( sOutputIdx, true );
} else { } else {
AC_cfg->ResetLineIndexToZero(); AC_cfg->ResetLineIndexToZero();
*Table << *AC_cfg; *Table << *AC_cfg;
@ -159,6 +165,11 @@ bool FGGain::Run(void )
} }
if (clip) {
if (Output > clipmax) Output = clipmax;
else if (Output < clipmin) Output = clipmin;
}
if (IsOutput) SetOutput(); if (IsOutput) SetOutput();
return true; return true;

View file

@ -1,8 +1,8 @@
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Header: FGGain.h Header: FGGain.h
Author: Author:
Date started: Date started:
------------- Copyright (C) ------------- ------------- Copyright (C) -------------
@ -94,6 +94,7 @@ CLASS DOCUMENTATION
ROWS \<number_of_rows> ROWS \<number_of_rows>
\<lookup_value gain_value> \<lookup_value gain_value>
? ?
[CLIPTO \<min> \<max> 1]
[OUTPUT \<property>] [OUTPUT \<property>]
\</COMPONENT> \</COMPONENT>
</pre> </pre>
@ -170,9 +171,9 @@ class FGGain : public FGFCSComponent
public: public:
FGGain(FGFCS* fcs, FGConfigFile* AC_cfg); FGGain(FGFCS* fcs, FGConfigFile* AC_cfg);
~FGGain(); ~FGGain();
double GetOutputPct() const { return OutputPct; } double GetOutputPct() const { return OutputPct; }
bool Run (void); bool Run (void);
private: private:
@ -181,8 +182,9 @@ private:
FGState* State; FGState* State;
double Gain; double Gain;
double Min, Max; double Min, Max;
double clipmin, clipmax;
double OutputPct; double OutputPct;
bool invert; bool invert, clip;
int Rows; int Rows;
FGPropertyManager* ScheduledBy; FGPropertyManager* ScheduledBy;

View file

@ -121,7 +121,7 @@ bool FGKinemat::Run(void )
Input = InputNodes[0]->getDoubleValue(); Input = InputNodes[0]->getDoubleValue();
if (DoScale) Input *= Detents[NumDetents-1]; if (DoScale) Input *= Detents[NumDetents-1];
Output = OutputNode->getDoubleValue(); Output = OutputNode->getDoubleValue();
@ -132,7 +132,7 @@ bool FGKinemat::Run(void )
// Process all detent intervals the movement traverses until either the // Process all detent intervals the movement traverses until either the
// final value is reached or the time interval has finished. // final value is reached or the time interval has finished.
while (0.0 < dt && Input != Output) { while ( 0.0 < dt && !EqualToRoundoff(Input, Output) ) {
// Find the area where Output is in // Find the area where Output is in
int ind; int ind;
@ -154,16 +154,20 @@ bool FGKinemat::Run(void )
if (Detents[ind] < ThisInput) ThisInput = Detents[ind]; if (Detents[ind] < ThisInput) ThisInput = Detents[ind];
// Compute the time to reach the value in ThisInput // Compute the time to reach the value in ThisInput
double ThisDt = fabs((ThisInput-Output)/Rate); double ThisDt = fabs((ThisInput-Output)/Rate);
if (ThisDt == 0.0)
break;
// and clip to the timestep size // and clip to the timestep size
if (dt < ThisDt) ThisDt = dt; if (dt < ThisDt) {
ThisDt = dt;
if (Output < Input)
Output += ThisDt*Rate;
else
Output -= ThisDt*Rate;
} else
// Handle this case separate to make shure the termination condition
// is met even in inexact arithmetics ...
Output = ThisInput;
dt -= ThisDt; dt -= ThisDt;
// Do the output calculation
if (Output < Input)
Output += ThisDt*Rate;
else
Output -= ThisDt*Rate;
} }
} }

View file

@ -77,11 +77,29 @@ CLASS DECLARATION
class FGKinemat : public FGFCSComponent { class FGKinemat : public FGFCSComponent {
public: public:
/** Initializer.
@param fcs A reference to the ccurrent flightcontrolsystem.
@param AC_cfg reference to the current aircraft configuration file.
Initializes the FGKinemat object from the given configuration
file. The Configuration file is expected to be at the stream
position where the KINEMAT object starts. Also it is expected to
be past the end of the current KINEMAT configuration on exit.
*/
FGKinemat(FGFCS* fcs, FGConfigFile* AC_cfg); FGKinemat(FGFCS* fcs, FGConfigFile* AC_cfg);
/** Destructor.
*/
~FGKinemat(); ~FGKinemat();
/** Kinemat output value.
@return the current output of the kinemat object on the range of [0,1].
*/
double GetOutputPct() const { return OutputPct; } double GetOutputPct() const { return OutputPct; }
/** Run method, overwrites FGModel::Run().
@return false on success, true on failure.
The routine doing the work.
*/
bool Run (void); bool Run (void);
private: private:

View file

@ -87,7 +87,7 @@ FGSummer::FGSummer(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
} else if (token == "OUTPUT") { } else if (token == "OUTPUT") {
IsOutput = true; IsOutput = true;
*AC_cfg >> sOutputIdx; *AC_cfg >> sOutputIdx;
OutputNode = PropertyManager->GetNode(sOutputIdx); OutputNode = PropertyManager->GetNode(sOutputIdx, true);
} }
} }

View file

@ -75,7 +75,7 @@ FGSwitch::FGSwitch(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
{ {
string token, value; string token, value;
struct test *current_test; struct test *current_test;
struct FGCondition *current_condition; string sOutputIdx;
Type = AC_cfg->GetValue("TYPE"); Type = AC_cfg->GetValue("TYPE");
Name = AC_cfg->GetValue("NAME"); Name = AC_cfg->GetValue("NAME");
@ -124,8 +124,13 @@ FGSwitch::FGSwitch(FGFCS* fcs, FGConfigFile* AC_cfg) : FGFCSComponent(fcs),
while (AC_cfg->GetValue() != string("/TEST")) { while (AC_cfg->GetValue() != string("/TEST")) {
current_test->conditions.push_back(FGCondition(AC_cfg, PropertyManager)); current_test->conditions.push_back(FGCondition(AC_cfg, PropertyManager));
} }
AC_cfg->GetNextConfigLine();
} else if (token == "OUTPUT") {
IsOutput = true;
*AC_cfg >> sOutputIdx;
*AC_cfg >> sOutputIdx;
OutputNode = PropertyManager->GetNode( sOutputIdx, true );
} }
AC_cfg->GetNextConfigLine();
} }
FGFCSComponent::bind(); FGFCSComponent::bind();
@ -178,6 +183,8 @@ bool FGSwitch::Run(void )
*iTests++; *iTests++;
} }
if (IsOutput) SetOutput();
return true; return true;
} }
@ -256,6 +263,7 @@ void FGSwitch::Debug(int from)
cout << endl; cout << endl;
*iTests++; *iTests++;
} }
if (IsOutput) cout << " OUTPUT: " << OutputNode->getName() << endl;
} }
} }
if (debug_lvl & 2 ) { // Instantiation/Destruction notification if (debug_lvl & 2 ) { // Instantiation/Destruction notification

View file

@ -86,7 +86,7 @@ additional conditions, as well as possibly additional CONDITION_GROUPs.
<pre> <pre>
\<COMPONENT NAME="switch1" TYPE="SWITCH"\> \<COMPONENT NAME="switch1" TYPE="SWITCH"\>
\<TEST LOGIC="{AND|OR|DEFAULT}" OUTPUT="{property|value}"\> \<TEST LOGIC="{AND|OR|DEFAULT}" VALUE="{property|value}"\>
{property} {conditional} {property|value} {property} {conditional} {property|value}
\<CONDITION_GROUP LOGIC="{AND|OR}"\> \<CONDITION_GROUP LOGIC="{AND|OR}"\>
{property} {conditional} {property|value} {property} {conditional} {property|value}
@ -94,11 +94,12 @@ additional conditions, as well as possibly additional CONDITION_GROUPs.
\</CONDITION_GROUP\> \</CONDITION_GROUP\>
... ...
\</TEST> \</TEST>
\<TEST LOGIC="{AND|OR}" OUTPUT="{property|value}"\> \<TEST LOGIC="{AND|OR}" VALUE="{property|value}"\>
{property} {conditional} {property|value} {property} {conditional} {property|value}
... ...
\</TEST\> \</TEST\>
... ...
[OUTPUT \<property>]
\</COMPONENT\> \</COMPONENT\>
</pre> </pre>