Latest round of JSBim updates.
This commit is contained in:
parent
2a4657c609
commit
1a13ecc1e9
21 changed files with 808 additions and 576 deletions
src/FDM/JSBSim
FGFDMExec.cppFGFDMExec.hFGJSBBase.cppFGJSBBase.hJSBSim.cxxJSBSim.hxx
initialization
input_output
math
models
|
@ -70,7 +70,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
namespace JSBSim {
|
||||||
|
|
||||||
static const char *IdSrc = "$Id: FGFDMExec.cpp,v 1.115 2011/09/25 11:56:00 bcoconni Exp $";
|
static const char *IdSrc = "$Id: FGFDMExec.cpp,v 1.118 2011/10/22 15:11:23 bcoconni Exp $";
|
||||||
static const char *IdHdr = ID_FDMEXEC;
|
static const char *IdHdr = ID_FDMEXEC;
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -85,7 +85,7 @@ FGFDMExec::FGFDMExec(FGPropertyManager* root, unsigned int* fdmctr) : Root(root)
|
||||||
|
|
||||||
Frame = 0;
|
Frame = 0;
|
||||||
Error = 0;
|
Error = 0;
|
||||||
GroundCallback = 0;
|
GroundCallback = new FGDefaultGroundCallback();
|
||||||
IC = 0;
|
IC = 0;
|
||||||
Trim = 0;
|
Trim = 0;
|
||||||
Script = 0;
|
Script = 0;
|
||||||
|
@ -186,6 +186,9 @@ FGFDMExec::~FGFDMExec()
|
||||||
|
|
||||||
if (FDMctr > 0) (*FDMctr)--;
|
if (FDMctr > 0) (*FDMctr)--;
|
||||||
|
|
||||||
|
if(GroundCallback)
|
||||||
|
delete GroundCallback;
|
||||||
|
|
||||||
Debug(1);
|
Debug(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -210,7 +213,7 @@ bool FGFDMExec::Allocate(void)
|
||||||
Models[ePropulsion] = new FGPropulsion(this);
|
Models[ePropulsion] = new FGPropulsion(this);
|
||||||
Models[eAerodynamics] = new FGAerodynamics (this);
|
Models[eAerodynamics] = new FGAerodynamics (this);
|
||||||
|
|
||||||
GroundCallback = new FGGroundCallback(((FGInertial*)Models[eInertial])->GetRefRadius());
|
GroundCallback->SetSeaLevelRadius(((FGInertial*)Models[eInertial])->GetRefRadius());
|
||||||
|
|
||||||
Models[eGroundReactions] = new FGGroundReactions(this);
|
Models[eGroundReactions] = new FGGroundReactions(this);
|
||||||
Models[eExternalReactions] = new FGExternalReactions(this);
|
Models[eExternalReactions] = new FGExternalReactions(this);
|
||||||
|
@ -266,8 +269,6 @@ bool FGFDMExec::DeAllocate(void)
|
||||||
delete IC;
|
delete IC;
|
||||||
delete Trim;
|
delete Trim;
|
||||||
|
|
||||||
delete GroundCallback;
|
|
||||||
|
|
||||||
Error = 0;
|
Error = 0;
|
||||||
|
|
||||||
modelLoaded = false;
|
modelLoaded = false;
|
||||||
|
@ -303,11 +304,11 @@ bool FGFDMExec::Run(void)
|
||||||
firstPass = false;
|
firstPass = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IncrTime();
|
||||||
|
|
||||||
// returns true if success, false if complete
|
// returns true if success, false if complete
|
||||||
if (Script != 0 && !IntegrationSuspended()) success = Script->RunScript();
|
if (Script != 0 && !IntegrationSuspended()) success = Script->RunScript();
|
||||||
|
|
||||||
IncrTime();
|
|
||||||
|
|
||||||
for (unsigned int i = 0; i < Models.size(); i++) {
|
for (unsigned int i = 0; i < Models.size(); i++) {
|
||||||
LoadInputs(i);
|
LoadInputs(i);
|
||||||
Models[i]->Run(holding);
|
Models[i]->Run(holding);
|
||||||
|
@ -563,9 +564,7 @@ void FGFDMExec::Initialize(FGInitialCondition *FGIC)
|
||||||
Propagate->InitializeDerivatives();
|
Propagate->InitializeDerivatives();
|
||||||
LoadInputs(eAtmosphere);
|
LoadInputs(eAtmosphere);
|
||||||
Atmosphere->Run(false);
|
Atmosphere->Run(false);
|
||||||
Winds->SetWindNED( FGIC->GetWindNFpsIC(),
|
Winds->SetWindNED(FGIC->GetWindNEDFpsIC());
|
||||||
FGIC->GetWindEFpsIC(),
|
|
||||||
FGIC->GetWindDFpsIC() );
|
|
||||||
Auxiliary->Run(false);
|
Auxiliary->Run(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ INCLUDES
|
||||||
DEFINITIONS
|
DEFINITIONS
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
#define ID_FDMEXEC "$Id: FGFDMExec.h,v 1.71 2011/09/07 02:37:04 jberndt Exp $"
|
#define ID_FDMEXEC "$Id: FGFDMExec.h,v 1.72 2011/10/14 22:46:49 bcoconni Exp $"
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
FORWARD DECLARATIONS
|
FORWARD DECLARATIONS
|
||||||
|
@ -181,7 +181,7 @@ CLASS DOCUMENTATION
|
||||||
property actually maps toa function call of DoTrim().
|
property actually maps toa function call of DoTrim().
|
||||||
|
|
||||||
@author Jon S. Berndt
|
@author Jon S. Berndt
|
||||||
@version $Revision: 1.71 $
|
@version $Revision: 1.72 $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -269,7 +269,8 @@ public:
|
||||||
bool RunIC(void);
|
bool RunIC(void);
|
||||||
|
|
||||||
/** Sets the ground callback pointer.
|
/** Sets the ground callback pointer.
|
||||||
@param gc A pointer to a ground callback object. */
|
@param gc A pointer to a ground callback object.
|
||||||
|
*/
|
||||||
void SetGroundCallback(FGGroundCallback* gc);
|
void SetGroundCallback(FGGroundCallback* gc);
|
||||||
|
|
||||||
/** Loads an aircraft model.
|
/** Loads an aircraft model.
|
||||||
|
|
|
@ -44,7 +44,7 @@ INCLUDES
|
||||||
|
|
||||||
namespace JSBSim {
|
namespace JSBSim {
|
||||||
|
|
||||||
static const char *IdSrc = "$Id: FGJSBBase.cpp,v 1.31 2011/07/27 03:55:48 jberndt Exp $";
|
static const char *IdSrc = "$Id: FGJSBBase.cpp,v 1.32 2011/10/22 14:38:30 bcoconni Exp $";
|
||||||
static const char *IdHdr = ID_JSBBASE;
|
static const char *IdHdr = ID_JSBBASE;
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -283,5 +283,67 @@ double FGJSBBase::GaussianRandomNumber(void)
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
double FGJSBBase::VcalibratedFromMach(double mach, double p, double psl, double rhosl)
|
||||||
|
{
|
||||||
|
double pt,A;
|
||||||
|
|
||||||
|
if (mach < 0) mach=0;
|
||||||
|
if (mach < 1) //calculate total pressure assuming isentropic flow
|
||||||
|
pt=p*pow((1 + 0.2*mach*mach),3.5);
|
||||||
|
else {
|
||||||
|
// shock in front of pitot tube, we'll assume its normal and use
|
||||||
|
// the Rayleigh Pitot Tube Formula, i.e. the ratio of total
|
||||||
|
// pressure behind the shock to the static pressure in front of
|
||||||
|
// the normal shock assumption should not be a bad one -- most supersonic
|
||||||
|
// aircraft place the pitot probe out front so that it is the forward
|
||||||
|
// most point on the aircraft. The real shock would, of course, take
|
||||||
|
// on something like the shape of a rounded-off cone but, here again,
|
||||||
|
// the assumption should be good since the opening of the pitot probe
|
||||||
|
// is very small and, therefore, the effects of the shock curvature
|
||||||
|
// should be small as well. AFAIK, this approach is fairly well accepted
|
||||||
|
// within the aerospace community
|
||||||
|
|
||||||
|
// The denominator below is zero for Mach ~ 0.38, for which
|
||||||
|
// we'll never be here, so we're safe
|
||||||
|
|
||||||
|
pt = p*166.92158*pow(mach,7.0)/pow(7*mach*mach-1,2.5);
|
||||||
|
}
|
||||||
|
|
||||||
|
A = pow(((pt-p)/psl+1),0.28571);
|
||||||
|
return sqrt(7*psl/rhosl*(A-1));
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
double FGJSBBase::MachFromVcalibrated(double vcas, double p, double psl, double rhosl)
|
||||||
|
{
|
||||||
|
double pt = p + psl*(pow(1+vcas*vcas*rhosl/(7.0*psl),3.5)-1);
|
||||||
|
|
||||||
|
if (pt/p < 1.89293)
|
||||||
|
return sqrt(5.0*(pow(pt/p, 0.2857143) -1)); // Mach < 1
|
||||||
|
else {
|
||||||
|
// Mach >= 1
|
||||||
|
double mach = sqrt(0.77666*pt/p); // Initial guess is based on a quadratic approximation of the Rayleigh formula
|
||||||
|
double delta = 1.;
|
||||||
|
double target = pt/(166.92158*p);
|
||||||
|
int iter = 0;
|
||||||
|
|
||||||
|
// Find the root with Newton-Raphson. Since the differential is never zero,
|
||||||
|
// the function is monotonic and has only one root with a multiplicity of one.
|
||||||
|
// Convergence is certain.
|
||||||
|
while (delta > 1E-5 && iter < 10) {
|
||||||
|
double m2 = mach*mach; // Mach^2
|
||||||
|
double m6 = m2*m2*m2; // Mach^6
|
||||||
|
delta = mach*m6/pow(7.0*m2-1.0,2.5) - target;
|
||||||
|
double diff = 7.0*m6*(2.0*m2-1)/pow(7.0*m2-1.0,3.5); // Never zero when Mach >= 1
|
||||||
|
mach -= delta/diff;
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return mach;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
} // namespace JSBSim
|
} // namespace JSBSim
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ using std::max;
|
||||||
DEFINITIONS
|
DEFINITIONS
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
#define ID_JSBBASE "$Id: FGJSBBase.h,v 1.33 2011/06/27 03:14:25 jberndt Exp $"
|
#define ID_JSBBASE "$Id: FGJSBBase.h,v 1.34 2011/10/22 14:38:30 bcoconni Exp $"
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
FORWARD DECLARATIONS
|
FORWARD DECLARATIONS
|
||||||
|
@ -72,7 +72,7 @@ CLASS DOCUMENTATION
|
||||||
* This class provides universal constants, utility functions, messaging
|
* This class provides universal constants, utility functions, messaging
|
||||||
* functions, and enumerated constants to JSBSim.
|
* functions, and enumerated constants to JSBSim.
|
||||||
@author Jon S. Berndt
|
@author Jon S. Berndt
|
||||||
@version $Id: FGJSBBase.h,v 1.33 2011/06/27 03:14:25 jberndt Exp $
|
@version $Id: FGJSBBase.h,v 1.34 2011/10/22 14:38:30 bcoconni Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -256,6 +256,29 @@ public:
|
||||||
return kelvin - 273.15;
|
return kelvin - 273.15;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Calculate the calibrated airspeed from the Mach number. It uses the
|
||||||
|
* Rayleigh formula for supersonic speeds (See "Introduction to Aerodynamics
|
||||||
|
* of a Compressible Fluid - H.W. Liepmann, A.E. Puckett - Wiley & sons
|
||||||
|
* (1947)" §5.4 pp 75-80)
|
||||||
|
* @param mach The Mach number
|
||||||
|
* @param p Pressure in psf
|
||||||
|
* @param psl Pressure at sea level in psf
|
||||||
|
* @param rhosl Density at sea level in slugs/ft^3
|
||||||
|
* @return The calibrated airspeed (CAS) in ft/s
|
||||||
|
* */
|
||||||
|
static double VcalibratedFromMach(double mach, double p, double psl, double rhosl);
|
||||||
|
|
||||||
|
/** Calculate the Mach number from the calibrated airspeed. For subsonic
|
||||||
|
* speeds, the reversed formula has a closed form. For supersonic speeds, the
|
||||||
|
* Rayleigh formula is reversed by the Newton-Raphson algorithm.
|
||||||
|
* @param vcas The calibrated airspeed (CAS) in ft/s
|
||||||
|
* @param p Pressure in psf
|
||||||
|
* @param psl Pressure at sea level in psf
|
||||||
|
* @param rhosl Density at sea level in slugs/ft^3
|
||||||
|
* @return The Mach number
|
||||||
|
* */
|
||||||
|
static double MachFromVcalibrated(double vcas, double p, double psl, double rhosl);
|
||||||
|
|
||||||
/** Finite precision comparison.
|
/** Finite precision comparison.
|
||||||
@param a first value to compare
|
@param a first value to compare
|
||||||
@param b second value to compare
|
@param b second value to compare
|
||||||
|
|
|
@ -112,6 +112,26 @@ public:
|
||||||
cont = FGColumnVector3( contact[0], contact[1], contact[2] );
|
cont = FGColumnVector3( contact[0], contact[1], contact[2] );
|
||||||
return agl;
|
return agl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual double GetTerrainGeoCentRadius(double t, const FGLocation& l) const {
|
||||||
|
double loc_cart[3] = { l(eX), l(eY), l(eZ) };
|
||||||
|
double contact[3], normal[3], vel[3], angularVel[3], agl = 0;
|
||||||
|
mInterface->get_agl_ft(t, loc_cart, SG_METER_TO_FEET*2, contact, normal,
|
||||||
|
vel, angularVel, &agl);
|
||||||
|
return sqrt(contact[0]*contact[0]+contact[1]*contact[1]+contact[2]*contact[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual double GetSeaLevelRadius(const FGLocation& l) const {
|
||||||
|
double seaLevelRadius, latGeoc;
|
||||||
|
|
||||||
|
sgGeodToGeoc(l.GetGeodLatitudeRad(), l.GetGeodAltitude(),
|
||||||
|
&seaLevelRadius, &latGeoc);
|
||||||
|
|
||||||
|
return seaLevelRadius * SG_METER_TO_FEET;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual void SetTerrainGeoCentRadius(double radius) {}
|
||||||
|
virtual void SetSeaLevelRadius(double radius) {}
|
||||||
private:
|
private:
|
||||||
FGJSBsim* mInterface;
|
FGJSBsim* mInterface;
|
||||||
};
|
};
|
||||||
|
@ -371,9 +391,6 @@ void FGJSBsim::init()
|
||||||
-wind_from_east->getDoubleValue(),
|
-wind_from_east->getDoubleValue(),
|
||||||
-wind_from_down->getDoubleValue() );
|
-wind_from_down->getDoubleValue() );
|
||||||
|
|
||||||
//Atmosphere->SetExTemperature(get_Static_temperature());
|
|
||||||
//Atmosphere->SetExPressure(get_Static_pressure());
|
|
||||||
//Atmosphere->SetExDensity(get_Density());
|
|
||||||
SG_LOG(SG_FLIGHT,SG_INFO,"T,p,rho: " << Atmosphere->GetTemperature()
|
SG_LOG(SG_FLIGHT,SG_INFO,"T,p,rho: " << Atmosphere->GetTemperature()
|
||||||
<< ", " << Atmosphere->GetPressure()
|
<< ", " << Atmosphere->GetPressure()
|
||||||
<< ", " << Atmosphere->GetDensity() );
|
<< ", " << Atmosphere->GetDensity() );
|
||||||
|
@ -394,7 +411,6 @@ void FGJSBsim::init()
|
||||||
|
|
||||||
needTrim = startup_trim->getBoolValue();
|
needTrim = startup_trim->getBoolValue();
|
||||||
common_init();
|
common_init();
|
||||||
fgic->SetSeaLevelRadiusFtIC( get_Sea_level_radius() );
|
|
||||||
|
|
||||||
copy_to_JSBsim();
|
copy_to_JSBsim();
|
||||||
fdmex->RunIC(); //loop JSBSim once w/o integrating
|
fdmex->RunIC(); //loop JSBSim once w/o integrating
|
||||||
|
@ -661,9 +677,6 @@ bool FGJSBsim::copy_to_JSBsim()
|
||||||
} // end FGEngine code block
|
} // end FGEngine code block
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Propagate->SetSeaLevelRadius( get_Sea_level_radius() );
|
|
||||||
|
|
||||||
Atmosphere->SetTemperature(temperature->getDoubleValue(), get_Altitude(), FGAtmosphere::eCelsius);
|
Atmosphere->SetTemperature(temperature->getDoubleValue(), get_Altitude(), FGAtmosphere::eCelsius);
|
||||||
Atmosphere->SetPressureSL(pressureSL->getDoubleValue(), FGAtmosphere::eInchesHg);
|
Atmosphere->SetPressureSL(pressureSL->getDoubleValue(), FGAtmosphere::eInchesHg);
|
||||||
|
|
||||||
|
@ -1024,11 +1037,10 @@ void FGJSBsim::set_Latitude(double lat)
|
||||||
fgic->SetSeaLevelRadiusFtIC( sea_level_radius_ft );
|
fgic->SetSeaLevelRadiusFtIC( sea_level_radius_ft );
|
||||||
fgic->SetLatitudeRadIC( lat_geoc );
|
fgic->SetLatitudeRadIC( lat_geoc );
|
||||||
}
|
}
|
||||||
else {
|
else
|
||||||
Propagate->SetSeaLevelRadius( sea_level_radius_ft );
|
|
||||||
Propagate->SetLatitude(lat_geoc);
|
Propagate->SetLatitude(lat_geoc);
|
||||||
FGInterface::set_Latitude(lat);
|
|
||||||
}
|
FGInterface::set_Latitude(lat);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1038,10 +1050,10 @@ void FGJSBsim::set_Longitude(double lon)
|
||||||
|
|
||||||
if (needTrim)
|
if (needTrim)
|
||||||
fgic->SetLongitudeRadIC(lon);
|
fgic->SetLongitudeRadIC(lon);
|
||||||
else {
|
else
|
||||||
Propagate->SetLongitude(lon);
|
Propagate->SetLongitude(lon);
|
||||||
FGInterface::set_Longitude(lon);
|
|
||||||
}
|
FGInterface::set_Longitude(lon);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the altitude above sea level.
|
// Sets the altitude above sea level.
|
||||||
|
@ -1051,10 +1063,10 @@ void FGJSBsim::set_Altitude(double alt)
|
||||||
|
|
||||||
if (needTrim)
|
if (needTrim)
|
||||||
fgic->SetAltitudeASLFtIC(alt);
|
fgic->SetAltitudeASLFtIC(alt);
|
||||||
else {
|
else
|
||||||
Propagate->SetAltitudeASL(alt);
|
Propagate->SetAltitudeASL(alt);
|
||||||
FGInterface::set_Altitude(alt);
|
|
||||||
}
|
FGInterface::set_Altitude(alt);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGJSBsim::set_V_calibrated_kts(double vc)
|
void FGJSBsim::set_V_calibrated_kts(double vc)
|
||||||
|
@ -1064,7 +1076,10 @@ void FGJSBsim::set_V_calibrated_kts(double vc)
|
||||||
if (needTrim)
|
if (needTrim)
|
||||||
fgic->SetVcalibratedKtsIC(vc);
|
fgic->SetVcalibratedKtsIC(vc);
|
||||||
else {
|
else {
|
||||||
double mach = getMachFromVcas(vc);
|
double p=pressure->getDoubleValue();
|
||||||
|
double psl=fdmex->GetAtmosphere()->GetPressureSL();
|
||||||
|
double rhosl=fdmex->GetAtmosphere()->GetDensitySL();
|
||||||
|
double mach = FGJSBBase::MachFromVcalibrated(vc, p, psl, rhosl);
|
||||||
double temp = 1.8*(temperature->getDoubleValue()+273.15);
|
double temp = 1.8*(temperature->getDoubleValue()+273.15);
|
||||||
double soundSpeed = sqrt(1.4*1716.0*temp);
|
double soundSpeed = sqrt(1.4*1716.0*temp);
|
||||||
FGColumnVector3 vUVW = Propagate->GetUVW();
|
FGColumnVector3 vUVW = Propagate->GetUVW();
|
||||||
|
@ -1073,9 +1088,9 @@ void FGJSBsim::set_V_calibrated_kts(double vc)
|
||||||
Propagate->SetUVW(1, vUVW(1));
|
Propagate->SetUVW(1, vUVW(1));
|
||||||
Propagate->SetUVW(2, vUVW(2));
|
Propagate->SetUVW(2, vUVW(2));
|
||||||
Propagate->SetUVW(3, vUVW(3));
|
Propagate->SetUVW(3, vUVW(3));
|
||||||
|
|
||||||
FGInterface::set_V_calibrated_kts(vc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FGInterface::set_V_calibrated_kts(vc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGJSBsim::set_Mach_number(double mach)
|
void FGJSBsim::set_Mach_number(double mach)
|
||||||
|
@ -1093,9 +1108,9 @@ void FGJSBsim::set_Mach_number(double mach)
|
||||||
Propagate->SetUVW(1, vUVW(1));
|
Propagate->SetUVW(1, vUVW(1));
|
||||||
Propagate->SetUVW(2, vUVW(2));
|
Propagate->SetUVW(2, vUVW(2));
|
||||||
Propagate->SetUVW(3, vUVW(3));
|
Propagate->SetUVW(3, vUVW(3));
|
||||||
|
|
||||||
FGInterface::set_Mach_number(mach);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FGInterface::set_Mach_number(mach);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGJSBsim::set_Velocities_Local( double north, double east, double down )
|
void FGJSBsim::set_Velocities_Local( double north, double east, double down )
|
||||||
|
@ -1114,9 +1129,9 @@ void FGJSBsim::set_Velocities_Local( double north, double east, double down )
|
||||||
Propagate->SetUVW(1, vUVW(1));
|
Propagate->SetUVW(1, vUVW(1));
|
||||||
Propagate->SetUVW(2, vUVW(2));
|
Propagate->SetUVW(2, vUVW(2));
|
||||||
Propagate->SetUVW(3, vUVW(3));
|
Propagate->SetUVW(3, vUVW(3));
|
||||||
|
|
||||||
FGInterface::set_Velocities_Local(north, east, down);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FGInterface::set_Velocities_Local(north, east, down);
|
||||||
}
|
}
|
||||||
|
|
||||||
void FGJSBsim::set_Velocities_Wind_Body( double u, double v, double w)
|
void FGJSBsim::set_Velocities_Wind_Body( double u, double v, double w)
|
||||||
|
@ -1133,9 +1148,9 @@ void FGJSBsim::set_Velocities_Wind_Body( double u, double v, double w)
|
||||||
Propagate->SetUVW(1, u);
|
Propagate->SetUVW(1, u);
|
||||||
Propagate->SetUVW(2, v);
|
Propagate->SetUVW(2, v);
|
||||||
Propagate->SetUVW(3, w);
|
Propagate->SetUVW(3, w);
|
||||||
|
|
||||||
FGInterface::set_Velocities_Wind_Body(u, v, w);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FGInterface::set_Velocities_Wind_Body(u, v, w);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Euler angles
|
//Euler angles
|
||||||
|
@ -1155,9 +1170,9 @@ void FGJSBsim::set_Euler_Angles( double phi, double theta, double psi )
|
||||||
FGMatrix33 Ti2b = Tl2b*Propagate->GetTi2l();
|
FGMatrix33 Ti2b = Tl2b*Propagate->GetTi2l();
|
||||||
FGQuaternion Qi = Ti2b.GetQuaternion();
|
FGQuaternion Qi = Ti2b.GetQuaternion();
|
||||||
Propagate->SetInertialOrientation(Qi);
|
Propagate->SetInertialOrientation(Qi);
|
||||||
|
|
||||||
FGInterface::set_Euler_Angles(phi, theta, psi);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FGInterface::set_Euler_Angles(phi, theta, psi);
|
||||||
}
|
}
|
||||||
|
|
||||||
//Flight Path
|
//Flight Path
|
||||||
|
@ -1178,9 +1193,9 @@ void FGJSBsim::set_Climb_Rate( double roc)
|
||||||
Propagate->SetUVW(1, vUVW(1));
|
Propagate->SetUVW(1, vUVW(1));
|
||||||
Propagate->SetUVW(2, vUVW(2));
|
Propagate->SetUVW(2, vUVW(2));
|
||||||
Propagate->SetUVW(3, vUVW(3));
|
Propagate->SetUVW(3, vUVW(3));
|
||||||
|
|
||||||
FGInterface::set_Climb_Rate(roc);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FGInterface::set_Climb_Rate(roc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1199,45 +1214,9 @@ void FGJSBsim::set_Gamma_vert_rad( double gamma)
|
||||||
Propagate->SetUVW(1, vUVW(1));
|
Propagate->SetUVW(1, vUVW(1));
|
||||||
Propagate->SetUVW(2, vUVW(2));
|
Propagate->SetUVW(2, vUVW(2));
|
||||||
Propagate->SetUVW(3, vUVW(3));
|
Propagate->SetUVW(3, vUVW(3));
|
||||||
|
|
||||||
FGInterface::set_Gamma_vert_rad(gamma);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Reverse the VCAS formula to obtain the corresponding Mach number. For subsonic
|
|
||||||
// speeds, the reversed formula has a closed form. For supersonic speeds, the
|
|
||||||
// formula is reversed by the Newton-Raphson algorithm.
|
|
||||||
|
|
||||||
double FGJSBsim::getMachFromVcas(double vcas)
|
|
||||||
{
|
|
||||||
double p=pressure->getDoubleValue();
|
|
||||||
double psl=fdmex->GetAtmosphere()->GetPressureSL();
|
|
||||||
double rhosl=fdmex->GetAtmosphere()->GetDensitySL();
|
|
||||||
|
|
||||||
double pt = p + psl*(pow(1+vcas*vcas*rhosl/(7.0*psl),3.5)-1);
|
|
||||||
|
|
||||||
if (pt/p < 1.89293)
|
|
||||||
return sqrt(5.0*(pow(pt/p, 0.2857143) -1)); // Mach < 1
|
|
||||||
else {
|
|
||||||
// Mach >= 1
|
|
||||||
double mach = sqrt(0.77666*pt/p); // Initial guess is based on a quadratic approximation of the Rayleigh formula
|
|
||||||
double delta = 1.;
|
|
||||||
double target = pt/(166.92158*p);
|
|
||||||
int iter = 0;
|
|
||||||
|
|
||||||
// Find the root with Newton-Raphson. Since the differential is never zero,
|
|
||||||
// the function is monotonic and has only one root with a multiplicity of one.
|
|
||||||
// Convergence is certain.
|
|
||||||
while (delta > 1E-5 && iter < 10) {
|
|
||||||
double m2 = mach*mach; // Mach^2
|
|
||||||
double m6 = m2*m2*m2; // Mach^6
|
|
||||||
delta = mach*m6/pow(7.0*m2-1.0,2.5) - target;
|
|
||||||
double diff = 7.0*m6*(2.0*m2-1)/pow(7.0*m2-1.0,3.5); // Never zero when Mach >= 1
|
|
||||||
mach -= delta/diff;
|
|
||||||
iter++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return mach;
|
FGInterface::set_Gamma_vert_rad(gamma);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -297,7 +297,6 @@ private:
|
||||||
|
|
||||||
void do_trim(void);
|
void do_trim(void);
|
||||||
|
|
||||||
double getMachFromVcas(double vcas);
|
|
||||||
bool update_ground_cache(JSBSim::FGLocation cart, double* cart_pos, double dt);
|
bool update_ground_cache(JSBSim::FGLocation cart, double* cart_pos, double dt);
|
||||||
void init_gear(void);
|
void init_gear(void);
|
||||||
void update_gear(void);
|
void update_gear(void);
|
||||||
|
|
|
@ -63,7 +63,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
namespace JSBSim {
|
||||||
|
|
||||||
static const char *IdSrc = "$Id: FGInitialCondition.cpp,v 1.69 2011/08/04 12:46:32 jberndt Exp $";
|
static const char *IdSrc = "$Id: FGInitialCondition.cpp,v 1.75 2011/10/23 15:05:32 bcoconni Exp $";
|
||||||
static const char *IdHdr = ID_INITIALCONDITION;
|
static const char *IdHdr = ID_INITIALCONDITION;
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
|
@ -74,6 +74,7 @@ FGInitialCondition::FGInitialCondition(FGFDMExec *FDMExec) : fdmex(FDMExec)
|
||||||
|
|
||||||
if(FDMExec != NULL ) {
|
if(FDMExec != NULL ) {
|
||||||
PropertyManager=fdmex->GetPropertyManager();
|
PropertyManager=fdmex->GetPropertyManager();
|
||||||
|
Atmosphere=fdmex->GetAtmosphere();
|
||||||
Constructing = true;
|
Constructing = true;
|
||||||
bind();
|
bind();
|
||||||
Constructing = false;
|
Constructing = false;
|
||||||
|
@ -105,16 +106,13 @@ void FGInitialCondition::ResetIC(double u0, double v0, double w0,
|
||||||
|
|
||||||
InitializeIC();
|
InitializeIC();
|
||||||
|
|
||||||
p = p0; q = q0; r = r0;
|
vPQR_body = FGColumnVector3(p0, q0, r0);
|
||||||
alpha = alpha0; beta = beta0;
|
alpha = alpha0; beta = beta0;
|
||||||
phi = phi0; theta = theta0; psi = psi0;
|
|
||||||
|
|
||||||
position.SetPosition(lonRad0, latRad0, altAGLFt0 + terrain_elevation + sea_level_radius);
|
position.SetPosition(lonRad0, latRad0, altAGLFt0 + terrain_elevation + sea_level_radius);
|
||||||
|
|
||||||
FGQuaternion Quat(phi, theta, psi);
|
orientation = FGQuaternion(phi0, theta0, psi0);
|
||||||
Quat.Normalize();
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
Tl2b = Quat.GetT();
|
|
||||||
Tb2l = Tl2b.Transposed();
|
|
||||||
|
|
||||||
vUVW_NED = Tb2l * FGColumnVector3(u0, v0, w0);
|
vUVW_NED = Tb2l * FGColumnVector3(u0, v0, w0);
|
||||||
vt = vUVW_NED.Magnitude();
|
vt = vUVW_NED.Magnitude();
|
||||||
|
@ -132,21 +130,20 @@ void FGInitialCondition::ResetIC(double u0, double v0, double w0,
|
||||||
void FGInitialCondition::InitializeIC(void)
|
void FGInitialCondition::InitializeIC(void)
|
||||||
{
|
{
|
||||||
alpha=beta=0;
|
alpha=beta=0;
|
||||||
theta=phi=psi=0;
|
|
||||||
terrain_elevation = 0;
|
terrain_elevation = 0;
|
||||||
sea_level_radius = fdmex->GetInertial()->GetRefRadius();
|
sea_level_radius = fdmex->GetInertial()->GetRefRadius();
|
||||||
|
position.SetEllipse(fdmex->GetInertial()->GetSemimajor(), fdmex->GetInertial()->GetSemiminor());
|
||||||
position.SetPosition(0., 0., sea_level_radius);
|
position.SetPosition(0., 0., sea_level_radius);
|
||||||
position.SetEarthPositionAngle(fdmex->GetPropagate()->GetEarthPositionAngle());
|
position.SetEarthPositionAngle(fdmex->GetPropagate()->GetEarthPositionAngle());
|
||||||
|
orientation = FGQuaternion(0.0, 0.0, 0.0);
|
||||||
vUVW_NED.InitMatrix();
|
vUVW_NED.InitMatrix();
|
||||||
p=q=r=0;
|
vPQR_body.InitMatrix();
|
||||||
vt=0;
|
vt=0;
|
||||||
|
|
||||||
targetNlfIC = 1.0;
|
targetNlfIC = 1.0;
|
||||||
|
|
||||||
Tw2b.InitMatrix(1., 0., 0., 0., 1., 0., 0., 0., 1.);
|
Tw2b.InitMatrix(1., 0., 0., 0., 1., 0., 0., 0., 1.);
|
||||||
Tb2w.InitMatrix(1., 0., 0., 0., 1., 0., 0., 0., 1.);
|
Tb2w.InitMatrix(1., 0., 0., 0., 1., 0., 0., 0., 1.);
|
||||||
Tl2b.InitMatrix(1., 0., 0., 0., 1., 0., 0., 0., 1.);
|
|
||||||
Tb2l.InitMatrix(1., 0., 0., 0., 1., 0., 0., 0., 1.);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
|
@ -168,12 +165,12 @@ void FGInitialCondition::WriteStateFile(int num)
|
||||||
if (outfile.is_open()) {
|
if (outfile.is_open()) {
|
||||||
outfile << "<?xml version=\"1.0\"?>" << endl;
|
outfile << "<?xml version=\"1.0\"?>" << endl;
|
||||||
outfile << "<initialize name=\"reset00\">" << endl;
|
outfile << "<initialize name=\"reset00\">" << endl;
|
||||||
outfile << " <ubody unit=\"FT/SEC\"> " << Propagate->GetUVW(eX) << " </ubody> " << endl;
|
outfile << " <ubody unit=\"FT/SEC\"> " << Propagate->GetUVW(eU) << " </ubody> " << endl;
|
||||||
outfile << " <vbody unit=\"FT/SEC\"> " << Propagate->GetUVW(eY) << " </vbody> " << endl;
|
outfile << " <vbody unit=\"FT/SEC\"> " << Propagate->GetUVW(eV) << " </vbody> " << endl;
|
||||||
outfile << " <wbody unit=\"FT/SEC\"> " << Propagate->GetUVW(eZ) << " </wbody> " << endl;
|
outfile << " <wbody unit=\"FT/SEC\"> " << Propagate->GetUVW(eW) << " </wbody> " << endl;
|
||||||
outfile << " <phi unit=\"DEG\"> " << Propagate->GetEuler(ePhi) << " </phi>" << endl;
|
outfile << " <phi unit=\"DEG\"> " << Propagate->GetEuler(ePhi)*radtodeg << " </phi>" << endl;
|
||||||
outfile << " <theta unit=\"DEG\"> " << Propagate->GetEuler(eTht) << " </theta>" << endl;
|
outfile << " <theta unit=\"DEG\"> " << Propagate->GetEuler(eTht)*radtodeg << " </theta>" << endl;
|
||||||
outfile << " <psi unit=\"DEG\"> " << Propagate->GetEuler(ePsi) << " </psi>" << endl;
|
outfile << " <psi unit=\"DEG\"> " << Propagate->GetEuler(ePsi)*radtodeg << " </psi>" << endl;
|
||||||
outfile << " <longitude unit=\"DEG\"> " << Propagate->GetLongitudeDeg() << " </longitude>" << endl;
|
outfile << " <longitude unit=\"DEG\"> " << Propagate->GetLongitudeDeg() << " </longitude>" << endl;
|
||||||
outfile << " <latitude unit=\"DEG\"> " << Propagate->GetLatitudeDeg() << " </latitude>" << endl;
|
outfile << " <latitude unit=\"DEG\"> " << Propagate->GetLatitudeDeg() << " </latitude>" << endl;
|
||||||
outfile << " <altitude unit=\"FT\"> " << Propagate->GetDistanceAGL() << " </altitude>" << endl;
|
outfile << " <altitude unit=\"FT\"> " << Propagate->GetDistanceAGL() << " </altitude>" << endl;
|
||||||
|
@ -189,8 +186,8 @@ void FGInitialCondition::WriteStateFile(int num)
|
||||||
void FGInitialCondition::SetVequivalentKtsIC(double ve)
|
void FGInitialCondition::SetVequivalentKtsIC(double ve)
|
||||||
{
|
{
|
||||||
double altitudeASL = position.GetRadius() - sea_level_radius;
|
double altitudeASL = position.GetRadius() - sea_level_radius;
|
||||||
double rho = fdmex->GetAtmosphere()->GetDensity(altitudeASL);
|
double rho = Atmosphere->GetDensity(altitudeASL);
|
||||||
double rhoSL = fdmex->GetAtmosphere()->GetDensitySL();
|
double rhoSL = Atmosphere->GetDensitySL();
|
||||||
SetVtrueFpsIC(ve*ktstofps*sqrt(rhoSL/rho));
|
SetVtrueFpsIC(ve*ktstofps*sqrt(rhoSL/rho));
|
||||||
lastSpeedSet = setve;
|
lastSpeedSet = setve;
|
||||||
}
|
}
|
||||||
|
@ -200,7 +197,7 @@ void FGInitialCondition::SetVequivalentKtsIC(double ve)
|
||||||
void FGInitialCondition::SetMachIC(double mach)
|
void FGInitialCondition::SetMachIC(double mach)
|
||||||
{
|
{
|
||||||
double altitudeASL = position.GetRadius() - sea_level_radius;
|
double altitudeASL = position.GetRadius() - sea_level_radius;
|
||||||
double temperature = fdmex->GetAtmosphere()->GetTemperature(altitudeASL);
|
double temperature = Atmosphere->GetTemperature(altitudeASL);
|
||||||
double soundSpeed = sqrt(SHRatio*Reng*temperature);
|
double soundSpeed = sqrt(SHRatio*Reng*temperature);
|
||||||
SetVtrueFpsIC(mach*soundSpeed);
|
SetVtrueFpsIC(mach*soundSpeed);
|
||||||
lastSpeedSet = setmach;
|
lastSpeedSet = setmach;
|
||||||
|
@ -211,8 +208,11 @@ void FGInitialCondition::SetMachIC(double mach)
|
||||||
void FGInitialCondition::SetVcalibratedKtsIC(double vcas)
|
void FGInitialCondition::SetVcalibratedKtsIC(double vcas)
|
||||||
{
|
{
|
||||||
double altitudeASL = position.GetRadius() - sea_level_radius;
|
double altitudeASL = position.GetRadius() - sea_level_radius;
|
||||||
double mach = getMachFromVcas(fabs(vcas)*ktstofps);
|
double pressure = Atmosphere->GetPressure(altitudeASL);
|
||||||
double temperature = fdmex->GetAtmosphere()->GetTemperature(altitudeASL);
|
double pressureSL = Atmosphere->GetPressureSL();
|
||||||
|
double rhoSL = Atmosphere->GetDensitySL();
|
||||||
|
double mach = MachFromVcalibrated(fabs(vcas)*ktstofps, pressure, pressureSL, rhoSL);
|
||||||
|
double temperature = Atmosphere->GetTemperature(altitudeASL);
|
||||||
double soundSpeed = sqrt(SHRatio*Reng*temperature);
|
double soundSpeed = sqrt(SHRatio*Reng*temperature);
|
||||||
|
|
||||||
SetVtrueFpsIC(mach*soundSpeed);
|
SetVtrueFpsIC(mach*soundSpeed);
|
||||||
|
@ -225,6 +225,7 @@ void FGInitialCondition::SetVcalibratedKtsIC(double vcas)
|
||||||
|
|
||||||
void FGInitialCondition::calcAeroAngles(const FGColumnVector3& _vt_NED)
|
void FGInitialCondition::calcAeroAngles(const FGColumnVector3& _vt_NED)
|
||||||
{
|
{
|
||||||
|
const FGMatrix33& Tl2b = orientation.GetT();
|
||||||
FGColumnVector3 _vt_BODY = Tl2b * _vt_NED;
|
FGColumnVector3 _vt_BODY = Tl2b * _vt_NED;
|
||||||
double ua = _vt_BODY(eX);
|
double ua = _vt_BODY(eX);
|
||||||
double va = _vt_BODY(eY);
|
double va = _vt_BODY(eY);
|
||||||
|
@ -271,11 +272,12 @@ void FGInitialCondition::calcAeroAngles(const FGColumnVector3& _vt_NED)
|
||||||
|
|
||||||
void FGInitialCondition::SetVgroundFpsIC(double vg)
|
void FGInitialCondition::SetVgroundFpsIC(double vg)
|
||||||
{
|
{
|
||||||
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
||||||
|
|
||||||
vUVW_NED(eU) = vg*cos(psi);
|
vUVW_NED(eU) = vg * orientation.GetCosEuler(ePsi);
|
||||||
vUVW_NED(eV) = vg*sin(psi);
|
vUVW_NED(eV) = vg * orientation.GetSinEuler(ePsi);
|
||||||
vUVW_NED(eW) = 0.;
|
vUVW_NED(eW) = 0.;
|
||||||
_vt_NED = vUVW_NED + _vWIND_NED;
|
_vt_NED = vUVW_NED + _vWIND_NED;
|
||||||
vt = _vt_NED.Magnitude();
|
vt = _vt_NED.Magnitude();
|
||||||
|
@ -294,6 +296,7 @@ void FGInitialCondition::SetVgroundFpsIC(double vg)
|
||||||
|
|
||||||
void FGInitialCondition::SetVtrueFpsIC(double vtrue)
|
void FGInitialCondition::SetVtrueFpsIC(double vtrue)
|
||||||
{
|
{
|
||||||
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
||||||
|
|
||||||
|
@ -322,6 +325,7 @@ void FGInitialCondition::SetClimbRateFpsIC(double hdot)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
FGColumnVector3 _WIND_NED = _vt_NED - vUVW_NED;
|
FGColumnVector3 _WIND_NED = _vt_NED - vUVW_NED;
|
||||||
double hdot0 = -_vt_NED(eW);
|
double hdot0 = -_vt_NED(eW);
|
||||||
|
@ -345,6 +349,7 @@ void FGInitialCondition::SetClimbRateFpsIC(double hdot)
|
||||||
|
|
||||||
void FGInitialCondition::SetAlphaRadIC(double alfa)
|
void FGInitialCondition::SetAlphaRadIC(double alfa)
|
||||||
{
|
{
|
||||||
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
calcThetaBeta(alfa, _vt_NED);
|
calcThetaBeta(alfa, _vt_NED);
|
||||||
}
|
}
|
||||||
|
@ -356,9 +361,10 @@ void FGInitialCondition::SetAlphaRadIC(double alfa)
|
||||||
|
|
||||||
void FGInitialCondition::calcThetaBeta(double alfa, const FGColumnVector3& _vt_NED)
|
void FGInitialCondition::calcThetaBeta(double alfa, const FGColumnVector3& _vt_NED)
|
||||||
{
|
{
|
||||||
|
FGColumnVector3 vOrient = orientation.GetEuler();
|
||||||
double calpha = cos(alfa), salpha = sin(alfa);
|
double calpha = cos(alfa), salpha = sin(alfa);
|
||||||
double cpsi = cos(psi), spsi = sin(psi);
|
double cpsi = orientation.GetCosEuler(ePsi), spsi = orientation.GetSinEuler(ePsi);
|
||||||
double cphi = cos(phi), sphi = sin(phi);
|
double cphi = orientation.GetCosEuler(ePhi), sphi = orientation.GetSinEuler(ePhi);
|
||||||
FGMatrix33 Tpsi( cpsi, spsi, 0.,
|
FGMatrix33 Tpsi( cpsi, spsi, 0.,
|
||||||
-spsi, cpsi, 0.,
|
-spsi, cpsi, 0.,
|
||||||
0., 0., 1.);
|
0., 0., 1.);
|
||||||
|
@ -400,13 +406,11 @@ void FGInitialCondition::calcThetaBeta(double alfa, const FGColumnVector3& _vt_N
|
||||||
v0xz.Normalize();
|
v0xz.Normalize();
|
||||||
v1xz.Normalize();
|
v1xz.Normalize();
|
||||||
double sinTheta = (v1xz * v0xz)(eY);
|
double sinTheta = (v1xz * v0xz)(eY);
|
||||||
theta = asin(sinTheta);
|
vOrient(eTht) = asin(sinTheta);
|
||||||
|
|
||||||
FGQuaternion Quat(phi, theta, psi);
|
orientation = FGQuaternion(vOrient);
|
||||||
Quat.Normalize();
|
|
||||||
Tl2b = Quat.GetT();
|
|
||||||
Tb2l = Quat.GetTInv();
|
|
||||||
|
|
||||||
|
const FGMatrix33& Tl2b = orientation.GetT();
|
||||||
FGColumnVector3 v2 = Talpha * Tl2b * _vt_NED;
|
FGColumnVector3 v2 = Talpha * Tl2b * _vt_NED;
|
||||||
|
|
||||||
alpha = alfa;
|
alpha = alfa;
|
||||||
|
@ -430,18 +434,24 @@ void FGInitialCondition::calcThetaBeta(double alfa, const FGColumnVector3& _vt_N
|
||||||
|
|
||||||
void FGInitialCondition::SetBetaRadIC(double bta)
|
void FGInitialCondition::SetBetaRadIC(double bta)
|
||||||
{
|
{
|
||||||
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
|
FGColumnVector3 vOrient = orientation.GetEuler();
|
||||||
|
|
||||||
beta = bta;
|
beta = bta;
|
||||||
double calpha = cos(alpha), salpha = sin(alpha);
|
double calpha = cos(alpha), salpha = sin(alpha);
|
||||||
double cbeta = cos(beta), sbeta = sin(beta);
|
double cbeta = cos(beta), sbeta = sin(beta);
|
||||||
|
double cphi = orientation.GetCosEuler(ePhi), sphi = orientation.GetSinEuler(ePhi);
|
||||||
|
FGMatrix33 TphiInv(1., 0., 0.,
|
||||||
|
0., cphi,-sphi,
|
||||||
|
0., sphi, cphi);
|
||||||
|
|
||||||
Tw2b = FGMatrix33(calpha*cbeta, -calpha*sbeta, -salpha,
|
Tw2b = FGMatrix33(calpha*cbeta, -calpha*sbeta, -salpha,
|
||||||
sbeta, cbeta, 0.0,
|
sbeta, cbeta, 0.0,
|
||||||
salpha*cbeta, -salpha*sbeta, calpha);
|
salpha*cbeta, -salpha*sbeta, calpha);
|
||||||
Tb2w = Tw2b.Transposed();
|
Tb2w = Tw2b.Transposed();
|
||||||
|
|
||||||
FGColumnVector3 vf = FGQuaternion(eX, phi).GetTInv() * Tw2b * FGColumnVector3(vt, 0., 0.);
|
FGColumnVector3 vf = TphiInv * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
FGColumnVector3 v0xy(_vt_NED(eX), _vt_NED(eY), 0.);
|
FGColumnVector3 v0xy(_vt_NED(eX), _vt_NED(eY), 0.);
|
||||||
FGColumnVector3 v1xy(sqrt(v0xy(eX)*v0xy(eX)+v0xy(eY)*v0xy(eY)-vf(eY)*vf(eY)),vf(eY),0.);
|
FGColumnVector3 v1xy(sqrt(v0xy(eX)*v0xy(eX)+v0xy(eY)*v0xy(eY)-vf(eY)*vf(eY)),vf(eY),0.);
|
||||||
v0xy.Normalize();
|
v0xy.Normalize();
|
||||||
|
@ -451,7 +461,7 @@ void FGInitialCondition::SetBetaRadIC(double bta)
|
||||||
|
|
||||||
double sinPsi = (v1xy * v0xy)(eZ);
|
double sinPsi = (v1xy * v0xy)(eZ);
|
||||||
double cosPsi = DotProduct(v0xy, v1xy);
|
double cosPsi = DotProduct(v0xy, v1xy);
|
||||||
psi = atan2(sinPsi, cosPsi);
|
vOrient(ePsi) = atan2(sinPsi, cosPsi);
|
||||||
FGMatrix33 Tpsi( cosPsi, sinPsi, 0.,
|
FGMatrix33 Tpsi( cosPsi, sinPsi, 0.,
|
||||||
-sinPsi, cosPsi, 0.,
|
-sinPsi, cosPsi, 0.,
|
||||||
0., 0., 1.);
|
0., 0., 1.);
|
||||||
|
@ -462,64 +472,32 @@ void FGInitialCondition::SetBetaRadIC(double bta)
|
||||||
v2xz.Normalize();
|
v2xz.Normalize();
|
||||||
vfxz.Normalize();
|
vfxz.Normalize();
|
||||||
double sinTheta = (v2xz * vfxz)(eY);
|
double sinTheta = (v2xz * vfxz)(eY);
|
||||||
theta = -asin(sinTheta);
|
vOrient(eTht) = -asin(sinTheta);
|
||||||
|
|
||||||
FGQuaternion Quat(phi, theta, psi);
|
orientation = FGQuaternion(vOrient);
|
||||||
Quat.Normalize();
|
|
||||||
Tl2b = Quat.GetT();
|
|
||||||
Tb2l = Quat.GetTInv();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
// Modifies the body frame orientation (roll angle phi). The true airspeed in
|
// Modifies the body frame orientation.
|
||||||
// the local NED frame is kept unchanged. Hence the true airspeed in the body
|
|
||||||
// frame is modified.
|
|
||||||
|
|
||||||
void FGInitialCondition::SetPhiRadIC(double fi)
|
void FGInitialCondition::SetEulerAngleRadIC(int idx, double angle)
|
||||||
{
|
{
|
||||||
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
|
const FGMatrix33& Tl2b = orientation.GetT();
|
||||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
|
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
||||||
|
FGColumnVector3 _vUVW_BODY = Tl2b * vUVW_NED;
|
||||||
|
FGColumnVector3 vOrient = orientation.GetEuler();
|
||||||
|
|
||||||
phi = fi;
|
vOrient(idx) = angle;
|
||||||
FGQuaternion Quat = FGQuaternion(phi, theta, psi);
|
orientation = FGQuaternion(vOrient);
|
||||||
Quat.Normalize();
|
|
||||||
Tl2b = Quat.GetT();
|
|
||||||
Tb2l = Quat.GetTInv();
|
|
||||||
|
|
||||||
calcAeroAngles(_vt_NED);
|
if ((lastSpeedSet != setned) && (lastSpeedSet != setvg)) {
|
||||||
}
|
const FGMatrix33& newTb2l = orientation.GetTInv();
|
||||||
|
vUVW_NED = newTb2l * _vUVW_BODY;
|
||||||
//******************************************************************************
|
_vt_NED = vUVW_NED + _vWIND_NED;
|
||||||
// Modifies the body frame orientation (pitch angle theta). The true airspeed in
|
vt = _vt_NED.Magnitude();
|
||||||
// the local NED frame is kept unchanged. Hence the true airspeed in the body
|
}
|
||||||
// frame is modified.
|
|
||||||
|
|
||||||
void FGInitialCondition::SetThetaRadIC(double teta)
|
|
||||||
{
|
|
||||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
|
||||||
|
|
||||||
theta = teta;
|
|
||||||
FGQuaternion Quat = FGQuaternion(phi, theta, psi);
|
|
||||||
Quat.Normalize();
|
|
||||||
Tl2b = Quat.GetT();
|
|
||||||
Tb2l = Quat.GetTInv();
|
|
||||||
|
|
||||||
calcAeroAngles(_vt_NED);
|
|
||||||
}
|
|
||||||
|
|
||||||
//******************************************************************************
|
|
||||||
// Modifies the body frame orientation (yaw angle psi). The true airspeed in
|
|
||||||
// the local NED frame is kept unchanged. Hence the true airspeed in the body
|
|
||||||
// frame is modified.
|
|
||||||
|
|
||||||
void FGInitialCondition::SetPsiRadIC(double psy)
|
|
||||||
{
|
|
||||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
|
||||||
|
|
||||||
psi = psy;
|
|
||||||
FGQuaternion Quat = FGQuaternion(phi, theta, psi);
|
|
||||||
Quat.Normalize();
|
|
||||||
Tl2b = Quat.GetT();
|
|
||||||
Tb2l = Quat.GetTInv();
|
|
||||||
|
|
||||||
calcAeroAngles(_vt_NED);
|
calcAeroAngles(_vt_NED);
|
||||||
}
|
}
|
||||||
|
@ -531,6 +509,8 @@ void FGInitialCondition::SetPsiRadIC(double psy)
|
||||||
|
|
||||||
void FGInitialCondition::SetBodyVelFpsIC(int idx, double vel)
|
void FGInitialCondition::SetBodyVelFpsIC(int idx, double vel)
|
||||||
{
|
{
|
||||||
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
|
const FGMatrix33& Tl2b = orientation.GetT();
|
||||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
FGColumnVector3 _vUVW_BODY = Tl2b * vUVW_NED;
|
FGColumnVector3 _vUVW_BODY = Tl2b * vUVW_NED;
|
||||||
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
||||||
|
@ -552,6 +532,7 @@ void FGInitialCondition::SetBodyVelFpsIC(int idx, double vel)
|
||||||
|
|
||||||
void FGInitialCondition::SetNEDVelFpsIC(int idx, double vel)
|
void FGInitialCondition::SetNEDVelFpsIC(int idx, double vel)
|
||||||
{
|
{
|
||||||
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
||||||
|
|
||||||
|
@ -583,9 +564,10 @@ void FGInitialCondition::SetWindNEDFpsIC(double wN, double wE, double wD )
|
||||||
|
|
||||||
void FGInitialCondition::SetCrossWindKtsIC(double cross)
|
void FGInitialCondition::SetCrossWindKtsIC(double cross)
|
||||||
{
|
{
|
||||||
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
||||||
FGColumnVector3 _vCROSS(-sin(psi), cos(psi), 0.);
|
FGColumnVector3 _vCROSS(-orientation.GetSinEuler(ePsi), orientation.GetCosEuler(ePsi), 0.);
|
||||||
|
|
||||||
// Gram-Schmidt process is used to remove the existing cross wind component
|
// Gram-Schmidt process is used to remove the existing cross wind component
|
||||||
_vWIND_NED -= DotProduct(_vWIND_NED, _vCROSS) * _vCROSS;
|
_vWIND_NED -= DotProduct(_vWIND_NED, _vCROSS) * _vCROSS;
|
||||||
|
@ -605,13 +587,14 @@ void FGInitialCondition::SetCrossWindKtsIC(double cross)
|
||||||
|
|
||||||
void FGInitialCondition::SetHeadWindKtsIC(double head)
|
void FGInitialCondition::SetHeadWindKtsIC(double head)
|
||||||
{
|
{
|
||||||
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
||||||
// This is a head wind, so the direction vector for the wind
|
// This is a head wind, so the direction vector for the wind
|
||||||
// needs to be set opposite to the heading the aircraft
|
// needs to be set opposite to the heading the aircraft
|
||||||
// is taking. So, the cos and sin of the heading (psi)
|
// is taking. So, the cos and sin of the heading (psi)
|
||||||
// are negated in the line below.
|
// are negated in the line below.
|
||||||
FGColumnVector3 _vHEAD(-cos(psi), -sin(psi), 0.);
|
FGColumnVector3 _vHEAD(-orientation.GetCosEuler(ePsi), -orientation.GetSinEuler(ePsi), 0.);
|
||||||
|
|
||||||
// Gram-Schmidt process is used to remove the existing head wind component
|
// Gram-Schmidt process is used to remove the existing head wind component
|
||||||
_vWIND_NED -= DotProduct(_vWIND_NED, _vHEAD) * _vHEAD;
|
_vWIND_NED -= DotProduct(_vWIND_NED, _vHEAD) * _vHEAD;
|
||||||
|
@ -632,6 +615,7 @@ void FGInitialCondition::SetHeadWindKtsIC(double head)
|
||||||
|
|
||||||
void FGInitialCondition::SetWindDownKtsIC(double wD)
|
void FGInitialCondition::SetWindDownKtsIC(double wD)
|
||||||
{
|
{
|
||||||
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
|
|
||||||
_vt_NED(eW) = vUVW_NED(eW) + wD;
|
_vt_NED(eW) = vUVW_NED(eW) + wD;
|
||||||
|
@ -647,6 +631,7 @@ void FGInitialCondition::SetWindDownKtsIC(double wD)
|
||||||
|
|
||||||
void FGInitialCondition::SetWindMagKtsIC(double mag)
|
void FGInitialCondition::SetWindMagKtsIC(double mag)
|
||||||
{
|
{
|
||||||
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
||||||
FGColumnVector3 _vHEAD(_vWIND_NED(eU), _vWIND_NED(eV), 0.);
|
FGColumnVector3 _vHEAD(_vWIND_NED(eU), _vWIND_NED(eV), 0.);
|
||||||
|
@ -672,6 +657,7 @@ void FGInitialCondition::SetWindMagKtsIC(double mag)
|
||||||
|
|
||||||
void FGInitialCondition::SetWindDirDegIC(double dir)
|
void FGInitialCondition::SetWindDirDegIC(double dir)
|
||||||
{
|
{
|
||||||
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
||||||
double mag = _vWIND_NED.Magnitude(eU, eV);
|
double mag = _vWIND_NED.Magnitude(eU, eV);
|
||||||
|
@ -693,25 +679,30 @@ void FGInitialCondition::SetWindDirDegIC(double dir)
|
||||||
void FGInitialCondition::SetAltitudeASLFtIC(double alt)
|
void FGInitialCondition::SetAltitudeASLFtIC(double alt)
|
||||||
{
|
{
|
||||||
double altitudeASL = position.GetRadius() - sea_level_radius;
|
double altitudeASL = position.GetRadius() - sea_level_radius;
|
||||||
double temperature = fdmex->GetAtmosphere()->GetTemperature(altitudeASL);
|
double temperature = Atmosphere->GetTemperature(altitudeASL);
|
||||||
|
double pressure = Atmosphere->GetPressure(altitudeASL);
|
||||||
|
double pressureSL = Atmosphere->GetPressureSL();
|
||||||
double soundSpeed = sqrt(SHRatio*Reng*temperature);
|
double soundSpeed = sqrt(SHRatio*Reng*temperature);
|
||||||
double rho = fdmex->GetAtmosphere()->GetDensity(altitudeASL);
|
double rho = Atmosphere->GetDensity(altitudeASL);
|
||||||
double rhoSL = fdmex->GetAtmosphere()->GetDensitySL();
|
double rhoSL = Atmosphere->GetDensitySL();
|
||||||
|
|
||||||
double mach0 = vt / soundSpeed;
|
double mach0 = vt / soundSpeed;
|
||||||
double vc0 = calcVcas(mach0);
|
double vc0 = VcalibratedFromMach(mach0, pressure, pressureSL, rhoSL);
|
||||||
double ve0 = vt * sqrt(rho/rhoSL);
|
double ve0 = vt * sqrt(rho/rhoSL);
|
||||||
|
|
||||||
altitudeASL=alt;
|
altitudeASL=alt;
|
||||||
position.SetRadius(alt + sea_level_radius);
|
position.SetRadius(alt + sea_level_radius);
|
||||||
|
|
||||||
temperature = fdmex->GetAtmosphere()->GetTemperature(altitudeASL);
|
temperature = Atmosphere->GetTemperature(altitudeASL);
|
||||||
soundSpeed = sqrt(SHRatio*Reng*temperature);
|
soundSpeed = sqrt(SHRatio*Reng*temperature);
|
||||||
rho = fdmex->GetAtmosphere()->GetDensity(altitudeASL);
|
rho = Atmosphere->GetDensity(altitudeASL);
|
||||||
|
pressure = Atmosphere->GetPressure(altitudeASL);
|
||||||
|
|
||||||
switch(lastSpeedSet) {
|
switch(lastSpeedSet) {
|
||||||
case setvc:
|
case setvc:
|
||||||
mach0 = getMachFromVcas(vc0);
|
mach0 = MachFromVcalibrated(vc0, pressure, pressureSL, rhoSL);
|
||||||
|
SetVtrueFpsIC(mach0 * soundSpeed);
|
||||||
|
break;
|
||||||
case setmach:
|
case setmach:
|
||||||
SetVtrueFpsIC(mach0 * soundSpeed);
|
SetVtrueFpsIC(mach0 * soundSpeed);
|
||||||
break;
|
break;
|
||||||
|
@ -723,90 +714,11 @@ void FGInitialCondition::SetAltitudeASLFtIC(double alt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
|
||||||
// Calculate the VCAS. Uses the Rayleigh formula for supersonic speeds
|
|
||||||
// (See "Introduction to Aerodynamics of a Compressible Fluid - H.W. Liepmann,
|
|
||||||
// A.E. Puckett - Wiley & sons (1947)" §5.4 pp 75-80)
|
|
||||||
|
|
||||||
double FGInitialCondition::calcVcas(double Mach) const
|
|
||||||
{
|
|
||||||
double altitudeASL = position.GetRadius() - sea_level_radius;
|
|
||||||
double p=fdmex->GetAtmosphere()->GetPressure(altitudeASL);
|
|
||||||
double psl=fdmex->GetAtmosphere()->GetPressureSL();
|
|
||||||
double rhosl=fdmex->GetAtmosphere()->GetDensitySL();
|
|
||||||
double pt,A,vcas;
|
|
||||||
|
|
||||||
if (Mach < 0) Mach=0;
|
|
||||||
if (Mach < 1) //calculate total pressure assuming isentropic flow
|
|
||||||
pt=p*pow((1 + 0.2*Mach*Mach),3.5);
|
|
||||||
else {
|
|
||||||
// shock in front of pitot tube, we'll assume its normal and use
|
|
||||||
// the Rayleigh Pitot Tube Formula, i.e. the ratio of total
|
|
||||||
// pressure behind the shock to the static pressure in front of
|
|
||||||
// the normal shock assumption should not be a bad one -- most supersonic
|
|
||||||
// aircraft place the pitot probe out front so that it is the forward
|
|
||||||
// most point on the aircraft. The real shock would, of course, take
|
|
||||||
// on something like the shape of a rounded-off cone but, here again,
|
|
||||||
// the assumption should be good since the opening of the pitot probe
|
|
||||||
// is very small and, therefore, the effects of the shock curvature
|
|
||||||
// should be small as well. AFAIK, this approach is fairly well accepted
|
|
||||||
// within the aerospace community
|
|
||||||
|
|
||||||
// The denominator below is zero for Mach ~ 0.38, for which
|
|
||||||
// we'll never be here, so we're safe
|
|
||||||
|
|
||||||
pt = p*166.92158*pow(Mach,7.0)/pow(7*Mach*Mach-1,2.5);
|
|
||||||
}
|
|
||||||
|
|
||||||
A = pow(((pt-p)/psl+1),0.28571);
|
|
||||||
vcas = sqrt(7*psl/rhosl*(A-1));
|
|
||||||
//cout << "calcVcas: vcas= " << vcas*fpstokts << " mach= " << Mach << " pressure: " << pt << endl;
|
|
||||||
return vcas;
|
|
||||||
}
|
|
||||||
|
|
||||||
//******************************************************************************
|
|
||||||
// Reverse the VCAS formula to obtain the corresponding Mach number. For subsonic
|
|
||||||
// speeds, the reversed formula has a closed form. For supersonic speeds, the
|
|
||||||
// formula is reversed by the Newton-Raphson algorithm.
|
|
||||||
|
|
||||||
double FGInitialCondition::getMachFromVcas(double vcas)
|
|
||||||
{
|
|
||||||
double altitudeASL = position.GetRadius() - sea_level_radius;
|
|
||||||
double p=fdmex->GetAtmosphere()->GetPressure(altitudeASL);
|
|
||||||
double psl=fdmex->GetAtmosphere()->GetPressureSL();
|
|
||||||
double rhosl=fdmex->GetAtmosphere()->GetDensitySL();
|
|
||||||
|
|
||||||
double pt = p + psl*(pow(1+vcas*vcas*rhosl/(7.0*psl),3.5)-1);
|
|
||||||
|
|
||||||
if (pt/p < 1.89293)
|
|
||||||
return sqrt(5.0*(pow(pt/p, 0.2857143) -1)); // Mach < 1
|
|
||||||
else {
|
|
||||||
// Mach >= 1
|
|
||||||
double mach = sqrt(0.77666*pt/p); // Initial guess is based on a quadratic approximation of the Rayleigh formula
|
|
||||||
double delta = 1.;
|
|
||||||
double target = pt/(166.92158*p);
|
|
||||||
int iter = 0;
|
|
||||||
|
|
||||||
// Find the root with Newton-Raphson. Since the differential is never zero,
|
|
||||||
// the function is monotonic and has only one root with a multiplicity of one.
|
|
||||||
// Convergence is certain.
|
|
||||||
while (delta > 1E-5 && iter < 10) {
|
|
||||||
double m2 = mach*mach; // Mach^2
|
|
||||||
double m6 = m2*m2*m2; // Mach^6
|
|
||||||
delta = mach*m6/pow(7.0*m2-1.0,2.5) - target;
|
|
||||||
double diff = 7.0*m6*(2.0*m2-1)/pow(7.0*m2-1.0,3.5); // Never zero when Mach >= 1
|
|
||||||
mach -= delta/diff;
|
|
||||||
iter++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mach;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
|
|
||||||
double FGInitialCondition::GetWindDirDegIC(void) const
|
double FGInitialCondition::GetWindDirDegIC(void) const
|
||||||
{
|
{
|
||||||
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
||||||
|
|
||||||
|
@ -818,6 +730,7 @@ double FGInitialCondition::GetWindDirDegIC(void) const
|
||||||
|
|
||||||
double FGInitialCondition::GetNEDWindFpsIC(int idx) const
|
double FGInitialCondition::GetNEDWindFpsIC(int idx) const
|
||||||
{
|
{
|
||||||
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
||||||
|
|
||||||
|
@ -828,6 +741,7 @@ double FGInitialCondition::GetNEDWindFpsIC(int idx) const
|
||||||
|
|
||||||
double FGInitialCondition::GetWindFpsIC(void) const
|
double FGInitialCondition::GetWindFpsIC(void) const
|
||||||
{
|
{
|
||||||
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
FGColumnVector3 _vWIND_NED = _vt_NED - vUVW_NED;
|
||||||
|
|
||||||
|
@ -838,6 +752,7 @@ double FGInitialCondition::GetWindFpsIC(void) const
|
||||||
|
|
||||||
double FGInitialCondition::GetBodyWindFpsIC(int idx) const
|
double FGInitialCondition::GetBodyWindFpsIC(int idx) const
|
||||||
{
|
{
|
||||||
|
const FGMatrix33& Tl2b = orientation.GetT();
|
||||||
FGColumnVector3 _vt_BODY = Tw2b * FGColumnVector3(vt, 0., 0.);
|
FGColumnVector3 _vt_BODY = Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
FGColumnVector3 _vUVW_BODY = Tl2b * vUVW_NED;
|
FGColumnVector3 _vUVW_BODY = Tl2b * vUVW_NED;
|
||||||
FGColumnVector3 _vWIND_BODY = _vt_BODY - _vUVW_BODY;
|
FGColumnVector3 _vWIND_BODY = _vt_BODY - _vUVW_BODY;
|
||||||
|
@ -850,10 +765,13 @@ double FGInitialCondition::GetBodyWindFpsIC(int idx) const
|
||||||
double FGInitialCondition::GetVcalibratedKtsIC(void) const
|
double FGInitialCondition::GetVcalibratedKtsIC(void) const
|
||||||
{
|
{
|
||||||
double altitudeASL = position.GetRadius() - sea_level_radius;
|
double altitudeASL = position.GetRadius() - sea_level_radius;
|
||||||
double temperature = fdmex->GetAtmosphere()->GetTemperature(altitudeASL);
|
double temperature = Atmosphere->GetTemperature(altitudeASL);
|
||||||
|
double pressure = Atmosphere->GetPressure(altitudeASL);
|
||||||
|
double pressureSL = Atmosphere->GetPressureSL();
|
||||||
|
double rhoSL = Atmosphere->GetDensitySL();
|
||||||
double soundSpeed = sqrt(SHRatio*Reng*temperature);
|
double soundSpeed = sqrt(SHRatio*Reng*temperature);
|
||||||
double mach = vt / soundSpeed;
|
double mach = vt / soundSpeed;
|
||||||
return fpstokts * calcVcas(mach);
|
return fpstokts * VcalibratedFromMach(mach, pressure, pressureSL, rhoSL);
|
||||||
}
|
}
|
||||||
|
|
||||||
//******************************************************************************
|
//******************************************************************************
|
||||||
|
@ -861,8 +779,8 @@ double FGInitialCondition::GetVcalibratedKtsIC(void) const
|
||||||
double FGInitialCondition::GetVequivalentKtsIC(void) const
|
double FGInitialCondition::GetVequivalentKtsIC(void) const
|
||||||
{
|
{
|
||||||
double altitudeASL = position.GetRadius() - sea_level_radius;
|
double altitudeASL = position.GetRadius() - sea_level_radius;
|
||||||
double rho = fdmex->GetAtmosphere()->GetDensity(altitudeASL);
|
double rho = Atmosphere->GetDensity(altitudeASL);
|
||||||
double rhoSL = fdmex->GetAtmosphere()->GetDensitySL();
|
double rhoSL = Atmosphere->GetDensitySL();
|
||||||
return fpstokts * vt * sqrt(rho/rhoSL);
|
return fpstokts * vt * sqrt(rho/rhoSL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -871,7 +789,7 @@ double FGInitialCondition::GetVequivalentKtsIC(void) const
|
||||||
double FGInitialCondition::GetMachIC(void) const
|
double FGInitialCondition::GetMachIC(void) const
|
||||||
{
|
{
|
||||||
double altitudeASL = position.GetRadius() - sea_level_radius;
|
double altitudeASL = position.GetRadius() - sea_level_radius;
|
||||||
double temperature = fdmex->GetAtmosphere()->GetTemperature(altitudeASL);
|
double temperature = Atmosphere->GetTemperature(altitudeASL);
|
||||||
double soundSpeed = sqrt(SHRatio*Reng*temperature);
|
double soundSpeed = sqrt(SHRatio*Reng*temperature);
|
||||||
return vt / soundSpeed;
|
return vt / soundSpeed;
|
||||||
}
|
}
|
||||||
|
@ -880,6 +798,7 @@ double FGInitialCondition::GetMachIC(void) const
|
||||||
|
|
||||||
double FGInitialCondition::GetBodyVelFpsIC(int idx) const
|
double FGInitialCondition::GetBodyVelFpsIC(int idx) const
|
||||||
{
|
{
|
||||||
|
const FGMatrix33& Tl2b = orientation.GetT();
|
||||||
FGColumnVector3 _vUVW_BODY = Tl2b * vUVW_NED;
|
FGColumnVector3 _vUVW_BODY = Tl2b * vUVW_NED;
|
||||||
|
|
||||||
return _vUVW_BODY(idx);
|
return _vUVW_BODY(idx);
|
||||||
|
@ -923,6 +842,8 @@ bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
|
||||||
result = Load_v1();
|
result = Load_v1();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fdmex->RunIC();
|
||||||
|
|
||||||
// Check to see if any engines are specified to be initialized in a running state
|
// Check to see if any engines are specified to be initialized in a running state
|
||||||
FGPropulsion* propulsion = fdmex->GetPropulsion();
|
FGPropulsion* propulsion = fdmex->GetPropulsion();
|
||||||
Element* running_elements = document->FindElement("running");
|
Element* running_elements = document->FindElement("running");
|
||||||
|
@ -937,9 +858,6 @@ bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
|
||||||
running_elements = document->FindNextElement("running");
|
running_elements = document->FindNextElement("running");
|
||||||
}
|
}
|
||||||
|
|
||||||
fdmex->RunIC();
|
|
||||||
fdmex->GetPropagate()->DumpState();
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -963,17 +881,16 @@ bool FGInitialCondition::Load_v1(void)
|
||||||
else if (document->FindElement("altitudeMSL")) // This is feet above sea level
|
else if (document->FindElement("altitudeMSL")) // This is feet above sea level
|
||||||
position.SetRadius(document->FindElementValueAsNumberConvertTo("altitudeMSL", "FT") + sea_level_radius);
|
position.SetRadius(document->FindElementValueAsNumberConvertTo("altitudeMSL", "FT") + sea_level_radius);
|
||||||
|
|
||||||
if (document->FindElement("phi"))
|
FGColumnVector3 vOrient = orientation.GetEuler();
|
||||||
phi = document->FindElementValueAsNumberConvertTo("phi", "RAD");
|
|
||||||
if (document->FindElement("theta"))
|
|
||||||
theta = document->FindElementValueAsNumberConvertTo("theta", "RAD");
|
|
||||||
if (document->FindElement("psi"))
|
|
||||||
psi = document->FindElementValueAsNumberConvertTo("psi", "RAD");
|
|
||||||
|
|
||||||
FGQuaternion Quat(phi, theta, psi);
|
if (document->FindElement("phi"))
|
||||||
Quat.Normalize();
|
vOrient(ePhi) = document->FindElementValueAsNumberConvertTo("phi", "RAD");
|
||||||
Tl2b = Quat.GetT();
|
if (document->FindElement("theta"))
|
||||||
Tb2l = Quat.GetTInv();
|
vOrient(eTht) = document->FindElementValueAsNumberConvertTo("theta", "RAD");
|
||||||
|
if (document->FindElement("psi"))
|
||||||
|
vOrient(ePsi) = document->FindElementValueAsNumberConvertTo("psi", "RAD");
|
||||||
|
|
||||||
|
orientation = FGQuaternion(vOrient);
|
||||||
|
|
||||||
if (document->FindElement("ubody"))
|
if (document->FindElement("ubody"))
|
||||||
SetUBodyFpsIC(document->FindElementValueAsNumberConvertTo("ubody", "FT/SEC"));
|
SetUBodyFpsIC(document->FindElementValueAsNumberConvertTo("ubody", "FT/SEC"));
|
||||||
|
@ -1024,9 +941,7 @@ bool FGInitialCondition::Load_v1(void)
|
||||||
-radInv*vUVW_NED(eNorth),
|
-radInv*vUVW_NED(eNorth),
|
||||||
-radInv*vUVW_NED(eEast)*position.GetTanLatitude() );
|
-radInv*vUVW_NED(eEast)*position.GetTanLatitude() );
|
||||||
|
|
||||||
p = vOmegaLocal(eP);
|
vPQR_body = vOmegaLocal;
|
||||||
q = vOmegaLocal(eR);
|
|
||||||
r = vOmegaLocal(eQ);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -1111,7 +1026,6 @@ bool FGInitialCondition::Load_v2(void)
|
||||||
// ToDo: Do we need to deal with normalization of the quaternions here?
|
// ToDo: Do we need to deal with normalization of the quaternions here?
|
||||||
|
|
||||||
Element* orientation_el = document->FindElement("orientation");
|
Element* orientation_el = document->FindElement("orientation");
|
||||||
FGQuaternion QuatLocal2Body;
|
|
||||||
if (orientation_el) {
|
if (orientation_el) {
|
||||||
string frame = orientation_el->GetAttributeValue("frame");
|
string frame = orientation_el->GetAttributeValue("frame");
|
||||||
frame = to_lower(frame);
|
frame = to_lower(frame);
|
||||||
|
@ -1132,7 +1046,7 @@ bool FGInitialCondition::Load_v2(void)
|
||||||
QuatI2Body.Normalize();
|
QuatI2Body.Normalize();
|
||||||
FGQuaternion QuatLocal2I = position.GetTl2i();
|
FGQuaternion QuatLocal2I = position.GetTl2i();
|
||||||
QuatLocal2I.Normalize();
|
QuatLocal2I.Normalize();
|
||||||
QuatLocal2Body = QuatLocal2I * QuatI2Body;
|
orientation = QuatLocal2I * QuatI2Body;
|
||||||
|
|
||||||
} else if (frame == "ecef") {
|
} else if (frame == "ecef") {
|
||||||
|
|
||||||
|
@ -1150,11 +1064,11 @@ bool FGInitialCondition::Load_v2(void)
|
||||||
QuatEC2Body.Normalize();
|
QuatEC2Body.Normalize();
|
||||||
FGQuaternion QuatLocal2EC = position.GetTl2ec(); // Get Q_e/l from matrix
|
FGQuaternion QuatLocal2EC = position.GetTl2ec(); // Get Q_e/l from matrix
|
||||||
QuatLocal2EC.Normalize();
|
QuatLocal2EC.Normalize();
|
||||||
QuatLocal2Body = QuatLocal2EC * QuatEC2Body; // Q_b/l = Q_e/l * Q_b/e
|
orientation = QuatLocal2EC * QuatEC2Body; // Q_b/l = Q_e/l * Q_b/e
|
||||||
|
|
||||||
} else if (frame == "local") {
|
} else if (frame == "local") {
|
||||||
|
|
||||||
QuatLocal2Body = FGQuaternion(vOrient);
|
orientation = FGQuaternion(vOrient);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
|
@ -1165,13 +1079,6 @@ bool FGInitialCondition::Load_v2(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QuatLocal2Body.Normalize();
|
|
||||||
phi = QuatLocal2Body.GetEuler(ePhi);
|
|
||||||
theta = QuatLocal2Body.GetEuler(eTht);
|
|
||||||
psi = QuatLocal2Body.GetEuler(ePsi);
|
|
||||||
Tl2b = QuatLocal2Body.GetT();
|
|
||||||
Tb2l = QuatLocal2Body.GetTInv();
|
|
||||||
|
|
||||||
// Initialize vehicle velocity
|
// Initialize vehicle velocity
|
||||||
// Allowable frames
|
// Allowable frames
|
||||||
// - ECI (Earth Centered Inertial)
|
// - ECI (Earth Centered Inertial)
|
||||||
|
@ -1183,6 +1090,8 @@ bool FGInitialCondition::Load_v2(void)
|
||||||
Element* velocity_el = document->FindElement("velocity");
|
Element* velocity_el = document->FindElement("velocity");
|
||||||
FGColumnVector3 vInitVelocity = FGColumnVector3(0.0, 0.0, 0.0);
|
FGColumnVector3 vInitVelocity = FGColumnVector3(0.0, 0.0, 0.0);
|
||||||
FGMatrix33 mTec2l = position.GetTec2l();
|
FGMatrix33 mTec2l = position.GetTec2l();
|
||||||
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
|
|
||||||
if (velocity_el) {
|
if (velocity_el) {
|
||||||
|
|
||||||
string frame = velocity_el->GetAttributeValue("frame");
|
string frame = velocity_el->GetAttributeValue("frame");
|
||||||
|
@ -1224,8 +1133,8 @@ bool FGInitialCondition::Load_v2(void)
|
||||||
// - ECEF (Earth Centered, Earth Fixed)
|
// - ECEF (Earth Centered, Earth Fixed)
|
||||||
// - Body
|
// - Body
|
||||||
|
|
||||||
FGColumnVector3 vLocalRate;
|
|
||||||
Element* attrate_el = document->FindElement("attitude_rate");
|
Element* attrate_el = document->FindElement("attitude_rate");
|
||||||
|
const FGMatrix33& Tl2b = orientation.GetT();
|
||||||
|
|
||||||
// Refer to Stevens and Lewis, 1.5-14a, pg. 49.
|
// Refer to Stevens and Lewis, 1.5-14a, pg. 49.
|
||||||
// This is the rotation rate of the "Local" frame, expressed in the local frame.
|
// This is the rotation rate of the "Local" frame, expressed in the local frame.
|
||||||
|
@ -1242,11 +1151,11 @@ bool FGInitialCondition::Load_v2(void)
|
||||||
FGColumnVector3 vAttRate = attrate_el->FindElementTripletConvertTo("RAD/SEC");
|
FGColumnVector3 vAttRate = attrate_el->FindElementTripletConvertTo("RAD/SEC");
|
||||||
|
|
||||||
if (frame == "eci") {
|
if (frame == "eci") {
|
||||||
vLocalRate = Tl2b * position.GetTi2l() * (vAttRate - vOmegaEarth);
|
vPQR_body = Tl2b * position.GetTi2l() * (vAttRate - vOmegaEarth);
|
||||||
} else if (frame == "ecef") {
|
} else if (frame == "ecef") {
|
||||||
vLocalRate = Tl2b * position.GetTec2l() * vAttRate;
|
vPQR_body = Tl2b * position.GetTec2l() * vAttRate;
|
||||||
} else if (frame == "local") {
|
} else if (frame == "local") {
|
||||||
vLocalRate = vAttRate + vOmegaLocal;
|
vPQR_body = vAttRate + vOmegaLocal;
|
||||||
} else if (!frame.empty()) { // misspelling of frame
|
} else if (!frame.empty()) { // misspelling of frame
|
||||||
|
|
||||||
cerr << endl << fgred << " Attitude rate frame type: \"" << frame
|
cerr << endl << fgred << " Attitude rate frame type: \"" << frame
|
||||||
|
@ -1254,17 +1163,13 @@ bool FGInitialCondition::Load_v2(void)
|
||||||
result = false;
|
result = false;
|
||||||
|
|
||||||
} else if (frame.empty()) {
|
} else if (frame.empty()) {
|
||||||
vLocalRate = vOmegaLocal;
|
vPQR_body = vOmegaLocal;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else { // Body frame attitude rate assumed 0 relative to local.
|
} else { // Body frame attitude rate assumed 0 relative to local.
|
||||||
vLocalRate = vOmegaLocal;
|
vPQR_body = vOmegaLocal;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = vLocalRate(eP);
|
|
||||||
q = vLocalRate(eQ);
|
|
||||||
r = vLocalRate(eR);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1317,7 +1222,9 @@ void FGInitialCondition::bind(void)
|
||||||
&FGInitialCondition::SetPhiDegIC,
|
&FGInitialCondition::SetPhiDegIC,
|
||||||
true);
|
true);
|
||||||
PropertyManager->Tie("ic/psi-true-deg", this,
|
PropertyManager->Tie("ic/psi-true-deg", this,
|
||||||
&FGInitialCondition::GetPsiDegIC );
|
&FGInitialCondition::GetPsiDegIC,
|
||||||
|
&FGInitialCondition::SetPsiDegIC,
|
||||||
|
true);
|
||||||
PropertyManager->Tie("ic/lat-gc-deg", this,
|
PropertyManager->Tie("ic/lat-gc-deg", this,
|
||||||
&FGInitialCondition::GetLatitudeDegIC,
|
&FGInitialCondition::GetLatitudeDegIC,
|
||||||
&FGInitialCondition::SetLatitudeDegIC,
|
&FGInitialCondition::SetLatitudeDegIC,
|
||||||
|
@ -1414,7 +1321,9 @@ void FGInitialCondition::bind(void)
|
||||||
&FGInitialCondition::SetPhiRadIC,
|
&FGInitialCondition::SetPhiRadIC,
|
||||||
true);
|
true);
|
||||||
PropertyManager->Tie("ic/psi-true-rad", this,
|
PropertyManager->Tie("ic/psi-true-rad", this,
|
||||||
&FGInitialCondition::GetPsiRadIC);
|
&FGInitialCondition::GetPsiRadIC,
|
||||||
|
&FGInitialCondition::SetPsiRadIC,
|
||||||
|
true);
|
||||||
PropertyManager->Tie("ic/lat-gc-rad", this,
|
PropertyManager->Tie("ic/lat-gc-rad", this,
|
||||||
&FGInitialCondition::GetLatitudeRadIC,
|
&FGInitialCondition::GetLatitudeRadIC,
|
||||||
&FGInitialCondition::SetLatitudeRadIC,
|
&FGInitialCondition::SetLatitudeRadIC,
|
||||||
|
|
|
@ -54,7 +54,7 @@ INCLUDES
|
||||||
DEFINITIONS
|
DEFINITIONS
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
#define ID_INITIALCONDITION "$Id: FGInitialCondition.h,v 1.28 2011/07/10 19:03:49 jberndt Exp $"
|
#define ID_INITIALCONDITION "$Id: FGInitialCondition.h,v 1.31 2011/10/23 15:05:32 bcoconni Exp $"
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
FORWARD DECLARATIONS
|
FORWARD DECLARATIONS
|
||||||
|
@ -65,6 +65,7 @@ namespace JSBSim {
|
||||||
class FGFDMExec;
|
class FGFDMExec;
|
||||||
class FGMatrix33;
|
class FGMatrix33;
|
||||||
class FGColumnVector3;
|
class FGColumnVector3;
|
||||||
|
class FGAtmosphere;
|
||||||
|
|
||||||
typedef enum { setvt, setvc, setve, setmach, setuvw, setned, setvg } speedset;
|
typedef enum { setvt, setvc, setve, setmach, setuvw, setned, setvg } speedset;
|
||||||
|
|
||||||
|
@ -213,7 +214,7 @@ CLASS DOCUMENTATION
|
||||||
@property ic/r-rad_sec (read/write) Yaw rate initial condition in radians/second
|
@property ic/r-rad_sec (read/write) Yaw rate initial condition in radians/second
|
||||||
|
|
||||||
@author Tony Peden
|
@author Tony Peden
|
||||||
@version "$Id: FGInitialCondition.h,v 1.28 2011/07/10 19:03:49 jberndt Exp $"
|
@version "$Id: FGInitialCondition.h,v 1.31 2011/10/23 15:05:32 bcoconni Exp $"
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -349,15 +350,15 @@ public:
|
||||||
|
|
||||||
/** Gets the initial pitch angle.
|
/** Gets the initial pitch angle.
|
||||||
@return Initial pitch angle in degrees */
|
@return Initial pitch angle in degrees */
|
||||||
double GetThetaDegIC(void) const { return theta*radtodeg; }
|
double GetThetaDegIC(void) const { return orientation.GetEulerDeg(eTht); }
|
||||||
|
|
||||||
/** Gets the initial roll angle.
|
/** Gets the initial roll angle.
|
||||||
@return Initial phi in degrees */
|
@return Initial phi in degrees */
|
||||||
double GetPhiDegIC(void) const { return phi*radtodeg; }
|
double GetPhiDegIC(void) const { return orientation.GetEulerDeg(ePhi); }
|
||||||
|
|
||||||
/** Gets the initial heading angle.
|
/** Gets the initial heading angle.
|
||||||
@return Initial psi in degrees */
|
@return Initial psi in degrees */
|
||||||
double GetPsiDegIC(void) const { return psi*radtodeg; }
|
double GetPsiDegIC(void) const { return orientation.GetEulerDeg(ePsi); }
|
||||||
|
|
||||||
/** Gets the initial latitude.
|
/** Gets the initial latitude.
|
||||||
@return Initial geocentric latitude in degrees */
|
@return Initial geocentric latitude in degrees */
|
||||||
|
@ -411,17 +412,17 @@ public:
|
||||||
@param vd Initial down velocity in feet/second */
|
@param vd Initial down velocity in feet/second */
|
||||||
void SetVDownFpsIC(double vd) { SetNEDVelFpsIC(eW, vd); }
|
void SetVDownFpsIC(double vd) { SetNEDVelFpsIC(eW, vd); }
|
||||||
|
|
||||||
/** Sets the initial roll rate.
|
/** Sets the initial body axis roll rate.
|
||||||
@param P Initial roll rate in radians/second */
|
@param P Initial roll rate in radians/second */
|
||||||
void SetPRadpsIC(double P) { p = P; }
|
void SetPRadpsIC(double P) { vPQR_body(eP) = P; }
|
||||||
|
|
||||||
/** Sets the initial pitch rate.
|
/** Sets the initial body axis pitch rate.
|
||||||
@param Q Initial pitch rate in radians/second */
|
@param Q Initial pitch rate in radians/second */
|
||||||
void SetQRadpsIC(double Q) { q = Q; }
|
void SetQRadpsIC(double Q) { vPQR_body(eQ) = Q; }
|
||||||
|
|
||||||
/** Sets the initial yaw rate.
|
/** Sets the initial body axis yaw rate.
|
||||||
@param R initial yaw rate in radians/second */
|
@param R initial yaw rate in radians/second */
|
||||||
void SetRRadpsIC(double R) { r = R; }
|
void SetRRadpsIC(double R) { vPQR_body(eR) = R; }
|
||||||
|
|
||||||
/** Sets the initial wind velocity.
|
/** Sets the initial wind velocity.
|
||||||
@param wN Initial wind velocity in local north direction, feet/second
|
@param wN Initial wind velocity in local north direction, feet/second
|
||||||
|
@ -473,6 +474,14 @@ public:
|
||||||
@return Initial body axis Z wind velocity in feet/second */
|
@return Initial body axis Z wind velocity in feet/second */
|
||||||
double GetWindWFpsIC(void) const { return GetBodyWindFpsIC(eW); }
|
double GetWindWFpsIC(void) const { return GetBodyWindFpsIC(eW); }
|
||||||
|
|
||||||
|
/** Gets the initial wind velocity in the NED local frame
|
||||||
|
@return Initial wind velocity in NED frame in feet/second */
|
||||||
|
const FGColumnVector3 GetWindNEDFpsIC(void) const {
|
||||||
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
|
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
|
return _vt_NED - vUVW_NED;
|
||||||
|
}
|
||||||
|
|
||||||
/** Gets the initial wind velocity in local frame.
|
/** Gets the initial wind velocity in local frame.
|
||||||
@return Initial wind velocity toward north in feet/second */
|
@return Initial wind velocity toward north in feet/second */
|
||||||
double GetWindNFpsIC(void) const { return GetNEDWindFpsIC(eX); }
|
double GetWindNFpsIC(void) const { return GetNEDWindFpsIC(eX); }
|
||||||
|
@ -497,10 +506,18 @@ public:
|
||||||
@return Initial rate of climb in feet/second */
|
@return Initial rate of climb in feet/second */
|
||||||
double GetClimbRateFpsIC(void) const
|
double GetClimbRateFpsIC(void) const
|
||||||
{
|
{
|
||||||
|
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||||
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
FGColumnVector3 _vt_NED = Tb2l * Tw2b * FGColumnVector3(vt, 0., 0.);
|
||||||
return _vt_NED(eW);
|
return _vt_NED(eW);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the initial body velocity
|
||||||
|
@return Initial body velocity in feet/second. */
|
||||||
|
const FGColumnVector3 GetUVWFpsIC(void) const {
|
||||||
|
const FGMatrix33& Tl2b = orientation.GetT();
|
||||||
|
return Tl2b * vUVW_NED;
|
||||||
|
}
|
||||||
|
|
||||||
/** Gets the initial body axis X velocity.
|
/** Gets the initial body axis X velocity.
|
||||||
@return Initial body axis X velocity in feet/second. */
|
@return Initial body axis X velocity in feet/second. */
|
||||||
double GetUBodyFpsIC(void) const { return GetBodyVelFpsIC(eU); }
|
double GetUBodyFpsIC(void) const { return GetBodyVelFpsIC(eU); }
|
||||||
|
@ -525,17 +542,21 @@ public:
|
||||||
@return Initial local frame Z (Down) axis velocity in feet/second. */
|
@return Initial local frame Z (Down) axis velocity in feet/second. */
|
||||||
double GetVDownFpsIC(void) const { return vUVW_NED(eW); }
|
double GetVDownFpsIC(void) const { return vUVW_NED(eW); }
|
||||||
|
|
||||||
|
/** Gets the initial body rotation rate
|
||||||
|
@return Initial body rotation rate in radians/second */
|
||||||
|
const FGColumnVector3 GetPQRRadpsIC(void) const { return vPQR_body; }
|
||||||
|
|
||||||
/** Gets the initial body axis roll rate.
|
/** Gets the initial body axis roll rate.
|
||||||
@return Initial body axis roll rate in radians/second */
|
@return Initial body axis roll rate in radians/second */
|
||||||
double GetPRadpsIC() const { return p; }
|
double GetPRadpsIC() const { return vPQR_body(eP); }
|
||||||
|
|
||||||
/** Gets the initial body axis pitch rate.
|
/** Gets the initial body axis pitch rate.
|
||||||
@return Initial body axis pitch rate in radians/second */
|
@return Initial body axis pitch rate in radians/second */
|
||||||
double GetQRadpsIC() const { return q; }
|
double GetQRadpsIC() const { return vPQR_body(eQ); }
|
||||||
|
|
||||||
/** Gets the initial body axis yaw rate.
|
/** Gets the initial body axis yaw rate.
|
||||||
@return Initial body axis yaw rate in radians/second */
|
@return Initial body axis yaw rate in radians/second */
|
||||||
double GetRRadpsIC() const { return r; }
|
double GetRRadpsIC() const { return vPQR_body(eR); }
|
||||||
|
|
||||||
/** Sets the initial flight path angle.
|
/** Sets the initial flight path angle.
|
||||||
@param gamma Initial flight path angle in radians */
|
@param gamma Initial flight path angle in radians */
|
||||||
|
@ -546,21 +567,21 @@ public:
|
||||||
@param alpha Initial angle of attack in radians */
|
@param alpha Initial angle of attack in radians */
|
||||||
void SetAlphaRadIC(double alpha);
|
void SetAlphaRadIC(double alpha);
|
||||||
|
|
||||||
/** Sets the initial pitch angle.
|
|
||||||
@param theta Initial pitch angle in radians */
|
|
||||||
void SetThetaRadIC(double theta);
|
|
||||||
|
|
||||||
/** Sets the initial sideslip angle.
|
/** Sets the initial sideslip angle.
|
||||||
@param beta Initial angle of sideslip in radians. */
|
@param beta Initial angle of sideslip in radians. */
|
||||||
void SetBetaRadIC(double beta);
|
void SetBetaRadIC(double beta);
|
||||||
|
|
||||||
/** Sets the initial roll angle.
|
/** Sets the initial roll angle.
|
||||||
@param phi Initial roll angle in radians */
|
@param phi Initial roll angle in radians */
|
||||||
void SetPhiRadIC(double phi);
|
void SetPhiRadIC(double phi) { SetEulerAngleRadIC(ePhi, phi); }
|
||||||
|
|
||||||
|
/** Sets the initial pitch angle.
|
||||||
|
@param theta Initial pitch angle in radians */
|
||||||
|
void SetThetaRadIC(double theta) { SetEulerAngleRadIC(eTht, theta); }
|
||||||
|
|
||||||
/** Sets the initial heading angle.
|
/** Sets the initial heading angle.
|
||||||
@param psi Initial heading angle in radians */
|
@param psi Initial heading angle in radians */
|
||||||
void SetPsiRadIC(double psi);
|
void SetPsiRadIC(double psi) { SetEulerAngleRadIC(ePsi, psi); }
|
||||||
|
|
||||||
/** Sets the initial latitude.
|
/** Sets the initial latitude.
|
||||||
@param lat Initial latitude in radians */
|
@param lat Initial latitude in radians */
|
||||||
|
@ -588,9 +609,9 @@ public:
|
||||||
@return Initial sideslip angle in radians */
|
@return Initial sideslip angle in radians */
|
||||||
double GetBetaRadIC(void) const { return beta; }
|
double GetBetaRadIC(void) const { return beta; }
|
||||||
|
|
||||||
/** Gets the initial roll angle.
|
/** Gets the initial position
|
||||||
@return Initial roll angle in radians */
|
@return Initial location */
|
||||||
double GetPhiRadIC(void) const { return phi; }
|
const FGLocation& GetPosition(void) const { return position; }
|
||||||
|
|
||||||
/** Gets the initial latitude.
|
/** Gets the initial latitude.
|
||||||
@return Initial latitude in radians */
|
@return Initial latitude in radians */
|
||||||
|
@ -600,13 +621,21 @@ public:
|
||||||
@return Initial longitude in radians */
|
@return Initial longitude in radians */
|
||||||
double GetLongitudeRadIC(void) const { return position.GetLongitude(); }
|
double GetLongitudeRadIC(void) const { return position.GetLongitude(); }
|
||||||
|
|
||||||
|
/** Gets the initial orientation
|
||||||
|
@return Initial orientation */
|
||||||
|
const FGQuaternion& GetOrientation(void) const { return orientation; }
|
||||||
|
|
||||||
|
/** Gets the initial roll angle.
|
||||||
|
@return Initial roll angle in radians */
|
||||||
|
double GetPhiRadIC(void) const { return orientation.GetEuler(ePhi); }
|
||||||
|
|
||||||
/** Gets the initial pitch angle.
|
/** Gets the initial pitch angle.
|
||||||
@return Initial pitch angle in radians */
|
@return Initial pitch angle in radians */
|
||||||
double GetThetaRadIC(void) const { return theta; }
|
double GetThetaRadIC(void) const { return orientation.GetEuler(eTht); }
|
||||||
|
|
||||||
/** Gets the initial heading angle.
|
/** Gets the initial heading angle.
|
||||||
@return Initial heading angle in radians */
|
@return Initial heading angle in radians */
|
||||||
double GetPsiRadIC(void) const { return psi; }
|
double GetPsiRadIC(void) const { return orientation.GetEuler(ePsi); }
|
||||||
|
|
||||||
/** Gets the initial speedset.
|
/** Gets the initial speedset.
|
||||||
@return Initial speedset */
|
@return Initial speedset */
|
||||||
|
@ -632,21 +661,22 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FGColumnVector3 vUVW_NED;
|
FGColumnVector3 vUVW_NED;
|
||||||
|
FGColumnVector3 vPQR_body;
|
||||||
FGLocation position;
|
FGLocation position;
|
||||||
|
FGQuaternion orientation;
|
||||||
double vt;
|
double vt;
|
||||||
double p,q,r;
|
|
||||||
double sea_level_radius;
|
double sea_level_radius;
|
||||||
double terrain_elevation;
|
double terrain_elevation;
|
||||||
double targetNlfIC;
|
double targetNlfIC;
|
||||||
|
|
||||||
FGMatrix33 Tw2b, Tb2w;
|
FGMatrix33 Tw2b, Tb2w;
|
||||||
FGMatrix33 Tl2b, Tb2l;
|
double alpha, beta;
|
||||||
double alpha, beta, theta, phi, psi;
|
|
||||||
|
|
||||||
speedset lastSpeedSet;
|
speedset lastSpeedSet;
|
||||||
|
|
||||||
FGFDMExec *fdmex;
|
FGFDMExec *fdmex;
|
||||||
FGPropertyManager *PropertyManager;
|
FGPropertyManager *PropertyManager;
|
||||||
|
FGAtmosphere* Atmosphere;
|
||||||
|
|
||||||
bool Load_v1(void);
|
bool Load_v1(void);
|
||||||
bool Load_v2(void);
|
bool Load_v2(void);
|
||||||
|
@ -654,13 +684,12 @@ private:
|
||||||
bool Constructing;
|
bool Constructing;
|
||||||
|
|
||||||
void InitializeIC(void);
|
void InitializeIC(void);
|
||||||
|
void SetEulerAngleRadIC(int idx, double angle);
|
||||||
void SetBodyVelFpsIC(int idx, double vel);
|
void SetBodyVelFpsIC(int idx, double vel);
|
||||||
void SetNEDVelFpsIC(int idx, double vel);
|
void SetNEDVelFpsIC(int idx, double vel);
|
||||||
double GetBodyWindFpsIC(int idx) const;
|
double GetBodyWindFpsIC(int idx) const;
|
||||||
double GetNEDWindFpsIC(int idx) const;
|
double GetNEDWindFpsIC(int idx) const;
|
||||||
double GetBodyVelFpsIC(int idx) const;
|
double GetBodyVelFpsIC(int idx) const;
|
||||||
double getMachFromVcas(double vcas);
|
|
||||||
double calcVcas(double Mach) const;
|
|
||||||
void calcAeroAngles(const FGColumnVector3& _vt_BODY);
|
void calcAeroAngles(const FGColumnVector3& _vt_BODY);
|
||||||
void calcThetaBeta(double alfa, const FGColumnVector3& _vt_NED);
|
void calcThetaBeta(double alfa, const FGColumnVector3& _vt_NED);
|
||||||
void bind(void);
|
void bind(void);
|
||||||
|
|
|
@ -39,34 +39,22 @@ namespace JSBSim {
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
FGGroundCallback::FGGroundCallback()
|
FGDefaultGroundCallback::FGDefaultGroundCallback(double referenceRadius)
|
||||||
{
|
{
|
||||||
mReferenceRadius = 20925650.0; // Sea level radius
|
mSeaLevelRadius = referenceRadius; // Sea level radius
|
||||||
|
mTerrainLevelRadius = mSeaLevelRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
FGGroundCallback::FGGroundCallback(double ReferenceRadius)
|
double FGDefaultGroundCallback::GetAltitude(const FGLocation& loc) const
|
||||||
{
|
{
|
||||||
mReferenceRadius = ReferenceRadius;
|
return loc.GetRadius() - mSeaLevelRadius;
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
FGGroundCallback::~FGGroundCallback()
|
double FGDefaultGroundCallback::GetAGLevel(double t, const FGLocation& loc,
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
double FGGroundCallback::GetAltitude(const FGLocation& loc) const
|
|
||||||
{
|
|
||||||
return loc.GetRadius() - mReferenceRadius;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
double FGGroundCallback::GetAGLevel(double t, const FGLocation& loc,
|
|
||||||
FGLocation& contact, FGColumnVector3& normal,
|
FGLocation& contact, FGColumnVector3& normal,
|
||||||
FGColumnVector3& vel, FGColumnVector3& angularVel) const
|
FGColumnVector3& vel, FGColumnVector3& angularVel) const
|
||||||
{
|
{
|
||||||
|
@ -75,9 +63,11 @@ double FGGroundCallback::GetAGLevel(double t, const FGLocation& loc,
|
||||||
normal = FGColumnVector3(loc).Normalize();
|
normal = FGColumnVector3(loc).Normalize();
|
||||||
double loc_radius = loc.GetRadius(); // Get the radius of the given location
|
double loc_radius = loc.GetRadius(); // Get the radius of the given location
|
||||||
// (e.g. the CG)
|
// (e.g. the CG)
|
||||||
double agl = loc_radius - mReferenceRadius;
|
double agl = loc_radius - mTerrainLevelRadius;
|
||||||
contact = (mReferenceRadius/loc_radius)*FGColumnVector3(loc);
|
contact = (mTerrainLevelRadius/loc_radius)*FGColumnVector3(loc);
|
||||||
return agl;
|
return agl;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
} // namespace JSBSim
|
||||||
|
|
|
@ -45,7 +45,7 @@ INCLUDES
|
||||||
DEFINITIONS
|
DEFINITIONS
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
#define ID_GROUNDCALLBACK "$Id: FGGroundCallback.h,v 1.9 2010/10/07 03:45:40 jberndt Exp $"
|
#define ID_GROUNDCALLBACK "$Id: FGGroundCallback.h,v 1.12 2011/10/14 22:46:49 bcoconni Exp $"
|
||||||
|
|
||||||
namespace JSBSim {
|
namespace JSBSim {
|
||||||
|
|
||||||
|
@ -53,13 +53,13 @@ namespace JSBSim {
|
||||||
CLASS DOCUMENTATION
|
CLASS DOCUMENTATION
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
/** This class provides callback slots to get ground specific data like
|
/** This class provides callback slots to get ground specific data.
|
||||||
ground elevation and such.
|
|
||||||
There is a default implementation, which returns values for a
|
The default implementation returns values for a
|
||||||
ball formed earth.
|
ball formed earth with an adjustable terrain elevation.
|
||||||
|
|
||||||
@author Mathias Froehlich
|
@author Mathias Froehlich
|
||||||
@version $Id: FGGroundCallback.h,v 1.9 2010/10/07 03:45:40 jberndt Exp $
|
@version $Id: FGGroundCallback.h,v 1.12 2011/10/14 22:46:49 bcoconni Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -69,31 +69,88 @@ CLASS DECLARATION
|
||||||
class FGGroundCallback : public FGJSBBase
|
class FGGroundCallback : public FGJSBBase
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/** Default constructor.
|
|
||||||
Within this constructor, the reference radius is set to the WGS84 equatorial
|
|
||||||
radius. This constructor should really not be called, instead relying on the
|
|
||||||
constructor that takes reference radius as an argument. */
|
|
||||||
FGGroundCallback();
|
|
||||||
|
|
||||||
/** Constructor
|
FGGroundCallback() {}
|
||||||
This constructor accepts the reference radius in feet. This is the preferred
|
virtual ~FGGroundCallback() {}
|
||||||
constructor. */
|
|
||||||
FGGroundCallback(double ReferenceRadius);
|
/** Compute the altitude above sealevel
|
||||||
virtual ~FGGroundCallback();
|
@param l location
|
||||||
|
*/
|
||||||
|
virtual double GetAltitude(const FGLocation& l) const = 0;
|
||||||
|
|
||||||
|
/** Compute the altitude above ground.
|
||||||
|
The altitude depends on time t and location l.
|
||||||
|
@param t simulation time
|
||||||
|
@param l location
|
||||||
|
@param contact Contact point location below the location l
|
||||||
|
@param normal Normal vector at the contact point
|
||||||
|
@param v Linear velocity at the contact point
|
||||||
|
@param w Angular velocity at the contact point
|
||||||
|
@return altitude above ground
|
||||||
|
*/
|
||||||
|
virtual double GetAGLevel(double t, const FGLocation& location,
|
||||||
|
FGLocation& contact,
|
||||||
|
FGColumnVector3& normal, FGColumnVector3& v,
|
||||||
|
FGColumnVector3& w) const = 0;
|
||||||
|
|
||||||
|
/** Compute the local terrain radius
|
||||||
|
@param t simulation time
|
||||||
|
@param location location
|
||||||
|
*/
|
||||||
|
virtual double GetTerrainGeoCentRadius(double t, const FGLocation& location) const = 0;
|
||||||
|
|
||||||
|
/** Return the sea level radius
|
||||||
|
@param t simulation time
|
||||||
|
@param location location
|
||||||
|
*/
|
||||||
|
virtual double GetSeaLevelRadius(const FGLocation& location) const = 0;
|
||||||
|
|
||||||
|
/** Set the local terrain radius.
|
||||||
|
Only needs to be implemented if JSBSim should be allowed
|
||||||
|
to modify the local terrain radius (see the default implementation)
|
||||||
|
*/
|
||||||
|
virtual void SetTerrainGeoCentRadius(double radius) { }
|
||||||
|
|
||||||
|
/** Set the sea level radius.
|
||||||
|
Only needs to be implemented if JSBSim should be allowed
|
||||||
|
to modify the sea level radius (see the default implementation)
|
||||||
|
*/
|
||||||
|
virtual void SetSeaLevelRadius(double radius) { }
|
||||||
|
|
||||||
/** Compute the altitude above sealevel. */
|
|
||||||
virtual double GetAltitude(const FGLocation& l) const;
|
|
||||||
/** Compute the altitude above ground. Defaults to sealevel altitude. */
|
|
||||||
virtual double GetAGLevel(double t, const FGLocation& l, FGLocation& cont,
|
|
||||||
FGColumnVector3& n, FGColumnVector3& v,
|
|
||||||
FGColumnVector3& w) const;
|
|
||||||
virtual void SetTerrainGeoCentRadius(double radius) {mReferenceRadius = radius;}
|
|
||||||
virtual double GetTerrainGeoCentRadius(void) const {return mReferenceRadius;}
|
|
||||||
private:
|
|
||||||
/// Reference radius.
|
|
||||||
double mReferenceRadius;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
// The default sphere earth implementation:
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
class FGDefaultGroundCallback : public FGGroundCallback
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
|
||||||
|
FGDefaultGroundCallback(double referenceRadius = 20925650.0);
|
||||||
|
|
||||||
|
double GetAltitude(const FGLocation& l) const;
|
||||||
|
|
||||||
|
double GetAGLevel(double t, const FGLocation& location,
|
||||||
|
FGLocation& contact,
|
||||||
|
FGColumnVector3& normal, FGColumnVector3& v,
|
||||||
|
FGColumnVector3& w) const;
|
||||||
|
|
||||||
|
void SetTerrainGeoCentRadius(double radius) { mTerrainLevelRadius = radius;}
|
||||||
|
double GetTerrainGeoCentRadius(double t, const FGLocation& location) const
|
||||||
|
{ return mTerrainLevelRadius; }
|
||||||
|
|
||||||
|
void SetSeaLevelRadius(double radius) { mSeaLevelRadius = radius; }
|
||||||
|
double GetSeaLevelRadius(const FGLocation& location) const
|
||||||
|
{return mSeaLevelRadius; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
double mSeaLevelRadius;
|
||||||
|
double mTerrainLevelRadius;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -45,7 +45,7 @@ INCLUDES
|
||||||
|
|
||||||
namespace JSBSim {
|
namespace JSBSim {
|
||||||
|
|
||||||
static const char *IdSrc = "$Id: FGLocation.cpp,v 1.23 2010/09/22 11:34:09 jberndt Exp $";
|
static const char *IdSrc = "$Id: FGLocation.cpp,v 1.25 2011/10/16 00:19:56 bcoconni Exp $";
|
||||||
static const char *IdHdr = ID_LOCATION;
|
static const char *IdHdr = ID_LOCATION;
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
@ -137,6 +137,7 @@ FGLocation::FGLocation(const FGLocation& l)
|
||||||
e = l.e;
|
e = l.e;
|
||||||
eps2 = l.eps2;
|
eps2 = l.eps2;
|
||||||
f = l.f;
|
f = l.f;
|
||||||
|
epa = l.epa;
|
||||||
|
|
||||||
/*ag
|
/*ag
|
||||||
* if the cache is not valid, all of the following values are unset.
|
* if the cache is not valid, all of the following values are unset.
|
||||||
|
@ -152,6 +153,10 @@ FGLocation::FGLocation(const FGLocation& l)
|
||||||
|
|
||||||
mTl2ec = l.mTl2ec;
|
mTl2ec = l.mTl2ec;
|
||||||
mTec2l = l.mTec2l;
|
mTec2l = l.mTec2l;
|
||||||
|
mTi2ec = l.mTi2ec;
|
||||||
|
mTec2i = l.mTec2i;
|
||||||
|
mTi2l = l.mTi2l;
|
||||||
|
mTl2i = l.mTl2i;
|
||||||
|
|
||||||
initial_longitude = l.initial_longitude;
|
initial_longitude = l.initial_longitude;
|
||||||
mGeodLat = l.mGeodLat;
|
mGeodLat = l.mGeodLat;
|
||||||
|
@ -173,6 +178,7 @@ const FGLocation& FGLocation::operator=(const FGLocation& l)
|
||||||
e = l.e;
|
e = l.e;
|
||||||
eps2 = l.eps2;
|
eps2 = l.eps2;
|
||||||
f = l.f;
|
f = l.f;
|
||||||
|
epa = l.epa;
|
||||||
|
|
||||||
//ag See comment in constructor above
|
//ag See comment in constructor above
|
||||||
if (!mCacheValid) return *this;
|
if (!mCacheValid) return *this;
|
||||||
|
@ -183,6 +189,10 @@ const FGLocation& FGLocation::operator=(const FGLocation& l)
|
||||||
|
|
||||||
mTl2ec = l.mTl2ec;
|
mTl2ec = l.mTl2ec;
|
||||||
mTec2l = l.mTec2l;
|
mTec2l = l.mTec2l;
|
||||||
|
mTi2ec = l.mTi2ec;
|
||||||
|
mTec2i = l.mTec2i;
|
||||||
|
mTi2l = l.mTi2l;
|
||||||
|
mTl2i = l.mTl2i;
|
||||||
|
|
||||||
initial_longitude = l.initial_longitude;
|
initial_longitude = l.initial_longitude;
|
||||||
mGeodLat = l.mGeodLat;
|
mGeodLat = l.mGeodLat;
|
||||||
|
|
|
@ -48,7 +48,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
namespace JSBSim {
|
||||||
|
|
||||||
static const char *IdSrc = "$Id: FGAerodynamics.cpp,v 1.41 2011/08/04 12:46:32 jberndt Exp $";
|
static const char *IdSrc = "$Id: FGAerodynamics.cpp,v 1.44 2011/10/23 14:23:13 jentron Exp $";
|
||||||
static const char *IdHdr = ID_AERODYNAMICS;
|
static const char *IdHdr = ID_AERODYNAMICS;
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -208,13 +208,15 @@ bool FGAerodynamics::Run(bool Holding)
|
||||||
if ( fabs(vFw(eDrag)) > 0.0) lod = fabs( vFw(eLift) / vFw(eDrag) );
|
if ( fabs(vFw(eDrag)) > 0.0) lod = fabs( vFw(eLift) / vFw(eDrag) );
|
||||||
|
|
||||||
// Calculate aerodynamic reference point shift, if any. The shift
|
// Calculate aerodynamic reference point shift, if any. The shift
|
||||||
// takes place in the body axis. That is, if the shift is negative,
|
// takes place in the structual axis. That is, if the shift is positive,
|
||||||
// it is towards the back (tail) of the vehicle. The AeroRPShift
|
// it is towards the back (tail) of the vehicle. The AeroRPShift
|
||||||
// function should be non-dimensionalized by the wing chord. The
|
// function should be non-dimensionalized by the wing chord. The
|
||||||
// calculated vDeltaRP will be in feet.
|
// calculated vDeltaRP will be in feet.
|
||||||
if (AeroRPShift) vDeltaRP(eX) = AeroRPShift->GetValue()*in.Wingchord;
|
if (AeroRPShift) vDeltaRP(eX) = AeroRPShift->GetValue()*in.Wingchord;
|
||||||
|
|
||||||
vDXYZcg = in.RPBody + vDeltaRP;
|
vDXYZcg(eX) = in.RPBody(eX) - vDeltaRP(eX); // vDeltaRP is given in the structural frame
|
||||||
|
vDXYZcg(eY) = in.RPBody(eY) + vDeltaRP(eY);
|
||||||
|
vDXYZcg(eZ) = in.RPBody(eZ) - vDeltaRP(eZ);
|
||||||
|
|
||||||
vMoments = vDXYZcg*vForces; // M = r X F
|
vMoments = vDXYZcg*vForces; // M = r X F
|
||||||
|
|
||||||
|
@ -382,7 +384,7 @@ string FGAerodynamics::GetAeroFunctionValues(const string& delimeter) const
|
||||||
for (unsigned int axis = 0; axis < 6; axis++) {
|
for (unsigned int axis = 0; axis < 6; axis++) {
|
||||||
for (unsigned int sd = 0; sd < AeroFunctions[axis].size(); sd++) {
|
for (unsigned int sd = 0; sd < AeroFunctions[axis].size(); sd++) {
|
||||||
if (buf.tellp() > 0) buf << delimeter;
|
if (buf.tellp() > 0) buf << delimeter;
|
||||||
buf << setw(9) << AeroFunctions[axis][sd]->GetValue();
|
buf << AeroFunctions[axis][sd]->GetValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -77,7 +77,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
namespace JSBSim {
|
||||||
|
|
||||||
static const char *IdSrc = "$Id: FGOutput.cpp,v 1.62 2011/09/25 15:38:30 bcoconni Exp $";
|
static const char *IdSrc = "$Id: FGOutput.cpp,v 1.63 2011/10/10 02:33:34 jentron Exp $";
|
||||||
static const char *IdHdr = ID_OUTPUT;
|
static const char *IdHdr = ID_OUTPUT;
|
||||||
|
|
||||||
// (stolen from FGFS native_fdm.cxx)
|
// (stolen from FGFS native_fdm.cxx)
|
||||||
|
@ -216,7 +216,7 @@ void FGOutput::SetType(const string& type)
|
||||||
{
|
{
|
||||||
if (type == "CSV") {
|
if (type == "CSV") {
|
||||||
Type = otCSV;
|
Type = otCSV;
|
||||||
delimeter = ", ";
|
delimeter = ",";
|
||||||
} else if (type == "TABULAR") {
|
} else if (type == "TABULAR") {
|
||||||
Type = otTab;
|
Type = otTab;
|
||||||
delimeter = "\t";
|
delimeter = "\t";
|
||||||
|
|
|
@ -68,7 +68,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
namespace JSBSim {
|
||||||
|
|
||||||
static const char *IdSrc = "$Id: FGPropagate.cpp,v 1.96 2011/09/17 15:36:35 bcoconni Exp $";
|
static const char *IdSrc = "$Id: FGPropagate.cpp,v 1.98 2011/10/22 15:11:24 bcoconni Exp $";
|
||||||
static const char *IdHdr = ID_PROPAGATE;
|
static const char *IdHdr = ID_PROPAGATE;
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -77,8 +77,6 @@ CLASS IMPLEMENTATION
|
||||||
|
|
||||||
FGPropagate::FGPropagate(FGFDMExec* fdmex)
|
FGPropagate::FGPropagate(FGFDMExec* fdmex)
|
||||||
: FGModel(fdmex),
|
: FGModel(fdmex),
|
||||||
LocalTerrainRadius(0),
|
|
||||||
SeaLevelRadius(0),
|
|
||||||
VehicleRadius(0)
|
VehicleRadius(0)
|
||||||
{
|
{
|
||||||
Debug(0);
|
Debug(0);
|
||||||
|
@ -115,10 +113,9 @@ FGPropagate::~FGPropagate(void)
|
||||||
bool FGPropagate::InitModel(void)
|
bool FGPropagate::InitModel(void)
|
||||||
{
|
{
|
||||||
// For initialization ONLY:
|
// For initialization ONLY:
|
||||||
SeaLevelRadius = LocalTerrainRadius = in.RefRadius;
|
VState.vLocation.SetRadius( FDMExec->GetGroundCallback()->
|
||||||
FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(LocalTerrainRadius);
|
GetTerrainGeoCentRadius(0.0,VState.vLocation) + 4.0 );
|
||||||
|
|
||||||
VState.vLocation.SetRadius( LocalTerrainRadius + 4.0 );
|
|
||||||
VState.vLocation.SetEllipse(in.SemiMajor, in.SemiMinor);
|
VState.vLocation.SetEllipse(in.SemiMajor, in.SemiMinor);
|
||||||
|
|
||||||
vInertialVelocity.InitMatrix();
|
vInertialVelocity.InitMatrix();
|
||||||
|
@ -145,11 +142,7 @@ void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
|
||||||
// Initialize the State Vector elements and the transformation matrices
|
// Initialize the State Vector elements and the transformation matrices
|
||||||
|
|
||||||
// Set the position lat/lon/radius
|
// Set the position lat/lon/radius
|
||||||
VState.vLocation.SetPosition( FGIC->GetLongitudeRadIC(),
|
VState.vLocation = FGIC->GetPosition();
|
||||||
FGIC->GetLatitudeRadIC(),
|
|
||||||
FGIC->GetAltitudeASLFtIC() + SeaLevelRadius);
|
|
||||||
|
|
||||||
VState.vLocation.SetEarthPositionAngle(0.0);
|
|
||||||
|
|
||||||
Ti2ec = VState.vLocation.GetTi2ec(); // ECI to ECEF transform
|
Ti2ec = VState.vLocation.GetTi2ec(); // ECI to ECEF transform
|
||||||
Tec2i = Ti2ec.Transposed(); // ECEF to ECI frame transform
|
Tec2i = Ti2ec.Transposed(); // ECEF to ECI frame transform
|
||||||
|
@ -161,31 +154,24 @@ void FGPropagate::SetInitialState(const FGInitialCondition *FGIC)
|
||||||
// Set the orientation from the euler angles (is normalized within the
|
// Set the orientation from the euler angles (is normalized within the
|
||||||
// constructor). The Euler angles represent the orientation of the body
|
// constructor). The Euler angles represent the orientation of the body
|
||||||
// frame relative to the local frame.
|
// frame relative to the local frame.
|
||||||
VState.qAttitudeLocal = FGQuaternion( FGIC->GetPhiRadIC(),
|
VState.qAttitudeLocal = FGIC->GetOrientation();
|
||||||
FGIC->GetThetaRadIC(),
|
|
||||||
FGIC->GetPsiRadIC() );
|
|
||||||
|
|
||||||
VState.qAttitudeECI = Ti2l.GetQuaternion()*VState.qAttitudeLocal;
|
VState.qAttitudeECI = Ti2l.GetQuaternion()*VState.qAttitudeLocal;
|
||||||
UpdateBodyMatrices();
|
UpdateBodyMatrices();
|
||||||
|
|
||||||
// Set the velocities in the instantaneus body frame
|
// Set the velocities in the instantaneus body frame
|
||||||
VState.vUVW = FGColumnVector3( FGIC->GetUBodyFpsIC(),
|
VState.vUVW = FGIC->GetUVWFpsIC();
|
||||||
FGIC->GetVBodyFpsIC(),
|
|
||||||
FGIC->GetWBodyFpsIC() );
|
|
||||||
|
|
||||||
// Compute the local frame ECEF velocity
|
// Compute the local frame ECEF velocity
|
||||||
vVel = Tb2l * VState.vUVW;
|
vVel = Tb2l * VState.vUVW;
|
||||||
|
|
||||||
// Recompute the LocalTerrainRadius.
|
// Compute local terrain velocity
|
||||||
RecomputeLocalTerrainRadius();
|
RecomputeLocalTerrainVelocity();
|
||||||
|
|
||||||
VehicleRadius = GetRadius();
|
VehicleRadius = GetRadius();
|
||||||
|
|
||||||
// Set the angular velocities of the body frame relative to the ECEF frame,
|
// Set the angular velocities of the body frame relative to the ECEF frame,
|
||||||
// expressed in the body frame.
|
// expressed in the body frame.
|
||||||
VState.vPQR = FGColumnVector3( FGIC->GetPRadpsIC(),
|
VState.vPQR = FGIC->GetPQRRadpsIC();
|
||||||
FGIC->GetQRadpsIC(),
|
|
||||||
FGIC->GetRRadpsIC() );
|
|
||||||
|
|
||||||
VState.vPQRi = VState.vPQR + Ti2b * in.vOmegaPlanet;
|
VState.vPQRi = VState.vPQR + Ti2b * in.vOmegaPlanet;
|
||||||
|
|
||||||
|
@ -269,8 +255,7 @@ bool FGPropagate::Run(bool Holding)
|
||||||
CalculateUVW();
|
CalculateUVW();
|
||||||
|
|
||||||
// Set auxilliary state variables
|
// Set auxilliary state variables
|
||||||
RecomputeLocalTerrainRadius();
|
RecomputeLocalTerrainVelocity();
|
||||||
|
|
||||||
VehicleRadius = GetRadius(); // Calculate current aircraft radius from center of planet
|
VehicleRadius = GetRadius(); // Calculate current aircraft radius from center of planet
|
||||||
|
|
||||||
VState.vPQR = VState.vPQRi - Ti2b * in.vOmegaPlanet;
|
VState.vPQR = VState.vPQRi - Ti2b * in.vOmegaPlanet;
|
||||||
|
@ -410,39 +395,79 @@ void FGPropagate::SetInertialRates(FGColumnVector3 vRates) {
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
void FGPropagate::RecomputeLocalTerrainRadius(void)
|
void FGPropagate::RecomputeLocalTerrainVelocity()
|
||||||
{
|
{
|
||||||
FGLocation contactloc;
|
FGLocation contact;
|
||||||
FGColumnVector3 dummy;
|
FGColumnVector3 normal;
|
||||||
double t = FDMExec->GetSimTime();
|
FDMExec->GetGroundCallback()->GetAGLevel(FDMExec->GetSimTime(),
|
||||||
|
VState.vLocation,
|
||||||
// Get the LocalTerrain radius.
|
contact, normal,
|
||||||
FDMExec->GetGroundCallback()->GetAGLevel(t, VState.vLocation, contactloc,
|
LocalTerrainVelocity,
|
||||||
dummy, LocalTerrainVelocity, LocalTerrainAngularVelocity);
|
LocalTerrainAngularVelocity);
|
||||||
LocalTerrainRadius = contactloc.GetRadius();
|
|
||||||
FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(LocalTerrainRadius);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
void FGPropagate::SetTerrainElevation(double terrainElev)
|
void FGPropagate::SetTerrainElevation(double terrainElev)
|
||||||
{
|
{
|
||||||
LocalTerrainRadius = terrainElev + SeaLevelRadius;
|
double radius = terrainElev + FDMExec->GetGroundCallback()->GetSeaLevelRadius(VState.vLocation);
|
||||||
FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(LocalTerrainRadius);
|
FDMExec->GetGroundCallback()->SetTerrainGeoCentRadius(radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGPropagate::SetSeaLevelRadius(double tt)
|
||||||
|
{
|
||||||
|
FDMExec->GetGroundCallback()->SetSeaLevelRadius(tt);
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
double FGPropagate::GetLocalTerrainRadius(void) const
|
||||||
|
{
|
||||||
|
return FDMExec->GetGroundCallback()->GetTerrainGeoCentRadius(FDMExec->GetSimTime(),
|
||||||
|
VState.vLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
double FGPropagate::GetTerrainElevation(void) const
|
double FGPropagate::GetTerrainElevation(void) const
|
||||||
{
|
{
|
||||||
return FDMExec->GetGroundCallback()->GetTerrainGeoCentRadius()-SeaLevelRadius;
|
return GetLocalTerrainRadius()
|
||||||
|
- FDMExec->GetGroundCallback()->GetSeaLevelRadius(VState.vLocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
double FGPropagate::GetDistanceAGL(void) const
|
double FGPropagate::GetDistanceAGL(void) const
|
||||||
{
|
{
|
||||||
return VState.vLocation.GetRadius() - LocalTerrainRadius;
|
FGColumnVector3 dummy;
|
||||||
|
FGLocation dummyloc;
|
||||||
|
double t = FDMExec->GetSimTime();
|
||||||
|
return FDMExec->GetGroundCallback()->GetAGLevel(t, VState.vLocation, dummyloc,
|
||||||
|
dummy, dummy, dummy);
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGPropagate::SetAltitudeASL(double altASL)
|
||||||
|
{
|
||||||
|
SetRadius(altASL + FDMExec->GetGroundCallback()->GetSeaLevelRadius(VState.vLocation));
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
double FGPropagate::GetAltitudeASL(void) const
|
||||||
|
{
|
||||||
|
return VState.vLocation.GetRadius()
|
||||||
|
- FDMExec->GetGroundCallback()->GetSeaLevelRadius(VState.vLocation);
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
void FGPropagate::SetDistanceAGL(double tt)
|
||||||
|
{
|
||||||
|
SetAltitudeASL(tt + GetTerrainElevation());
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -456,7 +481,7 @@ void FGPropagate::SetVState(const VehicleState& vstate)
|
||||||
Tec2i = Ti2ec.Transposed();
|
Tec2i = Ti2ec.Transposed();
|
||||||
UpdateLocationMatrices();
|
UpdateLocationMatrices();
|
||||||
SetInertialOrientation(vstate.qAttitudeECI);
|
SetInertialOrientation(vstate.qAttitudeECI);
|
||||||
RecomputeLocalTerrainRadius();
|
RecomputeLocalTerrainVelocity();
|
||||||
VehicleRadius = GetRadius();
|
VehicleRadius = GetRadius();
|
||||||
VState.vUVW = vstate.vUVW;
|
VState.vUVW = vstate.vUVW;
|
||||||
vVel = Tb2l * VState.vUVW;
|
vVel = Tb2l * VState.vUVW;
|
||||||
|
@ -469,7 +494,7 @@ void FGPropagate::SetVState(const VehicleState& vstate)
|
||||||
|
|
||||||
void FGPropagate::UpdateVehicleState(void)
|
void FGPropagate::UpdateVehicleState(void)
|
||||||
{
|
{
|
||||||
RecomputeLocalTerrainRadius();
|
RecomputeLocalTerrainVelocity();
|
||||||
VehicleRadius = GetRadius();
|
VehicleRadius = GetRadius();
|
||||||
VState.vInertialPosition = Tec2i * VState.vLocation;
|
VState.vInertialPosition = Tec2i * VState.vLocation;
|
||||||
UpdateLocationMatrices();
|
UpdateLocationMatrices();
|
||||||
|
|
|
@ -49,7 +49,7 @@ INCLUDES
|
||||||
DEFINITIONS
|
DEFINITIONS
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
#define ID_PROPAGATE "$Id: FGPropagate.h,v 1.63 2011/08/21 15:35:39 bcoconni Exp $"
|
#define ID_PROPAGATE "$Id: FGPropagate.h,v 1.64 2011/10/14 22:46:49 bcoconni Exp $"
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
FORWARD DECLARATIONS
|
FORWARD DECLARATIONS
|
||||||
|
@ -93,7 +93,7 @@ CLASS DOCUMENTATION
|
||||||
@endcode
|
@endcode
|
||||||
|
|
||||||
@author Jon S. Berndt, Mathias Froehlich, Bertrand Coconnier
|
@author Jon S. Berndt, Mathias Froehlich, Bertrand Coconnier
|
||||||
@version $Id: FGPropagate.h,v 1.63 2011/08/21 15:35:39 bcoconni Exp $
|
@version $Id: FGPropagate.h,v 1.64 2011/10/14 22:46:49 bcoconni Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -293,7 +293,7 @@ public:
|
||||||
units ft
|
units ft
|
||||||
@return The current altitude above sea level in feet.
|
@return The current altitude above sea level in feet.
|
||||||
*/
|
*/
|
||||||
double GetAltitudeASL(void) const { return VState.vLocation.GetRadius() - SeaLevelRadius; }
|
double GetAltitudeASL(void) const;
|
||||||
|
|
||||||
/** Returns the current altitude above sea level.
|
/** Returns the current altitude above sea level.
|
||||||
This function returns the altitude above sea level.
|
This function returns the altitude above sea level.
|
||||||
|
@ -377,7 +377,7 @@ public:
|
||||||
units feet
|
units feet
|
||||||
@return distance of the local terrain from the center of the earth.
|
@return distance of the local terrain from the center of the earth.
|
||||||
*/
|
*/
|
||||||
double GetLocalTerrainRadius(void) const { return LocalTerrainRadius; }
|
double GetLocalTerrainRadius(void) const;
|
||||||
|
|
||||||
double GetEarthPositionAngle(void) const { return VState.vLocation.GetEPA(); }
|
double GetEarthPositionAngle(void) const { return VState.vLocation.GetEPA(); }
|
||||||
|
|
||||||
|
@ -385,6 +385,8 @@ public:
|
||||||
|
|
||||||
const FGColumnVector3& GetTerrainVelocity(void) const { return LocalTerrainVelocity; }
|
const FGColumnVector3& GetTerrainVelocity(void) const { return LocalTerrainVelocity; }
|
||||||
const FGColumnVector3& GetTerrainAngularVelocity(void) const { return LocalTerrainAngularVelocity; }
|
const FGColumnVector3& GetTerrainAngularVelocity(void) const { return LocalTerrainAngularVelocity; }
|
||||||
|
void RecomputeLocalTerrainVelocity();
|
||||||
|
|
||||||
double GetTerrainElevation(void) const;
|
double GetTerrainElevation(void) const;
|
||||||
double GetDistanceAGL(void) const;
|
double GetDistanceAGL(void) const;
|
||||||
double GetRadius(void) const {
|
double GetRadius(void) const {
|
||||||
|
@ -502,11 +504,14 @@ public:
|
||||||
VehicleRadius = r;
|
VehicleRadius = r;
|
||||||
VState.vInertialPosition = Tec2i * VState.vLocation;
|
VState.vInertialPosition = Tec2i * VState.vLocation;
|
||||||
}
|
}
|
||||||
void SetAltitudeASL(double altASL) { SetRadius(altASL + SeaLevelRadius); }
|
|
||||||
void SetAltitudeASLmeters(double altASL) { SetRadius(altASL/fttom + SeaLevelRadius); }
|
void SetAltitudeASL(double altASL);
|
||||||
void SetSeaLevelRadius(double tt) { SeaLevelRadius = tt; }
|
void SetAltitudeASLmeters(double altASL) { SetAltitudeASL(altASL/fttom); }
|
||||||
|
|
||||||
|
void SetSeaLevelRadius(double tt);
|
||||||
void SetTerrainElevation(double tt);
|
void SetTerrainElevation(double tt);
|
||||||
void SetDistanceAGL(double tt) { SetRadius(tt + LocalTerrainRadius); }
|
void SetDistanceAGL(double tt);
|
||||||
|
|
||||||
void SetInitialState(const FGInitialCondition *);
|
void SetInitialState(const FGInitialCondition *);
|
||||||
void SetLocation(const FGLocation& l);
|
void SetLocation(const FGLocation& l);
|
||||||
void SetLocation(const FGColumnVector3& lv)
|
void SetLocation(const FGColumnVector3& lv)
|
||||||
|
@ -520,8 +525,6 @@ public:
|
||||||
SetLocation(l);
|
SetLocation(l);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RecomputeLocalTerrainRadius(void);
|
|
||||||
|
|
||||||
void NudgeBodyLocation(FGColumnVector3 deltaLoc) {
|
void NudgeBodyLocation(FGColumnVector3 deltaLoc) {
|
||||||
VState.vInertialPosition -= Tb2i*deltaLoc;
|
VState.vInertialPosition -= Tb2i*deltaLoc;
|
||||||
VState.vLocation -= Tb2ec*deltaLoc;
|
VState.vLocation -= Tb2ec*deltaLoc;
|
||||||
|
@ -563,8 +566,9 @@ private:
|
||||||
FGMatrix33 Ti2l;
|
FGMatrix33 Ti2l;
|
||||||
FGMatrix33 Tl2i;
|
FGMatrix33 Tl2i;
|
||||||
|
|
||||||
double LocalTerrainRadius, SeaLevelRadius, VehicleRadius;
|
double VehicleRadius;
|
||||||
FGColumnVector3 LocalTerrainVelocity, LocalTerrainAngularVelocity;
|
FGColumnVector3 LocalTerrainVelocity, LocalTerrainAngularVelocity;
|
||||||
|
|
||||||
eIntegrateType integrator_rotational_rate;
|
eIntegrateType integrator_rotational_rate;
|
||||||
eIntegrateType integrator_translational_rate;
|
eIntegrateType integrator_translational_rate;
|
||||||
eIntegrateType integrator_rotational_position;
|
eIntegrateType integrator_rotational_position;
|
||||||
|
|
|
@ -47,7 +47,7 @@ INCLUDES
|
||||||
DEFINITIONS
|
DEFINITIONS
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
#define ID_WINDS "$Id: FGWinds.h,v 1.5 2011/09/07 12:21:45 jberndt Exp $"
|
#define ID_WINDS "$Id: FGWinds.h,v 1.6 2011/10/22 15:11:24 bcoconni Exp $"
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
FORWARD DECLARATIONS
|
FORWARD DECLARATIONS
|
||||||
|
@ -150,6 +150,9 @@ public:
|
||||||
/// Sets a wind component in NED frame.
|
/// Sets a wind component in NED frame.
|
||||||
virtual void SetWindNED(int idx, double wind) { vWindNED(idx)=wind;}
|
virtual void SetWindNED(int idx, double wind) { vWindNED(idx)=wind;}
|
||||||
|
|
||||||
|
/// Sets the wind components in NED frame.
|
||||||
|
virtual void SetWindNED(const FGColumnVector3& wind) { vWindNED=wind; }
|
||||||
|
|
||||||
/// Retrieves the wind components in NED frame.
|
/// Retrieves the wind components in NED frame.
|
||||||
virtual FGColumnVector3& GetWindNED(void) { return vWindNED; }
|
virtual FGColumnVector3& GetWindNED(void) { return vWindNED; }
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
namespace JSBSim {
|
||||||
|
|
||||||
static const char *IdSrc = "$Id: FGPiston.cpp,v 1.67 2011/09/25 23:56:11 jentron Exp $";
|
static const char *IdSrc = "$Id: FGPiston.cpp,v 1.68 2011/10/11 15:13:34 jentron Exp $";
|
||||||
static const char *IdHdr = ID_PISTON;
|
static const char *IdHdr = ID_PISTON;
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -434,6 +434,8 @@ void FGPiston::Calculate(void)
|
||||||
|
|
||||||
RunPreFunctions();
|
RunPreFunctions();
|
||||||
|
|
||||||
|
TotalDeltaT = ( in.TotalDeltaT < 1e-9 ) ? 1.0 : in.TotalDeltaT;
|
||||||
|
|
||||||
/* The thruster controls the engine RPM because it encapsulates the gear ratio and other transmission variables */
|
/* The thruster controls the engine RPM because it encapsulates the gear ratio and other transmission variables */
|
||||||
RPM = Thruster->GetEngineRPM();
|
RPM = Thruster->GetEngineRPM();
|
||||||
|
|
||||||
|
@ -618,10 +620,7 @@ void FGPiston::doMAP(void)
|
||||||
|
|
||||||
// Add a one second lag to manifold pressure changes
|
// Add a one second lag to manifold pressure changes
|
||||||
double dMAP=0;
|
double dMAP=0;
|
||||||
if (in.TotalDeltaT > 0.0)
|
dMAP = (TMAP - p_ram * map_coefficient) * TotalDeltaT;
|
||||||
dMAP = (TMAP - p_ram * map_coefficient) * in.TotalDeltaT;
|
|
||||||
else
|
|
||||||
dMAP = (TMAP - p_ram * map_coefficient) / 120;
|
|
||||||
|
|
||||||
TMAP -=dMAP;
|
TMAP -=dMAP;
|
||||||
|
|
||||||
|
@ -799,10 +798,7 @@ void FGPiston::doEGT(void)
|
||||||
} else { // Drop towards ambient - guess an appropriate time constant for now
|
} else { // Drop towards ambient - guess an appropriate time constant for now
|
||||||
combustion_efficiency = 0;
|
combustion_efficiency = 0;
|
||||||
dEGTdt = (RankineToKelvin(in.Temperature) - ExhaustGasTemp_degK) / 100.0;
|
dEGTdt = (RankineToKelvin(in.Temperature) - ExhaustGasTemp_degK) / 100.0;
|
||||||
if (in.TotalDeltaT > 0.0)
|
delta_T_exhaust = dEGTdt * TotalDeltaT;
|
||||||
delta_T_exhaust = dEGTdt * in.TotalDeltaT;
|
|
||||||
else
|
|
||||||
delta_T_exhaust = dEGTdt / 120;
|
|
||||||
|
|
||||||
ExhaustGasTemp_degK += delta_T_exhaust;
|
ExhaustGasTemp_degK += delta_T_exhaust;
|
||||||
}
|
}
|
||||||
|
@ -841,12 +837,9 @@ void FGPiston::doCHT(void)
|
||||||
|
|
||||||
double HeatCapacityCylinderHead = CpCylinderHead * MassCylinderHead;
|
double HeatCapacityCylinderHead = CpCylinderHead * MassCylinderHead;
|
||||||
|
|
||||||
if (in.TotalDeltaT > 0.0)
|
CylinderHeadTemp_degK +=
|
||||||
CylinderHeadTemp_degK +=
|
(dqdt_cylinder_head / HeatCapacityCylinderHead) * TotalDeltaT;
|
||||||
(dqdt_cylinder_head / HeatCapacityCylinderHead) * in.TotalDeltaT;
|
|
||||||
else
|
|
||||||
CylinderHeadTemp_degK +=
|
|
||||||
(dqdt_cylinder_head / HeatCapacityCylinderHead) / 120.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -880,10 +873,7 @@ void FGPiston::doOilTemperature(void)
|
||||||
|
|
||||||
double dOilTempdt = (target_oil_temp - OilTemp_degK) / time_constant;
|
double dOilTempdt = (target_oil_temp - OilTemp_degK) / time_constant;
|
||||||
|
|
||||||
if (in.TotalDeltaT > 0.0)
|
OilTemp_degK += (dOilTempdt * TotalDeltaT);
|
||||||
OilTemp_degK += (dOilTempdt * in.TotalDeltaT);
|
|
||||||
else
|
|
||||||
OilTemp_degK += (dOilTempdt / 120.0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
|
@ -46,7 +46,7 @@ INCLUDES
|
||||||
DEFINITIONS
|
DEFINITIONS
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
#define ID_PISTON "$Id: FGPiston.h,v 1.31 2011/08/04 13:45:42 jberndt Exp $";
|
#define ID_PISTON "$Id: FGPiston.h,v 1.32 2011/10/11 16:16:16 jentron Exp $";
|
||||||
#define FG_MAX_BOOST_SPEEDS 3
|
#define FG_MAX_BOOST_SPEEDS 3
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -198,7 +198,7 @@ boostspeed they refer to:
|
||||||
@author David Megginson (initial porting and additional code)
|
@author David Megginson (initial porting and additional code)
|
||||||
@author Ron Jensen (additional engine code)
|
@author Ron Jensen (additional engine code)
|
||||||
@see Taylor, Charles Fayette, "The Internal Combustion Engine in Theory and Practice"
|
@see Taylor, Charles Fayette, "The Internal Combustion Engine in Theory and Practice"
|
||||||
@version $Id: FGPiston.h,v 1.31 2011/08/04 13:45:42 jberndt Exp $
|
@version $Id: FGPiston.h,v 1.32 2011/10/11 16:16:16 jentron Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -332,6 +332,7 @@ private:
|
||||||
//
|
//
|
||||||
// Inputs (in addition to those in FGEngine).
|
// Inputs (in addition to those in FGEngine).
|
||||||
//
|
//
|
||||||
|
double TotalDeltaT; // Time in seconds between calls.
|
||||||
double p_amb; // Pascals
|
double p_amb; // Pascals
|
||||||
double p_ram; // Pascals
|
double p_ram; // Pascals
|
||||||
double T_amb; // degrees Kelvin
|
double T_amb; // degrees Kelvin
|
||||||
|
|
|
@ -45,7 +45,7 @@ using namespace std;
|
||||||
|
|
||||||
namespace JSBSim {
|
namespace JSBSim {
|
||||||
|
|
||||||
static const char *IdSrc = "$Id: FGPropeller.cpp,v 1.38 2011/09/24 14:26:46 jentron Exp $";
|
static const char *IdSrc = "$Id: FGPropeller.cpp,v 1.39 2011/10/15 13:00:57 bcoconni Exp $";
|
||||||
static const char *IdHdr = ID_PROPELLER;
|
static const char *IdHdr = ID_PROPELLER;
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -124,7 +124,7 @@ FGPropeller::FGPropeller(FGFDMExec* exec, Element* prop_element, int num)
|
||||||
local_element = prop_element->GetParent()->FindElement("sense");
|
local_element = prop_element->GetParent()->FindElement("sense");
|
||||||
if (local_element) {
|
if (local_element) {
|
||||||
double Sense = local_element->GetDataAsNumber();
|
double Sense = local_element->GetDataAsNumber();
|
||||||
SetSense(fabs(Sense)/Sense);
|
SetSense(Sense >= 0.0 ? 1.0 : -1.0);
|
||||||
}
|
}
|
||||||
local_element = prop_element->GetParent()->FindElement("p_factor");
|
local_element = prop_element->GetParent()->FindElement("p_factor");
|
||||||
if (local_element) {
|
if (local_element) {
|
||||||
|
|
|
@ -47,6 +47,7 @@ INCLUDES
|
||||||
#include "FGRotor.h"
|
#include "FGRotor.h"
|
||||||
#include "input_output/FGXMLElement.h"
|
#include "input_output/FGXMLElement.h"
|
||||||
#include "models/FGMassBalance.h"
|
#include "models/FGMassBalance.h"
|
||||||
|
#include "models/FGPropulsion.h" // to get the GearRatio from a linked rotor
|
||||||
|
|
||||||
using std::cerr;
|
using std::cerr;
|
||||||
using std::endl;
|
using std::endl;
|
||||||
|
@ -55,7 +56,7 @@ using std::cout;
|
||||||
|
|
||||||
namespace JSBSim {
|
namespace JSBSim {
|
||||||
|
|
||||||
static const char *IdSrc = "$Id: FGRotor.cpp,v 1.17 2011/09/24 14:26:46 jentron Exp $";
|
static const char *IdSrc = "$Id: FGRotor.cpp,v 1.18 2011/10/15 21:30:28 jentron Exp $";
|
||||||
static const char *IdHdr = ID_ROTOR;
|
static const char *IdHdr = ID_ROTOR;
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
@ -69,6 +70,113 @@ CLASS IMPLEMENTATION
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
// Note: The FGTransmission class is currently carried 'pick-a-pack' by
|
||||||
|
// FGRotor.
|
||||||
|
|
||||||
|
FGTransmission::FGTransmission(FGFDMExec *exec, int num) :
|
||||||
|
FreeWheelTransmission(1.0),
|
||||||
|
ThrusterMoment(1.0), EngineMoment(1.0), EngineFriction(0.0),
|
||||||
|
ClutchCtrlNorm(1.0), BrakeCtrlNorm(0.0), MaxBrakePower(0.0),
|
||||||
|
EngineRPM(0.0), ThrusterRPM(0.0)
|
||||||
|
{
|
||||||
|
double dt;
|
||||||
|
PropertyManager = exec->GetPropertyManager();
|
||||||
|
dt = exec->GetDeltaT();
|
||||||
|
|
||||||
|
// avoid too abrupt changes in transmission
|
||||||
|
FreeWheelLag = Filter(200.0,dt);
|
||||||
|
BindModel(num);
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
FGTransmission::~FGTransmission(){
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
// basically P = Q*w and Q_Engine + (-Q_Rotor) = J * dw/dt, J = Moment
|
||||||
|
//
|
||||||
|
void FGTransmission::Calculate(double EnginePower, double ThrusterTorque, double dt) {
|
||||||
|
|
||||||
|
double coupling = 1.0, coupling_sq = 1.0;
|
||||||
|
double fw_mult = 1.0;
|
||||||
|
|
||||||
|
double d_omega = 0.0, engine_d_omega = 0.0, thruster_d_omega = 0.0; // relative changes
|
||||||
|
|
||||||
|
double engine_omega = rpm_to_omega(EngineRPM);
|
||||||
|
double safe_engine_omega = engine_omega < 1e-1 ? 1e-1 : engine_omega;
|
||||||
|
double engine_torque = EnginePower / safe_engine_omega;
|
||||||
|
|
||||||
|
double thruster_omega = rpm_to_omega(ThrusterRPM);
|
||||||
|
double safe_thruster_omega = thruster_omega < 1e-1 ? 1e-1 : thruster_omega;
|
||||||
|
|
||||||
|
engine_torque -= EngineFriction / safe_engine_omega;
|
||||||
|
ThrusterTorque += Constrain(0.0, BrakeCtrlNorm, 1.0) * MaxBrakePower / safe_thruster_omega;
|
||||||
|
|
||||||
|
// would the FWU release ?
|
||||||
|
engine_d_omega = engine_torque/EngineMoment * dt;
|
||||||
|
thruster_d_omega = - ThrusterTorque/ThrusterMoment * dt;
|
||||||
|
|
||||||
|
if ( thruster_omega+thruster_d_omega > engine_omega+engine_d_omega ) {
|
||||||
|
// don't drive the engine
|
||||||
|
FreeWheelTransmission = 0.0;
|
||||||
|
} else {
|
||||||
|
FreeWheelTransmission = 1.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fw_mult = FreeWheelLag.execute(FreeWheelTransmission);
|
||||||
|
coupling = fw_mult * Constrain(0.0, ClutchCtrlNorm, 1.0);
|
||||||
|
|
||||||
|
if (coupling < 0.999999) { // are the separate calculations needed ?
|
||||||
|
// assume linear transfer
|
||||||
|
engine_d_omega =
|
||||||
|
(engine_torque - ThrusterTorque*coupling)/(ThrusterMoment*coupling + EngineMoment) * dt;
|
||||||
|
thruster_d_omega =
|
||||||
|
(engine_torque*coupling - ThrusterTorque)/(ThrusterMoment + EngineMoment*coupling) * dt;
|
||||||
|
|
||||||
|
EngineRPM += omega_to_rpm(engine_d_omega);
|
||||||
|
ThrusterRPM += omega_to_rpm(thruster_d_omega);
|
||||||
|
|
||||||
|
// simulate friction in clutch
|
||||||
|
coupling_sq = coupling*coupling;
|
||||||
|
EngineRPM = (1.0-coupling_sq) * EngineRPM + coupling_sq * 0.02 * (49.0*EngineRPM + ThrusterRPM);
|
||||||
|
ThrusterRPM = (1.0-coupling_sq) * ThrusterRPM + coupling_sq * 0.02 * (EngineRPM + 49.0*ThrusterRPM);
|
||||||
|
|
||||||
|
// enforce equal rpm
|
||||||
|
if ( fabs(EngineRPM-ThrusterRPM) < 1e-3 ) {
|
||||||
|
EngineRPM = ThrusterRPM = 0.5 * (EngineRPM+ThrusterRPM);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
d_omega = (engine_torque - ThrusterTorque)/(ThrusterMoment + EngineMoment) * dt;
|
||||||
|
EngineRPM = ThrusterRPM += omega_to_rpm(d_omega);
|
||||||
|
}
|
||||||
|
|
||||||
|
// nothing will turn backward
|
||||||
|
if (EngineRPM < 0.0 ) EngineRPM = 0.0;
|
||||||
|
if (ThrusterRPM < 0.0 ) ThrusterRPM = 0.0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
|
bool FGTransmission::BindModel(int num)
|
||||||
|
{
|
||||||
|
string property_name, base_property_name;
|
||||||
|
base_property_name = CreateIndexedPropertyName("propulsion/engine", num);
|
||||||
|
|
||||||
|
property_name = base_property_name + "/brake-ctrl-norm";
|
||||||
|
PropertyManager->Tie( property_name.c_str(), this, &FGTransmission::GetBrakeCtrl, &FGTransmission::SetBrakeCtrl);
|
||||||
|
property_name = base_property_name + "/free-wheel-transmission";
|
||||||
|
PropertyManager->Tie( property_name.c_str(), this, &FGTransmission::GetFreeWheelTransmission);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
// Constructor
|
// Constructor
|
||||||
|
@ -78,7 +186,7 @@ FGRotor::FGRotor(FGFDMExec *exec, Element* rotor_element, int num)
|
||||||
rho(0.002356), // environment
|
rho(0.002356), // environment
|
||||||
Radius(0.0), BladeNum(0), // configuration parameters
|
Radius(0.0), BladeNum(0), // configuration parameters
|
||||||
Sense(1.0), NominalRPM(0.0), MinimalRPM(0.0), MaximalRPM(0.0),
|
Sense(1.0), NominalRPM(0.0), MinimalRPM(0.0), MaximalRPM(0.0),
|
||||||
ExternalRPM(0), RPMdefinition(0), ExtRPMsource(NULL),
|
ExternalRPM(0), RPMdefinition(0), ExtRPMsource(NULL), SourceGearRatio(1.0),
|
||||||
BladeChord(0.0), LiftCurveSlope(0.0), BladeTwist(0.0), HingeOffset(0.0),
|
BladeChord(0.0), LiftCurveSlope(0.0), BladeTwist(0.0), HingeOffset(0.0),
|
||||||
BladeFlappingMoment(0.0), BladeMassMoment(0.0), PolarMoment(0.0),
|
BladeFlappingMoment(0.0), BladeMassMoment(0.0), PolarMoment(0.0),
|
||||||
InflowLag(0.0), TipLossB(0.0),
|
InflowLag(0.0), TipLossB(0.0),
|
||||||
|
@ -93,9 +201,8 @@ FGRotor::FGRotor(FGFDMExec *exec, Element* rotor_element, int num)
|
||||||
theta_downwash(0.0), phi_downwash(0.0),
|
theta_downwash(0.0), phi_downwash(0.0),
|
||||||
ControlMap(eMainCtrl), // control
|
ControlMap(eMainCtrl), // control
|
||||||
CollectiveCtrl(0.0), LateralCtrl(0.0), LongitudinalCtrl(0.0),
|
CollectiveCtrl(0.0), LateralCtrl(0.0), LongitudinalCtrl(0.0),
|
||||||
BrakeCtrlNorm(0.0), MaxBrakePower(0.0),
|
Transmission(NULL), // interaction with engine
|
||||||
FreeWheelPresent(0), FreeWheelThresh(0.0), // free-wheeling-unit (FWU)
|
EngineRPM(0.0), MaxBrakePower(0.0), GearLoss(0.0), GearMoment(0.0)
|
||||||
FreeWheelTransmission(0.0)
|
|
||||||
{
|
{
|
||||||
FGColumnVector3 location(0.0, 0.0, 0.0), orientation(0.0, 0.0, 0.0);
|
FGColumnVector3 location(0.0, 0.0, 0.0), orientation(0.0, 0.0, 0.0);
|
||||||
Element *thruster_element;
|
Element *thruster_element;
|
||||||
|
@ -158,12 +265,58 @@ FGRotor::FGRotor(FGFDMExec *exec, Element* rotor_element, int num)
|
||||||
// ExternalRPM -- is the RPM dictated ?
|
// ExternalRPM -- is the RPM dictated ?
|
||||||
if (rotor_element->FindElement("ExternalRPM")) {
|
if (rotor_element->FindElement("ExternalRPM")) {
|
||||||
ExternalRPM = 1;
|
ExternalRPM = 1;
|
||||||
|
SourceGearRatio = 1.0;
|
||||||
RPMdefinition = (int) rotor_element->FindElementValueAsNumber("ExternalRPM");
|
RPMdefinition = (int) rotor_element->FindElementValueAsNumber("ExternalRPM");
|
||||||
|
int rdef = RPMdefinition;
|
||||||
|
if (RPMdefinition>=0) {
|
||||||
|
// avoid ourself and (still) unknown engines.
|
||||||
|
if (!exec->GetPropulsion()->GetEngine(RPMdefinition) || RPMdefinition==num) {
|
||||||
|
RPMdefinition = -1;
|
||||||
|
} else {
|
||||||
|
FGThruster *tr = exec->GetPropulsion()->GetEngine(RPMdefinition)->GetThruster();
|
||||||
|
SourceGearRatio = tr->GetGearRatio();
|
||||||
|
// cout << "# got sources' GearRatio: " << SourceGearRatio << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (RPMdefinition != rdef) {
|
||||||
|
cerr << "# discarded given RPM source (" << rdef << ") and switched to external control (-1)." << endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// configure the rotor parameters
|
// configure the rotor parameters
|
||||||
Configure(rotor_element);
|
Configure(rotor_element);
|
||||||
|
|
||||||
|
// configure the transmission parameters
|
||||||
|
if (!ExternalRPM) {
|
||||||
|
Transmission = new FGTransmission(exec, num);
|
||||||
|
|
||||||
|
Transmission->SetMaxBrakePower(MaxBrakePower);
|
||||||
|
|
||||||
|
if (rotor_element->FindElement("gearloss")) {
|
||||||
|
GearLoss = rotor_element->FindElementValueAsNumberConvertTo("gearloss","HP");
|
||||||
|
GearLoss *= hptoftlbssec;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GearLoss<1e-6) { // TODO, allow 0 ?
|
||||||
|
double ehp = 0.5 * BladeNum*BladeChord*Radius*Radius; // guess engine power
|
||||||
|
//cout << "# guessed engine power: " << ehp << endl;
|
||||||
|
GearLoss = 0.0025 * ehp * hptoftlbssec;
|
||||||
|
}
|
||||||
|
Transmission->SetEngineFriction(GearLoss);
|
||||||
|
|
||||||
|
// The MOI sensed behind the gear ( MOI_engine*sqr(GearRatio) ).
|
||||||
|
if (rotor_element->FindElement("gearmoment")) {
|
||||||
|
GearMoment = rotor_element->FindElementValueAsNumberConvertTo("gearmoment","SLUG*FT2");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GearMoment<1e-2) { // TODO, need better check for lower limit
|
||||||
|
GearMoment = 0.1*PolarMoment;
|
||||||
|
}
|
||||||
|
Transmission->SetEngineMoment(GearMoment);
|
||||||
|
|
||||||
|
Transmission->SetThrusterMoment(PolarMoment);
|
||||||
|
}
|
||||||
|
|
||||||
// shaft representation - a rather simple transform,
|
// shaft representation - a rather simple transform,
|
||||||
// but using a matrix is safer.
|
// but using a matrix is safer.
|
||||||
TboToHsr.InitMatrix( 0.0, 0.0, 1.0,
|
TboToHsr.InitMatrix( 0.0, 0.0, 1.0,
|
||||||
|
@ -175,9 +328,6 @@ FGRotor::FGRotor(FGFDMExec *exec, Element* rotor_element, int num)
|
||||||
// calculation would cause jumps too. 1Hz seems sufficient.
|
// calculation would cause jumps too. 1Hz seems sufficient.
|
||||||
damp_hagl = Filter(1.0, dt);
|
damp_hagl = Filter(1.0, dt);
|
||||||
|
|
||||||
// avoid too abrupt changes in power transmission
|
|
||||||
FreeWheelLag = Filter(200.0,dt);
|
|
||||||
|
|
||||||
// enable import-export
|
// enable import-export
|
||||||
BindModel();
|
BindModel();
|
||||||
|
|
||||||
|
@ -188,6 +338,7 @@ FGRotor::FGRotor(FGFDMExec *exec, Element* rotor_element, int num)
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
FGRotor::~FGRotor(){
|
FGRotor::~FGRotor(){
|
||||||
|
if (Transmission) delete Transmission;
|
||||||
Debug(1);
|
Debug(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,17 +457,6 @@ void FGRotor::Configure(Element* rotor_element)
|
||||||
GroundEffectExp = ConfigValue(rotor_element, "groundeffectexp", 0.0);
|
GroundEffectExp = ConfigValue(rotor_element, "groundeffectexp", 0.0);
|
||||||
GroundEffectShift = ConfigValueConv(rotor_element, "groundeffectshift", 0.0, "FT");
|
GroundEffectShift = ConfigValueConv(rotor_element, "groundeffectshift", 0.0, "FT");
|
||||||
|
|
||||||
// handle optional free-wheeling-unit (FWU)
|
|
||||||
FreeWheelPresent = 0;
|
|
||||||
FreeWheelTransmission = 1.0;
|
|
||||||
if (rotor_element->FindElement("freewheelthresh")) {
|
|
||||||
FreeWheelThresh = rotor_element->FindElementValueAsNumber("freewheelthresh");
|
|
||||||
if (FreeWheelThresh > 1.0) {
|
|
||||||
FreeWheelPresent = 1;
|
|
||||||
FreeWheelTransmission = 0.0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// precalc often used powers
|
// precalc often used powers
|
||||||
R[0]=1.0; R[1]=Radius; R[2]=R[1]*R[1]; R[3]=R[2]*R[1]; R[4]=R[3]*R[1];
|
R[0]=1.0; R[1]=Radius; R[2]=R[1]*R[1]; R[3]=R[2]*R[1]; R[4]=R[3]*R[1];
|
||||||
B[0]=1.0; B[1]=TipLossB; B[2]=B[1]*B[1]; B[3]=B[2]*B[1]; B[4]=B[3]*B[1];
|
B[0]=1.0; B[1]=TipLossB; B[2]=B[1]*B[1]; B[3]=B[2]*B[1]; B[4]=B[3]*B[1];
|
||||||
|
@ -564,7 +704,7 @@ FGColumnVector3 FGRotor::body_moments(double a_ic, double b_ic)
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
void FGRotor::CalcStatePart1(void)
|
void FGRotor::CalcRotorState(void)
|
||||||
{
|
{
|
||||||
double A_IC; // lateral (roll) control in radians
|
double A_IC; // lateral (roll) control in radians
|
||||||
double B_IC; // longitudinal (pitch) control in radians
|
double B_IC; // longitudinal (pitch) control in radians
|
||||||
|
@ -583,7 +723,7 @@ void FGRotor::CalcStatePart1(void)
|
||||||
|
|
||||||
// handle RPM requirements, calc omega.
|
// handle RPM requirements, calc omega.
|
||||||
if (ExternalRPM && ExtRPMsource) {
|
if (ExternalRPM && ExtRPMsource) {
|
||||||
RPM = ExtRPMsource->getDoubleValue() / GearRatio;
|
RPM = ExtRPMsource->getDoubleValue() * ( SourceGearRatio / GearRatio );
|
||||||
}
|
}
|
||||||
|
|
||||||
// MinimalRPM is always >= 1. MaximalRPM is always >= NominalRPM
|
// MinimalRPM is always >= 1. MaximalRPM is always >= NominalRPM
|
||||||
|
@ -632,64 +772,24 @@ void FGRotor::CalcStatePart1(void)
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
void FGRotor::CalcStatePart2(double PowerAvailable)
|
|
||||||
{
|
|
||||||
if (! ExternalRPM) {
|
|
||||||
// calculate new RPM
|
|
||||||
double ExcessTorque = PowerAvailable / Omega;
|
|
||||||
double deltaOmega = ExcessTorque / PolarMoment * in.TotalDeltaT;
|
|
||||||
RPM += deltaOmega/(2.0*M_PI) * 60.0;
|
|
||||||
}
|
|
||||||
RPM = Constrain(MinimalRPM, RPM, MaximalRPM); // trim again
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
// Simulation of a free-wheeling-unit (FWU). Might need improvements.
|
|
||||||
|
|
||||||
void FGRotor::calc_freewheel_state(double p_source, double p_load) {
|
|
||||||
|
|
||||||
// engine is off/detached, release.
|
|
||||||
if (p_source<1e-3) {
|
|
||||||
FreeWheelTransmission = 0.0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// engine is driving the rotor, engage.
|
|
||||||
if (p_source >= p_load) {
|
|
||||||
FreeWheelTransmission = 1.0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// releases if engine is detached, but stays calm if
|
|
||||||
// the load changes due to rotor dynamics.
|
|
||||||
if (p_source > 0.0 && p_load/(p_source+0.1) > FreeWheelThresh ) {
|
|
||||||
FreeWheelTransmission = 0.0;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
||||||
|
|
||||||
double FGRotor::Calculate(double EnginePower)
|
double FGRotor::Calculate(double EnginePower)
|
||||||
{
|
{
|
||||||
double FWmult = 1.0;
|
|
||||||
double DeltaPower;
|
|
||||||
|
|
||||||
CalcStatePart1();
|
CalcRotorState();
|
||||||
|
|
||||||
PowerRequired = Torque * Omega + BrakeCtrlNorm * MaxBrakePower;
|
if (! ExternalRPM) {
|
||||||
|
Transmission->SetClutchCtrlNorm(ClutchCtrlNorm);
|
||||||
|
|
||||||
if (FreeWheelPresent) {
|
// the RPM values are handled inside Transmission
|
||||||
calc_freewheel_state(EnginePower * ClutchCtrlNorm, PowerRequired);
|
Transmission->Calculate(EnginePower, Torque, in.TotalDeltaT);
|
||||||
FWmult = FreeWheelLag.execute(FreeWheelTransmission);
|
|
||||||
|
EngineRPM = Transmission->GetEngineRPM() * GearRatio;
|
||||||
|
RPM = Transmission->GetThrusterRPM();
|
||||||
|
} else {
|
||||||
|
EngineRPM = RPM * GearRatio;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeltaPower = EnginePower * ClutchCtrlNorm * FWmult - PowerRequired;
|
RPM = Constrain(MinimalRPM, RPM, MaximalRPM); // trim again
|
||||||
|
|
||||||
CalcStatePart2(DeltaPower);
|
|
||||||
|
|
||||||
return Thrust;
|
return Thrust;
|
||||||
}
|
}
|
||||||
|
@ -767,22 +867,17 @@ bool FGRotor::BindModel(void)
|
||||||
PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetLongitudinalCtrl, &FGRotor::SetLongitudinalCtrl);
|
PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetLongitudinalCtrl, &FGRotor::SetLongitudinalCtrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
property_name = base_property_name + "/brake-ctrl-norm";
|
|
||||||
PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetBrakeCtrl, &FGRotor::SetBrakeCtrl);
|
|
||||||
property_name = base_property_name + "/free-wheel-transmission";
|
|
||||||
PropertyManager->Tie( property_name.c_str(), this, &FGRotor::GetFreeWheelTransmission);
|
|
||||||
|
|
||||||
if (ExternalRPM) {
|
if (ExternalRPM) {
|
||||||
if (RPMdefinition == -1) {
|
if (RPMdefinition == -1) {
|
||||||
property_name = base_property_name + "/x-rpm-dict";
|
property_name = base_property_name + "/x-rpm-dict";
|
||||||
ExtRPMsource = PropertyManager->GetNode(property_name, true);
|
ExtRPMsource = PropertyManager->GetNode(property_name, true);
|
||||||
} else if (RPMdefinition >= 0 && RPMdefinition != EngineNum) {
|
} else if (RPMdefinition >= 0 && RPMdefinition != EngineNum) {
|
||||||
string ipn = CreateIndexedPropertyName("propulsion/engine", RPMdefinition);
|
string ipn = CreateIndexedPropertyName("propulsion/engine", RPMdefinition);
|
||||||
property_name = ipn + "/engine-rpm";
|
property_name = ipn + "/rotor-rpm";
|
||||||
ExtRPMsource = PropertyManager->GetNode(property_name, false);
|
ExtRPMsource = PropertyManager->GetNode(property_name, false);
|
||||||
if (! ExtRPMsource) {
|
if (! ExtRPMsource) {
|
||||||
cerr << "# Warning: Engine number " << EngineNum << "." << endl;
|
cerr << "# Warning: Engine number " << EngineNum << "." << endl;
|
||||||
cerr << "# No 'engine-rpm' property found for engine " << RPMdefinition << "." << endl;
|
cerr << "# No 'rotor-rpm' property found for engine " << RPMdefinition << "." << endl;
|
||||||
cerr << "# Please check order of engine definitons." << endl;
|
cerr << "# Please check order of engine definitons." << endl;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -860,7 +955,7 @@ void FGRotor::Debug(int from)
|
||||||
if (RPMdefinition == -1) {
|
if (RPMdefinition == -1) {
|
||||||
cout << " RPM is controlled externally" << endl;
|
cout << " RPM is controlled externally" << endl;
|
||||||
} else {
|
} else {
|
||||||
cout << " RPM source set to engine " << RPMdefinition << endl;
|
cout << " RPM source set to thruster " << RPMdefinition << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -876,6 +971,8 @@ void FGRotor::Debug(int from)
|
||||||
cout << " Lock Number = " << LockNumberByRho * 0.002356 << " (SL)" << endl;
|
cout << " Lock Number = " << LockNumberByRho * 0.002356 << " (SL)" << endl;
|
||||||
cout << " Solidity = " << Solidity << endl;
|
cout << " Solidity = " << Solidity << endl;
|
||||||
cout << " Max Brake Power = " << MaxBrakePower/hptoftlbssec << " HP" << endl;
|
cout << " Max Brake Power = " << MaxBrakePower/hptoftlbssec << " HP" << endl;
|
||||||
|
cout << " Gear Loss = " << GearLoss/hptoftlbssec << " HP" << endl;
|
||||||
|
cout << " Gear Moment = " << GearMoment << endl;
|
||||||
|
|
||||||
switch (ControlMap) {
|
switch (ControlMap) {
|
||||||
case eTailCtrl: ControlMapName = "Tail Rotor"; break;
|
case eTailCtrl: ControlMapName = "Tail Rotor"; break;
|
||||||
|
@ -884,12 +981,6 @@ void FGRotor::Debug(int from)
|
||||||
}
|
}
|
||||||
cout << " Control Mapping = " << ControlMapName << endl;
|
cout << " Control Mapping = " << ControlMapName << endl;
|
||||||
|
|
||||||
if (FreeWheelPresent) {
|
|
||||||
cout << " Free Wheel Threshold = " << FreeWheelThresh << endl;
|
|
||||||
} else {
|
|
||||||
cout << " No FWU present" << endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
if (debug_lvl & 2 ) { // Instantiation/Destruction notification
|
||||||
|
|
|
@ -46,7 +46,7 @@ INCLUDES
|
||||||
DEFINITIONS
|
DEFINITIONS
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
#define ID_ROTOR "$Id: FGRotor.h,v 1.11 2011/09/24 14:26:46 jentron Exp $"
|
#define ID_ROTOR "$Id: FGRotor.h,v 1.12 2011/10/15 21:30:28 jentron Exp $"
|
||||||
|
|
||||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
FORWARD DECLARATIONS
|
FORWARD DECLARATIONS
|
||||||
|
@ -80,6 +80,8 @@ CLASS DOCUMENTATION
|
||||||
<inflowlag> {number} </inflowlag>
|
<inflowlag> {number} </inflowlag>
|
||||||
<tiplossfactor> {number} </tiplossfactor>
|
<tiplossfactor> {number} </tiplossfactor>
|
||||||
<maxbrakepower unit="{POWER}"> {number} </maxbrakepower>
|
<maxbrakepower unit="{POWER}"> {number} </maxbrakepower>
|
||||||
|
<gearloss unit="{POWER}"> {number} </gearloss>
|
||||||
|
<gearmoment unit="{MOMENT}"> {number} </gearmoment>
|
||||||
|
|
||||||
<controlmap> {MAIN|TAIL|TANDEM} </controlmap>
|
<controlmap> {MAIN|TAIL|TANDEM} </controlmap>
|
||||||
<ExternalRPM> {number} </ExternalRPM>
|
<ExternalRPM> {number} </ExternalRPM>
|
||||||
|
@ -120,13 +122,18 @@ CLASS DOCUMENTATION
|
||||||
responses (typical values for main rotor: 0.1 - 0.2 s).
|
responses (typical values for main rotor: 0.1 - 0.2 s).
|
||||||
\<tiplossfactor> - Tip-loss factor. The Blade fraction that produces lift.
|
\<tiplossfactor> - Tip-loss factor. The Blade fraction that produces lift.
|
||||||
Value usually ranges between 0.95 - 1.0, optional (B).
|
Value usually ranges between 0.95 - 1.0, optional (B).
|
||||||
|
|
||||||
\<maxbrakepower> - Rotor brake, 20-30 hp should work for a mid size helicopter.
|
\<maxbrakepower> - Rotor brake, 20-30 hp should work for a mid size helicopter.
|
||||||
|
\<gearloss> - Friction in gear, 0.2% to 3% of the engine power, optional (see notes).
|
||||||
|
\<gearmoment> - Approximation for the moment of inertia of the gear (and engine),
|
||||||
|
defaults to 0.1 * polarmoment, optional.
|
||||||
|
|
||||||
\<controlmap> - Defines the control inputs used (see notes).
|
\<controlmap> - Defines the control inputs used (see notes).
|
||||||
|
|
||||||
\<ExternalRPM> - Links the rotor to another rotor, or an user controllable property.
|
\<ExternalRPM> - Links the rotor to another rotor, or an user controllable property.
|
||||||
|
|
||||||
Experimental properties
|
Experimental properties
|
||||||
|
|
||||||
\<groundeffectexp> - Exponent for ground effect approximation. Values usually range from 0.04
|
\<groundeffectexp> - Exponent for ground effect approximation. Values usually range from 0.04
|
||||||
for large rotors to 0.1 for smaller ones. As a rule of thumb the effect
|
for large rotors to 0.1 for smaller ones. As a rule of thumb the effect
|
||||||
vanishes at a height 2-3 times the rotor diameter.
|
vanishes at a height 2-3 times the rotor diameter.
|
||||||
|
@ -134,10 +141,6 @@ CLASS DOCUMENTATION
|
||||||
Omitting or setting to 0.0 disables the effect calculation.
|
Omitting or setting to 0.0 disables the effect calculation.
|
||||||
\<groundeffectshift> - Further adjustment of ground effect, approx. hub height or slightly above.
|
\<groundeffectshift> - Further adjustment of ground effect, approx. hub height or slightly above.
|
||||||
|
|
||||||
\<freewheelthresh> - Ratio of thruster power to engine power. The FWU will release when above
|
|
||||||
the threshold. The value shouldn't be too close to 1.0, 1.5 seems ok.
|
|
||||||
0 disables this feature, which is also the default.
|
|
||||||
|
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<h3>Notes:</h3>
|
<h3>Notes:</h3>
|
||||||
|
@ -154,7 +157,7 @@ CLASS DOCUMENTATION
|
||||||
<tt>propulsion/engine[x]/longitudinal-ctrl-rad</tt>.</li>
|
<tt>propulsion/engine[x]/longitudinal-ctrl-rad</tt>.</li>
|
||||||
<li> The tail collective (aka antitorque, aka pedal) control input. Read from
|
<li> The tail collective (aka antitorque, aka pedal) control input. Read from
|
||||||
<tt>propulsion/engine[x]/antitorque-ctrl-rad</tt> or
|
<tt>propulsion/engine[x]/antitorque-ctrl-rad</tt> or
|
||||||
<tt>propulsion/engine[x]/tail-collective-ctrl-rad</tt>.</li>
|
<tt>propulsion/engine[x]/tail-collective-ctrl-rad</tt>.</li>
|
||||||
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
@ -178,9 +181,23 @@ CLASS DOCUMENTATION
|
||||||
|
|
||||||
<h4>- Engine issues -</h4>
|
<h4>- Engine issues -</h4>
|
||||||
|
|
||||||
In order to keep the rotor speed constant, use of a RPM-Governor system is
|
In order to keep the rotor/engine speed constant, use of a RPM-Governor system is
|
||||||
encouraged (see examples).
|
encouraged (see examples).
|
||||||
|
|
||||||
|
In case the model requires the manual use of a clutch the <tt>\<gearloss\></tt>
|
||||||
|
property might need attention.<ul>
|
||||||
|
|
||||||
|
<li> Electrical: here the gear-loss should be rather large to keep the engine
|
||||||
|
controllable when the clutch is open (although full throttle might still make it
|
||||||
|
spin away).</li>
|
||||||
|
<li> Piston: this engine model already has some internal friction loss and also
|
||||||
|
looses power if it spins too high. Here the gear-loss could be set to 0.25%
|
||||||
|
of the engine power (which is also the approximated default).</li>
|
||||||
|
<li> Turboprop: Here the default value might be a bit too small. Also it's advisable
|
||||||
|
to adjust the power table for rpm values that are far beyond the nominal value.</li>
|
||||||
|
|
||||||
|
</ul>
|
||||||
|
|
||||||
<h4>- Development hints -</h4>
|
<h4>- Development hints -</h4>
|
||||||
|
|
||||||
Setting <tt>\<ExternalRPM> -1 \</ExternalRPM></tt> the rotor's RPM is controlled by
|
Setting <tt>\<ExternalRPM> -1 \</ExternalRPM></tt> the rotor's RPM is controlled by
|
||||||
|
@ -205,7 +222,7 @@ CLASS DOCUMENTATION
|
||||||
</dl>
|
</dl>
|
||||||
|
|
||||||
@author Thomas Kreitler
|
@author Thomas Kreitler
|
||||||
@version $Id: FGRotor.h,v 1.11 2011/09/24 14:26:46 jentron Exp $
|
@version $Id: FGRotor.h,v 1.12 2011/10/15 21:30:28 jentron Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -214,6 +231,57 @@ CLASS DOCUMENTATION
|
||||||
CLASS DECLARATION
|
CLASS DECLARATION
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||||
|
|
||||||
|
class FGTransmission : public FGJSBBase {
|
||||||
|
|
||||||
|
public:
|
||||||
|
FGTransmission(FGFDMExec *exec, int num);
|
||||||
|
~FGTransmission();
|
||||||
|
|
||||||
|
void Calculate(double EnginePower, double ThrusterTorque, double dt);
|
||||||
|
|
||||||
|
void SetMaxBrakePower(double x) {MaxBrakePower=x;}
|
||||||
|
double GetMaxBrakePower() const {return MaxBrakePower;}
|
||||||
|
void SetEngineFriction(double x) {EngineFriction=x;}
|
||||||
|
double GetEngineFriction() const {return EngineFriction;}
|
||||||
|
void SetEngineMoment(double x) {EngineMoment=x;}
|
||||||
|
double GetEngineMoment() const {return EngineMoment;}
|
||||||
|
void SetThrusterMoment(double x) {ThrusterMoment=x;}
|
||||||
|
double GetThrusterMoment() const {return ThrusterMoment;}
|
||||||
|
|
||||||
|
double GetFreeWheelTransmission() const {return FreeWheelTransmission;}
|
||||||
|
double GetEngineRPM() {return EngineRPM;}
|
||||||
|
double GetThrusterRPM() {return ThrusterRPM;}
|
||||||
|
|
||||||
|
double GetBrakeCtrl() const {return BrakeCtrlNorm;}
|
||||||
|
void SetBrakeCtrl(double x) {BrakeCtrlNorm=x;}
|
||||||
|
void SetClutchCtrlNorm(double x) {ClutchCtrlNorm=x;}
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool BindModel(int num);
|
||||||
|
// void Debug(int from);
|
||||||
|
|
||||||
|
inline double omega_to_rpm(double w) {return w * 9.54929658551372014613302580235;} // omega/(2.0*PI) * 60.0
|
||||||
|
inline double rpm_to_omega(double r) {return r * .104719755119659774615421446109;} // (rpm/60.0)*2.0*PI
|
||||||
|
|
||||||
|
Filter FreeWheelLag;
|
||||||
|
double FreeWheelTransmission; // state, 0: free, 1:locked
|
||||||
|
|
||||||
|
double ThrusterMoment;
|
||||||
|
double EngineMoment; // estimated MOI of gear and engine, influences acceleration
|
||||||
|
double EngineFriction; // estimated friction in gear and possibly engine
|
||||||
|
|
||||||
|
double ClutchCtrlNorm; // also in FGThruster.h
|
||||||
|
double BrakeCtrlNorm;
|
||||||
|
double MaxBrakePower;
|
||||||
|
|
||||||
|
double EngineRPM;
|
||||||
|
double ThrusterRPM;
|
||||||
|
FGPropertyManager* PropertyManager;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
class FGRotor : public FGThruster {
|
class FGRotor : public FGThruster {
|
||||||
|
|
||||||
enum eCtrlMapping {eMainCtrl=0, eTailCtrl, eTandemCtrl};
|
enum eCtrlMapping {eMainCtrl=0, eTailCtrl, eTandemCtrl};
|
||||||
|
@ -241,8 +309,8 @@ public:
|
||||||
void SetRPM(double rpm) { RPM = rpm; }
|
void SetRPM(double rpm) { RPM = rpm; }
|
||||||
|
|
||||||
/// Retrieves the RPMs of the Engine, as seen from this rotor.
|
/// Retrieves the RPMs of the Engine, as seen from this rotor.
|
||||||
double GetEngineRPM(void) const { return GearRatio*RPM; } // bit of a hack.
|
double GetEngineRPM(void) const {return EngineRPM;} //{ return GearRatio*RPM; }
|
||||||
void SetEngineRPM(double rpm) { RPM = rpm/GearRatio; } // bit of a hack.
|
void SetEngineRPM(double rpm) {EngineRPM = rpm;} //{ RPM = rpm/GearRatio; }
|
||||||
/// Tells the rotor's gear ratio, usually the engine asks for this.
|
/// Tells the rotor's gear ratio, usually the engine asks for this.
|
||||||
double GetGearRatio(void) { return GearRatio; }
|
double GetGearRatio(void) { return GearRatio; }
|
||||||
/// Retrieves the thrust of the rotor.
|
/// Retrieves the thrust of the rotor.
|
||||||
|
@ -267,8 +335,6 @@ public:
|
||||||
double GetCT(void) const { return C_T; }
|
double GetCT(void) const { return C_T; }
|
||||||
/// Retrieves the torque
|
/// Retrieves the torque
|
||||||
double GetTorque(void) const { return Torque; }
|
double GetTorque(void) const { return Torque; }
|
||||||
/// Retrieves the state of the free-wheeling-unit (FWU).
|
|
||||||
double GetFreeWheelTransmission(void) const { return FreeWheelTransmission; }
|
|
||||||
|
|
||||||
/// Downwash angle - currently only valid for a rotor that spins horizontally
|
/// Downwash angle - currently only valid for a rotor that spins horizontally
|
||||||
double GetThetaDW(void) const { return theta_downwash; }
|
double GetThetaDW(void) const { return theta_downwash; }
|
||||||
|
@ -281,8 +347,6 @@ public:
|
||||||
double GetLateralCtrl(void) const { return LateralCtrl; }
|
double GetLateralCtrl(void) const { return LateralCtrl; }
|
||||||
/// Retrieves the longitudinal control input in radians.
|
/// Retrieves the longitudinal control input in radians.
|
||||||
double GetLongitudinalCtrl(void) const { return LongitudinalCtrl; }
|
double GetLongitudinalCtrl(void) const { return LongitudinalCtrl; }
|
||||||
/// Retrieves the normalized brake control input.
|
|
||||||
double GetBrakeCtrl(void) const { return BrakeCtrlNorm; }
|
|
||||||
|
|
||||||
/// Sets the collective control input in radians.
|
/// Sets the collective control input in radians.
|
||||||
void SetCollectiveCtrl(double c) { CollectiveCtrl = c; }
|
void SetCollectiveCtrl(double c) { CollectiveCtrl = c; }
|
||||||
|
@ -290,8 +354,6 @@ public:
|
||||||
void SetLateralCtrl(double c) { LateralCtrl = c; }
|
void SetLateralCtrl(double c) { LateralCtrl = c; }
|
||||||
/// Sets the longitudinal control input in radians.
|
/// Sets the longitudinal control input in radians.
|
||||||
void SetLongitudinalCtrl(double c) { LongitudinalCtrl = c; }
|
void SetLongitudinalCtrl(double c) { LongitudinalCtrl = c; }
|
||||||
/// Sets the normalized brake control input.
|
|
||||||
void SetBrakeCtrl(double c) { BrakeCtrlNorm = c; }
|
|
||||||
|
|
||||||
// Stubs. Only main rotor RPM is returned
|
// Stubs. Only main rotor RPM is returned
|
||||||
string GetThrusterLabels(int id, string delimeter);
|
string GetThrusterLabels(int id, string delimeter);
|
||||||
|
@ -308,9 +370,7 @@ private:
|
||||||
|
|
||||||
void Configure(Element* rotor_element);
|
void Configure(Element* rotor_element);
|
||||||
|
|
||||||
// true entry points
|
void CalcRotorState(void);
|
||||||
void CalcStatePart1(void);
|
|
||||||
void CalcStatePart2(double PowerAvailable);
|
|
||||||
|
|
||||||
// rotor dynamics
|
// rotor dynamics
|
||||||
void calc_flow_and_thrust(double theta_0, double Uw, double Ww, double flow_scale = 1.0);
|
void calc_flow_and_thrust(double theta_0, double Uw, double Ww, double flow_scale = 1.0);
|
||||||
|
@ -319,8 +379,6 @@ private:
|
||||||
void calc_drag_and_side_forces(double theta_0);
|
void calc_drag_and_side_forces(double theta_0);
|
||||||
void calc_torque(double theta_0);
|
void calc_torque(double theta_0);
|
||||||
|
|
||||||
void calc_freewheel_state(double pwr_in, double pwr_out);
|
|
||||||
|
|
||||||
// transformations
|
// transformations
|
||||||
FGColumnVector3 hub_vel_body2ca( const FGColumnVector3 &uvw, const FGColumnVector3 &pqr,
|
FGColumnVector3 hub_vel_body2ca( const FGColumnVector3 &uvw, const FGColumnVector3 &pqr,
|
||||||
double a_ic = 0.0 , double b_ic = 0.0 );
|
double a_ic = 0.0 , double b_ic = 0.0 );
|
||||||
|
@ -341,6 +399,7 @@ private:
|
||||||
double Radius;
|
double Radius;
|
||||||
int BladeNum;
|
int BladeNum;
|
||||||
|
|
||||||
|
// rpm control
|
||||||
double Sense;
|
double Sense;
|
||||||
double NominalRPM;
|
double NominalRPM;
|
||||||
double MinimalRPM;
|
double MinimalRPM;
|
||||||
|
@ -348,6 +407,7 @@ private:
|
||||||
int ExternalRPM;
|
int ExternalRPM;
|
||||||
int RPMdefinition;
|
int RPMdefinition;
|
||||||
FGPropertyManager* ExtRPMsource;
|
FGPropertyManager* ExtRPMsource;
|
||||||
|
double SourceGearRatio;
|
||||||
|
|
||||||
double BladeChord;
|
double BladeChord;
|
||||||
double LiftCurveSlope;
|
double LiftCurveSlope;
|
||||||
|
@ -400,14 +460,12 @@ private:
|
||||||
double LateralCtrl;
|
double LateralCtrl;
|
||||||
double LongitudinalCtrl;
|
double LongitudinalCtrl;
|
||||||
|
|
||||||
double BrakeCtrlNorm, MaxBrakePower;
|
// interaction with engine
|
||||||
|
FGTransmission *Transmission;
|
||||||
// free-wheeling-unit (FWU)
|
double EngineRPM;
|
||||||
int FreeWheelPresent; // 'installed' or not
|
double MaxBrakePower;
|
||||||
double FreeWheelThresh; // when to release
|
double GearLoss;
|
||||||
Filter FreeWheelLag;
|
double GearMoment;
|
||||||
double FreeWheelTransmission; // state, 0: free, 1:locked
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue