]> git.mxchange.org Git - flightgear.git/commitdiff
Updated to YASim-0.1.1
authorcurt <curt>
Thu, 6 Dec 2001 18:13:24 +0000 (18:13 +0000)
committercurt <curt>
Thu, 6 Dec 2001 18:13:24 +0000 (18:13 +0000)
24 files changed:
src/FDM/YASim/Airplane.cpp
src/FDM/YASim/Airplane.hpp
src/FDM/YASim/Atmosphere.cpp
src/FDM/YASim/ControlMap.cpp
src/FDM/YASim/ControlMap.hpp
src/FDM/YASim/FGFDM.cpp
src/FDM/YASim/Gear.cpp
src/FDM/YASim/Jet.cpp
src/FDM/YASim/Jet.hpp
src/FDM/YASim/Math.cpp
src/FDM/YASim/Math.hpp
src/FDM/YASim/Model.cpp
src/FDM/YASim/Model.hpp
src/FDM/YASim/PistonEngine.cpp
src/FDM/YASim/PistonEngine.hpp
src/FDM/YASim/PropEngine.cpp
src/FDM/YASim/PropEngine.hpp
src/FDM/YASim/Propeller.cpp
src/FDM/YASim/Propeller.hpp
src/FDM/YASim/Surface.cpp
src/FDM/YASim/Thruster.cpp
src/FDM/YASim/Thruster.hpp
src/FDM/YASim/Wing.cpp
src/FDM/YASim/Wing.hpp

index 93a822a3ebc4b614d855f3ecea561884c8ec6b3b..3d76fff548560e8259319cf1efaa38c6aa1d18fa 100644 (file)
@@ -10,8 +10,6 @@
 #include "Airplane.hpp"
 namespace yasim {
 
-// FIXME: hook gear extension into the force calculation somehow...
-
 Airplane::Airplane()
 {
     _emptyWeight = 0;
@@ -19,10 +17,12 @@ Airplane::Airplane()
     _wing = 0;
     _tail = 0;
     _ballast = 0;
-    _cruiseRho = 0;
+    _cruiseP = 0;
+    _cruiseT = 0;
     _cruiseSpeed = 0;
     _cruiseWeight = 0;
-    _approachRho = 0;
+    _approachP = 0;
+    _approachT = 0;
     _approachSpeed = 0;
     _approachAoA = 0;
     _approachWeight = 0;
@@ -51,8 +51,7 @@ void Airplane::iterate(float dt)
 {
     _model.iterate();
 
-    // Consume fuel
-    // FIXME
+    // FIXME: Consume fuel
 }
 
 ControlMap* Airplane::getControlMap()
@@ -139,14 +138,16 @@ void Airplane::setApproach(float speed, float altitude)
 void Airplane::setApproach(float speed, float altitude, float aoa)
 {
     _approachSpeed = speed;
-    _approachRho = Atmosphere::getStdDensity(altitude);
+    _approachP = Atmosphere::getStdPressure(altitude);
+    _approachT = Atmosphere::getStdTemperature(altitude);
     _approachAoA = aoa;
 }
  
 void Airplane::setCruise(float speed, float altitude)
 {
     _cruiseSpeed = speed;
-    _cruiseRho = Atmosphere::getStdDensity(altitude);
+    _cruiseP = Atmosphere::getStdPressure(altitude);
+    _cruiseT = Atmosphere::getStdTemperature(altitude);
     _cruiseAoA = 0;
     _tailIncidence = 0;
 }
@@ -254,6 +255,7 @@ int Airplane::addWeight(float* pos, float size)
     wr->handle = _model.getBody()->addMass(0, pos);
 
     wr->surf = new Surface();
+    wr->surf->setPosition(pos);
     wr->surf->setTotalDrag(size*size);
     _model.addSurface(wr->surf);
     _surfs.add(wr->surf);
@@ -364,7 +366,7 @@ float Airplane::compileFuselage(Fuselage* f)
     float len = Math::mag3(fwd);
     float wid = f->width;
     int segs = (int)Math::ceil(len/wid);
-    float segWgt = wid*wid/segs;
+    float segWgt = len*wid/segs;
     for(int j=0; j<segs; j++) {
         float frac = (j+0.5) / segs;
         float pos[3];
@@ -406,10 +408,11 @@ void Airplane::compileGear(GearRec* gr)
 
     // Put the surface at the half-way point on the gear strut, give
     // it a drag coefficient equal to a square of the same dimension
-    // (gear are really draggy) and make it symmetric.
+    // (gear are really draggy) and make it symmetric.  Assume that
+    // the "length" of the gear is 3x the compression distance
     float pos[3], cmp[3];
     g->getCompression(cmp);
-    float length = Math::mag3(cmp);
+    float length = 3 * Math::mag3(cmp);
     g->getPosition(pos);
     Math::mul3(0.5, cmp, cmp);
     Math::add3(pos, cmp, pos);
@@ -486,6 +489,11 @@ void Airplane::compile()
         tr->handle = _model.addThruster(tr->thruster);
     }
 
+    // Ground effect
+    float gepos[3];
+    float gespan = _wing->getGroundEffect(gepos);
+    _model.setGroundEffect(gepos, gespan, .3);
+
     solveGear();
     solve();
 
@@ -550,31 +558,15 @@ void Airplane::solveGear()
 
 void Airplane::stabilizeThrust()
 {
-    float thrust[3], tmp[3];
-    float last = 0;
-    while(1) {
-        thrust[0] = thrust[1] = thrust[2] = 0;
-        for(int i=0; i<_thrusters.size(); i++) {
-            Thruster* t = _model.getThruster(i);
-            t->integrate(0.033);
-            t->getThrust(tmp);
-            Math::add3(thrust, tmp, thrust);
-        }
-
-        float t = Math::mag3(thrust);
-        float ratio = (t+0.1)/(last+0.1);
-       if(ratio < 1.00001 && ratio > 0.99999)
-           break;
-
-        last = t;
-    }
+    for(int i=0; i<_thrusters.size(); i++)
+       _model.getThruster(i)->stabilize();
 }
 
 void Airplane::runCruise()
 {
     setupState(_cruiseAoA, _cruiseSpeed, &_cruiseState);
     _model.setState(&_cruiseState);
-    _model.setAirDensity(_cruiseRho);
+    _model.setAir(_cruiseP, _cruiseT);
 
     // The control configuration
     _controls.reset();
@@ -600,7 +592,7 @@ void Airplane::runCruise()
     for(int i=0; i<_thrusters.size(); i++) {
        Thruster* t = ((ThrustRec*)_thrusters.get(i))->thruster;
        t->setWind(wind);
-       t->setDensity(_cruiseRho);
+       t->setAir(_cruiseP, _cruiseT);
     }
     stabilizeThrust();
 
@@ -614,7 +606,7 @@ void Airplane::runApproach()
 {
     setupState(_approachAoA, _approachSpeed, &_approachState);
     _model.setState(&_approachState);
-    _model.setAirDensity(_approachRho);
+    _model.setAir(_approachP, _approachT);
 
     // The control configuration
     _controls.reset();
@@ -640,7 +632,7 @@ void Airplane::runApproach()
     for(int i=0; i<_thrusters.size(); i++) {
        Thruster* t = ((ThrustRec*)_thrusters.get(i))->thruster;
        t->setWind(wind);
-       t->setDensity(_approachRho);
+       t->setAir(_approachP, _approachT);
     }
     stabilizeThrust();
 
index 250d1e15ebb4c073869e24fe9dfeeaffc0edb3e1..46fab823e44c72e08d03f8aeeb94e1a4b5dc8831 100644 (file)
@@ -112,13 +112,15 @@ private:
 
     Vector _cruiseControls;
     State _cruiseState;
-    float _cruiseRho;
+    float _cruiseP;
+    float _cruiseT;
     float _cruiseSpeed;
     float _cruiseWeight;
 
     Vector _approachControls;
     State _approachState;
-    float _approachRho;
+    float _approachP;
+    float _approachT;
     float _approachSpeed;
     float _approachAoA;
     float _approachWeight;
index c331b2fafde8e65a2ec24142a6b51f25e20bca80..7e532dd654a7b87d519ab9d0ecb9a01f47ddcce2 100644 (file)
@@ -7,7 +7,7 @@ namespace yasim {
 // McCormick lists 299.16/101325/1.22500, but those don't agree with
 // R=287.  I chose to correct the temperature to 288.20, since 79F is
 // pretty hot for a "standard" atmosphere.
-//                             meters   kelvin     kPa   kg/m^3
+//                             meters   kelvin      Pa   kg/m^3
 float Atmosphere::data[][4] = {{ 0,     288.20, 101325, 1.22500 },
                               { 900,   282.31,  90971, 1.12260 },
                               { 1800,  276.46,  81494, 1.02690 },
index e738b5b083354ad4caf6b50da825525d0c825027..0a90b71b432a838483e81d113b20078c7d43f12c 100644 (file)
@@ -1,5 +1,6 @@
 #include "Jet.hpp"
 #include "Thruster.hpp"
+#include "PropEngine.hpp"
 #include "Gear.hpp"
 #include "Wing.hpp"
 #include "Math.hpp"
@@ -114,7 +115,7 @@ void ControlMap::applyControls()
        switch(o->type) {
        case THROTTLE: ((Thruster*)obj)->setThrottle(lval);    break;
        case MIXTURE:  ((Thruster*)obj)->setMixture(lval);     break;
-       case PROP:     ((Thruster*)obj)->setPropAdvance(lval); break;
+       case ADVANCE:  ((PropEngine*)obj)->setAdvance(lval);   break;
        case REHEAT:   ((Jet*)obj)->setReheat(lval);           break;
        case BRAKE:    ((Gear*)obj)->setBrake(lval);           break;
        case STEER:    ((Gear*)obj)->setRotation(lval);        break;
index 0534298cf4efe3955c1f0fef5a81aa9ad172fe98..370181f6b7957038c6911e215d3d82db212f47a9 100644 (file)
@@ -9,7 +9,7 @@ class ControlMap {
 public:
     ~ControlMap();
 
-    enum OutputType { THROTTLE, MIXTURE, REHEAT, PROP,
+    enum OutputType { THROTTLE, MIXTURE, ADVANCE, REHEAT, PROP,
                      BRAKE, STEER, EXTEND,
                      INCIDENCE, FLAP0, FLAP1, SLAT, SPOILER };
 
index f606b15fa2d4dfc81fb7299ec292890b1c513704..085bbc25c60cff2952e4df742b2ad4442cceed27 100644 (file)
@@ -22,6 +22,7 @@ static const float LBS2N = 4.44822;
 static const float LBS2KG = 0.45359237;
 static const float CM2GALS = 264.172037284;
 static const float HP2W = 745.700;
+static const float INHG2PA = 3386.389;
 
 // Stubs, so that this can be compiled without the FlightGear
 // binary.  What's the best way to handle this?
@@ -141,6 +142,7 @@ void FGFDM::startElement(const char* name, const XMLAttributes &atts)
        v[2] = attrf(a, "z");
        float mass = attrf(a, "mass") * LBS2KG;
        j->setDryThrust(attrf(a, "thrust") * LBS2N);
+       j->setReheatThrust(attrf(a, "afterburner", 0) * LBS2N);
        j->setPosition(v);
        _airplane.addThruster(j, mass, v);
        sprintf(buf, "/engines/engine[%d]", _nextEngine++);
@@ -333,21 +335,36 @@ void FGFDM::parsePropeller(XMLAttributes* a)
     float radius = attrf(a, "radius");
     float speed = attrf(a, "cruise-speed") * KTS2MPS;
     float omega = attrf(a, "cruise-rpm") * RPM2RAD;
-    float rho = Atmosphere::getStdDensity(attrf(a, "alt") * FT2M);
-    float power = attrf(a, "takeoff-power") * HP2W;
-    float omega0 = attrf(a, "takeoff-rpm") * RPM2RAD;
-    
-    // FIXME: this is a hack.  Find a better way to ask the engine how
-    // much power it can produce under cruise conditions.
-    float cruisePower = (power * (rho/Atmosphere::getStdDensity(0))
-                        * (omega/omega0));
-
-    Propeller* prop = new Propeller(radius, speed, omega, rho, cruisePower,
-                                    omega0, power);
-    PistonEngine* eng = new PistonEngine(power, omega0);
+    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("turbo-mul")) {
+        float mul = attrf(a, "turbo-mul");
+        float mp = attrf(a, "wastegate-mp", 1e6) * INHG2PA;
+        eng->setTurboParams(mul, mp);
+    }
+
+    if(a->hasAttribute("takeoff-power")) {
+       float power0 = attrf(a, "takeoff-power") * HP2W;
+       float omega0 = attrf(a, "takeoff-rpm") * RPM2RAD;
+       prop->setTakeoff(omega0, power0);
+    }
+
+    if(a->hasAttribute("max-rpm")) {
+       float max = attrf(a, "max-rpm") * RPM2RAD;
+       float min = attrf(a, "min-rpm") * RPM2RAD;
+       thruster->setVariableProp(min, max);
+    }
+
     char buf[64];
     sprintf(buf, "/engines/engine[%d]", _nextEngine++);
     EngRec* er = new EngRec();
@@ -381,6 +398,7 @@ int FGFDM::parseOutput(const char* name)
 {
     if(eq(name, "THROTTLE"))  return ControlMap::THROTTLE;
     if(eq(name, "MIXTURE"))   return ControlMap::MIXTURE;
+    if(eq(name, "ADVANCE"))   return ControlMap::ADVANCE;
     if(eq(name, "REHEAT"))    return ControlMap::REHEAT;
     if(eq(name, "PROP"))      return ControlMap::PROP;
     if(eq(name, "BRAKE"))     return ControlMap::BRAKE;
index 056bc61a470909e3b8809ba16bfccb2dee1500a2..cd02dad1da1819fbe8e12e3b64c6719e4f2100b2 100644 (file)
@@ -49,7 +49,7 @@ void Gear::setDynamicFriction(float dfric)
 
 void Gear::setBrake(float brake)
 {
-    _brake = brake;
+    _brake = Math::clamp(brake, 0, 1);
 }
 
 void Gear::setRotation(float rotation)
@@ -59,7 +59,7 @@ void Gear::setRotation(float rotation)
 
 void Gear::setExtension(float extension)
 {
-    _extension = extension;
+    _extension = Math::clamp(extension, 0, 1);
 }
 
 void Gear::getPosition(float* out)
index b4169b69b52581e014dda5472d8a9aedb65ddc99..001196b53bca8123f14b61d3b57c2217f9fcf745 100644 (file)
@@ -7,15 +7,13 @@ Jet::Jet()
 {
     _rho0 = Atmosphere::getStdDensity(0);
     _thrust = 0;
+    _abThrust = 0;
     _reheat = 0;
 }
 
-Thruster* Jet::clone()
+void Jet::stabilize()
 {
-    Jet* j = new Jet();
-    j->_thrust = _thrust;
-    j->_rho0 = _rho0;
-    return j;
+    return; // no-op for now
 }
 
 void Jet::setDryThrust(float thrust)
@@ -23,14 +21,21 @@ void Jet::setDryThrust(float thrust)
     _thrust = thrust;
 }
 
+void Jet::setReheatThrust(float thrust)
+{
+    _abThrust = thrust;
+}
+
 void Jet::setReheat(float reheat)
 {
-    _reheat = reheat;
+    _reheat = Math::clamp(reheat, 0, 1);
 }
 
 void Jet::getThrust(float* out)
 {
-    float t = _thrust * _throttle * (_rho / _rho0);
+    float t = _thrust * _throttle;
+    t += (_abThrust - _thrust) * _reheat;
+    t *= _rho / _rho0;
     Math::mul3(t, _dir, out);
 }
 
index c51e3027657cde718eb58dd65acba712dd02cf0f..40b4c4d9e9cb34ab110d63117b13dc360899a1e6 100644 (file)
@@ -11,9 +11,10 @@ class Jet : public Thruster {
 public:
     Jet();
 
-    virtual Thruster* clone();
+    virtual Jet* getJet() { return this; }
 
     void setDryThrust(float thrust);
+    void setReheatThrust(float thrust);
     void setReheat(float reheat);
 
     virtual void getThrust(float* out);
@@ -21,9 +22,11 @@ public:
     virtual void getGyro(float* out);
     virtual float getFuelFlow();
     virtual void integrate(float dt);
+    virtual void stabilize();
 
 private:
     float _thrust;
+    float _abThrust;
     float _rho0;
     float _reheat;
 };
index 0af57a03f1ba178917fca37fdee72b4245dc2b59..53a8aef74f4d4973b4becd974355f1d41885cd87 100644 (file)
@@ -3,6 +3,13 @@
 #include "Math.hpp"
 namespace yasim {
 
+float Math::clamp(float val, float min, float max)
+{
+    if(val < min) return min;
+    if(val > max) return max;
+    return val;
+}
+
 float Math::abs(float f)
 {
     return ::fabs(f);
index 9407c2a9aa3a01596995258848f446e0e5c081c8..ef97f17f21ae7e1905c1a1ec942a032db80563c4 100644 (file)
@@ -6,6 +6,9 @@ namespace yasim {
 class Math
 {
 public:
+    // Dumb utilities
+    static float clamp(float val, float min, float max);
+
     // Simple wrappers around library routines
     static float abs(float f);
     static float sqrt(float f);
index 5cd77e9cbadfc4632453ecc5bdb9e59d701a8a87..ce5ea4c5ae4ade81ac3497dc4fd5b1d0a5583d3b 100644 (file)
@@ -77,7 +77,7 @@ void Model::initIteration()
         localWind(pos, _s, v);
 
        t->setWind(v);
-       t->setDensity(_rho);
+       t->setAir(_P, _T);
        t->integrate(_integrator.getInterval());
 
        t->getTorque(v);
@@ -126,6 +126,11 @@ int Model::addThruster(Thruster* t)
     return _thrusters.add(t);
 }
 
+int Model::numThrusters()
+{
+    return _thrusters.size();
+}
+
 Thruster* Model::getThruster(int handle)
 {
     return (Thruster*)_thrusters.get(handle);
@@ -146,6 +151,13 @@ int Model::addGear(Gear* gear)
     return _gears.add(gear);
 }
 
+void Model::setGroundEffect(float* pos, float span, float mul)
+{
+    Math::set3(pos, _wingCenter);
+    _groundEffectSpan = span;
+    _groundEffect = mul;
+}
+
 // The first three elements are a unit vector pointing from the global
 // origin to the plane, the final element is the distance from the
 // origin (the radius of the earth, in most implementations).  So
@@ -156,13 +168,10 @@ void Model::setGroundPlane(double* planeNormal, double fromOrigin)
     _ground[3] = fromOrigin;
 }
 
-void Model::setAirDensity(float rho)
-{
-    _rho = rho;
-}
-
 void Model::setAir(float pressure, float temp)
 {
+    _P = pressure;
+    _T = temp;
     _rho = Atmosphere::calcDensity(pressure, temp);
 }
 
@@ -197,6 +206,8 @@ void Model::calcForces(State* s)
 
     // Do each surface, remembering that the local velocity at each
     // point is different due to rotation.
+    float faero[3];
+    faero[0] = faero[1] = faero[2] = 0;
     for(int i=0; i<_surfaces.size(); i++) {
        Surface* sf = (Surface*)_surfaces.get(i);
 
@@ -207,6 +218,7 @@ void Model::calcForces(State* s)
 
        float force[3], torque[3];
        sf->calcForce(vs, _rho, force, torque);
+       Math::add3(faero, force, faero);
        _body.addForce(pos, force);
        _body.addTorque(torque);
     }
@@ -218,6 +230,17 @@ void Model::calcForces(State* s)
     float ground[4];
     ground[3] = localGround(s, ground);
 
+    // Account for ground effect by multiplying the vertical force
+    // component by an amount linear with the fraction of the wingspan
+    // above the ground.
+    float dist = ground[4] - Math::dot3(ground, _wingCenter);
+    if(dist > 0 && dist < _groundEffectSpan) {
+       float fz = Math::dot3(faero, ground);
+       Math::mul3(fz * _groundEffect * dist/_groundEffectSpan,
+                  ground, faero);
+       _body.addForce(faero);
+    }
+    
     // Convert the velocity and rotation vectors to local coordinates
     float lrot[3], lv[3];
     Math::vmul33(s->orient, s->rot, lrot);
index a54799d01534552ee4feedb5de7b8ebfff49366f..0a32c63040ab76096868ac0cbcf43fac74b51ba2 100644 (file)
@@ -35,6 +35,7 @@ public:
     Gear* getGear(int handle);
 
     // Semi-private methods for use by the Airplane solver.
+    int numThrusters();
     Thruster* getThruster(int handle);
     void setThruster(int handle, Thruster* t);
     void initIteration();
@@ -44,8 +45,8 @@ public:
     // Per-iteration settables
     //
     void setGroundPlane(double* planeNormal, double fromOrigin);
+    void setGroundEffect(float* pos, float span, float mul);
     void setWind(float* wind);
-    void setAirDensity(float rho);
     void setAir(float pressure, float temp);
 
     // BodyEnvironment callbacks
@@ -65,7 +66,13 @@ private:
     Vector _surfaces;
     Vector _gears;
 
+    float _groundEffectSpan;
+    float _groundEffect;
+    float _wingCenter[3];
+
     double _ground[4];
+    float _P;
+    float _T;
     float _rho;
     float _wind[3];
 
index bea871f0b5e7a56f47946ca9b44edde4fa591ab2..5a6cff14c2272e1b737d22f76016e7f40fa13880 100644 (file)
@@ -1,3 +1,5 @@
+#include "Atmosphere.hpp"
+#include "Math.hpp"
 #include "PistonEngine.hpp"
 namespace yasim {
 
@@ -11,13 +13,34 @@ PistonEngine::PistonEngine(float power, float speed)
     _omega0 = speed;
 
     // We must be at sea level under standard conditions
-    _rho0 = 1.225; // kg/m^3
+    _rho0 = Atmosphere::getStdDensity(0);
 
     // Further presume that takeoff is (duh) full throttle and
     // peak-power, that means that by our efficiency function, we are
     // at 11/8 of "ideal" fuel flow.
     float realFlow = _f0 * (11.0/8.0);
     _mixCoeff = realFlow * 1.1 / _omega0;
+
+    _turbo = 1;
+    _maxMP = 1e6; // No waste gate on non-turbo engines.
+}
+
+void PistonEngine::setTurboParams(float turbo, float maxMP)
+{
+    _turbo = turbo;
+    _maxMP = maxMP;
+
+    // This changes the "sea level" manifold air density
+    float P0 = Atmosphere::getStdPressure(0);
+    float P = P0 * _turbo;
+    if(P > _maxMP) P = _maxMP;
+    float T = Atmosphere::getStdTemperature(0) * Math::pow(P/P0, 2./7.);
+    _rho0 = P / (287.1 * T);
+}
+
+float PistonEngine::getPower()
+{
+    return _P0;
 }
 
 void PistonEngine::setThrottle(float t)
@@ -30,13 +53,21 @@ void PistonEngine::setMixture(float m)
     _mixture = m;
 }
 
-void PistonEngine::calc(float density, float speed,
+void PistonEngine::calc(float P, float T, float speed,
                        float* torqueOut, float* fuelFlowOut)
 {
     // The actual fuel flow
     float fuel = _mixture * _mixCoeff * speed;
 
     // manifold air density
+    if(_turbo != 1) {
+        float P1 = P * _turbo;
+        if(P1 > _maxMP) P1 = _maxMP;
+        T *= Math::pow(P1/P, 2./7.);
+        P = P1;
+    }
+    float density = P / (287.1 * T);
+    
     float rho = density * _throttle;
 
     // How much fuel could be burned with ideal (i.e. uncorrected!)
index 95f43c438bdc16392c99568bfbe5410d1fa91ca0..acfc01baa3b60a3ab09c57d1d7667ba9670e36b8 100644 (file)
@@ -7,16 +7,19 @@ class PistonEngine {
 public:
     // Initializes an engine from known "takeoff" parameters.
     PistonEngine(float power, float spd);
+    void setTurboParams(float mul, float maxMP);
 
     void setThrottle(float throttle);
     void setMixture(float mixture);
 
+    float getPower();
+
     // Calculates power output and fuel flow, based on a given
     // throttle setting (0-1 corresponding to the fraction of
     // "available" manifold pressure), mixture (fuel flux per rpm,
     // 0-1, where 1 is "max rich", or a little bit more than needed
     // for rated power at sea level)
-    void calc(float density, float speed,
+    void calc(float pressure, float temp, float speed,
              float* powerOut, float* fuelFlowOut);
 
 private:
@@ -29,6 +32,9 @@ private:
     // Runtime settables:
     float _throttle;
     float _mixture;
+
+    float _turbo;
+    float _maxMP;
 };
 
 }; // namespace yasim
index 56ebae51dfe721e2b5c14790983e5b5b2ae1f319..73cca9a10f3c18ac6893eb2400b60b84113fe5fa 100644 (file)
@@ -10,6 +10,8 @@ PropEngine::PropEngine(Propeller* prop, PistonEngine* eng, float moment)
     _omega = 52.3;
     _dir[0] = 1; _dir[1] = 0; _dir[2] = 0;
 
+    _variable = false;
+
     _prop = prop;
     _eng = eng;
     _moment = moment;
@@ -21,19 +23,21 @@ PropEngine::~PropEngine()
     delete _eng;
 }
 
-float PropEngine::getOmega()
+void PropEngine::setAdvance(float advance)
 {
-    return _omega;
+    _advance = Math::clamp(advance, 0, 1);
 }
 
-Thruster* PropEngine::clone()
+void PropEngine::setVariableProp(float min, float max)
 {
-    // FIXME: bloody mess
-    PropEngine* p = new PropEngine(_prop, _eng, _moment);
-    cloneInto(p);
-    p->_prop = new Propeller(*_prop);
-    p->_eng = new PistonEngine(*_eng);
-    return p;
+    _variable = true;
+    _minOmega = min;
+    _maxOmega = max;
+}
+
+float PropEngine::getOmega()
+{
+    return _omega;
 }
 
 void PropEngine::getThrust(float* out)
@@ -56,6 +60,44 @@ float PropEngine::getFuelFlow()
     return _fuelFlow;
 }
 
+void PropEngine::stabilize()
+{
+    float speed = -Math::dot3(_wind, _dir);
+    _eng->setThrottle(_throttle);
+    _eng->setMixture(_mixture);
+
+    if(_variable) {
+       _omega = _minOmega + _advance * (_maxOmega - _minOmega);
+       _prop->modPitch(1e6); // Start at maximum pitch and move down
+    } else {
+       _omega = 52;
+    }
+
+    bool goingUp = false;
+    float step = 10;
+    while(true) {
+       float etau, ptau, dummy;
+       _prop->calc(_rho, speed, _omega, &dummy, &ptau);
+       _eng->calc(_P, _T, _omega, &etau, &dummy);
+       float tdiff = etau - ptau;
+
+       if(Math::abs(tdiff/_moment) < 0.1)
+           break;
+
+       if(tdiff > 0) {
+           if(!goingUp) step *= 0.5;
+           goingUp = true;
+           if(!_variable)  _omega += step;
+           else            _prop->modPitch(1+(step*0.005));
+       } else {
+           if(goingUp) step *= 0.5;
+           goingUp = false;
+           if(!_variable)  _omega -= step;
+           else            _prop->modPitch(1-(step*0.005));
+       }
+    }
+}
+
 void PropEngine::integrate(float dt)
 {
     float speed = -Math::dot3(_wind, _dir);
@@ -67,14 +109,19 @@ void PropEngine::integrate(float dt)
     
     _prop->calc(_rho, speed, _omega,
                &thrust, &propTorque);
-    _eng->calc(_rho, _omega, &engTorque, &_fuelFlow);
+    _eng->calc(_P, _T, _omega, &engTorque, &_fuelFlow);
 
     // Turn the thrust into a vector and save it
     Math::mul3(thrust, _dir, _thrust);
 
     // Euler-integrate the RPM.  This doesn't need the full-on
     // Runge-Kutta stuff.
-    _omega += dt*(engTorque-propTorque)/Math::abs(_moment);
+    float rotacc = (engTorque-propTorque)/Math::abs(_moment);
+    _omega += dt * rotacc;
+
+    // Clamp to a 500 rpm idle.  This should probably be settable, and
+    // needs to go away when the startup code gets written.
+    if(_omega < 52.3) _omega = 52.3;
 
     // FIXME: Integrate the propeller governor here, when that gets
     // implemented...
@@ -82,13 +129,25 @@ void PropEngine::integrate(float dt)
     // Store the total angular momentum into _gyro
     Math::mul3(_omega*_moment, _dir, _gyro);
 
-    // Accumulate the engine torque, it acta on the body as a whole.
+    // Accumulate the engine torque, it acts on the body as a whole.
     // (Note: engine torque, not propeller torque.  They can be
     // different, but the difference goes to accelerating the
     // rotation.  It is the engine torque that is felt at the shaft
     // and works on the body.)
     float tau = _moment < 0 ? engTorque : -engTorque;
     Math::mul3(tau, _dir, _torque);
+
+    // Play with the variable propeller, but only if the propeller is
+    // vaguely stable alread (accelerating less than 100 rpm/s)
+    if(_variable && Math::abs(rotacc) < 20) {
+       float target = _minOmega + _advance*(_maxOmega-_minOmega);
+       float mod = 1.04;
+       if(target > _omega) mod = 1/mod;
+       float diff = Math::abs(target - _omega);
+       if(diff < 1) mod = 1 + (mod-1)*diff;
+       if(thrust < 0) mod = 1;
+       _prop->modPitch(mod);
+    }
 }
 
 }; // namespace yasim
index 481552a29343d8cb73bad5876aafe58532a8b3d1..e861fb087891a1cbb05426519c560ed73a08f995 100644 (file)
@@ -12,8 +12,13 @@ class PropEngine : public Thruster {
 public:
     PropEngine(Propeller* prop, PistonEngine* eng, float moment);
     virtual ~PropEngine();
-    
-    virtual Thruster* clone();
+
+    void setAdvance(float advance);
+    void setVariableProp(float min, float max);
+
+    virtual PropEngine* getPropEngine() { return this; }
+    virtual PistonEngine* getPistonEngine() { return _eng; }
+    virtual Propeller* getPropeller() { return _prop; }
 
     // Dynamic output
     virtual void getThrust(float* out);
@@ -23,6 +28,7 @@ public:
 
     // Runtime instructions
     virtual void integrate(float dt);
+    virtual void stabilize();
 
     float getOmega();
     
@@ -31,6 +37,11 @@ private:
     Propeller* _prop;
     PistonEngine* _eng;
 
+    bool _variable;
+    float _advance; // control input, 0-1
+    float _maxOmega;
+    float _minOmega;
+
     float _omega; // RPM, in radians/sec
     float _thrust[3];
     float _torque[3];
index bce03ab8b42f41a5cd413be913ba7692c0769be8..9e6245120ae6cb075e28e929dbfa33f5a0b5f982 100644 (file)
@@ -1,36 +1,48 @@
+#include <stdio.h>
+
 #include "Atmosphere.hpp"
 #include "Math.hpp"
 #include "Propeller.hpp"
 namespace yasim {
 
 Propeller::Propeller(float radius, float v, float omega,
-                    float rho, float power, float omega0,
-                     float power0)
+                    float rho, float power)
 {
     // Initialize numeric constants:
-    _lambdaPeak = Math::pow(9.0, -1.0/8.0);
-    _beta = 1.0/(Math::pow(9.0, -1.0/8.0) - Math::pow(9.0, -9.0/8.0));
+    _lambdaPeak = Math::pow(5.0, -1.0/4.0);
+    _beta = 1.0/(Math::pow(5.0, -1.0/4.0) - Math::pow(5.0, -5.0/4.0));
 
     _r = radius;
     _etaC = 0.85; // make this settable?
 
     _J0 = v/(omega*_lambdaPeak);
+    _baseJ0 = _J0;
 
     float V2 = v*v + (_r*omega)*(_r*omega);
     _F0 = 2*_etaC*power/(rho*v*V2);
 
-    float stallAngle = 0.25;
-    _lambdaS = _r*(_J0/_r - stallAngle) / _J0;
+    _matchTakeoff = false;
+}
 
-    // Now compute a correction for zero forward speed to make the
-    // takeoff performance correct.
-    float torque0 = power0/omega0; 
-    float thrust, torque;
-    _takeoffCoef = 1;
-    calc(Atmosphere::getStdDensity(0), 0, omega0, &thrust, &torque);
-    _takeoffCoef = torque/torque0;
+void Propeller::setTakeoff(float omega0, float power0)
+{
+    // Takeoff thrust coefficient at lambda==0
+    _matchTakeoff = true;
+    float V2 = _r*omega0 * _r*omega0;
+    float gamma = _etaC * _beta / _J0;
+    float torque = power0 / omega0;
+    float density = Atmosphere::getStdDensity(0);
+    _tc0 = (torque * gamma) / (0.5 * density * V2 * _F0);
+}
+    
+void Propeller::modPitch(float mod)
+{
+    _J0 *= mod;
+    if(_J0 < 0.25*_baseJ0) _J0 = 0.25*_baseJ0;
+    if(_J0 > 4*_baseJ0)    _J0 = 4*_baseJ0;
 }
 
+
 void Propeller::calc(float density, float v, float omega,
                     float* thrustOut, float* torqueOut)
 {
@@ -47,7 +59,7 @@ void Propeller::calc(float density, float v, float omega,
     float torque = 0;
     if(lambda > 1) {
        lambda = 1.0/lambda;
-       torque = (density*V2*_F0*_J0)/(8*_etaC*_beta*(1-_lambdaPeak));
+       torque = (density*V2*_F0*_J0)/(4*_etaC*_beta*(1-_lambdaPeak));
     }
 
     // There's an undefined point at 1.  Just offset by a tiny bit to
@@ -56,24 +68,18 @@ void Propeller::calc(float density, float v, float omega,
     // point number!)
     if(lambda == 1) lambda = 0.9999;
 
-    // Compute thrust, remembering to clamp lambda to the stall point
-    float lambda2 = lambda < _lambdaS ? _lambdaS : lambda;
-    float thrust = (0.5*density*V2*_F0/(1-_lambdaPeak))*(1-lambda2);
-
-    // Calculate lambda^8
-    float l8 = lambda*lambda; l8 = l8*l8; l8 = l8*l8;
+    // Calculate lambda^4
+    float l4 = lambda*lambda; l4 = l4*l4;
 
     // thrust/torque ratio
-    float gamma = (_etaC*_beta/_J0)*(1-l8);
-
-    // Correct slow speeds to get the takeoff parameters correct
-    if(lambda < _lambdaPeak) {
-        // This will interpolate takeoffCoef along a descending from 1
-        // at lambda==0 to 0 at the peak, fairing smoothly into the
-        // flat peak.
-        float frac = (lambda - _lambdaPeak)/_lambdaPeak;
-        gamma *= 1 + (_takeoffCoef - 1)*frac*frac;
-    }
+    float gamma = (_etaC*_beta/_J0)*(1-l4);
+
+    // Compute a thrust, clamp to takeoff thrust to prevend huge
+    // numbers at slow speeds.
+    float tc = (1 - lambda) / (1 - _lambdaPeak);
+    if(_matchTakeoff && tc > _tc0) tc = _tc0;
+
+    float thrust = 0.5 * density * V2 * _F0 * tc;
 
     if(torque > 0) {
        torque -= thrust/gamma;
index eed76450c30ab3a24218bc7850e8cb4fbfef27b6..2e4d3f565add50ee638f778cf5ba7029554abbe0 100644 (file)
@@ -14,8 +14,11 @@ public:
     // numbers for RPM and power (with air speed and density being
     // zero and sea level).  RPM values are in radians per second, of
     // course.
-    Propeller(float radius, float v, float omega, float rho, float power,
-              float omega0, float power0);
+    Propeller(float radius, float v, float omega, float rho, float power);
+
+    void setTakeoff(float omega0, float power0);
+
+    void modPitch(float mod);
 
     void calc(float density, float v, float omega,
              float* thrustOut, float* torqueOut);
@@ -23,12 +26,13 @@ public:
 private:
     float _r;           // characteristic radius
     float _J0;          // zero-thrust advance ratio
-    float _lambdaS;     // "propeller stall" normalized advance ratio
+    float _baseJ0;      //  ... uncorrected for prop advance
     float _F0;          // thrust coefficient
     float _etaC;        // Peak efficiency
     float _lambdaPeak;  // constant, ~0.759835;
     float _beta;        // constant, ~1.48058;
-    float _takeoffCoef; // correction to get the zero-speed torque right
+    float _tc0;         // thrust "coefficient" at takeoff
+    bool  _matchTakeoff; // Does _tc0 mean anything?
 };
 
 }; // namespace yasim
index e0a7093a41edd1d16cc8368acbf8655c65eb04bb..172920820a6e980ce8819efc68c3c1a1ef36b108 100644 (file)
@@ -236,8 +236,16 @@ float Surface::controlDrag()
     d *= 1 + _spoilerPos * (_spoilerDrag - 1);
     d *= 1 + _slatPos * (_slatDrag - 1);
 
-    // FIXME: flaps should REDUCE drag when the reduce lift!
-    d *= 1 + Math::abs(_flapPos) * (_flapDrag - 1);
+    // Negative flap deflections don't affect drag until their lift
+    // multiplier exceeds the "camber" (cz0) of the surface.
+    float fp = _flapPos;
+    if(fp < 0) {
+        fp = -fp;
+        fp -= _cz0/(_flapLift-1);
+        if(fp < 0) fp = 0;
+    }
+
+    d *= 1 + fp * (_flapDrag - 1);
 
     return d;
 }
index c288edf5e441af56037c0963ee0a9b9974b6579f..6dab8aa3c90e88b9915bd1c96243472be3fa6bc2 100644 (file)
@@ -8,8 +8,7 @@ Thruster::Thruster()
     for(int i=0; i<3; i++) _pos[i] = _wind[i] = 0;
     _throttle = 0;
     _mixture = 0;
-    _propAdvance = 0;
-    _rho = 0;
+    _P = _T = _rho = 0;
 }
 
 Thruster::~Thruster()
@@ -38,17 +37,12 @@ void Thruster::setDirection(float* dir)
 
 void Thruster::setThrottle(float throttle)
 {
-    _throttle = throttle;
+    _throttle = Math::clamp(throttle, 0, 1);
 }
 
 void Thruster::setMixture(float mixture)
 {
-    _mixture = mixture;
-}
-
-void Thruster::setPropAdvance(float propAdvance)
-{
-    _propAdvance = propAdvance;
+    _mixture = Math::clamp(mixture, 0, 1);
 }
 
 void Thruster::setWind(float* wind)
@@ -56,20 +50,11 @@ void Thruster::setWind(float* wind)
     for(int i=0; i<3; i++) _wind[i] = wind[i];
 }
 
-void Thruster::setDensity(float rho)
-{
-    _rho = rho;
-}
-
-void Thruster::cloneInto(Thruster* out)
+void Thruster::setAir(float pressure, float temp)
 {
-    for(int i=0; i<3; i++) {
-       out->_pos[i] = _pos[i];
-       out->_dir[i] = _dir[i];
-    }
-    out->_throttle = _throttle;
-    out->_mixture  = _mixture;
-    out->_propAdvance = _propAdvance;
+    _P = pressure;
+    _T = temp;
+    _rho = _P / (287.1 * _T);
 }
 
 }; // namespace yasim
index 25ceac8cfbfc3f788d5546c34595ec429f794306..cfb70eb7b392cf202d9ff1cc952d6330ee83c885 100644 (file)
@@ -3,23 +3,33 @@
 
 namespace yasim {
 
+class Jet;
+class PropEngine;
+class Propeller;
+class PistonEngine;
+
 class Thruster {
 public:
     Thruster();
     virtual ~Thruster();
 
+    // Typing info, these are the possible sub-type (or sub-parts)
+    // that a thruster might have.  Any might return null.  A little
+    // clumsy, but much simpler than an RTTI-based implementation.
+    virtual Jet* getJet() { return 0; }
+    virtual PropEngine* getPropEngine() { return 0; }
+    virtual Propeller* getPropeller() { return 0; }
+    virtual PistonEngine* getPistonEngine() { return 0; }
+    
     // Static data
     void getPosition(float* out);
     void setPosition(float* pos);
     void getDirection(float* out);
     void setDirection(float* dir);
 
-    virtual Thruster* clone()=0;
-
     // Controls
     void setThrottle(float throttle);
     void setMixture(float mixture);
-    void setPropAdvance(float advance);
 
     // Dynamic output
     virtual void getThrust(float* out)=0;
@@ -29,19 +39,19 @@ public:
 
     // Runtime instructions
     void setWind(float* wind);
-    void setDensity(float rho);
+    void setAir(float pressure, float temp);
     virtual void integrate(float dt)=0;
+    virtual void stabilize()=0;
 
 protected:
-    void cloneInto(Thruster* out);
-
     float _pos[3];
     float _dir[3];
     float _throttle;
     float _mixture;
-    float _propAdvance;
 
     float _wind[3];
+    float _P;
+    float _T;
     float _rho;
 };
 
index 4fa499d0b9844ea6fd4fc4f84c9c7d83a7029056..858e3b4cd66931f923633af9a0c1e3a0990125eb 100644 (file)
@@ -157,6 +157,8 @@ void Wing::setSpoiler(float start, float end, float lift, float drag)
 
 void Wing::setFlap0(float lval, float rval)
 {
+    lval = Math::clamp(lval, -1, 1);
+    rval = Math::clamp(rval, -1, 1);
     for(int i=0; i<_flap0Surfs.size(); i++) {
        ((Surface*)_flap0Surfs.get(i))->setFlap(lval);
        if(_mirror) ((Surface*)_flap0Surfs.get(++i))->setFlap(rval);
@@ -165,6 +167,8 @@ void Wing::setFlap0(float lval, float rval)
 
 void Wing::setFlap1(float lval, float rval)
 {
+    lval = Math::clamp(lval, -1, 1);
+    rval = Math::clamp(rval, -1, 1);
     for(int i=0; i<_flap1Surfs.size(); i++) {
        ((Surface*)_flap1Surfs.get(i))->setFlap(lval);
        if(_mirror) ((Surface*)_flap1Surfs.get(++i))->setFlap(rval);
@@ -173,6 +177,8 @@ void Wing::setFlap1(float lval, float rval)
 
 void Wing::setSpoiler(float lval, float rval)
 {
+    lval = Math::clamp(lval, 0, 1);
+    rval = Math::clamp(rval, 0, 1);
     for(int i=0; i<_spoilerSurfs.size(); i++) {
        ((Surface*)_spoilerSurfs.get(i))->setSpoiler(lval);
        if(_mirror) ((Surface*)_spoilerSurfs.get(++i))->setSpoiler(rval);
@@ -181,10 +187,19 @@ void Wing::setSpoiler(float lval, float rval)
 
 void Wing::setSlat(float val)
 {
+    val = Math::clamp(val, 0, 1);
     for(int i=0; i<_slatSurfs.size(); i++)
        ((Surface*)_slatSurfs.get(i))->setSlat(val);
 }
 
+float Wing::getGroundEffect(float* posOut)
+{
+    for(int i=0; i<3; i++) posOut[i] = _base[i];
+    float span = _length * Math::cos(_sweep) * Math::cos(_dihedral);
+    span = 2*(span + Math::abs(_base[2]));
+    return span;
+}
+
 void Wing::compile()
 {
     // Have we already been compiled?
index af47840f692cc58ea5db04132a1402e9e9960362..b448f83fa018d3426b6e761bc945ab965592c665 100644 (file)
@@ -44,6 +44,9 @@ public:
     // Compile the thing into a bunch of Surface objects
     void compile();
 
+    // Ground effect information
+    float getGroundEffect(float* posOut);
+    
     // Query the list of Surface objects
     int numSurfaces();
     Surface* getSurface(int n);