def test_state_raises_unitserror_if_rv_units_are_wrong(): _d = [1.0, 0.0, 0.0] * u.AU wrong_v = [0.0, 1.0e-6, 0.0] * u.AU with pytest.raises(u.UnitsError) as excinfo: Orbit.from_vectors(Sun, _d, wrong_v) assert ("UnitsError: Argument 'v' to function 'from_vectors' must be in units convertible to 'm / s'." in excinfo.exconly())
def test_J2_propagation_Earth(): # from Curtis example 12.2: r0 = np.array([-2384.46, 5729.01, 3050.46]) # km v0 = np.array([-7.36138, -2.98997, 1.64354]) # km/s orbit = Orbit.from_vectors(Earth, r0 * u.km, v0 * u.km / u.s) tofs = [48.0] * u.h rr, vv = cowell( Earth.k, orbit.r, orbit.v, tofs, ad=J2_perturbation, J2=Earth.J2.value, R=Earth.R.to(u.km).value, ) k = Earth.k.to(u.km ** 3 / u.s ** 2).value _, _, _, raan0, argp0, _ = rv2coe(k, r0, v0) _, _, _, raan, argp, _ = rv2coe(k, rr[0].to(u.km).value, vv[0].to(u.km / u.s).value) raan_variation_rate = (raan - raan0) / tofs[0].to(u.s).value argp_variation_rate = (argp - argp0) / tofs[0].to(u.s).value raan_variation_rate = (raan_variation_rate * u.rad / u.s).to(u.deg / u.h) argp_variation_rate = (argp_variation_rate * u.rad / u.s).to(u.deg / u.h) assert_quantity_allclose(raan_variation_rate, -0.172 * u.deg / u.h, rtol=1e-2) assert_quantity_allclose(argp_variation_rate, 0.282 * u.deg / u.h, 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 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_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_orbit_accepts_ecliptic_plane(): r = [1E+09, -4E+09, -1E+09] * u.km v = [5E+00, -1E+01, -4E+00] * u.km / u.s ss = Orbit.from_vectors(Sun, r, v, plane=Planes.EARTH_ECLIPTIC) assert ss.frame.is_equivalent_frame(HeliocentricEclipticJ2000(obstime=J2000))
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_cowell_works_with_small_perturbations(): r0 = [-2384.46, 5729.01, 3050.46] * u.km v0 = [-7.36138, -2.98997, 1.64354] * u.km / u.s r_expected = [ 13179.39566663877121754922, -13026.25123408228319021873, -9852.66213692844394245185, ] * u.km v_expected = ( [2.78170542314378943516, 3.21596786944631274352, 0.16327165546278937791] * u.km / u.s ) initial = Orbit.from_vectors(Earth, r0, v0) def accel(t0, state, k): v_vec = state[3:] norm_v = (v_vec * v_vec).sum() ** 0.5 return 1e-5 * v_vec / norm_v final = initial.propagate(3 * u.day, method=cowell, ad=accel) assert_quantity_allclose(final.r, r_expected) assert_quantity_allclose(final.v, v_expected)
def test_sso_disposal_numerical(ecc_0, ecc_f): a_0 = Earth.R.to(u.km).value + 900 # km f = 2.4e-7 # km / s2, assumed constant k = Earth.k.decompose([u.km, u.s]).value _, t_f = extra_quantities(k, a_0, ecc_0, ecc_f, f) # Retrieve r and v from initial orbit s0 = Orbit.from_classical(Earth, a_0 * u.km, ecc_0 * u.one, 0 * u.deg, 0 * u.deg, 0 * u.deg, 0 * u.deg) r0, v0 = s0.rv() optimal_accel = guidance_law(s0, ecc_f, f) # Propagate orbit r, v = cowell(k, r0.to(u.km).value, v0.to(u.km / u.s).value, t_f, ad=optimal_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.ecc.value, ecc_f, rtol=1e-4, atol=1e-4)
def test_propagation_sets_proper_epoch(): expected_epoch = time.Time("2017-09-01 12:05:50", scale="tdb") r = [-2.76132873e08, -1.71570015e08, -1.09377634e08] * u.km v = [13.17478674, -9.82584125, -1.48126639] * u.km / u.s florence = Orbit.from_vectors(Sun, r, v, plane=Planes.EARTH_ECLIPTIC) propagated = florence.propagate(expected_epoch) assert propagated.epoch == expected_epoch
def test_propagation_hyperbolic(): # Data from Curtis, example 3.5 r0 = [Earth.R.to(u.km).value + 300, 0, 0] * u.km v0 = [0, 15, 0] * u.km / u.s ss0 = Orbit.from_vectors(Earth, r0, v0) tof = 14941 * u.s ss1 = ss0.propagate(tof) r, v = ss1.rv() assert_almost_equal(norm(r).to(u.km).value, 163180, decimal=-1) assert_almost_equal(norm(v).to(u.km/u.s).value, 10.51, decimal=2)
def test_orbit_has_proper_frame(attractor, expected_frame_class): # Dummy data r = [1E+09, -4E+09, -1E+09] * u.km v = [5E+00, -1E+01, -4E+00] * u.km / u.s epoch = Time('2015-07-14 07:59', scale='tdb') ss = Orbit.from_vectors(attractor, r, v, epoch) assert ss.frame.is_equivalent_frame(expected_frame_class(obstime=epoch)) assert ss.frame.obstime == epoch
def test_hyperbolic_modulus_wrapped_nu(): ss = Orbit.from_vectors( Sun, [-9.77441841e+07, 1.01000539e+08, 4.37584668e+07] * u.km, [23.75936985, -43.09599568, -8.7084724] * u.km / u.s, ) num_values = 3 positions = ss.sample(num_values) assert_quantity_allclose(positions[0].data.xyz, ss.r)
def test_hyperbolic_nu_value_check(): # A custom hyperbolic orbit r = [1.197659243752796E+09, -4.443716685978071E+09, -1.747610548576734E+09] * u.km v = [5.540549267188614E+00, -1.251544669134140E+01, -4.848892572767733E+00] * u.km / u.s ss = Orbit.from_vectors(Sun, r, v, Time('2015-07-14 07:59', scale='tdb')) positions = ss.sample(100) assert isinstance(positions, HCRS) assert len(positions) == 100
def test_propagation(): # Data from Vallado, example 2.4 r0 = [1131.340, -2282.343, 6672.423] * u.km v0 = [-5.64305, 4.30333, 2.42879] * u.km / u.s ss0 = Orbit.from_vectors(Earth, r0, v0) tof = 40 * u.min ss1 = ss0.propagate(tof) r, v = ss1.rv() assert_array_almost_equal(r.value, [-4219.7527, 4363.0292, -3958.7666], decimal=1) assert_array_almost_equal(v.value, [3.689866, -1.916735, -6.112511], decimal=4)
def test_long_propagation_preserves_orbit_elements(method): tof = 100 * u.year r_halleys = np.array([-9018878.63569932, -94116054.79839276, 22619058.69943215]) # km v_halleys = np.array([-49.95092305, -12.94843055, -4.29251577]) # km/s halleys = Orbit.from_vectors(Sun, r_halleys * u.km, v_halleys * u.km / u.s) params_ini = rv2coe(Sun.k.to(u.km**3 / u.s**2).value, r_halleys, v_halleys)[:-1] r_new, v_new = halleys.propagate(tof, method=method).rv() params_final = rv2coe(Sun.k.to(u.km**3 / u.s**2).value, r_new.to(u.km).value, v_new.to(u.km / u.s).value)[:-1] print(params_ini, params_final) assert_quantity_allclose(params_ini, params_final)
def test_orbit_from_custom_body_raises_error_when_asked_frame(): attractor = Body(Sun, 1 * u.km ** 3 / u.s ** 2, "_DummyPlanet") r = [1E+09, -4E+09, -1E+09] * u.km v = [5E+00, -1E+01, -4E+00] * u.km / u.s ss = Orbit.from_vectors(attractor, r, v) with pytest.raises(NotImplementedError) as excinfo: ss.frame assert ("Frames for orbits around custom bodies are not yet supported" in excinfo.exconly())
def test_orbit_propagate_retains_plane(value): r = [1E+09, -4E+09, -1E+09] * u.km v = [5E+00, -1E+01, -4E+00] * u.km / u.s ss = Orbit.from_vectors(Sun, r, v, plane=Planes.EARTH_ECLIPTIC) orig_frame = ss.frame final_ss = ss.propagate(1 * u.h) expected_frame = orig_frame.replicate_without_data(obstime=final_ss.epoch) assert final_ss.frame.is_equivalent_frame(expected_frame)
def test_propagation_zero_time_returns_same_state(): # Bug #50 r0 = [1131.340, -2282.343, 6672.423] * u.km v0 = [-5.64305, 4.30333, 2.42879] * u.km / u.s ss0 = Orbit.from_vectors(Earth, r0, v0) tof = 0 * u.s ss1 = ss0.propagate(tof) r, v = ss1.rv() assert_array_almost_equal(r.value, r0.value) assert_array_almost_equal(v.value, v0.value)
def test_apply_maneuver_correct_dimensions(): orb = Orbit.from_vectors( Moon, [-22681.58976181, 942.47776988, 0] * u.km, [-0.04578917, -0.19408599, 0.0] * u.km / u.s, Time("2023-08-30 23:14", scale="tdb"), ) man = Maneuver((1 * u.s, [0.01, 0, 0] * u.km / u.s)) new_orb = orb.apply_maneuver(man, intermediate=False) assert new_orb.r.ndim == 1 assert new_orb.v.ndim == 1
def test_propagation_hyperbolic(): # Data from Curtis, example 3.5 r0 = [Earth.R.to(u.km).value + 300, 0, 0] * u.km v0 = [0, 15, 0] * u.km / u.s expected_r_norm = 163180 * u.km expected_v_norm = 10.51 * u.km / u.s ss0 = Orbit.from_vectors(Earth, r0, v0) tof = 14941 * u.s ss1 = ss0.propagate(tof) r, v = ss1.rv() assert_quantity_allclose(norm(r), expected_r_norm, rtol=1e-4) assert_quantity_allclose(norm(v), expected_v_norm, rtol=1e-3)
def test_orbit_is_pickable(): # A custom hyperbolic orbit r = [1.197659243752796E+09, -4.443716685978071E+09, -1.747610548576734E+09] * u.km v = [5.540549267188614E+00, -1.251544669134140E+01, -4.848892572767733E+00] * u.km / u.s epoch = Time('2015-07-14 07:59', scale='tdb') ss = Orbit.from_vectors(Sun, r, v, epoch) pickled = pickle.dumps(ss) ss_result = pickle.loads(pickled) assert_array_equal(ss.r, ss_result.r) assert_array_equal(ss.v, ss_result.v) assert ss_result.epoch == ss.epoch
def test_cowell_converges_with_small_perturbations(): r0 = [-2384.46, 5729.01, 3050.46] * u.km v0 = [-7.36138, -2.98997, 1.64354] * u.km / u.s initial = Orbit.from_vectors(Earth, r0, v0) def accel(t0, state, k): v_vec = state[3:] norm_v = (v_vec * v_vec).sum() ** .5 return 0.0 * v_vec / norm_v final = initial.propagate(initial.period, method=cowell, ad=accel) assert_quantity_allclose(final.r, initial.r) assert_quantity_allclose(final.v, initial.v)
def test_long_propagations_kepler_agrees_mean_motion(): tof = 100 * u.year r_mm, v_mm = iss.propagate(tof, method=mean_motion).rv() r_k, v_k = iss.propagate(tof, method=kepler).rv() assert_quantity_allclose(r_mm, r_k) assert_quantity_allclose(v_mm, v_k) r_halleys = [-9018878.63569932, -94116054.79839276, 22619058.69943215] # km v_halleys = [-49.95092305, -12.94843055, -4.29251577] # km/s halleys = Orbit.from_vectors(Sun, r_halleys * u.km, v_halleys * u.km / u.s) r_mm, v_mm = halleys.propagate(tof, method=mean_motion).rv() r_k, v_k = halleys.propagate(tof, method=kepler).rv() assert_quantity_allclose(r_mm, r_k) assert_quantity_allclose(v_mm, v_k)
def test_propagate_accepts_timedelta(): # Data from Vallado, example 2.4 r0 = [1131.340, -2282.343, 6672.423] * u.km v0 = [-5.64305, 4.30333, 2.42879] * u.km / u.s expected_r = [-4219.7527, 4363.0292, -3958.7666] * u.km expected_v = [3.689866, -1.916735, -6.112511] * u.km / u.s ss0 = Orbit.from_vectors(Earth, r0, v0) tof = time.TimeDelta(40 * u.min) ss1 = ss0.propagate(tof) r, v = ss1.rv() assert_quantity_allclose(r, expected_r, rtol=1e-5) assert_quantity_allclose(v, expected_v, rtol=1e-4)
def test_orbit_represent_as_produces_correct_data(): r = [1E+09, -4E+09, -1E+09] * u.km v = [5E+00, -1E+01, -4E+00] * u.km / u.s ss = Orbit.from_vectors(Sun, r, v) expected_result = CartesianRepresentation( *r, differentials=CartesianDifferential(*v) ) result = ss.represent_as(CartesianRepresentation) # We can't directly compare the objects, see https://github.com/astropy/astropy/issues/7793 assert (result.xyz == expected_result.xyz).all() assert (result.differentials['s'].d_xyz == expected_result.differentials['s'].d_xyz).all()
def iod_with_angles(epochs: Time, angles: Angle, location: EarthLocation): """ Solve initial orbit determination problem, with observation data be angles only Parameters ---------- epochs: `~astropy.time.Time` epochs.size should be N angles: `~astropy.coordinates.angles.Angle` angles.shape should be (N, 2), with the first column be RA and the second column be DE. location: `~astropy.coordinates.EarthLocation` location of the observatory Returns ------- orbit: `~poliastro.twobody.Orbit` """ import nessan_coord as coo from poliastro.bodies import Earth u_time = 13.446852063738202 * u.minute u_length = 6378.137 * u.kilometer times = [((epoch - epochs[0]) / u_time).to_value(u.one) for epoch in epochs] directions = coo.sph2cart(angles[:, 0].to_value(unit='rad'), angles[:, 1].to_value(unit='rad'), 1.0) obsvectors = [(iod_obs_tod(location, epoch)[0] / u_length).to_value(u.one) for epoch in epochs] # Add a first guess indices = np.array([10, 20], dtype=int) times = np.array(times) obsvectors = np.array(obsvectors) range = _iod_laplace_first_guess(times[indices], directions[indices], obsvectors[indices]) print(range * u_length) time, r, v, residual = _iod_laplace(times, directions, obsvectors, range) epoch = epochs[0] + time * u_time orbit = Orbit.from_vectors(Earth, r * u_length, v * u_length / u_time, epoch) residual = residual * u.rad return orbit, Angle(residual, unit='deg')
def test_cowell_propagation_with_zero_acceleration_equals_kepler(): # Data from Vallado, example 2.4 r0 = np.array([1131.340, -2282.343, 6672.423]) * u.km v0 = np.array([-5.64305, 4.30333, 2.42879]) * u.km / u.s tofs = [40 * 60.0] * u.s orbit = Orbit.from_vectors(Earth, r0, v0) expected_r = np.array([-4219.7527, 4363.0292, -3958.7666]) * u.km expected_v = np.array([3.689866, -1.916735, -6.112511]) * u.km / u.s r, v = cowell(Earth.k, orbit.r, orbit.v, tofs, ad=None) assert_quantity_allclose(r[0], expected_r, rtol=1e-5) assert_quantity_allclose(v[0], expected_v, rtol=1e-4)
def test_hyperbolic_nu_value_check(): # A custom hyperbolic orbit r = [ 1.197659243752796E+09, -4.443716685978071E+09, -1.747610548576734E+09 ] * u.km v = [ 5.540549267188614E+00, -1.251544669134140E+01, -4.848892572767733E+00 ] * u.km / u.s ss = Orbit.from_vectors(Sun, r, v, Time('2015-07-14 07:59', scale='tdb')) values, positions = ss.sample(100) assert isinstance(positions, CartesianRepresentation) assert isinstance(values, Time) assert len(positions) == len(values) == 100
def test_sample_one_point_equals_propagation_small_deltas( time_of_flight, method): # Time arithmetic loses precision, see # https://github.com/astropy/astropy/issues/6638 # Data from Vallado, example 2.4 r0 = [1131.340, -2282.343, 6672.423] * u.km v0 = [-5.64305, 4.30333, 2.42879] * u.km / u.s ss0 = Orbit.from_vectors(Earth, r0, v0) sample_times = Time([ss0.epoch + time_of_flight]) expected_ss = ss0.propagate(time_of_flight, method) rr = ss0.sample(sample_times, method) assert_quantity_allclose(rr[0].data.xyz, expected_ss.r)
def test_cowell_propagation_with_zero_acceleration_equals_kepler(): # Data from Vallado, example 2.4 r0 = np.array([1131.340, -2282.343, 6672.423]) # km v0 = np.array([-5.64305, 4.30333, 2.42879]) # km/s tof = 40 * 60.0 # s orbit = Orbit.from_vectors(Earth, r0 * u.km, v0 * u.km / u.s) expected_r = np.array([-4219.7527, 4363.0292, -3958.7666]) expected_v = np.array([3.689866, -1.916735, -6.112511]) r, v = cowell(orbit, tof, ad=None) assert_allclose(r, expected_r, rtol=1e-5) assert_allclose(v, expected_v, rtol=1e-4)
def test_repr_maneuver(): alt_f = 35781.34857 * u.km r = [-6045, -3490, 2500] * u.km v = [-3.457, 6.618, 2.533] * u.km / u.s alt_b = 503873.0 * u.km alt_fi = 376310.0 * u.km ss_i = Orbit.from_vectors(Earth, r, v) expected_hohmann_manuever = "Number of impulses: 2, Total cost: 3.060548 km / s" expected_bielliptic_maneuver = "Number of impulses: 3, Total cost: 3.122556 km / s" assert repr(Maneuver.hohmann(ss_i, Earth.R + alt_f)) == expected_hohmann_manuever assert ( repr(Maneuver.bielliptic(ss_i, Earth.R + alt_b, Earth.R + alt_fi)) == expected_bielliptic_maneuver )
def test_after_propagation_r_and_v_dimensions(propagator): r0 = [111.340, -228.343, 2413.423] * u.km v0 = [-5.64305, 4.30333, 2.42879] * u.km / u.s tof = time.TimeDelta(50 * u.s) orbit = Orbit.from_vectors(Earth, r0, v0) rr, vv = propagator( orbit.attractor.k, orbit.r, orbit.v, tof.reshape(-1).to(u.s), rtol=1e-10, ) assert rr.ndim == 2 assert vv.ndim == 2
def test_long_propagation_preserves_orbit_elements(method): tof = 100 * u.year r_halleys = np.array( [-9018878.63569932, -94116054.79839276, 22619058.69943215] ) # km v_halleys = np.array([-49.95092305, -12.94843055, -4.29251577]) # km/s halleys = Orbit.from_vectors(Sun, r_halleys * u.km, v_halleys * u.km / u.s) params_ini = rv2coe(Sun.k.to(u.km ** 3 / u.s ** 2).value, r_halleys, v_halleys)[:-1] r_new, v_new = halleys.propagate(tof, method=method).rv() params_final = rv2coe( Sun.k.to(u.km ** 3 / u.s ** 2).value, r_new.to(u.km).value, v_new.to(u.km / u.s).value, )[:-1] assert_quantity_allclose(params_ini, params_final)
def test_rv_ctll(): r = np.array([-2384.46, 5729.01, 3050.46]) * u.km v = np.array([-7.36138, -2.98997, 1.64354]) * u.km / u.s orbit = Orbit.from_vectors(Earth, r, v) a=satellite.Propagator(orbit,T=0.1) #constellation T = 10 P = 10 F = 0 p2 = p * u.km constellation = ctll.Ctll.from_WalkerDelta(T,P,F,p,ecc,inc,argp) #constellation.info(v=True) rv = constellation.rv(9,dt=1,method=propagation.farnocchia)
def test_orbit_is_pickable(): # A custom hyperbolic orbit r = [ 1.197659243752796E+09, -4.443716685978071E+09, -1.747610548576734E+09 ] * u.km v = [ 5.540549267188614E+00, -1.251544669134140E+01, -4.848892572767733E+00 ] * u.km / u.s epoch = Time('2015-07-14 07:59', scale='tdb') ss = Orbit.from_vectors(Sun, r, v, epoch) pickled = pickle.dumps(ss) ss_result = pickle.loads(pickled) assert_array_equal(ss.r, ss_result.r) assert_array_equal(ss.v, ss_result.v) assert ss_result.epoch == ss.epoch
def test_cowell_works_with_small_perturbations(): r0 = [-2384.46, 5729.01, 3050.46] * u.km v0 = [-7.36138, -2.98997, 1.64354] * u.km / u.s r_expected = [13179.39566663877121754922, -13026.25123408228319021873, -9852.66213692844394245185] * u.km v_expected = [2.78170542314378943516, 3.21596786944631274352, 0.16327165546278937791] * u.km / u.s initial = Orbit.from_vectors(Earth, r0, v0) def accel(t0, state, k): v_vec = state[3:] norm_v = (v_vec * v_vec).sum() ** .5 return 1e-5 * v_vec / norm_v final = initial.propagate(3 * u.day, method=cowell, ad=accel) assert_quantity_allclose(final.r, r_expected) assert_quantity_allclose(final.v, v_expected)
def test_node_event_equatorial_orbit(): node_event = NodeCrossEvent(terminal=True) events = [node_event] r = np.array([9946.2, 1035.4, 0.0]) v = np.array([7.0, -0.1, 0.0]) orb = Orbit.from_vectors(Earth, r * u.km, v * u.km / u.s) tofs = [5, 10, 50] << u.s rr, vv = cowell( Earth.k, orb.r, orb.v, tofs, events=events, ) assert_quantity_allclose(node_event.last_t, 0.0 * u.s, atol=1e-1 * u.s)
def state_propagate(x: np.ndarray, epoch_obs: Time, params: PropParams) -> np.ndarray: """ Propagates the state vector from moment of description to moment of observation in time another using the poliasto library. Allows for custom perturbations. :param x: State vector at time of original description :param epoch_obs: Time of observation. :param params: object which serves as catch all for relevant info. Includes dt or amount of time between initial description to moment of observation, epoch of initial description, and perturbations to be included. :return: Returns state vector at moment of observation """ r = x[0:3] * u.km v = x[3:6] * u.km / u.s dt = epoch_obs - params.epoch sat_i = Orbit.from_vectors(Earth, r, v, epoch=params.epoch) sat_f = sat_i.cov_propagate(dt, method=cowell, ad=a_d, perturbations=params.perturbations) output = np.concatenate([sat_f.r.value, sat_f.v.value]) return output
def test_umbra_event_not_triggering_is_ok(): attractor = Earth tof = 100 * u.s r0 = np.array([281.89, 1411.473, 750.672]) v0 = np.array([7.36138, 2.98997, 1.64354]) orbit = Orbit.from_vectors(attractor, r0 * u.km, v0 * u.km / u.s) umbra_event = UmbraEvent(orbit) events = [umbra_event] rr, _ = cowell( attractor.k, orbit.r, orbit.v, [tof] * u.s, events=events, ) assert umbra_event.last_t == tof
def test_node_cross_event(): t_node = 3.46524036 * u.s r = [-6142438.668, 3492467.56, -25767.257] << u.km v = [505.848, 942.781, 7435.922] << u.km / u.s orbit = Orbit.from_vectors(Earth, r, v) node_event = NodeCrossEvent(terminal=True) events = [node_event] tofs = [0.01, 0.1, 0.5, 0.8, 1, 3, 5, 6, 10, 15] << u.s rr, vv = cowell( Earth.k, orbit.r, orbit.v, tofs, events=events, ) assert_quantity_allclose(node_event.last_t, t_node)
def build_orbit(row, epoch=None): """Builds an Orbit instance from a DataFrame row. :param row: A row from the USSTRATCOM ETL DataFrame :type row: pandas.Series :param epoch: An optional epoch to instantiate the orbit at, if no epoch is passed then use the epoch in the row :type epoch: pandas.Timestamp :return: An orbit object built using the orbital data in the row :rtype: poliastro.twobody.Orbit """ r, v = get_state_vectors(row) if not epoch: epoch = row.epoch epoch_time = Time(epoch.to_numpy(), scale='utc') orbit = Orbit.from_vectors(Earth, r, v, epoch=epoch_time) return orbit
def orbit_check(date, v, m, Isp): # sprawdzenie czy orbita została osiągnieta date_iso = time.Time(str(date.iso), format='iso', scale='utc') r_out = Orbit.from_body_ephem(Jupiter, date_iso) # polozenie Jowisza po asyscie r_out1, vp_out1 = r_out.rv() v_exit = v + (vp_out1 / (24 * 3600) * u.day / u.s) # predkosc satelity po manewrach epoch_out = date.jyear ss_out = Orbit.from_vectors(Sun, r_out1, v_exit, epoch=epoch_out) # wyjsciowe parametry orbity print('Sprawdzanie osiągnięcia orbity ...') print() if ss_out.ecc >= 1: # ekscentrycznosc orbity print('Predkosc jest okej') else: print('Predkosc jest za mała') print() print('Dostosuj się do minimalnej orbity wyjściowej ') # minimalna orbita wyjsciowa paraboliczna: ss_out_new = Orbit.parabolic(Sun, ss_out.p, ss_out.inc, ss_out.raan, ss_out.argp, ss_out.nu, epoch=epoch_out) v_out_new = ss_out_new.rv()[1] - v_exit # obliczenia nowej predkosci dv_out_new = np.linalg.norm(v_out_new) * u.km / u.s m_p_new = m * (math.exp(dv_out_new / Isp) - 1 ) # obliczenia brakujace masy paliwa # Odpowiedz: print('Potrzebna delta V: %.3f km/s' % float(dv_out_new / u.km * u.s)) print('Potrzebna dod. masa paliwa: %i kg' % int(m_p_new / u.kg))
def test_cowell_propagation_callback(): # Data from Vallado, example 2.4 r0 = np.array([1131.340, -2282.343, 6672.423]) # km v0 = np.array([-5.64305, 4.30333, 2.42879]) # km/s tof = 40 * 60.0 # s orbit = Orbit.from_vectors(Earth, r0 * u.km, v0 * u.km / u.s) results = [] def cb(t, u_): row = [t] row.extend(u_) results.append(row) r, v = cowell(orbit, tof, callback=cb) assert len(results) == 17 assert len(results[0]) == 7 assert results[-1][0] == tof
def test_propagate_to_date_has_proper_epoch(): # Data from Vallado, example 2.4 r0 = [1131.340, -2282.343, 6672.423] * u.km v0 = [-5.64305, 4.30333, 2.42879] * u.km / u.s init_epoch = J2000 final_epoch = time.Time("2000-01-01 12:40:00", scale="tdb") expected_r = [-4219.7527, 4363.0292, -3958.7666] * u.km expected_v = [3.689866, -1.916735, -6.112511] * u.km / u.s ss0 = Orbit.from_vectors(Earth, r0, v0, epoch=init_epoch) ss1 = ss0.propagate(final_epoch) r, v = ss1.rv() assert_quantity_allclose(r, expected_r, rtol=1e-5) assert_quantity_allclose(v, expected_v, rtol=1e-4) # Tolerance should be higher, see https://github.com/astropy/astropy/issues/6638 assert (ss1.epoch - final_epoch).sec == approx(0.0, abs=1e-6)
def no_pert_earth(initial, time, f_time): # No perturbation # 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 datetimeFormat = '%Y-%m-%d %H:%M:%S.%f' diff =datetime.strptime(str(f_time), datetimeFormat)\ - datetime.strptime(str(time), datetimeFormat) print("Time difference:") print(diff) tofs = TimeDelta(f_time - time) tofs = TimeDelta(np.linspace(0, 31 * u.day, num=1)) rr = propagate(initial, tofs, method=cowell, ad=None) print("") print("Positions and velocity vectors are:") #print(str(rr.x)) #print([float(s) for s in re.findall(r'-?\d+\.?\d*',str(rr.x))]) r = [[float(s) for s in re.findall(r'-?\d+\.?\d*', str(rr.x))][0], [float(s) for s in re.findall(r'-?\d+\.?\d*', str(rr.y))][0], [float(s) for s in re.findall(r'-?\d+\.?\d*', str(rr.z))][0]] * u.km v = [[float(s) for s in re.findall(r'-?\d+\.?\d*', str(rr.v_x))][0], [float(s) for s in re.findall(r'-?\d+\.?\d*', str(rr.v_y))][0], [float(s) for s in re.findall(r'-?\d+\.?\d*', str(rr.v_z))][0]] * u.km / u.s f_orbit = Orbit.from_vectors(Earth, r, v) print(r) print(v) #f_orbit.plot() print("") print("Orbital elements:") print(f_orbit.classical()) print("") #print("") #print(f_orbit.ecc) plotOrbit((f_orbit.a.value), (f_orbit.ecc.value), (f_orbit.inc.value), (f_orbit.raan.value), (f_orbit.argp.value), (f_orbit.nu.value))
def test_J2_propagation_Earth(): # From Curtis example 12.2: r0 = np.array([-2384.46, 5729.01, 3050.46]) # km v0 = np.array([-7.36138, -2.98997, 1.64354]) # km/s orbit = Orbit.from_vectors(Earth, r0 * u.km, v0 * u.km / u.s) tofs = [48.0] * u.h def f(t0, u_, k): du_kep = func_twobody(t0, u_, k) ax, ay, az = J2_perturbation(t0, u_, k, J2=Earth.J2.value, R=Earth.R.to(u.km).value) du_ad = np.array([0, 0, 0, ax, ay, az]) return du_kep + du_ad rr, vv = cowell(Earth.k, orbit.r, orbit.v, tofs, f=f) k = Earth.k.to(u.km**3 / u.s**2).value _, _, _, raan0, argp0, _ = rv2coe(k, r0, v0) _, _, _, raan, argp, _ = rv2coe(k, rr[0].to(u.km).value, vv[0].to(u.km / u.s).value) raan_variation_rate = (raan - raan0) / tofs[0].to( u.s).value # type: ignore argp_variation_rate = (argp - argp0) / tofs[0].to( u.s).value # type: ignore raan_variation_rate = (raan_variation_rate * u.rad / u.s).to(u.deg / u.h) argp_variation_rate = (argp_variation_rate * u.rad / u.s).to(u.deg / u.h) assert_quantity_allclose(raan_variation_rate, -0.172 * u.deg / u.h, rtol=1e-2) assert_quantity_allclose(argp_variation_rate, 0.282 * u.deg / u.h, rtol=1e-2)
def test_cowell_converges_with_small_perturbations(): r0 = [-2384.46, 5729.01, 3050.46] * u.km v0 = [-7.36138, -2.98997, 1.64354] * u.km / u.s initial = Orbit.from_vectors(Earth, r0, v0) def accel(t0, state, k): v_vec = state[3:] norm_v = (v_vec * v_vec).sum()**0.5 return 0.0 * v_vec / norm_v def f(t0, u_, k): du_kep = func_twobody(t0, u_, k) ax, ay, az = accel(t0, u_, k) du_ad = np.array([0, 0, 0, ax, ay, az]) return du_kep + du_ad final = initial.propagate(initial.period, method=cowell, f=f) assert_quantity_allclose(final.r, initial.r) assert_quantity_allclose(final.v, initial.v)
def test_latitude_cross_event(): r = [-6142438.668, 3492467.56, -25767.257] << u.km v = [505.848, 942.781, 7435.922] << u.km / u.s orbit = Orbit.from_vectors(Earth, r, v) thresh_lat = 60 * u.deg latitude_cross_event = LatitudeCrossEvent(orbit, thresh_lat, terminal=True) t_lat = 1701.716842130476 * u.s tofs = [5] * u.d events = [latitude_cross_event] rr, _ = cowell( Earth.k, orbit.r, orbit.v, tofs, events=events, ) assert_quantity_allclose(latitude_cross_event.last_t, t_lat)
def test_LOS_event(): t_los = 2327.165 * u.s r2 = np.array([-500, 1500, 4012.09]) << u.km v2 = np.array([5021.38, -2900.7, 1000.354]) << u.km / u.s orbit = Orbit.from_vectors(Earth, r2, v2) tofs = [100, 500, 1000, 2000] << u.s # Propagate the secondary body to generate its position coordinates. rr, vv = cowell( Earth.k, orbit.r, orbit.v, tofs, ) pos_coords = rr # Trajectory of the secondary body. orb = Orbit.from_classical( attractor=Earth, a=16000 * u.km, ecc=0.53 * u.one, inc=5 * u.deg, raan=5 * u.deg, argp=10 * u.deg, nu=30 * u.deg, ) los_event = LosEvent(Earth, pos_coords, terminal=True) events = [los_event] tofs = [1, 5, 10, 100, 1000, 2000, 3000, 5000] << u.s r, v = cowell( Earth.k, orb.r, orb.v, tofs, events=events, ) assert_quantity_allclose(los_event.last_t, t_los)
def test_soyuz_standard_gto_numerical(): # Data from Soyuz Users Manual, issue 2 revision 0 r_a = (Earth.R + 35950 * u.km).to(u.km).value r_p = (Earth.R + 250 * u.km).to(u.km).value a = (r_a + r_p) / 2 # km ecc = r_a / a - 1 argp_0 = (178 * u.deg).to(u.rad).value # rad argp_f = (178 * u.deg + 5 * u.deg).to(u.rad).value # rad f = 2.4e-7 # km / s2 k = Earth.k.decompose([u.km, u.s]).value optimal_accel = guidance_law(f) _, t_f = extra_quantities(k, a, ecc, argp_0, argp_f, f) # Retrieve r and v from initial orbit s0 = Orbit.from_classical( Earth, a * u.km, (r_a / a - 1) * u.one, 6 * u.deg, 188.5 * u.deg, 178 * u.deg, 0 * u.deg ) 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=optimal_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.argp.to(u.rad).value, argp_f, rtol=1e-4)
def test_J2_propagation_Earth(): # from Curtis example 12.2: r0 = np.array([-2384.46, 5729.01, 3050.46]) # km v0 = np.array([-7.36138, -2.98997, 1.64354]) # km/s k = Earth.k.to(u.km**3 / u.s**2).value orbit = Orbit.from_vectors(Earth, r0 * u.km, v0 * u.km / u.s) tof = (48.0 * u.h).to(u.s).value r, v = cowell(orbit, tof, ad=J2_perturbation, J2=Earth.J2.value, R=Earth.R.to(u.km).value) _, _, _, raan0, argp0, _ = rv2coe(k, r0, v0) _, _, _, raan, argp, _ = rv2coe(k, r, v) raan_variation_rate = (raan - raan0) / tof argp_variation_rate = (argp - argp0) / tof raan_variation_rate = (raan_variation_rate * u.rad / u.s).to(u.deg / u.h) argp_variation_rate = (argp_variation_rate * u.rad / u.s).to(u.deg / u.h) assert_quantity_allclose(raan_variation_rate, -0.172 * u.deg / u.h, rtol=1e-2) assert_quantity_allclose(argp_variation_rate, 0.282 * u.deg / u.h, rtol=1e-2)
def test_propagate_with_j2j3(): x = [66666, 0, 0, 0, 2.451, 0] dt = 100 * u.day r = x[0:3] * u.km v = x[3:6] * u.km / u.s epoch = Time(2454283.0, format="jd", scale="tdb") epoch_obs = epoch + dt prop_params = PropParams(epoch) prop_params.add_perturbation(Perturbations.J2, build_j2()) prop_params.add_perturbation(Perturbations.J3, build_j3()) sat_i = Orbit.from_vectors(Earth, r, v, epoch=epoch) sat_f = sat_i.cov_propagate(dt, method=cowell, ad=a_d_j2j3, J2=Earth.J2.value, R=R, J3=Earth.J3.value) x_poli = np.concatenate([sat_f.r.value, sat_f.v.value]) x_custom = state_propagate(x, epoch_obs, prop_params) assert np.array_equal(x_custom, x_poli)
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) ** 0.5 return accel * v / norm_v ss = Orbit.circular(Earth, 500 * u.km) tofs = [20] * ss.period r, v = cowell(Earth.k, ss.r, ss.v, tofs, ad=constant_accel) ss_final = Orbit.from_vectors(Earth, r[0], v[0]) 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 * tofs[0] assert_quantity_allclose(dv, accel_dt, rtol=1e-2)
def orbit_example(): if request.method == 'POST': if request.is_json: # load JSON data req = request.get_json() # getting the body from JSON and importing it from poliastro body = req.get("body") import_path = "poliastro.bodies" bodies = importlib.import_module(import_path) body = getattr(bodies, body) # loading position magnitude and unit and unifying it position_value = req.get("position").get("value") position_unit = req.get("position").get("unit") position_unit = PrefixUnit(position_unit) r = position_value * position_unit # loading velocity magnitude and unit and unifying it velocity_value = req.get("velocity").get("value") velocity_unit = req.get("velocity").get("unit") velocity_unit = velocity_unit.split("/") velocity_unit = list(map(PrefixUnit, velocity_unit)) v = velocity_value * velocity_unit[0] / velocity_unit[1] # Calculating Orbit final_orbit = Orbit.from_vectors(body, r, v) pericenter_radius = final_orbit.r_p.value apocenter_radius = final_orbit.r_a.value inclination = final_orbit.inc.value reference_frame = str(final_orbit.frame) attractor = str(final_orbit.attractor) epoch = final_orbit.epoch.value return jsonify(pericenter_radius=pericenter_radius, apocenter_radius=apocenter_radius, inclination=inclination, reference_frame=reference_frame[1:-1], attractor=attractor, epoch=epoch)
def test_geo_cases_numerical(ecc_0, ecc_f): a = 42164 # km inc_0 = 0.0 # rad, baseline inc_f = (20.0 * u.deg).to(u.rad).value # rad argp = 0.0 # rad, the method is efficient for 0 and 180 f = 2.4e-7 # km / s2 k = Earth.k.decompose([u.km, u.s]).value _, _, t_f = extra_quantities(k, a, ecc_0, ecc_f, inc_0, inc_f, argp, f) # Retrieve r and v from initial orbit s0 = Orbit.from_classical( Earth, a * u.km, ecc_0 * u.one, inc_0 * u.deg, 0 * u.deg, argp * u.deg, 0 * u.deg ) r0, v0 = s0.rv() optimal_accel = guidance_law(s0, ecc_f, inc_f, f) # Propagate orbit r, v = cowell(k, r0.to(u.km).value, v0.to(u.km / u.s).value, t_f, ad=optimal_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.ecc.value, ecc_f, rtol=1e-2, atol=1e-2) assert_allclose(sf.inc.to(u.rad).value, inc_f, rtol=1e-1)