def distance_chart(body1, body2, date_start, interval, steps): """Generates a distance chart between body1 (e.g. Earth) and body2 (e.g. Mars) from date_start till interval (e.g. 10 days) and steps (36). Returns plotly's Figure.""" eph1 = Ephem.from_body( body1, time_range(date_start, end=date_start + steps * interval)) eph2 = Ephem.from_body( body2, time_range(date_start, end=date_start + steps * interval)) # Solve for departure and target orbits orb1 = Orbit.from_ephem(Sun, eph1, date_start) orb2 = Orbit.from_ephem(Sun, eph2, date_start) t_tbl = [] dist_tbl = [] t = date_start for i in range(1, steps): day = str(orb1.epoch)[:10] # take the first "2020-01-01" from the date t_tbl.append(day) dist = np.linalg.norm(orb1.r - orb2.r) dist_tbl.append(dist.value) orb1 = orb1.propagate(interval) orb2 = orb2.propagate(interval) fig = go.Figure() fig.add_trace( go.Scatter(x=t_tbl, y=dist_tbl, mode="lines+markers", name="Earth - Mars distance")) name = body1.name + "-" + body2.name + " distance" fig.update_layout(legend=dict(orientation="h", yanchor="bottom", y=1.02, xanchor="right", x=1), xaxis_title="date", yaxis_title="Distance [km]", title=name, margin=dict(l=20, r=20, t=40, b=20)) return fig
def test_plot_ephem_no_epoch(): epoch = Time("2020-02-14 00:00:00") ephem = Ephem.from_horizons( "2020 CD3", time_range(Time("2020-02-13 12:00:00"), end=Time("2020-02-14 12:00:00")), attractor=Earth, ) fig, ax = plt.subplots() plotter = StaticOrbitPlotter(ax=ax) plotter.set_attractor(Earth) plotter.set_orbit_frame(Orbit.from_ephem(Earth, ephem, epoch)) plotter.plot_ephem(ephem, label="2020 CD3 Minimoon", color="k") return fig
def set_body_frame(self, body, epoch=None): """Sets perifocal frame based on the orbit of a body at a particular epoch if given. Parameters ---------- body : poliastro.bodies.SolarSystemPlanet Body. epoch : astropy.time.Time, optional Epoch of current position. """ from warnings import warn from astropy import time from poliastro.bodies import Sun from poliastro.twobody import Orbit from ..warnings import TimeScaleWarning if not epoch: epoch = time.Time.now().tdb elif epoch.scale != "tdb": epoch = epoch.tdb warn( "Input time was converted to scale='tdb' with value " f"{epoch.tdb.value}. Use Time(..., scale='tdb') instead.", TimeScaleWarning, stacklevel=2, ) with warnings.catch_warnings(): ephem = Ephem.from_body(body, epoch, attractor=Sun, plane=self.plane) # type: ignore orbit = Orbit.from_ephem(Sun, ephem, epoch).change_plane( self.plane) # type: ignore self.set_orbit_frame(orbit)
date_launch = time.Time("2011-11-26 15:02", scale="utc").tdb date_arrival = time.Time("2012-08-06 05:17", scale="utc").tdb # To compute the transfer orbit, we have the useful function `lambert` : according to a theorem with the same name, *the transfer orbit between two points in space only depends on those two points and the time it takes to go from one to the other*. We could make use of the raw algorithms available in `poliastro.iod` for solving this but working with the `poliastro.maneuvers` is even easier! # # We just need to create the orbits for each one of the planets at the specific departure and arrival dates. # In[5]: earth = Ephem.from_body(Earth, time_range(date_launch, end=date_arrival)) mars = Ephem.from_body(Mars, time_range(date_launch, end=date_arrival)) # In[6]: # Solve for departure and target orbits ss_earth = Orbit.from_ephem(Sun, earth, date_launch) ss_mars = Orbit.from_ephem(Sun, mars, date_arrival) # We can now solve for the maneuver that will take us from Earth to Mars. After solving it, we just need to apply it to the departure orbit to solve for the transfer one. # In[7]: # Solve for the transfer maneuver man_lambert = Maneuver.lambert(ss_earth, ss_mars) # Get the transfer and final orbits ss_trans, ss_target = ss_earth.apply_maneuver(man_lambert, intermediate=True) # Let's plot this transfer orbit in 3D! # In[8]:
from poliastro.plotting.static import StaticOrbitPlotter from poliastro.util import time_range # In[2]: # Departure and time of flight for the mission EPOCH_DPT = Time("2018-12-01", scale="tdb") EPOCH_ARR = EPOCH_DPT + 2 * u.year epochs = time_range(EPOCH_DPT, end=EPOCH_ARR) # Origin and target orbits earth = Ephem.from_body(Earth, epochs=epochs) mars = Ephem.from_body(Mars, epochs=epochs) earth_departure = Orbit.from_ephem(Sun, earth, EPOCH_DPT) mars_arrival = Orbit.from_ephem(Sun, mars, EPOCH_ARR) # In[3]: def lambert_transfer(ss_dpt, ss_arr, revs): """ Returns the short and long transfer orbits when solving Lambert's problem. Parameters ---------- ss_dpt: poliastro.twobody.Orbit Deprature orbit. ss_arr: poliastro.twobody.Orbit Arrival orbit. revs: int
# In[20]: moon = Ephem.from_body(Moon, epochs, attractor=Earth) moon # In[21]: from poliastro.plotting.static import StaticOrbitPlotter plotter = StaticOrbitPlotter() plotter.set_attractor(Earth) plotter.set_body_frame(Moon) plotter.plot_ephem(moon, EPOCH, label=Moon, color=C_MOON) # And now, the glorious final plot: # In[22]: import matplotlib.pyplot as plt frame = StaticOrbitPlotter() frame.set_attractor(Earth) frame.set_orbit_frame(Orbit.from_ephem(Earth, florence_e, EPOCH)) frame.plot_ephem(florence_e, EPOCH, label="Florence", color=C_FLORENCE) frame.plot_ephem(moon, EPOCH, label=Moon, color=C_MOON) plt.show() # <div style="text-align: center; font-size: 3em;"><em>Per Python ad astra!</em></div>
r_e0, v_e0 = earth.rv(date_launch) # In[5]: # Assume that the insertion velocity is tangential to that of the Earth dv = C_3**0.5 * v_e0 / norm(v_e0) # We create the maneuver from impulse constructor man = Maneuver.impulse(dv) # If we now apply previous maneuver to the Junos's initial orbit (assume it is the Earth's one for simplicity), we will obtain the orbit around the Sun for Juno. The first inner cruise maneuver is defined just till the ahelion orbit. While Juno is traveling around its new orbit, Earth is also moving. After Juno reaches the aphelion it will be necessary to apply a second maneuver so the flyby is performed around Earth. Once that is achieved a final maneuver will be made in order to benefit from the gravity assist. Let us first propagate Juno's orbit till the aphelion. # In[6]: ss_e0 = Orbit.from_ephem(Sun, earth, date_launch) ss_efly = Orbit.from_ephem(Sun, earth, date_flyby) # Inner Cruise 1 ic1 = ss_e0.apply_maneuver(man) ic1_end = ic1.propagate_to_anomaly(180.0 * u.deg) # We solve for Earth's position when Juno is at aphelion ss_e_ic1 = Orbit.from_ephem(Sun, earth, epoch=ic1_end.epoch) # We can check new bodies positions plotter = StaticOrbitPlotter() plotter.plot_body_orbit(Earth, ic1_end.epoch, label="Earth at end of flyby") plotter.plot_trajectory( ic1_end.sample(min_anomaly=0 * u.deg, max_anomaly=180 * u.deg), label="Inner cruise 1 full orbit",
def transfer_vel(body1, body2, attractor): """Returns transfer parameters for body1 (e.g. Earth) to body2 (e.g. Mars). Optionally, the main attractor can be specified. If omitted, Sun is assumed. Returns: helio1 - heliocentric velocity at departure (before Hohmann) (body1) helio2 - heliocentric velocity at arrival (body2) v1 - heliocentric velocity at departure (after Hohmann burn) v2 - heliocentric velocity at arrival (before Hohmann burn) tof - time of flight (in days) """ # How to obtain the orbit. The from_horisons method seems to be no longer supported # as of perylune 0.16.3. method = "ephem" # allowed values are ephem, horizons_orbit if attractor is None: attractor = Sun # Let's assume the calculations are done for 2020. date_start = time.Time("2020-01-01 00:00", scale="utc").tdb date_end = time.Time("2021-12-31 23:59", scale="utc").tdb name1, id_type1 = name_to_horizons_id(body1) name2, id_type2 = name_to_horizons_id(body2) if method == "ephem": # Get the ephemerides first and then contruct orbit based on them. This is the recommended # way. See warning in Orbit.from_horizons about deprecation. ephem1 = Ephem.from_horizons(name=name1, epochs=time_range(date_start, end=date_end), plane=Planes.EARTH_ECLIPTIC, id_type=id_type1) ephem2 = Ephem.from_horizons(name=name2, epochs=time_range(date_start, end=date_end), plane=Planes.EARTH_ECLIPTIC, id_type=id_type2) # Solve for departure and target orbits orb1 = Orbit.from_ephem(Sun, ephem1, date_start + 180 * u.day) orb2 = Orbit.from_ephem(Sun, ephem2, date_end) elif method == "horizons_orbit": # This is the old way. Sadly, it produces way better values. orb1 = Orbit.from_horizons(name=name1, attractor=attractor, plane=Planes.EARTH_ECLIPTIC, id_type=id_type1) orb2 = Orbit.from_horizons(name=name2, attractor=attractor, plane=Planes.EARTH_ECLIPTIC, id_type=id_type2) else: raise "Invalid method set." # The escape_delta_v returns a tuple of escape velocity at current, periapsis, apoapsis. helio1 = heliocentric_velocity(orb1) helio2 = heliocentric_velocity(orb2) #vesc1 = escape_vel(orb1, False)[1] #vesc2 = escape_vel(orb2, False)[1] hoh1, hoh2, tof = hohmann_velocity(orb1, orb2) return helio1, helio2, hoh1, hoh2, tof