public static void PrecomputeGlobalCenterOfLift(FARCenterQuery lift, FARCenterQuery dummy, Vector3 vel) { /* Center of lift is the location where the derivative of * the total torque provided by aerodynamic forces relative to * AoA is zero (or at least minimal). This approximates the * derivative by a simple subtraction, like before. */ var parts = GetAllEditorModules(); for (int i = 0; i < parts.Count; i++) { FARBaseAerodynamics ba = parts[i]; ba.velocityEditor = vel; ba.ResetCenterOfLift(); } FlightEnv defaultfltenv = FlightEnv.NewDefaultVal(); // run computations twice to let things like flap interactions settle for (int i = 0; i < parts.Count; i++) { FARBaseAerodynamics ba = parts[i]; ba.PrecomputeCenterOfLift(vel, defaultfltenv, dummy); } for (int i = 0; i < parts.Count; i++) { FARBaseAerodynamics ba = parts[i]; ba.PrecomputeCenterOfLift(vel, defaultfltenv, lift); } }
public void SimulateAeroProperties(out Vector3 aeroForce, out Vector3 aeroTorque, Vector3 velocityWorldVector, double altitude) { // Rodhern: It seems that this method, 'SimulateAeroProperties', is only used in FARAPI, which in turn can be used by say KSPTrajectories. // The parameter 'FARCenterQuery dummy' is from a code fix by Benjamin Chung (commit 18fbb9d29431679a4de9dfc22a443f400d2d4f8b). FARCenterQuery center = new FARCenterQuery(); FARCenterQuery dummy = new FARCenterQuery(); float pressure; float density; float temperature; float speedOfSound; CelestialBody body = vessel.mainBody; //Calculate main gas properties pressure = (float)body.GetPressure(altitude); temperature = (float)body.GetTemperature(altitude); density = (float)body.GetDensity(pressure, temperature); speedOfSound = (float)body.GetSpeedOfSound(pressure, density); if (pressure <= 0 || temperature <= 0 || density <= 0 || speedOfSound <= 0) { aeroForce = Vector3.zero; aeroTorque = Vector3.zero; return; } float velocityMag = velocityWorldVector.magnitude; float machNumber = velocityMag / speedOfSound; float reynoldsNumber = (float)FARAeroUtil.CalculateReynoldsNumber(density, Length, velocityMag, machNumber, temperature, body.atmosphereAdiabaticIndex); float reynoldsPerLength = reynoldsNumber / (float)Length; float pseudoKnudsenNumber = machNumber / (reynoldsNumber + machNumber); float skinFriction = (float)FARAeroUtil.SkinFrictionDrag(reynoldsNumber, machNumber); FlightEnv fenv = FlightEnv.NewPredicted(vessel.mainBody, altitude, machNumber); if (_currentAeroSections != null) { for (int i = 0; i < _currentAeroSections.Count; i++) { FARAeroSection curSection = _currentAeroSections[i]; if (curSection != null) { curSection.PredictionCalculateAeroForces(density, machNumber, reynoldsPerLength, pseudoKnudsenNumber, skinFriction, velocityWorldVector, center); } } for (int i = 0; i < _legacyWingModels.Count; i++) { FARWingAerodynamicModel curWing = _legacyWingModels[i]; if ((object)curWing != null) { Vector3d force = curWing.PrecomputeCenterOfLift(velocityWorldVector, fenv, dummy); center.AddForce(curWing.transform.position, force); } } } aeroForce = center.force; aeroTorque = center.TorqueAt(vessel.CoM); }
public InstantConditionSimVars(InstantConditionSim parent, CelestialBody body, double altitude, double machNumber, double neededCl, double beta, double phi, int flap, bool spoilers) { this.parent = parent; this.neededCl = neededCl; this.CoM = parent.GetCoM(); FlightEnv fltenv = FlightEnv.NewSim(body, altitude, machNumber); iterationInput = new InstantConditionSimInput(0, beta, phi, 0, 0, 0, fltenv, 0, flap, spoilers); iterationOutput = new InstantConditionSimOutput(); }
public InstantConditionSimInput(double alpha, double beta, double phi, double alphaDot, double betaDot, double phiDot, FlightEnv fltenv, double pitchValue, int flaps, bool spoilers) { this.alpha = alpha; this.beta = beta; this.phi = phi; this.alphaDot = alphaDot; this.betaDot = betaDot; this.phiDot = phiDot; this.fltenv = fltenv; this.pitchValue = pitchValue; this.flaps = flaps; this.spoilers = spoilers; }
/// <summary> /// The single parameter constructor creates an object that represents /// an artificial default condition. This default condition is straight /// and level flight, flaps and spoilers retracted, yoke centered, at /// mach 0.5 in a 1-density (kg/m3) atmosphere (in Kerbin's case). /// At Kerbin that is roughly travelling at altitude 1 km at 170 m/s. /// </summary> public InstantConditionSimInput(CelestialBody body) { this.fltenv = FlightEnv.NewDefaultVal(body); }
public virtual Vector3d PrecomputeCenterOfLift(Vector3d velocity, FlightEnv fltenv, FARCenterQuery center) { return(Vector3d.zero); }
public GraphData MachNumberSweep(double aoAdegrees, double pitch, double lowerBound, double upperBound, int numPoints, int flapSetting, bool spoilers, CelestialBody body) { FARAeroUtil.UpdateCurrentActiveBody(body); FARAeroUtil.ResetEditorParts(); double[] ClValues = new double[(int)numPoints]; double[] CdValues = new double[(int)numPoints]; double[] CmValues = new double[(int)numPoints]; double[] LDValues = new double[(int)numPoints]; double[] AlphaValues = new double[(int)numPoints]; InstantConditionSimInput input = new InstantConditionSimInput(aoAdegrees, 0, 0, 0, 0, 0, FlightEnv.NewDefaultVal(body), pitch, flapSetting, spoilers); for (int i = 0; i < numPoints; i++) { input.fltenv.MachNumber = lowerBound + (upperBound - lowerBound) * (i == 0? 0 : i / (numPoints - 1.0)); if (input.fltenv.MachNumber < 1E-3) { input.fltenv.MachNumber = 1E-3; } InstantConditionSimOutput output; _instantCondition.GetClCdCmSteady(input, out output, i == 0, false); AlphaValues[i] = input.fltenv.MachNumber; ClValues[i] = output.Cl; CdValues[i] = output.Cd; CmValues[i] = output.Cm; LDValues[i] = output.Cl * 0.1 / output.Cd; } GraphData data = new GraphData(); data.xValues = AlphaValues; data.AddData(ClValues, GUIColors.GetColor(0), Localizer.Format("FARAbbrevCl"), true); data.AddData(CdValues, GUIColors.GetColor(1), Localizer.Format("FARAbbrevCd"), true); data.AddData(CmValues, GUIColors.GetColor(2), Localizer.Format("FARAbbrevCm"), true); data.AddData(LDValues, GUIColors.GetColor(3), Localizer.Format("FARAbbrevL_D"), true); data.exportdata.AddSizeVariables(_instantCondition, pitch, flapSetting, spoilers); data.exportdata.AddMachSweepXVariable(aoAdegrees, AlphaValues); data.exportdata.AddYVariables(data); return(data); }
public int ExportSweep(CelestialBody body, double pitch, int flapSetting, bool spoilers) { if (!IsReady()) { return(0); } FARAeroUtil.UpdateCurrentActiveBody(body); FARAeroUtil.ResetEditorParts(); StaticAnalysisExportFile exportdata = new StaticAnalysisExportFile(); InstantConditionSimInput input = new InstantConditionSimInput(0, 0, 0, 0, 0, 0, FlightEnv.NewDefaultVal(body), pitch, flapSetting, spoilers); InstantConditionSimOutput output; Vector3d centerofmass = _instantCondition.GetCoM(); // Loop through each combination (two dimensions). foreach (float mach in exportdata.MachNumberList) { input.fltenv.MachNumber = mach; input.alpha = 0; // zero is used as a neutral value for the reset _instantCondition.ResetClCdCmSteady(centerofmass, input); // reset old results (particularly cossweep) that may not reflect the current mach number foreach (float aoadeg in exportdata.AoADegreeList) { input.alpha = aoadeg; _instantCondition.GetClCdCmSteady(input, out output, true, true); exportdata.AddDatapoint(mach, aoadeg, output.Cl, output.Cd, output.Cm); } } exportdata.Export(); return(exportdata.DataCount); }
public GraphData AngleOfAttackSweep(double machNumber, double pitch, double lowerBound, double upperBound, int numPoints, int flapSetting, bool spoilers, CelestialBody body) { if (machNumber < 1E-3) { machNumber = 1E-3; } FARAeroUtil.UpdateCurrentActiveBody(body); FARAeroUtil.ResetEditorParts(); double[] ClValues = new double[(int)numPoints]; double[] CdValues = new double[(int)numPoints]; double[] CmValues = new double[(int)numPoints]; double[] LDValues = new double[(int)numPoints]; double[] AlphaValues = new double[(int)numPoints]; double[] ClValues2 = new double[(int)numPoints]; double[] CdValues2 = new double[(int)numPoints]; double[] CmValues2 = new double[(int)numPoints]; double[] LDValues2 = new double[(int)numPoints]; InstantConditionSimInput input = new InstantConditionSimInput(0, 0, 0, 0, 0, 0, FlightEnv.NewDefaultVal(body), pitch, flapSetting, spoilers); input.fltenv.MachNumber = machNumber; for (int i = 0; i < 2 * numPoints; i++) { double angle = 0; if (i < numPoints) { angle = lowerBound + (upperBound - lowerBound) * (i == 0? 0 : i / (numPoints - 1.0)); } else { angle = upperBound + (lowerBound - upperBound) * (i == numPoints ? 0 : (i - numPoints) / (numPoints - 1.0)); } input.alpha = angle; InstantConditionSimOutput output; _instantCondition.GetClCdCmSteady(input, out output, i == 0, false); if (i < numPoints) { AlphaValues[i] = angle; ClValues[i] = output.Cl; CdValues[i] = output.Cd; CmValues[i] = output.Cm; LDValues[i] = output.Cl * 0.1 / output.Cd; } else { ClValues2[numPoints * 2 - 1 - i] = output.Cl; CdValues2[numPoints * 2 - 1 - i] = output.Cd; CmValues2[numPoints * 2 - 1 - i] = output.Cm; LDValues2[numPoints * 2 - 1 - i] = output.Cl * 0.1 / output.Cd; } } GraphData data = new GraphData(); data.xValues = AlphaValues; data.AddData(ClValues2, GUIColors.GetColor(0) * 0.5f, "Cl2", false); data.AddData(ClValues, GUIColors.GetColor(0), Localizer.Format("FARAbbrevCl"), true); data.AddData(CdValues2, GUIColors.GetColor(1) * 0.5f, "Cd2", false); data.AddData(CdValues, GUIColors.GetColor(1), Localizer.Format("FARAbbrevCd"), true); data.AddData(CmValues2, GUIColors.GetColor(2) * 0.5f, "Cm2", false); data.AddData(CmValues, GUIColors.GetColor(2), Localizer.Format("FARAbbrevCm"), true); data.AddData(LDValues2, GUIColors.GetColor(3) * 0.5f, "L/D2", false); data.AddData(LDValues, GUIColors.GetColor(3), Localizer.Format("FARAbbrevL_D"), true); data.exportdata.AddSizeVariables(_instantCondition, pitch, flapSetting, spoilers); data.exportdata.AddAoASweepXVariable(machNumber, AlphaValues); data.exportdata.AddYVariables(data); return(data); }