Sync w. JSBSim CVS
This commit is contained in:
parent
56f085b6f1
commit
8e1482f746
86 changed files with 5305 additions and 4950 deletions
|
@ -37,7 +37,7 @@ INCLUDES
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
#include "FGAerodynamics.h"
|
#include "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();
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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");
|
||||||
|
|
|
@ -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;}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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) );
|
||||||
|
|
|
@ -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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,317 +0,0 @@
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
Module: FGMatrix33.cpp
|
|
||||||
Author: Originally by Tony Peden [formatted here (and broken??) by JSB]
|
|
||||||
Date started: 1998
|
|
||||||
Purpose: FGMatrix33 class
|
|
||||||
Called by: Various
|
|
||||||
|
|
||||||
FUNCTIONAL DESCRIPTION
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
HISTORY
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
??/??/?? TP Created
|
|
||||||
03/16/2000 JSB Added exception throwing
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
INCLUDES
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#include "FGColumnVector4.h"
|
|
||||||
|
|
||||||
namespace JSBSim {
|
|
||||||
|
|
||||||
static const char *IdSrc = "$Id$";
|
|
||||||
static const char *IdHdr = ID_COLUMNVECTOR4;
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
CLASS IMPLEMENTATION
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
FGColumnVector4::FGColumnVector4(void)
|
|
||||||
{
|
|
||||||
rowCtr = 1;
|
|
||||||
data[1]=0;data[2]=0;data[3]=0;data[4]=0;
|
|
||||||
|
|
||||||
Debug(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
FGColumnVector4::FGColumnVector4(double A, double B, double C, double D)
|
|
||||||
{
|
|
||||||
rowCtr = 1;
|
|
||||||
data[1]=A;
|
|
||||||
data[2]=B;
|
|
||||||
data[3]=C;
|
|
||||||
data[4]=D;
|
|
||||||
|
|
||||||
Debug(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
FGColumnVector4::~FGColumnVector4(void)
|
|
||||||
{
|
|
||||||
Debug(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
FGColumnVector4::FGColumnVector4(const FGColumnVector4& b)
|
|
||||||
{
|
|
||||||
data[1] = b.data[1];
|
|
||||||
data[2] = b.data[2];
|
|
||||||
data[3] = b.data[3];
|
|
||||||
data[4] = b.data[4];
|
|
||||||
|
|
||||||
rowCtr = 1;
|
|
||||||
|
|
||||||
Debug(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
FGColumnVector4 FGColumnVector4::operator=(const FGColumnVector4& b)
|
|
||||||
{
|
|
||||||
data[1] = b.data[1];
|
|
||||||
data[2] = b.data[2];
|
|
||||||
data[3] = b.data[3];
|
|
||||||
data[4] = b.data[4];
|
|
||||||
rowCtr = 1;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
FGColumnVector4 FGColumnVector4::operator+(const FGColumnVector4& C)
|
|
||||||
{
|
|
||||||
FGColumnVector4 Sum;
|
|
||||||
|
|
||||||
Sum(1) = C(1) + data[1];
|
|
||||||
Sum(2) = C(2) + data[2];
|
|
||||||
Sum(3) = C(3) + data[3];
|
|
||||||
Sum(4) = C(4) + data[4];
|
|
||||||
return Sum;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
void FGColumnVector4::operator+=(const FGColumnVector4& C)
|
|
||||||
{
|
|
||||||
data[1] += C(1);
|
|
||||||
data[2] += C(2);
|
|
||||||
data[3] += C(3);
|
|
||||||
data[4] += C(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
FGColumnVector4 FGColumnVector4::operator*(const double scalar)
|
|
||||||
{
|
|
||||||
FGColumnVector4 Product;
|
|
||||||
|
|
||||||
Product(1) = scalar * data[1];
|
|
||||||
Product(2) = scalar * data[2];
|
|
||||||
Product(3) = scalar * data[3];
|
|
||||||
Product(4) = scalar * data[4];
|
|
||||||
|
|
||||||
return Product;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
void FGColumnVector4::operator*=(const double scalar)
|
|
||||||
{
|
|
||||||
data[1] *= scalar;
|
|
||||||
data[2] *= scalar;
|
|
||||||
data[3] *= scalar;
|
|
||||||
data[4] *= scalar;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
FGColumnVector4 FGColumnVector4::operator-(const FGColumnVector4& V)
|
|
||||||
{
|
|
||||||
|
|
||||||
FGColumnVector4 Diff;
|
|
||||||
|
|
||||||
Diff(1) = data[1] - V(1);
|
|
||||||
Diff(2) = data[2] - V(2);
|
|
||||||
Diff(3) = data[3] - V(3);
|
|
||||||
Diff(4) = data[4] - V(4);
|
|
||||||
|
|
||||||
return Diff;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
void FGColumnVector4::operator-=(const FGColumnVector4& V)
|
|
||||||
{
|
|
||||||
data[1] -= V(1);
|
|
||||||
data[2] -= V(2);
|
|
||||||
data[3] -= V(3);
|
|
||||||
data[4] -= V(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
FGColumnVector4 FGColumnVector4::operator/(const double scalar)
|
|
||||||
{
|
|
||||||
FGColumnVector4 Quotient;
|
|
||||||
|
|
||||||
if (scalar != 0) {
|
|
||||||
double tmp = 1.0/scalar;
|
|
||||||
Quotient(1) = data[1] * tmp;
|
|
||||||
Quotient(2) = data[2] * tmp;
|
|
||||||
Quotient(3) = data[3] * tmp;
|
|
||||||
Quotient(4) = data[4] * tmp;
|
|
||||||
} else {
|
|
||||||
cerr << "Attempt to divide by zero in method FGColumnVector4::operator/(const double scalar), object " << this << endl;
|
|
||||||
}
|
|
||||||
return Quotient;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
void FGColumnVector4::operator/=(const double scalar)
|
|
||||||
{
|
|
||||||
FGColumnVector4 Quotient;
|
|
||||||
|
|
||||||
if (scalar != 0) {
|
|
||||||
double tmp = 1.0/scalar;
|
|
||||||
data[1] *= tmp;
|
|
||||||
data[2] *= tmp;
|
|
||||||
data[3] *= tmp;
|
|
||||||
data[4] *= tmp;
|
|
||||||
} else {
|
|
||||||
cerr << "Attempt to divide by zero in method FGColumnVector4::operator/=(const double scalar), object " << this << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
FGColumnVector4 operator*(const double scalar, const FGColumnVector4& C)
|
|
||||||
{
|
|
||||||
FGColumnVector4 Product;
|
|
||||||
|
|
||||||
Product(1) = scalar * C(1);
|
|
||||||
Product(2) = scalar * C(2);
|
|
||||||
Product(3) = scalar * C(3);
|
|
||||||
Product(4) = scalar * C(4);
|
|
||||||
return Product;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
double FGColumnVector4::Magnitude(void)
|
|
||||||
{
|
|
||||||
double num;
|
|
||||||
|
|
||||||
if ((data[1] == 0.00) &&
|
|
||||||
(data[2] == 0.00) &&
|
|
||||||
(data[3] == 0.00) &&
|
|
||||||
(data[4] == 0.00))
|
|
||||||
{
|
|
||||||
return 0.00;
|
|
||||||
} else {
|
|
||||||
num = data[1]*data[1];
|
|
||||||
num += data[2]*data[2];
|
|
||||||
num += data[3]*data[3];
|
|
||||||
num += data[4]*data[4];
|
|
||||||
return sqrt(num);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
FGColumnVector4 FGColumnVector4::Normalize(void)
|
|
||||||
{
|
|
||||||
double Mag = Magnitude();
|
|
||||||
|
|
||||||
if (Mag != 0) {
|
|
||||||
Mag = 1.0/Mag;
|
|
||||||
data[1] *= Mag;
|
|
||||||
data[2] *= Mag;
|
|
||||||
data[3] *= Mag;
|
|
||||||
data[4] *= Mag;
|
|
||||||
}
|
|
||||||
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
FGColumnVector4 FGColumnVector4::multElementWise(const FGColumnVector4& V)
|
|
||||||
{
|
|
||||||
FGColumnVector4 Product;
|
|
||||||
|
|
||||||
Product(1) = data[1] * V(1);
|
|
||||||
Product(2) = data[2] * V(2);
|
|
||||||
Product(3) = data[3] * V(3);
|
|
||||||
Product(4) = data[4] * V(4);
|
|
||||||
|
|
||||||
return Product;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
ostream& operator<<(ostream& os, FGColumnVector4& col)
|
|
||||||
{
|
|
||||||
os << col(1) << " , " << col(2) << " , " << col(3) << " , " << col(4);
|
|
||||||
return os;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
FGColumnVector4& FGColumnVector4::operator<<(const double ff)
|
|
||||||
{
|
|
||||||
data[rowCtr] = ff;
|
|
||||||
if (++rowCtr > 4) rowCtr = 1;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
// The bitmasked value choices are as follows:
|
|
||||||
// unset: In this case (the default) JSBSim would only print
|
|
||||||
// out the normally expected messages, essentially echoing
|
|
||||||
// the config files as they are read. If the environment
|
|
||||||
// variable is not set, debug_lvl is set to 1 internally
|
|
||||||
// 0: This requests JSBSim not to output any messages
|
|
||||||
// whatsoever.
|
|
||||||
// 1: This value explicity requests the normal JSBSim
|
|
||||||
// startup messages
|
|
||||||
// 2: This value asks for a message to be printed out when
|
|
||||||
// a class is instantiated
|
|
||||||
// 4: When this value is set, a message is displayed when a
|
|
||||||
// FGModel object executes its Run() method
|
|
||||||
// 8: When this value is set, various runtime state variables
|
|
||||||
// are printed out periodically
|
|
||||||
// 16: When set various parameters are sanity checked and
|
|
||||||
// a message is printed out when they go out of bounds
|
|
||||||
|
|
||||||
void FGColumnVector4::Debug(int from)
|
|
||||||
{
|
|
||||||
if (debug_lvl <= 0) return;
|
|
||||||
|
|
||||||
if (debug_lvl & 1) { // Standard console startup message output
|
|
||||||
}
|
|
||||||
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
|
||||||
if (from == 0) cout << "Instantiated: FGColumnVector4" << endl;
|
|
||||||
if (from == 1) cout << "Destroyed: FGColumnVector4" << endl;
|
|
||||||
}
|
|
||||||
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
|
|
||||||
}
|
|
||||||
if (debug_lvl & 8 ) { // Runtime state variables
|
|
||||||
}
|
|
||||||
if (debug_lvl & 16) { // Sanity checking
|
|
||||||
}
|
|
||||||
if (debug_lvl & 64) { // Sanity checking
|
|
||||||
if (from == 0) { // Constructor
|
|
||||||
cout << IdSrc << endl;
|
|
||||||
cout << IdHdr << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,132 +0,0 @@
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
Header: FGColumnVector4.h
|
|
||||||
Author: Originally by Tony Peden [formatted and adapted here by Jon Berndt]
|
|
||||||
Date started: Unknown
|
|
||||||
|
|
||||||
HISTORY
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
SENTRY
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#ifndef FGCOLUMNVECTOR4_H
|
|
||||||
#define FGCOLUMNVECTOR4_H
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
INCLUDES
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#include <stdlib.h>
|
|
||||||
#ifdef FGFS
|
|
||||||
# include <math.h>
|
|
||||||
# include <simgear/compiler.h>
|
|
||||||
# include STL_STRING
|
|
||||||
# include STL_FSTREAM
|
|
||||||
# include STL_IOSTREAM
|
|
||||||
SG_USING_STD(string);
|
|
||||||
SG_USING_STD(ostream);
|
|
||||||
SG_USING_STD(istream);
|
|
||||||
SG_USING_STD(cerr);
|
|
||||||
SG_USING_STD(cout);
|
|
||||||
SG_USING_STD(endl);
|
|
||||||
// SG_USING_STD(sqrt);
|
|
||||||
#else
|
|
||||||
# include <string>
|
|
||||||
# if defined (sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
|
|
||||||
# include <fstream.h>
|
|
||||||
# include <iostream.h>
|
|
||||||
# include <math.h>
|
|
||||||
# else
|
|
||||||
# include <fstream>
|
|
||||||
# if defined (sgi) && !defined(__GNUC__)
|
|
||||||
# include <math.h>
|
|
||||||
# else
|
|
||||||
# include <cmath>
|
|
||||||
# endif
|
|
||||||
# include <iostream>
|
|
||||||
using std::ostream;
|
|
||||||
using std::istream;
|
|
||||||
using std::cerr;
|
|
||||||
using std::cout;
|
|
||||||
using std::endl;
|
|
||||||
using std::sqrt;
|
|
||||||
# endif
|
|
||||||
using std::string;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "FGJSBBase.h"
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
DEFINITIONS
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#define ID_COLUMNVECTOR4 "$Id$"
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
FORWARD DECLARATIONS
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
namespace JSBSim {
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
CLASS DOCUMENTATION
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
/** This class implements a 4 dimensional vector.
|
|
||||||
@author Jon S. Berndt, Tony Peden, et. al.
|
|
||||||
@version $Id$
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
CLASS DECLARATION
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
class FGColumnVector4 : public FGJSBBase
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FGColumnVector4(void);
|
|
||||||
FGColumnVector4(double A, double B, double C, double D);
|
|
||||||
FGColumnVector4(const FGColumnVector4& b);
|
|
||||||
~FGColumnVector4(void);
|
|
||||||
|
|
||||||
FGColumnVector4 operator=(const FGColumnVector4& b);
|
|
||||||
|
|
||||||
FGColumnVector4 operator*(const double scalar);
|
|
||||||
FGColumnVector4 operator/(const double scalar);
|
|
||||||
FGColumnVector4 operator+(const FGColumnVector4& B); // must not return reference
|
|
||||||
FGColumnVector4 operator-(const FGColumnVector4& B);
|
|
||||||
|
|
||||||
void operator-=(const FGColumnVector4 &B);
|
|
||||||
void operator+=(const FGColumnVector4 &B);
|
|
||||||
void operator*=(const double scalar);
|
|
||||||
void operator/=(const double scalar);
|
|
||||||
|
|
||||||
inline double operator()(int m) const { return data[m]; }
|
|
||||||
inline double& operator()(int m) { return data[m]; }
|
|
||||||
|
|
||||||
FGColumnVector4& operator<<(const double ff);
|
|
||||||
|
|
||||||
inline void InitMatrix(void) { data[1]=0; data[2]=0; data[3]=0; data[4]=0; }
|
|
||||||
inline void InitMatrix(double ff) { data[1]=ff; data[2]=ff; data[3]=ff; data[4]=ff;}
|
|
||||||
|
|
||||||
double Magnitude(void);
|
|
||||||
FGColumnVector4 Normalize(void);
|
|
||||||
|
|
||||||
friend FGColumnVector4 operator*(const double scalar, const FGColumnVector4& A);
|
|
||||||
|
|
||||||
friend ostream& operator<<(ostream& os, FGColumnVector4& col);
|
|
||||||
|
|
||||||
|
|
||||||
FGColumnVector4 multElementWise(const FGColumnVector4& V);
|
|
||||||
|
|
||||||
private:
|
|
||||||
double data[5];
|
|
||||||
int rowCtr;
|
|
||||||
void Debug(int from);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,131 +0,0 @@
|
||||||
/*******************************************************************************
|
|
||||||
|
|
||||||
Header: FGDefs.h
|
|
||||||
Author: Jon S. Berndt
|
|
||||||
Date started: 02/01/99
|
|
||||||
|
|
||||||
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
|
||||||
Foundation; either version 2 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
|
||||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
|
|
||||||
Further information about the GNU General Public License can also be found on
|
|
||||||
the world wide web at http://www.gnu.org.
|
|
||||||
|
|
||||||
HISTORY
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
02/01/99 JSB Created
|
|
||||||
|
|
||||||
********************************************************************************
|
|
||||||
SENTRY
|
|
||||||
*******************************************************************************/
|
|
||||||
|
|
||||||
#ifndef FGDEFS_H
|
|
||||||
#define FGDEFS_H
|
|
||||||
|
|
||||||
#define GRAVITY 32.174
|
|
||||||
#define INVGRAVITY 0.031081
|
|
||||||
#define EARTHRAD 20925650.00 // feet, equatorial
|
|
||||||
#define EARTHRADSQRD 437882827922500.0
|
|
||||||
#define ONESECOND 4.848136811E-6
|
|
||||||
#define Reng 1716 //Specific Gas Constant,ft^2/(sec^2*R)
|
|
||||||
#define SHRATIO 1.4 //Specific Heat Ratio
|
|
||||||
#define RADTODEG 57.29578
|
|
||||||
#define DEGTORAD 1.745329E-2
|
|
||||||
#define KTSTOFPS 1.68781
|
|
||||||
#define FPSTOKTS 0.592484
|
|
||||||
#define INCHTOFT 0.08333333
|
|
||||||
#define OMEGA_EARTH .00007272205217
|
|
||||||
#define NEEDED_CFG_VERSION "1.50"
|
|
||||||
#define JSBSIM_VERSION "0.9.0"
|
|
||||||
|
|
||||||
#define HPTOFTLBSSEC 550
|
|
||||||
#define METERS_TO_FEET 3.2808
|
|
||||||
|
|
||||||
#if defined ( sgi ) && !defined( __GNUC__ )
|
|
||||||
#define __STL_FUNCTION_TMPL_PARTIAL_ORDER
|
|
||||||
#endif
|
|
||||||
|
|
||||||
enum eParam {
|
|
||||||
FG_UNDEF = 0,
|
|
||||||
FG_TIME,
|
|
||||||
FG_QBAR,
|
|
||||||
FG_WINGAREA,
|
|
||||||
FG_WINGSPAN,
|
|
||||||
FG_CBAR,
|
|
||||||
FG_ALPHA,
|
|
||||||
FG_ALPHADOT,
|
|
||||||
FG_BETA,
|
|
||||||
FG_BETADOT,
|
|
||||||
FG_PHI,
|
|
||||||
FG_THT,
|
|
||||||
FG_PSI,
|
|
||||||
FG_PITCHRATE,
|
|
||||||
FG_ROLLRATE,
|
|
||||||
FG_YAWRATE,
|
|
||||||
FG_CL_SQRD,
|
|
||||||
FG_MACH,
|
|
||||||
FG_ALTITUDE,
|
|
||||||
FG_BI2VEL,
|
|
||||||
FG_CI2VEL,
|
|
||||||
FG_ELEVATOR_POS,
|
|
||||||
FG_AILERON_POS,
|
|
||||||
FG_RUDDER_POS,
|
|
||||||
FG_SPDBRAKE_POS,
|
|
||||||
FG_SPOILERS_POS,
|
|
||||||
FG_FLAPS_POS,
|
|
||||||
FG_ELEVATOR_CMD,
|
|
||||||
FG_AILERON_CMD,
|
|
||||||
FG_RUDDER_CMD,
|
|
||||||
FG_SPDBRAKE_CMD,
|
|
||||||
FG_SPOILERS_CMD,
|
|
||||||
FG_FLAPS_CMD,
|
|
||||||
FG_THROTTLE_CMD,
|
|
||||||
FG_THROTTLE_POS,
|
|
||||||
FG_MIXTURE_CMD,
|
|
||||||
FG_MIXTURE_POS,
|
|
||||||
FG_MAGNETO_CMD,
|
|
||||||
FG_STARTER_CMD,
|
|
||||||
FG_ACTIVE_ENGINE,
|
|
||||||
FG_HOVERB,
|
|
||||||
FG_PITCH_TRIM_CMD,
|
|
||||||
FG_LEFT_BRAKE_CMD,
|
|
||||||
FG_CENTER_BRAKE_CMD,
|
|
||||||
FG_RIGHT_BRAKE_CMD,
|
|
||||||
FG_SET_LOGGING,
|
|
||||||
FG_ALPHAH,
|
|
||||||
FG_ALPHAW,
|
|
||||||
FG_LBARH, //normalized horizontal tail arm
|
|
||||||
FG_LBARV, //normalized vertical tail arm
|
|
||||||
FG_HTAILAREA,
|
|
||||||
FG_VTAILAREA,
|
|
||||||
FG_VBARH, //horizontal tail volume
|
|
||||||
FG_VBARV //vertical tail volume
|
|
||||||
};
|
|
||||||
|
|
||||||
enum eAction {
|
|
||||||
FG_RAMP = 1,
|
|
||||||
FG_STEP = 2,
|
|
||||||
FG_EXP = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
enum eType {
|
|
||||||
FG_VALUE = 1,
|
|
||||||
FG_DELTA = 2,
|
|
||||||
FG_BOOL = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************************************************************************/
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
Module: FGUtility.cpp
|
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
|
|
@ -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);
|
||||||
};
|
};
|
||||||
}
|
}
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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++) {
|
||||||
|
|
|
@ -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>
|
||||||
< FLIGHT_CONTROL NAME="X-15 SAS">
|
\<FLIGHT_CONTROL NAME="X-15 SAS">
|
||||||
|
|
||||||
< COMPONENT NAME="Pitch Trim Sum" TYPE="SUMMER">
|
\<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>
|
||||||
</COMPONENT>
|
|
||||||
|
|
||||||
< COMPONENT NAME="Pitch Command Scale" TYPE="AEROSURFACE_SCALE">
|
\<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
|
||||||
</COMPONENT>
|
\</COMPONENT>
|
||||||
|
|
||||||
< COMPONENT NAME="Pitch Gain 1" TYPE="PURE_GAIN">
|
\<COMPONENT NAME="Pitch Gain 1" TYPE="PURE_GAIN">
|
||||||
ID 2
|
INPUT fcs/pitch-command-scale
|
||||||
INPUT 1
|
|
||||||
GAIN -0.36
|
GAIN -0.36
|
||||||
</COMPONENT>
|
\</COMPONENT>
|
||||||
|
|
||||||
< COMPONENT NAME="Pitch Scheduled Gain 1" TYPE="SCHEDULED_GAIN">
|
|
||||||
ID 3
|
|
||||||
INPUT 2
|
|
||||||
GAIN 0.017
|
|
||||||
SCHEDULED_BY FG_ELEVATOR_POS
|
|
||||||
-0.35 -6.0
|
|
||||||
-0.17 -3.0
|
|
||||||
0.00 -2.0
|
|
||||||
0.09 -3.0
|
|
||||||
0.17 -5.0
|
|
||||||
0.60 -12.0
|
|
||||||
</COMPONENT>
|
|
||||||
|
|
||||||
... 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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
|
@ -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
|
||||||
|
|
216
src/FDM/JSBSim/FGLocation.cpp
Normal file
216
src/FDM/JSBSim/FGLocation.cpp
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
Module: FGLocation.cpp
|
||||||
|
Author: Jon S. Berndt
|
||||||
|
Date started: 04/04/2004
|
||||||
|
Purpose: Store an arbitrary location on the globe
|
||||||
|
|
||||||
|
------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------------
|
||||||
|
------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
|
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
Further information about the GNU General Public License can also be found on
|
||||||
|
the world wide web at http://www.gnu.org.
|
||||||
|
|
||||||
|
FUNCTIONAL DESCRIPTION
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
This class encapsulates an arbitrary position in the globe with its accessors.
|
||||||
|
It has vector properties, so you can add multiply ....
|
||||||
|
|
||||||
|
HISTORY
|
||||||
|
------------------------------------------------------------------------------
|
||||||
|
04/04/2004 MF Created
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
INCLUDES
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#ifdef FGFS
|
||||||
|
# include <simgear/compiler.h>
|
||||||
|
# ifdef SG_HAVE_STD_INCLUDES
|
||||||
|
# include <cmath>
|
||||||
|
# else
|
||||||
|
# include <math.h>
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# if defined(sgi) && !defined(__GNUC__)
|
||||||
|
# include <math.h>
|
||||||
|
# else
|
||||||
|
# include <cmath>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "FGLocation.h"
|
||||||
|
#include "FGPropertyManager.h"
|
||||||
|
|
||||||
|
namespace JSBSim {
|
||||||
|
|
||||||
|
static const char *IdSrc = "$Id$";
|
||||||
|
static const char *IdHdr = ID_LOCATION;
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
CLASS IMPLEMENTATION
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
FGLocation::FGLocation(double lon, double lat, double radius)
|
||||||
|
{
|
||||||
|
mCacheValid = false;
|
||||||
|
|
||||||
|
double sinLat = sin(lat);
|
||||||
|
double cosLat = cos(lat);
|
||||||
|
double sinLon = sin(lon);
|
||||||
|
double cosLon = cos(lon);
|
||||||
|
mECLoc = FGColumnVector3( radius*cosLat*cosLon,
|
||||||
|
radius*cosLat*sinLon,
|
||||||
|
radius*sinLat );
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGLocation::SetLongitude(double longitude)
|
||||||
|
{
|
||||||
|
double rtmp = sqrt(mECLoc(eX)*mECLoc(eX) + mECLoc(eY)*mECLoc(eY));
|
||||||
|
// Fast return if we are on the north or south pole ...
|
||||||
|
if (rtmp == 0.0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mCacheValid = false;
|
||||||
|
|
||||||
|
mECLoc(eX) = rtmp*sin(longitude);
|
||||||
|
mECLoc(eY) = rtmp*cos(longitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGLocation::SetLatitude(double latitude)
|
||||||
|
{
|
||||||
|
mCacheValid = false;
|
||||||
|
|
||||||
|
double r = mECLoc.Magnitude();
|
||||||
|
if (r == 0.0) {
|
||||||
|
mECLoc(eX) = 1.0;
|
||||||
|
r = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
double rtmp = sqrt(mECLoc(eX)*mECLoc(eX) + mECLoc(eY)*mECLoc(eY));
|
||||||
|
if (rtmp != 0.0) {
|
||||||
|
double fac = r/rtmp*cos(latitude);
|
||||||
|
mECLoc(eX) *= fac;
|
||||||
|
mECLoc(eY) *= fac;
|
||||||
|
} else {
|
||||||
|
mECLoc(eX) = r*cos(latitude);
|
||||||
|
mECLoc(eY) = 0.0;
|
||||||
|
}
|
||||||
|
mECLoc(eZ) = r*sin(latitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGLocation::SetRadius(double radius)
|
||||||
|
{
|
||||||
|
mCacheValid = false;
|
||||||
|
|
||||||
|
double rold = mECLoc.Magnitude();
|
||||||
|
if (rold == 0.0)
|
||||||
|
mECLoc(eX) = radius;
|
||||||
|
else
|
||||||
|
mECLoc *= radius/rold;
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGLocation::ComputeDerivedUnconditional(void) const
|
||||||
|
{
|
||||||
|
// The radius is just the Euclidean norm of the vector.
|
||||||
|
mRadius = mECLoc.Magnitude();
|
||||||
|
|
||||||
|
// The distance of the location to the y-axis, which is the axis
|
||||||
|
// through the poles.
|
||||||
|
double rxy = sqrt(mECLoc(eX)*mECLoc(eX) + mECLoc(eY)*mECLoc(eY));
|
||||||
|
|
||||||
|
// Compute the sin/cos values of the longitude
|
||||||
|
double sinLon, cosLon;
|
||||||
|
if (rxy == 0.0) {
|
||||||
|
sinLon = 0.0;
|
||||||
|
cosLon = 1.0;
|
||||||
|
} else {
|
||||||
|
sinLon = mECLoc(eY)/rxy;
|
||||||
|
cosLon = mECLoc(eX)/rxy;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the sin/cos values of the latitude
|
||||||
|
double sinLat, cosLat;
|
||||||
|
if (mRadius == 0.0) {
|
||||||
|
sinLat = 0.0;
|
||||||
|
cosLat = 1.0;
|
||||||
|
} else {
|
||||||
|
sinLat = mECLoc(eZ)/mRadius;
|
||||||
|
cosLat = rxy/mRadius;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the longitude and latitude itself
|
||||||
|
if ( mECLoc( eX ) == 0.0 && mECLoc( eY ) == 0.0 )
|
||||||
|
mLon = 0.0;
|
||||||
|
else
|
||||||
|
mLon = atan2( mECLoc( eY ), mECLoc( eX ) );
|
||||||
|
|
||||||
|
if ( rxy == 0.0 && mECLoc( eZ ) == 0.0 )
|
||||||
|
mLat = 0.0;
|
||||||
|
else
|
||||||
|
mLat = atan2( mECLoc(eZ), rxy );
|
||||||
|
|
||||||
|
// Compute the transform matrices from and to the earth centered frame.
|
||||||
|
// see Durham Chapter 4, problem 1, page 52
|
||||||
|
mTec2l = FGMatrix33( -cosLon*sinLat, -sinLon*sinLat, cosLat,
|
||||||
|
-sinLon , cosLon , 0.0 ,
|
||||||
|
-cosLon*cosLat, -sinLon*cosLat, -sinLat );
|
||||||
|
|
||||||
|
mTl2ec = mTec2l.Transposed();
|
||||||
|
|
||||||
|
// Mark the cached values as valid
|
||||||
|
mCacheValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGLocation::bind(FGPropertyManager* PropertyManager, const string& prefix) const
|
||||||
|
{
|
||||||
|
PropertyManager->Tie(prefix + "lat-gc-rad", (FGLocation*)this,
|
||||||
|
&FGLocation::GetLatitude);
|
||||||
|
PropertyManager->Tie(prefix + "lat-gc-deg", (FGLocation*)this,
|
||||||
|
&FGLocation::GetLatitudeDeg);
|
||||||
|
PropertyManager->Tie(prefix + "long-gc-rad", (FGLocation*)this,
|
||||||
|
&FGLocation::GetLongitude);
|
||||||
|
PropertyManager->Tie(prefix + "long-gc-deg", (FGLocation*)this,
|
||||||
|
&FGLocation::GetLongitudeDeg);
|
||||||
|
PropertyManager->Tie(prefix + "radius-ft", (FGLocation*)this,
|
||||||
|
&FGLocation::GetRadius);
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGLocation::unbind(FGPropertyManager* PropertyManager, const string& prefix) const
|
||||||
|
{
|
||||||
|
PropertyManager->Untie(prefix + "lat-gc-rad");
|
||||||
|
PropertyManager->Untie(prefix + "lat-gc-deg");
|
||||||
|
PropertyManager->Untie(prefix + "long-gc-rad");
|
||||||
|
PropertyManager->Untie(prefix + "long-gc-deg");
|
||||||
|
PropertyManager->Untie(prefix + "radius-ft");
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
} // namespace JSBSim
|
437
src/FDM/JSBSim/FGLocation.h
Normal file
437
src/FDM/JSBSim/FGLocation.h
Normal file
|
@ -0,0 +1,437 @@
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
Header: FGLocation.h
|
||||||
|
Author: Jon S. Berndt, Mathias Froehlich
|
||||||
|
Date started: 04/04/2004
|
||||||
|
|
||||||
|
------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------------
|
||||||
|
------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
|
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
Further information about the GNU General Public License can also be found on
|
||||||
|
the world wide web at http://www.gnu.org.
|
||||||
|
|
||||||
|
HISTORY
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
04/04/2004 MF Created from code previously in the old positions class.
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
SENTRY
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#ifndef FGLOCATION_H
|
||||||
|
#define FGLOCATION_H
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
INCLUDES
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#include "FGJSBBase.h"
|
||||||
|
#include "FGPropertyManager.h"
|
||||||
|
#include "FGColumnVector3.h"
|
||||||
|
#include "FGMatrix33.h"
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
DEFINITIONS
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#define ID_LOCATION "$Id$"
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
FORWARD DECLARATIONS
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
namespace JSBSim {
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
CLASS DOCUMENTATION
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
/** Holds an arbitrary location in the earth centered reference frame.
|
||||||
|
This coordinate frame has its center in the middle of the earth.
|
||||||
|
Its x-axis points from the center of the earth towards a location
|
||||||
|
with zero latitude and longitude on the earths surface. The y-axis
|
||||||
|
points from the center of the earth towards a location with zero
|
||||||
|
latitude and 90deg longitude on the earths surface. The z-axis
|
||||||
|
points from the earths center to the geographic north pole.
|
||||||
|
|
||||||
|
This class provides access functions to set and get the location as
|
||||||
|
either the simple x, y and z values in ft or longitude/latitude and
|
||||||
|
the radial distance of the location from the earth center.
|
||||||
|
|
||||||
|
It is common to associate a parent frame with a location. This
|
||||||
|
frame is usually called the local horizontal frame or simply the local
|
||||||
|
frame. This frame has its x/y plane parallel to the surface of the earth
|
||||||
|
(with the assumption of a spherical earth). The x-axis points
|
||||||
|
towards north, the y-axis points towards east and the z-axis
|
||||||
|
points to the center of the earth.
|
||||||
|
|
||||||
|
Since this frame is determined by the location, this class also
|
||||||
|
provides the rotation matrices required to transform from the
|
||||||
|
earth centered frame to the local horizontal frame and back. There
|
||||||
|
are also conversion functions for conversion of position vectors
|
||||||
|
given in the one frame to positions in the other frame.
|
||||||
|
|
||||||
|
The earth centered reference frame is *NOT* an inertial frame
|
||||||
|
since it rotates with the earth.
|
||||||
|
|
||||||
|
The coordinates in the earth centered frame are the master values.
|
||||||
|
All other values are computed from these master values and are
|
||||||
|
cached as long as the location is changed by access through a
|
||||||
|
non-const member function. Values are cached to improve performance.
|
||||||
|
It is best practice to work with a natural set of master values.
|
||||||
|
Other parameters that are derived from these master values are calculated
|
||||||
|
only when needed, and IF they are needed and calculated, then they are
|
||||||
|
cached (stored and remembered) so they do not need to be re-calculated
|
||||||
|
until the master values they are derived from are themselves changed
|
||||||
|
(and become stale).
|
||||||
|
|
||||||
|
Accuracy and round off:
|
||||||
|
|
||||||
|
Given that we model a vehicle near the earth, the earths surface
|
||||||
|
radius is about 2*10^7, ft and that we use double values for the
|
||||||
|
representation of the location, we have an accuracy of about
|
||||||
|
1e-16*2e7ft/1=2e-9ft left. This should be sufficient for our needs.
|
||||||
|
Note that this is the same relative accuracy we would have when we
|
||||||
|
compute directly with lon/lat/radius. For the radius value this
|
||||||
|
is clear. For the lon/lat pair this is easy to see. Take for
|
||||||
|
example KSFO located at about 37.61deg north 122.35deg west, which
|
||||||
|
corresponds to 0.65642rad north and 2.13541rad west. Both values
|
||||||
|
are of magnitude of about 1. But 1ft corresponds to about
|
||||||
|
1/(2e7*2*pi)=7.9577e-09rad. So the left accuracy with this
|
||||||
|
representation is also about 1*1e-16/7.9577e-09=1.2566e-08 which
|
||||||
|
is of the same magnitude as the representation chosen here.
|
||||||
|
|
||||||
|
The advantage of this representation is that it is a linear space
|
||||||
|
without singularities. The singularities are the north and south
|
||||||
|
pole and most notably the non-steady jump at -pi to pi. It is
|
||||||
|
harder to track this jump correctly especially when we need to
|
||||||
|
work with error norms and derivatives of the equations of motion
|
||||||
|
within the time-stepping code. Also, the rate of change is of the
|
||||||
|
same magnitude for all components in this representation which is
|
||||||
|
an advantage for numerical stability in implicit time-stepping too.
|
||||||
|
|
||||||
|
@see W. C. Durham "Aircraft Dynamics & Control", section 2.2
|
||||||
|
|
||||||
|
@author Mathias Froehlich
|
||||||
|
@version $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
CLASS DECLARATION
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
class FGLocation : virtual FGJSBBase
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
/** Default constructor. */
|
||||||
|
FGLocation() { mCacheValid = false; }
|
||||||
|
|
||||||
|
/** Constructor to set the longitude, latitude and the distance
|
||||||
|
from the center of the earth. */
|
||||||
|
FGLocation(double lon, double lat, double radius);
|
||||||
|
|
||||||
|
/** Copy constructor. */
|
||||||
|
FGLocation(const FGColumnVector3& lv)
|
||||||
|
: mECLoc(lv), mCacheValid(false) {}
|
||||||
|
|
||||||
|
/** Copy constructor. */
|
||||||
|
FGLocation(const FGLocation& l)
|
||||||
|
: mECLoc(l.mECLoc), mCacheValid(l.mCacheValid) {
|
||||||
|
if (!mCacheValid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
mLon = l.mLon;
|
||||||
|
mLat = l.mLat;
|
||||||
|
mRadius = l.mRadius;
|
||||||
|
|
||||||
|
mTl2ec = l.mTl2ec;
|
||||||
|
mTec2l = l.mTec2l;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the longitude.
|
||||||
|
@return the longitude in rad of the location represented with this
|
||||||
|
class instance. The returned values are in the range between
|
||||||
|
-pi <= lon <= pi. Longitude is positive east and negative west. */
|
||||||
|
double GetLongitude() const { ComputeDerived(); return mLon; }
|
||||||
|
|
||||||
|
/** Get the longitude.
|
||||||
|
@return the longitude in deg of the location represented with this
|
||||||
|
class instance. The returned values are in the range between
|
||||||
|
-180 <= lon <= 180. Longitude is positive east and negative west. */
|
||||||
|
double GetLongitudeDeg() const { ComputeDerived(); return radtodeg*mLon; }
|
||||||
|
|
||||||
|
/** Set the longitude.
|
||||||
|
@param longitude Longitude in rad to set.
|
||||||
|
Sets the longitude of the location represented with this class
|
||||||
|
instance to the value of the given argument. The value is meant
|
||||||
|
to be in rad. The latitude and the radius value are preserved
|
||||||
|
with this call with the exception of radius being equal to
|
||||||
|
zero. If the radius is previously set to zero it is changed to be
|
||||||
|
equal to 1.0 past this call. Longitude is positive east and negative west. */
|
||||||
|
void SetLongitude(double longitude);
|
||||||
|
|
||||||
|
/** Get the sine of Longitude. */
|
||||||
|
double GetSinLongitude() const { ComputeDerived(); return -mTec2l(2,1); }
|
||||||
|
|
||||||
|
/** Get the cosine of Longitude. */
|
||||||
|
double GetCosLongitude() const { ComputeDerived(); return mTec2l(2,2); }
|
||||||
|
|
||||||
|
/** Get the latitude.
|
||||||
|
@return the latitude in rad of the location represented with this
|
||||||
|
class instance. The returned values are in the range between
|
||||||
|
-pi/2 <= lon <= pi/2. Latitude is positive north and negative south. */
|
||||||
|
double GetLatitude() const { ComputeDerived(); return mLat; }
|
||||||
|
|
||||||
|
/** Get the latitude.
|
||||||
|
@return the latitude in deg of the location represented with this
|
||||||
|
class instance. The returned values are in the range between
|
||||||
|
-90 <= lon <= 90. Latitude is positive north and negative south. */
|
||||||
|
double GetLatitudeDeg() const { ComputeDerived(); return radtodeg*mLat; }
|
||||||
|
|
||||||
|
/** Set the latitude.
|
||||||
|
@param latitude Latitude in rad to set.
|
||||||
|
Sets the latitude of the location represented with this class
|
||||||
|
instance to the value of the given argument. The value is meant
|
||||||
|
to be in rad. The longitude and the radius value are preserved
|
||||||
|
with this call with the exception of radius being equal to
|
||||||
|
zero. If the radius is previously set to zero it is changed to be
|
||||||
|
equal to 1.0 past this call.
|
||||||
|
Latitude is positive north and negative south.
|
||||||
|
The arguments should be within the bounds of -pi/2 <= lat <= pi/2.
|
||||||
|
The behavior of this function with arguments outside this range is
|
||||||
|
left as an exercise to the gentle reader ... */
|
||||||
|
void SetLatitude(double latitude);
|
||||||
|
|
||||||
|
/** Get the sine of Latitude. */
|
||||||
|
double GetSinLatitude() const { ComputeDerived(); return -mTec2l(3,3); }
|
||||||
|
|
||||||
|
/** Get the cosine of Latitude. */
|
||||||
|
double GetCosLatitude() const { ComputeDerived(); return mTec2l(1,3); }
|
||||||
|
|
||||||
|
/** Get the cosine of Latitude. */
|
||||||
|
double GetTanLatitude() const {
|
||||||
|
ComputeDerived();
|
||||||
|
double cLat = mTec2l(1,3);
|
||||||
|
if (cLat == 0.0)
|
||||||
|
return 0.0;
|
||||||
|
else
|
||||||
|
return -mTec2l(3,3)/cLat;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Get the distance from the center of the earth.
|
||||||
|
@return the distance of the location represented with this class
|
||||||
|
instance to the center of the earth in ft. The radius value is
|
||||||
|
always positive. */
|
||||||
|
double GetRadius() const { ComputeDerived(); return mRadius; }
|
||||||
|
|
||||||
|
/** Set the distance from the center of the earth.
|
||||||
|
@param radius Radius in ft to set.
|
||||||
|
Sets the radius of the location represented with this class
|
||||||
|
instance to the value of the given argument. The value is meant
|
||||||
|
to be in ft. The latitude and longitude values are preserved
|
||||||
|
with this call with the exception of radius being equal to
|
||||||
|
zero. If the radius is previously set to zero, latitude and
|
||||||
|
longitude is set equal to zero past this call.
|
||||||
|
The argument should be positive.
|
||||||
|
The behavior of this function called with a negative argument is
|
||||||
|
left as an exercise to the gentle reader ... */
|
||||||
|
void SetRadius(double radius);
|
||||||
|
|
||||||
|
/** Transform matrix from local horizontal to earth centered frame.
|
||||||
|
Returns a const reference to the rotation matrix of the transform from
|
||||||
|
the local horizontal frame to the earth centered frame. */
|
||||||
|
const FGMatrix33& GetTl2ec(void) const { ComputeDerived(); return mTl2ec; }
|
||||||
|
|
||||||
|
/** Transform matrix from the earth centered to local horizontal frame.
|
||||||
|
Returns a const reference to the rotation matrix of the transform from
|
||||||
|
the earth centered frame to the local horizontal frame. */
|
||||||
|
const FGMatrix33& GetTec2l(void) const { ComputeDerived(); return mTec2l; }
|
||||||
|
|
||||||
|
/** Conversion from Local frame coordinates to a location in the
|
||||||
|
earth centered and fixed frame.
|
||||||
|
@parm lvec Vector in the local horizontal coordinate frame
|
||||||
|
@return The location in the earth centered and fixed frame */
|
||||||
|
FGLocation LocalToLocation(const FGColumnVector3& lvec) const {
|
||||||
|
ComputeDerived(); return mTl2ec*lvec + mECLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Conversion from a location in the earth centered and fixed frame
|
||||||
|
to local horizontal frame coordinates.
|
||||||
|
@parm ecvec Vector in the earth centered and fixed frame
|
||||||
|
@return The vector in the local horizontal coordinate frame */
|
||||||
|
FGColumnVector3 LocationToLocal(const FGColumnVector3& ecvec) const {
|
||||||
|
ComputeDerived(); return mTec2l*(ecvec - mECLoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// For time-stepping, locations have vector properties...
|
||||||
|
|
||||||
|
/** Read access the entries of the vector.
|
||||||
|
@param idx the component index.
|
||||||
|
Return the value of the matrix entry at the given index.
|
||||||
|
Indices are counted starting with 1.
|
||||||
|
Note that the index given in the argument is unchecked. */
|
||||||
|
double operator()(unsigned int idx) const { return Entry(idx); }
|
||||||
|
|
||||||
|
/** Write access the entries of the vector.
|
||||||
|
@param idx the component index.
|
||||||
|
@return a reference to the vector entry at the given index.
|
||||||
|
Indices are counted starting with 1.
|
||||||
|
Note that the index given in the argument is unchecked. */
|
||||||
|
double& operator()(unsigned int idx) { return Entry(idx); }
|
||||||
|
|
||||||
|
/** Read access the entries of the vector.
|
||||||
|
@param idx the component index.
|
||||||
|
@return the value of the matrix entry at the given index.
|
||||||
|
Indices are counted starting with 1.
|
||||||
|
This function is just a shortcut for the @ref double
|
||||||
|
operator()(unsigned int idx) const function. It is
|
||||||
|
used internally to access the elements in a more convenient way.
|
||||||
|
Note that the index given in the argument is unchecked. */
|
||||||
|
double Entry(unsigned int idx) const { return mECLoc.Entry(idx); }
|
||||||
|
|
||||||
|
/** Write access the entries of the vector.
|
||||||
|
@param idx the component index.
|
||||||
|
@return a reference to the vector entry at the given index.
|
||||||
|
Indices are counted starting with 1.
|
||||||
|
This function is just a shortcut for the double&
|
||||||
|
operator()(unsigned int idx) function. It is
|
||||||
|
used internally to access the elements in a more convenient way.
|
||||||
|
Note that the index given in the argument is unchecked. */
|
||||||
|
double& Entry(unsigned int idx) {
|
||||||
|
mCacheValid = false; return mECLoc.Entry(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
const FGLocation& operator=(const FGLocation& l) {
|
||||||
|
mECLoc = l.mECLoc;
|
||||||
|
mCacheValid = l.mCacheValid;
|
||||||
|
if (!mCacheValid)
|
||||||
|
return *this;
|
||||||
|
|
||||||
|
mLon = l.mLon;
|
||||||
|
mLat = l.mLat;
|
||||||
|
mRadius = l.mRadius;
|
||||||
|
|
||||||
|
mTl2ec = l.mTl2ec;
|
||||||
|
mTec2l = l.mTec2l;
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
bool operator==(const FGLocation& l) const {
|
||||||
|
return mECLoc == l.mECLoc;
|
||||||
|
}
|
||||||
|
bool operator!=(const FGLocation& l) const { return ! operator==(l); }
|
||||||
|
const FGLocation& operator+=(const FGLocation &l) {
|
||||||
|
mCacheValid = false;
|
||||||
|
mECLoc += l.mECLoc;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
const FGLocation& operator-=(const FGLocation &l) {
|
||||||
|
mCacheValid = false;
|
||||||
|
mECLoc -= l.mECLoc;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
const FGLocation& operator*=(double scalar) {
|
||||||
|
mCacheValid = false;
|
||||||
|
mECLoc *= scalar;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
const FGLocation& operator/=(double scalar) {
|
||||||
|
return operator*=(1.0/scalar);
|
||||||
|
}
|
||||||
|
FGLocation operator+(const FGLocation& l) const {
|
||||||
|
return FGLocation(mECLoc + l.mECLoc);
|
||||||
|
}
|
||||||
|
FGLocation operator-(const FGLocation& l) const {
|
||||||
|
return FGLocation(mECLoc - l.mECLoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
FGLocation operator*(double scalar) const {
|
||||||
|
return FGLocation(scalar*mECLoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Cast to a simple 3d vector */
|
||||||
|
operator const FGColumnVector3&() const {
|
||||||
|
return mECLoc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Ties into the property tree.
|
||||||
|
Ties the variables represented by this class into the property tree. */
|
||||||
|
void bind(FGPropertyManager*, const string&) const;
|
||||||
|
|
||||||
|
/** Remove from property tree.
|
||||||
|
Unties the variables represented by this class into the property tree. */
|
||||||
|
void unbind(FGPropertyManager*, const string&) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** Computation of derived values.
|
||||||
|
This function re-computes the derived values like lat/lon and
|
||||||
|
transformation matrices. It does this unconditionally. */
|
||||||
|
void ComputeDerivedUnconditional(void) const;
|
||||||
|
|
||||||
|
/** Computation of derived values.
|
||||||
|
This function checks if the derived values like lat/lon and
|
||||||
|
transformation matrices are already computed. If so, it
|
||||||
|
returns. If they need to be computed this is done here. */
|
||||||
|
void ComputeDerived(void) const {
|
||||||
|
if (!mCacheValid)
|
||||||
|
ComputeDerivedUnconditional();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The coordinates in the earth centered frame. This is the master copy.
|
||||||
|
The coordinate frame has its center in the middle of the earth.
|
||||||
|
Its x-axis points from the center of the earth towards a
|
||||||
|
location with zero latitude and longitude on the earths
|
||||||
|
surface. The y-axis points from the center of the earth towards a
|
||||||
|
location with zero latitude and 90deg longitude on the earths
|
||||||
|
surface. The z-axis points from the earths center to the
|
||||||
|
geographic north pole.
|
||||||
|
@see W. C. Durham "Aircraft Dynamics & Control", section 2.2 */
|
||||||
|
FGColumnVector3 mECLoc;
|
||||||
|
|
||||||
|
/** The cached lon/lat/radius values. */
|
||||||
|
mutable double mLon;
|
||||||
|
mutable double mLat;
|
||||||
|
mutable double mRadius;
|
||||||
|
|
||||||
|
/** The cached rotation matrices from and to the associated frames. */
|
||||||
|
mutable FGMatrix33 mTl2ec;
|
||||||
|
mutable FGMatrix33 mTec2l;
|
||||||
|
|
||||||
|
/** A data validity flag.
|
||||||
|
This class implements caching of the derived values like the
|
||||||
|
orthogonal rotation matrices or the lon/lat/radius values. For caching we
|
||||||
|
carry a flag which signals if the values are valid or not.
|
||||||
|
The C++ keyword "mutable" tells the compiler that the data member is
|
||||||
|
allowed to change during a const member function. */
|
||||||
|
mutable bool mCacheValid;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Scalar multiplication.
|
||||||
|
|
||||||
|
@param scalar scalar value to multiply with.
|
||||||
|
@param l Vector to multiply.
|
||||||
|
|
||||||
|
Multiply the Vector with a scalar value. */
|
||||||
|
inline FGLocation operator*(double scalar, const FGLocation& l)
|
||||||
|
{
|
||||||
|
return l.operator*(scalar);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace JSBSim
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
#endif
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
FUNCTIONAL DESCRIPTION
|
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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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).
|
||||||
|
|
|
@ -1,367 +0,0 @@
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
Module: FGPosition.cpp
|
|
||||||
Author: Jon S. Berndt
|
|
||||||
Date started: 01/05/99
|
|
||||||
Purpose: Integrate the EOM to determine instantaneous position
|
|
||||||
Called by: FGFDMExec
|
|
||||||
|
|
||||||
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
|
||||||
Foundation; either version 2 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
|
||||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
|
|
||||||
Further information about the GNU General Public License can also be found on
|
|
||||||
the world wide web at http://www.gnu.org.
|
|
||||||
|
|
||||||
FUNCTIONAL DESCRIPTION
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
This class encapsulates the integration of rates and accelerations to get the
|
|
||||||
current position of the aircraft.
|
|
||||||
|
|
||||||
HISTORY
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
01/05/99 JSB Created
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
COMMENTS, REFERENCES, and NOTES
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
[1] Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
|
|
||||||
Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
|
|
||||||
School, January 1994
|
|
||||||
[2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
|
|
||||||
JSC 12960, July 1977
|
|
||||||
[3] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
|
|
||||||
NASA-Ames", NASA CR-2497, January 1975
|
|
||||||
[4] Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
|
|
||||||
Wiley & Sons, 1979 ISBN 0-471-03032-5
|
|
||||||
[5] Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
|
|
||||||
1982 ISBN 0-471-08936-2
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
INCLUDES
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#ifdef FGFS
|
|
||||||
# include <simgear/compiler.h>
|
|
||||||
# ifdef SG_HAVE_STD_INCLUDES
|
|
||||||
# include <cmath>
|
|
||||||
# include <iomanip>
|
|
||||||
# else
|
|
||||||
# include <math.h>
|
|
||||||
# include <iomanip.h>
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# if defined(sgi) && !defined(__GNUC__)
|
|
||||||
# include <math.h>
|
|
||||||
# if (_COMPILER_VERSION < 740)
|
|
||||||
# include <iomanip.h>
|
|
||||||
# else
|
|
||||||
# include <iomanip>
|
|
||||||
# endif
|
|
||||||
# else
|
|
||||||
# include <cmath>
|
|
||||||
# include <iomanip>
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "FGPosition.h"
|
|
||||||
#include "FGState.h"
|
|
||||||
#include "FGFDMExec.h"
|
|
||||||
#include "FGAircraft.h"
|
|
||||||
#include "FGMassBalance.h"
|
|
||||||
#include "FGTranslation.h"
|
|
||||||
#include "FGRotation.h"
|
|
||||||
#include "FGInertial.h"
|
|
||||||
#include "FGPropertyManager.h"
|
|
||||||
|
|
||||||
namespace JSBSim {
|
|
||||||
|
|
||||||
static const char *IdSrc = "$Id$";
|
|
||||||
static const char *IdHdr = ID_POSITION;
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
CLASS IMPLEMENTATION
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
FGPosition::FGPosition(FGFDMExec* fdmex) : FGModel(fdmex)
|
|
||||||
{
|
|
||||||
Name = "FGPosition";
|
|
||||||
LongitudeDot = LatitudeDot = RadiusDot = 0.0;
|
|
||||||
|
|
||||||
for (int i=0;i<4;i++) {
|
|
||||||
LatitudeDot_prev[i] = 0.0;
|
|
||||||
LongitudeDot_prev[i] = 0.0;
|
|
||||||
RadiusDot_prev[i] = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
vVRPoffset.InitMatrix();
|
|
||||||
|
|
||||||
Longitude = Latitude = 0.0;
|
|
||||||
LongitudeVRP = LatitudeVRP = 0.0;
|
|
||||||
gamma = Vt = Vground = 0.0;
|
|
||||||
hoverbmac = hoverbcg = 0.0;
|
|
||||||
psigt = 0.0;
|
|
||||||
bind();
|
|
||||||
Debug(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
FGPosition::~FGPosition(void)
|
|
||||||
{
|
|
||||||
unbind();
|
|
||||||
Debug(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
bool FGPosition::InitModel(void)
|
|
||||||
{
|
|
||||||
FGModel::InitModel();
|
|
||||||
|
|
||||||
h = 3.0; // Est. height of aircraft cg off runway
|
|
||||||
SeaLevelRadius = Inertial->RefRadius(); // For initialization ONLY
|
|
||||||
Radius = SeaLevelRadius + h;
|
|
||||||
RunwayRadius = SeaLevelRadius;
|
|
||||||
DistanceAGL = Radius - RunwayRadius; // Geocentric
|
|
||||||
vRunwayNormal(3) = -1.0; // Initialized for standalone mode
|
|
||||||
b = 1;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
/*
|
|
||||||
Purpose: Called on a schedule to perform Positioning algorithms
|
|
||||||
Notes: [TP] Make sure that -Vt <= hdot <= Vt, which, of course, should always
|
|
||||||
be the case
|
|
||||||
[JB] Run in standalone mode, SeaLevelRadius will be reference radius.
|
|
||||||
In FGFS, SeaLevelRadius is stuffed from FGJSBSim in JSBSim.cxx each pass.
|
|
||||||
*/
|
|
||||||
|
|
||||||
bool FGPosition::Run(void)
|
|
||||||
{
|
|
||||||
double cosLat;
|
|
||||||
double hdot_Vt;
|
|
||||||
|
|
||||||
if (!FGModel::Run()) {
|
|
||||||
GetState();
|
|
||||||
|
|
||||||
Vground = sqrt( vVel(eNorth)*vVel(eNorth) + vVel(eEast)*vVel(eEast) );
|
|
||||||
|
|
||||||
if (vVel(eNorth) == 0) psigt = 0;
|
|
||||||
else psigt = atan2(vVel(eEast), vVel(eNorth));
|
|
||||||
|
|
||||||
if (psigt < 0.0) psigt += 2*M_PI;
|
|
||||||
|
|
||||||
Radius = h + SeaLevelRadius;
|
|
||||||
|
|
||||||
cosLat = cos(Latitude);
|
|
||||||
if (cosLat != 0) LongitudeDot = vVel(eEast) / (Radius * cosLat);
|
|
||||||
LatitudeDot = vVel(eNorth) / Radius;
|
|
||||||
RadiusDot = -vVel(eDown);
|
|
||||||
|
|
||||||
Longitude += State->Integrate(FGState::TRAPZ, dt*rate, LongitudeDot, LongitudeDot_prev);
|
|
||||||
Latitude += State->Integrate(FGState::TRAPZ, dt*rate, LatitudeDot, LatitudeDot_prev);
|
|
||||||
Radius += State->Integrate(FGState::TRAPZ, dt*rate, RadiusDot, RadiusDot_prev);
|
|
||||||
|
|
||||||
h = Radius - SeaLevelRadius; // Geocentric
|
|
||||||
|
|
||||||
vVRPoffset = State->GetTb2l() * MassBalance->StructuralToBody(Aircraft->GetXYZvrp());
|
|
||||||
|
|
||||||
// vVRP - the vector to the Visual Reference Point - now contains the
|
|
||||||
// offset from the CG to the VRP, in units of feet, in the Local coordinate
|
|
||||||
// frame, where X points north, Y points East, and Z points down. This needs
|
|
||||||
// to be converted to Lat/Lon/Alt, now.
|
|
||||||
|
|
||||||
if (cosLat != 0)
|
|
||||||
LongitudeVRP = vVRPoffset(eEast) / (Radius * cosLat) + Longitude;
|
|
||||||
|
|
||||||
LatitudeVRP = vVRPoffset(eNorth) / Radius + Latitude;
|
|
||||||
hVRP = h - vVRPoffset(eDown);
|
|
||||||
/*
|
|
||||||
cout << "Lat/Lon/Alt : " << Latitude << " / " << Longitude << " / " << h << endl;
|
|
||||||
cout << "Lat/Lon/Alt VRP: " << LatitudeVRP << " / " << LongitudeVRP << " / " << hVRP << endl << endl;
|
|
||||||
*/
|
|
||||||
DistanceAGL = Radius - RunwayRadius; // Geocentric
|
|
||||||
|
|
||||||
hoverbcg = DistanceAGL/b;
|
|
||||||
|
|
||||||
vMac = State->GetTb2l()*MassBalance->StructuralToBody(Aircraft->GetXYZrp());
|
|
||||||
hoverbmac = (DistanceAGL + vMac(3)) / b;
|
|
||||||
|
|
||||||
if (Vt > 0) {
|
|
||||||
hdot_Vt = RadiusDot/Vt;
|
|
||||||
if (fabs(hdot_Vt) <= 1) gamma = asin(hdot_Vt);
|
|
||||||
} else {
|
|
||||||
gamma = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
void FGPosition::GetState(void)
|
|
||||||
{
|
|
||||||
dt = State->Getdt();
|
|
||||||
|
|
||||||
Vt = Translation->GetVt();
|
|
||||||
vVel = State->GetTb2l() * Translation->GetUVW();
|
|
||||||
vVelDot = State->GetTb2l() * Translation->GetUVWdot();
|
|
||||||
|
|
||||||
b = Aircraft->GetWingSpan();
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
void FGPosition::Seth(double tt)
|
|
||||||
{
|
|
||||||
h = tt;
|
|
||||||
Radius = h + SeaLevelRadius;
|
|
||||||
DistanceAGL = Radius - RunwayRadius; // Geocentric
|
|
||||||
hoverbcg = DistanceAGL/b;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
void FGPosition::SetDistanceAGL(double tt)
|
|
||||||
{
|
|
||||||
DistanceAGL=tt;
|
|
||||||
Radius = RunwayRadius + DistanceAGL;
|
|
||||||
h = Radius - SeaLevelRadius;
|
|
||||||
hoverbcg = DistanceAGL/b;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
void FGPosition::bind(void)
|
|
||||||
{
|
|
||||||
PropertyManager->Tie("velocities/v-north-fps", this,
|
|
||||||
&FGPosition::GetVn);
|
|
||||||
PropertyManager->Tie("velocities/v-east-fps", this,
|
|
||||||
&FGPosition::GetVe);
|
|
||||||
PropertyManager->Tie("velocities/v-down-fps", this,
|
|
||||||
&FGPosition::GetVd);
|
|
||||||
PropertyManager->Tie("velocities/vg-fps", this,
|
|
||||||
&FGPosition::GetVground);
|
|
||||||
PropertyManager->Tie("flight-path/psi-gt-rad", this,
|
|
||||||
&FGPosition::GetGroundTrack);
|
|
||||||
PropertyManager->Tie("position/h-sl-ft", this,
|
|
||||||
&FGPosition::Geth,
|
|
||||||
&FGPosition::Seth,
|
|
||||||
true);
|
|
||||||
PropertyManager->Tie("velocities/h-dot-fps", this,
|
|
||||||
&FGPosition::Gethdot);
|
|
||||||
PropertyManager->Tie("position/lat-gc-rad", this,
|
|
||||||
&FGPosition::GetLatitude,
|
|
||||||
&FGPosition::SetLatitude);
|
|
||||||
PropertyManager->Tie("position/lat-dot-gc-rad", this,
|
|
||||||
&FGPosition::GetLatitudeDot);
|
|
||||||
PropertyManager->Tie("position/long-gc-rad", this,
|
|
||||||
&FGPosition::GetLongitude,
|
|
||||||
&FGPosition::SetLongitude,
|
|
||||||
true);
|
|
||||||
PropertyManager->Tie("position/long-dot-gc-rad", this,
|
|
||||||
&FGPosition::GetLongitudeDot);
|
|
||||||
PropertyManager->Tie("metrics/runway-radius", this,
|
|
||||||
&FGPosition::GetRunwayRadius,
|
|
||||||
&FGPosition::SetRunwayRadius);
|
|
||||||
PropertyManager->Tie("position/h-agl-ft", this,
|
|
||||||
&FGPosition::GetDistanceAGL,
|
|
||||||
&FGPosition::SetDistanceAGL);
|
|
||||||
PropertyManager->Tie("position/radius-to-vehicle-ft", this,
|
|
||||||
&FGPosition::GetRadius);
|
|
||||||
PropertyManager->Tie("flight-path/gamma-rad", this,
|
|
||||||
&FGPosition::GetGamma,
|
|
||||||
&FGPosition::SetGamma);
|
|
||||||
PropertyManager->Tie("aero/h_b-cg-ft", this,
|
|
||||||
&FGPosition::GetHOverBCG);
|
|
||||||
PropertyManager->Tie("aero/h_b-mac-ft", this,
|
|
||||||
&FGPosition::GetHOverBMAC);
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
void FGPosition::unbind(void)
|
|
||||||
{
|
|
||||||
PropertyManager->Untie("velocities/v-north-fps");
|
|
||||||
PropertyManager->Untie("velocities/v-east-fps");
|
|
||||||
PropertyManager->Untie("velocities/v-down-fps");
|
|
||||||
PropertyManager->Untie("velocities/vg-fps");
|
|
||||||
PropertyManager->Untie("flight-path/psi-gt-rad");
|
|
||||||
PropertyManager->Untie("position/h-sl-ft");
|
|
||||||
PropertyManager->Untie("velocities/h-dot-fps");
|
|
||||||
PropertyManager->Untie("position/lat-gc-rad");
|
|
||||||
PropertyManager->Untie("position/lat-dot-gc-rad");
|
|
||||||
PropertyManager->Untie("position/long-gc-rad");
|
|
||||||
PropertyManager->Untie("position/long-dot-gc-rad");
|
|
||||||
PropertyManager->Untie("metrics/runway-radius");
|
|
||||||
PropertyManager->Untie("position/h-agl-ft");
|
|
||||||
PropertyManager->Untie("position/radius-to-vehicle-ft");
|
|
||||||
PropertyManager->Untie("flight-path/gamma-rad");
|
|
||||||
PropertyManager->Untie("aero/h_b-cg-ft");
|
|
||||||
PropertyManager->Untie("aero/h_b-mac-ft");
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
// The bitmasked value choices are as follows:
|
|
||||||
// unset: In this case (the default) JSBSim would only print
|
|
||||||
// out the normally expected messages, essentially echoing
|
|
||||||
// the config files as they are read. If the environment
|
|
||||||
// variable is not set, debug_lvl is set to 1 internally
|
|
||||||
// 0: This requests JSBSim not to output any messages
|
|
||||||
// whatsoever.
|
|
||||||
// 1: This value explicity requests the normal JSBSim
|
|
||||||
// startup messages
|
|
||||||
// 2: This value asks for a message to be printed out when
|
|
||||||
// a class is instantiated
|
|
||||||
// 4: When this value is set, a message is displayed when a
|
|
||||||
// FGModel object executes its Run() method
|
|
||||||
// 8: When this value is set, various runtime state variables
|
|
||||||
// are printed out periodically
|
|
||||||
// 16: When set various parameters are sanity checked and
|
|
||||||
// a message is printed out when they go out of bounds
|
|
||||||
|
|
||||||
void FGPosition::Debug(int from)
|
|
||||||
{
|
|
||||||
if (debug_lvl <= 0) return;
|
|
||||||
|
|
||||||
if (debug_lvl & 1) { // Standard console startup message output
|
|
||||||
if (from == 0) { // Constructor
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
|
||||||
if (from == 0) cout << "Instantiated: FGPosition" << endl;
|
|
||||||
if (from == 1) cout << "Destroyed: FGPosition" << endl;
|
|
||||||
}
|
|
||||||
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
|
|
||||||
}
|
|
||||||
if (debug_lvl & 8 ) { // Runtime state variables
|
|
||||||
}
|
|
||||||
if (debug_lvl & 16) { // Sanity checking
|
|
||||||
}
|
|
||||||
if (debug_lvl & 64) {
|
|
||||||
if (from == 0) { // Constructor
|
|
||||||
cout << IdSrc << endl;
|
|
||||||
cout << IdHdr << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,154 +0,0 @@
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
Header: FGPosition.h
|
|
||||||
Author: Jon S. Berndt
|
|
||||||
Date started: 1/5/99
|
|
||||||
|
|
||||||
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
|
||||||
Foundation; either version 2 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
|
||||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
|
|
||||||
Further information about the GNU General Public License can also be found on
|
|
||||||
the world wide web at http://www.gnu.org.
|
|
||||||
|
|
||||||
HISTORY
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
01/05/99 JSB Created
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
SENTRY
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#ifndef FGPOSITION_H
|
|
||||||
#define FGPOSITION_H
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
INCLUDES
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#include "FGModel.h"
|
|
||||||
#include "FGColumnVector3.h"
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
DEFINITIONS
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#define ID_POSITION "$Id$"
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
FORWARD DECLARATIONS
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
namespace JSBSim {
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
CLASS DOCUMENTATION
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
/** Models the lateral and longitudinal translational EOM.
|
|
||||||
@author Jon S. Berndt
|
|
||||||
@version $Id$
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
CLASS DECLARATION
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
class FGPosition : public FGModel {
|
|
||||||
public:
|
|
||||||
/** Constructor
|
|
||||||
@param Executive a pointer to the parent executive object */
|
|
||||||
FGPosition(FGFDMExec* Executive);
|
|
||||||
|
|
||||||
/// Destructor
|
|
||||||
~FGPosition();
|
|
||||||
|
|
||||||
bool InitModel(void);
|
|
||||||
|
|
||||||
/** Runs the Position model; called by the Executive
|
|
||||||
@see JSBSim.cpp documentation
|
|
||||||
@return false if no error */
|
|
||||||
bool Run(void);
|
|
||||||
|
|
||||||
inline FGColumnVector3& GetVel(void) { return vVel; }
|
|
||||||
inline FGColumnVector3& GetVelDot(void) { return vVelDot; }
|
|
||||||
inline double GetVn(void) const { return vVel(eX); }
|
|
||||||
inline double GetVe(void) const { return vVel(eY); }
|
|
||||||
inline double GetVd(void) const { return vVel(eZ); }
|
|
||||||
inline double GetVground(void) const { return Vground; }
|
|
||||||
inline double GetGroundTrack(void) const { return psigt; }
|
|
||||||
inline double Geth(void) const { return h; }
|
|
||||||
inline double GethVRP(void) const { return hVRP; }
|
|
||||||
inline double Gethdot(void) const { return RadiusDot; }
|
|
||||||
inline double GetLatitude(void) const { return Latitude; }
|
|
||||||
inline double GetLatitudeVRP(void) const { return LatitudeVRP; }
|
|
||||||
inline double GetLatitudeDot(void) const { return LatitudeDot; }
|
|
||||||
inline double GetLongitude(void) const { return Longitude; }
|
|
||||||
inline double GetLongitudeVRP(void) const { return LongitudeVRP; }
|
|
||||||
inline double GetLongitudeDot(void) const { return LongitudeDot; }
|
|
||||||
inline double GetRunwayRadius(void) const { return RunwayRadius; }
|
|
||||||
inline double GetDistanceAGL(void) const { return DistanceAGL; }
|
|
||||||
inline double GetRadius(void) const { return Radius; }
|
|
||||||
inline FGColumnVector3& GetRunwayNormal(void) { return vRunwayNormal; }
|
|
||||||
|
|
||||||
inline double GetGamma(void) const { return gamma; }
|
|
||||||
inline void SetGamma(double tt) { gamma = tt; }
|
|
||||||
inline double GetHOverBCG(void) const { return hoverbcg; }
|
|
||||||
inline double GetHOverBMAC(void) const { return hoverbmac; }
|
|
||||||
void SetvVel(const FGColumnVector3& v) { vVel = v; }
|
|
||||||
void SetLatitude(double tt) { Latitude = tt; }
|
|
||||||
void SetLongitude(double tt) { Longitude = tt; }
|
|
||||||
void Seth(double tt);
|
|
||||||
void SetRunwayRadius(double tt) { RunwayRadius = tt; }
|
|
||||||
void SetSeaLevelRadius(double tt) { SeaLevelRadius = tt;}
|
|
||||||
void SetDistanceAGL(double tt);
|
|
||||||
inline void SetRunwayNormal(double fgx, double fgy, double fgz ) {
|
|
||||||
vRunwayNormal << fgx << fgy << fgz;
|
|
||||||
}
|
|
||||||
void SetVRP(FGColumnVector3& vrp) {vVRP = vrp;}
|
|
||||||
|
|
||||||
void bind(void);
|
|
||||||
void unbind(void);
|
|
||||||
|
|
||||||
private:
|
|
||||||
FGColumnVector3 vVel;
|
|
||||||
FGColumnVector3 vVelDot;
|
|
||||||
FGColumnVector3 vRunwayNormal;
|
|
||||||
FGColumnVector3 vVRP;
|
|
||||||
FGColumnVector3 vVRPoffset;
|
|
||||||
FGColumnVector3 vMac;
|
|
||||||
|
|
||||||
double Radius, h, hVRP;
|
|
||||||
double LatitudeDot, LongitudeDot, RadiusDot;
|
|
||||||
double LatitudeDot_prev[4], LongitudeDot_prev[4], RadiusDot_prev[4];
|
|
||||||
double Longitude, Latitude;
|
|
||||||
double LongitudeVRP, LatitudeVRP;
|
|
||||||
double dt;
|
|
||||||
double RunwayRadius;
|
|
||||||
double DistanceAGL;
|
|
||||||
double SeaLevelRadius;
|
|
||||||
double gamma;
|
|
||||||
double Vt, Vground;
|
|
||||||
double hoverbcg,hoverbmac,b;
|
|
||||||
|
|
||||||
double psigt;
|
|
||||||
|
|
||||||
void GetState(void);
|
|
||||||
void Debug(int from);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
#endif
|
|
||||||
|
|
380
src/FDM/JSBSim/FGPropagate.cpp
Normal file
380
src/FDM/JSBSim/FGPropagate.cpp
Normal file
|
@ -0,0 +1,380 @@
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
Module: FGPropagate.cpp
|
||||||
|
Author: Jon S. Berndt
|
||||||
|
Date started: 01/05/99
|
||||||
|
Purpose: Integrate the EOM to determine instantaneous position
|
||||||
|
Called by: FGFDMExec
|
||||||
|
|
||||||
|
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
|
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
Further information about the GNU General Public License can also be found on
|
||||||
|
the world wide web at http://www.gnu.org.
|
||||||
|
|
||||||
|
FUNCTIONAL DESCRIPTION
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
This class encapsulates the integration of rates and accelerations to get the
|
||||||
|
current position of the aircraft.
|
||||||
|
|
||||||
|
HISTORY
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
01/05/99 JSB Created
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
COMMENTS, REFERENCES, and NOTES
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
[1] Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
|
||||||
|
Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
|
||||||
|
School, January 1994
|
||||||
|
[2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
|
||||||
|
JSC 12960, July 1977
|
||||||
|
[3] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
|
||||||
|
NASA-Ames", NASA CR-2497, January 1975
|
||||||
|
[4] Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
|
||||||
|
Wiley & Sons, 1979 ISBN 0-471-03032-5
|
||||||
|
[5] Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
|
||||||
|
1982 ISBN 0-471-08936-2
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
INCLUDES
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#ifdef FGFS
|
||||||
|
# include <simgear/compiler.h>
|
||||||
|
# ifdef SG_HAVE_STD_INCLUDES
|
||||||
|
# include <cmath>
|
||||||
|
# include <iomanip>
|
||||||
|
# else
|
||||||
|
# include <math.h>
|
||||||
|
# include <iomanip.h>
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
# if defined(sgi) && !defined(__GNUC__)
|
||||||
|
# include <math.h>
|
||||||
|
# if (_COMPILER_VERSION < 740)
|
||||||
|
# include <iomanip.h>
|
||||||
|
# else
|
||||||
|
# include <iomanip>
|
||||||
|
# endif
|
||||||
|
# else
|
||||||
|
# include <cmath>
|
||||||
|
# include <iomanip>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "FGPropagate.h"
|
||||||
|
#include "FGState.h"
|
||||||
|
#include "FGFDMExec.h"
|
||||||
|
#include "FGAircraft.h"
|
||||||
|
#include "FGMassBalance.h"
|
||||||
|
#include "FGInertial.h"
|
||||||
|
#include "FGPropertyManager.h"
|
||||||
|
|
||||||
|
namespace JSBSim {
|
||||||
|
|
||||||
|
static const char *IdSrc = "$Id$";
|
||||||
|
static const char *IdHdr = ID_PROPAGATE;
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
CLASS IMPLEMENTATION
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
FGPropagate::FGPropagate(FGFDMExec* fdmex) : FGModel(fdmex)
|
||||||
|
{
|
||||||
|
Name = "FGPropagate";
|
||||||
|
|
||||||
|
bind();
|
||||||
|
Debug(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
FGPropagate::~FGPropagate(void)
|
||||||
|
{
|
||||||
|
unbind();
|
||||||
|
Debug(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
bool FGPropagate::InitModel(void)
|
||||||
|
{
|
||||||
|
FGModel::InitModel();
|
||||||
|
|
||||||
|
SeaLevelRadius = Inertial->RefRadius(); // For initialization ONLY
|
||||||
|
RunwayRadius = SeaLevelRadius;
|
||||||
|
|
||||||
|
VState.vLocation.SetRadius( SeaLevelRadius + 4.0 );
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
|
||||||
|
{
|
||||||
|
SeaLevelRadius = FGIC->GetSeaLevelRadiusFtIC();
|
||||||
|
RunwayRadius = FGIC->GetSeaLevelRadiusFtIC() + FGIC->GetTerrainAltitudeFtIC();
|
||||||
|
|
||||||
|
// Set the position lat/lon/radius
|
||||||
|
VState.vLocation = FGLocation( FGIC->GetLongitudeRadIC(),
|
||||||
|
FGIC->GetLatitudeRadIC(),
|
||||||
|
FGIC->GetAltitudeFtIC() + FGIC->GetSeaLevelRadiusFtIC() );
|
||||||
|
|
||||||
|
// Set the Orientation from the euler angles
|
||||||
|
VState.vQtrn = FGQuaternion( FGIC->GetPhiRadIC(),
|
||||||
|
FGIC->GetThetaRadIC(),
|
||||||
|
FGIC->GetPsiRadIC() );
|
||||||
|
|
||||||
|
// Set the velocities in the instantaneus body frame
|
||||||
|
VState.vUVW = FGColumnVector3( FGIC->GetUBodyFpsIC(),
|
||||||
|
FGIC->GetVBodyFpsIC(),
|
||||||
|
FGIC->GetWBodyFpsIC() );
|
||||||
|
|
||||||
|
// Set the angular velocities in the instantaneus body frame.
|
||||||
|
VState.vPQR = FGColumnVector3( FGIC->GetPRadpsIC(),
|
||||||
|
FGIC->GetQRadpsIC(),
|
||||||
|
FGIC->GetRRadpsIC() );
|
||||||
|
|
||||||
|
// Compute some derived values.
|
||||||
|
vVel = VState.vQtrn.GetTInv()*VState.vUVW;
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
/*
|
||||||
|
Purpose: Called on a schedule to perform EOM integration
|
||||||
|
Notes: [JB] Run in standalone mode, SeaLevelRadius will be reference radius.
|
||||||
|
In FGFS, SeaLevelRadius is stuffed from FGJSBSim in JSBSim.cxx each pass.
|
||||||
|
|
||||||
|
At the top of this Run() function, see several "shortcuts" (or, aliases) being
|
||||||
|
set up for use later, rather than using the longer class->function() notation.
|
||||||
|
|
||||||
|
Here, propagation of state is done using a simple explicit Euler scheme (see the
|
||||||
|
bottom of the function). This propagation is done using the current state values
|
||||||
|
and current derivatives. Based on these values we compute an approximation to the
|
||||||
|
state values for (now + dt).
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
bool FGPropagate::Run(void)
|
||||||
|
{
|
||||||
|
if (FGModel::Run()) return true; // Fast return if we have nothing to do ...
|
||||||
|
|
||||||
|
double dt = State->Getdt()*rate; // The 'stepsize'
|
||||||
|
const FGColumnVector3 omega( 0.0, 0.0, Inertial->omega() ); // earth rotation
|
||||||
|
const FGColumnVector3& vForces = Aircraft->GetForces(); // current forces
|
||||||
|
const FGColumnVector3& vMoments = Aircraft->GetMoments(); // current moments
|
||||||
|
|
||||||
|
double mass = MassBalance->GetMass(); // mass
|
||||||
|
const FGMatrix33& J = MassBalance->GetJ(); // inertia matrix
|
||||||
|
const FGMatrix33& Jinv = MassBalance->GetJinv(); // inertia matrix inverse
|
||||||
|
double r = GetRadius(); // radius
|
||||||
|
if (r == 0.0) {cerr << "radius = 0 !" << endl; r = 1e-16;} // radius check
|
||||||
|
double rInv = 1.0/r;
|
||||||
|
FGColumnVector3 gAccel( 0.0, 0.0, Inertial->GetGAccel(r) );
|
||||||
|
|
||||||
|
// The rotation matrices:
|
||||||
|
const FGMatrix33& Tl2b = GetTl2b(); // local to body frame
|
||||||
|
const FGMatrix33& Tb2l = GetTb2l(); // body to local frame
|
||||||
|
const FGMatrix33& Tec2l = VState.vLocation.GetTec2l(); // earth centered to local frame
|
||||||
|
const FGMatrix33& Tl2ec = VState.vLocation.GetTl2ec(); // local to earth centered frame
|
||||||
|
|
||||||
|
// Inertial angular velocity measured in the body frame.
|
||||||
|
const FGColumnVector3 pqri = VState.vPQR + Tl2b*(Tec2l*omega);
|
||||||
|
|
||||||
|
// Compute vehicle velocity wrt EC frame, expressed in Local horizontal frame.
|
||||||
|
vVel = Tb2l * VState.vUVW;
|
||||||
|
|
||||||
|
// First compute the time derivatives of the vehicle state values:
|
||||||
|
|
||||||
|
// Compute body frame rotational accelerations based on the current body moments
|
||||||
|
vPQRdot = Jinv*(vMoments - pqri*(J*pqri));
|
||||||
|
|
||||||
|
// Compute body frame accelerations based on the current body forces
|
||||||
|
vUVWdot = VState.vUVW*VState.vPQR + vForces/mass;
|
||||||
|
|
||||||
|
// Centrifugal acceleration.
|
||||||
|
FGColumnVector3 ecVel = Tl2ec*vVel;
|
||||||
|
FGColumnVector3 ace = 2.0*omega*ecVel;
|
||||||
|
vUVWdot -= Tl2b*(Tec2l*ace);
|
||||||
|
|
||||||
|
// Coriolis acceleration.
|
||||||
|
FGColumnVector3 aeec = omega*(omega*VState.vLocation);
|
||||||
|
vUVWdot -= Tl2b*(Tec2l*aeec);
|
||||||
|
|
||||||
|
// Gravitation accel
|
||||||
|
vUVWdot += Tl2b*gAccel;
|
||||||
|
|
||||||
|
// Compute vehicle velocity wrt EC frame, expressed in EC frame
|
||||||
|
FGColumnVector3 vLocationDot = Tl2ec * vVel;
|
||||||
|
|
||||||
|
FGColumnVector3 omegaLocal( rInv*vVel(eEast),
|
||||||
|
-rInv*vVel(eNorth),
|
||||||
|
-rInv*vVel(eEast)*VState.vLocation.GetTanLatitude() );
|
||||||
|
|
||||||
|
// Compute quaternion orientation derivative on current body rates
|
||||||
|
FGQuaternion vQtrndot = VState.vQtrn.GetQDot( VState.vPQR - Tl2b*omegaLocal );
|
||||||
|
|
||||||
|
// Propagate velocities
|
||||||
|
VState.vPQR += dt*vPQRdot;
|
||||||
|
VState.vUVW += dt*vUVWdot;
|
||||||
|
|
||||||
|
// Propagate positions
|
||||||
|
VState.vQtrn += dt*vQtrndot;
|
||||||
|
VState.vLocation += dt*vLocationDot;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGPropagate::Seth(double tt)
|
||||||
|
{
|
||||||
|
VState.vLocation.SetRadius( tt + SeaLevelRadius );
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGPropagate::SetDistanceAGL(double tt)
|
||||||
|
{
|
||||||
|
VState.vLocation.SetRadius( tt + RunwayRadius );
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGPropagate::bind(void)
|
||||||
|
{
|
||||||
|
typedef double (FGPropagate::*PMF)(int) const;
|
||||||
|
PropertyManager->Tie("velocities/h-dot-fps", this, &FGPropagate::Gethdot);
|
||||||
|
|
||||||
|
PropertyManager->Tie("velocities/v-north-fps", this, eNorth, (PMF)&FGPropagate::GetVel);
|
||||||
|
PropertyManager->Tie("velocities/v-east-fps", this, eEast, (PMF)&FGPropagate::GetVel);
|
||||||
|
PropertyManager->Tie("velocities/v-down-fps", this, eDown, (PMF)&FGPropagate::GetVel);
|
||||||
|
|
||||||
|
PropertyManager->Tie("velocities/u-fps", this, eU, (PMF)&FGPropagate::GetUVW);
|
||||||
|
PropertyManager->Tie("velocities/v-fps", this, eV, (PMF)&FGPropagate::GetUVW);
|
||||||
|
PropertyManager->Tie("velocities/w-fps", this, eW, (PMF)&FGPropagate::GetUVW);
|
||||||
|
|
||||||
|
PropertyManager->Tie("velocities/p-rad_sec", this, eP, (PMF)&FGPropagate::GetPQR);
|
||||||
|
PropertyManager->Tie("velocities/q-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQR);
|
||||||
|
PropertyManager->Tie("velocities/r-rad_sec", this, eR, (PMF)&FGPropagate::GetPQR);
|
||||||
|
|
||||||
|
PropertyManager->Tie("accelerations/pdot-rad_sec", this, eP, (PMF)&FGPropagate::GetPQRdot);
|
||||||
|
PropertyManager->Tie("accelerations/qdot-rad_sec", this, eQ, (PMF)&FGPropagate::GetPQRdot);
|
||||||
|
PropertyManager->Tie("accelerations/rdot-rad_sec", this, eR, (PMF)&FGPropagate::GetPQRdot);
|
||||||
|
|
||||||
|
PropertyManager->Tie("accelerations/udot-fps", this, eU, (PMF)&FGPropagate::GetUVWdot);
|
||||||
|
PropertyManager->Tie("accelerations/vdot-fps", this, eV, (PMF)&FGPropagate::GetUVWdot);
|
||||||
|
PropertyManager->Tie("accelerations/wdot-fps", this, eW, (PMF)&FGPropagate::GetUVWdot);
|
||||||
|
|
||||||
|
PropertyManager->Tie("position/h-sl-ft", this, &FGPropagate::Geth, &FGPropagate::Seth, true);
|
||||||
|
PropertyManager->Tie("position/lat-gc-rad", this, &FGPropagate::GetLatitude, &FGPropagate::SetLatitude);
|
||||||
|
PropertyManager->Tie("position/long-gc-rad", this, &FGPropagate::GetLongitude, &FGPropagate::SetLongitude);
|
||||||
|
PropertyManager->Tie("position/h-agl-ft", this, &FGPropagate::GetDistanceAGL, &FGPropagate::SetDistanceAGL);
|
||||||
|
PropertyManager->Tie("position/radius-to-vehicle-ft", this, &FGPropagate::GetRadius);
|
||||||
|
|
||||||
|
PropertyManager->Tie("metrics/runway-radius", this, &FGPropagate::GetRunwayRadius, &FGPropagate::SetRunwayRadius);
|
||||||
|
|
||||||
|
PropertyManager->Tie("attitude/phi-rad", this, &FGPropagate::Getphi);
|
||||||
|
PropertyManager->Tie("attitude/theta-rad", this, &FGPropagate::Gettht);
|
||||||
|
PropertyManager->Tie("attitude/psi-rad", this, &FGPropagate::Getpsi);
|
||||||
|
|
||||||
|
PropertyManager->Tie("attitude/roll-rad", this, &FGPropagate::Getphi);
|
||||||
|
PropertyManager->Tie("attitude/pitch-rad", this, &FGPropagate::Gettht);
|
||||||
|
PropertyManager->Tie("attitude/heading-true-rad", this, &FGPropagate::Getpsi);
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGPropagate::unbind(void)
|
||||||
|
{
|
||||||
|
PropertyManager->Untie("velocities/v-north-fps");
|
||||||
|
PropertyManager->Untie("velocities/v-east-fps");
|
||||||
|
PropertyManager->Untie("velocities/v-down-fps");
|
||||||
|
PropertyManager->Untie("velocities/h-dot-fps");
|
||||||
|
PropertyManager->Untie("velocities/u-fps");
|
||||||
|
PropertyManager->Untie("velocities/v-fps");
|
||||||
|
PropertyManager->Untie("velocities/w-fps");
|
||||||
|
PropertyManager->Untie("velocities/p-rad_sec");
|
||||||
|
PropertyManager->Untie("velocities/q-rad_sec");
|
||||||
|
PropertyManager->Untie("velocities/r-rad_sec");
|
||||||
|
PropertyManager->Untie("accelerations/udot-fps");
|
||||||
|
PropertyManager->Untie("accelerations/vdot-fps");
|
||||||
|
PropertyManager->Untie("accelerations/wdot-fps");
|
||||||
|
PropertyManager->Untie("accelerations/pdot-rad_sec");
|
||||||
|
PropertyManager->Untie("accelerations/qdot-rad_sec");
|
||||||
|
PropertyManager->Untie("accelerations/rdot-rad_sec");
|
||||||
|
PropertyManager->Untie("position/h-sl-ft");
|
||||||
|
PropertyManager->Untie("position/lat-gc-rad");
|
||||||
|
PropertyManager->Untie("position/long-gc-rad");
|
||||||
|
PropertyManager->Untie("position/h-agl-ft");
|
||||||
|
PropertyManager->Untie("position/radius-to-vehicle-ft");
|
||||||
|
PropertyManager->Untie("metrics/runway-radius");
|
||||||
|
PropertyManager->Untie("attitude/phi-rad");
|
||||||
|
PropertyManager->Untie("attitude/theta-rad");
|
||||||
|
PropertyManager->Untie("attitude/psi-rad");
|
||||||
|
PropertyManager->Untie("attitude/roll-rad");
|
||||||
|
PropertyManager->Untie("attitude/pitch-rad");
|
||||||
|
PropertyManager->Untie("attitude/heading-true-rad");
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
// The bitmasked value choices are as follows:
|
||||||
|
// unset: In this case (the default) JSBSim would only print
|
||||||
|
// out the normally expected messages, essentially echoing
|
||||||
|
// the config files as they are read. If the environment
|
||||||
|
// variable is not set, debug_lvl is set to 1 internally
|
||||||
|
// 0: This requests JSBSim not to output any messages
|
||||||
|
// whatsoever.
|
||||||
|
// 1: This value explicity requests the normal JSBSim
|
||||||
|
// startup messages
|
||||||
|
// 2: This value asks for a message to be printed out when
|
||||||
|
// a class is instantiated
|
||||||
|
// 4: When this value is set, a message is displayed when a
|
||||||
|
// FGModel object executes its Run() method
|
||||||
|
// 8: When this value is set, various runtime state variables
|
||||||
|
// are printed out periodically
|
||||||
|
// 16: When set various parameters are sanity checked and
|
||||||
|
// a message is printed out when they go out of bounds
|
||||||
|
|
||||||
|
void FGPropagate::Debug(int from)
|
||||||
|
{
|
||||||
|
if (debug_lvl <= 0) return;
|
||||||
|
|
||||||
|
if (debug_lvl & 1) { // Standard console startup message output
|
||||||
|
if (from == 0) { // Constructor
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
||||||
|
if (from == 0) cout << "Instantiated: FGPropagate" << endl;
|
||||||
|
if (from == 1) cout << "Destroyed: FGPropagate" << endl;
|
||||||
|
}
|
||||||
|
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
|
||||||
|
}
|
||||||
|
if (debug_lvl & 8 ) { // Runtime state variables
|
||||||
|
}
|
||||||
|
if (debug_lvl & 16) { // Sanity checking
|
||||||
|
}
|
||||||
|
if (debug_lvl & 64) {
|
||||||
|
if (from == 0) { // Constructor
|
||||||
|
cout << IdSrc << endl;
|
||||||
|
cout << IdHdr << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
176
src/FDM/JSBSim/FGPropagate.h
Normal file
176
src/FDM/JSBSim/FGPropagate.h
Normal file
|
@ -0,0 +1,176 @@
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
Header: FGPropagate.h
|
||||||
|
Author: Jon S. Berndt
|
||||||
|
Date started: 1/5/99
|
||||||
|
|
||||||
|
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
|
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
Further information about the GNU General Public License can also be found on
|
||||||
|
the world wide web at http://www.gnu.org.
|
||||||
|
|
||||||
|
HISTORY
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
01/05/99 JSB Created
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
SENTRY
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#ifndef FGPROPAGATE_H
|
||||||
|
#define FGPROPAGATE_H
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
INCLUDES
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#include "FGModel.h"
|
||||||
|
#include "FGColumnVector3.h"
|
||||||
|
#include "FGInitialCondition.h"
|
||||||
|
#include "FGLocation.h"
|
||||||
|
#include "FGQuaternion.h"
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
DEFINITIONS
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#define ID_PROPAGATE "$Id$"
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
FORWARD DECLARATIONS
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
namespace JSBSim {
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
CLASS DOCUMENTATION
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
/** Models the EOM and integration/propagation of state
|
||||||
|
@author Jon S. Berndt, Mathias Froehlich
|
||||||
|
@version $Id$
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
CLASS DECLARATION
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
// state vector
|
||||||
|
|
||||||
|
struct VehicleState {
|
||||||
|
FGLocation vLocation;
|
||||||
|
FGColumnVector3 vUVW;
|
||||||
|
FGColumnVector3 vPQR;
|
||||||
|
FGQuaternion vQtrn;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FGPropagate : public FGModel {
|
||||||
|
public:
|
||||||
|
/** Constructor
|
||||||
|
@param Executive a pointer to the parent executive object */
|
||||||
|
FGPropagate(FGFDMExec* Executive);
|
||||||
|
|
||||||
|
/// Destructor
|
||||||
|
~FGPropagate();
|
||||||
|
|
||||||
|
bool InitModel(void);
|
||||||
|
|
||||||
|
/** Runs the Propagate model; called by the Executive
|
||||||
|
@return false if no error */
|
||||||
|
bool Run(void);
|
||||||
|
|
||||||
|
const FGColumnVector3& GetVel(void) const { return vVel; }
|
||||||
|
const FGColumnVector3& GetUVW(void) const { return VState.vUVW; }
|
||||||
|
const FGColumnVector3& GetUVWdot(void) const { return vUVWdot; }
|
||||||
|
const FGColumnVector3& GetPQR(void) const {return VState.vPQR;}
|
||||||
|
const FGColumnVector3& GetPQRdot(void) const {return vPQRdot;}
|
||||||
|
const FGColumnVector3& GetEuler(void) const { return VState.vQtrn.GetEuler(); }
|
||||||
|
|
||||||
|
double GetUVW (int idx) const { return VState.vUVW(idx); }
|
||||||
|
double GetUVWdot(int idx) const { return vUVWdot(idx); }
|
||||||
|
double GetVel(int idx) const { return vVel(idx); }
|
||||||
|
double Geth(void) const { return VState.vLocation.GetRadius() - SeaLevelRadius; }
|
||||||
|
double GetPQR(int axis) const {return VState.vPQR(axis);}
|
||||||
|
double GetPQRdot(int idx) const {return vPQRdot(idx);}
|
||||||
|
double GetEuler(int axis) const { return VState.vQtrn.GetEuler()(axis); }
|
||||||
|
double Gethdot(void) const { return -vVel(eDown); }
|
||||||
|
|
||||||
|
/** Returns the "constant" RunwayRadius.
|
||||||
|
The RunwayRadius parameter is set by the calling application or set to
|
||||||
|
zero if JSBSim is running in standalone mode.
|
||||||
|
@return distance of the runway from the center of the earth.
|
||||||
|
@units feet */
|
||||||
|
double GetRunwayRadius(void) const { return RunwayRadius; }
|
||||||
|
double GetSeaLevelRadius(void) const { return SeaLevelRadius; }
|
||||||
|
double GetDistanceAGL(void) const { return VState.vLocation.GetRadius()-RunwayRadius; }
|
||||||
|
double GetRadius(void) const { return VState.vLocation.GetRadius(); }
|
||||||
|
double GetLongitude(void) const { return VState.vLocation.GetLongitude(); }
|
||||||
|
double GetLatitude(void) const { return VState.vLocation.GetLatitude(); }
|
||||||
|
const FGLocation& GetLocation(void) const { return VState.vLocation; }
|
||||||
|
|
||||||
|
double Getphi(void) const { return VState.vQtrn.GetEulerPhi(); }
|
||||||
|
double Gettht(void) const { return VState.vQtrn.GetEulerTheta(); }
|
||||||
|
double Getpsi(void) const { return VState.vQtrn.GetEulerPsi(); }
|
||||||
|
|
||||||
|
double GetCosphi(void) const { return VState.vQtrn.GetCosEulerPhi(); }
|
||||||
|
double GetCostht(void) const { return VState.vQtrn.GetCosEulerTheta(); }
|
||||||
|
double GetCospsi(void) const { return VState.vQtrn.GetCosEulerPsi(); }
|
||||||
|
|
||||||
|
double GetSinphi(void) const { return VState.vQtrn.GetSinEulerPhi(); }
|
||||||
|
double GetSintht(void) const { return VState.vQtrn.GetSinEulerTheta(); }
|
||||||
|
double GetSinpsi(void) const { return VState.vQtrn.GetSinEulerPsi(); }
|
||||||
|
|
||||||
|
/** Retrieves the local-to-body transformation matrix.
|
||||||
|
@return a reference to the local-to-body transformation matrix. */
|
||||||
|
const FGMatrix33& GetTl2b(void) const { return VState.vQtrn.GetT(); }
|
||||||
|
|
||||||
|
/** Retrieves the body-to-local transformation matrix.
|
||||||
|
@return a reference to the body-to-local matrix. */
|
||||||
|
const FGMatrix33& GetTb2l(void) const { return VState.vQtrn.GetTInv(); }
|
||||||
|
|
||||||
|
// SET functions
|
||||||
|
|
||||||
|
void SetLongitude(double lon) { VState.vLocation.SetLongitude(lon); }
|
||||||
|
void SetLatitude(double lat) { VState.vLocation.SetLatitude(lat); }
|
||||||
|
void SetRadius(double r) { VState.vLocation.SetRadius(r); }
|
||||||
|
void SetLocation(const FGLocation& l) { VState.vLocation = l; }
|
||||||
|
void Seth(double tt);
|
||||||
|
void SetRunwayRadius(double tt) { RunwayRadius = tt; }
|
||||||
|
void SetSeaLevelRadius(double tt) { SeaLevelRadius = tt; }
|
||||||
|
void SetDistanceAGL(double tt);
|
||||||
|
void SetInitialState(const FGInitialCondition *);
|
||||||
|
|
||||||
|
void bind(void);
|
||||||
|
void unbind(void);
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
// state vector
|
||||||
|
|
||||||
|
struct VehicleState VState;
|
||||||
|
|
||||||
|
FGColumnVector3 vVel;
|
||||||
|
FGColumnVector3 vPQRdot;
|
||||||
|
FGColumnVector3 vUVWdot;
|
||||||
|
|
||||||
|
double RunwayRadius, SeaLevelRadius;
|
||||||
|
|
||||||
|
void Debug(int from);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
#endif
|
|
@ -35,11 +35,12 @@ HISTORY
|
||||||
INCLUDES
|
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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
235
src/FDM/JSBSim/FGQuaternion.cpp
Normal file
235
src/FDM/JSBSim/FGQuaternion.cpp
Normal file
|
@ -0,0 +1,235 @@
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
Module: FGQuaternion.cpp
|
||||||
|
Author: Jon Berndt, Mathias Froehlich
|
||||||
|
Date started: 12/02/98
|
||||||
|
|
||||||
|
------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------------
|
||||||
|
------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
|
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
Further information about the GNU General Public License can also be found on
|
||||||
|
the world wide web at http://www.gnu.org.
|
||||||
|
|
||||||
|
HISTORY
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
12/02/98 JSB Created
|
||||||
|
15/01/04 Mathias Froehlich implemented a quaternion class from many places
|
||||||
|
in JSBSim.
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
SENTRY
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
INCLUDES
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#ifdef FGFS
|
||||||
|
# include <math.h>
|
||||||
|
# include <simgear/compiler.h>
|
||||||
|
# include STL_IOSTREAM
|
||||||
|
SG_USING_STD(cerr);
|
||||||
|
SG_USING_STD(cout);
|
||||||
|
SG_USING_STD(endl);
|
||||||
|
#else
|
||||||
|
# include <string>
|
||||||
|
# if defined(sgi) && !defined(__GNUC__) && (_COMPILER_VERSION < 740)
|
||||||
|
# include <iostream.h>
|
||||||
|
# include <math.h>
|
||||||
|
# else
|
||||||
|
# include <iostream>
|
||||||
|
# if defined(sgi) && !defined(__GNUC__)
|
||||||
|
# include <math.h>
|
||||||
|
# else
|
||||||
|
# include <cmath>
|
||||||
|
# endif
|
||||||
|
using std::cerr;
|
||||||
|
using std::cout;
|
||||||
|
using std::endl;
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "FGMatrix33.h"
|
||||||
|
#include "FGColumnVector3.h"
|
||||||
|
|
||||||
|
#include "FGQuaternion.h"
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
DEFINITIONS
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
namespace JSBSim {
|
||||||
|
|
||||||
|
static const char *IdSrc = "$Id$";
|
||||||
|
static const char *IdHdr = ID_QUATERNION;
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
// Initialize from q
|
||||||
|
FGQuaternion::FGQuaternion(const FGQuaternion& q)
|
||||||
|
: mCacheValid(q.mCacheValid) {
|
||||||
|
Entry(1) = q(1);
|
||||||
|
Entry(2) = q(2);
|
||||||
|
Entry(3) = q(3);
|
||||||
|
Entry(4) = q(4);
|
||||||
|
if (mCacheValid) {
|
||||||
|
mT = q.mT;
|
||||||
|
mTInv = q.mTInv;
|
||||||
|
mEulerAngles = q.mEulerAngles;
|
||||||
|
mEulerSines = q.mEulerSines;
|
||||||
|
mEulerCosines = q.mEulerCosines;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
// Initialize with the three euler angles
|
||||||
|
FGQuaternion::FGQuaternion(double phi, double tht, double psi)
|
||||||
|
: mCacheValid(false) {
|
||||||
|
double thtd2 = 0.5*tht;
|
||||||
|
double psid2 = 0.5*psi;
|
||||||
|
double phid2 = 0.5*phi;
|
||||||
|
|
||||||
|
double Sthtd2 = sin(thtd2);
|
||||||
|
double Spsid2 = sin(psid2);
|
||||||
|
double Sphid2 = sin(phid2);
|
||||||
|
|
||||||
|
double Cthtd2 = cos(thtd2);
|
||||||
|
double Cpsid2 = cos(psid2);
|
||||||
|
double Cphid2 = cos(phid2);
|
||||||
|
|
||||||
|
double Cphid2Cthtd2 = Cphid2*Cthtd2;
|
||||||
|
double Cphid2Sthtd2 = Cphid2*Sthtd2;
|
||||||
|
double Sphid2Sthtd2 = Sphid2*Sthtd2;
|
||||||
|
double Sphid2Cthtd2 = Sphid2*Cthtd2;
|
||||||
|
|
||||||
|
Entry(1) = Cphid2Cthtd2*Cpsid2 + Sphid2Sthtd2*Spsid2;
|
||||||
|
Entry(2) = Sphid2Cthtd2*Cpsid2 - Cphid2Sthtd2*Spsid2;
|
||||||
|
Entry(3) = Cphid2Sthtd2*Cpsid2 + Sphid2Cthtd2*Spsid2;
|
||||||
|
Entry(4) = Cphid2Cthtd2*Spsid2 - Sphid2Sthtd2*Cpsid2;
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
/**
|
||||||
|
Returns the derivative of the quaternion coresponding to the
|
||||||
|
angular velocities PQR.
|
||||||
|
*/
|
||||||
|
FGQuaternion FGQuaternion::GetQDot(const FGColumnVector3& PQR) const {
|
||||||
|
FGQuaternion QDot;
|
||||||
|
QDot(1) = -0.5*(Entry(2)*PQR(eP) + Entry(3)*PQR(eQ) + Entry(4)*PQR(eR));
|
||||||
|
QDot(2) = 0.5*(Entry(1)*PQR(eP) + Entry(3)*PQR(eR) - Entry(4)*PQR(eQ));
|
||||||
|
QDot(3) = 0.5*(Entry(1)*PQR(eQ) + Entry(4)*PQR(eP) - Entry(2)*PQR(eR));
|
||||||
|
QDot(4) = 0.5*(Entry(1)*PQR(eR) + Entry(2)*PQR(eQ) - Entry(3)*PQR(eP));
|
||||||
|
return QDot;
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGQuaternion::Normalize()
|
||||||
|
{
|
||||||
|
// Note: this does not touch the cache
|
||||||
|
// since it does not change the orientation ...
|
||||||
|
|
||||||
|
double norm = Magnitude();
|
||||||
|
if (norm == 0.0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
double rnorm = 1.0/norm;
|
||||||
|
Entry(1) *= rnorm;
|
||||||
|
Entry(2) *= rnorm;
|
||||||
|
Entry(3) *= rnorm;
|
||||||
|
Entry(4) *= rnorm;
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
// Compute the derived values if required ...
|
||||||
|
void FGQuaternion::ComputeDerivedUnconditional(void) const
|
||||||
|
{
|
||||||
|
mCacheValid = true;
|
||||||
|
|
||||||
|
// First normalize the 4-vector
|
||||||
|
double norm = Magnitude();
|
||||||
|
if (norm == 0.0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
double rnorm = 1.0/norm;
|
||||||
|
double q1 = rnorm*Entry(1);
|
||||||
|
double q2 = rnorm*Entry(2);
|
||||||
|
double q3 = rnorm*Entry(3);
|
||||||
|
double q4 = rnorm*Entry(4);
|
||||||
|
|
||||||
|
// Now compute the transformation matrix.
|
||||||
|
double q1q1 = q1*q1;
|
||||||
|
double q2q2 = q2*q2;
|
||||||
|
double q3q3 = q3*q3;
|
||||||
|
double q4q4 = q4*q4;
|
||||||
|
double q1q2 = q1*q2;
|
||||||
|
double q1q3 = q1*q3;
|
||||||
|
double q1q4 = q1*q4;
|
||||||
|
double q2q3 = q2*q3;
|
||||||
|
double q2q4 = q2*q4;
|
||||||
|
double q3q4 = q3*q4;
|
||||||
|
|
||||||
|
mT(1,1) = q1q1 + q2q2 - q3q3 - q4q4;
|
||||||
|
mT(1,2) = 2.0*(q2q3 + q1q4);
|
||||||
|
mT(1,3) = 2.0*(q2q4 - q1q3);
|
||||||
|
mT(2,1) = 2.0*(q2q3 - q1q4);
|
||||||
|
mT(2,2) = q1q1 - q2q2 + q3q3 - q4q4;
|
||||||
|
mT(2,3) = 2.0*(q3q4 + q1q2);
|
||||||
|
mT(3,1) = 2.0*(q2q4 + q1q3);
|
||||||
|
mT(3,2) = 2.0*(q3q4 - q1q2);
|
||||||
|
mT(3,3) = q1q1 - q2q2 - q3q3 + q4q4;
|
||||||
|
// Since this is an orthogonal matrix, the inverse is simply
|
||||||
|
// the transpose.
|
||||||
|
mTInv = mT;
|
||||||
|
mTInv.T();
|
||||||
|
|
||||||
|
// Compute the Euler-angles
|
||||||
|
if (mT(3,3) == 0.0)
|
||||||
|
mEulerAngles(ePhi) = 0.5*M_PI;
|
||||||
|
else
|
||||||
|
mEulerAngles(ePhi) = atan2(mT(2,3), mT(3,3));
|
||||||
|
|
||||||
|
if (mT(1,3) < -1.0)
|
||||||
|
mEulerAngles(eTht) = 0.5*M_PI;
|
||||||
|
else if (1.0 < mT(1,3))
|
||||||
|
mEulerAngles(eTht) = -0.5*M_PI;
|
||||||
|
else
|
||||||
|
mEulerAngles(eTht) = asin(-mT(1,3));
|
||||||
|
|
||||||
|
if (mT(1,1) == 0.0)
|
||||||
|
mEulerAngles(ePsi) = 0.5*M_PI;
|
||||||
|
else {
|
||||||
|
double psi = atan2(mT(1,2), mT(1,1));
|
||||||
|
if (psi < 0.0)
|
||||||
|
psi += 2*M_PI;
|
||||||
|
mEulerAngles(ePsi) = psi;
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: may be one can compute those values easier ???
|
||||||
|
mEulerSines(ePhi) = sin(mEulerAngles(ePhi));
|
||||||
|
// mEulerSines(eTht) = sin(mEulerAngles(eTht));
|
||||||
|
mEulerSines(eTht) = -mT(1,3);
|
||||||
|
mEulerSines(ePsi) = sin(mEulerAngles(ePsi));
|
||||||
|
mEulerCosines(ePhi) = cos(mEulerAngles(ePhi));
|
||||||
|
mEulerCosines(eTht) = cos(mEulerAngles(eTht));
|
||||||
|
mEulerCosines(ePsi) = cos(mEulerAngles(ePsi));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace JSBSim
|
499
src/FDM/JSBSim/FGQuaternion.h
Normal file
499
src/FDM/JSBSim/FGQuaternion.h
Normal file
|
@ -0,0 +1,499 @@
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
Header: FGQuaternion.h
|
||||||
|
Author: Jon Berndt, Mathis Froehlich
|
||||||
|
Date started: 12/02/98
|
||||||
|
|
||||||
|
------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) ------------------
|
||||||
|
------- (C) 2004 Mathias Froehlich (Mathias.Froehlich@web.de) ----
|
||||||
|
|
||||||
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU General Public License as published by the Free Software
|
||||||
|
Foundation; either version 2 of the License, or (at your option) any later
|
||||||
|
version.
|
||||||
|
|
||||||
|
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
||||||
|
details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License along with
|
||||||
|
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||||
|
Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
|
Further information about the GNU General Public License can also be found on
|
||||||
|
the world wide web at http://www.gnu.org.
|
||||||
|
|
||||||
|
HISTORY
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
12/02/98 JSB Created
|
||||||
|
15/01/04 MF Quaternion class from old FGColumnVector4
|
||||||
|
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
SENTRY
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#ifndef FGQUATERNION_H
|
||||||
|
#define FGQUATERNION_H
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
INCLUDES
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#include "FGJSBBase.h"
|
||||||
|
#include "FGMatrix33.h"
|
||||||
|
#include "FGColumnVector3.h"
|
||||||
|
#include "FGPropertyManager.h"
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
DEFINITIONS
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
#define ID_QUATERNION "$Id$"
|
||||||
|
|
||||||
|
namespace JSBSim {
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
CLASS DOCUMENTATION
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
/** Models the Quaternion representation of rotations.
|
||||||
|
FGQuaternion is a representation of an arbitrary rotation through a
|
||||||
|
quaternion. It has vector properties. This class also contains access
|
||||||
|
functions to the euler angle representation of rotations and access to
|
||||||
|
transformation matrices for 3D vectors. Transformations and euler angles are
|
||||||
|
therefore computed once they are requested for the first time. Then they are
|
||||||
|
cached for later usage as long as the class is not accessed trough
|
||||||
|
a nonconst member function.
|
||||||
|
|
||||||
|
Note: The order of rotations used in this class corresponds to a 3-2-1 sequence,
|
||||||
|
or Y-P-R, or Z-Y-X, if you prefer.
|
||||||
|
|
||||||
|
@see Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
|
||||||
|
Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
|
||||||
|
School, January 1994
|
||||||
|
@see D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
|
||||||
|
JSC 12960, July 1977
|
||||||
|
@see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
|
||||||
|
NASA-Ames", NASA CR-2497, January 1975
|
||||||
|
@see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
|
||||||
|
Wiley & Sons, 1979 ISBN 0-471-03032-5
|
||||||
|
@see Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
|
||||||
|
1982 ISBN 0-471-08936-2
|
||||||
|
@author Mathias Froehlich, extended FGColumnVector4 originally by Tony Peden
|
||||||
|
and Jon Berndt
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
CLASS DECLARATION
|
||||||
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
class FGQuaternion
|
||||||
|
: virtual FGJSBBase {
|
||||||
|
public:
|
||||||
|
/** Default initializer.
|
||||||
|
Default initializer, initializes the class with the identity rotation. */
|
||||||
|
FGQuaternion() : mCacheValid(false) {
|
||||||
|
Entry(1) = 1.0;
|
||||||
|
Entry(2) = Entry(3) = Entry(4) = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Copy constructor.
|
||||||
|
Copy constructor, initializes the quaternion.
|
||||||
|
@param q a constant reference to another FGQuaternion instance */
|
||||||
|
FGQuaternion(const FGQuaternion& q);
|
||||||
|
|
||||||
|
/** Initializer by euler angles.
|
||||||
|
Initialize the quaternion with the euler angles.
|
||||||
|
@param phi The euler X axis (roll) angle in radians
|
||||||
|
@param tht The euler Y axis (attitude) angle in radians
|
||||||
|
@param psi The euler Z axis (heading) angle in radians */
|
||||||
|
FGQuaternion(double phi, double tht, double psi);
|
||||||
|
|
||||||
|
/// Destructor.
|
||||||
|
~FGQuaternion() {}
|
||||||
|
|
||||||
|
/** Quaternion 'velocity' for given angular rates.
|
||||||
|
Computes the quaternion derivative which results from the given
|
||||||
|
angular velocities
|
||||||
|
@param PQR a constant reference to the body rate vector
|
||||||
|
@return the quaternion derivative */
|
||||||
|
FGQuaternion GetQDot(const FGColumnVector3& PQR) const;
|
||||||
|
|
||||||
|
/** Transformation matrix.
|
||||||
|
@return a reference to the transformation/rotation matrix
|
||||||
|
corresponding to this quaternion rotation. */
|
||||||
|
const FGMatrix33& GetT() const { ComputeDerived(); return mT; }
|
||||||
|
|
||||||
|
/** Backward transformation matrix.
|
||||||
|
@return a reference to the inverse transformation/rotation matrix
|
||||||
|
corresponding to this quaternion rotation. */
|
||||||
|
const FGMatrix33& GetTInv() const { ComputeDerived(); return mTInv; }
|
||||||
|
|
||||||
|
/** Retrieves the Euler angles.
|
||||||
|
@return a reference to the triad of euler angles corresponding
|
||||||
|
to this quaternion rotation.
|
||||||
|
@units radians */
|
||||||
|
const FGColumnVector3& GetEuler() const {
|
||||||
|
ComputeDerived();
|
||||||
|
return mEulerAngles;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Euler angle theta.
|
||||||
|
@return the euler angle theta (pitch attitude) corresponding to this
|
||||||
|
quaternion rotation.
|
||||||
|
@units radians */
|
||||||
|
double GetEulerTheta() const {
|
||||||
|
ComputeDerived();
|
||||||
|
return mEulerAngles(eTht);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Euler angle theta.
|
||||||
|
@return the euler angle theta (pitch attitude) corresponding to
|
||||||
|
this quaternion rotation.
|
||||||
|
@units degrees */
|
||||||
|
double GetEulerThetaDeg() const {
|
||||||
|
ComputeDerived();
|
||||||
|
return radtodeg*mEulerAngles(eTht);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Euler angle psi.
|
||||||
|
@return the heading euler angle (psi) corresponding to this quaternion
|
||||||
|
rotation.
|
||||||
|
@units radians */
|
||||||
|
double GetEulerPsi() const {
|
||||||
|
ComputeDerived();
|
||||||
|
return mEulerAngles(ePsi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Retrieves the heading angle.
|
||||||
|
@return the Euler angle psi (heading) corresponding to this quaternion
|
||||||
|
rotation.
|
||||||
|
@units degrees */
|
||||||
|
double GetEulerPsiDeg() const {
|
||||||
|
ComputeDerived();
|
||||||
|
return radtodeg*mEulerAngles(ePsi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Retrieves the roll angle.
|
||||||
|
@return the euler angle phi (roll) corresponding to this quaternion
|
||||||
|
rotation.
|
||||||
|
@units radians */
|
||||||
|
double GetEulerPhi() const {
|
||||||
|
ComputeDerived();
|
||||||
|
return mEulerAngles(ePhi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Retrieves the roll angle.
|
||||||
|
Returns the Euler angle phi (roll) corresponding to this quaternion rotation.
|
||||||
|
@units degrees */
|
||||||
|
double GetEulerPhiDeg() const {
|
||||||
|
ComputeDerived();
|
||||||
|
return radtodeg*mEulerAngles(ePhi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Retrieves sine theta.
|
||||||
|
@return the sine of the Euler angle theta (pitch attitude) corresponding
|
||||||
|
to this quaternion rotation. */
|
||||||
|
double GetSinEulerTheta() const {
|
||||||
|
ComputeDerived();
|
||||||
|
return mEulerSines(eTht);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Retrieves sine psi.
|
||||||
|
@return the sine of the Euler angle psi (heading) corresponding to this
|
||||||
|
quaternion rotation. */
|
||||||
|
double GetSinEulerPsi() const {
|
||||||
|
ComputeDerived();
|
||||||
|
return mEulerSines(ePsi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sine of euler angle phi.
|
||||||
|
@return the sine of the Euler angle phi (roll) corresponding to this
|
||||||
|
quaternion rotation. */
|
||||||
|
double GetSinEulerPhi() const {
|
||||||
|
ComputeDerived();
|
||||||
|
return mEulerSines(ePhi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Cosine of euler angle theta.
|
||||||
|
@return the cosine of the Euler angle theta (pitch) corresponding to this
|
||||||
|
quaternion rotation. */
|
||||||
|
double GetCosEulerTheta() const {
|
||||||
|
ComputeDerived();
|
||||||
|
return mEulerCosines(eTht);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Cosine of euler angle psi.
|
||||||
|
@return the cosine of the Euler angle psi (heading) corresponding to this
|
||||||
|
quaternion rotation. */
|
||||||
|
double GetCosEulerPsi() const {
|
||||||
|
ComputeDerived();
|
||||||
|
return mEulerCosines(ePsi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Cosine of euler angle phi.
|
||||||
|
@return the cosine of the Euler angle phi (roll) corresponding to this
|
||||||
|
quaternion rotation. */
|
||||||
|
double GetCosEulerPhi() const {
|
||||||
|
ComputeDerived();
|
||||||
|
return mEulerCosines(ePhi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Read access the entries of the vector.
|
||||||
|
|
||||||
|
@param idx the component index.
|
||||||
|
|
||||||
|
Return the value of the matrix entry at the given index.
|
||||||
|
Indices are counted starting with 1.
|
||||||
|
|
||||||
|
Note that the index given in the argument is unchecked.
|
||||||
|
*/
|
||||||
|
double operator()(unsigned int idx) const { return Entry(idx); }
|
||||||
|
|
||||||
|
/** Write access the entries of the vector.
|
||||||
|
|
||||||
|
@param idx the component index.
|
||||||
|
|
||||||
|
Return a reference to the vector entry at the given index.
|
||||||
|
Indices are counted starting with 1.
|
||||||
|
|
||||||
|
Note that the index given in the argument is unchecked.
|
||||||
|
*/
|
||||||
|
double& operator()(unsigned int idx) { return Entry(idx); }
|
||||||
|
|
||||||
|
/** Read access the entries of the vector.
|
||||||
|
|
||||||
|
@param idx the component index.
|
||||||
|
|
||||||
|
Return the value of the matrix entry at the given index.
|
||||||
|
Indices are counted starting with 1.
|
||||||
|
|
||||||
|
This function is just a shortcut for the @ref double
|
||||||
|
operator()(unsigned int idx) const function. It is
|
||||||
|
used internally to access the elements in a more convenient way.
|
||||||
|
|
||||||
|
Note that the index given in the argument is unchecked.
|
||||||
|
*/
|
||||||
|
double Entry(unsigned int idx) const { return mData[idx-1]; }
|
||||||
|
|
||||||
|
/** Write access the entries of the vector.
|
||||||
|
|
||||||
|
@param idx the component index.
|
||||||
|
|
||||||
|
Return a reference to the vector entry at the given index.
|
||||||
|
Indices are counted starting with 1.
|
||||||
|
|
||||||
|
This function is just a shortcut for the @ref double&
|
||||||
|
operator()(unsigned int idx) function. It is
|
||||||
|
used internally to access the elements in a more convenient way.
|
||||||
|
|
||||||
|
Note that the index given in the argument is unchecked.
|
||||||
|
*/
|
||||||
|
double& Entry(unsigned int idx) { mCacheValid = false; return mData[idx-1]; }
|
||||||
|
|
||||||
|
/** Assignment operator "=".
|
||||||
|
Assign the value of q to the current object. Cached values are
|
||||||
|
conserved.
|
||||||
|
@param q reference to an FGQuaternion instance
|
||||||
|
@return reference to a quaternion object */
|
||||||
|
const FGQuaternion& operator=(const FGQuaternion& q) {
|
||||||
|
// Copy the master values ...
|
||||||
|
Entry(1) = q(1);
|
||||||
|
Entry(2) = q(2);
|
||||||
|
Entry(3) = q(3);
|
||||||
|
Entry(4) = q(4);
|
||||||
|
// .. and copy the derived values if they are valid
|
||||||
|
mCacheValid = q.mCacheValid;
|
||||||
|
if (mCacheValid) {
|
||||||
|
mT = q.mT;
|
||||||
|
mTInv = q.mTInv;
|
||||||
|
mEulerAngles = q.mEulerAngles;
|
||||||
|
mEulerSines = q.mEulerSines;
|
||||||
|
mEulerCosines = q.mEulerCosines;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Comparison operator "==".
|
||||||
|
@param q a quaternion reference
|
||||||
|
@return true if both quaternions represent the same rotation. */
|
||||||
|
bool operator==(const FGQuaternion& q) const {
|
||||||
|
return Entry(1) == q(1) && Entry(2) == q(2)
|
||||||
|
&& Entry(3) == q(3) && Entry(4) == q(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Comparison operator "!=".
|
||||||
|
@param q a quaternion reference
|
||||||
|
@return true if both quaternions do not represent the same rotation. */
|
||||||
|
bool operator!=(const FGQuaternion& q) const { return ! operator==(q); }
|
||||||
|
const FGQuaternion& operator+=(const FGQuaternion& q) {
|
||||||
|
// Copy the master values ...
|
||||||
|
Entry(1) += q(1);
|
||||||
|
Entry(2) += q(2);
|
||||||
|
Entry(3) += q(3);
|
||||||
|
Entry(4) += q(4);
|
||||||
|
mCacheValid = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Arithmetic operator "-=".
|
||||||
|
@param q a quaternion reference.
|
||||||
|
@return a quaternion reference representing Q, where Q = Q - q. */
|
||||||
|
const FGQuaternion& operator-=(const FGQuaternion& q) {
|
||||||
|
// Copy the master values ...
|
||||||
|
Entry(1) -= q(1);
|
||||||
|
Entry(2) -= q(2);
|
||||||
|
Entry(3) -= q(3);
|
||||||
|
Entry(4) -= q(4);
|
||||||
|
mCacheValid = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Arithmetic operator "*=".
|
||||||
|
@param scalar a multiplicative value.
|
||||||
|
@return a quaternion reference representing Q, where Q = Q * scalar. */
|
||||||
|
const FGQuaternion& operator*=(double scalar) {
|
||||||
|
Entry(1) *= scalar;
|
||||||
|
Entry(2) *= scalar;
|
||||||
|
Entry(3) *= scalar;
|
||||||
|
Entry(4) *= scalar;
|
||||||
|
mCacheValid = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Arithmetic operator "/=".
|
||||||
|
@param scalar a divisor value.
|
||||||
|
@return a quaternion reference representing Q, where Q = Q / scalar. */
|
||||||
|
const FGQuaternion& operator/=(double scalar) {
|
||||||
|
return operator*=(1.0/scalar);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Arithmetic operator "+".
|
||||||
|
@param q a quaternion to be summed.
|
||||||
|
@return a quaternion representing Q, where Q = Q + q. */
|
||||||
|
FGQuaternion operator+(const FGQuaternion& q) const {
|
||||||
|
return FGQuaternion(Entry(1)+q(1), Entry(2)+q(2),
|
||||||
|
Entry(3)+q(3), Entry(4)+q(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Arithmetic operator "-".
|
||||||
|
@param q a quaternion to be subtracted.
|
||||||
|
@return a quaternion representing Q, where Q = Q - q. */
|
||||||
|
FGQuaternion operator-(const FGQuaternion& q) const {
|
||||||
|
return FGQuaternion(Entry(1)-q(1), Entry(2)-q(2),
|
||||||
|
Entry(3)-q(3), Entry(4)-q(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Arithmetic operator "*".
|
||||||
|
Multiplication of two quaternions is like performing successive rotations.
|
||||||
|
@param q a quaternion to be multiplied.
|
||||||
|
@return a quaternion representing Q, where Q = Q * q. */
|
||||||
|
FGQuaternion operator*(const FGQuaternion& q) const {
|
||||||
|
return FGQuaternion(Entry(1)*q(1)-Entry(2)*q(2)-Entry(3)*q(3)-Entry(4)*q(4),
|
||||||
|
Entry(1)*q(2)+Entry(2)*q(1)+Entry(3)*q(4)-Entry(4)*q(3),
|
||||||
|
Entry(1)*q(3)-Entry(2)*q(4)+Entry(3)*q(1)+Entry(4)*q(2),
|
||||||
|
Entry(1)*q(4)+Entry(2)*q(3)-Entry(3)*q(2)+Entry(4)*q(1));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Arithmetic operator "*=".
|
||||||
|
Multiplication of two quaternions is like performing successive rotations.
|
||||||
|
@param q a quaternion to be multiplied.
|
||||||
|
@return a quaternion reference representing Q, where Q = Q * q. */
|
||||||
|
const FGQuaternion& operator*=(const FGQuaternion& q) {
|
||||||
|
double q0 = Entry(1)*q(1)-Entry(2)*q(2)-Entry(3)*q(3)-Entry(4)*q(4);
|
||||||
|
double q1 = Entry(1)*q(2)+Entry(2)*q(1)+Entry(3)*q(4)-Entry(4)*q(3);
|
||||||
|
double q2 = Entry(1)*q(3)-Entry(2)*q(4)+Entry(3)*q(1)+Entry(4)*q(2);
|
||||||
|
double q3 = Entry(1)*q(4)+Entry(2)*q(3)-Entry(3)*q(2)+Entry(4)*q(1);
|
||||||
|
Entry(1) = q0;
|
||||||
|
Entry(2) = q1;
|
||||||
|
Entry(3) = q2;
|
||||||
|
Entry(4) = q3;
|
||||||
|
mCacheValid = false;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend FGQuaternion operator*(double, const FGQuaternion&);
|
||||||
|
|
||||||
|
/** Length of the vector.
|
||||||
|
|
||||||
|
Compute and return the euclidean norm of this vector.
|
||||||
|
*/
|
||||||
|
double Magnitude() const { return sqrt(SqrMagnitude()); }
|
||||||
|
|
||||||
|
/** Square of the length of the vector.
|
||||||
|
|
||||||
|
Compute and return the square of the euclidean norm of this vector.
|
||||||
|
*/
|
||||||
|
double SqrMagnitude() const {
|
||||||
|
return Entry(1)*Entry(1)+Entry(2)*Entry(2)
|
||||||
|
+Entry(3)*Entry(3)+Entry(4)*Entry(4);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Normialze.
|
||||||
|
|
||||||
|
Normalize the vector to have the Magnitude() == 1.0. If the vector
|
||||||
|
is equal to zero it is left untouched.
|
||||||
|
*/
|
||||||
|
void Normalize();
|
||||||
|
|
||||||
|
/** Zero quaternion vector. Does not represent any orientation.
|
||||||
|
Useful for initialization of increments */
|
||||||
|
static FGQuaternion zero(void) { return FGQuaternion( 0.0, 0.0, 0.0, 0.0 ); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
/** Copying by assigning the vector valued components. */
|
||||||
|
FGQuaternion(double q1, double q2, double q3, double q4) : mCacheValid(false)
|
||||||
|
{ Entry(1) = q1; Entry(2) = q2; Entry(3) = q3; Entry(4) = q4; }
|
||||||
|
|
||||||
|
/** Computation of derived values.
|
||||||
|
This function recomputes the derived values like euler angles and
|
||||||
|
transformation matrices. It does this unconditionally. */
|
||||||
|
void ComputeDerivedUnconditional(void) const;
|
||||||
|
|
||||||
|
/** Computation of derived values.
|
||||||
|
This function checks if the derived values like euler angles and
|
||||||
|
transformation matrices are already computed. If so, it
|
||||||
|
returns. If they need to be computed this is done here. */
|
||||||
|
void ComputeDerived(void) const {
|
||||||
|
if (!mCacheValid)
|
||||||
|
ComputeDerivedUnconditional();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The quaternion values itself. This is the master copy. */
|
||||||
|
double mData[4];
|
||||||
|
|
||||||
|
/** A data validity flag.
|
||||||
|
This class implements caching of the derived values like the
|
||||||
|
orthogonal rotation matrices or the Euler angles. For caching we
|
||||||
|
carry a flag which signals if the values are valid or not.
|
||||||
|
The C++ keyword "mutable" tells the compiler that the data member is
|
||||||
|
allowed to change during a const member function. */
|
||||||
|
mutable bool mCacheValid;
|
||||||
|
|
||||||
|
/** This stores the transformation matrices. */
|
||||||
|
mutable FGMatrix33 mT;
|
||||||
|
mutable FGMatrix33 mTInv;
|
||||||
|
|
||||||
|
/** The cached euler angles. */
|
||||||
|
mutable FGColumnVector3 mEulerAngles;
|
||||||
|
|
||||||
|
/** The cached sines and cosines of the euler angles. */
|
||||||
|
mutable FGColumnVector3 mEulerSines;
|
||||||
|
mutable FGColumnVector3 mEulerCosines;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Scalar multiplication.
|
||||||
|
|
||||||
|
@param scalar scalar value to multiply with.
|
||||||
|
@param p Vector to multiply.
|
||||||
|
|
||||||
|
Multiply the Vector with a scalar value.
|
||||||
|
*/
|
||||||
|
inline FGQuaternion operator*(double scalar, const FGQuaternion& q) {
|
||||||
|
return FGQuaternion(scalar*q(1), scalar*q(2), scalar*q(3), scalar*q(4));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace JSBSim
|
||||||
|
|
||||||
|
#endif
|
|
@ -38,6 +38,8 @@ HISTORY
|
||||||
INCLUDES
|
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();
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -1,267 +0,0 @@
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
Module: FGRotation.cpp
|
|
||||||
Author: Jon Berndt
|
|
||||||
Date started: 12/02/98
|
|
||||||
Purpose: Integrates the rotational EOM
|
|
||||||
Called by: FGFDMExec
|
|
||||||
|
|
||||||
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
|
||||||
Foundation; either version 2 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
|
||||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
|
|
||||||
Further information about the GNU General Public License can also be found on
|
|
||||||
the world wide web at http://www.gnu.org.
|
|
||||||
|
|
||||||
FUNCTIONAL DESCRIPTION
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
This class integrates the rotational EOM.
|
|
||||||
|
|
||||||
HISTORY
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
12/02/98 JSB Created
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
COMMENTS, REFERENCES, and NOTES
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
[1] Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
|
|
||||||
Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
|
|
||||||
School, January 1994
|
|
||||||
[2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
|
|
||||||
JSC 12960, July 1977
|
|
||||||
[3] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
|
|
||||||
NASA-Ames", NASA CR-2497, January 1975
|
|
||||||
[4] Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
|
|
||||||
Wiley & Sons, 1979 ISBN 0-471-03032-5
|
|
||||||
[5] Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
|
|
||||||
1982 ISBN 0-471-08936-2
|
|
||||||
|
|
||||||
The order of rotations used in this class corresponds to a 3-2-1 sequence,
|
|
||||||
or Y-P-R, or Z-Y-X, if you prefer.
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
INCLUDES
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#include "FGRotation.h"
|
|
||||||
#include "FGAtmosphere.h"
|
|
||||||
#include "FGState.h"
|
|
||||||
#include "FGFDMExec.h"
|
|
||||||
#include "FGAircraft.h"
|
|
||||||
#include "FGMassBalance.h"
|
|
||||||
#include "FGPropertyManager.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace JSBSim {
|
|
||||||
|
|
||||||
static const char *IdSrc = "$Id$";
|
|
||||||
static const char *IdHdr = ID_ROTATION;
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
CLASS IMPLEMENTATION
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
|
|
||||||
FGRotation::FGRotation(FGFDMExec* fdmex) : FGModel(fdmex)
|
|
||||||
{
|
|
||||||
Name = "FGRotation";
|
|
||||||
cTht = cPhi = cPsi = 1.0;
|
|
||||||
sTht = sPhi = sPsi = 0.0;
|
|
||||||
|
|
||||||
vPQRdot.InitMatrix();
|
|
||||||
vPQRdot_prev[0].InitMatrix();
|
|
||||||
vPQRdot_prev[1].InitMatrix();
|
|
||||||
vPQRdot_prev[2].InitMatrix();
|
|
||||||
vPQRdot_prev[3].InitMatrix();
|
|
||||||
|
|
||||||
bind();
|
|
||||||
|
|
||||||
Debug(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
FGRotation::~FGRotation()
|
|
||||||
{
|
|
||||||
unbind();
|
|
||||||
Debug(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
bool FGRotation::Run(void)
|
|
||||||
{
|
|
||||||
double tTheta;
|
|
||||||
|
|
||||||
if (!FGModel::Run()) {
|
|
||||||
GetState();
|
|
||||||
|
|
||||||
vPQRdot = MassBalance->GetJinv()*(vMoments - vPQR*(MassBalance->GetJ()*vPQR));
|
|
||||||
vPQR += State->Integrate(FGState::TRAPZ, dt*rate, vPQRdot, vPQRdot_prev);
|
|
||||||
|
|
||||||
vAeroPQR = vPQR + Atmosphere->GetTurbPQR();
|
|
||||||
|
|
||||||
State->IntegrateQuat(vPQR, rate);
|
|
||||||
State->CalcMatrices();
|
|
||||||
vEuler = State->CalcEuler();
|
|
||||||
|
|
||||||
cTht = cos(vEuler(eTht)); sTht = sin(vEuler(eTht));
|
|
||||||
cPhi = cos(vEuler(ePhi)); sPhi = sin(vEuler(ePhi));
|
|
||||||
cPsi = cos(vEuler(ePsi)); sPsi = sin(vEuler(ePsi));
|
|
||||||
|
|
||||||
vEulerRates(eTht) = vPQR(2)*cPhi - vPQR(3)*sPhi;
|
|
||||||
if (cTht != 0.0) {
|
|
||||||
tTheta = sTht/cTht; // what's cheaper: / or tan() ?
|
|
||||||
vEulerRates(ePhi) = vPQR(1) + (vPQR(2)*sPhi + vPQR(3)*cPhi)*tTheta;
|
|
||||||
vEulerRates(ePsi) = (vPQR(2)*sPhi + vPQR(3)*cPhi)/cTht;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debug_lvl > 1) Debug(2);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
void FGRotation::GetState(void)
|
|
||||||
{
|
|
||||||
dt = State->Getdt();
|
|
||||||
vMoments = Aircraft->GetMoments();
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
void FGRotation::bind(void)
|
|
||||||
{
|
|
||||||
typedef double (FGRotation::*PMF)(int) const;
|
|
||||||
PropertyManager->Tie("velocities/p-rad_sec", this,1,
|
|
||||||
(PMF)&FGRotation::GetPQR);
|
|
||||||
PropertyManager->Tie("velocities/q-rad_sec", this,2,
|
|
||||||
(PMF)&FGRotation::GetPQR);
|
|
||||||
PropertyManager->Tie("velocities/r-rad_sec", this,3,
|
|
||||||
(PMF)&FGRotation::GetPQR);
|
|
||||||
PropertyManager->Tie("velocities/p-aero-rad_sec", this,1,
|
|
||||||
(PMF)&FGRotation::GetAeroPQR);
|
|
||||||
PropertyManager->Tie("velocities/q-aero-rad_sec", this,2,
|
|
||||||
(PMF)&FGRotation::GetAeroPQR);
|
|
||||||
PropertyManager->Tie("velocities/r-aero-rad_sec", this,3,
|
|
||||||
(PMF)&FGRotation::GetAeroPQR);
|
|
||||||
PropertyManager->Tie("accelerations/pdot-rad_sec", this,1,
|
|
||||||
(PMF)&FGRotation::GetPQRdot);
|
|
||||||
PropertyManager->Tie("accelerations/qdot-rad_sec", this,2,
|
|
||||||
(PMF)&FGRotation::GetPQRdot);
|
|
||||||
PropertyManager->Tie("accelerations/rdot-rad_sec", this,3,
|
|
||||||
(PMF)&FGRotation::GetPQRdot);
|
|
||||||
PropertyManager->Tie("attitude/roll-rad", this,1,
|
|
||||||
(PMF)&FGRotation::GetEuler);
|
|
||||||
PropertyManager->Tie("attitude/pitch-rad", this,2,
|
|
||||||
(PMF)&FGRotation::GetEuler);
|
|
||||||
PropertyManager->Tie("attitude/heading-true-rad", this,3,
|
|
||||||
(PMF)&FGRotation::GetEuler);
|
|
||||||
PropertyManager->Tie("velocities/phidot-rad_sec", this,1,
|
|
||||||
(PMF)&FGRotation::GetEulerRates);
|
|
||||||
PropertyManager->Tie("velocities/thetadot-rad_sec", this,2,
|
|
||||||
(PMF)&FGRotation::GetEulerRates);
|
|
||||||
PropertyManager->Tie("velocities/psidot-rad_sec", this,3,
|
|
||||||
(PMF)&FGRotation::GetEulerRates);
|
|
||||||
PropertyManager->Tie("attitude/phi-rad", this,
|
|
||||||
&FGRotation::Getphi);
|
|
||||||
PropertyManager->Tie("attitude/theta-rad", this,
|
|
||||||
&FGRotation::Gettht);
|
|
||||||
PropertyManager->Tie("attitude/psi-true-rad", this,
|
|
||||||
&FGRotation::Getpsi);
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
void FGRotation::unbind(void)
|
|
||||||
{
|
|
||||||
PropertyManager->Untie("velocities/p-rad_sec");
|
|
||||||
PropertyManager->Untie("velocities/q-rad_sec");
|
|
||||||
PropertyManager->Untie("velocities/r-rad_sec");
|
|
||||||
PropertyManager->Untie("velocities/p-aero-rad_sec");
|
|
||||||
PropertyManager->Untie("velocities/q-aero-rad_sec");
|
|
||||||
PropertyManager->Untie("velocities/r-aero-rad_sec");
|
|
||||||
PropertyManager->Untie("accelerations/pdot-rad_sec");
|
|
||||||
PropertyManager->Untie("accelerations/qdot-rad_sec");
|
|
||||||
PropertyManager->Untie("accelerations/rdot-rad_sec");
|
|
||||||
PropertyManager->Untie("attitude/roll-rad");
|
|
||||||
PropertyManager->Untie("attitude/pitch-rad");
|
|
||||||
PropertyManager->Untie("attitude/heading-true-rad");
|
|
||||||
PropertyManager->Untie("velocities/phidot-rad_sec");
|
|
||||||
PropertyManager->Untie("velocities/thetadot-rad_sec");
|
|
||||||
PropertyManager->Untie("velocities/psidot-rad_sec");
|
|
||||||
PropertyManager->Untie("attitude/phi-rad");
|
|
||||||
PropertyManager->Untie("attitude/theta-rad");
|
|
||||||
PropertyManager->Untie("attitude/psi-true-rad");
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
// The bitmasked value choices are as follows:
|
|
||||||
// unset: In this case (the default) JSBSim would only print
|
|
||||||
// out the normally expected messages, essentially echoing
|
|
||||||
// the config files as they are read. If the environment
|
|
||||||
// variable is not set, debug_lvl is set to 1 internally
|
|
||||||
// 0: This requests JSBSim not to output any messages
|
|
||||||
// whatsoever.
|
|
||||||
// 1: This value explicity requests the normal JSBSim
|
|
||||||
// startup messages
|
|
||||||
// 2: This value asks for a message to be printed out when
|
|
||||||
// a class is instantiated
|
|
||||||
// 4: When this value is set, a message is displayed when a
|
|
||||||
// FGModel object executes its Run() method
|
|
||||||
// 8: When this value is set, various runtime state variables
|
|
||||||
// are printed out periodically
|
|
||||||
// 16: When set various parameters are sanity checked and
|
|
||||||
// a message is printed out when they go out of bounds
|
|
||||||
|
|
||||||
void FGRotation::Debug(int from)
|
|
||||||
{
|
|
||||||
if (debug_lvl <= 0) return;
|
|
||||||
|
|
||||||
if (debug_lvl & 1) { // Standard console startup message output
|
|
||||||
if (from == 0) { // Constructor
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
|
||||||
if (from == 0) cout << "Instantiated: FGRotation" << endl;
|
|
||||||
if (from == 1) cout << "Destroyed: FGRotation" << endl;
|
|
||||||
}
|
|
||||||
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
|
|
||||||
}
|
|
||||||
if (debug_lvl & 8 ) { // Runtime state variables
|
|
||||||
}
|
|
||||||
if (debug_lvl & 16) { // Sanity check variables
|
|
||||||
if (from == 2) {
|
|
||||||
if (fabs(vPQR(eP)) > 100)
|
|
||||||
cout << "FGRotation::P (Roll Rate) out of bounds: " << vPQR(eP) << endl;
|
|
||||||
if (fabs(vPQR(eQ)) > 100)
|
|
||||||
cout << "FGRotation::Q (Pitch Rate) out of bounds: " << vPQR(eQ) << endl;
|
|
||||||
if (fabs(vPQR(eR)) > 100)
|
|
||||||
cout << "FGRotation::R (Yaw Rate) out of bounds: " << vPQR(eR) << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (debug_lvl & 64) {
|
|
||||||
if (from == 0) { // Constructor
|
|
||||||
cout << IdSrc << endl;
|
|
||||||
cout << IdHdr << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,156 +0,0 @@
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
Header: FGRotation.h
|
|
||||||
Author: Jon Berndt
|
|
||||||
Date started: 12/02/98
|
|
||||||
|
|
||||||
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
|
||||||
Foundation; either version 2 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
|
||||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
|
|
||||||
Further information about the GNU General Public License can also be found on
|
|
||||||
the world wide web at http://www.gnu.org.
|
|
||||||
|
|
||||||
HISTORY
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
12/02/98 JSB Created
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
SENTRY
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#ifndef FGROTATION_H
|
|
||||||
#define FGROTATION_H
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
INCLUDES
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#ifdef FGFS
|
|
||||||
# include <simgear/compiler.h>
|
|
||||||
# include <math.h>
|
|
||||||
#else
|
|
||||||
# if defined (sgi) && !defined(__GNUC__)
|
|
||||||
# include <math.h>
|
|
||||||
# else
|
|
||||||
# include <cmath>
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "FGModel.h"
|
|
||||||
#include "FGColumnVector3.h"
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
DEFINITIONS
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#define ID_ROTATION "$Id$"
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
FORWARD DECLARATIONS
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
namespace JSBSim {
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
CLASS DOCUMENTATION
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
/** Models the rotational portion of the Equations of Motion.
|
|
||||||
Note: The order of rotations used in this class corresponds to a 3-2-1 sequence,
|
|
||||||
or Y-P-R, or Z-Y-X, if you prefer.
|
|
||||||
@see Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
|
|
||||||
Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
|
|
||||||
School, January 1994
|
|
||||||
@see D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
|
|
||||||
JSC 12960, July 1977
|
|
||||||
@see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
|
|
||||||
NASA-Ames", NASA CR-2497, January 1975
|
|
||||||
@see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
|
|
||||||
Wiley & Sons, 1979 ISBN 0-471-03032-5
|
|
||||||
@see Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
|
|
||||||
1982 ISBN 0-471-08936-2
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
CLASS DECLARATION
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
class FGRotation : public FGModel
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
FGRotation(FGFDMExec*);
|
|
||||||
~FGRotation();
|
|
||||||
|
|
||||||
bool Run(void);
|
|
||||||
|
|
||||||
inline FGColumnVector3& GetPQR(void) {return vPQR;}
|
|
||||||
inline double GetPQR(int axis) const {return vPQR(axis);}
|
|
||||||
inline FGColumnVector3& GetAeroPQR(void) {return vAeroPQR;}
|
|
||||||
inline double GetAeroPQR(int axis) const {return vAeroPQR(axis);}
|
|
||||||
inline FGColumnVector3& GetPQRdot(void) {return vPQRdot;}
|
|
||||||
inline double GetPQRdot(int idx) const {return vPQRdot(idx);}
|
|
||||||
inline FGColumnVector3& GetEuler(void) {return vEuler;}
|
|
||||||
inline double GetEuler(int axis) const {return vEuler(axis);}
|
|
||||||
inline FGColumnVector3& GetEulerRates(void) { return vEulerRates; }
|
|
||||||
inline double GetEulerRates(int axis) const { return vEulerRates(axis); }
|
|
||||||
inline void SetPQR(FGColumnVector3 tt) {vPQR = tt;}
|
|
||||||
inline void SetPQR(double p, double q, double r) {vPQR(eP)=p;
|
|
||||||
vPQR(eQ)=q;
|
|
||||||
vPQR(eR)=r;}
|
|
||||||
inline void SetAeroPQR(FGColumnVector3 tt) {vAeroPQR = tt;}
|
|
||||||
inline void SetAeroPQR(double p, double q, double r) {vAeroPQR(eP)=p;
|
|
||||||
vAeroPQR(eQ)=q;
|
|
||||||
vAeroPQR(eR)=r;}
|
|
||||||
inline void SetEuler(FGColumnVector3 tt) {vEuler = tt;}
|
|
||||||
|
|
||||||
inline double Getphi(void) const {return vEuler(1);}
|
|
||||||
inline double Gettht(void) const {return vEuler(2);}
|
|
||||||
inline double Getpsi(void) const {return vEuler(3);}
|
|
||||||
|
|
||||||
inline double GetCosphi(void) const {return cPhi;}
|
|
||||||
inline double GetCostht(void) const {return cTht;}
|
|
||||||
inline double GetCospsi(void) const {return cPsi;}
|
|
||||||
|
|
||||||
inline double GetSinphi(void) const {return sPhi;}
|
|
||||||
inline double GetSintht(void) const {return sTht;}
|
|
||||||
inline double GetSinpsi(void) const {return sPsi;}
|
|
||||||
|
|
||||||
void bind(void);
|
|
||||||
void unbind(void);
|
|
||||||
|
|
||||||
private:
|
|
||||||
FGColumnVector3 vPQR;
|
|
||||||
FGColumnVector3 vAeroPQR;
|
|
||||||
FGColumnVector3 vPQRdot;
|
|
||||||
FGColumnVector3 vPQRdot_prev[4];
|
|
||||||
FGColumnVector3 vMoments;
|
|
||||||
FGColumnVector3 vEuler;
|
|
||||||
FGColumnVector3 vEulerRates;
|
|
||||||
|
|
||||||
double cTht,sTht;
|
|
||||||
double cPhi,sPhi;
|
|
||||||
double cPsi,sPsi;
|
|
||||||
|
|
||||||
double dt;
|
|
||||||
|
|
||||||
void GetState(void);
|
|
||||||
|
|
||||||
void Debug(int from);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -66,6 +66,20 @@ double FGRotor::Calculate(double PowerAvailable)
|
||||||
return 0.0;
|
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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -1,447 +0,0 @@
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
Module: FGSimTurbine.cpp
|
|
||||||
Author: David Culp
|
|
||||||
Date started: 03/11/2003
|
|
||||||
Purpose: This module models a turbine engine.
|
|
||||||
|
|
||||||
------------- Copyright (C) 2003 David Culp (davidculp2@comcast.net) ---------
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
|
||||||
Foundation; either version 2 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
|
||||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
|
|
||||||
Further information about the GNU General Public License can also be found on
|
|
||||||
the world wide web at http://www.gnu.org.
|
|
||||||
|
|
||||||
FUNCTIONAL DESCRIPTION
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
This class descends from the FGEngine class and models a Turbine engine based
|
|
||||||
on parameters given in the engine config file for this class
|
|
||||||
|
|
||||||
HISTORY
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
03/11/2003 DPC Created
|
|
||||||
09/08/2003 DPC Changed Calculate() and added engine phases
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
INCLUDES
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include "FGSimTurbine.h"
|
|
||||||
|
|
||||||
namespace JSBSim {
|
|
||||||
|
|
||||||
static const char *IdSrc = "$Id$";
|
|
||||||
static const char *IdHdr = ID_SIMTURBINE;
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
CLASS IMPLEMENTATION
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
|
|
||||||
FGSimTurbine::FGSimTurbine(FGFDMExec* exec, FGConfigFile* cfg) : FGEngine(exec)
|
|
||||||
{
|
|
||||||
SetDefaults();
|
|
||||||
|
|
||||||
Load(cfg);
|
|
||||||
Debug(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
FGSimTurbine::~FGSimTurbine()
|
|
||||||
{
|
|
||||||
Debug(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
// The main purpose of Calculate() is to determine what phase the engine should
|
|
||||||
// be in, then call the corresponding function.
|
|
||||||
|
|
||||||
double FGSimTurbine::Calculate(double dummy)
|
|
||||||
{
|
|
||||||
TAT = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556;
|
|
||||||
dt = State->Getdt() * Propulsion->GetRate();
|
|
||||||
ThrottleCmd = FCS->GetThrottleCmd(EngineNumber);
|
|
||||||
|
|
||||||
// When trimming is finished check if user wants engine OFF or RUNNING
|
|
||||||
if ((phase == tpTrim) && (dt > 0)) {
|
|
||||||
if (Running && !Starved) {
|
|
||||||
phase = tpRun;
|
|
||||||
N2 = IdleN2;
|
|
||||||
N1 = IdleN1;
|
|
||||||
OilTemp_degK = 366.0;
|
|
||||||
Cutoff = false;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
phase = tpOff;
|
|
||||||
Cutoff = true;
|
|
||||||
EGT_degC = TAT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!Running && Cutoff && Starter) {
|
|
||||||
if (phase == tpOff) phase = tpSpinUp;
|
|
||||||
}
|
|
||||||
if (!Running && !Cutoff && (N2 > 15.0)) phase = tpStart;
|
|
||||||
if (Cutoff && (phase != tpSpinUp)) phase = tpOff;
|
|
||||||
if (dt == 0) phase = tpTrim;
|
|
||||||
if (Starved) phase = tpOff;
|
|
||||||
if (Stalled) phase = tpStall;
|
|
||||||
if (Seized) phase = tpSeize;
|
|
||||||
|
|
||||||
switch (phase) {
|
|
||||||
case tpOff: Thrust = Off(); break;
|
|
||||||
case tpRun: Thrust = Run(); break;
|
|
||||||
case tpSpinUp: Thrust = SpinUp(); break;
|
|
||||||
case tpStart: Thrust = Start(); break;
|
|
||||||
case tpStall: Thrust = Stall(); break;
|
|
||||||
case tpSeize: Thrust = Seize(); break;
|
|
||||||
case tpTrim: Thrust = Trim(); break;
|
|
||||||
default: Thrust = Off();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Thrust;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
double FGSimTurbine::Off(void)
|
|
||||||
{
|
|
||||||
double qbar = Translation->Getqbar();
|
|
||||||
Running = false;
|
|
||||||
FuelFlow_pph = Seek(&FuelFlow_pph, 0, 1000.0, 10000.0);
|
|
||||||
N1 = Seek(&N1, qbar/10.0, N1/2.0, N1/2.0);
|
|
||||||
N2 = Seek(&N2, qbar/15.0, N2/2.0, N2/2.0);
|
|
||||||
EGT_degC = Seek(&EGT_degC, TAT, 11.7, 7.3);
|
|
||||||
OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0.2, 0.2);
|
|
||||||
OilPressure_psi = N2 * 0.62;
|
|
||||||
NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
|
|
||||||
EPR = Seek(&EPR, 1.0, 0.2, 0.2);
|
|
||||||
Augmentation = false;
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
double FGSimTurbine::Run(void)
|
|
||||||
{
|
|
||||||
double idlethrust, milthrust, thrust;
|
|
||||||
double N2norm; // 0.0 = idle N2, 1.0 = maximum N2
|
|
||||||
idlethrust = MilThrust * ThrustTables[0]->TotalValue();
|
|
||||||
milthrust = (MilThrust - idlethrust) * ThrustTables[1]->TotalValue();
|
|
||||||
|
|
||||||
Running = true;
|
|
||||||
Starter = false;
|
|
||||||
|
|
||||||
N2 = Seek(&N2, IdleN2 + ThrottleCmd * N2_factor, delay, delay * 3.0);
|
|
||||||
N1 = Seek(&N1, IdleN1 + ThrottleCmd * N1_factor, delay, delay * 2.4);
|
|
||||||
N2norm = (N2 - IdleN2) / N2_factor;
|
|
||||||
thrust = idlethrust + (milthrust * N2norm * N2norm);
|
|
||||||
thrust = thrust * (1.0 - BleedDemand);
|
|
||||||
EGT_degC = TAT + 363.1 + ThrottleCmd * 357.1;
|
|
||||||
OilPressure_psi = N2 * 0.62;
|
|
||||||
OilTemp_degK = Seek(&OilTemp_degK, 366.0, 1.2, 0.1);
|
|
||||||
EPR = 1.0 + thrust/MilThrust;
|
|
||||||
|
|
||||||
if (!Augmentation) {
|
|
||||||
FuelFlow_pph = Seek(&FuelFlow_pph, thrust * TSFC, 1000.0, 100000);
|
|
||||||
if (FuelFlow_pph < IdleFF) FuelFlow_pph = IdleFF;
|
|
||||||
NozzlePosition = Seek(&NozzlePosition, 1.0 - N2norm, 0.8, 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (AugMethod == 1) {
|
|
||||||
if ((ThrottleCmd > 0.99) && (N2 > 97.0)) {Augmentation = true;}
|
|
||||||
else {Augmentation = false;}
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((Augmented == 1) && Augmentation) {
|
|
||||||
thrust = MaxThrust * ThrustTables[2]->TotalValue();
|
|
||||||
FuelFlow_pph = Seek(&FuelFlow_pph, thrust * ATSFC, 5000.0, 10000.0);
|
|
||||||
NozzlePosition = Seek(&NozzlePosition, 1.0, 0.8, 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((Injected == 1) && Injection)
|
|
||||||
thrust = thrust * ThrustTables[3]->TotalValue();
|
|
||||||
|
|
||||||
ConsumeFuel();
|
|
||||||
if (Cutoff) phase = tpOff;
|
|
||||||
if (Starved) phase = tpOff;
|
|
||||||
|
|
||||||
return thrust;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
double FGSimTurbine::SpinUp(void)
|
|
||||||
{
|
|
||||||
Running = false;
|
|
||||||
FuelFlow_pph = 0.0;
|
|
||||||
N2 = Seek(&N2, 25.18, 3.0, N2/2.0);
|
|
||||||
N1 = Seek(&N1, 5.21, 1.0, N1/2.0);
|
|
||||||
EGT_degC = Seek(&EGT_degC, TAT, 11.7, 7.3);
|
|
||||||
OilPressure_psi = N2 * 0.62;
|
|
||||||
OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0.2, 0.2);
|
|
||||||
EPR = 1.0;
|
|
||||||
NozzlePosition = 1.0;
|
|
||||||
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
double FGSimTurbine::Start(void)
|
|
||||||
{
|
|
||||||
if ((N2 > 15.0) && !Starved) { // minimum 15% N2 needed for start
|
|
||||||
Cranking = true; // provided for sound effects signal
|
|
||||||
if (N2 < IdleN2) {
|
|
||||||
N2 = Seek(&N2, IdleN2, 2.0, N2/2.0);
|
|
||||||
N1 = Seek(&N1, IdleN1, 1.4, N1/2.0);
|
|
||||||
EGT_degC = Seek(&EGT_degC, TAT + 363.1, 21.3, 7.3);
|
|
||||||
FuelFlow_pph = Seek(&FuelFlow_pph, IdleFF, 103.7, 103.7);
|
|
||||||
OilPressure_psi = N2 * 0.62;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
phase = tpRun;
|
|
||||||
Running = true;
|
|
||||||
Starter = false;
|
|
||||||
Cranking = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else { // no start if N2 < 15%
|
|
||||||
phase = tpOff;
|
|
||||||
Starter = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
double FGSimTurbine::Stall(void)
|
|
||||||
{
|
|
||||||
double qbar = Translation->Getqbar();
|
|
||||||
EGT_degC = TAT + 903.14;
|
|
||||||
FuelFlow_pph = IdleFF;
|
|
||||||
N1 = Seek(&N1, qbar/10.0, 0, N1/10.0);
|
|
||||||
N2 = Seek(&N2, qbar/15.0, 0, N2/10.0);
|
|
||||||
if (ThrottleCmd == 0) phase = tpRun; // clear the stall with throttle
|
|
||||||
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
double FGSimTurbine::Seize(void)
|
|
||||||
{
|
|
||||||
double qbar = Translation->Getqbar();
|
|
||||||
N2 = 0.0;
|
|
||||||
N1 = Seek(&N1, qbar/20.0, 0, N1/15.0);
|
|
||||||
FuelFlow_pph = IdleFF;
|
|
||||||
OilPressure_psi = 0.0;
|
|
||||||
OilTemp_degK = Seek(&OilTemp_degK, TAT + 273.0, 0, 0.2);
|
|
||||||
Running = false;
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
double FGSimTurbine::Trim(void)
|
|
||||||
{
|
|
||||||
double idlethrust, milthrust, thrust;
|
|
||||||
idlethrust = MilThrust * ThrustTables[0]->TotalValue();
|
|
||||||
milthrust = (MilThrust - idlethrust) * ThrustTables[1]->TotalValue();
|
|
||||||
thrust = idlethrust + (milthrust * ThrottleCmd * ThrottleCmd);
|
|
||||||
return thrust;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
double FGSimTurbine::CalcFuelNeed(void)
|
|
||||||
{
|
|
||||||
return FuelFlow_pph /3600 * State->Getdt() * Propulsion->GetRate();
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
double FGSimTurbine::GetPowerAvailable(void) {
|
|
||||||
if( ThrottleCmd <= 0.77 )
|
|
||||||
return 64.94*ThrottleCmd;
|
|
||||||
else
|
|
||||||
return 217.38*ThrottleCmd - 117.38;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
double FGSimTurbine::Seek(double *var, double target, double accel, double decel) {
|
|
||||||
double v = *var;
|
|
||||||
if (v > target) {
|
|
||||||
v -= dt * decel;
|
|
||||||
if (v < target) v = target;
|
|
||||||
} else if (v < target) {
|
|
||||||
v += dt * accel;
|
|
||||||
if (v > target) v = target;
|
|
||||||
}
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
void FGSimTurbine::SetDefaults(void)
|
|
||||||
{
|
|
||||||
Name = "Not defined";
|
|
||||||
N1 = N2 = 0.0;
|
|
||||||
Type = etSimTurbine;
|
|
||||||
MilThrust = 10000.0;
|
|
||||||
MaxThrust = 10000.0;
|
|
||||||
BypassRatio = 0.0;
|
|
||||||
TSFC = 0.8;
|
|
||||||
ATSFC = 1.7;
|
|
||||||
IdleN1 = 30.0;
|
|
||||||
IdleN2 = 60.0;
|
|
||||||
MaxN1 = 100.0;
|
|
||||||
MaxN2 = 100.0;
|
|
||||||
Augmented = 0;
|
|
||||||
AugMethod = 0;
|
|
||||||
Injected = 0;
|
|
||||||
BleedDemand = 0.0;
|
|
||||||
ThrottleCmd = 0.0;
|
|
||||||
InletPosition = 1.0;
|
|
||||||
NozzlePosition = 1.0;
|
|
||||||
Augmentation = false;
|
|
||||||
Injection = false;
|
|
||||||
Reversed = false;
|
|
||||||
Cutoff = true;
|
|
||||||
phase = tpOff;
|
|
||||||
Stalled = false;
|
|
||||||
Seized = false;
|
|
||||||
Overtemp = false;
|
|
||||||
Fire = false;
|
|
||||||
EGT_degC = 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
bool FGSimTurbine::Load(FGConfigFile *Eng_cfg)
|
|
||||||
{
|
|
||||||
string token;
|
|
||||||
|
|
||||||
Name = Eng_cfg->GetValue("NAME");
|
|
||||||
Eng_cfg->GetNextConfigLine();
|
|
||||||
int counter=0;
|
|
||||||
|
|
||||||
while (Eng_cfg->GetValue() != string("/FG_SIMTURBINE")) {
|
|
||||||
*Eng_cfg >> token;
|
|
||||||
|
|
||||||
if (token[0] == '<') token.erase(0,1); // Tables are read "<TABLE"
|
|
||||||
|
|
||||||
if (token == "MILTHRUST") *Eng_cfg >> MilThrust;
|
|
||||||
else if (token == "MAXTHRUST") *Eng_cfg >> MaxThrust;
|
|
||||||
else if (token == "BYPASSRATIO") *Eng_cfg >> BypassRatio;
|
|
||||||
else if (token == "TSFC") *Eng_cfg >> TSFC;
|
|
||||||
else if (token == "ATSFC") *Eng_cfg >> ATSFC;
|
|
||||||
else if (token == "IDLEN1") *Eng_cfg >> IdleN1;
|
|
||||||
else if (token == "IDLEN2") *Eng_cfg >> IdleN2;
|
|
||||||
else if (token == "MAXN1") *Eng_cfg >> MaxN1;
|
|
||||||
else if (token == "MAXN2") *Eng_cfg >> MaxN2;
|
|
||||||
else if (token == "AUGMENTED") *Eng_cfg >> Augmented;
|
|
||||||
else if (token == "AUGMETHOD") *Eng_cfg >> AugMethod;
|
|
||||||
else if (token == "INJECTED") *Eng_cfg >> Injected;
|
|
||||||
else if (token == "MINTHROTTLE") *Eng_cfg >> MinThrottle;
|
|
||||||
else if (token == "TABLE") {
|
|
||||||
if (counter++ == 0) Debug(2); // print engine specs prior to table read
|
|
||||||
ThrustTables.push_back( new FGCoefficient(FDMExec) );
|
|
||||||
ThrustTables.back()->Load(Eng_cfg);
|
|
||||||
}
|
|
||||||
else cerr << "Unhandled token in Engine config file: " << token << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pre-calculations and initializations
|
|
||||||
|
|
||||||
delay = 60.0 / (BypassRatio + 3.0);
|
|
||||||
N1_factor = MaxN1 - IdleN1;
|
|
||||||
N2_factor = MaxN2 - IdleN2;
|
|
||||||
OilTemp_degK = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556 + 273.0;
|
|
||||||
IdleFF = pow(MilThrust, 0.2) * 107.0; // just an estimate
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
// The bitmasked value choices are as follows:
|
|
||||||
// unset: In this case (the default) JSBSim would only print
|
|
||||||
// out the normally expected messages, essentially echoing
|
|
||||||
// the config files as they are read. If the environment
|
|
||||||
// variable is not set, debug_lvl is set to 1 internally
|
|
||||||
// 0: This requests JSBSim not to output any messages
|
|
||||||
// whatsoever.
|
|
||||||
// 1: This value explicity requests the normal JSBSim
|
|
||||||
// startup messages
|
|
||||||
// 2: This value asks for a message to be printed out when
|
|
||||||
// a class is instantiated
|
|
||||||
// 4: When this value is set, a message is displayed when a
|
|
||||||
// FGModel object executes its Run() method
|
|
||||||
// 8: When this value is set, various runtime state variables
|
|
||||||
// are printed out periodically
|
|
||||||
// 16: When set various parameters are sanity checked and
|
|
||||||
// a message is printed out when they go out of bounds
|
|
||||||
|
|
||||||
void FGSimTurbine::Debug(int from)
|
|
||||||
{
|
|
||||||
if (debug_lvl <= 0) return;
|
|
||||||
|
|
||||||
if (debug_lvl & 1) { // Standard console startup message output
|
|
||||||
if (from == 0) { // Constructor
|
|
||||||
|
|
||||||
}
|
|
||||||
if (from == 2) { // called from Load()
|
|
||||||
cout << "\n Engine Name: " << Name << endl;
|
|
||||||
cout << " MilThrust: " << MilThrust << endl;
|
|
||||||
cout << " MaxThrust: " << MaxThrust << endl;
|
|
||||||
cout << " BypassRatio: " << BypassRatio << endl;
|
|
||||||
cout << " TSFC: " << TSFC << endl;
|
|
||||||
cout << " ATSFC: " << ATSFC << endl;
|
|
||||||
cout << " IdleN1: " << IdleN1 << endl;
|
|
||||||
cout << " IdleN2: " << IdleN2 << endl;
|
|
||||||
cout << " MaxN1: " << MaxN1 << endl;
|
|
||||||
cout << " MaxN2: " << MaxN2 << endl;
|
|
||||||
cout << " Augmented: " << Augmented << endl;
|
|
||||||
cout << " AugMethod: " << AugMethod << endl;
|
|
||||||
cout << " Injected: " << Injected << endl;
|
|
||||||
cout << " MinThrottle: " << MinThrottle << endl;
|
|
||||||
|
|
||||||
cout << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
|
||||||
if (from == 0) cout << "Instantiated: FGSimTurbine" << endl;
|
|
||||||
if (from == 1) cout << "Destroyed: FGSimTurbine" << endl;
|
|
||||||
}
|
|
||||||
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
|
|
||||||
}
|
|
||||||
if (debug_lvl & 8 ) { // Runtime state variables
|
|
||||||
}
|
|
||||||
if (debug_lvl & 16) { // Sanity checking
|
|
||||||
}
|
|
||||||
if (debug_lvl & 64) {
|
|
||||||
if (from == 0) { // Constructor
|
|
||||||
cout << IdSrc << endl;
|
|
||||||
cout << IdHdr << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,243 +0,0 @@
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
Header: FGSimTurbine.h
|
|
||||||
Author: David Culp
|
|
||||||
Date started: 03/11/2003
|
|
||||||
|
|
||||||
------------- Copyright (C) 2003 David Culp (davidculp2@comcast.net)----------
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
|
||||||
Foundation; either version 2 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
|
||||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
|
|
||||||
Further information about the GNU General Public License can also be found on
|
|
||||||
the world wide web at http://www.gnu.org.
|
|
||||||
|
|
||||||
HISTORY
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
03/11/2003 DPC Created, based on FGTurbine
|
|
||||||
09/22/2003 DPC Added starting, stopping, new framework
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
SENTRY
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#ifndef FGSIMTURBINE_H
|
|
||||||
#define FGSIMTURBINE_H
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
INCLUDES
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#include <vector>
|
|
||||||
#include "FGEngine.h"
|
|
||||||
#include "FGConfigFile.h"
|
|
||||||
#include "FGCoefficient.h"
|
|
||||||
|
|
||||||
#define ID_SIMTURBINE "$Id$"
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
FORWARD DECLARATIONS
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
namespace JSBSim {
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
CLASS DOCUMENTATION
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
/** This class models a turbine engine. Based on Jon Berndt's FGTurbine module.
|
|
||||||
Here the term "phase" signifies the engine's mode of operation. At any given
|
|
||||||
time the engine is in only one phase. At simulator startup the engine will be
|
|
||||||
placed in the Trim phase in order to provide a simplified thrust value without
|
|
||||||
throttle lag. When trimming is complete the engine will go to the Off phase,
|
|
||||||
unless the value FGEngine::Running has been previously set to true, in which
|
|
||||||
case the engine will go to the Run phase. Once an engine is in the Off phase
|
|
||||||
the full starting procedure (or airstart) must be used to get it running.
|
|
||||||
<P>
|
|
||||||
- STARTING (on ground):
|
|
||||||
-# Set the control FGEngine::Starter to true. The engine will spin up to
|
|
||||||
a maximum of about %25 N2 (%5.2 N1). This simulates the action of a
|
|
||||||
pneumatic starter.
|
|
||||||
-# After reaching %15 N2 set the control FGEngine::Cutoff to false. If fuel
|
|
||||||
is available the engine will now accelerate to idle. The starter will
|
|
||||||
automatically be set to false after the start cycle.
|
|
||||||
<P>
|
|
||||||
- STARTING (in air):
|
|
||||||
-# Increase speed to obtain a minimum of %15 N2. If this is not possible,
|
|
||||||
the starter may be used to assist.
|
|
||||||
-# Place the control FGEngine::Cutoff to false.
|
|
||||||
<P>
|
|
||||||
Ignition is assumed to be on anytime the Cutoff control is set to false,
|
|
||||||
therefore a seperate ignition system is not modeled.
|
|
||||||
|
|
||||||
Configuration File Format
|
|
||||||
<pre>
|
|
||||||
\<FG_SIMTURBINE NAME="<name>">
|
|
||||||
MILTHRUST \<thrust>
|
|
||||||
MAXTHRUST \<thrust>
|
|
||||||
BYPASSRATIO \<bypass ratio>
|
|
||||||
TSFC \<thrust specific fuel consumption>
|
|
||||||
ATSFC \<afterburning thrust specific fuel consumption>
|
|
||||||
IDLEN1 \<idle N1>
|
|
||||||
IDLEN2 \<idle N2>
|
|
||||||
MAXN1 \<max N1>
|
|
||||||
MAXN2 \<max N2>
|
|
||||||
AUGMENTED \<0|1>
|
|
||||||
AUGMETHOD \<0|1>
|
|
||||||
INJECTED \<0|1>
|
|
||||||
...
|
|
||||||
\</FG_SIMTURBINE>
|
|
||||||
</pre>
|
|
||||||
Definition of the turbine engine configuration file parameters:
|
|
||||||
<pre>
|
|
||||||
<b>MILTHRUST</b> - Maximum thrust, static, at sea level, lbf.
|
|
||||||
<b>MAXTHRUST</b> - Afterburning thrust, static, at sea level, lbf
|
|
||||||
[this value will be ignored when AUGMENTED is zero (false)].
|
|
||||||
<b>BYPASSRATIO</b> - Ratio of bypass air flow to core air flow.
|
|
||||||
<b>TSFC</b> - Thrust-specific fuel consumption, lbm/hr/lbf
|
|
||||||
[i.e. fuel flow divided by thrust].
|
|
||||||
<b>ATSFC</b> - Afterburning TSFC, lbm/hr/lbf
|
|
||||||
[this value will be ignored when AUGMENTED is zero (false)]
|
|
||||||
<b>IDLEN1</b> - Fan rotor rpm (% of max) at idle
|
|
||||||
<b>IDLEN2</b> - Core rotor rpm (% of max) at idle
|
|
||||||
<b>MAXN1</b> - Fan rotor rpm (% of max) at full throttle [not always 100!]
|
|
||||||
<b>MAXN2</b> - Core rotor rpm (% of max) at full throttle [not always 100!]
|
|
||||||
<b>AUGMENTED</b>
|
|
||||||
0 == afterburner not installed
|
|
||||||
1 == afterburner installed
|
|
||||||
<b>AUGMETHOD</b>
|
|
||||||
0 == afterburner activated by property /engines/engine[n]/augmentation
|
|
||||||
1 == afterburner activated by pushing throttle above 99% position
|
|
||||||
[this item will be ignored when AUGMENTED == 0]
|
|
||||||
<b>INJECTED</b>
|
|
||||||
0 == Water injection not installed
|
|
||||||
1 == Water injection installed
|
|
||||||
</pre>
|
|
||||||
@author David P. Culp
|
|
||||||
@version "$Id$"
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
CLASS DECLARATION
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
class FGSimTurbine : public FGEngine
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
/** Constructor
|
|
||||||
@param Executive pointer to executive structure
|
|
||||||
@param Eng_cfg pointer to engine config file instance */
|
|
||||||
FGSimTurbine(FGFDMExec* Executive, FGConfigFile* Eng_cfg);
|
|
||||||
/// Destructor
|
|
||||||
~FGSimTurbine();
|
|
||||||
|
|
||||||
enum phaseType { tpOff, tpRun, tpSpinUp, tpStart, tpStall, tpSeize, tpTrim };
|
|
||||||
|
|
||||||
double Calculate(double PowerRequired);
|
|
||||||
double CalcFuelNeed(void);
|
|
||||||
double GetPowerAvailable(void);
|
|
||||||
double Seek(double* var, double target, double accel, double decel);
|
|
||||||
|
|
||||||
phaseType GetPhase(void) { return phase; }
|
|
||||||
|
|
||||||
bool GetOvertemp(void) {return Overtemp; }
|
|
||||||
bool GetInjection(void) {return Injection;}
|
|
||||||
bool GetFire(void) { return Fire; }
|
|
||||||
bool GetAugmentation(void) {return Augmentation;}
|
|
||||||
bool GetReversed(void) { return Reversed; }
|
|
||||||
bool GetCutoff(void) { return Cutoff; }
|
|
||||||
int GetIgnition(void) {return Ignition;}
|
|
||||||
|
|
||||||
double GetInlet(void) { return InletPosition; }
|
|
||||||
double GetNozzle(void) { return NozzlePosition; }
|
|
||||||
double GetBleedDemand(void) {return BleedDemand;}
|
|
||||||
double GetN1(void) {return N1;}
|
|
||||||
double GetN2(void) {return N2;}
|
|
||||||
double GetEPR(void) {return EPR;}
|
|
||||||
double GetEGT(void) {return EGT_degC;}
|
|
||||||
|
|
||||||
double getOilPressure_psi () const {return OilPressure_psi;}
|
|
||||||
double getOilTemp_degF (void) {return KelvinToFahrenheit(OilTemp_degK);}
|
|
||||||
|
|
||||||
void SetInjection(bool injection) {Injection = injection;}
|
|
||||||
void SetIgnition(int ignition) {Ignition = ignition;}
|
|
||||||
void SetAugmentation(bool augmentation) {Augmentation = augmentation;}
|
|
||||||
void SetPhase( phaseType p ) { phase = p; }
|
|
||||||
void SetEPR(double epr) {EPR = epr;}
|
|
||||||
void SetBleedDemand(double bleedDemand) {BleedDemand = bleedDemand;}
|
|
||||||
void SetReverse(bool reversed) { Reversed = reversed; }
|
|
||||||
void SetCutoff(bool cutoff) { Cutoff = cutoff; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
typedef vector<FGCoefficient*> CoeffArray;
|
|
||||||
CoeffArray ThrustTables;
|
|
||||||
|
|
||||||
phaseType phase; ///< Operating mode, or "phase"
|
|
||||||
double MilThrust; ///< Maximum Unaugmented Thrust, static @ S.L. (lbf)
|
|
||||||
double MaxThrust; ///< Maximum Augmented Thrust, static @ S.L. (lbf)
|
|
||||||
double BypassRatio; ///< Bypass Ratio
|
|
||||||
double TSFC; ///< Thrust Specific Fuel Consumption (lbm/hr/lbf)
|
|
||||||
double ATSFC; ///< Augmented TSFC (lbm/hr/lbf)
|
|
||||||
double IdleN1; ///< Idle N1
|
|
||||||
double IdleN2; ///< Idle N2
|
|
||||||
double N1; ///< N1
|
|
||||||
double N2; ///< N2
|
|
||||||
double MaxN1; ///< N1 at 100% throttle
|
|
||||||
double MaxN2; ///< N2 at 100% throttle
|
|
||||||
double IdleFF; ///< Idle Fuel Flow (lbm/hr)
|
|
||||||
double delay; ///< Inverse spool-up time from idle to 100% (seconds)
|
|
||||||
double dt; ///< Simulator time slice
|
|
||||||
double N1_factor; ///< factor to tie N1 and throttle
|
|
||||||
double N2_factor; ///< factor to tie N2 and throttle
|
|
||||||
double ThrottleCmd; ///< FCS-supplied throttle position
|
|
||||||
double TAT; ///< total air temperature (deg C)
|
|
||||||
bool Stalled; ///< true if engine is compressor-stalled
|
|
||||||
bool Seized; ///< true if inner spool is seized
|
|
||||||
bool Overtemp; ///< true if EGT exceeds limits
|
|
||||||
bool Fire; ///< true if engine fire detected
|
|
||||||
bool Injection;
|
|
||||||
bool Augmentation;
|
|
||||||
bool Reversed;
|
|
||||||
bool Cutoff;
|
|
||||||
int Injected; ///< = 1 if water injection installed
|
|
||||||
int Ignition;
|
|
||||||
int Augmented; ///< = 1 if augmentation installed
|
|
||||||
int AugMethod; ///< = 0 if using property /engine[n]/augmentation
|
|
||||||
///< = 1 if using last 1% of throttle movement
|
|
||||||
double EGT_degC;
|
|
||||||
double EPR;
|
|
||||||
double OilPressure_psi;
|
|
||||||
double OilTemp_degK;
|
|
||||||
double BleedDemand;
|
|
||||||
double InletPosition;
|
|
||||||
double NozzlePosition;
|
|
||||||
|
|
||||||
double Off(void);
|
|
||||||
double Run(void);
|
|
||||||
double SpinUp(void);
|
|
||||||
double Start(void);
|
|
||||||
double Stall(void);
|
|
||||||
double Seize(void);
|
|
||||||
double Trim(void);
|
|
||||||
|
|
||||||
void SetDefaults(void);
|
|
||||||
bool Load(FGConfigFile *ENG_cfg);
|
|
||||||
void Debug(int from);
|
|
||||||
|
|
||||||
};
|
|
||||||
}
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -47,8 +47,8 @@ INCLUDES
|
||||||
# endif
|
# endif
|
||||||
#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
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -1,320 +0,0 @@
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
Module: FGTranslation.cpp
|
|
||||||
Author: Jon Berndt
|
|
||||||
Date started: 12/02/98
|
|
||||||
Purpose: Integrates the translational EOM
|
|
||||||
Called by: FDMExec
|
|
||||||
|
|
||||||
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
|
||||||
Foundation; either version 2 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
|
||||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
|
|
||||||
Further information about the GNU General Public License can also be found on
|
|
||||||
the world wide web at http://www.gnu.org.
|
|
||||||
|
|
||||||
FUNCTIONAL DESCRIPTION
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
This class integrates the translational EOM.
|
|
||||||
|
|
||||||
HISTORY
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
12/02/98 JSB Created
|
|
||||||
7/23/99 TP Added data member and modified Run and PutState to calcuate
|
|
||||||
Mach number
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
COMMENTS, REFERENCES, and NOTES
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
[1] Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
|
|
||||||
Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
|
|
||||||
School, January 1994
|
|
||||||
[2] D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
|
|
||||||
JSC 12960, July 1977
|
|
||||||
[3] Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
|
|
||||||
NASA-Ames", NASA CR-2497, January 1975
|
|
||||||
[4] Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
|
|
||||||
Wiley & Sons, 1979 ISBN 0-471-03032-5
|
|
||||||
[5] Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
|
|
||||||
1982 ISBN 0-471-08936-2
|
|
||||||
|
|
||||||
The order of rotations used in this class corresponds to a 3-2-1 sequence,
|
|
||||||
or Y-P-R, or Z-Y-X, if you prefer.
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
INCLUDES
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#include "FGTranslation.h"
|
|
||||||
#include "FGRotation.h"
|
|
||||||
#include "FGAtmosphere.h"
|
|
||||||
#include "FGState.h"
|
|
||||||
#include "FGFDMExec.h"
|
|
||||||
#include "FGFCS.h"
|
|
||||||
#include "FGMassBalance.h"
|
|
||||||
#include "FGAircraft.h"
|
|
||||||
#include "FGPosition.h"
|
|
||||||
#include "FGAuxiliary.h"
|
|
||||||
#include "FGOutput.h"
|
|
||||||
#include "FGPropertyManager.h"
|
|
||||||
|
|
||||||
namespace JSBSim {
|
|
||||||
|
|
||||||
static const char *IdSrc = "$Id$";
|
|
||||||
static const char *IdHdr = ID_TRANSLATION;
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
CLASS IMPLEMENTATION
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
|
|
||||||
FGTranslation::FGTranslation(FGFDMExec* fdmex) : FGModel(fdmex)
|
|
||||||
{
|
|
||||||
Name = "FGTranslation";
|
|
||||||
qbar = 0;
|
|
||||||
qbarUW = 0.0;
|
|
||||||
qbarUV = 0.0;
|
|
||||||
Vt = 0.0;
|
|
||||||
Mach = 0.0;
|
|
||||||
alpha = beta = 0.0;
|
|
||||||
adot = bdot = 0.0;
|
|
||||||
|
|
||||||
vUVWdot.InitMatrix();
|
|
||||||
vUVWdot_prev[0].InitMatrix();
|
|
||||||
vUVWdot_prev[1].InitMatrix();
|
|
||||||
vUVWdot_prev[2].InitMatrix();
|
|
||||||
vUVWdot_prev[3].InitMatrix();
|
|
||||||
|
|
||||||
bind();
|
|
||||||
Debug(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
FGTranslation::~FGTranslation(void)
|
|
||||||
{
|
|
||||||
unbind();
|
|
||||||
Debug(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
bool FGTranslation::Run(void)
|
|
||||||
{
|
|
||||||
if (!FGModel::Run()) {
|
|
||||||
|
|
||||||
vUVWdot = vUVW*Rotation->GetPQR() + Aircraft->GetBodyAccel();
|
|
||||||
|
|
||||||
vUVW += State->Integrate(FGState::TRAPZ, State->Getdt()*rate, vUVWdot, vUVWdot_prev);
|
|
||||||
|
|
||||||
vAeroUVW = vUVW + State->GetTl2b()*Atmosphere->GetWindNED();
|
|
||||||
|
|
||||||
Vt = vAeroUVW.Magnitude();
|
|
||||||
if ( Vt > 1) {
|
|
||||||
if (vAeroUVW(eW) != 0.0)
|
|
||||||
alpha = vAeroUVW(eU)*vAeroUVW(eU) > 0.0 ? atan2(vAeroUVW(eW), vAeroUVW(eU)) : 0.0;
|
|
||||||
if (vAeroUVW(eV) != 0.0)
|
|
||||||
beta = vAeroUVW(eU)*vAeroUVW(eU)+vAeroUVW(eW)*vAeroUVW(eW) > 0.0 ? atan2(vAeroUVW(eV),
|
|
||||||
sqrt(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW))) : 0.0;
|
|
||||||
|
|
||||||
double mUW = (vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW));
|
|
||||||
double signU=1;
|
|
||||||
if (vAeroUVW(eU) != 0.0)
|
|
||||||
signU = vAeroUVW(eU)/fabs(vAeroUVW(eU));
|
|
||||||
|
|
||||||
if ( (mUW == 0.0) || (Vt == 0.0) ) {
|
|
||||||
adot = 0.0;
|
|
||||||
bdot = 0.0;
|
|
||||||
} else {
|
|
||||||
adot = (vAeroUVW(eU)*vAeroUVW(eW) - vAeroUVW(eW)*vUVWdot(eU))/mUW;
|
|
||||||
bdot = (signU*mUW*vUVWdot(eV) - vAeroUVW(eV)*(vAeroUVW(eU)*vUVWdot(eU)
|
|
||||||
+ vAeroUVW(eW)*vUVWdot(eW)))/(Vt*Vt*sqrt(mUW));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
alpha = beta = adot = bdot = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
qbar = 0.5*Atmosphere->GetDensity()*Vt*Vt;
|
|
||||||
qbarUW = 0.5*Atmosphere->GetDensity()*(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eW)*vAeroUVW(eW));
|
|
||||||
qbarUV = 0.5*Atmosphere->GetDensity()*(vAeroUVW(eU)*vAeroUVW(eU) + vAeroUVW(eV)*vAeroUVW(eV));
|
|
||||||
Mach = Vt / Atmosphere->GetSoundSpeed();
|
|
||||||
vMachUVW(eU) = vAeroUVW(eU) / Atmosphere->GetSoundSpeed();
|
|
||||||
vMachUVW(eV) = vAeroUVW(eV) / Atmosphere->GetSoundSpeed();
|
|
||||||
vMachUVW(eW) = vAeroUVW(eW) / Atmosphere->GetSoundSpeed();
|
|
||||||
|
|
||||||
if (debug_lvl > 1) Debug(1);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
void FGTranslation::bind(void)
|
|
||||||
{
|
|
||||||
typedef double (FGTranslation::*PMF)(int) const;
|
|
||||||
PropertyManager->Tie("velocities/u-fps", this,1,
|
|
||||||
(PMF)&FGTranslation::GetUVW /*,
|
|
||||||
&FGTranslation::SetUVW,
|
|
||||||
true */);
|
|
||||||
PropertyManager->Tie("velocities/v-fps", this,2,
|
|
||||||
(PMF)&FGTranslation::GetUVW /*,
|
|
||||||
&FGTranslation::SetUVW,
|
|
||||||
true*/);
|
|
||||||
PropertyManager->Tie("velocities/w-fps", this,3,
|
|
||||||
(PMF)&FGTranslation::GetUVW /*,
|
|
||||||
&FGTranslation::SetUVW,
|
|
||||||
true*/);
|
|
||||||
PropertyManager->Tie("accelerations/udot-fps", this,1,
|
|
||||||
(PMF)&FGTranslation::GetUVWdot);
|
|
||||||
PropertyManager->Tie("accelerations/vdot-fps", this,2,
|
|
||||||
(PMF)&FGTranslation::GetUVWdot);
|
|
||||||
PropertyManager->Tie("accelerations/wdot-fps", this,3,
|
|
||||||
(PMF)&FGTranslation::GetUVWdot);
|
|
||||||
PropertyManager->Tie("velocities/u-aero-fps", this,1,
|
|
||||||
(PMF)&FGTranslation::GetAeroUVW);
|
|
||||||
PropertyManager->Tie("velocities/v-aero-fps", this,2,
|
|
||||||
(PMF)&FGTranslation::GetAeroUVW);
|
|
||||||
PropertyManager->Tie("velocities/w-aero-fps", this,3,
|
|
||||||
(PMF)&FGTranslation::GetAeroUVW);
|
|
||||||
PropertyManager->Tie("aero/alpha-rad", this,
|
|
||||||
&FGTranslation::Getalpha,
|
|
||||||
&FGTranslation::Setalpha,
|
|
||||||
true);
|
|
||||||
PropertyManager->Tie("aero/beta-rad", this,
|
|
||||||
&FGTranslation::Getbeta,
|
|
||||||
&FGTranslation::Setbeta,
|
|
||||||
true);
|
|
||||||
PropertyManager->Tie("aero/mag-beta-rad", this,
|
|
||||||
&FGTranslation::GetMagBeta);
|
|
||||||
PropertyManager->Tie("aero/qbar-psf", this,
|
|
||||||
&FGTranslation::Getqbar,
|
|
||||||
&FGTranslation::Setqbar,
|
|
||||||
true);
|
|
||||||
PropertyManager->Tie("aero/qbarUW-psf", this,
|
|
||||||
&FGTranslation::GetqbarUW,
|
|
||||||
&FGTranslation::SetqbarUW,
|
|
||||||
true);
|
|
||||||
PropertyManager->Tie("aero/qbarUV-psf", this,
|
|
||||||
&FGTranslation::GetqbarUV,
|
|
||||||
&FGTranslation::SetqbarUV,
|
|
||||||
true);
|
|
||||||
PropertyManager->Tie("velocities/vt-fps", this,
|
|
||||||
&FGTranslation::GetVt,
|
|
||||||
&FGTranslation::SetVt,
|
|
||||||
true);
|
|
||||||
PropertyManager->Tie("velocities/mach-norm", this,
|
|
||||||
&FGTranslation::GetMach,
|
|
||||||
&FGTranslation::SetMach,
|
|
||||||
true);
|
|
||||||
PropertyManager->Tie("aero/alphadot-rad_sec", this,
|
|
||||||
&FGTranslation::Getadot,
|
|
||||||
&FGTranslation::Setadot,
|
|
||||||
true);
|
|
||||||
PropertyManager->Tie("aero/betadot-rad_sec", this,
|
|
||||||
&FGTranslation::Getbdot,
|
|
||||||
&FGTranslation::Setbdot,
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
void FGTranslation::unbind(void)
|
|
||||||
{
|
|
||||||
PropertyManager->Untie("velocities/u-fps");
|
|
||||||
PropertyManager->Untie("velocities/v-fps");
|
|
||||||
PropertyManager->Untie("velocities/w-fps");
|
|
||||||
PropertyManager->Untie("accelerations/udot-fps");
|
|
||||||
PropertyManager->Untie("accelerations/vdot-fps");
|
|
||||||
PropertyManager->Untie("accelerations/wdot-fps");
|
|
||||||
PropertyManager->Untie("velocities/u-aero-fps");
|
|
||||||
PropertyManager->Untie("velocities/v-aero-fps");
|
|
||||||
PropertyManager->Untie("velocities/w-aero-fps");
|
|
||||||
PropertyManager->Untie("aero/alpha-rad");
|
|
||||||
PropertyManager->Untie("aero/beta-rad");
|
|
||||||
PropertyManager->Untie("aero/qbar-psf");
|
|
||||||
PropertyManager->Untie("aero/qbarUW-psf");
|
|
||||||
PropertyManager->Untie("aero/qbarUV-psf");
|
|
||||||
PropertyManager->Untie("velocities/vt-fps");
|
|
||||||
PropertyManager->Untie("velocities/mach-norm");
|
|
||||||
PropertyManager->Untie("aero/alphadot-rad_sec");
|
|
||||||
PropertyManager->Untie("aero/betadot-rad_sec");
|
|
||||||
PropertyManager->Untie("aero/mag-beta-rad");
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
// The bitmasked value choices are as follows:
|
|
||||||
// unset: In this case (the default) JSBSim would only print
|
|
||||||
// out the normally expected messages, essentially echoing
|
|
||||||
// the config files as they are read. If the environment
|
|
||||||
// variable is not set, debug_lvl is set to 1 internally
|
|
||||||
// 0: This requests JSBSim not to output any messages
|
|
||||||
// whatsoever.
|
|
||||||
// 1: This value explicity requests the normal JSBSim
|
|
||||||
// startup messages
|
|
||||||
// 2: This value asks for a message to be printed out when
|
|
||||||
// a class is instantiated
|
|
||||||
// 4: When this value is set, a message is displayed when a
|
|
||||||
// FGModel object executes its Run() method
|
|
||||||
// 8: When this value is set, various runtime state variables
|
|
||||||
// are printed out periodically
|
|
||||||
// 16: When set various parameters are sanity checked and
|
|
||||||
// a message is printed out when they go out of bounds
|
|
||||||
|
|
||||||
void FGTranslation::Debug(int from)
|
|
||||||
{
|
|
||||||
if (debug_lvl <= 0) return;
|
|
||||||
|
|
||||||
if (debug_lvl & 1) { // Standard console startup message output
|
|
||||||
if (from == 0) { // Constructor
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
|
||||||
if (from == 0) cout << "Instantiated: FGTranslation" << endl;
|
|
||||||
if (from == 1) cout << "Destroyed: FGTranslation" << endl;
|
|
||||||
}
|
|
||||||
if (debug_lvl & 4 ) { // Run() method entry print for FGModel-derived objects
|
|
||||||
}
|
|
||||||
if (debug_lvl & 8 ) { // Runtime state variables
|
|
||||||
}
|
|
||||||
if (debug_lvl & 16) { // Sanity checking
|
|
||||||
if (fabs(vUVW(eU)) > 1e6)
|
|
||||||
cout << "FGTranslation::U velocity out of bounds: " << vUVW(eU) << endl;
|
|
||||||
if (fabs(vUVW(eV)) > 1e6)
|
|
||||||
cout << "FGTranslation::V velocity out of bounds: " << vUVW(eV) << endl;
|
|
||||||
if (fabs(vUVW(eW)) > 1e6)
|
|
||||||
cout << "FGTranslation::W velocity out of bounds: " << vUVW(eW) << endl;
|
|
||||||
if (fabs(vUVWdot(eU)) > 1e4)
|
|
||||||
cout << "FGTranslation::U acceleration out of bounds: " << vUVWdot(eU) << endl;
|
|
||||||
if (fabs(vUVWdot(eV)) > 1e4)
|
|
||||||
cout << "FGTranslation::V acceleration out of bounds: " << vUVWdot(eV) << endl;
|
|
||||||
if (fabs(vUVWdot(eW)) > 1e4)
|
|
||||||
cout << "FGTranslation::W acceleration out of bounds: " << vUVWdot(eW) << endl;
|
|
||||||
if (Mach > 100 || Mach < 0.00)
|
|
||||||
cout << "FGTranslation::Mach is out of bounds: " << Mach << endl;
|
|
||||||
if (qbar > 1e6 || qbar < 0.00)
|
|
||||||
cout << "FGTranslation::qbar is out of bounds: " << qbar << endl;
|
|
||||||
}
|
|
||||||
if (debug_lvl & 64) {
|
|
||||||
if (from == 0) { // Constructor
|
|
||||||
cout << IdSrc << endl;
|
|
||||||
cout << IdHdr << endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,155 +0,0 @@
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
Header: FGTranslation.h
|
|
||||||
Author: Jon Berndt
|
|
||||||
Date started: 12/02/98
|
|
||||||
|
|
||||||
------------- Copyright (C) 1999 Jon S. Berndt (jsb@hal-pc.org) -------------
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
|
||||||
the terms of the GNU General Public License as published by the Free Software
|
|
||||||
Foundation; either version 2 of the License, or (at your option) any later
|
|
||||||
version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
||||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
||||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
|
|
||||||
details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along with
|
|
||||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
|
||||||
Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
||||||
|
|
||||||
Further information about the GNU General Public License can also be found on
|
|
||||||
the world wide web at http://www.gnu.org.
|
|
||||||
|
|
||||||
HISTORY
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
12/02/98 JSB Created
|
|
||||||
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
SENTRY
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#ifndef FGTRANSLATION_H
|
|
||||||
#define FGTRANSLATION_H
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
INCLUDES
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#ifdef FGFS
|
|
||||||
# include <simgear/compiler.h>
|
|
||||||
# ifdef SG_HAVE_STD_INCLUDES
|
|
||||||
# include <cmath>
|
|
||||||
# else
|
|
||||||
# include <math.h>
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# if defined(sgi) && !defined(__GNUC__)
|
|
||||||
# include <math.h>
|
|
||||||
# else
|
|
||||||
# include <cmath>
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "FGModel.h"
|
|
||||||
#include "FGColumnVector3.h"
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
DEFINITIONS
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
#define ID_TRANSLATION "$Id$"
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
FORWARD DECLARATION
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
namespace JSBSim {
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
CLASS DOCUMENTATION
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
/** Models the translation aspects of the EOM.
|
|
||||||
Note: The order of rotations used in this class corresponds to a 3-2-1 sequence,
|
|
||||||
or Y-P-R, or Z-Y-X, if you prefer.
|
|
||||||
@see Cooke, Zyda, Pratt, and McGhee, "NPSNET: Flight Simulation Dynamic Modeling
|
|
||||||
Using Quaternions", Presence, Vol. 1, No. 4, pp. 404-420 Naval Postgraduate
|
|
||||||
School, January 1994
|
|
||||||
@see D. M. Henderson, "Euler Angles, Quaternions, and Transformation Matrices",
|
|
||||||
JSC 12960, July 1977
|
|
||||||
@see Richard E. McFarland, "A Standard Kinematic Model for Flight Simulation at
|
|
||||||
NASA-Ames", NASA CR-2497, January 1975
|
|
||||||
@see Barnes W. McCormick, "Aerodynamics, Aeronautics, and Flight Mechanics",
|
|
||||||
Wiley & Sons, 1979 ISBN 0-471-03032-5
|
|
||||||
@see Bernard Etkin, "Dynamics of Flight, Stability and Control", Wiley & Sons,
|
|
||||||
1982 ISBN 0-471-08936-2
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
CLASS DECLARATION
|
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
|
||||||
|
|
||||||
class FGTranslation : public FGModel {
|
|
||||||
public:
|
|
||||||
FGTranslation(FGFDMExec*);
|
|
||||||
~FGTranslation();
|
|
||||||
|
|
||||||
inline double GetUVW (int idx) const { return vUVW(idx); }
|
|
||||||
inline FGColumnVector3& GetUVW (void) { return vUVW; }
|
|
||||||
inline FGColumnVector3& GetUVWdot(void) { return vUVWdot; }
|
|
||||||
inline double GetUVWdot(int idx) const { return vUVWdot(idx); }
|
|
||||||
inline FGColumnVector3& GetAeroUVW (void) { return vAeroUVW; }
|
|
||||||
inline double GetAeroUVW (int idx) const { return vAeroUVW(idx); }
|
|
||||||
|
|
||||||
double Getalpha(void) const { return alpha; }
|
|
||||||
double Getbeta (void) const { return beta; }
|
|
||||||
inline double GetMagBeta(void) const { return fabs(beta); }
|
|
||||||
double Getqbar (void) const { return qbar; }
|
|
||||||
double GetqbarUW (void) const { return qbarUW; }
|
|
||||||
double GetqbarUV (void) const { return qbarUV; }
|
|
||||||
inline double GetVt (void) const { return Vt; }
|
|
||||||
double GetMach (void) const { return Mach; }
|
|
||||||
double GetMachU(void) const { return vMachUVW(eU); }
|
|
||||||
double Getadot (void) const { return adot; }
|
|
||||||
double Getbdot (void) const { return bdot; }
|
|
||||||
|
|
||||||
void SetUVW(FGColumnVector3 tt) { vUVW = tt; }
|
|
||||||
void SetAeroUVW(FGColumnVector3 tt) { vAeroUVW = tt; }
|
|
||||||
|
|
||||||
inline void Setalpha(double tt) { alpha = tt; }
|
|
||||||
inline void Setbeta (double tt) { beta = tt; }
|
|
||||||
inline void Setqbar (double tt) { qbar = tt; }
|
|
||||||
inline void SetqbarUW (double tt) { qbarUW = tt; }
|
|
||||||
inline void SetqbarUV (double tt) { qbarUV = tt; }
|
|
||||||
inline void SetVt (double tt) { Vt = tt; }
|
|
||||||
inline void SetMach (double tt) { Mach=tt; }
|
|
||||||
inline void Setadot (double tt) { adot = tt; }
|
|
||||||
inline void Setbdot (double tt) { bdot = tt; }
|
|
||||||
|
|
||||||
inline void SetAB(double t1, double t2) { alpha=t1; beta=t2; }
|
|
||||||
|
|
||||||
bool Run(void);
|
|
||||||
|
|
||||||
void bind(void);
|
|
||||||
void unbind(void);
|
|
||||||
|
|
||||||
private:
|
|
||||||
FGColumnVector3 vUVW;
|
|
||||||
FGColumnVector3 vUVWdot;
|
|
||||||
FGColumnVector3 vUVWdot_prev[4];
|
|
||||||
FGColumnVector3 vAeroUVW;
|
|
||||||
FGColumnVector3 vMachUVW;
|
|
||||||
|
|
||||||
double Vt, Mach;
|
|
||||||
double qbar, qbarUW, qbarUV;
|
|
||||||
double alpha, beta;
|
|
||||||
double adot,bdot;
|
|
||||||
void Debug(int from);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue