diff --git a/src/FDM/YASim/Engine.hpp b/src/FDM/YASim/Engine.hpp index edbe15d3d..8be455507 100644 --- a/src/FDM/YASim/Engine.hpp +++ b/src/FDM/YASim/Engine.hpp @@ -4,6 +4,7 @@ namespace yasim { class PistonEngine; +class TurbineEngine; // // Interface for the "Engine" part of a PropEngine object. This is a @@ -15,6 +16,7 @@ class PistonEngine; class Engine { public: virtual PistonEngine* isPistonEngine() { return 0; } + virtual TurbineEngine* isTurbineEngine() { return 0; } void setThrottle(float throttle) { _throttle = throttle; } void setStarter(bool starter) { _starter = starter; } @@ -28,6 +30,8 @@ public: virtual bool isCranking() { return false; } virtual void calc(float pressure, float temp, float speed) = 0; + virtual void stabilize() {} + virtual void integrate(float dt) {} virtual float getTorque() = 0; virtual float getFuelFlow() = 0; diff --git a/src/FDM/YASim/FGFDM.cpp b/src/FDM/YASim/FGFDM.cpp index 6454f848e..577a8c28f 100644 --- a/src/FDM/YASim/FGFDM.cpp +++ b/src/FDM/YASim/FGFDM.cpp @@ -11,6 +11,7 @@ #include "PropEngine.hpp" #include "Propeller.hpp" #include "PistonEngine.hpp" +#include "TurbineEngine.hpp" #include "Rotor.hpp" #include "Rotorpart.hpp" #include "Rotorblade.hpp" @@ -35,6 +36,8 @@ static const float K2DEGFOFFSET = -459.4; static const float CIN2CM = 1.6387064e-5; static const float YASIM_PI = 3.14159265358979323846; +static const float NM2FTLB = (1/(LBS2N*FT2M)); + // Stubs, so that this can be compiled without the FlightGear // binary. What's the best way to handle this? @@ -175,6 +178,10 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts) _airplane.setTail(parseWing(a, name)); } else if(eq(name, "vstab") || eq(name, "mstab")) { _airplane.addVStab(parseWing(a, name)); + } else if(eq(name, "piston-engine")) { + parsePistonEngine(a); + } else if(eq(name, "turbine-engine")) { + parseTurbineEngine(a); } else if(eq(name, "propeller")) { parsePropeller(a); } else if(eq(name, "thruster")) { @@ -448,22 +455,24 @@ void FGFDM::setOutputProperties() float lbs = Math::mag3(tmp) * (KG2LBS/9.8); node->setFloatValue("prop-thrust", lbs); // Deprecated name node->setFloatValue("thrust-lbs", lbs); - node->setFloatValue("fuel-flow-gph", (t->getFuelFlow()/fuelDensity) * 3600 * CM2GALS); if(t->getPropEngine()) { PropEngine* p = t->getPropEngine(); node->setFloatValue("rpm", p->getOmega() * (1/RPM2RAD)); - + node->setFloatValue("torque-ftlb", + p->getEngine()->getTorque() * NM2FTLB); + if(p->getEngine()->isPistonEngine()) { PistonEngine* pe = p->getEngine()->isPistonEngine(); node->setFloatValue("mp-osi", pe->getMP() * (1/INHG2PA)); node->setFloatValue("mp-inhg", pe->getMP() * (1/INHG2PA)); node->setFloatValue("egt-degf", pe->getEGT() * K2DEGF + K2DEGFOFFSET); -// } else if(p->isTurbineEngine()) { -// TurbineEngine* te = p->isTurbineEngine(); + } else if(p->getEngine()->isTurbineEngine()) { + TurbineEngine* te = p->getEngine()->isTurbineEngine(); + node->setFloatValue("n2", te->getN2()); } } @@ -595,28 +604,12 @@ Rotor* FGFDM::parseRotor(XMLAttributes* a, const char* type) return w; } -void FGFDM::parsePropeller(XMLAttributes* a) +void FGFDM::parsePistonEngine(XMLAttributes* a) { - float cg[3]; - cg[0] = attrf(a, "x"); - cg[1] = attrf(a, "y"); - cg[2] = attrf(a, "z"); - float mass = attrf(a, "mass") * LBS2KG; - float moment = attrf(a, "moment"); - float radius = attrf(a, "radius"); - float speed = attrf(a, "cruise-speed") * KTS2MPS; - float omega = attrf(a, "cruise-rpm") * RPM2RAD; - float power = attrf(a, "cruise-power") * HP2W; - float rho = Atmosphere::getStdDensity(attrf(a, "cruise-alt") * FT2M); - - // Hack, fix this pronto: float engP = attrf(a, "eng-power") * HP2W; float engS = attrf(a, "eng-rpm") * RPM2RAD; - Propeller* prop = new Propeller(radius, speed, omega, rho, power); PistonEngine* eng = new PistonEngine(engP, engS); - PropEngine* thruster = new PropEngine(prop, eng, moment); - _airplane.addThruster(thruster, mass, cg); if(a->hasAttribute("displacement")) eng->setDisplacement(attrf(a, "displacement") * CIN2CM); @@ -630,6 +623,66 @@ void FGFDM::parsePropeller(XMLAttributes* a) eng->setTurboParams(mul, mp); } + ((PropEngine*)_currObj)->setEngine(eng); +} + +void FGFDM::parseTurbineEngine(XMLAttributes* a) +{ + float power = attrf(a, "eng-power") * HP2W; + float omega = attrf(a, "eng-rpm") * RPM2RAD; + float alt = attrf(a, "alt") * FT2M; + float flatRating = attrf(a, "flat-rating") * HP2W; + TurbineEngine* eng = new TurbineEngine(power, omega, alt, flatRating); + + if(a->hasAttribute("min-n2")) + eng->setN2Range(attrf(a, "min-n2"), attrf(a, "max-n2")); + + // Nasty units conversion: lbs/hr per hp -> kg/s per watt + if(a->hasAttribute("bsfc")) + eng->setFuelConsumption(attrf(a, "bsfc") * (LBS2KG/(3600*HP2W))); + + ((PropEngine*)_currObj)->setEngine(eng); +} + +void FGFDM::parsePropeller(XMLAttributes* a) +{ + // Legacy Handling for the old engines syntax: + PistonEngine* eng = 0; + if(a->hasAttribute("eng-power")) { + SG_LOG(SG_FLIGHT,SG_ALERT, "WARNING: " + << "Legacy engine definition in YASim configuration file. " + << "Please fix."); + float engP = attrf(a, "eng-power") * HP2W; + float engS = attrf(a, "eng-rpm") * RPM2RAD; + eng = new PistonEngine(engP, engS); + if(a->hasAttribute("displacement")) + eng->setDisplacement(attrf(a, "displacement") * CIN2CM); + if(a->hasAttribute("compression")) + eng->setCompression(attrf(a, "compression")); + if(a->hasAttribute("turbo-mul")) { + float mul = attrf(a, "turbo-mul"); + float mp = attrf(a, "wastegate-mp", 1e6) * INHG2PA; + eng->setTurboParams(mul, mp); + } + } + + // Now parse the actual propeller definition: + float cg[3]; + cg[0] = attrf(a, "x"); + cg[1] = attrf(a, "y"); + cg[2] = attrf(a, "z"); + float mass = attrf(a, "mass") * LBS2KG; + float moment = attrf(a, "moment"); + float radius = attrf(a, "radius"); + float speed = attrf(a, "cruise-speed") * KTS2MPS; + float omega = attrf(a, "cruise-rpm") * RPM2RAD; + float power = attrf(a, "cruise-power") * HP2W; + float rho = Atmosphere::getStdDensity(attrf(a, "cruise-alt") * FT2M); + + Propeller* prop = new Propeller(radius, speed, omega, rho, power); + PropEngine* thruster = new PropEngine(prop, eng, moment); + _airplane.addThruster(thruster, mass, cg); + if(a->hasAttribute("takeoff-power")) { float power0 = attrf(a, "takeoff-power") * HP2W; float omega0 = attrf(a, "takeoff-rpm") * RPM2RAD; diff --git a/src/FDM/YASim/FGFDM.hpp b/src/FDM/YASim/FGFDM.hpp index d5e02471d..66a842ba1 100644 --- a/src/FDM/YASim/FGFDM.hpp +++ b/src/FDM/YASim/FGFDM.hpp @@ -41,6 +41,8 @@ private: int parseAxis(const char* name); int parseOutput(const char* name); void parseWeight(XMLAttributes* a); + void parseTurbineEngine(XMLAttributes* a); + void parsePistonEngine(XMLAttributes* a); void parsePropeller(XMLAttributes* a); bool eq(const char* a, const char* b); bool caseeq(const char* a, const char* b); diff --git a/src/FDM/YASim/Makefile.am b/src/FDM/YASim/Makefile.am index 2d4e557ae..2311fbb11 100644 --- a/src/FDM/YASim/Makefile.am +++ b/src/FDM/YASim/Makefile.am @@ -18,9 +18,11 @@ SHARED_SOURCE_FILES = \ Jet.cpp Jet.hpp \ Math.cpp Math.hpp \ Model.cpp Model.hpp \ - PistonEngine.cpp PistonEngine.hpp \ PropEngine.cpp PropEngine.hpp \ Propeller.cpp Propeller.hpp \ + Engine.hpp \ + PistonEngine.cpp PistonEngine.hpp \ + TurbineEngine.cpp TurbineEngine.hpp \ RigidBody.cpp RigidBody.hpp \ Rotor.cpp Rotor.hpp \ Rotorblade.cpp Rotorblade.hpp \ diff --git a/src/FDM/YASim/PropEngine.cpp b/src/FDM/YASim/PropEngine.cpp index 9b7afdc67..a6474bc90 100644 --- a/src/FDM/YASim/PropEngine.cpp +++ b/src/FDM/YASim/PropEngine.cpp @@ -113,6 +113,7 @@ void PropEngine::stabilize() float ptau, dummy; _prop->calc(_rho, speed, _omega * _gearRatio, &dummy, &ptau); _eng->calc(_pressure, _temp, _omega); + _eng->stabilize(); float etau = _eng->getTorque(); float tdiff = etau - ptau; @@ -157,6 +158,7 @@ void PropEngine::integrate(float dt) _prop->calc(_rho, speed, _omega * _gearRatio, &thrust, &propTorque); _eng->calc(_pressure, _temp, _omega); + _eng->integrate(dt); engTorque = _eng->getTorque(); _fuelFlow = _eng->getFuelFlow(); diff --git a/src/FDM/YASim/PropEngine.hpp b/src/FDM/YASim/PropEngine.hpp index 92ad8549e..4094b2d2c 100644 --- a/src/FDM/YASim/PropEngine.hpp +++ b/src/FDM/YASim/PropEngine.hpp @@ -2,17 +2,19 @@ #define _PROPENGINE_HPP #include "Thruster.hpp" +#include "Engine.hpp" namespace yasim { class Propeller; -class Engine; class PropEngine : public Thruster { public: PropEngine(Propeller* prop, Engine* eng, float moment); virtual ~PropEngine(); + void setEngine(Engine* eng) { delete _eng; _eng = eng; } + void setMagnetos(int magnetos); void setAdvance(float advance); void setPropPitch(float proppitch); diff --git a/src/FDM/YASim/TurbineEngine.cpp b/src/FDM/YASim/TurbineEngine.cpp new file mode 100644 index 000000000..4be094e18 --- /dev/null +++ b/src/FDM/YASim/TurbineEngine.cpp @@ -0,0 +1,61 @@ +#include "Atmosphere.hpp" + +#include "TurbineEngine.hpp" + +namespace yasim { + +TurbineEngine::TurbineEngine(float power, float omega, float alt, + float flatRating) +{ + _rho0 = Atmosphere::getStdDensity(0); + _maxTorque = (power/omega) * _rho0 / Atmosphere::getStdDensity(alt); + _flatRating = flatRating; + _bsfc = 0.047; // == 0.5 lb/hr per hp + _n2Min = 65; + _n2Max = 100; + + _rho = _rho0; + _omega = 0; + _n2 = _n2Target = _n2Min; + _torque = 0; + _fuelFlow = 0; +} + +void TurbineEngine::setOutputFromN2() +{ + float frac = (_n2 - _n2Min) / (_n2Max - _n2Min); + _torque = frac * _maxTorque * (_rho / _rho0); + _fuelFlow = _bsfc * _torque * _omega; +} + +void TurbineEngine::stabilize() +{ + _n2 = _n2Target; + setOutputFromN2(); +} + +void TurbineEngine::integrate(float dt) +{ + // Low-pass the N2 speed to give a realistic spooling time. See + // the notes in Jet::setSpooling() for details; this corresponds + // to a hard-coded spool time of 2 seconds. + const float DECAY = 1.15; + _n2 = (_n2 + dt * DECAY * _n2Target)/(1 + dt * DECAY); + setOutputFromN2(); +} + +void TurbineEngine::calc(float pressure, float temp, float omega) +{ + _omega = omega; + _rho = Atmosphere::calcStdDensity(pressure, temp); + + float torque = _throttle * _maxTorque * _rho / _rho0; + float power = torque * omega; + if(power > _flatRating) + torque = _flatRating / omega; + + float frac = torque / (_maxTorque * (_rho / _rho0)); + _n2Target = _n2Min + (_n2Max - _n2Min) * frac; +} + +}; // namespace yasim diff --git a/src/FDM/YASim/TurbineEngine.hpp b/src/FDM/YASim/TurbineEngine.hpp new file mode 100644 index 000000000..09c0233d2 --- /dev/null +++ b/src/FDM/YASim/TurbineEngine.hpp @@ -0,0 +1,46 @@ +#ifndef _TURBINEENGINE_HPP +#define _TURBINEENGINE_HPP + +#include "Engine.hpp" + +namespace yasim { + +class TurbineEngine : public Engine { +public: + virtual TurbineEngine* isTurbineEngine() { return this; } + + TurbineEngine(float power, float omega, float alt, float flatRating); + void setN2Range(float min, float max) { _n2Min = min; _n2Max = max; } + void setFuelConsumption(float bsfc) { _bsfc = bsfc; } + + virtual void calc(float pressure, float temp, float speed); + virtual void stabilize(); + virtual void integrate(float dt); + + virtual float getTorque() { return _torque; } + virtual float getFuelFlow() { return _fuelFlow; } + float getN2() { return _n2; } + +private: + void setOutputFromN2(); + + float _maxTorque; + float _flatRating; + float _rho0; + float _bsfc; // SI units! kg/s per watt + float _n2Min; + float _n2Max; + + float _n2Target; + float _torqueTarget; + float _fuelFlowTarget; + + float _n2; + float _rho; + float _omega; + float _torque; + float _fuelFlow; +}; + +}; // namespace yasim +#endif // _TURBINEENGINE_HPP