private double Tasklet(AscentSimulationControl currentBestGuess, double currentBestScore, double perturbationScale, bool print, out AscentSimulationControl control, out LookAheadState lookAheadState, out State state) { control = new AscentSimulationControl() { InitialVerticalTime = Math.Max(5, currentBestGuess.InitialVerticalTime + (perturbationScale * _random.NextDouble(1))), KickPitchTime = Math.Max(0, currentBestGuess.KickPitchTime + (perturbationScale * _random.NextDouble(4))), KickPitchAngle = currentBestGuess.KickPitchAngle, //Math.Max(0, currentBestGuess.KickPitchAngle + (perturbationScale * _random.NextDouble(1))), StagingAngle = Math.Max(0, Math.Min(90, currentBestGuess.StagingAngle + (perturbationScale * _random.NextDouble(2)))), MaxAcceleration = Math.Max(0, currentBestGuess.MaxAcceleration + (perturbationScale * _random.NextDouble(0.1))), Rocket = currentBestGuess.Rocket //Stage1Duration = currentBestGuess.Stage1Duration, // + (perturbationScale * _random.NextDouble(3)), //Stage2Duration = currentBestGuess.Stage2Duration, // + (perturbationScale * _random.NextDouble(3)), //Stage1InitialAcceleration = currentBestGuess.Stage1InitialAcceleration, //Stage1MaxAcceleration = currentBestGuess.Stage1MaxAcceleration, //Stage2InitialAcceleration = currentBestGuess.Stage2InitialAcceleration, //Stage2MaxAcceleration = currentBestGuess.Stage2MaxAcceleration //InitialTurnDuration = currentBestGuess.InitialTurnDuration + (perturbationScale * _random.NextDouble(0.2)), //MaxThrust1 = currentBestGuess.MaxThrust1, //MinThrust1 = currentBestGuess.MinThrust1, //MaxThrust2 = currentBestGuess.MaxThrust2, //MinThrust2 = currentBestGuess.MinThrust2, //ThrustCutoff = 1000, // Math.Max(0, currentBestGuess.ThrustCutoff + (perturbationScale * _random.NextDouble(5))), ////ThrustCurve = Math.Max(0, currentBestGuess.ThrustCurve + (perturbationScale * _random.NextDouble(5))), //ThrustDuration1 = Math.Max(0, currentBestGuess.ThrustDuration1 + (perturbationScale * _random.NextDouble(5))), //ThrustDuration2 = Math.Max(0, currentBestGuess.ThrustDuration2 + (perturbationScale * _random.NextDouble(5))), //TurnDelay = currentBestGuess.TurnDelay, //Math.Max(0, currentBestGuess.TurnDelay + (perturbationScale * _random.NextDouble(1))), //TurnDuration = Math.Max(0, currentBestGuess.TurnDuration + (perturbationScale * _random.NextDouble(1))), }; var simulation = new AscentSimulation(Goal, control, InitialState, SurfaceVelocity); double totalFuelMass = control.Rocket.TotalFuelMass(); while (!simulation.CurrentState.IsDone) { //Console.WriteLine("{0} {1}", simulation.CurrentState.ExpendedMass - totalFuelMass, simulation.CurrentState.Time); simulation.FastTick(TimeStep, MicroSteps); if (simulation.LookAheadState.Apoapsis / 1000.0 > (Goal.Apoapsis + 15) || simulation.LookAheadState.Periapsis / 1000.0 > (Goal.Periapsis + 15)) { //control.Stage2Duration = Math.Max(0, simulation.CurrentState.Time - control.Stage1Duration); break; } } if (print) { Print(Goal, simulation.LookAheadState, simulation.CurrentState, control, currentBestScore); } lookAheadState = simulation.LookAheadState; state = simulation.CurrentState; return(ComputeScore(Goal, simulation.LookAheadState, state, control)); }
private static void Print(AscentSimulationGoal goal, LookAheadState lookAheadState, State state, AscentSimulationControl guess, double bestScore) { Console.WriteLine("{0,1:F} {1,1:F}, {2,2:F}/{3,2:F}: g {4,1:F}, d {5,1:F}, mass left {6,2:F} kg - score {7,3:F}/{8,3:F}", (lookAheadState.Periapsis) / 1000.0, (lookAheadState.Apoapsis) / 1000.0, (state.Position.Length - Constants.EarthRadius) / 1000.0, state.ReachedAltitude / 1000.0, state.LossesToGravity, state.LossesToDrag, guess.Rocket.TotalFuelMass() - state.ExpendedMass, ComputeScore(goal, lookAheadState, state, guess), bestScore ); }
public static double ComputeScore(AscentSimulationGoal goal, LookAheadState lookAheadState, State state, AscentSimulationControl guess) { const double distanceScaling = 10.0; double distanceFromApoapsisGoal = lookAheadState.Apoapsis / 1000.0 - goal.Apoapsis; double distanceFromPeriapsisGoal = lookAheadState.Periapsis / 1000.0 - goal.Periapsis; double distanceFromReachedAltitudeGoal = state.ReachedAltitude / 1000.0 - goal.Periapsis; double distanceFromAltitudeGoal = (state.Position.Length - Constants.EarthRadius) / 1000.0 - goal.Periapsis; double totalFuel = guess.Rocket.TotalFuelMass(); double fuelLeft = (totalFuel - state.ExpendedMass) / totalFuel; return(ErrorFunction(distanceFromApoapsisGoal, distanceScaling) + ErrorFunction(distanceFromPeriapsisGoal, distanceScaling) + ErrorFunction(distanceFromReachedAltitudeGoal, distanceScaling) + ErrorFunction(distanceFromAltitudeGoal, distanceScaling) + fuelLeft * 5); //+ ErrorFunction((guess.ThrustDuration1 + guess.ThrustDuration2) - guess.ThrustCutoff, 1); }
public static void CalculateOrbit(ref LookAheadState lookAheadState, State state) { var mu = Constants.EarthGravitationalConstant; var radiusVector = state.Position; var velocityVector = state.Velocity; var h = Vector3d.Cross( radiusVector, velocityVector ); var r = radiusVector.Length; var eccentricityVector = ( (velocityVector.LengthSquared - mu / r) * radiusVector - Vector3d.Dot(radiusVector, velocityVector) * velocityVector ) / mu; var eccentricity = eccentricityVector.Length; var specificOrbitalEnergy = velocityVector.LengthSquared / 2 - mu / r; var semiMajorAxis = -mu / (2 * specificOrbitalEnergy); var semiMinorAxis = semiMajorAxis * Math.Sqrt(1 - eccentricity * eccentricity); var apoapsis = (1 + eccentricity) * semiMajorAxis; var periapsis = (1 - eccentricity) * semiMajorAxis; var semiLatusRectum = periapsis * (1 + eccentricity); var thetaFromPeriapsis = Math.Acos(((semiLatusRectum - r) / (eccentricity * r)) % (Math.PI * 2)); var actualRotation = Math.Atan2(radiusVector.Y, radiusVector.X) + Math.PI / 2; double argumentOfPeriapsis; if (h.Z < 0) { thetaFromPeriapsis = Math.PI * 2 - thetaFromPeriapsis; argumentOfPeriapsis = actualRotation - thetaFromPeriapsis; //rotationMatrix = Matrix4d.Mult(rotationMatrix, Matrix4d.RotateY(Math.PI)); } else { argumentOfPeriapsis = actualRotation - thetaFromPeriapsis; } var rotationMatrix = Matrix4d.CreateRotationZ(argumentOfPeriapsis); int highAccuracyPoints = lookAheadState.FuturePositions.Length / 2; double highAccuracyAngle = Math.PI / 20; if (SampleOrbit(ref lookAheadState.FuturePositions, ref rotationMatrix, semiLatusRectum, eccentricity, thetaFromPeriapsis, highAccuracyAngle, 0, highAccuracyPoints)) { SampleOrbit(ref lookAheadState.FuturePositions, ref rotationMatrix, semiLatusRectum, eccentricity, thetaFromPeriapsis - highAccuracyAngle, Math.PI * 2 - highAccuracyAngle, highAccuracyPoints, lookAheadState.FuturePositions.Length - highAccuracyPoints); } //double approximatePerimeter = Math.PI * (3 * (semiMajorAxis + semiMinorAxis) - Math.Sqrt((3*semiMajorAxis + semiMinorAxis) * (semiMajorAxis + 3*semiMinorAxis))); lookAheadState.Apoapsis = apoapsis - Constants.EarthRadius; lookAheadState.Periapsis = periapsis - Constants.EarthRadius; lookAheadState.Eccentricity = eccentricity; lookAheadState.SemiMajorAxis = semiMajorAxis; lookAheadState.SemiMinorAxis = semiMinorAxis; lookAheadState.SemiLatusRectum = semiLatusRectum; lookAheadState.ArgumentOfPeriapsis = argumentOfPeriapsis; lookAheadState.Theta = thetaFromPeriapsis; //Title = string.Format("e{0,2:F}, {1,2:F} km {2,2:F} km, r {3,2:F}, v {4,2:F} {5,2:F} {6,2:F} {7,2:F}, a{8,2:F} b{9,2:F}", e, (apoapsis - Constants.EarthRadius)/1000, (periapsis - Constants.EarthRadius) / 1000, (radiusVector.Length - Constants.EarthRadius) /1000, velocityVector.Length / 1000, theta2, actualRotation, offset, (a - Constants.EarthRadius)/1000, (b - Constants.EarthRadius)/1000); /* * GL.PushMatrix(); * //GL.Rotate(offset / Math.PI * 180, Vector3d.UnitZ); * GL.LineWidth(2f); * GL.Color3(1f, 0f, 0f); * GL.Begin(PrimitiveType.LineLoop); * for (var theta = 0.0; theta < Math.PI * 2.0; theta += 0.01) * { * GL.Vertex3(Math.Sin(theta) * b, Math.Cos(theta) * a + (apoapsis - a), 0); * } * GL.End(); * GL.PopMatrix(); */ }