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 Number of revolutions. Returns ------- ss_short: poliastro.twobody.Orbit Short transfer orbit. ss_long: poliastro.twobody.Orbit Long transfer orbit. """ # Solving for short and long maneuvers lambert_short = Maneuver.lambert(earth_departure, mars_arrival, short=True, M=revs) lambert_long = Maneuver.lambert(earth_departure, mars_arrival, short=False, M=revs) # Aplly both maneuvers ss_short, _ = ss_dpt.apply_maneuver(lambert_short, intermediate=True) ss_long, _ = ss_dpt.apply_maneuver(lambert_long, intermediate=True) return ss_short, ss_long
def test_maneuver_total_time(): dt1 = 10.0 * u.s dt2 = 100.0 * u.s _v = np.zeros(3) * u.km / u.s # Unused velocity expected_total_time = 110.0 * u.s man = Maneuver((dt1, _v), (dt2, _v)) assert_quantity_allclose(man.get_total_time(), expected_total_time)
def test_maneuver_total_time(): dt1 = 10.0 * u.s dt2 = 100.0 * u.s _v = np.zeros(3) * u.km / u.s # Unused velocity expected_total_time = 110.0 * u.s man = Maneuver((dt1, _v), (dt2, _v)) assert_almost_equal(man.get_total_time().to(u.s).value, expected_total_time.value)
def Earth_to_Jupiter(delta_v): """ Calculates the manuever and the launch windows from Earth to Jupiter, assuming tangential impulsive maneuver from Earth orbit around the Sun Earth_to_Jupiter(dv): 'dv' is given with velocity units (u.m/u.s) Returns: ss_transfer = trasfer orbit object t = time to the first next launch window T = period between possible launch windows t_transfer = time of transfer from launch to Jupiter arrival """ dv = delta_v * v_Earth_dir # Initial transfer orbit calculation (to obtain transfer time) man_tmp = Maneuver.impulse(dv) transfer = ss_Earth.apply_maneuver(man_tmp) # Angles calculation # nu_Jupiter: nu of transfer orbit where it crosses Jupiter nu_Jupiter = (np.math.acos((transfer.p/R_J - 1)/transfer.ecc)*u.rad) ang_vel_Earth = (norm(v_Earth).value / R_E.value)*u.rad/u.s ang_vel_Jupiter = (norm(v_Jupiter).value / R_J.value)*u.rad/u.s # Transfer time M = nu_to_M(nu_Jupiter, transfer.ecc) t_transfer = M/transfer.n # Delta_nu at launch (Final nu - nu that Jupiter walks during transfer) delta_nu_at_launch = nu_Jupiter - ang_vel_Jupiter * t_transfer # Angles in radians nu_init = angle(r_Earth, r_Jupiter)*u.rad # Next launch window in t: t = (nu_init - delta_nu_at_launch) / (ang_vel_Earth - ang_vel_Jupiter) # Time between windows T = (2*np.pi*u.rad) / (ang_vel_Earth - ang_vel_Jupiter) # If time to the windows is negative (in the past), we should wait until next window while t < 0: t = t + T # Earth at launch ss_Earth_launch = ss_Earth.propagate(t) launch_dir = ss_Earth_launch.v / norm(ss_Earth_launch.v) dv = delta_v * launch_dir # Maneuver calculation man = Maneuver((t, dv)) ss_transfer = ss_Earth.apply_maneuver(man) return ss_transfer, t, T, t_transfer
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_maneuver_raises_error_if_dvs_are_not_vectors(): dt = 1 * u.s wrong_dv = 1 * u.km / u.s with pytest.raises(ValueError) as excinfo: Maneuver((dt, wrong_dv)) assert "ValueError: Delta-V must be three dimensions vectors" in excinfo.exconly( )
def test_hohmann_maneuver(nu): # Data from Vallado, example 6.1 alt_i = 191.34411 * u.km alt_f = 35781.34857 * u.km _a = 0 * u.deg ss_i = Orbit.from_classical(Earth, Earth.R + alt_i, ecc=0 * u.one, inc=_a, raan=_a, argp=_a, nu=nu) # Expected output expected_dv = 3.935224 * u.km / u.s expected_t_pericenter = ss_i.time_to_anomaly(0 * u.deg) expected_t_trans = 5.256713 * u.h expected_total_time = expected_t_pericenter + expected_t_trans man = Maneuver.hohmann(ss_i, Earth.R + alt_f) assert_quantity_allclose(man.get_total_cost(), expected_dv, rtol=1e-5) assert_quantity_allclose(man.get_total_time(), expected_total_time, rtol=1e-5) assert_quantity_allclose(ss_i.apply_maneuver(man).ecc, 0 * u.one, atol=1e-14 * u.one)
def test_maneuver_raises_error_if_units_are_wrong(): wrong_dt = 1.0 _v = np.zeros(3) * u.km / u.s # Unused velocity with pytest.raises(u.UnitsError) as excinfo: Maneuver([wrong_dt, _v]) assert ("UnitsError: Argument 'dts' to function '_initialize' must be in units convertible to 's'." in excinfo.exconly())
def test_plot_maneuver(): # Data from Vallado, example 6.1 alt_i = 191.34411 * u.km alt_f = 35781.34857 * u.km _a = 0 * u.deg ss_i = Orbit.from_classical( attractor=Earth, a=Earth.R + alt_i, ecc=0 * u.one, inc=_a, raan=_a, argp=_a, nu=_a, ) # Create the maneuver man = Maneuver.hohmann(ss_i, Earth.R + alt_f) # Plot the maneuver fig, ax = plt.subplots() plotter = StaticOrbitPlotter(ax=ax) plotter.plot(ss_i, label="Initial orbit", color="blue") plotter.plot_maneuver(ss_i, man, label="Hohmann maneuver", color="red") return fig
def test_bielliptic_maneuver(nu): # Data from Vallado, example 6.2 alt_i = 191.34411 * u.km alt_b = 503873.0 * u.km alt_f = 376310.0 * u.km _a = 0 * u.deg ss_i = Orbit.from_classical(Earth, Earth.R + alt_i, ecc=0 * u.one, inc=_a, raan=_a, argp=_a, nu=nu) # Expected output expected_dv = 3.904057 * u.km / u.s expected_t_pericenter = ss_i.time_to_anomaly(0 * u.deg) expected_t_trans = 593.919803 * u.h expected_total_time = expected_t_pericenter + expected_t_trans 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_total_time, rtol=1e-6)
def test_correct_pericenter_J2_exception(): ss0 = Orbit.from_classical( Mercury, 1000 * u.km, 0 * u.one, 0 * u.deg, 0 * u.deg, 0 * u.deg, 0 * u.deg, ) max_delta_r = 30 * u.km with pytest.raises(NotImplementedError) as excinfo: Maneuver.correct_pericenter(ss0, max_delta_r) assert excinfo.type == NotImplementedError assert (str( excinfo.value ) == f"The correction maneuver is not yet supported for {ss0.attractor}")
def _split_burn_to_impulse_list(self, dv): split_impulse = dv / self.simulation_ratio # applying these maneuvers takes a long time; reduce simulation ratio? impulse = [] for x in range(0, self.simulation_ratio): impulse.append((self.simulation_step, split_impulse)) maneuvers = Maneuver(*impulse) return maneuvers
def test_correct_pericenter_ecc_exception(): ss0 = Orbit.from_classical( Earth, 1000 * u.km, 0.5 * u.one, 0 * u.deg, 0 * u.deg, 0 * u.deg, 0 * u.deg, ) max_delta_r = 30 * u.km with pytest.raises(NotImplementedError) as excinfo: Maneuver.correct_pericenter(ss0, max_delta_r) assert excinfo.type == NotImplementedError assert ( str(excinfo.value) == f"The correction maneuver is not yet supported with {ss0.ecc},it should be less than or equal to 0.001" )
def test_maneuver_constructor_raises_error_if_invalid_delta_v(): dv1 = np.zeros(3) * u.km / u.s dv2 = np.ones(2) * u.km / u.s # Incorrect dv with pytest.raises(ValueError) as excinfo: with warnings.catch_warnings(): # Different length numpy arrays generate a deprecation warning. warnings.simplefilter("ignore", category=np.VisibleDeprecationWarning) Maneuver((0 * u.s, dv1), (2 * u.s, dv2)) assert "Delta-V must be three dimensions vectors" in excinfo.exconly()
def orbit_impulse( orbit, vector ): #alter an obejcts orbit due an impulse (used for debris projectile collisions) dv = [vector[0].value, vector[1].to(vector[0].unit).value, 0 ] * vector[0].unit man = Maneuver.impulse(dv) return orbit.apply_maneuver(man)
def generate_fitness_score(w1, w2, w3, w4, delt_v_size, test_orb, seq): num_vs = 0 for man in seq: if man == '1': test_orb = test_orb.apply_maneuver( Maneuver.impulse((delt_v_size, 0, 0) * u.m / u.s)) num_vs += 1 if man == '2': test_orb = test_orb.apply_maneuver( Maneuver.impulse((0, delt_v_size, 0) * u.m / u.s)) num_vs += 1 if man == '3': test_orb = test_orb.apply_maneuver( Maneuver.impulse((0, 0, delt_v_size) * u.m / u.s)) num_vs += 1 if man == '4': test_orb = test_orb.apply_maneuver( Maneuver.impulse((-delt_v_size, 0, 0) * u.m / u.s)) num_vs += 1 if man == '5': test_orb = test_orb.apply_maneuver( Maneuver.impulse((0, -delt_v_size, 0) * u.m / u.s)) num_vs += 1 if man == '6': test_orb = test_orb.apply_maneuver( Maneuver.impulse((0, 0, -delt_v_size) * u.m / u.s)) num_vs += 1 test_orb = test_orb.propagate(20 * u.min) return np.abs(float(test_orb.inc / u.rad - 1.57)) * w1 + float( test_orb.ecc) * w2 + np.abs(float( test_orb.raan / u.rad)) * w3 + np.abs( float(test_orb.a / u.km - 15000) / 15000) * w4
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_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_lambert_tof_exception(): ss_f = Orbit.circular( attractor=Earth, alt=36_000 * u.km, inc=0 * u.deg, raan=0 * u.deg, arglat=0 * u.deg, epoch=Time("J2000"), ) ss_i = Orbit.circular( attractor=Earth, alt=36_000 * u.km, inc=0 * u.deg, raan=0 * u.deg, arglat=0 * u.deg, epoch=Time("J2001"), ) with pytest.raises(ValueError) as excinfo: Maneuver.lambert(ss_i, ss_f) assert excinfo.type == ValueError assert ( str(excinfo.value) == "Epoch of initial orbit greater than epoch of final orbit, causing a negative time of flight" )
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_correct_pericenter(attractor, max_delta_r, a, ecc, inc, expected_t, expected_v): ss0 = Orbit.from_classical( attractor, a, ecc, inc, 0 * u.deg, 0 * u.deg, 0 * u.deg, ) maneuver = Maneuver.correct_pericenter(ss0, max_delta_r) assert_quantity_allclose(maneuver[0][0], expected_t) assert_quantity_allclose(maneuver[0][1].value.tolist(), expected_v.value.tolist())
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 _targetting(departure_body, target_body, t_launch, t_arrival): """This function returns the increment in departure and arrival velocities.""" # Get position and velocities for departure and arrival rr_dpt_body, vv_dpt_body = _get_state(departure_body, t_launch) rr_arr_body, vv_arr_body = _get_state(target_body, t_arrival) # Transform into Orbit objects attractor = departure_body.parent ss_dpt = Orbit.from_vectors(attractor, rr_dpt_body, vv_dpt_body, epoch=t_launch) ss_arr = Orbit.from_vectors(attractor, rr_arr_body, vv_arr_body, epoch=t_arrival) # Define time of flight tof = ss_arr.epoch - ss_dpt.epoch if tof <= 0: return None, None, None, None, None try: # Lambert is now a Maneuver object man_lambert = Maneuver.lambert(ss_dpt, ss_arr) # Get norm delta velocities dv_dpt = norm(man_lambert.impulses[0][1]) dv_arr = norm(man_lambert.impulses[1][1]) # Compute all the output variables 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 total_delta_v(launch, arrival): """Calculate the total delta v for specific combination of launch date and arrival date :param launch: launch time in isoformat string :param arrival: desired arrival time in isoformat string """ date_launch = time.Time(launch, scale="utc") date_arrival = time.Time(arrival, scale="utc") ss_earth = Orbit.from_body_ephem(Earth, date_launch) ss_mars = Orbit.from_body_ephem(Mars, date_arrival) man_lambert = Maneuver.lambert(ss_earth, ss_mars) return { 'delta_v': man_lambert.get_total_cost().value, 'total_seconds': man_lambert.get_total_time().value }
def prograde_maneuver(o: Orbit, dv, delay): """ Generates maneuver in the prograde direction. dv - expressed as dimensionless float (in m/s) delay - delay expressed as u.s (in seconds) """ if delay is None: delay = 0 * u.s # If the units used are km rather than m, then we need to shrink the dv value by 3 orders of magnitude if o.v[0].unit == u.km / u.s: dv /= 1000 # normalize v len = np.linalg.norm(o.v) vnorm = o.v / len.value v = vnorm * dv man = Maneuver((delay, v)) return man
def maneuver_phasing_form_orbit(part_of_period, orbit, plot=False, intermediate=True): period = (orbit.period).value time_maneuver = part_of_period * period semi_major_axis_maneuver = semi_major_axis_from_period(time_maneuver) delta_v = linear_velocity((orbit.a).value, (orbit.a).value) - \ linear_velocity((orbit.a).value, semi_major_axis_maneuver) a_ph = semi_major_axis_maneuver ss_i = orbit hoh = Maneuver.hohmann(ss_i, a_ph * u.km) ss_a, ss_f = ss_i.apply_maneuver(hoh, intermediate=intermediate) if plot: fig, ax = plt.subplots() # (figsize=(4, 4)) plotter = StaticOrbitPlotter(ax) plotter.plot(ss_i, label="Initial orbit", color="red") plotter.plot(ss_a, label="Phasing orbit", color="blue") plt.savefig("figures/ManeuverPhasing, t_man=" + str(part_of_period) + ".png") return 2 * delta_v, period * part_of_period, ss_a, ss_f
def test_maneuver_impulse(): dv = [1, 0, 0] * u.m / u.s man = Maneuver.impulse(dv) assert man.impulses[0] == (0 * u.s, dv)
#This is a plot of all of the initial spacecraft orbits op = OrbitPlotter3D() op.plot(tests[0].orbit) op.plot(tests[1].orbit) op.plot(tests[2].orbit) op.plot(tests[3].orbit) #This is a plot of the final spacecraft orbits, after applying the fittest maneuver strings for each of them. f_orbs = [test.orbit for test in tests] delt_v_size = 500 for i in range(0,len(f_orbs)): for man in fittest[i][0]: if man == '1': f_orbs[i] = f_orbs[i].apply_maneuver(Maneuver.impulse((delt_v_size,0,0)*u.m/u.s)) if man == '2': f_orbs[i] = f_orbs[i].apply_maneuver(Maneuver.impulse((0,delt_v_size,0)*u.m/u.s)) if man == '3': f_orbs[i] = f_orbs[i].apply_maneuver(Maneuver.impulse((0,0,delt_v_size)*u.m/u.s)) if man == '4': f_orbs[i] = f_orbs[i].apply_maneuver(Maneuver.impulse((-delt_v_size,0,0)*u.m/u.s)) if man == '5': f_orbs[i] = f_orbs[i].apply_maneuver(Maneuver.impulse((0,-delt_v_size,0)*u.m/u.s)) if man == '6': f_orbs[i] = f_orbs[i].apply_maneuver(Maneuver.impulse((0,0,-delt_v_size)*u.m/u.s)) f_orbs[i] = f_orbs[i].propagate(20*u.min) op = OrbitPlotter3D() op.plot(f_orbs[0]) op.plot(f_orbs[1])
def maneuver(self, dv): man = Maneuver.impulse(dv*u.km/u.s) self.orbit = self.orbit.apply_maneuver(man)