JSBSim sync.
* Fixed the initial conditions settings (geodetic altitude is now correctly computed). * FGLGear reports the time at which it detected a violent ground hit (aka crash) * Doc update of the kinematic component * TurboProp code cleanup with the removal of lots of obsolete/no-op members.
This commit is contained in:
parent
9650cf4e6a
commit
a1a7aa267c
7 changed files with 157 additions and 144 deletions
|
@ -653,7 +653,7 @@ bool FGJSBsim::copy_to_JSBsim()
|
|||
FGTurboProp* eng = (FGTurboProp*)Propulsion->GetEngine(i);
|
||||
eng->SetReverse( globals->get_controls()->get_reverser(i) );
|
||||
eng->SetCutoff( globals->get_controls()->get_cutoff(i) );
|
||||
eng->SetIgnition( globals->get_controls()->get_ignition(i) );
|
||||
// eng->SetIgnition( globals->get_controls()->get_ignition(i) );
|
||||
|
||||
eng->SetGeneratorPower( globals->get_controls()->get_generator_breaker(i) );
|
||||
eng->SetCondition( globals->get_controls()->get_condition(i) );
|
||||
|
@ -881,9 +881,9 @@ bool FGJSBsim::copy_from_JSBsim()
|
|||
node->setDoubleValue("n1", eng->GetN1());
|
||||
//node->setDoubleValue("n2", eng->GetN2());
|
||||
node->setDoubleValue("itt_degf", 32 + eng->GetITT()*9/5);
|
||||
node->setBoolValue("ignition", eng->GetIgnition() != 0);
|
||||
node->setDoubleValue("nozzle-pos-norm", eng->GetNozzle());
|
||||
node->setDoubleValue("inlet-pos-norm", eng->GetInlet());
|
||||
// node->setBoolValue("ignition", eng->GetIgnition() != 0);
|
||||
// node->setDoubleValue("nozzle-pos-norm", eng->GetNozzle());
|
||||
// node->setDoubleValue("inlet-pos-norm", eng->GetInlet());
|
||||
node->setDoubleValue("oil-pressure-psi", eng->getOilPressure_psi());
|
||||
node->setBoolValue("reversed", eng->GetReversed());
|
||||
node->setBoolValue("cutoff", eng->GetCutoff());
|
||||
|
|
|
@ -58,7 +58,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc,"$Id: FGInitialCondition.cpp,v 1.107 2016/01/24 18:18:38 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGInitialCondition.cpp,v 1.111 2016/07/03 17:20:55 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_INITIALCONDITION);
|
||||
|
||||
//******************************************************************************
|
||||
|
@ -104,6 +104,8 @@ void FGInitialCondition::ResetIC(double u0, double v0, double w0,
|
|||
position.SetLongitude(lonRad0);
|
||||
position.SetLatitude(latRad0);
|
||||
position.SetAltitudeAGL(altAGLFt0);
|
||||
lastLatitudeSet = setgeoc;
|
||||
lastAltitudeSet = setagl;
|
||||
|
||||
orientation = FGQuaternion(phi0, theta0, psi0);
|
||||
const FGMatrix33& Tb2l = orientation.GetTInv();
|
||||
|
@ -125,8 +127,12 @@ void FGInitialCondition::ResetIC(double u0, double v0, double w0,
|
|||
void FGInitialCondition::InitializeIC(void)
|
||||
{
|
||||
alpha=beta=0;
|
||||
a = fdmex->GetInertial()->GetSemimajor();
|
||||
double b = fdmex->GetInertial()->GetSemiminor();
|
||||
double ec = b/a;
|
||||
e2 = 1.0 - ec*ec;
|
||||
|
||||
position.SetEllipse(fdmex->GetInertial()->GetSemimajor(), fdmex->GetInertial()->GetSemiminor());
|
||||
position.SetEllipse(a, b);
|
||||
|
||||
position.SetPositionGeodetic(0.0, 0.0, 0.0);
|
||||
position.SetEarthPositionAngle(fdmex->GetPropagate()->GetEarthPositionAngle());
|
||||
|
@ -143,6 +149,7 @@ void FGInitialCondition::InitializeIC(void)
|
|||
|
||||
lastSpeedSet = setvt;
|
||||
lastAltitudeSet = setasl;
|
||||
lastLatitudeSet = setgeoc;
|
||||
enginesRunning = 0;
|
||||
needTrim = 0;
|
||||
}
|
||||
|
@ -696,18 +703,26 @@ void FGInitialCondition::SetAltitudeASLFtIC(double alt)
|
|||
double mach0 = vt / soundSpeed;
|
||||
double vc0 = VcalibratedFromMach(mach0, pressure, pressureSL, rhoSL);
|
||||
double ve0 = vt * sqrt(rho/rhoSL);
|
||||
double PitotAngle = Aircraft->GetPitotAngle();
|
||||
|
||||
double geodLatitude = position.GetGeodLatitudeRad();
|
||||
altitudeASL=alt;
|
||||
position.SetAltitudeASL(alt);
|
||||
|
||||
if (lastLatitudeSet == setgeod) {
|
||||
double h = ComputeGeodAltitude(geodLatitude);
|
||||
position.SetPositionGeodetic(position.GetLongitude(), geodLatitude, h);
|
||||
}
|
||||
|
||||
soundSpeed = Atmosphere->GetSoundSpeed(altitudeASL);
|
||||
rho = Atmosphere->GetDensity(altitudeASL);
|
||||
pressure = Atmosphere->GetPressure(altitudeASL);
|
||||
|
||||
switch(lastSpeedSet) {
|
||||
case setvc:
|
||||
mach0 = MachFromVcalibrated(vc0, pressure, pressureSL, rhoSL);
|
||||
SetVtrueFpsIC(mach0 * soundSpeed);
|
||||
mach0 = MachFromVcalibrated(vc0 * cos(alpha+PitotAngle) * cos(beta),
|
||||
pressure, pressureSL, rhoSL);
|
||||
SetVtrueFpsIC(mach0 * soundSpeed / (cos(alpha+PitotAngle) * cos(beta)));
|
||||
break;
|
||||
case setmach:
|
||||
SetVtrueFpsIC(mach0 * soundSpeed);
|
||||
|
@ -728,6 +743,8 @@ void FGInitialCondition::SetLatitudeRadIC(double lat)
|
|||
{
|
||||
double altitude;
|
||||
|
||||
lastLatitudeSet = setgeoc;
|
||||
|
||||
switch(lastAltitudeSet) {
|
||||
case setagl:
|
||||
altitude = GetAltitudeAGLFtIC();
|
||||
|
@ -735,9 +752,8 @@ void FGInitialCondition::SetLatitudeRadIC(double lat)
|
|||
SetAltitudeAGLFtIC(altitude);
|
||||
break;
|
||||
default:
|
||||
altitude = position.GetAltitudeASL();
|
||||
position.SetLatitude(lat);
|
||||
position.SetAltitudeASL(altitude);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -903,6 +919,68 @@ bool FGInitialCondition::Load(string rstfile, bool useStoredPath)
|
|||
return result;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
// Given an altitude above the sea level (or a position radius which is the
|
||||
// same) and a geodetic latitude, compute the geodetic altitude. It is assumed
|
||||
// that the terrain is a sphere and that the elevation is uniform all over the
|
||||
// Earth. Would that assumption fail, the computation below would need to be
|
||||
// adapted since the position radius would depend on the terrain elevation which
|
||||
// depends itself on the latitude.
|
||||
//
|
||||
// This is an acceptable trade off because this routine is only used by
|
||||
// standalone JSBSim which uses FGDefaultGroundCallback which assumes that the
|
||||
// Earth is a sphere.
|
||||
|
||||
double FGInitialCondition::ComputeGeodAltitude(double geodLatitude)
|
||||
{
|
||||
double R = position.GetRadius();
|
||||
double slat = sin(geodLatitude);
|
||||
double RN = a / sqrt(1.0 - e2*slat*slat);
|
||||
double p1 = e2*RN*slat*slat;
|
||||
double p2 = e2*e2*RN*RN*slat*slat-R*R;
|
||||
return p1 + sqrt(p1*p1-p2) - RN;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
|
||||
bool FGInitialCondition::LoadLatitude(Element* position_el)
|
||||
{
|
||||
Element* latitude_el = position_el->FindElement("latitude");
|
||||
|
||||
if (latitude_el) {
|
||||
double latitude = position_el->FindElementValueAsNumberConvertTo("latitude", "RAD");
|
||||
|
||||
if (fabs(latitude) > 0.5*M_PI) {
|
||||
string unit_type = latitude_el->GetAttributeValue("unit");
|
||||
if (unit_type.empty()) unit_type="RAD";
|
||||
|
||||
cerr << latitude_el->ReadFrom() << "The latitude value "
|
||||
<< latitude_el->GetDataAsNumber() << " " << unit_type
|
||||
<< " is outside the range [";
|
||||
if (unit_type == "DEG")
|
||||
cerr << "-90 DEG ; +90 DEG]" << endl;
|
||||
else
|
||||
cerr << "-PI/2 RAD; +PI/2 RAD]" << endl;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
string lat_type = latitude_el->GetAttributeValue("type");
|
||||
|
||||
if (lat_type == "geod" || lat_type == "geodetic") {
|
||||
double h = ComputeGeodAltitude(latitude);
|
||||
position.SetPositionGeodetic(position.GetLongitude(), latitude, h);
|
||||
lastLatitudeSet = setgeod;
|
||||
}
|
||||
else {
|
||||
position.SetLatitude(latitude);
|
||||
lastLatitudeSet = setgeoc;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//******************************************************************************
|
||||
|
||||
bool FGInitialCondition::Load_v1(Element* document)
|
||||
|
@ -921,31 +999,7 @@ bool FGInitialCondition::Load_v1(Element* document)
|
|||
else if (document->FindElement("altitudeMSL")) // This is feet above sea level
|
||||
SetAltitudeASLFtIC(document->FindElementValueAsNumberConvertTo("altitudeMSL", "FT"));
|
||||
|
||||
double altitude = GetAltitudeASLFtIC();
|
||||
double longitude = GetLongitudeRadIC();
|
||||
|
||||
Element* latitude_el = document->FindElement("latitude");
|
||||
if (latitude_el) {
|
||||
double latitude = document->FindElementValueAsNumberConvertTo("latitude", "RAD");
|
||||
if (fabs(latitude) > 0.5*M_PI) {
|
||||
string unit_type = latitude_el->GetAttributeValue("unit");
|
||||
if (unit_type.empty()) unit_type="RAD";
|
||||
cerr << latitude_el->ReadFrom() << "The latitude value "
|
||||
<< latitude_el->GetDataAsNumber() << " " << unit_type
|
||||
<< " is outside the range [";
|
||||
if (unit_type == "DEG")
|
||||
cerr << "-90 DEG ; +90 DEG]" << endl;
|
||||
else
|
||||
cerr << "-PI/2 RAD; +PI/2 RAD]" << endl;
|
||||
result = false;
|
||||
}
|
||||
|
||||
string lat_type = latitude_el->GetAttributeValue("type");
|
||||
if (lat_type == "geod" || lat_type == "geodetic")
|
||||
position.SetPositionGeodetic(longitude, latitude, altitude); // Longitude and altitude will be set later on
|
||||
else
|
||||
position.SetLatitude(latitude);
|
||||
}
|
||||
result = LoadLatitude(document);
|
||||
|
||||
FGColumnVector3 vOrient = orientation.GetEuler();
|
||||
|
||||
|
@ -995,9 +1049,7 @@ bool FGInitialCondition::Load_v1(Element* document)
|
|||
if (document->FindElement("xwind"))
|
||||
SetCrossWindKtsIC(document->FindElementValueAsNumberConvertTo("xwind", "KTS"));
|
||||
if (document->FindElement("targetNlf"))
|
||||
{
|
||||
SetTargetNlfIC(document->FindElementValueAsNumber("targetNlf"));
|
||||
}
|
||||
if (document->FindElement("trim"))
|
||||
needTrim = document->FindElementValueAsNumber("trim");
|
||||
|
||||
|
@ -1006,9 +1058,9 @@ bool FGInitialCondition::Load_v1(Element* document)
|
|||
const FGMatrix33& Tl2b = orientation.GetT();
|
||||
double radInv = 1.0 / position.GetRadius();
|
||||
FGColumnVector3 vOmegaLocal = FGColumnVector3(
|
||||
radInv*vUVW_NED(eEast),
|
||||
-radInv*vUVW_NED(eNorth),
|
||||
-radInv*vUVW_NED(eEast)*position.GetTanLatitude() );
|
||||
radInv*vUVW_NED(eEast),
|
||||
-radInv*vUVW_NED(eNorth),
|
||||
-radInv*vUVW_NED(eEast)*position.GetTanLatitude() );
|
||||
|
||||
vPQR_body = Tl2b * vOmegaLocal;
|
||||
|
||||
|
@ -1035,6 +1087,9 @@ bool FGInitialCondition::Load_v2(Element* document)
|
|||
}
|
||||
FGColumnVector3 vOmegaEarth = fdmex->GetInertial()->GetOmegaPlanet();
|
||||
|
||||
if (document->FindElement("elevation"))
|
||||
fdmex->GetGroundCallback()->SetTerrainGeoCentRadius(document->FindElementValueAsNumberConvertTo("elevation", "FT")+position.GetSeaLevelRadius());
|
||||
|
||||
// Initialize vehicle position
|
||||
//
|
||||
// Allowable frames:
|
||||
|
@ -1049,7 +1104,6 @@ bool FGInitialCondition::Load_v2(Element* document)
|
|||
position = position.GetTi2ec() * position_el->FindElementTripletConvertTo("FT");
|
||||
} else if (frame == "ecef") {
|
||||
if (!position_el->FindElement("x") && !position_el->FindElement("y") && !position_el->FindElement("z")) {
|
||||
Element* latitude_el = position_el->FindElement("latitude");
|
||||
if (position_el->FindElement("longitude"))
|
||||
position.SetLongitude(position_el->FindElementValueAsNumberConvertTo("longitude", "RAD"));
|
||||
|
||||
|
@ -1064,17 +1118,7 @@ bool FGInitialCondition::Load_v2(Element* document)
|
|||
result = false;
|
||||
}
|
||||
|
||||
double altitude = position.GetAltitudeASL();
|
||||
double longitude = position.GetLongitude();
|
||||
|
||||
if (latitude_el) {
|
||||
string lat_type = latitude_el->GetAttributeValue("type");
|
||||
double latitude = position_el->FindElementValueAsNumberConvertTo("latitude", "RAD");
|
||||
if (lat_type == "geod" || lat_type == "geodetic")
|
||||
position.SetPositionGeodetic(longitude, latitude, altitude);
|
||||
else
|
||||
position.SetLatitude(latitude);
|
||||
}
|
||||
result = LoadLatitude(position_el);
|
||||
|
||||
} else {
|
||||
position = position_el->FindElementTripletConvertTo("FT");
|
||||
|
@ -1088,9 +1132,6 @@ bool FGInitialCondition::Load_v2(Element* document)
|
|||
result = false;
|
||||
}
|
||||
|
||||
if (document->FindElement("elevation"))
|
||||
fdmex->GetGroundCallback()->SetTerrainGeoCentRadius(document->FindElementValueAsNumberConvertTo("elevation", "FT")+position.GetSeaLevelRadius());
|
||||
|
||||
// End of position initialization
|
||||
|
||||
// Initialize vehicle orientation
|
||||
|
|
|
@ -54,7 +54,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_INITIALCONDITION "$Id: FGInitialCondition.h,v 1.44 2016/01/10 16:35:28 bcoconni Exp $"
|
||||
#define ID_INITIALCONDITION "$Id: FGInitialCondition.h,v 1.46 2016/07/03 17:20:55 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -71,7 +71,8 @@ class FGPropertyManager;
|
|||
class Element;
|
||||
|
||||
typedef enum { setvt, setvc, setve, setmach, setuvw, setned, setvg } speedset;
|
||||
typedef enum { setasl, setagl} altitudeset;
|
||||
typedef enum { setasl, setagl } altitudeset;
|
||||
typedef enum { setgeoc, setgeod } latitudeset;
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
CLASS DOCUMENTATION
|
||||
|
@ -219,7 +220,7 @@ CLASS DOCUMENTATION
|
|||
@property ic/r-rad_sec (read/write) Yaw rate initial condition in radians/second
|
||||
|
||||
@author Tony Peden
|
||||
@version "$Id: FGInitialCondition.h,v 1.44 2016/01/10 16:35:28 bcoconni Exp $"
|
||||
@version "$Id: FGInitialCondition.h,v 1.46 2016/07/03 17:20:55 bcoconni Exp $"
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -677,9 +678,11 @@ private:
|
|||
|
||||
FGMatrix33 Tw2b, Tb2w;
|
||||
double alpha, beta;
|
||||
double a, e2;
|
||||
|
||||
speedset lastSpeedSet;
|
||||
altitudeset lastAltitudeSet;
|
||||
latitudeset lastLatitudeSet;
|
||||
unsigned int enginesRunning;
|
||||
int needTrim;
|
||||
|
||||
|
@ -699,6 +702,8 @@ private:
|
|||
double GetBodyVelFpsIC(int idx) const;
|
||||
void calcAeroAngles(const FGColumnVector3& _vt_BODY);
|
||||
void calcThetaBeta(double alfa, const FGColumnVector3& _vt_NED);
|
||||
double ComputeGeodAltitude(double geodLatitude);
|
||||
bool LoadLatitude(Element* position_el);
|
||||
void Debug(int from);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ DEFINITIONS
|
|||
GLOBAL DATA
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
IDENT(IdSrc,"$Id: FGLGear.cpp,v 1.123 2016/05/16 18:19:57 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGLGear.cpp,v 1.124 2016/06/25 17:48:02 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_LGEAR);
|
||||
|
||||
// Body To Structural (body frame is rotated 180 deg about Y and lengths are given in
|
||||
|
@ -555,7 +555,9 @@ void FGLGear::CrashDetect(void)
|
|||
GetMoments().Magnitude() > 5000000000.0 ||
|
||||
SinkRate > 1.4666*30 ) && !fdmex->IntegrationSuspended())
|
||||
{
|
||||
PutMessage("Crash Detected: Simulation FREEZE.");
|
||||
ostringstream buf;
|
||||
buf << "*CRASH DETECTED* " << fdmex->GetSimTime() << " seconds: " << name;
|
||||
PutMessage(buf.str());
|
||||
// fdmex->SuspendIntegration();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ INCLUDES
|
|||
DEFINITIONS
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
#define ID_FLAPS "$Id: FGKinemat.h,v 1.12 2016/06/12 14:47:46 bcoconni Exp $"
|
||||
#define ID_FLAPS "$Id: FGKinemat.h,v 1.13 2016/07/09 11:35:39 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -56,14 +56,16 @@ namespace JSBSim {
|
|||
CLASS DOCUMENTATION
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
|
||||
|
||||
/** Encapsulates a kinematic (mechanical) component for the flight control system.
|
||||
This component models the action of a moving effector, such as an aerosurface or
|
||||
other mechanized entity such as a landing gear strut for the purpose of effecting
|
||||
vehicle control or configuration. The form of the component specification is:
|
||||
/** Encapsulates a kinematic (mechanical) component for the flight control
|
||||
system. This component models the action of a moving effector, such as an
|
||||
aerosurface or other mechanized entity such as a landing gear strut for the
|
||||
purpose of effecting vehicle control or configuration. The form of the component
|
||||
specification is:
|
||||
|
||||
@code
|
||||
<kinematic name="Gear Control">
|
||||
<input> [-]property </input>
|
||||
[<noscale/>]
|
||||
<traverse>
|
||||
<setting>
|
||||
<position> number </position>
|
||||
|
@ -102,6 +104,13 @@ takes to get to that position from an adjacent setting. For example:
|
|||
|
||||
In this case, it takes 5 seconds to get to a 1 setting. As this is a software
|
||||
mechanization of a servo-actuator, there should be an output specified.
|
||||
|
||||
Positions must be given in ascending order.
|
||||
|
||||
By default, the input is assumed to be in the range [-1;1] and is scaled to the
|
||||
value specified in the last <position> tag. This behavior can be modified by
|
||||
adding a <noscale/> tag to the component definition: in that case, the input
|
||||
value is directly used to determine the current position of the component.
|
||||
*/
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
83
src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp
Normal file → Executable file
83
src/FDM/JSBSim/models/propulsion/FGTurboProp.cpp
Normal file → Executable file
|
@ -55,7 +55,7 @@ using namespace std;
|
|||
|
||||
namespace JSBSim {
|
||||
|
||||
IDENT(IdSrc,"$Id: FGTurboProp.cpp,v 1.32 2015/09/27 09:54:21 bcoconni Exp $");
|
||||
IDENT(IdSrc,"$Id: FGTurboProp.cpp,v 1.35 2016/07/10 12:39:28 bcoconni Exp $");
|
||||
IDENT(IdHdr,ID_TURBOPROP);
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
@ -64,11 +64,10 @@ CLASS IMPLEMENTATION
|
|||
|
||||
FGTurboProp::FGTurboProp(FGFDMExec* exec, Element *el, int engine_number, struct Inputs& input)
|
||||
: FGEngine(engine_number, input),
|
||||
ITT_N1(NULL), EnginePowerRPM_N1(NULL), EnginePowerVC(NULL), EnginePowerVCFN(NULL), CombustionEfficiency_N1(NULL),
|
||||
FDMExec(exec)
|
||||
ITT_N1(NULL), EnginePowerRPM_N1(NULL), EnginePowerVC(NULL),
|
||||
CombustionEfficiency_N1(NULL)
|
||||
{
|
||||
SetDefaults();
|
||||
|
||||
Load(exec, el);
|
||||
Debug(0);
|
||||
}
|
||||
|
@ -79,7 +78,8 @@ FGTurboProp::~FGTurboProp()
|
|||
{
|
||||
delete ITT_N1;
|
||||
delete EnginePowerRPM_N1;
|
||||
delete EnginePowerVC;
|
||||
if (dynamic_cast<FGTable*>(EnginePowerVC))
|
||||
delete EnginePowerVC;
|
||||
delete CombustionEfficiency_N1;
|
||||
Debug(1);
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ bool FGTurboProp::Load(FGFDMExec* exec, Element *el)
|
|||
|
||||
string property_prefix = CreateIndexedPropertyName("propulsion/engine", EngineNumber);
|
||||
|
||||
EnginePowerVCFN = GetPreFunction(property_prefix+"/EnginePowerVC");
|
||||
EnginePowerVC = GetPreFunction(property_prefix+"/EnginePowerVC");
|
||||
|
||||
|
||||
// ToDo: Need to make sure units are properly accounted for below.
|
||||
|
@ -115,12 +115,8 @@ bool FGTurboProp::Load(FGFDMExec* exec, Element *el)
|
|||
MilThrust = el->FindElementValueAsNumberConvertTo("milthrust","LBS");
|
||||
if (el->FindElement("idlen1"))
|
||||
IdleN1 = el->FindElementValueAsNumber("idlen1");
|
||||
if (el->FindElement("idlen2"))
|
||||
IdleN2 = el->FindElementValueAsNumber("idlen2");
|
||||
if (el->FindElement("maxn1"))
|
||||
MaxN1 = el->FindElementValueAsNumber("maxn1");
|
||||
if (el->FindElement("maxn2"))
|
||||
MaxN2 = el->FindElementValueAsNumber("maxn2");
|
||||
if (el->FindElement("betarangeend"))
|
||||
BetaRangeThrottleEnd = el->FindElementValueAsNumber("betarangeend")/100.0;
|
||||
BetaRangeThrottleEnd = Constrain(0.0, BetaRangeThrottleEnd, 0.99999);
|
||||
|
@ -146,17 +142,16 @@ bool FGTurboProp::Load(FGFDMExec* exec, Element *el)
|
|||
if (el->FindElement("itt_delay"))
|
||||
ITT_Delay = el->FindElementValueAsNumber("itt_delay");
|
||||
|
||||
Element *table_element;
|
||||
string name;
|
||||
Element *table_element = el->FindElement("table");
|
||||
FGPropertyManager* PropertyManager = exec->GetPropertyManager();
|
||||
|
||||
while (true) {
|
||||
table_element = el->FindNextElement("table");
|
||||
if (!table_element) break;
|
||||
name = table_element->GetAttributeValue("name");
|
||||
if (!EnginePowerVCFN && name == "EnginePowerVC") {
|
||||
while (table_element) {
|
||||
string name = table_element->GetAttributeValue("name");
|
||||
if (!EnginePowerVC && name == "EnginePowerVC") {
|
||||
EnginePowerVC = new FGTable(PropertyManager, table_element);
|
||||
std::cerr << "Note: Using the EnginePowerVC without enclosed <function> tag is deprecated" << std::endl;
|
||||
cerr << table_element->ReadFrom()
|
||||
<<"Note: Using the EnginePowerVC without enclosed <function> tag is deprecated"
|
||||
<< endl;
|
||||
} else if (name == "EnginePowerRPM_N1") {
|
||||
EnginePowerRPM_N1 = new FGTable(PropertyManager, table_element);
|
||||
} else if (name == "ITT_N1") {
|
||||
|
@ -167,13 +162,13 @@ bool FGTurboProp::Load(FGFDMExec* exec, Element *el)
|
|||
cerr << el->ReadFrom() << "Unknown table type: " << name
|
||||
<< " in turboprop definition." << endl;
|
||||
}
|
||||
table_element = el->FindNextElement("table");
|
||||
}
|
||||
|
||||
// Pre-calculations and initializations
|
||||
|
||||
delay=1;
|
||||
N1_factor = MaxN1 - IdleN1;
|
||||
N2_factor = MaxN2 - IdleN2;
|
||||
OilTemp_degK = in.TAT_c + 273.0;
|
||||
|
||||
// default table based on '9.333 - (N1)/12.0' approximation
|
||||
|
@ -188,7 +183,7 @@ bool FGTurboProp::Load(FGFDMExec* exec, Element *el)
|
|||
*CombustionEfficiency_N1 << 110.0 << 6.0;
|
||||
}
|
||||
|
||||
bindmodel(exec->GetPropertyManager());
|
||||
bindmodel(PropertyManager);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -200,8 +195,6 @@ void FGTurboProp::Calculate(void)
|
|||
{
|
||||
RunPreFunctions();
|
||||
|
||||
TAT = in.TAT_c;
|
||||
|
||||
ThrottlePos = in.ThrottlePos[EngineNumber];
|
||||
|
||||
/* The thruster controls the engine RPM because it encapsulates the gear ratio and other transmission variables */
|
||||
|
@ -230,16 +223,15 @@ void FGTurboProp::Calculate(void)
|
|||
if ((phase == tpTrim) && (in.TotalDeltaT > 0)) {
|
||||
if (Running && !Starved) {
|
||||
phase = tpRun;
|
||||
N2 = IdleN2;
|
||||
N1 = IdleN1;
|
||||
OilTemp_degK = 366.0;
|
||||
Cutoff = false;
|
||||
} else {
|
||||
phase = tpOff;
|
||||
Cutoff = true;
|
||||
Eng_ITT_degC = TAT;
|
||||
Eng_Temperature = TAT;
|
||||
OilTemp_degK = TAT+273.15;
|
||||
Eng_ITT_degC = in.TAT_c;
|
||||
Eng_Temperature = in.TAT_c;
|
||||
OilTemp_degK = in.TAT_c+273.15;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -312,9 +304,9 @@ double FGTurboProp::Off(void)
|
|||
//allow the air turn with generator
|
||||
N1 = ExpSeek(&N1, in.qbar/15.0, Idle_Max_Delay*2.5, Idle_Max_Delay * 5);
|
||||
|
||||
OilTemp_degK = ExpSeek(&OilTemp_degK,273.15 + TAT, 400 , 400);
|
||||
OilTemp_degK = ExpSeek(&OilTemp_degK,273.15 + in.TAT_c, 400 , 400);
|
||||
|
||||
Eng_Temperature = ExpSeek(&Eng_Temperature,TAT,300,400);
|
||||
Eng_Temperature = ExpSeek(&Eng_Temperature,in.TAT_c,300,400);
|
||||
double ITT_goal = ITT_N1->GetValue(N1,0.1) + ((N1>20) ? 0.0 : (20-N1)/20.0 * Eng_Temperature);
|
||||
Eng_ITT_degC = ExpSeek(&Eng_ITT_degC,ITT_goal,ITT_Delay,ITT_Delay*1.2);
|
||||
|
||||
|
@ -338,7 +330,7 @@ double FGTurboProp::Run(void)
|
|||
N1 = ExpSeek(&N1, IdleN1 + ThrottlePos * N1_factor, Idle_Max_Delay, Idle_Max_Delay * 2.4);
|
||||
|
||||
EngPower_HP = EnginePowerRPM_N1->GetValue(RPM,N1);
|
||||
EngPower_HP *= EnginePowerVCFN ? EnginePowerVCFN->GetValue() : EnginePowerVC->GetValue();
|
||||
EngPower_HP *= EnginePowerVC->GetValue();
|
||||
if (EngPower_HP > MaxPower) EngPower_HP = MaxPower;
|
||||
|
||||
CombustionEfficiency = CombustionEfficiency_N1->GetValue(N1);
|
||||
|
@ -377,17 +369,16 @@ double FGTurboProp::SpinUp(void)
|
|||
|
||||
N1 = ExpSeek(&N1, StarterN1, Idle_Max_Delay * 6, Idle_Max_Delay * 2.4);
|
||||
|
||||
Eng_Temperature = ExpSeek(&Eng_Temperature,TAT,300,400);
|
||||
Eng_Temperature = ExpSeek(&Eng_Temperature,in.TAT_c,300,400);
|
||||
double ITT_goal = ITT_N1->GetValue(N1,0.1) + ((N1>20) ? 0.0 : (20-N1)/20.0 * Eng_Temperature);
|
||||
Eng_ITT_degC = ExpSeek(&Eng_ITT_degC,ITT_goal,ITT_Delay,ITT_Delay*1.2);
|
||||
|
||||
OilTemp_degK = ExpSeek(&OilTemp_degK,273.15 + TAT, 400 , 400);
|
||||
OilTemp_degK = ExpSeek(&OilTemp_degK,273.15 + in.TAT_c, 400 , 400);
|
||||
|
||||
OilPressure_psi = (N1/100.0*0.25+(0.1-(OilTemp_degK-273.15)*0.1/80.0)*N1/100.0) / 7692.0e-6; //from MPa to psi
|
||||
NozzlePosition = 1.0;
|
||||
|
||||
EngPower_HP = EnginePowerRPM_N1->GetValue(RPM,N1);
|
||||
EngPower_HP *= EnginePowerVCFN ? EnginePowerVCFN->GetValue() : EnginePowerVC->GetValue();
|
||||
EngPower_HP *= EnginePowerVC->GetValue();
|
||||
if (EngPower_HP > MaxPower) EngPower_HP = MaxPower;
|
||||
|
||||
if (StartTime>=0) StartTime+=in.TotalDeltaT;
|
||||
|
@ -406,12 +397,12 @@ double FGTurboProp::Start(void)
|
|||
double EngPower_HP = 0.0;
|
||||
|
||||
EngStarting = false;
|
||||
if ((N1 > 15.0) && !Starved) { // minimum 15% N2 needed for start
|
||||
if ((N1 > 15.0) && !Starved) { // minimum 15% N1 needed for start
|
||||
double old_N1 = N1;
|
||||
Cranking = true; // provided for sound effects signal
|
||||
if (N1 < IdleN1) {
|
||||
EngPower_HP = EnginePowerRPM_N1->GetValue(RPM,N1);
|
||||
EngPower_HP *= EnginePowerVCFN ? EnginePowerVCFN->GetValue() : EnginePowerVC->GetValue();
|
||||
EngPower_HP *= EnginePowerVC->GetValue();
|
||||
if (EngPower_HP > MaxPower) EngPower_HP = MaxPower;
|
||||
N1 = ExpSeek(&N1, IdleN1*1.1, Idle_Max_Delay*4, Idle_Max_Delay * 2.4);
|
||||
CombustionEfficiency = CombustionEfficiency_N1->GetValue(N1);
|
||||
|
@ -430,7 +421,7 @@ double FGTurboProp::Start(void)
|
|||
Cranking = false;
|
||||
FuelFlow_pph = 0;
|
||||
}
|
||||
} else { // no start if N2 < 15% or Starved
|
||||
} else { // no start if N1 < 15% or Starved
|
||||
phase = tpOff;
|
||||
Starter = false;
|
||||
}
|
||||
|
@ -483,23 +474,15 @@ double FGTurboProp::ExpSeek(double *var, double target, double accel_tau, double
|
|||
void FGTurboProp::SetDefaults(void)
|
||||
{
|
||||
// Name = "Not defined";
|
||||
N1 = N2 = 0.0;
|
||||
N1 = 0.0;
|
||||
HP = 0.0;
|
||||
Type = etTurboprop;
|
||||
MilThrust = 10000.0;
|
||||
IdleN1 = 30.0;
|
||||
IdleN2 = 60.0;
|
||||
MaxN1 = 100.0;
|
||||
MaxN2 = 100.0;
|
||||
InletPosition = 1.0;
|
||||
NozzlePosition = 1.0;
|
||||
Reversed = false;
|
||||
Cutoff = true;
|
||||
phase = tpOff;
|
||||
Stalled = false;
|
||||
Seized = false;
|
||||
Overtemp = false;
|
||||
Fire = false;
|
||||
Eng_ITT_degC = 0.0;
|
||||
|
||||
GeneratorPower=true;
|
||||
|
@ -523,7 +506,6 @@ string FGTurboProp::GetEngineLabels(const string& delimiter)
|
|||
std::ostringstream buf;
|
||||
|
||||
buf << Name << "_N1[" << EngineNumber << "]" << delimiter
|
||||
<< Name << "_N2[" << EngineNumber << "]" << delimiter
|
||||
<< Name << "_PwrAvail[" << EngineNumber << "]" << delimiter
|
||||
<< Thruster->GetThrusterLabels(EngineNumber, delimiter);
|
||||
|
||||
|
@ -537,7 +519,6 @@ string FGTurboProp::GetEngineValues(const string& delimiter)
|
|||
std::ostringstream buf;
|
||||
|
||||
buf << N1 << delimiter
|
||||
<< N2 << delimiter
|
||||
<< HP << delimiter
|
||||
<< Thruster->GetThrusterValues(EngineNumber,delimiter);
|
||||
|
||||
|
@ -548,12 +529,12 @@ string FGTurboProp::GetEngineValues(const string& delimiter)
|
|||
|
||||
int FGTurboProp::InitRunning(void)
|
||||
{
|
||||
FDMExec->SuspendIntegration();
|
||||
double dt = in.TotalDeltaT;
|
||||
in.TotalDeltaT = 0.0;
|
||||
Cutoff=false;
|
||||
Running=true;
|
||||
N2=16.0;
|
||||
Calculate();
|
||||
FDMExec->ResumeIntegration();
|
||||
in.TotalDeltaT = dt;
|
||||
return phase==tpRun;
|
||||
}
|
||||
|
||||
|
@ -565,8 +546,6 @@ void FGTurboProp::bindmodel(FGPropertyManager* PropertyManager)
|
|||
base_property_name = CreateIndexedPropertyName("propulsion/engine", EngineNumber);
|
||||
property_name = base_property_name + "/n1";
|
||||
PropertyManager->Tie( property_name.c_str(), &N1);
|
||||
// property_name = base_property_name + "/n2";
|
||||
// PropertyManager->Tie( property_name.c_str(), &N2);
|
||||
property_name = base_property_name + "/reverser";
|
||||
PropertyManager->Tie( property_name.c_str(), &Reversed);
|
||||
property_name = base_property_name + "/power-hp";
|
||||
|
|
31
src/FDM/JSBSim/models/propulsion/FGTurboProp.h
Normal file → Executable file
31
src/FDM/JSBSim/models/propulsion/FGTurboProp.h
Normal file → Executable file
|
@ -46,7 +46,7 @@ INCLUDES
|
|||
#include "FGEngine.h"
|
||||
#include "math/FGTable.h"
|
||||
|
||||
#define ID_TURBOPROP "$Id: FGTurboProp.h,v 1.21 2015/09/27 09:54:21 bcoconni Exp $"
|
||||
#define ID_TURBOPROP "$Id: FGTurboProp.h,v 1.24 2016/07/10 12:39:28 bcoconni Exp $"
|
||||
|
||||
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
FORWARD DECLARATIONS
|
||||
|
@ -102,13 +102,13 @@ public:
|
|||
/// Destructor
|
||||
~FGTurboProp();
|
||||
|
||||
enum phaseType { tpOff, tpRun, tpSpinUp, tpStart, tpStall, tpSeize, tpTrim };
|
||||
enum phaseType { tpOff, tpRun, tpSpinUp, tpStart, tpTrim };
|
||||
|
||||
void Calculate(void);
|
||||
double CalcFuelNeed(void);
|
||||
|
||||
double GetPowerAvailable(void) const { return (HP * hptoftlbssec); }
|
||||
double GetRPM(void) const { return (RPM); }
|
||||
double GetRPM(void) const { return RPM; }
|
||||
double GetIeluThrottle(void) const { return (ThrottlePos); }
|
||||
bool GetIeluIntervent(void) const { return Ielu_intervent; }
|
||||
|
||||
|
@ -117,16 +117,10 @@ public:
|
|||
|
||||
phaseType GetPhase(void) const { return phase; }
|
||||
|
||||
bool GetOvertemp(void) const {return Overtemp; }
|
||||
bool GetFire(void) const { return Fire; }
|
||||
bool GetReversed(void) const { return Reversed; }
|
||||
bool GetCutoff(void) const { return Cutoff; }
|
||||
int GetIgnition(void) const {return Ignition;}
|
||||
|
||||
double GetInlet(void) const { return InletPosition; }
|
||||
double GetNozzle(void) const { return NozzlePosition; }
|
||||
double GetN1(void) const {return N1;}
|
||||
double GetN2(void) const {return N2;}
|
||||
double GetEPR(void) const {return EPR;}
|
||||
double GetITT(void) const {return Eng_ITT_degC;}
|
||||
double GetEngStarting(void) const { return EngStarting; }
|
||||
|
@ -137,7 +131,6 @@ public:
|
|||
inline bool GetGeneratorPower(void) const { return GeneratorPower; }
|
||||
inline int GetCondition(void) const { return Condition; }
|
||||
|
||||
void SetIgnition(int ignition) {Ignition = ignition;}
|
||||
void SetPhase( phaseType p ) { phase = p; }
|
||||
void SetEPR(double epr) {EPR = epr;}
|
||||
void SetReverse(bool reversed) { Reversed = reversed; }
|
||||
|
@ -154,29 +147,17 @@ private:
|
|||
phaseType phase; ///< Operating mode, or "phase"
|
||||
double MilThrust; ///< Maximum Unaugmented Thrust, static @ S.L. (lbf)
|
||||
double IdleN1; ///< Idle N1
|
||||
double IdleN2; ///< Idle N2
|
||||
double N1; ///< N1
|
||||
double N2; ///< N2
|
||||
double MaxN1; ///< N1 at 100% throttle
|
||||
double MaxN2; ///< N2 at 100% throttle
|
||||
double delay; ///< Inverse spool-up time from idle to 100% (seconds)
|
||||
double N1_factor; ///< factor to tie N1 and throttle
|
||||
double N2_factor; ///< factor to tie N2 and throttle
|
||||
double ThrottlePos; ///< FCS-supplied throttle position, modified locally
|
||||
double TAT; ///< total air temperature (deg C)
|
||||
bool Stalled; ///< true if engine is compressor-stalled
|
||||
bool Seized; ///< true if inner spool is seized
|
||||
bool Overtemp; ///< true if EGT exceeds limits
|
||||
bool Fire; ///< true if engine fire detected
|
||||
bool Reversed;
|
||||
bool Cutoff;
|
||||
int Ignition;
|
||||
|
||||
double EPR;
|
||||
double OilPressure_psi;
|
||||
double OilTemp_degK;
|
||||
double InletPosition;
|
||||
double NozzlePosition;
|
||||
|
||||
double Ielu_max_torque; // max propeller torque (before ielu intervent)
|
||||
bool Ielu_intervent;
|
||||
|
@ -190,8 +171,6 @@ private:
|
|||
double StarterN1; // rotates of generator maked by starter [%]
|
||||
double MaxStartingTime; // maximal time for start [s] (-1 means not used)
|
||||
double RPM; // shaft RPM
|
||||
//double Velocity;
|
||||
//double rho;
|
||||
double PSFC; // Power specific fuel comsumption [lb/(HP*hr)] at best efficiency
|
||||
double CombustionEfficiency;
|
||||
|
||||
|
@ -220,10 +199,8 @@ private:
|
|||
|
||||
FGTable* ITT_N1; // ITT temperature depending on throttle command
|
||||
FGTable* EnginePowerRPM_N1;
|
||||
FGTable* EnginePowerVC;
|
||||
FGFunction* EnginePowerVCFN;
|
||||
FGParameter* EnginePowerVC;
|
||||
FGTable* CombustionEfficiency_N1;
|
||||
FGFDMExec* FDMExec;
|
||||
};
|
||||
}
|
||||
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
Loading…
Add table
Reference in a new issue