public Maneuver(System.DateTime date, SatelliteMotion resulting_motion) { Date = date; ResultingMotion = resulting_motion; WasExecuted = false; }
public HohmannTransfer(SatelliteMotion original_motion, SatelliteMotion target_motion, System.DateTime earliest_departure_date) : base(original_motion, target_motion) { Debug.Assert(original_motion.Primary == target_motion.Primary); DepartureDate = GetLaunchWindow(earliest_departure_date); }
public void ChangeMotion(SatelliteMotion motion) { Motion = motion; if (Primary != null && transform.parent != Motion.Primary.SatellitesContainer) { transform.SetParent(Primary.SatellitesContainer); } }
//How much additional mass is required to push craft_mass public float GetPropellentMassRequired(Navigation.Transfer.Maneuver maneuver, SatelliteMotion craft_motion, float craft_mass) { float payload_fraction = Mathf.Pow( (float)System.Math.E, -GetVelocityChangeRequired(maneuver, craft_motion) / ExhaustVelocity); return(craft_mass / (1 / (1 - payload_fraction) - 1)); }
public System.DateTime GetLaunchWindow(System.DateTime earliest_launch, int launch_window_skip_count = 0) { //Can't use .TransferMotion here because this method is //used to determine DepartureDate, which is required for //calculating .TransferMotion SatelliteMotion simple_transfer_motion = new SatelliteMotion(TargetMotion.Primary, OriginalMotion.DistanceFromPrimary, TargetMotion.DistanceFromPrimary, 0, 0); if (simple_transfer_motion.Periapsis > simple_transfer_motion.Apoapsis) { Utility.Swap(ref simple_transfer_motion.Periapsis, ref simple_transfer_motion.Apoapsis); } float radial_launch_window = Mathf.PI - (2 * Mathf.PI) * (simple_transfer_motion.Period / 2) / TargetMotion.Period; float seconds_until_launch_window = (radial_launch_window - TargetMotion.TrueAnomalyAtDate(earliest_launch) + OriginalMotion.TrueAnomalyAtDate(earliest_launch)) / GetRelativeRadialVelocity(); while (seconds_until_launch_window < 0) { seconds_until_launch_window += GetLaunchWindowPeriod(); } System.DateTime launch_date = earliest_launch.AddSeconds(seconds_until_launch_window); launch_date.AddSeconds(GetLaunchWindowPeriod() * launch_window_skip_count); return(launch_date); }
public InterplanetaryTransfer(SatelliteMotion original_motion, SatelliteMotion target_motion, System.DateTime earliest_launch_date) : base(original_motion, target_motion) { Satellite transfer_primary = null; foreach (SatelliteMotion octave in original_motion.Hierarchy) { if (target_motion.Hierarchy.Contains(octave.Primary.Motion)) { transfer_primary = octave.Primary; break; } } Debug.Assert(transfer_primary != null); hohmann_transfer = new HohmannTransfer( OriginalMotion.Hierarchy.PreviousElement(transfer_primary.Motion), TargetMotion.Hierarchy.PreviousElement(transfer_primary.Motion), earliest_launch_date); }
public Transfer(SatelliteMotion original_motion, SatelliteMotion target_motion) { OriginalMotion = original_motion; TargetMotion = target_motion; }
public float GetVelocityChangeRequired(Navigation.Transfer.Maneuver maneuver, SatelliteMotion craft_motion) { //If craft's primary does not change, just take the difference in //velocities between current and target motion at the date of the //maneuver if (maneuver.ResultingMotion.Primary == Craft.Primary) { return((maneuver.ResultingMotion.LocalVelocityAtDate(maneuver.Date) - craft_motion.LocalVelocityAtDate(maneuver.Date)) .magnitude); } //In the more complex case of changing your orbit to another body, //this problem is solved by calculating total dV needed to escape n levels //(i.e. escaping lunar orbit to solar orbit is going down 2 levels) of //orbit and achieve the correct final relative velocity between craft //immediately before and after maneuver. Because of reversiblity of //orbits, the same dV is required for insertion (f.e. inserting into lunar //orbit from solar orbit) Therefore, I simply figure out which side would //be prior to escape ("innermost") and which would be after escape //("outermost"), and then solve the problem as an escape. SatelliteMotion innermost_motion = craft_motion, outermost_motion = maneuver.ResultingMotion; if (maneuver.ResultingMotion.Primary.IsChildOf(craft_motion.Primary)) { Utility.Swap(ref innermost_motion, ref outermost_motion); } Debug.Assert( maneuver.ResultingMotion.Primary.IsChildOf(craft_motion.Primary) || craft_motion.Primary.IsChildOf(maneuver.ResultingMotion.Primary), "Cannot enter orbit around primary's cousin in a single step."); int imaginary_primary_index = innermost_motion.Hierarchy.IndexOf(outermost_motion.Primary.Motion) - 1; SatelliteMotion top_level_satellite = innermost_motion.Hierarchy[imaginary_primary_index]; float top_level_velocity_change = (outermost_motion.LocalVelocityAtDate(maneuver.Date) - top_level_satellite.LocalVelocityAtDate(maneuver.Date)).magnitude; float current_level_velocity_change = top_level_velocity_change; float velocity_change = top_level_velocity_change; bool use_energy_based_solution = true; if (use_energy_based_solution) { //This solution simply sums the total potential energy gained //when escaping a planet/satellite and use it to calculate the //necessary periapsis velocity to escape with the correct amount //of kinetic energy. //The else case solves the same problem, but considers velocity directy //using formula v_infinity^2 = v_initial^2 - v_escape^2 //I implemented both in order to confirm the results of the other. float potential_energy_sum = 0; foreach (SatelliteMotion motion in innermost_motion.Hierarchy) { if (motion == top_level_satellite) { break; } potential_energy_sum += -MathConstants.GravitationalConstant * motion.Primary.Mass / motion.AltitudeAtDate(maneuver.Date); } velocity_change = Mathf.Abs( Mathf.Sqrt(2 * (Mathf.Pow(top_level_velocity_change, 2) / 2 - potential_energy_sum)) - innermost_motion.LocalVelocityAtDate(maneuver.Date).magnitude); } else { //Solve the problem for each stage in the journey //F.e. First you must escape the Moon, then you must still have //enough speed to escape the Earth, and finally, you must still //have enough speed to enter the new orbit around the sun. //The problem is solved backwards. We start with the //"infinity velocity" you should have upon escaping earth. This //is difference between earth's velocity and the craft's velocity //after the maneuver. Using the infinity velocity and the escape //velocity of earth, we can calculate the dV required to reach //that speed, given altitude. Then, assuming we aren't done //(if the craft is directly orbiting the earth, rather than the //moon, we're done), we use that dV as the new infinity velocity, //in this case the velocity we should have upon escaping the moon. //In both examples, the altitude used for escape velocity is //derived from going one level down in the hierarchy; with earth //as the primary, we use the moon's altitude. With the moon, we //use the craft's altitude. while (imaginary_primary_index > 0) { SatelliteMotion imaginary_craft_motion = innermost_motion.Hierarchy[imaginary_primary_index - 1]; Satellite imaginary_primary = imaginary_craft_motion.Primary; float escape_velocity = Mathf.Sqrt( 2 * MathConstants.GravitationalConstant * imaginary_primary.Mass / imaginary_craft_motion.AltitudeAtDate(maneuver.Date)); float infinity_velocity = current_level_velocity_change; float periapsis_velocity = Mathf.Sqrt(Mathf.Pow(infinity_velocity, 2) + Mathf.Pow(escape_velocity, 2)); current_level_velocity_change = periapsis_velocity; velocity_change = Mathf.Abs( periapsis_velocity - imaginary_craft_motion.LocalVelocityAtDate(maneuver.Date).magnitude); imaginary_primary_index--; } } return(velocity_change); }