public VelPoint(AeroPredictor vessel, CelestialBody body, float altitude, float speed) { this.altitude = altitude; this.speed = speed; AeroPredictor.Conditions conditions = new AeroPredictor.Conditions(body, speed, altitude); float gravParameter, radius; lock (body) { gravParameter = (float)body.gravParameter; radius = (float)body.Radius; } this.mach = conditions.mach; this.dynamicPressure = 0.0005f * conditions.atmDensity * speed * speed; float weight = (vessel.Mass * gravParameter / ((radius + altitude) * (radius + altitude))) - (vessel.Mass * speed * speed / (radius + altitude)); Vector3 thrustForce = vessel.GetThrustForce(conditions); AoA_max = vessel.GetMaxAoA(conditions, out Lift_max); AoA_level = Mathf.Min(vessel.GetAoA(conditions, weight), AoA_max); pitchInput = vessel.GetPitchInput(conditions, AoA_level); Thrust_available = thrustForce.magnitude; Vector3 force = vessel.GetAeroForce(conditions, AoA_level, pitchInput); drag = AeroPredictor.GetDragForceMagnitude(force, AoA_level); Thrust_excess = -drag - AeroPredictor.GetDragForceMagnitude(thrustForce, AoA_level); Accel_excess = Thrust_excess / vessel.Mass / WindTunnelWindow.gAccel; LDRatio = Mathf.Abs(AeroPredictor.GetLiftForceMagnitude(force, AoA_level) / drag); dLift = (vessel.GetLiftForceMagnitude(conditions, AoA_level + WindTunnelWindow.AoAdelta, pitchInput) - vessel.GetLiftForceMagnitude(conditions, AoA_level, pitchInput)) / (WindTunnelWindow.AoAdelta * Mathf.Rad2Deg); }
public GenData(AeroPredictor vessel, Conditions conditions, float speed, CalculationManager manager) { this.vessel = vessel; this.conditions = conditions; this.speed = speed; this.storeState = manager.GetStateToken(); }
private IEnumerator ProcessOptimalLine(string graphName, AeroPredictor vessel, Conditions conditions, float exitSpeed, float exitAlt, float initialSpeed, float initialAlt, CostIncreaseFunction costIncreaseFunc, Predicate <float> neighborPredicate, float[,] predicateData, CostIncreaseFunction timeDifferenceFunc) { CalculationManager singleUseManager = new CalculationManager(); LineGenData lineGenData = new LineGenData(singleUseManager, vessel, conditions, exitSpeed, exitAlt, initialSpeed, initialAlt, costIncreaseFunc, neighborPredicate, predicateData, timeDifferenceFunc); ThreadPool.QueueUserWorkItem(OptimalLineTask, lineGenData); while (!singleUseManager.Completed) { yield return(0); } List <AscentPathPoint> results = (List <AscentPathPoint>)lineGenData.state.Result; if (timeDifferenceFunc != costIncreaseFunc) { ((MetaLineGraph)graphables[graphName]).SetValues(results.Select(pt => new Vector2(pt.speed, pt.altitude)).ToArray(), new float[][] { results.Select(pt => pt.climbAngle * Mathf.Rad2Deg).ToArray(), results.Select(pt => pt.climbRate).ToArray(), results.Select(pt => pt.cost).ToArray(), results.Select(pt => pt.time).ToArray() }); } else { ((MetaLineGraph)graphables[graphName]).SetValues(results.Select(pt => new Vector2(pt.speed, pt.altitude)).ToArray(), new float[][] { results.Select(pt => pt.climbAngle * Mathf.Rad2Deg).ToArray(), results.Select(pt => pt.climbRate).ToArray(), results.Select(pt => pt.cost).ToArray() }); } //this.GetOptimalPath(vessel, conditions, 1410, 17700, 0, 0, fuelToClimb, f => f > 0, excessP).Select(pt => new Vector2(pt.speed, pt.altitude)).ToArray()); //((LineGraph)graphables["Time-Optimal Path"]).SetValues( //this.GetOptimalPath(vessel, conditions, 1410, 17700, 0, 0, timeToClimb, f => f > 0, excessP).Select(pt => new Vector2(pt.speed, pt.altitude)).ToArray()); singleUseManager.Dispose(); }
public void Calculate(AeroPredictor vessel, CelestialBody body, float altitude, float speed, float lowerBound = -20f, float upperBound = 20f, float step = 0.5f) { Conditions newConditions = new Conditions(body, altitude, speed, lowerBound, upperBound, step); if (newConditions.Equals(currentConditions)) { valuesSet = true; return; } Cancel(); if (!cache.TryGetValue(newConditions, out AoAPoints)) { WindTunnelWindow.Instance.StartCoroutine(Processing(calculationManager, newConditions, vessel)); } else { AverageLiftSlope = AoAPoints.Select(pt => pt.dLift / pt.dynamicPressure).Where(v => !float.IsNaN(v) && !float.IsInfinity(v)).Average(); currentConditions = newConditions; calculationManager.Status = CalculationManager.RunStatus.Completed; UpdateGraphs(); valuesSet = true; } }
public static SimulatedEngine Borrow(ModuleEngines module, AeroPredictor vessel) { SimulatedEngine engine = pool.Borrow(); engine.vessel = vessel; // This is possibly dangerous and may lead to NullReferenceException engine.Init(module, null); return(engine); }
public EnvelopePoint(AeroPredictor vessel, CelestialBody body, float altitude, float speed, float AoA_guess = float.NaN, float maxA_guess = float.NaN, float pitchI_guess = float.NaN) { this.altitude = altitude; this.speed = speed; AeroPredictor.Conditions conditions = new AeroPredictor.Conditions(body, speed, altitude); float gravParameter, radius; lock (body) { gravParameter = (float)body.gravParameter; radius = (float)body.Radius; } this.mach = conditions.mach; this.dynamicPressure = 0.0005f * conditions.atmDensity * speed * speed; float weight = (vessel.Mass * gravParameter / ((radius + altitude) * (radius + altitude))); // TODO: Minus centrifugal force... Vector3 thrustForce = vessel.GetThrustForce(conditions); //AoA_max = vessel.GetMaxAoA(conditions, out Lift_max, maxA_guess); if (float.IsNaN(maxA_guess)) { AoA_max = vessel.GetMaxAoA(conditions, out Lift_max, maxA_guess); } else { AoA_max = maxA_guess; Lift_max = AeroPredictor.GetLiftForceMagnitude(vessel.GetAeroForce(conditions, AoA_max, 1) + thrustForce, AoA_max); } AoA_level = vessel.GetAoA(conditions, weight, guess: AoA_guess, pitchInputGuess: 0, lockPitchInput: true); if (AoA_level < AoA_max) { pitchInput = vessel.GetPitchInput(conditions, AoA_level, guess: pitchI_guess); } else { pitchInput = 1; } Thrust_available = thrustForce.magnitude; force = vessel.GetAeroForce(conditions, AoA_level, pitchInput); liftforce = AeroPredictor.ToFlightFrame(force, AoA_level); //vessel.GetLiftForce(body, speed, altitude, AoA_level, mach, atmDensity); drag = AeroPredictor.GetDragForceMagnitude(force, AoA_level); float lift = AeroPredictor.GetLiftForceMagnitude(force, AoA_level); Thrust_excess = -drag - AeroPredictor.GetDragForceMagnitude(thrustForce, AoA_level); if (weight > Lift_max)// AoA_level >= AoA_max) { Thrust_excess = Lift_max - weight; AoA_level = AoA_max; } Accel_excess = (Thrust_excess / vessel.Mass / WindTunnelWindow.gAccel); LDRatio = Mathf.Abs(lift / drag); dLift = (vessel.GetLiftForceMagnitude(conditions, AoA_level + WindTunnelWindow.AoAdelta, pitchInput) - vessel.GetLiftForceMagnitude(conditions, AoA_level, pitchInput)) / (WindTunnelWindow.AoAdelta * Mathf.Rad2Deg); }
public GenData(AeroPredictor vessel, Conditions conditions, float speed, float altitude, CalculationManager manager, float AoA_guess = float.NaN, float maxA_guess = float.NaN, float pitchI_guess = float.NaN) { this.vessel = vessel; this.conditions = conditions; this.speed = speed; this.altitude = altitude; this.storeState = manager.GetStateToken(); this.AoA_guess = AoA_guess; this.maxA_guess = maxA_guess; this.pitchI_guess = pitchI_guess; }
public LineGenData(CalculationManager manager, AeroPredictor vessel, Conditions conditions, float exitSpeed, float exitAlt, float initialSpeed, float initialAlt, CostIncreaseFunction costIncreaseFunc, Predicate <float> neighborPredicate, float[,] predicateData, CostIncreaseFunction timeDifferenceFunc) { this.state = manager.GetStateToken(); this.vessel = vessel; this.conditions = conditions; this.exitSpeed = exitSpeed; this.exitAlt = exitAlt; this.initialSpeed = initialSpeed; this.initialAlt = initialAlt; this.costIncreaseFunc = costIncreaseFunc; this.timeDifferenceFunc = timeDifferenceFunc; this.neighborPredicate = neighborPredicate; this.predicateData = predicateData; }
public override void OnAxesChanged(AeroPredictor vessel, float xMin, float xMax, float yMin, float yMax, float zMin, float zMax) { const float variance = 0.75f; const int numPts = 125; if (!currentConditions.Contains(currentConditions.Modify(lowerBound: xMin, upperBound: xMax))) { Calculate(vessel, currentConditions.body, currentConditions.altitude, xMin, xMax, (xMax - xMin) / numPts); } else if (currentConditions.step > (xMax - xMin / numPts) / variance) { Calculate(vessel, currentConditions.body, currentConditions.altitude, xMin, xMax, (xMax - xMin) / numPts); } }
public void Calculate(AeroPredictor vessel, CelestialBody body, float lowerBoundSpeed = 0, float upperBoundSpeed = 2000, float stepSpeed = 50f, float lowerBoundAltitude = 0, float upperBoundAltitude = 60000, float stepAltitude = 500) { Conditions newConditions = new Conditions(body, lowerBoundSpeed, upperBoundSpeed, stepSpeed, lowerBoundAltitude, upperBoundAltitude, stepAltitude); if (currentConditions.Equals(newConditions) && calculationManager.Status != CalculationManager.RunStatus.PreStart) { return; } Cancel(); bool loadedCache = false; Conditions loadedConditions; if (cache.TryGetValue(newConditions, out envelopePoints)) { loadedCache = true; loadedConditions = cachedConditions[newConditions]; currentConditions = loadedConditions; } else if (TryGetContaining(newConditions, out loadedConditions, out envelopePoints)) { loadedCache = true; currentConditions = loadedConditions; } if (loadedCache) { calculationManager.Status = CalculationManager.RunStatus.Completed; UpdateGraphs(); valuesSet = true; if (loadedConditions.stepSpeed > stepSpeed || loadedConditions.stepAltitude > stepAltitude) { WindTunnel.Instance.StartCoroutine(RefinementProcessing(calculationManager, newConditions, vessel, envelopePoints, loadedConditions, new Queue <Conditions>(new Conditions[] { newConditions.Modify(stepSpeed: stepSpeed / 2, stepAltitude: stepAltitude / 2) }), true)); } else if (loadedConditions.stepSpeed > stepSpeed / 2 || loadedConditions.stepAltitude > stepAltitude / 2) { WindTunnel.Instance.StartCoroutine(RefinementProcessing(calculationManager, newConditions, vessel, envelopePoints, loadedConditions, forcePushToGraph: true)); } return; } WindTunnel.Instance.StartCoroutine(Processing(calculationManager, newConditions, vessel)); }
public override void OnAxesChanged(AeroPredictor vessel, float xMin, float xMax, float yMin, float yMax, float zMin, float zMax) { const float variance = 0.5f; const int numPts = 80; xMin = (xMin < -180 ? -180 : xMin) * Mathf.Deg2Rad; xMax = (xMax > 180 ? 180 : xMax) * Mathf.Deg2Rad; float step = Mathf.Min(2 * Mathf.Deg2Rad, (xMax - xMin) / numPts * Mathf.Deg2Rad); if (!currentConditions.Contains(currentConditions.Modify(lowerBound: xMin, upperBound: xMax))) { Calculate(vessel, currentConditions.body, currentConditions.altitude, currentConditions.speed, xMin, xMax, step); } else if (currentConditions.step > step / variance) { Calculate(vessel, currentConditions.body, currentConditions.altitude, currentConditions.speed, xMin, xMax, step); } }
public void CalculateOptimalLines(AeroPredictor vessel, Conditions conditions, float exitSpeed, float exitAlt, float initialSpeed, float initialAlt) { float[,] accel = envelopePoints.SelectToArray(pt => pt.Accel_excess * WindTunnelWindow.gAccel); float[,] burnRate = envelopePoints.SelectToArray(pt => pt.fuelBurnRate); CostIncreaseFunction timeToClimb = (current, last) => { float dE = Mathf.Abs(WindTunnelWindow.gAccel * (last.y - current.y) / ((current.x + last.x) / 2) + (last.x - current.x)); float P = (accel[current.xi, current.yi] + accel[last.xi, last.yi]) / 2; return(dE / P); }; CostIncreaseFunction fuelToClimb = (current, last) => { float dF = (burnRate[current.xi, current.yi] + burnRate[last.xi, last.yi]) / 2; return(timeToClimb(current, last) * dF); }; WindTunnelWindow.Instance.StartCoroutine(ProcessOptimalLine("Fuel-Optimal Path", vessel, conditions, exitSpeed, exitAlt, initialSpeed, initialAlt, fuelToClimb, f => f > 0, accel, timeToClimb)); WindTunnelWindow.Instance.StartCoroutine(ProcessOptimalLine("Time-Optimal Path", vessel, conditions, exitSpeed, exitAlt, initialSpeed, initialAlt, timeToClimb, f => f > 0, accel, timeToClimb)); }
public AoAPoint(AeroPredictor vessel, CelestialBody body, float altitude, float speed, float AoA) { this.altitude = altitude; this.speed = speed; AeroPredictor.Conditions conditions = new AeroPredictor.Conditions(body, speed, altitude); this.AoA = AoA; this.mach = conditions.mach; this.dynamicPressure = 0.0005f * conditions.atmDensity * speed * speed; this.pitchInput = vessel.GetPitchInput(conditions, AoA); this.pitchInput_dry = vessel.GetPitchInput(conditions, AoA, true); Vector3 force = AeroPredictor.ToFlightFrame(vessel.GetAeroForce(conditions, AoA, pitchInput), AoA); torque = vessel.GetAeroTorque(conditions, AoA).x; torque_dry = vessel.GetAeroTorque(conditions, AoA, 0, true).x; Lift = force.y; Drag = -force.z; LDRatio = Mathf.Abs(Lift / Drag); dLift = (vessel.GetLiftForceMagnitude(conditions, AoA + WindTunnelWindow.AoAdelta, pitchInput) - Lift) / (WindTunnelWindow.AoAdelta * Mathf.Rad2Deg); }
public void Calculate(AeroPredictor vessel, CelestialBody body, float altitude, float lowerBound = 0, float upperBound = 2000, float step = 50) { Conditions newConditions = new Conditions(body, altitude, lowerBound, upperBound, step); if (newConditions.Equals(currentConditions)) { valuesSet = true; return; } Cancel(); if (!cache.TryGetValue(newConditions, out VelPoints)) { WindTunnel.Instance.StartCoroutine(Processing(calculationManager, newConditions, vessel)); } else { currentConditions = newConditions; calculationManager.Status = CalculationManager.RunStatus.Completed; UpdateGraphs(); valuesSet = true; } }
private IEnumerator Processing(CalculationManager manager, Conditions conditions, AeroPredictor vessel) { int numPts = (int)Math.Ceiling((conditions.upperBound - conditions.lowerBound) / conditions.step); VelPoint[] newVelPoints = new VelPoint[numPts + 1]; float trueStep = (conditions.upperBound - conditions.lowerBound) / numPts; CalculationManager.State[] results = new CalculationManager.State[numPts + 1]; for (int i = 0; i <= numPts; i++) { //newAoAPoints[i] = new AoAPoint(vessel, conditions.body, conditions.altitude, conditions.speed, conditions.lowerBound + trueStep * i); GenData genData = new GenData(vessel, conditions, conditions.lowerBound + trueStep * i, manager); results[i] = genData.storeState; ThreadPool.QueueUserWorkItem(GenerateVelPoint, genData); } while (!manager.Completed) { if (manager.Status == CalculationManager.RunStatus.Cancelled) { yield break; } yield return(0); } for (int i = 0; i <= numPts; i++) { newVelPoints[i] = (VelPoint)results[i].Result; } if (!manager.Cancelled) { cache.Add(conditions, newVelPoints); VelPoints = newVelPoints; currentConditions = conditions; UpdateGraphs(); valuesSet = true; } }
private static void GenerateLevel(Conditions conditions, CalculationManager manager, ref CalculationManager.State[,] results, AeroPredictor vessel) { float[,] AoAs_guess = null, maxAs_guess = null, pitchIs_guess = null; if (results != null) { AoAs_guess = results.SelectToArray(pt => ((EnvelopePoint)pt.Result).AoA_level); maxAs_guess = results.SelectToArray(pt => ((EnvelopePoint)pt.Result).AoA_max); pitchIs_guess = results.SelectToArray(pt => ((EnvelopePoint)pt.Result).pitchInput); } int numPtsX = (int)Math.Ceiling((conditions.upperBoundSpeed - conditions.lowerBoundSpeed) / conditions.stepSpeed); int numPtsY = (int)Math.Ceiling((conditions.upperBoundAltitude - conditions.lowerBoundAltitude) / conditions.stepAltitude); float trueStepX = (conditions.upperBoundSpeed - conditions.lowerBoundSpeed) / numPtsX; float trueStepY = (conditions.upperBoundAltitude - conditions.lowerBoundAltitude) / numPtsY; results = new CalculationManager.State[numPtsX + 1, numPtsY + 1]; for (int j = 0; j <= numPtsY; j++) { for (int i = 0; i <= numPtsX; i++) { if (manager.Cancelled) { return; } float x = (float)i / numPtsX; float y = (float)j / numPtsY; float aoa_guess = AoAs_guess != null?AoAs_guess.Lerp2(x, y) : float.NaN; float maxA_guess = maxAs_guess != null?maxAs_guess.Lerp2(x, y) : float.NaN; float pi_guess = pitchIs_guess != null?pitchIs_guess.Lerp2(x, y) : float.NaN; GenData genData = new GenData(vessel, conditions, conditions.lowerBoundSpeed + trueStepX * i, conditions.lowerBoundAltitude + trueStepY * j, manager, aoa_guess, maxA_guess, pi_guess); results[i, j] = genData.storeState; ThreadPool.QueueUserWorkItem(GenerateSurfPoint, genData); } } }
private List <AscentPathPoint> GetOptimalPath(AeroPredictor vessel, Conditions conditions, float exitSpeed, float exitAlt, float initialSpeed, float initialAlt, CostIncreaseFunction costIncreaseFunc, Predicate <float> neighborPredicate, float[,] predicateData, CostIncreaseFunction timeFunc) { System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch(); System.Diagnostics.Stopwatch profileWatch = new System.Diagnostics.Stopwatch(); long[] sections = new long[3]; stopwatch.Start(); EnvelopePointExtensions.UniqueQueue <Coords> queue = new EnvelopePointExtensions.UniqueQueue <Coords>(500); Coords baseCoord = new Coords(conditions.lowerBoundSpeed, conditions.lowerBoundAltitude, conditions.stepSpeed, conditions.stepAltitude, Mathf.RoundToInt((conditions.upperBoundSpeed - conditions.lowerBoundSpeed) / conditions.stepSpeed) + 1, Mathf.RoundToInt((conditions.upperBoundAltitude - conditions.lowerBoundAltitude) / conditions.stepAltitude) + 1); float rangeX = (conditions.upperBoundSpeed - conditions.lowerBoundSpeed) - conditions.stepSpeed; float rangeY = (conditions.upperBoundAltitude - conditions.lowerBoundAltitude) - conditions.stepAltitude; profileWatch.Start(); float[,] costMatrix = new float[baseCoord.width, baseCoord.height]; costMatrix.SetAll(float.MaxValue); baseCoord = new Coords(exitSpeed, exitAlt, baseCoord); if (!neighborPredicate(predicateData.Lerp2(exitSpeed / rangeX, exitAlt / rangeY))) { IEnumerator <CoordLocator> exitCoordFinder = CoordLocator.GenerateCoordLocators(predicateData).GetTaxicabNeighbors(baseCoord.xi, baseCoord.yi, -1, Linq2.Quadrant.II, Linq2.Quadrant.III, Linq2.Quadrant.IV); while (exitCoordFinder.MoveNext() && !neighborPredicate(exitCoordFinder.Current.value)) { } baseCoord = new Coords(exitCoordFinder.Current.x, exitCoordFinder.Current.y, baseCoord); exitSpeed = baseCoord.x; exitAlt = baseCoord.y; } costMatrix[baseCoord.xi, baseCoord.yi] = 0; foreach (Coords c in baseCoord.GetNeighbors(neighborPredicate, predicateData)) { queue.Enqueue(c); } Coords coord; while (queue.Count > 0) { coord = queue.Dequeue(); List <Coords> neighbors = coord.GetNeighbors(neighborPredicate, predicateData); Coords bestNeighbor = neighbors[0]; float bestCost = costMatrix[bestNeighbor.xi, bestNeighbor.yi]; for (int i = neighbors.Count - 1; i >= 1; i--) { if (costMatrix[neighbors[i].xi, neighbors[i].yi] < bestCost) { bestNeighbor = neighbors[i]; bestCost = costMatrix[bestNeighbor.xi, bestNeighbor.yi]; } } float newCost = bestCost + costIncreaseFunc(coord, bestNeighbor); if (newCost < costMatrix[coord.xi, coord.yi]) { costMatrix[coord.xi, coord.yi] = newCost; neighbors.Remove(bestNeighbor); for (int i = neighbors.Count - 1; i >= 0; i--) { if (costMatrix[neighbors[i].xi, neighbors[i].yi] > newCost) { queue.Enqueue(neighbors[i]); } } } } profileWatch.Stop(); sections[0] = profileWatch.ElapsedMilliseconds; profileWatch.Reset(); profileWatch.Start(); float[,] gradientx = new float[baseCoord.width - 1, baseCoord.height - 1]; float[,] gradienty = new float[baseCoord.width - 1, baseCoord.height - 1]; for (int i = baseCoord.width - 2; i >= 0; i--) { for (int j = baseCoord.height - 2; j >= 0; j--) { gradientx[i, j] = ((costMatrix[i + 1, j] - costMatrix[i, j]) + (costMatrix[i + 1, j + 1] - costMatrix[i, j + 1])) / 2 / conditions.stepAltitude; gradienty[i, j] = ((costMatrix[i, j + 1] - costMatrix[i, j]) + (costMatrix[i + 1, j + 1] - costMatrix[i + 1, j])) / 2 / conditions.stepSpeed; } } profileWatch.Stop(); sections[1] = profileWatch.ElapsedMilliseconds; profileWatch.Reset(); profileWatch.Start(); /*new Graphing.SurfGraph(costMatrix, conditions.lowerBoundSpeed, conditions.upperBoundSpeed, conditions.lowerBoundAltitude, conditions.upperBoundAltitude). * WriteToFile("costMatrix"); * new Graphing.SurfGraph(gradientx, conditions.lowerBoundSpeed + conditions.stepSpeed / 2, conditions.upperBoundSpeed - conditions.stepSpeed / 2, conditions.lowerBoundAltitude + conditions.stepAltitude / 2, conditions.upperBoundAltitude - conditions.stepAltitude / 2). * WriteToFile("gradientX"); * new Graphing.SurfGraph(gradienty, conditions.lowerBoundSpeed + conditions.stepSpeed / 2, conditions.upperBoundSpeed - conditions.stepSpeed / 2, conditions.lowerBoundAltitude + conditions.stepAltitude / 2, conditions.upperBoundAltitude - conditions.stepAltitude / 2). * WriteToFile("gradientY");*/ List <AscentPathPoint> result = new List <AscentPathPoint>(300); int iter = -1; coord = new Coords(initialSpeed, initialAlt, baseCoord); coord = new Coords(costMatrix.First(0, 0, f => f >= initialSpeed && f < float.MaxValue / 100) + 1, coord.yi, baseCoord); Coords lastCoord = coord; float lastCost = 0, lastTime = 0; while (true) { iter++; if (iter % 10 == 0) { //result.Add(new EnvelopePoint(vessel, conditions.body, coord.y, coord.x)); if (result.Count > 0) { lastCost = result[result.Count - 1].cost; lastTime = result[result.Count - 1].time; } result.Add(new AscentPathPoint(coord.x, coord.y, costIncreaseFunc(coord, lastCoord) + lastCost, (coord.y - lastCoord.y) / timeFunc(coord, lastCoord), timeFunc(coord, lastCoord) + lastTime)); float dx = (coord.x - lastCoord.x) / rangeX; float dy = (coord.y - lastCoord.y) / rangeY; float r = Mathf.Sqrt(dx * dx + dy * dy); //Debug.LogFormat("{0}\t{1}\t{2}", coord.x, coord.y, r); lastCoord = coord; if (r < 0.00001f && iter > 0) { break; } } float xW = (coord.x - conditions.stepSpeed / 2) / rangeX; float yW = (coord.y - conditions.stepAltitude / 2) / rangeY; if (Mathf.Abs(coord.x - exitSpeed) < 10 && Mathf.Abs(coord.y - exitAlt) < 100) { break; } try { Vector2 d = new Vector2(gradientx.Lerp2(xW, yW), gradienty.Lerp2(xW, yW)); if (d.sqrMagnitude <= 0) { break; } float step = 5 / Mathf.Sqrt(d.x * d.x + (d.y * conditions.stepSpeed / conditions.stepAltitude) * (d.y * conditions.stepSpeed / conditions.stepAltitude)); coord = coord.Offset(-d * step); } catch (Exception ex) { Debug.Log("Exception in gradient finding."); Debug.Log(iter); Debug.Log("xW: " + xW + " yW: " + yW); throw ex; } } coord = new Coords(exitSpeed, exitAlt, lastCoord); if (result.Count > 0) { lastCost = result[result.Count - 1].cost; lastTime = result[result.Count - 1].time; } result.Add(new AscentPathPoint(coord.x, coord.y, costIncreaseFunc(coord, lastCoord) + lastCost, (coord.y - lastCoord.y) / timeFunc(coord, lastCoord), timeFunc(coord, lastCoord) + lastTime)); profileWatch.Stop(); stopwatch.Stop(); Debug.Log("Time: " + stopwatch.ElapsedMilliseconds + " Iterations: " + iter); Debug.Log("Costing: " + sections[0] + " Gradients: " + sections[1] + " Minimizing: " + profileWatch.ElapsedMilliseconds); return(result); }
private IEnumerator Processing(CalculationManager manager, Conditions conditions, AeroPredictor vessel) { int numPtsX = (int)Math.Ceiling((conditions.upperBoundSpeed - conditions.lowerBoundSpeed) / conditions.stepSpeed); int numPtsY = (int)Math.Ceiling((conditions.upperBoundAltitude - conditions.lowerBoundAltitude) / conditions.stepAltitude); EnvelopePoint[,] newEnvelopePoints = new EnvelopePoint[numPtsX + 1, numPtsY + 1]; GenData rootData = new GenData(vessel, conditions, 0, 0, manager); //System.Diagnostics.Stopwatch timer = new System.Diagnostics.Stopwatch(); //timer.Start(); ThreadPool.QueueUserWorkItem(SetupInBackground, rootData, true); while (!manager.Completed) { //Debug.Log(manager.PercentComplete + "% done calculating..."); if (manager.Status == CalculationManager.RunStatus.Cancelled) { yield break; } yield return(0); } //timer.Stop(); //Debug.Log("Time taken: " + timer.ElapsedMilliseconds / 1000f); newEnvelopePoints = ((CalculationManager.State[, ])rootData.storeState.Result) .SelectToArray(pt => (EnvelopePoint)pt.Result); AddToCache(conditions, newEnvelopePoints); if (!manager.Cancelled) { envelopePoints = newEnvelopePoints; currentConditions = conditions; UpdateGraphs(); CalculateOptimalLines(vessel, conditions, WindTunnelWindow.Instance.TargetSpeed, WindTunnelWindow.Instance.TargetAltitude, 0, 0); valuesSet = true; } yield return(0); if (!manager.Cancelled) { Conditions nextConditions = conditions.Modify(stepSpeed: conditions.stepSpeed / 2, stepAltitude: conditions.stepAltitude / 2); WindTunnel.Instance.StartCoroutine(RefinementProcessing(calculationManager, nextConditions, vessel, newEnvelopePoints, conditions)); } }
private IEnumerator RefinementProcessing(CalculationManager manager, Conditions conditions, AeroPredictor vessel, EnvelopePoint[,] basisData, Conditions basisConditions = new Conditions(), Queue <Conditions> followOnConditions = null, bool forcePushToGraph = false) { int numPtsX = (int)Math.Ceiling((conditions.upperBoundSpeed - conditions.lowerBoundSpeed) / conditions.stepSpeed); int numPtsY = (int)Math.Ceiling((conditions.upperBoundAltitude - conditions.lowerBoundAltitude) / conditions.stepAltitude); EnvelopePoint[,] newEnvelopePoints = new EnvelopePoint[numPtsX + 1, numPtsY + 1]; CalculationManager backgroundManager = new CalculationManager(); manager.OnCancelCallback += backgroundManager.Cancel; CalculationManager.State[,] results = new CalculationManager.State[numPtsX + 1, numPtsY + 1]; GenData rootData = new GenData(vessel, conditions, 0, 0, backgroundManager); ThreadPool.QueueUserWorkItem(ContinueInBackground, new object[] { rootData, results, basisData, basisConditions }); while (!backgroundManager.Completed) { if (manager.Status == CalculationManager.RunStatus.Cancelled) { backgroundManager.Cancel(); yield break; } yield return(0); } manager.OnCancelCallback -= backgroundManager.Cancel; newEnvelopePoints = ((CalculationManager.State[, ])rootData.storeState.Result) .SelectToArray(pt => (EnvelopePoint)pt.Result); AddToCache(conditions, newEnvelopePoints); if (currentConditions.Equals(conditions) || (forcePushToGraph && !backgroundManager.Cancelled)) { envelopePoints = newEnvelopePoints; currentConditions = conditions; UpdateGraphs(); valuesSet = true; } backgroundManager.Dispose(); if (!manager.Cancelled && followOnConditions != null && followOnConditions.Count > 0) { yield return(0); Conditions nextConditions = followOnConditions.Dequeue(); WindTunnel.Instance.StartCoroutine(RefinementProcessing(manager, nextConditions, vessel, newEnvelopePoints, conditions, followOnConditions, forcePushToGraph)); } }
public EnvelopePoint(AeroPredictor vessel, CelestialBody body, float altitude, float speed, float AoA_guess = float.NaN, float maxA_guess = float.NaN, float pitchI_guess = float.NaN) { this.altitude = altitude; this.speed = speed; AeroPredictor.Conditions conditions = new AeroPredictor.Conditions(body, speed, altitude); float gravParameter, radius; gravParameter = (float)body.gravParameter; radius = (float)body.Radius; this.mach = conditions.mach; this.dynamicPressure = 0.0005f * conditions.atmDensity * speed * speed; float weight = (vessel.Mass * gravParameter / ((radius + altitude) * (radius + altitude))) - (vessel.Mass * speed * speed / (radius + altitude)); Vector3 thrustForce = vessel.GetThrustForce(conditions); fuelBurnRate = vessel.GetFuelBurnRate(conditions); //AoA_max = vessel.GetMaxAoA(conditions, out Lift_max, maxA_guess); if (float.IsNaN(maxA_guess)) { AoA_max = vessel.GetMaxAoA(conditions, out Lift_max, maxA_guess); //Lift_max = AeroPredictor.GetLiftForceMagnitude(vessel.GetAeroForce(conditions, AoA_max, 1) + thrustForce, AoA_max); } else { AoA_max = maxA_guess; Lift_max = AeroPredictor.GetLiftForceMagnitude(vessel.GetAeroForce(conditions, AoA_max, 1) + thrustForce, AoA_max); } AoA_level = vessel.GetAoA(conditions, weight, guess: AoA_guess, pitchInputGuess: 0, lockPitchInput: true); if (AoA_level < AoA_max) { pitchInput = vessel.GetPitchInput(conditions, AoA_level, guess: pitchI_guess); } else { pitchInput = 1; } if (speed < 5 && Math.Abs(altitude) < 10) { AoA_level = 0; } Thrust_available = thrustForce.magnitude; //vessel.GetAeroCombined(conditions, AoA_level, pitchInput, out force, out Vector3 torque); force = vessel.GetAeroForce(conditions, AoA_level, pitchInput); aeroforce = AeroPredictor.ToFlightFrame(force, AoA_level); //vessel.GetLiftForce(body, speed, altitude, AoA_level, mach, atmDensity); drag = -aeroforce.z; float lift = aeroforce.y; Thrust_excess = -drag - AeroPredictor.GetDragForceMagnitude(thrustForce, AoA_level); if (weight > Lift_max)// AoA_level >= AoA_max) { Thrust_excess = Lift_max - weight; AoA_level = AoA_max; } Accel_excess = (Thrust_excess / vessel.Mass / WindTunnelWindow.gAccel); LDRatio = Math.Abs(lift / drag); dLift = (vessel.GetLiftForceMagnitude(conditions, AoA_level + WindTunnelWindow.AoAdelta, pitchInput) - lift) / (WindTunnelWindow.AoAdelta * Mathf.Rad2Deg); //stabilityDerivative = (vessel.GetAeroTorque(conditions, AoA_level + WindTunnelWindow.AoAdelta, pitchInput).x - torque.x) // / (WindTunnelWindow.AoAdelta * Mathf.Rad2Deg); //GetStabilityValues(vessel, conditions, AoA_level, out stabilityRange, out stabilityScore); completed = true; }
private IEnumerator Processing(CalculationManager manager, Conditions conditions, AeroPredictor vessel) { int numPtsX = (int)Math.Ceiling((conditions.upperBoundSpeed - conditions.lowerBoundSpeed) / conditions.stepSpeed); int numPtsY = (int)Math.Ceiling((conditions.upperBoundAltitude - conditions.lowerBoundAltitude) / conditions.stepAltitude); EnvelopePoint[,] newEnvelopePoints = new EnvelopePoint[numPtsX + 1, numPtsY + 1]; GenData rootData = new GenData(vessel, conditions, 0, 0, manager); ThreadPool.QueueUserWorkItem(SetupInBackground, rootData); while (!manager.Completed) { //Debug.Log(manager.PercentComplete + "% done calculating..."); if (manager.Status == CalculationManager.RunStatus.Cancelled) { yield break; } yield return(0); } newEnvelopePoints = ((CalculationManager.State[, ])rootData.storeState.Result) .SelectToArray(pt => (EnvelopePoint)pt.Result); if (!manager.Cancelled) { //cache.Add(conditions, newEnvelopePoints); AddToCache(conditions, newEnvelopePoints); envelopePoints = newEnvelopePoints; currentConditions = conditions; GenerateGraphs(); valuesSet = true; } float stepSpeed = conditions.stepSpeed, stepAltitude = conditions.stepAltitude; for (int i = 2; i <= 2; i++) { yield return(0); CalculationManager backgroundManager = new CalculationManager(); manager.OnCancelCallback += backgroundManager.Cancel; conditions = new Conditions(conditions.body, conditions.lowerBoundSpeed, conditions.upperBoundSpeed, stepSpeed / i, conditions.lowerBoundAltitude, conditions.upperBoundAltitude, stepAltitude / i); CalculationManager.State[,] prevResults = ((CalculationManager.State[, ])rootData.storeState.Result).SelectToArray(p => p); rootData = new GenData(vessel, conditions, 0, 0, backgroundManager); ThreadPool.QueueUserWorkItem(ContinueInBackground, new object[] { rootData, prevResults }); while (!backgroundManager.Completed) { if (manager.Status == CalculationManager.RunStatus.Cancelled) { backgroundManager.Cancel(); yield break; } yield return(0); } newEnvelopePoints = ((CalculationManager.State[, ])rootData.storeState.Result) .SelectToArray(pt => (EnvelopePoint)pt.Result); if (!manager.Cancelled) { //cache.Add(conditions, newEnvelopePoints); AddToCache(conditions, newEnvelopePoints); envelopePoints = newEnvelopePoints; currentConditions = conditions; UpdateGraphs(); valuesSet = true; } } }
private static void GenerateLevel(Conditions conditions, CalculationManager manager, ref CalculationManager.State[,] results, AeroPredictor vessel, Conditions basisConditions = new Conditions(), EnvelopePoint[,] resultPoints = null) { float[,] AoAs_guess = null, maxAs_guess = null, pitchIs_guess = null; if (resultPoints != null) { AoAs_guess = resultPoints.SelectToArray(pt => pt.AoA_level); maxAs_guess = resultPoints.SelectToArray(pt => pt.AoA_max); pitchIs_guess = resultPoints.SelectToArray(pt => pt.pitchInput); } else if (results != null) { AoAs_guess = results.SelectToArray(pt => ((EnvelopePoint)pt.Result).AoA_level); maxAs_guess = results.SelectToArray(pt => ((EnvelopePoint)pt.Result).AoA_max); pitchIs_guess = results.SelectToArray(pt => ((EnvelopePoint)pt.Result).pitchInput); resultPoints = results.SelectToArray(pt => (EnvelopePoint)pt.Result); } int numPtsX = (int)Math.Ceiling((conditions.upperBoundSpeed - conditions.lowerBoundSpeed) / conditions.stepSpeed); int numPtsY = (int)Math.Ceiling((conditions.upperBoundAltitude - conditions.lowerBoundAltitude) / conditions.stepAltitude); float trueStepX = (conditions.upperBoundSpeed - conditions.lowerBoundSpeed) / numPtsX; float trueStepY = (conditions.upperBoundAltitude - conditions.lowerBoundAltitude) / numPtsY; results = new CalculationManager.State[numPtsX + 1, numPtsY + 1]; for (int j = 0; j <= numPtsY; j++) { for (int i = 0; i <= numPtsX; i++) { if (manager.Cancelled) { return; } float x = (float)i / numPtsX; float y = (float)j / numPtsY; float aoa_guess = AoAs_guess != null?AoAs_guess.Lerp2(x, y) : float.NaN; float maxA_guess = maxAs_guess != null?maxAs_guess.Lerp2(x, y) : float.NaN; float pi_guess = pitchIs_guess != null?pitchIs_guess.Lerp2(x, y) : float.NaN; float speed = conditions.lowerBoundSpeed + trueStepX * i; float altitude = conditions.lowerBoundAltitude + trueStepY * j; GenData genData = new GenData(vessel, conditions, speed, altitude, manager, aoa_guess, maxA_guess, pi_guess); results[i, j] = genData.storeState; if (!basisConditions.Equals(Conditions.Blank) && !basisConditions.Equals(new Conditions()) && basisConditions.Contains(speed, altitude, out int ii, out int jj)) { results[i, j].StoreResult(resultPoints[ii, jj]); }
private static void GetStabilityValues(AeroPredictor vessel, AeroPredictor.Conditions conditions, float AoA_centre, out float stabilityRange, out float stabilityScore) { const int step = 5; const int range = 90; const int alphaSteps = range / step; float[] torques = new float[2 * alphaSteps + 1]; float[] aoas = new float[2 * alphaSteps + 1]; int start, end; for (int i = 0; i <= 2 * alphaSteps; i++) { aoas[i] = (i - alphaSteps) * step * Mathf.Deg2Rad; torques[i] = vessel.GetAeroTorque(conditions, aoas[i], 0).x; } int eq = 0 + alphaSteps; int dir = (int)Math.Sign(torques[eq]); if (dir == 0) { start = eq - 1; end = eq + 1; } else { while (eq > 0 && eq < 2 * alphaSteps) { eq += dir; if (Math.Sign(torques[eq]) != dir) { break; } } if (eq == 0 || eq == 2 * alphaSteps) { stabilityRange = 0; stabilityScore = 0; return; } if (dir < 0) { start = eq; end = eq + 1; } else { start = eq - 1; end = eq; } } while (torques[start] > 0 && start > 0) { start -= 1; } while (torques[end] < 0 && end < 2 * alphaSteps - 1) { end += 1; } float min = (Mathf.InverseLerp(torques[start], torques[start + 1], 0) + start) * step; float max = (-Mathf.InverseLerp(torques[end], torques[end - 1], 0) + end) * step; stabilityRange = max - min; stabilityScore = 0; for (int i = start; i < end; i++) { stabilityScore += (torques[i] + torques[i + 1]) / 2 * step; } }
private IEnumerator Processing(CalculationManager manager, Conditions conditions, AeroPredictor vessel) { int numPts = (int)Math.Ceiling((conditions.upperBound - conditions.lowerBound) / conditions.step); AoAPoint[] newAoAPoints = new AoAPoint[numPts + 1]; float trueStep = (conditions.upperBound - conditions.lowerBound) / numPts; CalculationManager.State[] results = new CalculationManager.State[numPts + 1]; for (int i = 0; i <= numPts; i++) { //newAoAPoints[i] = new AoAPoint(vessel, conditions.body, conditions.altitude, conditions.speed, conditions.lowerBound + trueStep * i); GenData genData = new GenData(vessel, conditions, conditions.lowerBound + trueStep * i, manager); results[i] = genData.storeState; ThreadPool.QueueUserWorkItem(GenerateAoAPoint, genData); } while (!manager.Completed) { if (manager.Status == CalculationManager.RunStatus.Cancelled) { yield break; } yield return(0); } for (int i = 0; i <= numPts; i++) { newAoAPoints[i] = (AoAPoint)results[i].Result; } if (!manager.Cancelled) { cache.Add(conditions, newAoAPoints); AoAPoints = newAoAPoints; AverageLiftSlope = AoAPoints.Select(pt => pt.dLift / pt.dynamicPressure).Where(v => !float.IsNaN(v) && !float.IsInfinity(v)).Average(); currentConditions = conditions; GenerateGraphs(); valuesSet = true; } }