From 97b75a79bff9b9bafef9246d8d03fb3e1911aced Mon Sep 17 00:00:00 2001
From: andy <andy>
Date: Mon, 27 Feb 2006 23:35:02 +0000
Subject: [PATCH] Inspired by a patch from Vivian, this adds a settable
 "WASTEGATE" control to piston engines that allows external scripts to control
 the turbo/supercharger boost programatically by setting this axis to values
 in the range [0:1].  It also adds a "turbo-lag" attribute (a time in seconds)
 to engines implementing turbocharger spooling delays.

This isn't terribly well tested, but doesn't seem to have broken
anything.
---
 src/FDM/YASim/ControlMap.cpp   |  3 +++
 src/FDM/YASim/ControlMap.hpp   |  2 +-
 src/FDM/YASim/FGFDM.cpp        |  3 +++
 src/FDM/YASim/PistonEngine.cpp | 24 +++++++++++++++++++++---
 src/FDM/YASim/PistonEngine.hpp | 10 +++++++++-
 src/FDM/YASim/PropEngine.cpp   |  8 ++++++++
 6 files changed, 45 insertions(+), 5 deletions(-)

diff --git a/src/FDM/YASim/ControlMap.cpp b/src/FDM/YASim/ControlMap.cpp
index cd7174cc5..77f9a3fd6 100644
--- a/src/FDM/YASim/ControlMap.cpp
+++ b/src/FDM/YASim/ControlMap.cpp
@@ -215,6 +215,9 @@ void ControlMap::applyControls(float dt)
 	case BOOST:
 	    ((PistonEngine*)((Thruster*)obj)->getEngine())->setBoost(lval);
 	    break;
+        case WASTEGATE:
+            ((PistonEngine*)((Thruster*)obj)->getEngine())->setWastegate(lval);
+            break;
 	}
     }
 }
diff --git a/src/FDM/YASim/ControlMap.hpp b/src/FDM/YASim/ControlMap.hpp
index 75e553216..8fdd2afba 100644
--- a/src/FDM/YASim/ControlMap.hpp
+++ b/src/FDM/YASim/ControlMap.hpp
@@ -15,7 +15,7 @@ public:
 		      INCIDENCE, FLAP0, FLAP1, SLAT, SPOILER, VECTOR,
                       BOOST, CASTERING, PROPPITCH, PROPFEATHER,
                       COLLECTIVE, CYCLICAIL, CYCLICELE, ROTORENGINEON,
-                      REVERSE_THRUST };
+                      REVERSE_THRUST, WASTEGATE };
 
     enum { OPT_SPLIT  = 0x01,
            OPT_INVERT = 0x02,
diff --git a/src/FDM/YASim/FGFDM.cpp b/src/FDM/YASim/FGFDM.cpp
index c883ebd1f..1d4a6d033 100644
--- a/src/FDM/YASim/FGFDM.cpp
+++ b/src/FDM/YASim/FGFDM.cpp
@@ -701,6 +701,9 @@ void FGFDM::parsePistonEngine(XMLAttributes* a)
         eng->setTurboParams(mul, mp);
     }
 
+    if(a->hasAttribute("supercharger"))
+        eng->setSupercharger(attrb(a, "supercharger"));
+
     ((PropEngine*)_currObj)->setEngine(eng);
 }
 
diff --git a/src/FDM/YASim/PistonEngine.cpp b/src/FDM/YASim/PistonEngine.cpp
index 6bb297c11..c3dbe5c3b 100644
--- a/src/FDM/YASim/PistonEngine.cpp
+++ b/src/FDM/YASim/PistonEngine.cpp
@@ -36,6 +36,9 @@ PistonEngine::PistonEngine(float power, float speed)
 
     _turbo = 1;
     _maxMP = 1e6; // No waste gate on non-turbo engines.
+    _wastegate = 1;
+    _charge = 1;
+    _chargeTarget = 1;
 
     // Guess at reasonable values for these guys.  Displacements run
     // at about 2 cubic inches per horsepower or so, at least for
@@ -100,11 +103,16 @@ float PistonEngine::getEGT()
 void PistonEngine::stabilize()
 {
     _oilTemp = _oilTempTarget;
+    _charge = _chargeTarget;
 }
 
 void PistonEngine::integrate(float dt) 
 {
     _oilTemp += (_dOilTempdt * dt);
+
+    // See comments in Jet.cpp for how this decay constant works
+    float decay = 1.5f * 2.3f / _turboLag;
+    _charge = (_charge + dt*decay * _chargeTarget) / (1 + dt*decay);
 }
 
 void PistonEngine::calc(float pressure, float temp, float speed)
@@ -128,17 +136,27 @@ void PistonEngine::calc(float pressure, float temp, float speed)
     float B = 0.55620178;
     float C = 1.246708471;
     float rpm_factor = A * Math::pow(B, rpm_norm) * Math::pow(rpm_norm, C);
+    _chargeTarget = 1 + (_boost * (_turbo-1) * rpm_factor);
+
+    if(_hasSuper) {
+        // Superchargers have no lag
+        _charge = _chargeTarget;
+    } else if(!_running) {
+        // Turbochargers only work when the engine is actually
+        // running.  The 25% number is a guesstimate from Vivian.
+        _chargeTarget = 1 + (_chargeTarget - 1) * 0.25;
+    }
 
     // We need to adjust the minimum manifold pressure to get a
     // reasonable idle speed (a "closed" throttle doesn't suck a total
     // vacuum in real manifolds).  This is a hack.
     float _minMP = (-0.008 * _turbo ) + 0.1;
 
+    _mp = pressure * _charge;
+
     // Scale to throttle setting, clamp to wastegate
-    if(_running) {
-        _mp = pressure * (1 + (_boost * (_turbo-1) * rpm_factor));
+    if(_running)
         _mp *= _minMP + (1 -_minMP) * _throttle;
-    }
     if(_mp > _maxMP) _mp = _maxMP;
 
     // The "boost" is the delta above ambient
diff --git a/src/FDM/YASim/PistonEngine.hpp b/src/FDM/YASim/PistonEngine.hpp
index 7ce647acd..4aa3e5670 100644
--- a/src/FDM/YASim/PistonEngine.hpp
+++ b/src/FDM/YASim/PistonEngine.hpp
@@ -14,6 +14,9 @@ public:
     void setTurboParams(float mul, float maxMP);
     void setDisplacement(float d);
     void setCompression(float c);
+    void setWastegate(float norm) { _wastegate = norm; }
+    void setSupercharger(float hasSuper) { _hasSuper = hasSuper; }
+    void setTurboLag(float lag) { _turboLag = lag; }
 
     bool isCranking();
     float getMP();
@@ -36,7 +39,12 @@ private:
     float _f0;       // "ideal" fuel flow at P0/omega0
     float _mixCoeff; // fuel flow per omega at full mixture
     float _turbo;    // (or super-)charger pressure multiplier
-    float _maxMP;    // wastegate setting
+    bool _hasSuper;  // true indicates gear-driven (not turbo)
+    float _turboLag; // turbo lag time in seconds
+    float _charge;   // current {turbo|super}charge multiplier
+    float _chargeTarget;  // eventual charge value
+    float _maxMP;    // static maximum pressure
+    float _wastegate;    // wastegate setting, [0:1]
     float _displacement; // piston stroke volume
     float _compression;  // compression ratio (>1)
 
diff --git a/src/FDM/YASim/PropEngine.cpp b/src/FDM/YASim/PropEngine.cpp
index 38cb886e8..c6581f445 100644
--- a/src/FDM/YASim/PropEngine.cpp
+++ b/src/FDM/YASim/PropEngine.cpp
@@ -127,6 +127,14 @@ void PropEngine::stabilize()
 	_eng->calc(_pressure, _temp, _omega);
         _eng->stabilize();
 
+        // Do it again -- the turbo sets the target MP in the first
+        // run, stabilize sets the current to the target, then we need
+        // to run again to get the correct output torque.  Clumsy, but
+        // it works without side effects (other than solver
+        // performance).  In the future, the Engine objects should
+        // store state to allow them to do the work themselves.
+	_eng->calc(_pressure, _temp, _omega);
+
         // Compute torque as seen by the engine's end of the gearbox.
         // The propeller will be moving more slowly (for gear ratios
         // less than one), so it's torque will be higher than the