Example #1
0
 virtual public void CreateEngine()
 {
     engineSolver = new EngineSolver();
 }
Example #2
0
        /// <summary>
        /// Update method for piston engine
        /// </summary>
        /// <param name="solver"></param>
        /// <param name="shaftRPM"></param>
        /// <param name="deltaTime">the current delta time for updates</param>
        public void Update(EngineSolver solver, double shaftRPM, double deltaTime)
        {
            double pAmb = solver.p0 + _ramAir * solver.Q;

            _throttle     = solver.throttle;
            _fuel         = solver.ffFraction > 0d;
            _engineThrust = 0d;
            _status       = "Windmilling";
            bool canStart = _running = solver.running;

            // in precedence order, set running = false (highest priority message last)
            if (shaftRPM < 60d)           // 60RPM min for engine running
            {
                _status  = "Too Low RPM"; // status should never be seen because
                _running = false;         // the starter motor bit at the end will happen
                // or another case will trump this.
            }
            if (_throttle == 0d || !canStart)
            {
                _status  = "Magnetos Off";
                _running = false;
                canStart = false;
            }
            if (!_fuel)
            {
                _status  = "Out of Fuel";
                _running = false;
                canStart = false;
            }
            if (!solver.oxygen || solver.rho <= 0d)
            {
                _status  = "No Oxygen";
                _running = false;
                canStart = false;
            }

            if (_running)
            {
                _status = "Nominal";

                shaftRPM = Math.Max(shaftRPM, 30d); // 30RPM min when running to avoid NaNs

                // check if we need to switch boost modes
                double power;
                double MAP;
                float  fuelRatio  = FuelAirRatio(_mixture);
                double efficiency = mixtureEfficiency.Evaluate(fuelRatio);
                if (_boostSwitch > 0)
                {
                    if (pAmb < _boostSwitch - 1000d && _boostMode < 1)
                    {
                        _boostMode++;
                    }
                    if (pAmb > _boostSwitch + 1000d && _boostMode > 0)
                    {
                        _boostMode--;
                    }

                    _chargeTarget = GetChargeTarget(shaftRPM, _boostMode);
                    _charge       = GetCharge(_chargeTarget, deltaTime);

                    MAP = CalcMAP(pAmb, _boostMode, _charge);

                    // Compute fuel flow
                    _airFlow  = GetAirflow(pAmb, solver.t0, solver.R_c, solver.gamma_c, shaftRPM, MAP);
                    _fuelFlow = _airFlow * fuelRatio;
                    power     = _fuelFlow * efficiency * _bsfcRecip - _boostCosts[_boostMode];
                }
                else // auto switch
                {
                    // assume supercharger for now, so charge = target
                    double target0 = GetChargeTarget(shaftRPM, 0);
                    double target1 = GetChargeTarget(shaftRPM, 1);
                    double charge0 = GetCharge(target0, deltaTime);
                    double charge1 = GetCharge(target1, deltaTime);
                    double MAP0    = CalcMAP(pAmb, 0, charge0);
                    double MAP1    = CalcMAP(pAmb, 1, charge1);

                    double airflow0    = GetAirflow(pAmb, solver.t0, solver.R_c, solver.gamma_c, shaftRPM, MAP0);
                    double m_dot_fuel0 = airflow0 * fuelRatio;
                    double power0      = m_dot_fuel0 * efficiency * _bsfcRecip - _boostCosts[0];

                    double airflow1    = GetAirflow(pAmb, solver.t0, solver.R_c, solver.gamma_c, shaftRPM, MAP1);
                    double m_dot_fuel1 = airflow1 * fuelRatio;
                    double power1      = m_dot_fuel1 * efficiency * _bsfcRecip - _boostCosts[1];

                    if (power0 >= power1)
                    {
                        MAP           = MAP0;
                        _chargeTarget = target0;
                        _charge       = charge0;
                        power         = power0;
                        _airFlow      = airflow0;
                        _fuelFlow     = m_dot_fuel0;
                        _boostMode    = 0;
                        _chargeTemp   = GetCAT(MAP, pAmb, solver.t0); // duplication of effort, but oh well, this needs to be done to reset _chargeTemp
                    }
                    else
                    {
                        MAP           = MAP1;
                        _chargeTarget = target1;
                        _charge       = charge1;
                        power         = power1;
                        _airFlow      = airflow1;
                        _fuelFlow     = m_dot_fuel1;
                        _boostMode    = 1;
                    }
                }

                _mp = MAP;
                //_chargeTemp = GetCAT(MAP, pAmb, solver.t0); // duplication of effort, but oh well

                // The "boost" is the delta above ambient
                _boostPressure = _mp - pAmb;

                _power      = power;
                _totalPower = _power + _boostCosts[_boostMode];
                _egt        = GetEGT(efficiency, solver.t0, solver.Cp_c);

                // Additional thrust from engine
                // FIXME now that we calculate EGT should use that.

                // heat from mixture, heat hack for over-RPM, multiply by relative manifold pressure
                double tmpRatio = shaftRPM / _rpm0;
                if (tmpRatio > 1d)
                {
                    tmpRatio *= tmpRatio;
                }
                float mixRatio = (1.5f - _mixture);
                mixRatio *= mixRatio;
                mixRatio  = (mixRatio + 0.2f) * 1.2f;
                double tempDelta = tmpRatio * mixRatio * _mp / _maxMP;


                // exhaust thrust, normalized to "10% HP in lbf"
                if (_exhaustThrust != 0d)
                {
                    _netExhaustThrust = _exhaustThrust * (_totalPower * W2HP * 0.1d * LBFTON) * tempDelta;
                    _engineThrust    += _netExhaustThrust;
                }

                // Meredith Effect radiator thrust, scaled by Q and by how hot the engine is running and the ambient temperature
                // CTOK is there because tempdelta is expressed as a multiple of 0C-in-K (FIXME)
                if (_meredithEffect != 0d)
                {
                    _netMeredithEffect = _meredithEffect * solver.Q * (tempDelta * 273.15d / solver.t0);
                    _engineThrust     += _netMeredithEffect;
                }

                //MonoBehaviour.print("Engine running: HP " + power * W2HP + "/" + _totalPower * W2HP + ", rpm " + shaftRPM + ", mp " + _mp + ", charge " + _charge + ", cat " + _chargeTemp + ", chargeRho " + _chargeDensity + ", egt " + _egt + ", fuel " + _fuelFlow + ", airflow " + _airFlow + ", effic " + efficiency);
            }
            else
            {
                _mp            = solver.p0;
                _boostPressure = 0d;
                // assume a starter motor of 15% power
                if (canStart)
                {
                    _status   = "Starter On";
                    _power    = _totalPower = 0.2d * _power0;
                    _fuelFlow = _power * _bsfc * 0.2d;
                    _airFlow  = _fuelFlow * 10d;
                    _mp       = 0.15d * _maxMP;
                    _egt      = GetEGT(1d, solver.t0, solver.Cp_c);
                }
                else
                {
                    _fuelFlow = _airFlow = _power = _totalPower = 0d;
                    if (_egt > solver.t0 + 1d)
                    {
                        _egt += (solver.t0 - _egt) * 0.05d * deltaTime;
                    }
                    else
                    {
                        _egt = solver.t0;
                    }
                }
            }

            // unused

            /*
             * // Oil temperature.
             * // Assume a linear variation between ~90degC at idle and ~120degC
             * // at full power.  No attempt to correct for airflow over the
             * // engine is made.  Make the time constant to attain target steady-
             * // state oil temp greater at engine off than on to reflect no
             * // circulation.  Nothing fancy, but populates the guage with a
             * // plausible value.
             * double tau;	// secs
             * if (_running)
             * {
             *  _oilTempTarget = 363.0f + (30.0f * (power / _power0));
             *  tau = 600;
             *  // Reduce tau linearly to 300 at max power
             *  tau -= (power / _power0) * 300.0f;
             * }
             * else
             * {
             *  _oilTempTarget = temp;
             *  tau = 1500;
             * }
             * _dOilTempdt = (_oilTempTarget - _oilTemp) / tau;*/
        }