//Computes the delta-V of the burn required to change an orbit's inclination to a given value //at a given UT. If the latitude at that time is too high, so that the desired inclination //cannot be attained, the burn returned will achieve as low an inclination as possible (namely, inclination = latitude). //The input inclination is in degrees. //Note that there are two orbits through each point with a given inclination. The convention used is: // - first, clamp newInclination to the range -180, 180 // - if newInclination > 0, do the cheaper burn to set that inclination // - if newInclination < 0, do the more expensive burn to set that inclination public static Vector3d DeltaVToChangeInclination(Orbit o, double UT, double newInclination) { double latitude = o.referenceBody.GetLatitude(o.SwappedAbsolutePositionAtUT(UT)); double desiredHeading = HeadingForInclination(newInclination, latitude); Vector3d actualHorizontalVelocity = Vector3d.Exclude(o.Up(UT), o.SwappedOrbitalVelocityAtUT(UT)); Vector3d eastComponent = actualHorizontalVelocity.magnitude * Math.Sin(Math.PI / 180 * desiredHeading) * o.East(UT); Vector3d northComponent = actualHorizontalVelocity.magnitude * Math.Cos(Math.PI / 180 * desiredHeading) * o.North(UT); if (Vector3d.Dot(actualHorizontalVelocity, northComponent) < 0) northComponent *= -1; if (MuUtils.ClampDegrees180(newInclination) < 0) northComponent *= -1; Vector3d desiredHorizontalVelocity = eastComponent + northComponent; return desiredHorizontalVelocity - actualHorizontalVelocity; }
//Computes the deltaV of the burn needed to set a given LAN at a given UT. public static Vector3d DeltaVToShiftLAN(Orbit o, double UT, double newLAN) { Vector3d pos = o.SwappedAbsolutePositionAtUT(UT); // Burn position in the same reference frame as LAN double burn_latitude = o.referenceBody.GetLatitude(pos); double burn_longitude = o.referenceBody.GetLongitude(pos) + o.referenceBody.rotationAngle; const double target_latitude = 0; // Equator double target_longitude = 0; // Prime Meridian // Select the location of either the descending or ascending node. // If the descending node is closer than the ascending node, or there is no ascending node, target the reverse of the newLAN // Otherwise target the newLAN if (o.AscendingNodeEquatorialExists() && o.DescendingNodeEquatorialExists()) { if (o.TimeOfDescendingNodeEquatorial(UT) < o.TimeOfAscendingNodeEquatorial(UT)) { // DN is closer than AN // Burning for the AN would entail flipping the orbit around, and would be very expensive // therefore, burn for the corresponding Longitude of the Descending Node target_longitude = MuUtils.ClampDegrees360(newLAN + 180.0); } else { // DN is closer than AN target_longitude = MuUtils.ClampDegrees360(newLAN); } } else if (o.AscendingNodeEquatorialExists() && !o.DescendingNodeEquatorialExists()) { // No DN target_longitude = MuUtils.ClampDegrees360(newLAN); } else if (!o.AscendingNodeEquatorialExists() && o.DescendingNodeEquatorialExists()) { // No AN target_longitude = MuUtils.ClampDegrees360(newLAN + 180.0); } else { throw new ArgumentException("OrbitalManeuverCalculator.DeltaVToShiftLAN: No Equatorial Nodes"); } double desiredHeading = MuUtils.ClampDegrees360(Heading(burn_latitude, burn_longitude, target_latitude, target_longitude)); Vector3d actualHorizontalVelocity = Vector3d.Exclude(o.Up(UT), o.SwappedOrbitalVelocityAtUT(UT)); Vector3d eastComponent = actualHorizontalVelocity.magnitude * Math.Sin(Math.PI / 180 * desiredHeading) * o.East(UT); Vector3d northComponent = actualHorizontalVelocity.magnitude * Math.Cos(Math.PI / 180 * desiredHeading) * o.North(UT); Vector3d desiredHorizontalVelocity = eastComponent + northComponent; return desiredHorizontalVelocity - actualHorizontalVelocity; }
//Computes the delta-V of the burn required to change an orbit's inclination to a given value //at a given UT. If the latitude at that time is too high, so that the desired inclination //cannot be attained, the burn returned will achieve as low an inclination as possible (namely, inclination = latitude). //The input inclination is in degrees. //Note that there are two orbits through each point with a given inclination. The convention used is: // - first, clamp newInclination to the range -180, 180 // - if newInclination > 0, do the cheaper burn to set that inclination // - if newInclination < 0, do the more expensive burn to set that inclination public static Vector3d DeltaVToChangeInclination(Orbit o, double UT, double newInclination) { double latitude = o.referenceBody.GetLatitude(o.SwappedAbsolutePositionAtUT(UT)); double desiredHeading = HeadingForInclination(newInclination, latitude); Vector3d actualHorizontalVelocity = Vector3d.Exclude(o.Up(UT), o.SwappedOrbitalVelocityAtUT(UT)); Vector3d eastComponent = actualHorizontalVelocity.magnitude * Math.Sin(Math.PI / 180 * desiredHeading) * o.East(UT); Vector3d northComponent = actualHorizontalVelocity.magnitude * Math.Cos(Math.PI / 180 * desiredHeading) * o.North(UT); if (Vector3d.Dot(actualHorizontalVelocity, northComponent) < 0) { northComponent *= -1; } if (MuUtils.ClampDegrees180(newInclination) < 0) { northComponent *= -1; } Vector3d desiredHorizontalVelocity = eastComponent + northComponent; return(desiredHorizontalVelocity - actualHorizontalVelocity); }
//Computes the deltaV of the burn needed to set a given LAN at a given UT. public static Vector3d DeltaVToShiftLAN(Orbit o, double UT, double newLAN) { Vector3d pos = o.SwappedAbsolutePositionAtUT(UT); // Burn position in the same reference frame as LAN double burn_latitude = o.referenceBody.GetLatitude(pos); double burn_longitude = o.referenceBody.GetLongitude(pos) + o.referenceBody.rotationAngle; const double target_latitude = 0; // Equator double target_longitude = 0; // Prime Meridian // Select the location of either the descending or ascending node. // If the descending node is closer than the ascending node, or there is no ascending node, target the reverse of the newLAN // Otherwise target the newLAN if (o.AscendingNodeEquatorialExists() && o.DescendingNodeEquatorialExists()) { if (o.TimeOfDescendingNodeEquatorial(UT) < o.TimeOfAscendingNodeEquatorial(UT)) { // DN is closer than AN // Burning for the AN would entail flipping the orbit around, and would be very expensive // therefore, burn for the corresponding Longitude of the Descending Node target_longitude = MuUtils.ClampDegrees360(newLAN + 180.0); } else { // DN is closer than AN target_longitude = MuUtils.ClampDegrees360(newLAN); } } else if (o.AscendingNodeEquatorialExists() && !o.DescendingNodeEquatorialExists()) { // No DN target_longitude = MuUtils.ClampDegrees360(newLAN); } else if (!o.AscendingNodeEquatorialExists() && o.DescendingNodeEquatorialExists()) { // No AN target_longitude = MuUtils.ClampDegrees360(newLAN + 180.0); } else { throw new ArgumentException("OrbitalManeuverCalculator.DeltaVToShiftLAN: No Equatorial Nodes"); } double desiredHeading = MuUtils.ClampDegrees360(Heading(burn_latitude, burn_longitude, target_latitude, target_longitude)); Vector3d actualHorizontalVelocity = Vector3d.Exclude(o.Up(UT), o.SwappedOrbitalVelocityAtUT(UT)); Vector3d eastComponent = actualHorizontalVelocity.magnitude * Math.Sin(Math.PI / 180 * desiredHeading) * o.East(UT); Vector3d northComponent = actualHorizontalVelocity.magnitude * Math.Cos(Math.PI / 180 * desiredHeading) * o.North(UT); Vector3d desiredHorizontalVelocity = eastComponent + northComponent; return(desiredHorizontalVelocity - actualHorizontalVelocity); }