public override void CalculatePerformance(double airRatio, double commandedThrottle, double flowMult, double ispMult) { // set base bits base.CalculatePerformance(airRatio, commandedThrottle, flowMult, ispMult); statusString = "Nominal"; combusting = running; if (running && ((useOxygen && !oxygen) || eair0 <= 0d)) { combusting = false; statusString = "No oxygen"; } else if (ffFraction <= 0d) { combusting = false; statusString = "No fuel"; } else if (underwater) { combusting = false; statusString = "Underwater"; } if (combusting) { power = power0 * Math.Min(1d, rho / rho0) * SolverMathUtil.Lerp(0.01d, 1d, throttle); double x = vz * weight * 9.80665d / power; torque = power / omega / Math.Pow((x / buff + 1d), buff); double CLift = omega * omega * r * r * r / 3d + vx * vx * r / 4d / Math.PI; double CTorq = omega * omega * r * r * r * r / 4d + vx * vx * r * r / 8d / Math.PI; // float CTilt = omega * r * r * r * vx / PI + r * vx * vx * vx / omega; thrust = torque * ldr * CLift / CTorq; thrust *= flowMult * ispMult; // tilt = lift / CLift * CTilt; fuelFlow = BSFC * power * flowMult; Isp = thrust / (fuelFlow * 9.80665d); SFC = 3600d / Isp; } }
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); } }