Example #1
0
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)
Example #2
0
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())
Example #3
0
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(
    )
Example #4
0
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 _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
Example #6
0
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()
Example #7
0
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
Example #8
0
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
Example #9
0
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
Example #10
0
iss_30m = iss.propagate(30 * u.min)
iss_30m.epoch

iss_30m.nu.to(u.deg)
#plot (iss_30m)

earth = Orbit.from_body_ephem(Earth)

#plot(earth)
earth_30d = earth.propagate(30 * u.day)
#plot(earth_30d)

from poliastro.maneuver import Maneuver
dv = [5, 0, 0] * u.m / u.s
man = Maneuver.impulse(dv)
man = Maneuver((0 * u.s, dv))

ss_i = Orbit.circular(Earth, alt=700 * u.km)
ss_i
#plot(ss_i)
hoh = Maneuver.hohmann(ss_i, 36000 * u.km)
hoh.get_total_cost()
hoh.get_total_time()
print(hoh.get_total_cost())
print(hoh.get_total_time())

hoh.impulses[0]
hoh[0]
tuple(val.decompose([u.km, u.s]) for val in hoh[1])

ss_f = ss_i.apply_maneuver(hoh)
Example #11
0
def plane_change_maneuver(o: Orbit, theta):
    """ Generates inclination change maneuver. This changes the inclination by theta degress.
        o - initial orbit
        theta - expressed in plain float as degrees or as u.deg. This maneuver in general should be
        performed at either ascending or descending node.

        returns:
        maneuver that can be applied on the initial orbit.

        To perform this calculation, a local coords system is needed. (i,j,k) unit vectors are defined.
        The coords system is oriented as follows:

       j^ (normal vector)
        |
        |
        |
        +---------->    (velocity vector) ----------- orbital plane
       k             i

        (towards viewer = r vector, from Earth center to spacecraft)

        In this coords system, the inclination change is done in i,j plane.

                   _^
              vf__/  \
             __/      \ dv = vf - v
          __/          \
         /              \
        +---------------->
                v

        First we need to calculate the expected final velocity (vf). The get the delta-v vector as
        a difference of vf minus the original velocity.

         """

    # Let's assume the delay is not configurable and the maneuver always takes place immediately.
    delay = 0 * u.s

    if type(theta) == float:
        theta = theta * u.deg

    # Get the v (current velocity) and r (distance from Earth center) as vectors and make both of them dimiensionless
    # Also convert them to km first. We want to get rid of the units, because they complicate the cross product.
    v = o.v.to(u.km / u.s) / u.km * u.s
    r = o.r.to(u.km) / u.km

    # This is a normal vector. It is perpendicular to the plane defined by r (connected Earth center with the object) and
    # v (velocity). This has the right direction.
    normal = np.cross(v, r)
    # Now we need to calculate the right vectors magnitude
    normal = normal / np.linalg.norm(normal).value

    # Let's get 3 unit vectors and the r,v,n mangitudes (lenghts) expressed as floats
    v_len = np.linalg.norm(v).value
    n_len = np.linalg.norm(normal).value
    r_len = np.linalg.norm(r).value

    # get the unit vectors
    i = v / v_len
    j = normal / n_len
    k = r / r_len

    #print("i=%s" % i)
    #print("j=%s" % j)
    #print("k=%s" % k)

    # final velocity after maneuver
    vf = i * v_len * np.cos(theta) + j * v_len * np.sin(theta)

    #print("vf=%s" % vf)

    # The maneuver dv is a difference between original and final velocity
    dv = vf - v
    dv = dv * u.km / u.s

    # Ok, turn this into maneuver and we're done!
    man = Maneuver((delay, dv))

    return man
Example #12
0
def change_periapsis(conn: Client, node_ut: float, new_periapsis_alt: float):
    """Execute to change periapsis

    Execute to change periapsis.
    To be simple, burn only horizontal, so it might be not optimal

    Args:
        conn: kRPC connection
        new_periapsis_alt: new periapsis altitude
        node_ut: schedule burn at specific time, if not specified burn at next apoapsis

    Returns:
        return nothing, return when procedure finished
    """
    vessel = conn.space_center.active_vessel
    attractor = vessel.orbit.body
    reference_frame = attractor.non_rotating_reference_frame

    attractor_surface_radius = (
        vessel.orbit.apoapsis - vessel.orbit.apoapsis_altitude
    )
    new_periapsis = new_periapsis_alt + attractor_surface_radius

    if not vessel.orbit.apoapsis < 0 and new_periapsis >= vessel.orbit.apoapsis:
        return

    krpc_bodies, poliastro_bodies = krpc_poliastro_bodies(conn)

    ut = conn.space_center.ut

    time_to_burn = node_ut - ut
    is_raising = new_periapsis > vessel.orbit.periapsis

    prograde_vector_at_node = prograde_vector_at_ut(
        vessel.orbit, node_ut, reference_frame
    )
    anti_radial_vector_at_node = anti_radial_vector_at_ut(
        vessel.orbit, node_ut, reference_frame
    )
    normal_vector_at_node = normal_vector_at_ut(
        vessel.orbit, node_ut, reference_frame
    )
    horizontal_vector_at_node = horizontal_vector_at_ut(
        vessel.orbit, node_ut, reference_frame
    )
    burn_direction = 1 if is_raising else -1
    burn_vector = burn_direction * horizontal_vector_at_node

    r_i = vessel.position(reference_frame) * AstropyUnit.m
    v_i = vessel.velocity(reference_frame) * AstropyUnit.m / AstropyUnit.s
    ss_i = PoliastroOrbit.from_vectors(
        poliastro_bodies[attractor.name], r_i, v_i
    )

    # get upper bound of deltaV
    min_dv = 0
    max_dv = 0
    if is_raising:
        max_dv = 0.25
        tmp_new_pe = vessel.orbit.periapsis
        while tmp_new_pe < new_periapsis:
            max_dv *= 2
            tmp_burn = max_dv * burn_vector * AstropyUnit.m / AstropyUnit.s
            tmp_maneuver = Maneuver((time_to_burn * AstropyUnit.s, tmp_burn))
            tmp_new_ss = ss_i.apply_maneuver(tmp_maneuver)
            tmp_new_pe = abs(tmp_new_ss.r_p.to(AstropyUnit.m).value)
            if max_dv > 100000:
                break
    else:
        # horizontal speed should be max_dv for lowering periapsis
        max_dv = vessel.flight(reference_frame).horizontal_speed

    # binary search
    while max_dv - min_dv > 0.01:
        tmp_dv = (max_dv + min_dv) / 2.0
        tmp_burn = tmp_dv * burn_vector * AstropyUnit.m / AstropyUnit.s
        tmp_maneuver = Maneuver((time_to_burn * AstropyUnit.s, tmp_burn))
        tmp_new_ss = ss_i.apply_maneuver(tmp_maneuver)
        tmp_new_pe = abs(tmp_new_ss.r_p.to(AstropyUnit.m).value)

        if (is_raising and tmp_new_pe > new_periapsis) or (
            not is_raising and tmp_new_pe < new_periapsis
        ):
            max_dv = tmp_dv
        else:
            min_dv = tmp_dv

    dv_vector = burn_vector * (max_dv + min_dv) / 2.0

    dv_prograde = dot(dv_vector, prograde_vector_at_node) * norm(dv_vector)
    dv_anti_radial = dot(dv_vector, anti_radial_vector_at_node) * norm(
        dv_vector
    )
    dv_normal = dot(dv_vector, normal_vector_at_node) * norm(dv_vector)

    vessel.control.add_node(
        node_ut, prograde=dv_prograde, radial=dv_anti_radial, normal=dv_normal
    )

    # TODO: replace this logic to burn for dynamic change periapsis?
    # instead of just executing node, dynamically update direction
    execute_next_node(conn)