def _targetting(departure_body, target_body, t_launch, t_arrival): """This function returns the increment in departure and arrival velocities. """ rr_dpt_body, vv_dpt_body = _get_state(departure_body, t_launch) rr_arr_body, vv_arr_body = _get_state(target_body, t_arrival) # Compute time of flight tof = t_arrival - t_launch if tof <= 0: return None, None, None, None, None try: (v_dpt, v_arr), = lambert(Sun.k, rr_dpt_body.xyz, rr_arr_body.xyz, tof) # Compute all the output variables dv_dpt = norm(v_dpt - vv_dpt_body.xyz) dv_arr = norm(v_arr - vv_arr_body.xyz) c3_launch = dv_dpt**2 c3_arrival = dv_arr**2 return ( dv_dpt.to(u.km / u.s).value, dv_arr.to(u.km / u.s).value, c3_launch.to(u.km**2 / u.s**2).value, c3_arrival.to(u.km**2 / u.s**2).value, tof.jd, ) except AssertionError: return None, None, None, None, None
def _targetting(departure_body, target_body, t_launch, t_arrival): """This function returns the increment in departure and arrival velocities. """ rr_dpt_body, vv_dpt_body = _get_state(departure_body, t_launch) rr_arr_body, vv_arr_body = _get_state(target_body, t_arrival) # Compute time of flight tof = t_arrival - t_launch if tof <= 0: return None, None, None, None, None try: (v_dpt, v_arr), = lambert(Sun.k, rr_dpt_body.xyz, rr_arr_body.xyz, tof) # Compute all the output variables dv_dpt = norm(v_dpt - vv_dpt_body.xyz) dv_arr = norm(v_arr - vv_arr_body.xyz) c3_launch = dv_dpt ** 2 c3_arrival = dv_arr ** 2 return ( dv_dpt.to(u.km / u.s).value, dv_arr.to(u.km / u.s).value, c3_launch.to(u.km ** 2 / u.s ** 2).value, c3_arrival.to(u.km ** 2 / u.s ** 2).value, tof.jd, ) except AssertionError: return None, None, None, None, None
def lambert(self, r0, rf, tof, m=0): k = self.star.mu * u.m**3 / u.s**2 r0 = r0 * u.m rf = rf * u.m tof = tof * u.s (v0, v), = iod.lambert(k, r0, rf, tof, M=m) v0 = [1000 * v0.value[0], 1000 * v0.value[1], 1000 * v0.value[2]] v = [1000 * v.value[0], 1000 * v.value[1], 1000 * v.value[2]] return v0, v
def test_curtis53(self): k = k_earth.to(units.km ** 3 / units.s ** 2).value r0 = np.array([273378.0, 0.0, 0.0]) r = np.array([145820.0, 12758.0, 0.0]) tof = 13.5 * 3600.0 va, vb = lambert(k, r0, r, tof) # ERRATA: j component is positive assert_array_almost_equal(va, np.array([-2.4356, 0.26741, 0.0]), decimal=3)
def test_curtis52(self): k = k_earth.to(units.km ** 3 / units.s ** 2).value r0 = np.array([5000.0, 10000.0, 2100.0]) r = np.array([-14600.0, 2500.0, 7000.0]) tof = 3600.0 va, vb = lambert(k, r0, r, tof) assert_array_almost_equal(va, np.array([-5.9925, 1.9254, 3.2456]), decimal=3) assert_array_almost_equal(vb, np.array([-3.3125, -4.1966, -0.38529]), decimal=3)
def test_vallado75(self): k = k_earth.to(units.km ** 3 / units.s ** 2).value r0 = np.array([15945.34, 0.0, 0.0]) r = np.array([12214.83399, 10249.46731, 0.0]) tof = 76.0 * 60.0 va, vb = lambert(k, r0, r, tof) assert_array_almost_equal(va, np.array([2.058925, 2.915956, 0.0]), decimal=3) assert_array_almost_equal(vb, np.array([-3.451569, 0.910301, 0.0]), decimal=3)
def test_curtis53(): k = Earth.k r0 = [273378.0, 0.0, 0.0] * u.km r = [145820.0, 12758.0, 0.0] * u.km tof = 13.5 * u.h # ERRATA: j component is positive expected_va = [-2.4356, 0.26741, 0.0] * u.km / u.s va, vb = lambert(k, r0, r, tof) assert_array_almost_equal(va.to(u.km / u.s).value, expected_va.value, decimal=3)
def test_curtis52(): k = Earth.k r0 = [5000.0, 10000.0, 2100.0] * u.km r = [-14600.0, 2500.0, 7000.0] * u.km tof = 1.0 * u.h expected_va = [-5.9925, 1.9254, 3.2456] * u.km / u.s expected_vb = [-3.3125, -4.1966, -0.38529] * u.km / u.s va, vb = lambert(k, r0, r, tof) assert_array_almost_equal(va.to(u.km / u.s).value, expected_va.value, decimal=4) assert_array_almost_equal(vb.to(u.km / u.s).value, expected_vb.value, decimal=4)
def test_vallado75(): k = Earth.k r0 = [15945.34, 0.0, 0.0] * u.km r = [12214.83399, 10249.46731, 0.0] * u.km tof = 76.0 * u.min expected_va = [2.058925, 2.915956, 0.0] * u.km / u.s expected_vb = [-3.451569, 0.910301, 0.0] * u.km / u.s va, vb = lambert(k, r0, r, tof) assert_array_almost_equal(va.to(u.km / u.s).value, expected_va.value, decimal=4) assert_array_almost_equal(vb.to(u.km / u.s).value, expected_vb.value, decimal=5)
def optimal_transit(date, transit_min, transit_max, planet1, planet2, vs0, step): date_arrival = date + transit_min # minimalna data wykonania tranzytu date_max = date + transit_max # maksymalna data wykonania, zakonczenie petli date_arrival_final = date_arrival vs_temp = 0 * u.km / u.s dv_final = 0 * u.km / u.s step_first = True # petla idaca po datach z okreslonym krokiem while date_arrival < date_max: tof = date_arrival - date # tof - time of flight date_iso = time.Time(str(date.iso), scale='utc') # data startu date_arrival_iso = time.Time(str(date_arrival.iso), scale='utc') # data przylotu r1 = Orbit.from_body_ephem(planet1, date_iso) r2 = Orbit.from_body_ephem(planet2, date_arrival_iso) r_1, v_1 = r1.rv() # pozycja i predkosc planety poczatkowej r_2, v_2 = r2.rv() # pozycja i predkosc planety koncowej (vs1, vs2), = iod.lambert(Sun.k, r_1, r_2, tof) # rozwiazanie zagadnienia lamberta dv_vector = vs1 - ( vs0 + (v_1 / (24 * 3600) * u.day / u.s) ) # zmiana predkosci niezbedna do udanego wykonania manewru dv = np.linalg.norm( dv_vector / 10) * u.km / u.s # modul wektora zmiany predkosci if step_first: # zapis wynikow z pierwszego kroku dv_final = dv vs_temp = vs2 step_first = False else: if dv < dv_final: # sprawdzenie czy kolejny krok jest bardziej korzystna dv_final = dv date_arrival_final = date_arrival vs_temp = vs2 date_arrival += step * u.day return dv_final, date_arrival_final, vs_temp # funkcja zwraca niezbedny przyrost predkosci, date przybycia
def transit(date, date_arrival, planet1, planet2): #czas trwania misji tof = date_arrival - date N = 50 tof.to(u.h) times_vector = time_range(date, end=date_arrival, periods=N) # okreslenie pozycji planet w przedziale czasu: od startu do końca misji rr_planet1, vv_planet1 = get_body_barycentric_posvel(planet1, times_vector) rr_planet2, vv_planet2 = get_body_barycentric_posvel(planet2, times_vector) r0 = rr_planet1[0].xyz #wektor pozycji Ziemi w momencie startu v0 = vv_planet1[0].xyz #wektor predkosci Ziemi w momencie startu rf = rr_planet2[ -1].xyz #wektor pozycji planety docelowej w momencie końca misji vf = vv_planet2[ -1].xyz #wektor predkosci planety docelowej w momencie końca misji # rozwiazanie problemu Lamberta (va, vb), = iod.lambert(Sun.k, r0, rf, tof, numiter=1000) return (r0, v0, rf, vf, va, vb, rr_planet1, rr_planet2, times_vector)
times_vector = time.Time(jd_vec, format='jd') rr_earth, vv_earth = ephem.planet_ephem(ephem.EARTH, times_vector) rr_earth[:, 0] vv_earth[:, 0] rr_mars, vv_mars = ephem.planet_ephem(ephem.MARS, times_vector) rr_mars[:, 0] vv_mars[:, 0] # Compute the transfer orbit! r0 = rr_earth[:, 0] rf = rr_mars[:, -1] (va, vb), = iod.lambert(Sun.k, r0, rf, tof) ss0_trans = State.from_vectors(Sun, r0, va, date_launch) ssf_trans = State.from_vectors(Sun, rf, vb, date_arrival) # Extract whole orbit of Earth, Mars and transfer (for plotting) rr_trans = np.zeros_like(rr_earth) rr_trans[:, 0] = r0 for ii in range(1, len(jd_vec)): tof = (jd_vec[ii] - jd_vec[0]) * u.day rr_trans[:, ii] = ss0_trans.propagate(tof).r # Better compute backwards jd_init = (date_arrival - 1 * u.year).jd jd_vec_rest = np.linspace(jd_init, jd_launch, num=N)
differential_cls=CartesianDifferential) moon_gcrs = moon_icrs.transform_to(GCRS(obstime=EPOCH)) moon_gcrs.representation = CartesianRepresentation moon_gcrs moon = Orbit.from_vectors( Earth, [moon_gcrs.x, moon_gcrs.y, moon_gcrs.z] * u.km, [moon_gcrs.v_x, moon_gcrs.v_y, moon_gcrs.v_z] * (u.km / u.s), epoch=EPOCH) ss0 = apollo ssf = moon #Solve for Lambert's Problem (Determining Translunar Trajectory) (v0, v), = iod.lambert(Earth.k, ss0.r, ssf.r, tof) ss0_trans = Orbit.from_vectors(Earth, ss0.r, v0, date_launch) dv = (ss0_trans.v - ss0.v) dv = dv.to(u.m / u.s) man = Maneuver.impulse(dv) ss_f = ss0.apply_maneuver(man) print( "The required Delta-V to perform the Translunar Injection maneuver is: " + str(dv)) #Plotting Solution in 2D - Earth close-up plt.ion() op = OrbitPlotter() op.plot(ss0, label="Apollo") op.plot(ssf, label="Moon")
# ### 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]: print("Relative error of {:.2f} %".format((C_3_lambert - C_3_A) / C_3_A * 100))
from poliastro.threebody.flybys import compute_flyby from brentq import brentq import matplotlib.pyplot as plt T_ref = 150 * u.day k = Sun.k a_ref = np.cbrt(k * T_ref**2 / (4 * np.pi**2)).to(u.km) energy_ref = (-k / (2 * a_ref)).to(u.J / u.kg) flyby_1_time = Time("2018-09-28", scale="tdb") r_mag_ref = norm(Orbit.from_body_ephem(Venus, epoch=flyby_1_time).r) v_mag_ref = np.sqrt(2 * k / r_mag_ref - k / a_ref) d_launch = Time("2018-08-11", scale="tdb") ss0 = Orbit.from_body_ephem(Earth, d_launch) ss1 = Orbit.from_body_ephem(Venus, epoch=flyby_1_time) tof = flyby_1_time - d_launch (v0, v1_pre), = iod.lambert(Sun.k, ss0.r, ss1.r, tof.to(u.s)) V = Orbit.from_body_ephem(Venus, epoch=flyby_1_time).v h = 2548 * u.km d_flyby_1 = Venus.R + h V_2_v_, delta_ = compute_flyby(v1_pre, V, Venus.k, d_flyby_1) theta_range = np.linspace(0, 2 * np.pi) def func(theta): V_2_v, _ = compute_flyby(v1_pre, V, Venus.k, d_flyby_1, theta * u.rad) ss_1 = Orbit.from_vectors(Sun, ss1.r, V_2_v, epoch=flyby_1_time) return (ss_1.period - T_ref).to(u.day).value plt.plot(theta_range, [func(theta) for theta in theta_range]) plt.axhline(0, color="k", linestyle="dashed")
def go_to_mars(offset=0., tof_=6000.): # Initial data N = 50 date_launch = time.Time('2011-11-26 15:02', scale='utc') + offset * u.day #date_arrival = time.Time('2012-08-06 05:17', scale='utc') tof = tof_ * u.h # Calculate vector of times from launch and arrival date_arrival = date_launch + tof dt = (date_arrival - date_launch) / N # Idea from http://docs.astropy.org/en/stable/time/#getting-started times_vector = date_launch + dt * np.arange(N + 1) rr_earth, vv_earth = get_body_ephem("earth", times_vector) rr_mars, vv_mars = get_body_ephem("mars", times_vector) # Compute the transfer orbit! r0 = rr_earth[:, 0] rf = rr_mars[:, -1] (va, vb), = iod.lambert(Sun.k, r0, rf, tof) ss0_trans = Orbit.from_vectors(Sun, r0, va, date_launch) ssf_trans = Orbit.from_vectors(Sun, rf, vb, date_arrival) # Extract whole orbit of Earth, Mars and transfer (for plotting) rr_trans = np.zeros_like(rr_earth) rr_trans[:, 0] = r0 for ii in range(1, len(times_vector)): tof = (times_vector[ii] - times_vector[0]).to(u.day) rr_trans[:, ii] = ss0_trans.propagate(tof).r # Better compute backwards date_final = date_arrival - 1 * u.year dt2 = (date_final - date_launch) / N times_rest_vector = date_launch + dt2 * np.arange(N + 1) rr_earth_rest, _ = get_body_ephem("earth", times_rest_vector) rr_mars_rest, _ = get_body_ephem("mars", times_rest_vector) # Plot figure fig = plt.gcf() ax = plt.gca() ax.cla() def plot_body(ax, r, color, size, border=False, **kwargs): """Plots body in axes object. """ return ax.plot(*r[:, None], marker='o', color=color, ms=size, mew=int(border), **kwargs) # I like color color_earth0 = '#3d4cd5' color_earthf = '#525fd5' color_mars0 = '#ec3941' color_marsf = '#ec1f28' color_sun = '#ffcc00' color_orbit = '#888888' color_trans = '#444444' # Plotting orbits is easy! ax.plot(*rr_earth.to(u.km).value, color=color_earth0) ax.plot(*rr_mars.to(u.km).value, color=color_mars0) ax.plot(*rr_trans.to(u.km).value, color=color_trans) ax.plot(*rr_earth_rest.to(u.km).value, ls='--', color=color_orbit) ax.plot(*rr_mars_rest.to(u.km).value, ls='--', color=color_orbit) # But plotting planets feels even magical! plot_body(ax, np.zeros(3), color_sun, 16) plot_body(ax, r0.to(u.km).value, color_earth0, 8) plot_body(ax, rr_earth[:, -1].to(u.km).value, color_earthf, 8) plot_body(ax, rr_mars[:, 0].to(u.km).value, color_mars0, 8) plot_body(ax, rf.to(u.km).value, color_marsf, 8) # Add some text #ax.text(-0.75e8, -3.5e8, -1.5e8, "MSL mission:\nfrom Earth to Mars", size=20, ha='center', va='center', bbox={"pad": 30, "lw": 0, "fc": "w"}) ax.text(r0[0].to(u.km).value * 1.4, r0[1].to(u.km).value * 0.4, r0[2].to(u.km).value * 1.25, f"Earth at launch\n({date_launch.datetime:%b %d})", ha="left", va="bottom", backgroundcolor='#ffffff') ax.text(rf[0].to(u.km).value * 0.7, rf[1].to(u.km).value * 1.1, rf[2].to(u.km).value, f"Mars at arrival\n({date_arrival.datetime:%b %d})", ha="left", va="top", backgroundcolor='#ffffff') ax.text(-1.9e8, 8e7, 0, "Transfer\norbit", ha="right", va="center", backgroundcolor='#ffffff') # Tune axes ax.set_xlim(-3e8, 3e8) ax.set_ylim(-3e8, 3e8) ax.set_zlim(-3e8, 3e8) ax.view_init(30, 260)
r0 = r0[0] r1 = r1[0] V = V[0] # In[15]: tof = flyby_1_time - d_launch # In[16]: from poliastro import iod # In[17]: ((v0, v1_pre), ) = iod.lambert(Sun.k, r0, r1, tof.to(u.s)) # In[18]: v0 # In[19]: v1_pre # In[20]: norm(v1_pre) # ## 3. Flyby #1 around Venus #
tuple(val.decompose([u.km, u.s]) for val in hoh[1]) ss_f = ss_i.apply_maneuver(hoh) #plot(ss_f) from poliastro.plotting import OrbitPlotter op = OrbitPlotter() ss_a, ss_f = ss_i.apply_maneuver(hoh, intermediate=True) #op.plot(ss_i, label="Initial orbit") #op.plot(ss_a, label="Transfer orbit") #op.plot(ss_f, label="Final orbit") from astropy import time epoch = time.Time("2015-05-09 10:43") Orbit.from_body_ephem(Earth, epoch) from astropy.coordinates import solar_system_ephemeris solar_system_ephemeris.set("jpl") date_launch = time.Time('2011-11-26 15:02', scale='utc') date_arrival = time.Time('2012-08-06 05:17', scale='utc') tof = date_arrival - date_launch ss0 = Orbit.from_body_ephem(Earth, date_launch) ssf = Orbit.from_body_ephem(Mars, date_arrival) from poliastro import iod (v0, v), = iod.lambert(Sun.k, ss0.r, ssf.r, tof) #op.plot(ss0) #op.plot(ssf)
def test(): """Not consolodted test function, just a place to copy/paste interactive test case """ ## From http://nbviewer.jupyter.org/github/poliastro/poliastro/blob/master/examples/Going%20to%20Mars%20with%20Python%20using%20poliastro.ipynb r_earth = [64601872, 1.2142001e8, 52638008] * u.km r_mars = [-1.2314831e8, 1.9075313e8, 90809903] * u.km ## Not a valid funciton, just writing down some useful starting point tests import astropy.units as u from astropy import time from poliastro import iod # This is the big one! from poliastro.bodies import Sun from poliastro.twobody import Orbit from poliastro import ephem ephem.download_kernel("de421") ## MSL Stats from: http://mars.jpl.nasa.gov/msl/mission/overview/ launch_date = time.Time("2011-11-26 15:02:00", scale="utc") arrival_date = time.Time("2012-08-06 05:17:00", scale="utc") tof = arrival_date - launch_date print("Time of flight: {} hours".format(tof.to(u.h))) ## Get vector of times from launch and arrival Julian days N = 50 launch_jd = launch_date.jd arrival_jd = arrival_date.jd jd_vec = np.linspace(launch_jd, arrival_jd, num=N) times_vec = time.Time(jd_vec, format="jd") ## Use `ephem` module to get Earth and Mars positions r_earth, v_earth = ephem.planet_ephem(ephem.EARTH, times_vec) r_mars, v_mars = ephem.planet_ephem(ephem.MARS, times_vec) r0 = r_earth[:, 0] r1 = r_mars[:, -1] ## Compute departure/arrival velocities, using Sun as main attractor (v_depart_iod, v_arrive_iod), = iod.lambert(Sun.k, r0, r1, tof) vd, va = lambert._gauss_universal_variable(Sun.k.value, r0.value, r1.value, tof.to(u.s).value, rtol=1e-8, finder=1, maxiter=1000000) departures = [ time.Time(d, format="jd") for d in np.linspace( time.Time("2020-01-01").jd, time.Time("2020-04-01").jd) ] arrivals = [ time.Time(d, format="jd") for d in np.linspace( time.Time("2020-08-01").jd, time.Time("2021-04-01").jd) ] xx = np.zeros((50, 5)) idx = 0 for d in departures: x, y = lambert.interplanetary_trajectory("Earth", "mars", d, arrivals) xx[idx] = x idx += 1 c = contour([D.value for D in departures], [A.value for A in arrivals], xx) clabel(c, inline=1, fontsize=10)