1
0
Fork 0

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:
Bertrand Coconnier 2016-07-10 14:45:09 +02:00
parent 9650cf4e6a
commit a1a7aa267c
7 changed files with 157 additions and 144 deletions

View file

@ -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());

View file

@ -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

View file

@ -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);
};
}

View file

@ -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();
}
}

View file

@ -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
View 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
View 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;
};
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%