Esempio n. 1
0
        protected void CalculateTTR()
        {
            //calculate TTR at design point first

            // Don't overwrite th0 and th1
            EngineThermodynamics ambientTherm = EngineThermodynamics.StandardConditions(false);

            ambientTherm.T = T_d;
            EngineThermodynamics inletTherm = ambientTherm.ChangeReferenceFrameMach(M_d);
            // Note that this work is negative
            // Different mass flows between compressor, turbine, and bypass automatically taken care of by MassRatio
            double compressorWork;

            th3 = inletTherm.AdiabaticProcessWithPressureRatio(CPR, out compressorWork, efficiency: eta_c);
            double fanWork = 0d;

            if (BPR > 0d)
            {
                th2             = inletTherm.AdiabaticProcessWithPressureRatio(FPR, out fanWork, efficiency: eta_c);
                fanWork        *= BPR;
                fanWorkConstant = fanWork / compressorWork;
            }
            double turbineWork = compressorWork + fanWork;

            th4 = th3.AddFuelToTemperature(Tt4, h_f);
            th5 = th4.AdiabaticProcessWithWork(turbineWork, efficiency: eta_t);
            TTR = th5.T / th4.T;
        }
        protected void GetThrustData(out double thrustVac, out double thrustASL)
        {
            rfSolver.SetPropellantStatus(true, true);

            bool   oldE        = EngineIgnited;
            bool   oldIg       = ignited;
            float  oldThrottle = currentThrottle;
            double oldLastPropellantFraction = lastPropellantFraction;

            currentThrottle        = 1f;
            lastPropellantFraction = 1d;
            EngineIgnited          = true;
            ignited = true;

            ambientTherm = EngineThermodynamics.StandardConditions(true);
            inletTherm   = ambientTherm;

            rfSolver.UpdateThrustRatio(1d);
            rfSolver.SetPropellantStatus(true, true);

            UpdateSolver(EngineThermodynamics.StandardConditions(true), 0d, Vector3d.zero, 0d, true, true, false);
            thrustASL = engineSolver.GetThrust() * 0.001d;
            double spaceHeight = Planetarium.fetch?.Home?.atmosphereDepth + 1000d ?? 141000d;

            UpdateSolver(EngineThermodynamics.VacuumConditions(true), spaceHeight, Vector3d.zero, 0d, true, true, false);
            thrustVac = engineSolver.GetThrust() * 0.001d;

            EngineIgnited          = oldE;
            ignited                = oldIg;
            currentThrottle        = oldThrottle;
            lastPropellantFraction = oldLastPropellantFraction;
        }
Esempio n. 3
0
        private void SetStaticSimulation()
        {
            ambientTherm = EngineThermodynamics.StandardConditions(true);

            inletTherm    = ambientTherm;
            inletTherm.P *= AJEInlet.OverallStaticTPR(defaultTPR);

            areaRatio = 1d;
            lastPropellantFraction = 1d;
        }
Esempio n. 4
0
        public override void UpdateSolver(EngineThermodynamics ambientTherm, double altitude, Vector3d vel, double mach, bool ignited, bool oxygen, bool underwater)
        {
            Vector3 t = thrustTransforms[0].forward.normalized;

            vx = (float)Vector3.Cross(vel, t).magnitude;
            vz = -(float)Vector3.Dot(vel, t);

            (engineSolver as SolverRotor).UpdateFlightParams(vx, vz);

            base.UpdateSolver(ambientTherm, altitude, vel, mach, ignited, oxygen, underwater);
        }
Esempio n. 5
0
        public override void UpdateSolver(EngineThermodynamics ambientTherm, double altitude, Vector3d vel, double mach, bool ignited, bool oxygen, bool underwater)
        {
            // change up the velocity vector, it's now vs the engine part.
            v   = Vector3d.Dot(vel, -thrustTransforms[0].forward);
            vel = (Vector3d)thrustTransforms[0].forward * -v;

            // set engine params prior to calculation
            if (pistonEngine != null)
            {
                pistonEngine.SetWastegate(boost);
                pistonEngine.SetMixture(mixture);
            }
            // set prop (+ engine) params
            solverProp.SetRPMLever(rpmLever);
            solverProp.SetTweaks(CtTweak, CpTweak, VolETweak, MachPowTweak);

            base.UpdateSolver(ambientTherm, altitude, vel, mach, ignited, oxygen, underwater);
        }
Esempio n. 6
0
        protected void InitializeEngine()
        {
            //calculate TTR at design point first

            // Don't overwrite th0 and th1
            EngineThermodynamics ambientTherm = EngineThermodynamics.StandardConditions(false);

            ambientTherm.T = T_d;
            EngineThermodynamics inletTherm = ambientTherm.ChangeReferenceFrameMach(M_d);

            th7    = inletTherm.AddFuelToTemperature(9999d, h_f, throttle: throttle, maxFar: maxFar);
            th7.P *= 0.95;

            double massFlow = inletTherm.CalculateMassFlow(Aref, 0.5d);

            Athroat = th7.CalculateFlowArea(massFlow * th7.MassRatio, 1d);

            if (!adjustableNozzle)
            {
                p8 = ambientTherm.P;
                CalculateANozzle();
            }
        }
Esempio n. 7
0
        public string GetStaticThrustInfo()
        {
            string output = "";

            if (engineSolver == null || !(engineSolver is SolverRotor))
            {
                CreateEngine();
            }

            // get stats
            ambientTherm = EngineThermodynamics.StandardConditions(true);

            currentThrottle        = 1f;
            lastPropellantFraction = 1d;

            UpdateSolver(ambientTherm, 0d, Vector3.zero, 0d, true, true, false);
            double thrust = (engineSolver.GetThrust() * 0.001d);
            double power  = ((engineSolver as SolverRotor).GetPower() / 745.7d);

            output += "<b>Static Power: </b>" + power.ToString("F0") + " HP\n";
            output += "<b>Static Thrust: </b>" + thrust.ToString("F2") + " kN\n";

            return(output);
        }
Esempio n. 8
0
        protected string GetThrustInfo()
        {
            string output = "";

            if (engineSolver == null || !(engineSolver is SolverRF))
            {
                CreateEngine();
            }
            rfSolver.SetPropellantStatus(true, true);
            // get stats
            double pressure = 101.325d, temperature = 288.15d, density = 1.225d;

            if (Planetarium.fetch != null)
            {
                CelestialBody home = Planetarium.fetch.Home;
                if (home != null)
                {
                    pressure    = home.GetPressure(0d);
                    temperature = home.GetTemperature(0d);
                    density     = home.GetDensity(pressure, temperature);
                }
            }
            ambientTherm = new EngineThermodynamics();
            ambientTherm.FromAmbientConditions(pressure, temperature, density);
            inletTherm = new EngineThermodynamics();
            inletTherm.CopyFrom(ambientTherm);
            currentThrottle        = 1f;
            lastPropellantFraction = 1d;
            bool oldE = EngineIgnited;

            EngineIgnited = true;
            bool oldIg = ignited;

            ignited = true;

            rfSolver.UpdateThrustRatio(1d);
            rfSolver.SetPropellantStatus(true, true);

            UpdateSolver(ambientTherm, 0d, Vector3d.zero, 0d, true, true, false);
            double thrustASL = (engineSolver.GetThrust() * 0.001d);

            if (atmChangeFlow) // If it's a jet
            {
                output += "<b>Static Thrust: </b>" + (thrustASL).ToString("0.0##") + " kN" + ThrottleString();
                if (useVelCurve) // if thrust changes with mach
                {
                    float vMin, vMax, tMin, tMax;
                    velCurve.FindMinMaxValue(out vMin, out vMax, out tMin, out tMax); // get the max mult, and thus report maximum thrust possible.
                    output += "\n<b>Max. Thrust: </b>" + (thrustASL * vMax).ToString("0.0##") + " kN Mach " + tMax.ToString("0.#");
                }
            }
            else
            {
                // get stats again
                double spaceHeight = 131000d;
                pressure = 0d;
                density  = 0d;
                if (Planetarium.fetch != null)
                {
                    CelestialBody home = Planetarium.fetch.Home;
                    if (home != null)
                    {
                        temperature = home.GetTemperature(home.atmosphereDepth + 1d);
                        spaceHeight = home.atmosphereDepth + 1000d;
                    }
                }
                else
                {
                    temperature = PhysicsGlobals.SpaceTemperature;
                }
                ambientTherm.FromAmbientConditions(pressure, temperature, density);
                UpdateSolver(ambientTherm, spaceHeight, Vector3d.zero, 0d, true, true, false);
                double thrustVac = (engineSolver.GetThrust() * 0.001d);

                if (thrustASL != thrustVac)
                {
                    output += (throttleLocked ? "<b>" : "<b>Max. ") + "Thrust (Vac.): </b>" + (thrustVac).ToString("0.0##") + " kN" + ThrottleString()
                              + "\n" + (throttleLocked ? "<b>" : "<b>Max. ") + "Thrust (ASL): </b>" + (thrustASL).ToString("0.0##") + " kN";
                }
                else
                {
                    output += (throttleLocked ? "<b>" : "<b>Max. ") + "Thrust: </b>" + (thrustVac).ToString("0.0##") + " kN" + ThrottleString();
                }
            }
            output       += "\n";
            EngineIgnited = oldE;
            ignited       = oldIg;
            return(output);
        }
Esempio n. 9
0
        public override void UpdateSolver(EngineThermodynamics ambientTherm, double altitude, Vector3d vel, double mach, bool ignited, bool oxygen, bool underwater)
        {
            choppercontrol = Vector3.zero;
            float radar = 0;

            if (HighLogic.LoadedSceneIsEditor)
            {
                hdg = vessel.ReferenceTransform.up;
                choppercontrol.z = 0.85f;
            }
            else if (HighLogic.LoadedSceneIsFlight)
            {
                hdg   = vessel.ReferenceTransform.up;
                rgt   = vessel.ReferenceTransform.right;
                dwn   = vessel.ReferenceTransform.forward;
                radar = (float)vessel.radarAltitude + Vector3.Dot(vessel.upAxis, thrustTransforms[0].position - vessel.transform.position);
                if (cycAuth != 0)
                {
                    choppercontrol.x  = vessel.ctrlState.roll;
                    choppercontrol.y  = vessel.ctrlState.pitch;
                    choppercontrol.y -= Vector3.Dot(vel, hdg) * cycTrim * 0.01f;
                    choppercontrol.z  = vessel.ctrlState.mainThrottle;// -  * vessel.ctrlState.pitch - colDiffRollCoeff * vessel.ctrlState.roll;

                    //thrustTransforms[0].forward = Quaternion.AngleAxis(-choppercontrol.x * maxSwashPlateAngle, hdg) * thrustTransformVectorDefault;
                    //thrustTransforms[0].forward = Quaternion.AngleAxis(choppercontrol.y * maxSwashPlateAngle, rgt) * thrustTransforms[0].forward;

                    Vector3 upAxis     = (Vector3)vessel.upAxis;
                    float   rollangle  = Vector3.SignedAngle(rgt, upAxis, hdg) - 90f;
                    float   pitchangle = 90f - Vector3.SignedAngle(upAxis, hdg, rgt);

                    rollPID.Update(-rollKp, -rollKi, -rollKd, choppercontrol.x * 90, rollangle, Time.deltaTime);
                    pitchPID.Update(-pitchKp, -pitchKi, -pitchKd, choppercontrol.y * 90, pitchangle, Time.deltaTime);

                    if (colDiffRoll)//Osprey
                    {
                        choppercontrol.z += rollPID.getDrive() * cycAuth / 100 * colDiffRollCoeff;
                        choppercontrol.x  = 0;
                        choppercontrol.y  = pitchPID.getDrive() / 100 + pitchDiffYawCoeff * vessel.ctrlState.yaw;
                        choppercontrol.y *= cycAuth;
                    }
                    else if (colDiffPitch)//Chinook
                    {
                        choppercontrol.z += pitchPID.getDrive() * cycAuth / 100 * colDiffPitchCoeff;
                        choppercontrol.y  = Vector3.Dot(vel, hdg) * cycTrim * 0.01f;
                        choppercontrol.x  = rollPID.getDrive() / 100 + rollDiffYawCoeff * vessel.ctrlState.yaw;
                        choppercontrol.x *= cycAuth;
                    }
                    else
                    {
                        choppercontrol.y  = pitchPID.getDrive() / 100 + pitchDiffYawCoeff * vessel.ctrlState.yaw;
                        choppercontrol.y *= cycAuth;
                        choppercontrol.x  = rollPID.getDrive() / 100 + rollDiffYawCoeff * vessel.ctrlState.yaw;
                        choppercontrol.x *= cycAuth;
                    }
                }
                else
                {
                    choppercontrol.x = choppercontrol.y = 0;
                    choppercontrol.z = vessel.ctrlState.mainThrottle;
                }
            }
            else
            {
                hdg.Set(0, 1, 0);
            }

            Vector3 t = thrustTransforms[0].forward.normalized;

            vel += Vector3.Cross(vessel.angularVelocity, thrustTransforms[0].position - vessel.transform.position);
            (engineSolver as SolverRotor).UpdateFlightParams(choppercontrol, vel, hdg, t, radar, (float)ambientTherm.SpeedOfSound(1), this.thrustPercentage);

            base.UpdateSolver(ambientTherm, altitude, vel, mach, ignited, oxygen, underwater);
        }
Esempio n. 10
0
        public override void CalculatePerformance(double airRatio, double commandedThrottle, double flowMult, double ispMult)
        {
            // set base bits
            base.CalculatePerformance(airRatio, commandedThrottle, flowMult, ispMult);

            // if we're not combusting, don't combust and start cooling off
            combusting   = running;
            statusString = "Nominal";
            if (running && (!oxygen || eair0 <= 0d))
            {
                combusting   = false;
                statusString = "No oxygen";
            }
            else if (ffFraction <= 0d)
            {
                combusting   = false;
                statusString = "No fuel";
            }
            else if (airRatio < 0.01d)
            {
                combusting   = false;
                statusString = "Insufficient intake area";
            }
            else if (underwater)
            {
                combusting   = false;
                statusString = "Nozzle in water";
            }

            if (combusting)
            {
                if (Tt7 > 0)
                {
                    if (unifiedThrottle)
                    {
                        mainThrottle = commandedThrottle;
                        abThrottle   = commandedThrottle;
                    }
                    else
                    {
                        mainThrottle = Math.Min(commandedThrottle * 1.5d, 1d);
                        abThrottle   = Math.Max(commandedThrottle * 3d - 2d, 0d);
                    }
                }
                else
                {
                    mainThrottle = commandedThrottle;
                    abThrottle   = 0d;
                }

                double coreThrottle = SolverMathUtil.Lerp(minThrottle, 1d, mainThrottle);

                prat3 = CPR;
                double invfac      = eta_c * th1.Gamma / (th1.Gamma - 1.0);
                double turbineWork = 0d;
                for (int i = 0; i < 20; i++)    //use iteration to calculate CPR
                {
                    th3 = th1.AdiabaticProcessWithPressureRatio(prat3, efficiency: eta_c);
                    // FIXME use ffFraction here? Instead of just multiplying thrust by fuel fraction in the module?
                    // is so, set multiplyThrustByFuelFrac = false in the ModuleEnginesAJEJet.
                    th4 = th3.AddFuelToTemperature(Tt4, h_f, throttle: coreThrottle);
                    th5 = th4.AdiabaticProcessWithTempRatio(TTR, out turbineWork, eta_t);

                    th3 = th1.AdiabaticProcessWithWork(turbineWork / (1d + fanWorkConstant), efficiency: eta_c);

                    double x = prat3;

                    prat3 = th3.P / th1.P;

                    if (Math.Abs(x - prat3) < 0.01)
                    {
                        break;
                    }
                }

                if (BPR > 0d)
                {
                    th2           = th1.AdiabaticProcessWithWork(turbineWork * fanWorkConstant / (1d + fanWorkConstant) / BPR, efficiency: eta_c);
                    th2.MassRatio = BPR;
                    prat2         = th2.P / th1.P;
                }

                if (exhaustMixer && BPR > 0)//exhaust mixer
                {
                    th2.P *= 0.98;
                    th6    = EngineThermodynamics.MixStreams(th5, th2);
                }
                else
                {
                    th6 = th5;
                }

                if (Tt7 > 0)
                {
                    th7 = th6.AddFuelToTemperature(Tt7, h_f, throttle: abThrottle);
                }
                else
                {
                    th7 = th6;
                }

                //Nozzle code is from NASA

                double p8, V8;
                //double A8;
                double epr = th7.P / th1.P;
                double etr = th7.T / th1.T;

                // The factor of 0.75 implies that the mach number of air entering the compressor is about 0.5
                // The factor can be calculated as
                // 1 / (1 - ff_ab) * sqrt(gamma_c/gamma_ab * R_ab / R_c) * M * (1 + (gamma_c + 1)/2 * M^2)^(-(gamma_c + 1)/(2 * (gamma_c - 1)) / ((gamma_ab + 1) / 2)^(-(gamma_ab + 1)/(2 * (gamma_ab - 1))
                //
                //A8 = .75 * Aref * th7.MassRatio * Math.Sqrt(th1.Gamma / th7.Gamma * th7.R / th1.R) * Math.Sqrt(etr) / epr;//ratio of nozzle area to ref area
                //double area8max = .75 * Math.Sqrt(etr) / epr;//ratio of nozzle area to ref area
                //A8 = area8max * Aref;
                //if (exhaustMixer && BPR > 0)
                //    A8 *= (1 + BPR);
                //double eair = th7.P * Math.Sqrt(th7.Gamma / th7.R / th7.T) *
                //    Math.Pow((0.5d + 0.5d * th7.Gamma), 0.5d * (1d + th7.Gamma) / (1d - th7.Gamma));//corrected mass flow per area
                //mdot = eair * A8;

                // Assume turbine is choked all the time
                coreAirflow = th4.CalculateMassFlow(Aref * turbineAreaRatio, 1d) / th4.MassRatio;
                mdot        = th7.MassRatio * coreAirflow;

                if (!adjustableNozzle)
                {
                    p8 = th7.ChokedPressure();
                    if (p8 < th0.P)
                    {
                        p8 = th0.P;
                    }
                }
                else
                {
                    p8 = th0.P;
                }
                double exitEnergy = th7.Cp * th7.T * eta_n * (1.0 - Math.Pow(p8 / th7.P, th7.R / th7.Cp));
                V8  = Math.Sqrt(Math.Abs(2d * exitEnergy));    //exit velocity - may be negative under certain conditions
                V8 *= Math.Sign(exitEnergy);
                double exitMach = th7.CalculateMach(Math.Abs(V8));
                Anozzle = th7.CalculateFlowArea(mdot, exitMach);
                thrust  = V8 * mdot + (p8 - th0.P) * Anozzle;
                thrust -= mdot * (1d - th7.FF) * (vel);//ram drag

                if (BPR > 0d && FPR > 1d && exhaustMixer == false)
                {
                    //fan thrust from NASA
                    double pfexit = th2.ChokedPressure();
                    if (pfexit < th0.P)
                    {
                        pfexit = th0.P;
                    }
                    double fExitEnergy = th2.Cp * th2.T * eta_n * (1d - Math.Pow(pfexit / th2.P, th2.R / th2.Cp));
                    double ues         = Math.Sqrt(Math.Abs(2d * fExitEnergy));
                    ues *= Math.Sign(fExitEnergy);
                    double bypassAirFlow = coreAirflow * th2.MassRatio; // th2.MassRatio will be equal to BPR at this point
                    double ANozzleBypass = th2.CalculateFlowArea(bypassAirFlow, th2.CalculateMach(ues));
                    thrust += bypassAirFlow * ues + (pfexit - p0) * ANozzleBypass;
                    thrust -= bypassAirFlow * vel;
                }

                thrust  *= flowMult * ispMult;
                fuelFlow = mdot * th7.FF * flowMult;
                Isp      = thrust / (fuelFlow * 9.80665);
                SFC      = 3600d / Isp;

                /*
                 * debugstring = "";
                 * debugstring += "TTR:\t" + TTR.ToString("F3") + "\r\n";
                 * debugstring += "CPR:\t" + prat3.ToString("F3") + "\r\n"; ;
                 * debugstring += "p0: " + th0.P.ToString("F2") + "\tt0: " + th0.T.ToString("F2") + "\r\n";
                 * debugstring += "P1: " + th1.P.ToString("F2") + "\tT1: " + th1.T.ToString("F2") + "\r\n";
                 * debugstring += "P2: " + th2.P.ToString("F2") + "\tT2: " + th2.T.ToString("F2") + "\r\n";
                 * debugstring += "P3: " + th3.P.ToString("F2") + "\tT3: " + th3.T.ToString("F2") + "\r\n";
                 * debugstring += "P4: " + th4.P.ToString("F2") + "\tT4: " + th4.T.ToString("F2") + "\r\n";
                 * debugstring += "P5: " + th5.P.ToString("F2") + "\tT5: " + th5.T.ToString("F2") + "\r\n";
                 * debugstring += "P6: " + th6.P.ToString("F2") + "\tT6: " + th6.T.ToString("F2") + "\r\n";
                 * debugstring += "P7: " + th7.P.ToString("F2") + "\tT7: " + th7.ToString("F2") + "\r\n";
                 * debugstring += "EPR: " + epr.ToString("F2") + "\tETR: " + etr.ToString("F2") + "\r\n";
                 *
                 * debugstring += "FF: " + th5.FF.ToString("P") + "\t";
                 * debugstring += "FF_AB: " + th7.FF.ToString("P") + "\r\n";
                 * debugstring += "V8: " + V8.ToString("F2") + "\tA8: " + A8.ToString("F2") + "\r\n";
                 * debugstring += "Thrust: " + (thrust / 1000).ToString("F1") + "\tmdot: " + mdot.ToString("F2") + "\r\n";
                 * debugstring += "Isp: " + Isp.ToString("F0") + "\tSFC: " + (3600 / Isp).ToString("F3") + "\r\n";
                 * Debug.Log(debugstring);*/
            }
            else
            {
                double shutdownScalar = Math.Pow(spoolFactor, TimeWarp.fixedDeltaTime);

                th3.T = Math.Max(t0, th3.T * shutdownScalar - 4d);

                mainThrottle = Math.Max(0d, mainThrottle * shutdownScalar - 0.05d);
                if (Tt7 > 0)
                {
                    abThrottle = Math.Max(0d, abThrottle * shutdownScalar - 0.05d);
                }
            }
            // Set FX power
            if (Tt7 == 0)
            {
                fxPower = (float)mainThrottle;
            }
            else
            {
                fxPower = (float)(mainThrottle * 0.25d + abThrottle * 0.75d);
            }
        }
            protected new string GetThrustInfo()
            {
                string output = "";
                if (engineSolver == null || !(engineSolver is SolverRF))
                    CreateEngine();
                (engineSolver as SolverRF).SetEngineStatus(true, true, true);
                // get stats
                double pressure = 101.325d, temperature = 288.15d, density = 1.225d;
                if (Planetarium.fetch != null)
                {
                    CelestialBody home = Planetarium.fetch.Home;
                    if (home != null)
                    {
                        pressure = home.GetPressure(0d);
                        temperature = home.GetTemperature(0d);
                        density = home.GetDensity(pressure, temperature);
                    }
                }
                ambientTherm = new EngineThermodynamics();
                ambientTherm.FromAmbientConditions(pressure, temperature, density);
                inletTherm = new EngineThermodynamics();
                inletTherm.CopyFrom(ambientTherm);

                currentThrottle = 1f;
                lastPropellantFraction = 1d;
                bool oldE = EngineIgnited;
                EngineIgnited = true;
                (engineSolver as SolverRF).UpdateThrustRatio(1d);

                UpdateFlightCondition(ambientTherm, 0d, Vector3d.zero, 0d, true);
                double thrustASL = (engineSolver.GetThrust() * 0.001d);

                if (atmChangeFlow) // If it's a jet
                {
                    output += "<b>Static Thrust: </b>" + (thrustASL).ToString("0.0##") + " kN" + ThrottleString();
                    if (useVelCurve) // if thrust changes with mach
                    {
                        float vMin, vMax, tMin, tMax;
                        velCurve.FindMinMaxValue(out vMin, out vMax, out tMin, out tMax); // get the max mult, and thus report maximum thrust possible.
                        output += "\n<b>Max. Thrust: </b>" + (thrustASL* vMax).ToString("0.0##") + " kN Mach " + tMax.ToString("0.#");
                    }
                }
                else
                {
                    // get stats again
                    double spaceHeight = 131000d;
                    pressure = 0d;
                    density = 0d;
                    if (Planetarium.fetch != null)
                    {
                        CelestialBody home = Planetarium.fetch.Home;
                        if (home != null)
                        {
                            temperature = home.GetTemperature(home.atmosphereDepth + 1d);
                            spaceHeight = home.atmosphereDepth + 1000d;
                        }
                    }
                    else
                        temperature = PhysicsGlobals.SpaceTemperature;
                    ambientTherm.FromAmbientConditions(pressure, temperature, density);

                    UpdateFlightCondition(ambientTherm, spaceHeight, Vector3d.zero, 0d, true);
                    double thrustVac = (engineSolver.GetThrust() * 0.001d);

                    if (thrustASL != thrustVac)
                    {
                        output += (throttleLocked ? "<b>" : "<b>Max. ") + "Thrust (Vac.): </b>" + (thrustVac).ToString("0.0##") + " kN" + ThrottleString()
                            + "\n" + (throttleLocked ? "<b>" : "<b>Max. ") + "Thrust (ASL): </b>" + (thrustASL).ToString("0.0##") + " kN";
                    }
                    else
                    {
                        output += (throttleLocked ? "<b>" : "<b>Max. ") + "Thrust: </b>" + (thrustVac).ToString("0.0##") + " kN" + ThrottleString();
                    }
                }
                output += "\n";
                EngineIgnited = oldE;
                return output;
            }
Esempio n. 12
0
        public override void CalculatePerformance(double airRatio, double commandedThrottle, double flowMult, double ispMult)
        {
            // set base bits
            base.CalculatePerformance(airRatio, commandedThrottle, flowMult, ispMult);

            // if we're not combusting, don't combust and start cooling off
            combusting   = running;
            statusString = "Nominal";
            if (running && (!oxygen || eair0 <= 0d))
            {
                combusting   = false;
                statusString = "No oxygen";
            }
            else if (ffFraction <= 0d)
            {
                combusting   = false;
                statusString = "No fuel";
            }
            else if (th1.P * 0.9 < th0.P)
            {
                combusting   = false;
                statusString = "Below ignition speed";
            }
            else if (airRatio < 0.01d)
            {
                combusting   = false;
                statusString = "Insufficient intake area";
            }
            else if (underwater)
            {
                combusting   = false;
                statusString = "Nozzle in water";
            }

            if (combusting)
            {
                th7    = th1.AddFuelToTemperature(9999d, h_f, throttle: throttle, maxFar: maxFar);
                th7.P *= 0.95;

                //Nozzle code is from NASA

                //double A8;
                double epr = th7.P / th1.P;
                double etr = th7.T / th1.T;

                coreAirflow = th7.CalculateMassFlow(Athroat, 1d) / th7.MassRatio;
                mdot        = th7.MassRatio * coreAirflow;

                if (adjustableNozzle)
                {
                    p8 = th0.P;
                    double exitEnergy = th7.Cp * th7.T * eta_n * (1.0 - Math.Pow(p8 / th7.P, th7.R / th7.Cp));
                    V8  = Math.Sqrt(Math.Abs(2d * exitEnergy));    //exit velocity - may be negative under certain conditions
                    V8 *= Math.Sign(exitEnergy);
                    double exitMach = th7.CalculateMach(Math.Abs(V8));
                    Anozzle = th7.CalculateFlowArea(mdot, exitMach);
                }

                thrust  = V8 * mdot + (p8 - th0.P) * Anozzle;
                thrust -= mdot * (1d - th7.FF) * (vel);//ram drag

                thrust  *= flowMult * ispMult;
                fuelFlow = mdot * th7.FF * flowMult;
                Isp      = thrust / (fuelFlow * 9.80665);
                SFC      = 3600d / Isp;
            }
            // Set FX power
            fxPower = (float)throttle;
        }
        public override void UpdateSolver(EngineThermodynamics ambientTherm, double altitude, Vector3d vel, double mach, bool sIgnited, bool oxygen, bool underwater)
        {
            UnityEngine.Profiling.Profiler.BeginSample("ModuleEnginesRF.UpdateSolver");
            throttledUp = false;

            // handle ignition
            if (HighLogic.LoadedSceneIsFlight)
            {
                if (vessel.ctrlState.mainThrottle > 0f || throttleLocked)
                {
                    throttledUp = true;
                }
                else
                {
                    ignited = false; // FIXME handle engine spinning down, non-instant shutoff.
                }
                IgnitionUpdate();

                // Ullage
                if (ullage && RFSettings.Instance.simulateUllage)
                {
                    if (EngineIgnited && ignited && throttledUp && rfSolver.GetRunning())
                    {
                        double state     = ullageSet.GetUllageStability();
                        double testValue = Math.Pow(state, RFSettings.Instance.stabilityPower);
                        if (UnityEngine.Random.value > testValue)
                        {
                            ScreenMessages.PostScreenMessage(ullageFail);
                            FlightLogger.fetch.LogEvent($"[{FormatTime(vessel.missionTime)}] {ullageFail.message}");
                            reignitable = false;
                            ullageOK    = false;
                            ignited     = false;
                            Flameout("Vapor in feed line");
                        }
                    }
                }
                if (!ullageSet.PressureOK())
                {
                    Flameout("Lack of pressure", false, ignited);
                    ignited     = false;
                    reignitable = false;
                }

                rfSolver.SetPropellantStatus(ullageSet.PressureOK(), ullageOK || !RFSettings.Instance.simulateUllage);

                // do thrust curve
                if (ignited && useThrustCurve)
                {
                    thrustCurveRatio   = (float)(curveProp.totalResourceAvailable / curveProp.totalResourceCapacity);
                    thrustCurveDisplay = thrustCurve.Evaluate(thrustCurveUseTime ? curveTime : thrustCurveRatio);
                    if (thrustCurveUseTime && EngineIgnited)
                    {
                        curveTime += TimeWarp.fixedDeltaTime;
                    }
                    rfSolver.UpdateThrustRatio(thrustCurveDisplay);
                }
            }

            // Set part temp
            rfSolver.SetPartTemp(part.temperature);

            // do heat
            // heatProduction = (float)(scaleRecip * extHeatkW / PhysicsGlobals.InternalHeatProductionFactor * part.thermalMassReciprocal);
            heatProduction = 0;

            // run base method code
            base.UpdateSolver(ambientTherm, altitude, vel, mach, ignited, oxygen, CheckTransformsUnderwater());
            UnityEngine.Profiling.Profiler.EndSample();
        }
        public override void UpdateSolver(EngineThermodynamics ambientTherm, double altitude, Vector3d vel, double mach, bool sIgnited, bool oxygen, bool underwater)
        {
            throttledUp = false;

            // handle ignition
            if (HighLogic.LoadedSceneIsFlight)
            {
                if (vessel.ctrlState.mainThrottle > 0f || throttleLocked)
                {
                    throttledUp = true;
                }
                else
                {
                    ignited = false;
                }
                IgnitionUpdate();

                // Ullage
                bool pressureOK = ullageSet.PressureOK();
                propellantStatus = "Nominal";
                if (ullage && RFSettings.Instance.simulateUllage)
                {
                    propellantStatus = ullageSet.GetUllageState(out ullageColor);
                    part.stackIcon.SetIconColor(ullageColor);
                    if (EngineIgnited && ignited && throttledUp && rfSolver.GetRunning())
                    {
                        double state     = ullageSet.GetUllageStability();
                        double testValue = Math.Pow(state, RFSettings.Instance.stabilityPower);
                        if (UnityEngine.Random.value > testValue)
                        {
                            ScreenMessages.PostScreenMessage(ullageFail);
                            FlightLogger.fetch.LogEvent("[" + FormatTime(vessel.missionTime) + "] " + ullageFail.message);
                            reignitable = false;
                            ullageOK    = false;
                            ignited     = false;
                            Flameout("Vapor in feed line");
                        }
                    }
                }
                if (!pressureOK)
                {
                    propellantStatus = "Feed pressure too low"; // override ullage status indicator
                    Flameout("Lack of pressure", false, ignited);
                    ignited     = false;
                    reignitable = false;
                }
                needSetPropStatus = false;

                rfSolver.SetPropellantStatus(pressureOK, (ullageOK || !RFSettings.Instance.simulateUllage));

                // do thrust curve
                if (ignited && useThrustCurve)
                {
                    thrustCurveRatio = (float)((propellants[curveProp].totalResourceAvailable / propellants[curveProp].totalResourceCapacity));
                    if (thrustCurveUseTime)
                    {
                        thrustCurveDisplay = thrustCurve.Evaluate(curveTime);
                        if (EngineIgnited)
                        {
                            curveTime += TimeWarp.fixedDeltaTime;
                        }
                    }
                    else
                    {
                        thrustCurveDisplay = thrustCurve.Evaluate(thrustCurveRatio);
                    }
                    rfSolver.UpdateThrustRatio(thrustCurveDisplay);
                }
            }

            // Set part temp
            rfSolver.SetPartTemp(part.temperature);

            // do heat
            // heatProduction = (float)(scaleRecip * extHeatkW / PhysicsGlobals.InternalHeatProductionFactor * part.thermalMassReciprocal);
            heatProduction = 0;

            // run base method code
            base.UpdateSolver(ambientTherm, altitude, vel, mach, ignited, oxygen, CheckTransformsUnderwater());
        }
Esempio n. 15
0
        protected string GetThrustInfo()
        {
            string output = string.Empty;

            if (engineSolver == null || !(engineSolver is SolverRF))
            {
                CreateEngine();
            }
            rfSolver.SetPropellantStatus(true, true);

            ambientTherm = EngineThermodynamics.StandardConditions(true);
            inletTherm   = ambientTherm;

            currentThrottle        = 1f;
            lastPropellantFraction = 1d;
            bool oldE = EngineIgnited;

            EngineIgnited = true;
            bool oldIg = ignited;

            ignited = true;

            rfSolver.UpdateThrustRatio(1d);
            rfSolver.SetPropellantStatus(true, true);

            UpdateSolver(ambientTherm, 0d, Vector3d.zero, 0d, true, true, false);
            double thrustASL = (engineSolver.GetThrust() * 0.001d);

            if (atmChangeFlow) // If it's a jet
            {
                output += "<b>Static Thrust: </b>" + (thrustASL).ToString("0.0##") + " kN" + ThrottleString();
                if (useVelCurve) // if thrust changes with mach
                {
                    float vMin, vMax, tMin, tMax;
                    velCurve.FindMinMaxValue(out vMin, out vMax, out tMin, out tMax); // get the max mult, and thus report maximum thrust possible.
                    output += "\n<b>Max. Thrust: </b>" + (thrustASL * vMax).ToString("0.0##") + " kN Mach " + tMax.ToString("0.#");
                }
            }
            else
            {
                // get stats again
                ambientTherm = EngineThermodynamics.VacuumConditions(true);
                double spaceHeight = Planetarium.fetch?.Home?.atmosphereDepth + 1000d ?? 141000d;
                UpdateSolver(ambientTherm, spaceHeight, Vector3d.zero, 0d, true, true, false);
                double thrustVac = (engineSolver.GetThrust() * 0.001d);

                if (thrustASL != thrustVac)
                {
                    output += (throttleLocked ? "<b>" : "<b>Max. ") + "Thrust (Vac.): </b>" + (thrustVac).ToString("0.0##") + " kN" + ThrottleString()
                              + "\n" + (throttleLocked ? "<b>" : "<b>Max. ") + "Thrust (ASL): </b>" + (thrustASL).ToString("0.0##") + " kN";
                }
                else
                {
                    output += (throttleLocked ? "<b>" : "<b>Max. ") + "Thrust: </b>" + (thrustVac).ToString("0.0##") + " kN" + ThrottleString();
                }
            }
            output       += "\n";
            EngineIgnited = oldE;
            ignited       = oldIg;
            return(output);
        }
        protected string GetThrustInfo()
        {
            string output = string.Empty;

            if (engineSolver == null || !(engineSolver is SolverRF))
            {
                CreateEngine();
            }
            rfSolver.SetPropellantStatus(true, true);

            ambientTherm = EngineThermodynamics.StandardConditions(true);
            inletTherm   = ambientTherm;

            currentThrottle        = 1f;
            lastPropellantFraction = 1d;
            bool oldE = EngineIgnited;

            EngineIgnited = true;
            bool oldIg = ignited;

            ignited = true;

            rfSolver.UpdateThrustRatio(1d);
            rfSolver.SetPropellantStatus(true, true);

            UpdateSolver(ambientTherm, 0d, Vector3d.zero, 0d, true, true, false);
            double thrustASL = (engineSolver.GetThrust() * 0.001d);

            var weight = part.mass * (Planetarium.fetch?.Home?.GeeASL * 9.80665 ?? 9.80665);

            if (atmChangeFlow) // If it's a jet
            {
                if (throttleLocked || minThrottle == 1f)
                {
                    output += String.Format("<b> Static Thrust: </b>{0} (TWR {1}), {2}\n", Utilities.FormatThrust(thrustASL), (thrustASL / weight).ToString("0.0##"), (throttleLocked ? "throttle locked" : "unthrottleable"));
                }
                else
                {
                    output += String.Format("{0}% min throttle\n", (minThrottle * 100f).ToString("N0"));
                    output += String.Format("<b>Max. Static Thrust: </b>{0} (TWR {1})\n", Utilities.FormatThrust(thrustASL), (thrustASL / weight).ToString("0.0##"));
                    output += String.Format("<b>Min. Static Thrust: </b>{0} (TWR {1})\n", Utilities.FormatThrust(thrustASL * minThrottle), (thrustASL * minThrottle / weight).ToString("0.0##"));
                }

                if (useVelCurve) // if thrust changes with mach
                {
                    float vMin, vMax, tMin, tMax;
                    velCurve.FindMinMaxValue(out vMin, out vMax, out tMin, out tMax); // get the max mult, and thus report maximum thrust possible.
                    output += String.Format("<b>Max. Thrust: </b>{0} at Mach {1} (TWR {2})\n", Utilities.FormatThrust(thrustASL * vMax), tMax.ToString("0.#"), (thrustASL * vMax / weight).ToString("0.0##"));
                }
            }
            else
            {
                // get stats again
                ambientTherm = EngineThermodynamics.VacuumConditions(true);
                double spaceHeight = Planetarium.fetch?.Home?.atmosphereDepth + 1000d ?? 141000d;
                UpdateSolver(ambientTherm, spaceHeight, Vector3d.zero, 0d, true, true, false);
                double thrustVac = (engineSolver.GetThrust() * 0.001d);

                if (throttleLocked || minThrottle == 1f)
                {
                    var suffix = throttleLocked ? "throttle locked" : "unthrottleable";
                    if (thrustASL != thrustVac)
                    {
                        output += String.Format("<b>Thrust (Vac): </b>{0} (TWR {1}), {2}\n", Utilities.FormatThrust(thrustVac), (thrustVac / weight).ToString("0.0##"), suffix);
                        output += String.Format("<b>Thrust (ASL): </b>{0} (TWR {1}), {2}\n", Utilities.FormatThrust(thrustASL), (thrustASL / weight).ToString("0.0##"), suffix);
                    }
                    else
                    {
                        output += String.Format("<b>Thrust: </b>{0} (TWR {1}), {2}\n", Utilities.FormatThrust(thrustVac), (thrustVac / weight).ToString("0.0##"), suffix);
                    }
                }
                else
                {
                    output += String.Format("{0}% min throttle\n", (minThrottle * 100f).ToString("N0"));
                    if (thrustASL != thrustVac)
                    {
                        output += String.Format("<b>Max. Thrust (Vac): </b>{0} (TWR {1})\n", Utilities.FormatThrust(thrustVac), (thrustVac / weight).ToString("0.0##"));
                        output += String.Format("<b>Max. Thrust (ASL): </b>{0} (TWR {1})\n", Utilities.FormatThrust(thrustASL), (thrustASL / weight).ToString("0.0##"));
                        output += String.Format("<b>Min. Thrust (Vac): </b>{0} (TWR {1})\n", Utilities.FormatThrust(thrustVac * minThrottle), (thrustVac * minThrottle / weight).ToString("0.0##"));
                        output += String.Format("<b>Min. Thrust (ASL): </b>{0} (TWR {1})\n", Utilities.FormatThrust(thrustASL * minThrottle), (thrustASL * minThrottle / weight).ToString("0.0##"));
                    }
                    else
                    {
                        output += String.Format("<b>Max. Thrust: </b>{0} (TWR {1})\n", Utilities.FormatThrust(thrustVac), (thrustVac / weight).ToString("0.0##"));
                        output += String.Format("<b>Min. Thrust: </b>{0} (TWR {1})\n", Utilities.FormatThrust(thrustVac * minThrottle), (thrustVac * minThrottle / weight).ToString("0.0##"));
                    }
                }
            }
            EngineIgnited = oldE;
            ignited       = oldIg;
            return(output);
        }
            public override void UpdateFlightCondition(EngineThermodynamics ambientTherm, double altitude, Vector3d vel, double mach, bool oxygen)
            {
                throttledUp = false;
                if (!(engineSolver is ModularEngineSolver)) {
                    base.UpdateFlightCondition(ambientTherm, altitude, vel, mach, oxygen);
                    return;
                }
                SolverRF realSolver = (engineSolver as SolverRF);
                // handle ignition
                if (HighLogic.LoadedSceneIsFlight && vessel != null)
                {
                    if (vessel.ctrlState.mainThrottle > 0f || throttleLocked)
                        throttledUp = true;
                    else
                        ignited = false;
                    IgnitionUpdate();

                    // Ullage
                    bool pressureOK = ullageSet.PressureOK();
                    propellantStatus = "Nominal";
                    if (ullage && RFSettings.Instance.simulateUllage)
                    {
                        propellantStatus = ullageSet.GetUllageState();
                        if (EngineIgnited && ignited && throttledUp && realSolver.GetRunning())
                        {
                            double state = ullageSet.GetUllageStability();
                            double testValue = Math.Pow(state, RFSettings.Instance.stabilityPower);
                            if (UnityEngine.Random.value > testValue)
                            {
                                ScreenMessages.PostScreenMessage(ullageFail);
                                FlightLogger.eventLog.Add("[" + FormatTime(vessel.missionTime) + "] " + ullageFail.message);
                                reignitable = false;
                                ullageOK = false;
                                ignited = false;
                                Flameout("Vapor in feed line");
                            }
                        }
                    }
                    if (!pressureOK)
                    {
                        propellantStatus = "Feed pressure too low"; // override ullage status indicator
                        vFlameout("Lack of pressure", false, ignited);
                        ignited = false;
                        reignitable = false;
                    }

                    realSolver.SetEngineStatus(pressureOK, (ullageOK || !RFSettings.Instance.simulateUllage), ignited);

                    // do thrust curve
                    if (ignited && useThrustCurve)
                    {
                        thrustCurveRatio = (float)((propellants[curveProp].totalResourceAvailable / propellants[curveProp].totalResourceCapacity));
                        if (thrustCurveUseTime)
                        {
                            thrustCurveDisplay = thrustCurve.Evaluate(curveTime);
                            if (EngineIgnited)
                            {
                                curveTime += TimeWarp.fixedDeltaTime;
                            }
                        }
                        else
                        {
                            thrustCurveDisplay = thrustCurve.Evaluate(thrustCurveRatio);
                        }
                        realSolver.UpdateThrustRatio(thrustCurveDisplay);
                        thrustCurveDisplay *= 100f;
                    }
                }

                // Set part temp
                realSolver.SetPartTemp(part.temperature);

                // do heat
                heatProduction = (float)(scaleRecip * extHeatkW / PhysicsGlobals.InternalHeatProductionFactor * part.thermalMassReciprocal);

                // run base method code
                base.UpdateFlightCondition(ambientTherm, altitude, vel, mach, oxygen);
            }