def test_from_body_non_tdb_epochs_warning(epochs): unused_body = Earth epochs = Time.now() # This uses UTC scale warning_pattern = "Input time was converted to scale='tdb'" with pytest.warns(TimeScaleWarning, match=warning_pattern): Ephem.from_body(unused_body, epochs)
def test_from_body_non_tdb_epochs_warning(epochs): unused_body = Earth epochs = Time.now() # This uses UTC scale with pytest.warns(TimeScaleWarning) as record: Ephem.from_body(unused_body, epochs) assert len(record) == 1 assert "Input time was converted to scale='tdb'" in record[0].message.args[ 0] assert "Use Time(..., scale='tdb') instead" in record[0].message.args[0]
def _get_ephem(self): for x in self.body_dict["bodies"]: body = DummyBody(moon_dict[x]["index"]) ephem = Ephem.from_body(body, self.current_time, attractor=self.body_dict["attractor"]) self.ephems[x] = ephem
def test_ephem_from_body_has_expected_properties(method, plane, FrameClass, rtol): epochs = Time( [ "2020-03-01 12:00:00", "2020-03-17 00:00:00.000", "2020-04-01 12:00:00.000" ], scale="tdb", ) equatorial_coordinates = CartesianRepresentation( [ (-1.40892271e08, 45067626.83900666, 19543510.68386639), (-1.4925067e08, 9130104.71634121, 3964948.59999307), (-1.46952333e08, -27413113.24215863, -11875983.21773582), ] * u.km, xyz_axis=1, differentials=CartesianDifferential( [ (-10.14262131, -25.96929533, -11.25810932), (-2.28639444, -27.3906416, -11.87218591), (5.67814544, -26.84316701, -11.63720607), ] * (u.km / u.s), xyz_axis=1, ), ) expected_coordinates = ( ICRS(equatorial_coordinates).transform_to(FrameClass).represent_as( CartesianRepresentation, CartesianDifferential)) earth = Ephem.from_body(Earth, epochs, plane=plane) coordinates = earth.sample(method=method) assert earth.epochs is epochs assert_coordinates_allclose(coordinates, expected_coordinates, rtol=rtol)
def _plot_body_orbit( self, body, epoch, *, label=None, color=None, trail=False, ): if color is None: color = BODY_COLORS.get(body.name) self.set_attractor(body.parent) # Get approximate, mean value for the period period = get_mean_elements(body, epoch).period label = generate_label(epoch, label or str(body)) epochs = time_range(epoch, periods=self._num_points, end=epoch + period, scale="tdb") ephem = Ephem.from_body(body, epochs, attractor=body.parent, plane=self.plane) return self._plot_ephem(ephem, epoch, label=label, color=color, trail=trail)
def _get_ephem_from_list_of_bodies( bodies, epochs) -> Dict[str, Tuple[SolarSystemPlanet, Ephem]]: list_of_bodies = {} for i in bodies: ephem = Ephem.from_body(i, epochs) list_of_bodies[i.name] = (i, ephem) return list_of_bodies
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_from_body_scalar_epoch_uses_reshaped_epochs(): expected_epochs = Time(["2020-03-01 12:00:00"], scale="tdb") epochs = expected_epochs[0] unused_plane = Planes.EARTH_EQUATOR ephem = Ephem.from_body(Earth, epochs, plane=unused_plane) assert ephem.epochs == expected_epochs
def get_earth_ephem(epoch=None): if epoch is None: today = date.today() epoch = time.Time(today.strftime("%Y-%m-%d") + " 12:00") # UTC by default earth_eph = Ephem.from_body(Earth, epoch.tdb) return earth_eph
def test_ephem_without_frame_raises_error(): epochs = time.Time("2020-04-29 10:43", scale="tdb") earth = Ephem.from_body(Earth, epochs) plotter = OrbitPlotter2D() with pytest.raises(ValueError) as excinfo: plotter.set_attractor(Sun) plotter.plot_ephem(earth) assert ("A frame must be set up first, please use " "set_orbit_frame(orbit) or plot(orbit)" in excinfo.exconly())
def test_from_ephem_has_expected_properties(): epoch = J2000_TDB ephem = Ephem.from_body(Earth, epoch, attractor=Sun) expected_r, expected_v = ephem.rv(epoch) ss = Orbit.from_ephem(Sun, ephem, epoch) assert ss.plane is ephem.plane assert ss.epoch == epoch assert_quantity_allclose(ss.r, expected_r) assert_quantity_allclose(ss.v, expected_v)
def bodies_vector(T, dt, body1, body2, epoch=J2000, timedelta = None): """Returns vector for every dt in [0,T] from bodie1 to bodie2 Parameters ---------- T : float time of propagation dt : float time interval body1 : ~poliastro.bodies.Body first body body2 : ~poliastro.bodies.Body second body epoch : ~astropy.time.Time, optional Epoch offset timedelta : ~astropy.time.Time, optional desired time of propagation Returns ------- diff : ~astropy.units.quantity.Quantity vectors for timedelta propagation from body1 to body2 """ DT_TIME = 500 if not timedelta: time_delta = Time([epoch + j*u.s for j in np.linspace(0,3600*24*1.01*T, int(3600*24*T/DT_TIME)) ] ) else: time_delta = timedelta ephem_b1 = Ephem.from_body(body1, time_delta.tdb) ephem_b2 = Ephem.from_body(body2, time_delta.tdb) tofs = Time([epoch + j*dt*u.s for j in range(10,int(3600*24*T/dt)+10)]) r_b1, _ = ephem_b1.rv(tofs) r_b2, _ = ephem_b2.rv(tofs) diff = (r_b2-r_b1).to(u.km) return diff
def reset(self): # get planet and spaceship positions at start_time, reset spaceship fuel, self.current_time = self.start_time self.current_ephem = self._get_ephem_from_list_of_bodies( self.body_list, self.start_time) # set up spacecraft self.spaceship = self._init_spaceship() start_body_ephem = Ephem.from_body(self.start_body, self.start_time) self.spaceship.rv = (self.spaceship.rv[0] + start_body_ephem.rv()[0], self.spaceship.rv[1] + start_body_ephem.rv()[1]) # convert spaceship rv to system-relative rather than earth observation = self._get_observation() return observation
def dist_chart(asteroid, date, timespan): solar_system_ephemeris.set('jpl') EPOCH = Time(date, scale="tdb") epochs = time_range(EPOCH - TimeDelta(timespan), end=EPOCH + TimeDelta(timespan)) epochs_moon = time_range(EPOCH - TimeDelta(15 * u.day), end=EPOCH + TimeDelta(15 * u.day)) moon = Ephem.from_body(Moon, epochs_moon, attractor=Earth) aster = Ephem.from_horizons(asteroid, epochs, attractor=Earth) plotter = StaticOrbitPlotter() plotter.set_attractor(Earth) plotter.set_body_frame(Moon) plotter.plot_ephem(moon, EPOCH, label=Moon) plotter.plot_ephem(aster, EPOCH, label=asteroid) return plotter
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)
frame = OrbitPlotter3D() frame.plot_body_orbit(Earth, J2000) frame.plot(eros, label="eros") # In[7]: from poliastro.ephem import Ephem from poliastro.util import time_range # In[8]: date_launch = time.Time("2011-11-26 15:02", scale="utc").tdb date_arrival = time.Time("2012-08-06 05:17", scale="utc").tdb earth = Ephem.from_body(Earth, time_range(date_launch, end=date_arrival, periods=50)) # In[9]: frame = OrbitPlotter3D() frame.set_attractor(Sun) frame.plot_body_orbit(Earth, J2000, label=Earth) frame.plot_ephem(earth, label=Earth) # In[10]: frame = OrbitPlotter3D() frame.plot(eros, label="eros") frame.plot_trajectory(earth.sample(), label=Earth)
ax.set_xlim(-8000, 8000) ax.set_ylim(-20000, 20000); # ### Option b): Compute $v_{\infty}$ using the Jupyter flyby # # According to Wikipedia, the closest approach occurred at 05:43:40 UTC. We can use this data to compute the solution of the Lambert problem between the Earth and Jupiter. # In[6]: nh_date = time.Time("2006-01-19 19:00", scale="utc").tdb nh_flyby_date = time.Time("2007-02-28 05:43:40", scale="utc").tdb nh_tof = nh_flyby_date - nh_date nh_r_0, v_earth = Ephem.from_body(Earth, nh_date).rv(nh_date) nh_r_f, v_jup = Ephem.from_body(Jupiter, nh_flyby_date).rv(nh_flyby_date) (nh_v_0, nh_v_f), = iod.lambert(Sun.k, nh_r_0, nh_r_f, nh_tof) # The hyperbolic excess velocity is measured with respect to the Earth: # In[7]: C_3_lambert = (norm(nh_v_0 - v_earth)).to(u.km / u.s) ** 2 C_3_lambert # In[8]:
# The initial data was gathered from Wikipedia: the date of the launch was on **November 26, 2011 at 15:02 UTC** and landing was on **August 6, 2012 at 05:17 UTC**. We compute then the time of flight, which is exactly what it sounds. # In[4]: # Initial data 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)
from poliastro.ephem import Ephem from poliastro.twobody import Orbit from poliastro.maneuver import Maneuver 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.
# In[8]: from poliastro.ephem import Ephem from poliastro.util import norm from astropy.time import Time # In[9]: flyby_1_time = Time("2018-09-28", scale="tdb") flyby_1_time # In[10]: r_mag_ref = norm(Ephem.from_body(Venus, flyby_1_time).rv()[0]) r_mag_ref.to(u.au) # In[11]: v_mag_ref = np.sqrt(2 * k / r_mag_ref - k / a_ref) v_mag_ref.to(u.km / u.s) # ## 2. Lambert arc between #0 and #1 # # To compute the arrival velocity to Venus at flyby #1, we have the necessary data to solve the boundary value problem. # In[12]: d_launch = Time("2018-08-11", scale="tdb") d_launch
end=EPOCH + TimeDelta(3 * 30 * u.day)) # In[10]: florence = Ephem.from_horizons("Florence", epochs, plane=Planes.EARTH_ECLIPTIC) florence # In[11]: florence.plane # And now, let's compute the distance between Florence and the Earth at that epoch: # In[12]: earth = Ephem.from_body(Earth, epochs, plane=Planes.EARTH_ECLIPTIC) earth # In[13]: from poliastro.util import norm # In[14]: min_distance = norm(florence.rv(EPOCH)[0] - earth.rv(EPOCH)[0]) - Earth.R min_distance.to(u.km) # <div class="alert alert-success">This value is consistent with what ESA says! $7\,060\,160$ km</div> # In[15]:
def _get_ephem_from_list_of_bodies(bodies, current_time): list_of_bodies = [] for i in bodies: body = Ephem.from_body(i, current_time) list_of_bodies.append([i, body]) return list_of_bodies
# Atlas V supplied a launch energy C_3 = 31.1 * u.km**2 / u.s**2 # With previous dates we can create the different orbits that define the position of the Earth along the mission. # In[3]: # Plot initial Earth's position Earth.plot(date_launch, label="Initial Earth's position") # Since both Earth states have been obtained (initial and flyby) we can now solve for Juno's maneuvers. The first one sets Juno into an elliptical orbit around the Sun so it apply a gravity assist around the Earth. # In[4]: earth = Ephem.from_body(Earth, time_range(date_launch, end=date_arrival, periods=500)) 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]: