def test_atmospheric_drag(): # http://farside.ph.utexas.edu/teaching/celestial/Celestialhtml/node94.html#sair (10.148) # given the expression for \dot{r} / r, aproximate \Delta r \approx F_r * \Delta t R = Earth.R.to(u.km).value k = Earth.k.to(u.km**3 / u.s**2).value # parameters of a circular orbit with h = 250 km (any value would do, but not too small) orbit = Orbit.circular(Earth, 250 * u.km) r0, _ = orbit.rv() r0 = r0.to(u.km).value # parameters of a body C_D = 2.2 # dimentionless (any value would do) A = ((np.pi / 4.0) * (u.m**2)).to(u.km**2).value # km^2 m = 100 # kg B = C_D * A / m # parameters of the atmosphere rho0 = Earth.rho0.to(u.kg / u.km**3).value # kg/km^3 H0 = Earth.H0.to(u.km).value tof = 100000 # s dr_expected = -B * rho0 * np.exp(-(norm(r0) - R) / H0) * np.sqrt(k * norm(r0)) * tof # assuming the atmospheric decay during tof is small, # dr_expected = F_r * tof (Newton's integration formula), where # F_r = -B rho(r) |r|^2 sqrt(k / |r|^3) = -B rho(r) sqrt(k |r|) r, v = cowell(orbit, tof, ad=atmospheric_drag, R=R, C_D=C_D, A=A, m=m, H0=H0, rho0=rho0) assert_quantity_allclose(norm(r) - norm(r0), dr_expected, rtol=1e-2)
def test_cowell_propagation_circle_to_circle(): # From [Edelbaum, 1961] accel = 1e-7 def constant_accel(t0, u, k): v = u[3:] norm_v = (v[0]**2 + v[1]**2 + v[2]**2)**.5 return accel * v / norm_v ss = Orbit.circular(Earth, 500 * u.km) tof = 20 * ss.period r0, v0 = ss.rv() k = ss.attractor.k r, v = cowell(k.to(u.km**3 / u.s**2).value, r0.to(u.km).value, v0.to(u.km / u.s).value, tof.to(u.s).value, ad=constant_accel) ss_final = Orbit.from_vectors(Earth, r * u.km, v * u.km / u.s) da_a0 = (ss_final.a - ss.a) / ss.a dv_v0 = abs(norm(ss_final.v) - norm(ss.v)) / norm(ss.v) assert_almost_equal(da_a0.value, 2 * dv_v0.value, decimal=4) dv = abs(norm(ss_final.v) - norm(ss.v)) accel_dt = accel * u.km / u.s**2 * tof assert_almost_equal(dv.value, accel_dt.value, decimal=4)
def test_cowell_propagation_circle_to_circle(): # From [Edelbaum, 1961] accel = 1e-7 def constant_accel(t0, u, k): v = u[3:] norm_v = (v[0]**2 + v[1]**2 + v[2]**2)**.5 return accel * v / norm_v ss = Orbit.circular(Earth, 500 * u.km) tof = 20 * ss.period r, v = cowell(ss, tof.to(u.s).value, ad=constant_accel) ss_final = Orbit.from_vectors( Earth, r * u.km, v * u.km / u.s) da_a0 = (ss_final.a - ss.a) / ss.a dv_v0 = abs(norm(ss_final.v) - norm(ss.v)) / norm(ss.v) assert_quantity_allclose(da_a0, 2 * dv_v0, rtol=1e-2) dv = abs(norm(ss_final.v) - norm(ss.v)) accel_dt = accel * u.km / u.s**2 * tof assert_quantity_allclose(dv, accel_dt, rtol=1e-2)
def test_leo_geo_numerical(inc_0): edelbaum_accel = guidance_law(k, a_0, a_f, inc_0, inc_f, f) _, t_f = extra_quantities(k, a_0, a_f, inc_0, inc_f, f) # Retrieve r and v from initial orbit s0 = Orbit.circular(Earth, a_0 * u.km - Earth.R, inc_0 * u.rad) r0, v0 = s0.rv() # Propagate orbit r, v = cowell(k, r0.to(u.km).value, v0.to(u.km / u.s).value, t_f, ad=edelbaum_accel, nsteps=1000000) sf = Orbit.from_vectors(Earth, r * u.km, v * u.km / u.s, s0.epoch + t_f * u.s) assert_allclose(sf.a.to(u.km).value, a_f, rtol=1e-5) assert_allclose(sf.ecc.value, 0.0, atol=1e-2) assert_allclose(sf.inc.to(u.rad).value, inc_f, atol=1e-3)
def test_pqw_for_circular_equatorial_orbit(): ss = Orbit.circular(Earth, 600 * u.km) expected_p = [1, 0, 0] * u.one expected_q = [0, 1, 0] * u.one expected_w = [0, 0, 1] * u.one p, q, w = ss.pqw() assert_allclose(p, expected_p) assert_allclose(q, expected_q) assert_allclose(w, expected_w)
def test_sample_custom_body_raises_warning_and_returns_coords(): # See https://github.com/poliastro/poliastro/issues/649 orbit = Orbit.circular(Moon, 100 * u.km) with pytest.warns( UserWarning, match="returning only cartesian coordinates instead" ): coords = orbit.sample(10) assert isinstance(coords, CartesianRepresentation) assert len(coords) == 10
def test_hohmann_maneuver(): # Data from Vallado, example 6.1 alt_i = 191.34411 * u.km alt_f = 35781.34857 * u.km ss_i = Orbit.circular(Earth, alt_i) expected_dv = 3.935224 * u.km / u.s expected_t_trans = 5.256713 * u.h man = Maneuver.hohmann(ss_i, Earth.R + alt_f) assert_quantity_allclose(ss_i.apply_maneuver(man).ecc, 0 * u.one, atol=1e-14 * u.one) assert_quantity_allclose(man.get_total_cost(), expected_dv, rtol=1e-5) assert_quantity_allclose(man.get_total_time(), expected_t_trans, rtol=1e-5)
def test_bielliptic_maneuver(): # Data from Vallado, example 6.2 alt_i = 191.34411 * u.km alt_b = 503873.0 * u.km alt_f = 376310.0 * u.km ss_i = Orbit.circular(Earth, alt_i) expected_dv = 3.904057 * u.km / u.s expected_t_trans = 593.919803 * u.h man = Maneuver.bielliptic(ss_i, Earth.R + alt_b, Earth.R + alt_f) assert_allclose(ss_i.apply_maneuver(man).ecc, 0 * u.one, atol=1e-12 * u.one) assert_quantity_allclose(man.get_total_cost(), expected_dv, rtol=1e-5) assert_quantity_allclose(man.get_total_time(), expected_t_trans, rtol=1e-6)
def test_hohmann_maneuver(): # Data from Vallado, example 6.1 alt_i = 191.34411 * u.km alt_f = 35781.34857 * u.km ss_i = Orbit.circular(Earth, alt_i) expected_dv = 3.935224 * u.km / u.s expected_t_trans = 5.256713 * u.h man = Maneuver.hohmann(ss_i, Earth.R + alt_f) assert_almost_equal(ss_i.apply_maneuver(man).ecc, 0) assert_almost_equal(man.get_total_cost().to(u.km / u.s).value, expected_dv.value, decimal=5) assert_almost_equal(man.get_total_time().to(u.h).value, expected_t_trans.value, decimal=5)
def test_bielliptic_maneuver(): # Data from Vallado, example 6.2 alt_i = 191.34411 * u.km alt_b = 503873.0 * u.km alt_f = 376310.0 * u.km ss_i = Orbit.circular(Earth, alt_i) expected_dv = 3.904057 * u.km / u.s expected_t_trans = 593.919803 * u.h man = Maneuver.bielliptic(ss_i, Earth.R + alt_b, Earth.R + alt_f) assert_almost_equal(ss_i.apply_maneuver(man).ecc, 0) assert_almost_equal(man.get_total_cost().to(u.km / u.s).value, expected_dv.value, decimal=5) assert_almost_equal(man.get_total_time().to(u.h).value, expected_t_trans.value, decimal=2)
def test_leo_geo_numerical(inc_0): f = 3.5e-7 # km / s2 a_0 = 7000.0 # km a_f = 42166.0 # km inc_f = 0.0 # rad k = Earth.k.to(u.km**3 / u.s**2).value a_d, _, t_f = change_a_inc(k, a_0, a_f, inc_0, inc_f, f) # Retrieve r and v from initial orbit s0 = Orbit.circular(Earth, a_0 * u.km - Earth.R, inc_0 * u.rad) # Propagate orbit sf = s0.propagate(t_f * u.s, method=cowell, ad=a_d, rtol=1e-6) assert_allclose(sf.a.to(u.km).value, a_f, rtol=1e-3) assert_allclose(sf.ecc.value, 0.0, atol=1e-2) assert_allclose(sf.inc.to(u.rad).value, inc_f, atol=2e-3)
def test_geosync_has_proper_period(): expected_period = 1436 # min ss = Orbit.circular(Earth, alt=42164 * u.km - Earth.R) assert_almost_equal(ss.period.to(u.min).value, expected_period, decimal=0)
import numpy as np import matplotlib.pyplot as plt plt.ion() # To immediately show plots from astropy import units as u from poliastro.bodies import Earth, Mars, Sun from poliastro.twobody import Orbit plt.style.use("seaborn") # Recommended h = 625*u.km r_circ = Earth.R + h circ = Orbit.circular(Earth,h) T_circ = circ.state.period N = 9 delay = T_circ/N T_ph = T_circ + delay a_ph = np.power(T_ph/2/np.pi * np.sqrt(Earth.k),(2/3)) rp=Earth.R + h ra = 2*a_ph - rp e_ph = (ra-rp)/(ra+rp) phasing = Orbit.from_classical(Earth,a_ph,e_ph,0*u.deg,0*u.deg,0*u.deg,0*u.deg) from poliastro.plotting import OrbitPlotter op = OrbitPlotter() op.plot(circ, label="Final circular orbit") op.plot(phasing, label="Phasing orbit")
B = x * A_over_m #Min kommentar: Skrev in x istället för C_D # parameters of the atmosphere rho0 = rho0_earth.to(u.kg / u.km**3).value # kg/km^3 H0 = H0_earth.to( u.km ).value #Min kommentar: Ändras atmosfärens egenskaper ju högre radien är i det här programmet? #[<matplotlib.lines.Line2D at 0x7ffb5f511048>] #Orbital Decay #If atmospheric drag causes the orbit to fully decay, additional code is needed to stop the integration when the satellite reaches the surface. #Please note that you will likely want to use a more sophisticated atmosphere model than the one in atmospheric_drag for these sorts of computations. orbit = Orbit.circular( Earth, 230 * u.km, epoch=Time(0.0, format="jd", scale="tdb") ) #Min kommentar: Här tror jag att jag kan ändra på värdet hos radien på omloppsbanan tofs = TimeDelta( np.linspace(0 * u.h, 100 * u.d, num=200) ) #Min kommentar: Här tror jag deltatiden beskrivs, att den mäter mellan noll timmar till ett max antal dagar, samt att den mäter 2000 gånger. from poliastro.twobody.events import LithobrakeEvent lithobrake_event = LithobrakeEvent(R) events = [lithobrake_event] rr = propagate( orbit, tofs, method=cowell, ad=atmospheric_drag_exponential, R=R,
import plotly.io as pio pio.renderers.default = "notebook_connected" R = Earth.R.to(u.km).value k = Earth.k.to(u.km**3 / u.s**2).value C_D = 2.2 A_over_m = (((4 * np.pi * 0.0144) / 4.0) * (u.m**2) / (48 * u.kg)).to_value( u.km**2 / u.kg) B = C_D * A_over_m #rho0 = rho0_earth.to(u.kg / u.km ** 3).value #H0 = H0_earth.to(u.km).value orbit = Orbit.circular(Earth, 200 * u.km, epoch=Time(0.0, format="jd", scale="tdb")) tofs = TimeDelta(np.linspace(0 * u.h, 100000000 * u.d, num=200)) from poliastro.twobody.events import LithobrakeEvent lithobrake_event = LithobrakeEvent(R) events = [lithobrake_event] coesa76 = COESA76() rr, _ = cowell( Earth.k, orbit.r, orbit.v, tofs,
# In[2]: import plotly.io as pio pio.renderers.default = "notebook_connected" # ### Atmospheric drag ### # The poliastro package now has several commonly used natural perturbations. One of them is atmospheric drag! See how one can monitor decay of the near-Earth orbit over time using our new module poliastro.twobody.perturbations! # In[3]: R = Earth.R.to(u.km).value k = Earth.k.to(u.km**3 / u.s**2).value orbit = Orbit.circular(Earth, 250 * u.km, epoch=Time(0.0, format="jd", scale="tdb")) # parameters of a body C_D = 2.2 # dimentionless (any value would do) A_over_m = ((np.pi / 4.0) * (u.m**2) / (100 * u.kg)).to_value(u.km**2 / u.kg) # km^2/kg B = C_D * A_over_m # parameters of the atmosphere rho0 = rho0_earth.to(u.kg / u.km**3).value # kg/km^3 H0 = H0_earth.to(u.km).value tofs = TimeDelta(np.linspace(0 * u.h, 100000 * u.s, num=2000)) rr = propagate(
def test_circular_has_proper_semimajor_axis(): alt = 500 * u.km attractor = Earth expected_a = Earth.R + alt ss = Orbit.circular(attractor, alt) assert ss.a == expected_a
def test_orbit_representation(): ss = Orbit.circular(Earth, 600 * u.km, 20 * u.deg) expected_str = "6978 x 6978 km x 20.0 deg orbit around Earth (\u2641)" assert str(ss) == repr(ss) == expected_str
def test_geosync_has_proper_period(): expected_period = 1436 * u.min ss = Orbit.circular(Earth, alt=42164 * u.km - Earth.R) assert_quantity_allclose(ss.period, expected_period, rtol=1e-4)
iss_f_kep.argp, rtol=rtol, atol=1e-08 * u.rad) assert np.allclose(iss_f_num.nu, iss_f_kep.nu, rtol=rtol, atol=1e-08 * u.rad) # ## Numerical validation # # According to [Edelbaum, 1961], a coplanar, semimajor axis change with tangent thrust is defined by: # # $$\frac{\operatorname{d}\!a}{a_0} = 2 \frac{F}{m V_0}\operatorname{d}\!t, \qquad \frac{\Delta{V}}{V_0} = \frac{1}{2} \frac{\Delta{a}}{a_0}$$ # # So let's create a new circular orbit and perform the necessary checks, assuming constant mass and thrust (i.e. constant acceleration): # In[18]: ss = Orbit.circular(Earth, 500 * u.km) tof = 20 * ss.period ad = constant_accel_factory(1e-7) r, v = cowell(ss.attractor.k, ss.r, ss.v, [tof] * u.s, ad=ad) ss_final = Orbit.from_vectors(Earth, r[0], v[0], ss.epoch + tof) # In[19]: da_a0 = (ss_final.a - ss.a) / ss.a da_a0 # In[20]:
def test_atmospheric_demise(): # Test an orbital decay that hits Earth. No analytic solution. R = Earth.R.to(u.km).value orbit = Orbit.circular(Earth, 230 * u.km) t_decay = 48.2179 * u.d # not an analytic value # Parameters of a body C_D = 2.2 # dimentionless (any value would do) A_over_m = ((np.pi / 4.0) * (u.m**2) / (100 * u.kg)).to_value( u.km**2 / u.kg) # km^2/kg # Parameters of the atmosphere rho0 = rho0_earth.to(u.kg / u.km**3).value # kg/km^3 H0 = H0_earth.to(u.km).value # km tofs = [365] * u.d # Actually hits the ground a bit after day 48 lithobrake_event = LithobrakeEvent(R) events = [lithobrake_event] def f(t0, u_, k): du_kep = func_twobody(t0, u_, k) ax, ay, az = atmospheric_drag_exponential(t0, u_, k, R=R, C_D=C_D, A_over_m=A_over_m, H0=H0, rho0=rho0) du_ad = np.array([0, 0, 0, ax, ay, az]) return du_kep + du_ad rr, _ = cowell( Earth.k, orbit.r, orbit.v, tofs, events=events, f=f, ) assert_quantity_allclose(norm(rr[0].to(u.km).value), R, atol=1) # Below 1km assert_quantity_allclose(lithobrake_event.last_t, t_decay, rtol=1e-2) # Make sure having the event not firing is ok tofs = [1] * u.d lithobrake_event = LithobrakeEvent(R) events = [lithobrake_event] rr, _ = cowell( Earth.k, orbit.r, orbit.v, tofs, events=events, f=f, ) assert lithobrake_event.last_t == tofs[-1]
def test_propagation_custom_body_works(): # See https://github.com/poliastro/poliastro/issues/649 orbit = Orbit.circular(Moon, 100 * u.km) orbit.propagate(1 * u.h)
def start_date_optimal(H, date0, date1, m, Isp, step): delta_v = 0 * u.km / u.s v_out = 0 * u.km / u.s m_prop = 0 * u.kg date_in = date0 date_out = date0 step_one0 = True x1 = [] x2 = [] x3 = [] x4 = [] while date0 < date1: epoch0 = date0.jyear ss0 = Orbit.circular(Earth, H, epoch=epoch0) vsE = ss0.rv()[1] dvEV, date_arrivalV, vsV = transit_opt1.transit_optimal( date0, transit_minEV, transit_maxEV, Earth, Venus, vsE, step) dvVJ, date_arrivalJ, vsJ = transit_opt1.transit_optimal( date_arrivalV, transit_minVJ, transit_maxVJ, Venus, Jupiter, vsV, step) dvJU, date_arrivalU, vsU = transit_opt1.transit_optimal( date_arrivalJ, transit_minJU, transit_maxJU, Jupiter, Uranus, vsJ, step) #koszty paliwa: m_pJU = m * (math.exp((dvJU) / Isp) - 1) m_pVJ = (m + m_pJU) * (math.exp((dvVJ) / Isp) - 1) m_pEV = (m + m_pJU + m_pVJ) * (math.exp((dvEV) / Isp) - 1) dv_total = (dvEV) + (dvVJ) + (dvJU) m_p = m_pEV + m_pVJ + m_pJU x1.append(date0.iso[0:10]) x2.append(int((date_arrivalU - date0).jd)) x3.append(float(dv_total / u.km * u.s)) x4.append(int(m_p / u.kg)) print( date0.iso[0:10], ', %i days, %.3f km/s, %i kg' % (int( (date_arrivalU - date0).jd), float( dv_total / u.km * u.s), int(m_p / u.kg))) if step_one0: delta_v = dv_total m_prop = m_p v_out = vsU date_out = date_arrivalU step_one0 = False else: if dv_total < delta_v: delta_v = dv_total m_prop = m_p v_out = vsU date_in = date0 date_out = date_arrivalU date0 += step * u.day lista = {'1': x1, '2': x2, '3': x3, '4': x4} #lista = pd.DataFrame(lista) return delta_v, v_out, date_in, date_out, m_prop, lista
def test_orbit_representation(): ss = Orbit.circular(Earth, 600 * u.km, 20 * u.deg, epoch=Time("2018-09-08 09:04:00", scale="tdb")) expected_str = "6978 x 6978 km x 20.0 deg (GCRS) orbit around Earth (\u2641) at epoch 2018-09-08 09:04:00.000 (TDB)" assert str(ss) == repr(ss) == expected_str
from poliastro.ephem import build_ephem_interpolant from poliastro.core.elements import rv2coe from poliastro.atmosphere import COESA76 from poliastro.constants import rho0_earth, H0_earth from poliastro.core.perturbations import atmospheric_drag_exponential, atmospheric_drag_model, third_body, J2_perturbation from poliastro.bodies import Earth, Moon from poliastro.twobody import Orbit from poliastro.plotting import OrbitPlotter3D import plotly.io as pio pio.renderers.default = "notebook_connected" from poliastro.twobody.events import LithobrakeEvent R = Earth.R.to(u.km).value orbit = Orbit.circular(Earth, 300 * u.km) t_decay = 7.17 * u.d # parameters of a body C_D = 2.2 # dimentionless (any value would do) #A_over_m = ((np.pi / 4.0) * (u.m ** 2) / (100 * u.kg)).to_value( #u.km ** 2 / u.kg #) # km^2/kg A_over_m = (((4 * np.pi * 0.0144) / 4.0) * (u.m**2) / (48 * u.kg)).to_value( u.km**2 / u.kg) tofs = [365] * u.d lithobrake_event = LithobrakeEvent(R) events = [lithobrake_event]