HISTORY
--------------------------------------------------------------------------------
05/14/2004 Created
+02/08/2011 T. Kreitler, added rotor support
//JVK (mark)
INCLUDES
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-#include <vector>
+#include <iostream>
#include <sstream>
-#include "FGTurboProp.h"
+#include "FGTurboProp.h"
#include "FGPropeller.h"
+#include "FGRotor.h"
+
+using namespace std;
namespace JSBSim {
-static const char *IdSrc = "$Id$";
+static const char *IdSrc = "$Id: FGTurboProp.cpp,v 1.24 2011/09/25 23:56:11 jentron Exp $";
static const char *IdHdr = ID_TURBOPROP;
/*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
CLASS IMPLEMENTATION
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
-FGTurboProp::FGTurboProp(FGFDMExec* exec, Element *el, int engine_number)
- : FGEngine(exec, el, engine_number)
+FGTurboProp::FGTurboProp(FGFDMExec* exec, Element *el, int engine_number, struct Inputs& input)
+ : FGEngine(exec, el, engine_number, input),
+ ITT_N1(NULL), EnginePowerRPM_N1(NULL), EnginePowerVC(NULL)
{
SetDefaults();
+ thrusterType = Thruster->GetType();
Load(exec, el);
+ bindmodel();
Debug(0);
}
FGTurboProp::~FGTurboProp()
{
+ delete ITT_N1;
+ delete EnginePowerRPM_N1;
+ delete EnginePowerVC;
Debug(1);
}
if (el->FindElement("idlen1"))
IdleN1 = el->FindElementValueAsNumber("idlen1");
if (el->FindElement("idlen2"))
- IdleN2 = el->FindElementValueAsNumber("idlen1");
+ 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);
if (el->FindElement("reversemaxpower"))
ReverseMaxPower = el->FindElementValueAsNumber("reversemaxpower")/100.0;
delay=1;
N1_factor = MaxN1 - IdleN1;
N2_factor = MaxN2 - IdleN2;
- OilTemp_degK = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556 + 273.0;
+ OilTemp_degK = in.TAT_c + 273.0;
if (IdleFF==-1) IdleFF = pow(MilThrust, 0.2) * 107.0; // just an estimate
- cout << "ENG POWER:" << EnginePowerRPM_N1->GetValue(1200,90) << "\n";
+ // cout << "ENG POWER:" << EnginePowerRPM_N1->GetValue(1200,90) << endl;
return true;
}
// The main purpose of Calculate() is to determine what phase the engine should
// be in, then call the corresponding function.
-double FGTurboProp::Calculate(void)
+void FGTurboProp::Calculate(void)
{
- TAT = (Auxiliary->GetTotalTemperature() - 491.69) * 0.5555556;
- dt = State->Getdt() * Propulsion->GetRate();
+ RunPreFunctions();
+
+ TAT = in.TAT_c;
- ThrottleCmd = FCS->GetThrottleCmd(EngineNumber);
+ ThrottlePos = in.ThrottlePos[EngineNumber];
- Prop_RPM = Thruster->GetRPM() * Thruster->GetGearRatio();
- if (Thruster->GetType() == FGThruster::ttPropeller) {
- ((FGPropeller*)Thruster)->SetAdvance(FCS->GetPropAdvance(EngineNumber));
- ((FGPropeller*)Thruster)->SetFeather(FCS->GetPropFeather(EngineNumber));
+/* The thruster controls the engine RPM because it encapsulates the gear ratio and other transmission variables */
+ RPM = Thruster->GetEngineRPM();
+ if (thrusterType == FGThruster::ttPropeller) {
+ ((FGPropeller*)Thruster)->SetAdvance(in.PropAdvance[EngineNumber]);
+ ((FGPropeller*)Thruster)->SetFeather(in.PropFeather[EngineNumber]);
((FGPropeller*)Thruster)->SetReverse(Reversed);
if (Reversed) {
- ((FGPropeller*)Thruster)->SetReverseCoef(ThrottleCmd);
+ ((FGPropeller*)Thruster)->SetReverseCoef(ThrottlePos);
} else {
((FGPropeller*)Thruster)->SetReverseCoef(0.0);
}
- }
- if (Reversed) {
- if (ThrottleCmd < BetaRangeThrottleEnd) {
- ThrottleCmd = 0.0; // idle when in Beta-range
- } else {
- // when reversed:
- ThrottleCmd = (ThrottleCmd-BetaRangeThrottleEnd)/(1-BetaRangeThrottleEnd) * ReverseMaxPower;
+ if (Reversed) {
+ if (ThrottlePos < BetaRangeThrottleEnd) {
+ ThrottlePos = 0.0; // idle when in Beta-range
+ } else {
+ // when reversed:
+ ThrottlePos = (ThrottlePos-BetaRangeThrottleEnd)/(1-BetaRangeThrottleEnd) * ReverseMaxPower;
+ }
}
}
// When trimming is finished check if user wants engine OFF or RUNNING
- if ((phase == tpTrim) && (dt > 0)) {
+ if ((phase == tpTrim) && (in.TotalDeltaT > 0)) {
if (Running && !Starved) {
phase = tpRun;
N2 = IdleN2;
StartTime = -1;
}
if (Cutoff && (phase != tpSpinUp)) phase = tpOff;
- if (dt == 0) phase = tpTrim;
+ if (in.TotalDeltaT == 0) phase = tpTrim;
if (Starved) phase = tpOff;
if (Condition >= 10) {
phase = tpOff;
StartTime=-1;
}
- if (Condition < 1) {
- if (Ielu_max_torque > 0
- && -Ielu_max_torque > ((FGPropeller*)(Thruster))->GetTorque()
- && ThrottleCmd >= OldThrottle ) {
- ThrottleCmd = OldThrottle - 0.1 * dt; //IELU down
- Ielu_intervent = true;
- } else if (Ielu_max_torque > 0 && Ielu_intervent && ThrottleCmd >= OldThrottle) {
- ThrottleCmd = OldThrottle;
- ThrottleCmd = OldThrottle + 0.05 * dt; //IELU up
- Ielu_intervent = true;
+ // limiter intervention wanted?
+ if (Ielu_max_torque > 0.0) {
+ double torque = 0.0;
+
+ if (thrusterType == FGThruster::ttPropeller) {
+ torque = ((FGPropeller*)(Thruster))->GetTorque();
+ } else if (thrusterType == FGThruster::ttRotor) {
+ torque = ((FGRotor*)(Thruster))->GetTorque();
+ }
+
+ if (Condition < 1) {
+ if ( abs(torque) > Ielu_max_torque && ThrottlePos >= OldThrottle ) {
+ ThrottlePos = OldThrottle - 0.1 * in.TotalDeltaT; //IELU down
+ Ielu_intervent = true;
+ } else if ( Ielu_intervent && ThrottlePos >= OldThrottle) {
+ ThrottlePos = OldThrottle + 0.05 * in.TotalDeltaT; //IELU up
+ Ielu_intervent = true;
+ } else {
+ Ielu_intervent = false;
+ }
} else {
Ielu_intervent = false;
}
- } else {
- Ielu_intervent = false;
+ OldThrottle = ThrottlePos;
}
- OldThrottle = ThrottleCmd;
switch (phase) {
- case tpOff: Eng_HP = Off(); break;
- case tpRun: Eng_HP = Run(); break;
- case tpSpinUp: Eng_HP = SpinUp(); break;
- case tpStart: Eng_HP = Start(); break;
- default: Eng_HP = 0;
+ case tpOff: HP = Off(); break;
+ case tpRun: HP = Run(); break;
+ case tpSpinUp: HP = SpinUp(); break;
+ case tpStart: HP = Start(); break;
+ default: HP = 0;
}
+
+ LoadThrusterInputs();
+ Thruster->Calculate(HP * hptoftlbssec);
- //printf ("EngHP: %lf / Requi: %lf\n",Eng_HP,Prop_Required_Power);
- return Thruster->Calculate((Eng_HP * hptoftlbssec)-Thruster->GetPowerRequired());
+ RunPostFunctions();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
double FGTurboProp::Off(void)
{
- double qbar = Auxiliary->Getqbar();
Running = false; EngStarting = false;
FuelFlow_pph = Seek(&FuelFlow_pph, 0, 800.0, 800.0);
//allow the air turn with generator
- N1 = ExpSeek(&N1, qbar/15.0, Idle_Max_Delay*2.5, Idle_Max_Delay * 5);
+ 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);
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
- ConsumeFuel(); // for possible setting Starved = false when fuel tank
- // is refilled (fuel crossfeed etc.)
-
- if (Prop_RPM>5) return -0.012; // friction in engine when propeller spining (estimate)
+ if (RPM>5) return -0.012; // friction in engine when propeller spining (estimate)
return 0.0;
}
//---
double old_N1 = N1;
- N1 = ExpSeek(&N1, IdleN1 + ThrottleCmd * N1_factor, Idle_Max_Delay, Idle_Max_Delay * 2.4);
+ N1 = ExpSeek(&N1, IdleN1 + ThrottlePos * N1_factor, Idle_Max_Delay, Idle_Max_Delay * 2.4);
- EngPower_HP = EnginePowerRPM_N1->GetValue(Prop_RPM,N1);
+ EngPower_HP = EnginePowerRPM_N1->GetValue(RPM,N1);
EngPower_HP *= EnginePowerVC->GetValue();
if (EngPower_HP > MaxPower) EngPower_HP = MaxPower;
OilTemp_degK = Seek(&OilTemp_degK, 353.15, 0.4-N1*0.001, 0.04);
- ConsumeFuel();
-
if (Cutoff) phase = tpOff;
if (Starved) phase = tpOff;
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(Prop_RPM,N1);
+ EngPower_HP = EnginePowerRPM_N1->GetValue(RPM,N1);
EngPower_HP *= EnginePowerVC->GetValue();
if (EngPower_HP > MaxPower) EngPower_HP = MaxPower;
- if (StartTime>=0) StartTime+=dt;
+ if (StartTime>=0) StartTime+=in.TotalDeltaT;
if (StartTime > MaxStartingTime && MaxStartingTime > 0) { //start failed due timeout
phase = tpOff;
StartTime = -1;
}
- ConsumeFuel(); // for possible setting Starved = false when fuel tank
- // is refilled (fuel crossfeed etc.)
-
return EngPower_HP;
}
double FGTurboProp::Start(void)
{
- double EngPower_HP,eff_coef;
+ double EngPower_HP = 0.0;
+ double eff_coef;
+
EngStarting = false;
if ((N1 > 15.0) && !Starved) { // minimum 15% N2 needed for start
double old_N1 = N1;
Cranking = true; // provided for sound effects signal
if (N1 < IdleN1) {
- EngPower_HP = EnginePowerRPM_N1->GetValue(Prop_RPM,N1);
+ EngPower_HP = EnginePowerRPM_N1->GetValue(RPM,N1);
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);
Starter = false;
Cranking = false;
FuelFlow_pph = 0;
- EngPower_HP=0.0;
}
} else { // no start if N2 < 15% or Starved
phase = tpOff;
Starter = false;
}
- ConsumeFuel();
-
return EngPower_HP;
}
double FGTurboProp::CalcFuelNeed(void)
{
- double dT = State->Getdt() * Propulsion->GetRate();
FuelFlowRate = FuelFlow_pph / 3600.0;
- FuelExpended = FuelFlowRate * dT;
+ FuelExpended = FuelFlowRate * in.TotalDeltaT;
+ if (!Starved) FuelUsedLbs += FuelExpended;
return FuelExpended;
}
{
double v = *var;
if (v > target) {
- v -= dt * decel;
+ v -= in.TotalDeltaT * decel;
if (v < target) v = target;
} else if (v < target) {
- v += dt * accel;
+ v += in.TotalDeltaT * accel;
if (v > target) v = target;
}
return v;
// exponential delay instead of the linear delay used in Seek
double v = *var;
if (v > target) {
- v = (v - target) * exp ( -dt / decel_tau) + target;
+ v = (v - target) * exp ( -in.TotalDeltaT / decel_tau) + target;
} else if (v < target) {
- v = (target - v) * (1 - exp ( -dt / accel_tau)) + v;
+ v = (target - v) * (1 - exp ( -in.TotalDeltaT / accel_tau)) + v;
}
return v;
}
void FGTurboProp::SetDefaults(void)
{
- Name = "Not defined";
+// Name = "Not defined";
N1 = N2 = 0.0;
+ HP = 0.0;
Type = etTurboprop;
MilThrust = 10000.0;
IdleN1 = 30.0;
IdleN2 = 60.0;
MaxN1 = 100.0;
MaxN2 = 100.0;
- ThrottleCmd = 0.0;
InletPosition = 1.0;
NozzlePosition = 1.0;
Reversed = false;
Ielu_intervent=false;
Idle_Max_Delay = 1.0;
+
+ ThrottlePos = OldThrottle = 0.0;
+ ITT_Delay = 0.05;
+ ReverseMaxPower = 0.0;
+ BetaRangeThrottleEnd = 0.0;
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-string FGTurboProp::GetEngineLabels(string delimeter)
+string FGTurboProp::GetEngineLabels(const string& delimiter)
{
std::ostringstream buf;
- buf << Name << "_N1[" << EngineNumber << "]" << delimeter
- << Name << "_N2[" << EngineNumber << "]" << delimeter
- << Name << "__PwrAvailJVK[" << EngineNumber << "]" << delimeter
- << Thruster->GetThrusterLabels(EngineNumber, delimeter);
+ buf << Name << "_N1[" << EngineNumber << "]" << delimiter
+ << Name << "_N2[" << EngineNumber << "]" << delimiter
+ << Name << "_PwrAvail[" << EngineNumber << "]" << delimiter
+ << Thruster->GetThrusterLabels(EngineNumber, delimiter);
return buf.str();
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-string FGTurboProp::GetEngineValues(string delimeter)
+string FGTurboProp::GetEngineValues(const string& delimiter)
{
std::ostringstream buf;
- buf << N1 << delimeter
- << N2 << delimeter
- << Thruster->GetThrusterValues(EngineNumber,delimeter);
+ buf << N1 << delimiter
+ << N2 << delimiter
+ << HP << delimiter
+ << Thruster->GetThrusterValues(EngineNumber,delimiter);
return buf.str();
}
int FGTurboProp::InitRunning(void)
{
- State->SuspendIntegration();
+ FDMExec->SuspendIntegration();
Cutoff=false;
Running=true;
N2=16.0;
Calculate();
- State->ResumeIntegration();
+ FDMExec->ResumeIntegration();
return phase==tpRun;
}
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 + "/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";
+ PropertyManager->Tie( property_name.c_str(), &HP);
+ property_name = base_property_name + "/itt-c";
+ PropertyManager->Tie( property_name.c_str(), &Eng_ITT_degC);
+ property_name = base_property_name + "/engtemp-c";
+ PropertyManager->Tie( property_name.c_str(), &Eng_Temperature);
+ property_name = base_property_name + "/ielu_intervent";
+ PropertyManager->Tie( property_name.c_str(), &Ielu_intervent);
}
//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%