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; }
private void SetStaticSimulation() { ambientTherm = EngineThermodynamics.StandardConditions(true); inletTherm = ambientTherm; inletTherm.P *= AJEInlet.OverallStaticTPR(defaultTPR); areaRatio = 1d; lastPropellantFraction = 1d; }
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); }
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); }
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(); } }
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); }
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); }
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); }
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; }
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()); }
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); }