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
Example #2
0
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
Example #3
0
    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