Beispiel #1
0
def test_parabolic_elements_fail_early():
    attractor = Earth
    ecc = 1.0 * u.one
    _d = 1.0 * u.AU  # Unused distance
    _a = 1.0 * u.deg  # Unused angle
    with pytest.raises(ValueError) as excinfo:
        Orbit.from_classical(attractor, _d, ecc, _a, _a, _a, _a)
    assert ("ValueError: For parabolic orbits use Orbit.parabolic instead" in excinfo.exconly())
Beispiel #2
0
def test_bad_inclination_raises_exception():
    _d = 1.0 * u.AU  # Unused distance
    _ = 0.5 * u.one  # Unused dimensionless value
    _a = 1.0 * u.deg  # Unused angle
    bad_inc = 200 * u.deg
    _body = Sun  # Unused body
    with pytest.raises(ValueError) as excinfo:
        Orbit.from_classical(_body, _d, _, bad_inc, _a, _a, _a)
    assert ("ValueError: Inclination must be between 0 and 180 degrees" in excinfo.exconly())
def test_parabolic_elements_fail_early():
    attractor = Earth
    ecc = 1.0 * u.one
    _d = 1.0 * u.AU  # Unused distance
    _a = 1.0 * u.deg  # Unused angle
    with pytest.raises(ValueError) as excinfo:
        Orbit.from_classical(attractor, _d, ecc, _a, _a, _a, _a)
    assert ("ValueError: For parabolic orbits use Orbit.parabolic instead"
            in excinfo.exconly())
Beispiel #4
0
def test_bad_hyperbolic_raises_exception():
    bad_a = 1.0 * u.AU
    ecc = 1.5 * u.one
    _a = 1.0 * u.deg  # Unused angle
    _inc = 100 * u.deg  # Unused inclination
    _body = Sun  # Unused body
    with pytest.raises(ValueError) as excinfo:
        Orbit.from_classical(_body, bad_a, ecc, _inc, _a, _a, _a)
    assert ("Hyperbolic orbits have negative semimajor axis" in excinfo.exconly())
Beispiel #5
0
def test_state_raises_unitserror_if_elements_units_are_wrong():
    _d = 1.0 * u.AU  # Unused distance
    _ = 0.5 * u.one  # Unused dimensionless value
    _a = 1.0 * u.deg  # Unused angle
    wrong_angle = 1.0 * u.AU
    with pytest.raises(u.UnitsError) as excinfo:
        Orbit.from_classical(Sun, _d, _, _a, _a, _a, wrong_angle)
    assert ("UnitsError: Argument 'nu' to function 'from_classical' must be in units convertible to 'rad'."
            in excinfo.exconly())
def test_state_raises_unitserror_if_elements_units_are_wrong():
    _d = 1.0 * u.AU  # Unused distance
    _ = 0.5 * u.one  # Unused dimensionless value
    _a = 1.0 * u.deg  # Unused angle
    wrong_angle = 1.0 * u.AU
    with pytest.raises(u.UnitsError) as excinfo:
        Orbit.from_classical(Sun, _d, _, _a, _a, _a, wrong_angle)
    assert (
        "UnitsError: Argument 'nu' to function 'from_classical' must be in units convertible to 'rad'."
        in excinfo.exconly())
def test_bad_inclination_raises_exception():
    _d = 1.0 * u.AU  # Unused distance
    _ = 0.5 * u.one  # Unused dimensionless value
    _a = 1.0 * u.deg  # Unused angle
    _body = Sun  # Unused body
    bad_inc = 200 * u.deg
    with pytest.raises(ValueError) as excinfo:
        Orbit.from_classical(_body, _d, _, bad_inc, _a, _a, _a)
    assert ("ValueError: Inclination must be between 0 and 180 degrees"
            in excinfo.exconly())
def test_bad_hyperbolic_raises_exception():
    bad_a = 1.0 * u.AU
    ecc = 1.5 * u.one
    _inc = 100 * u.deg  # Unused inclination
    _a = 1.0 * u.deg  # Unused angle
    _body = Sun  # Unused body
    with pytest.raises(ValueError) as excinfo:
        Orbit.from_classical(_body, bad_a, ecc, _inc, _a, _a, _a)
    assert "Hyperbolic orbits have negative semimajor axis" in excinfo.exconly(
    )
Beispiel #9
0
def test_mean_motion(ecc):
    _a = 0.0 * u.rad
    tof = 1.0 * u.min
    if ecc < 1.0:
        orbit = Orbit.from_classical(Earth, 10000 * u.km, ecc * u.one, _a, _a, _a, 1.0 * u.rad)
    else:
        orbit = Orbit.from_classical(Earth, -10000 * u.km, ecc * u.one, _a, _a, _a, 1.0 * u.rad)
    orbit_cowell = orbit.propagate(tof, method=cowell)
    orbit_mean_motion = orbit.propagate(tof, method=mean_motion)

    assert_quantity_allclose(orbit_cowell.r, orbit_mean_motion.r)
    assert_quantity_allclose(orbit_cowell.v, orbit_mean_motion.v)
def test_mean_motion(ecc):
    _a = 0.0 * u.rad
    tof = 1.0 * u.min
    if ecc < 1.0:
        orbit = Orbit.from_classical(Earth, 10000 * u.km, ecc * u.one, _a, _a, _a, 1.0 * u.rad)
    else:
        orbit = Orbit.from_classical(Earth, -10000 * u.km, ecc * u.one, _a, _a, _a, 1.0 * u.rad)
    orbit_cowell = orbit.propagate(tof, method=cowell)
    orbit_mean_motion = orbit.propagate(tof, method=mean_motion)

    assert_quantity_allclose(orbit_cowell.r, orbit_mean_motion.r)
    assert_quantity_allclose(orbit_cowell.v, orbit_mean_motion.v)
Beispiel #11
0
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)
Beispiel #12
0
def test_propagating_to_certain_nu_is_correct():
    # take an elliptic orbit
    a = 1.0 * u.AU
    ecc = 1.0 / 3.0 * u.one
    _a = 0.0 * u.rad
    nu = 10 * u.deg
    elliptic = Orbit.from_classical(Sun, a, ecc, _a, _a, _a, nu)

    elliptic_at_perihelion = elliptic.propagate_to_anomaly(0.0 * u.rad)
    r_per, _ = elliptic_at_perihelion.rv()

    elliptic_at_aphelion = elliptic.propagate_to_anomaly(np.pi * u.rad)
    r_ap, _ = elliptic_at_aphelion.rv()

    assert_quantity_allclose(norm(r_per), a * (1.0 - ecc))
    assert_quantity_allclose(norm(r_ap), a * (1.0 + ecc))

    # TODO: Test specific values
    assert elliptic_at_perihelion.epoch > elliptic.epoch
    assert elliptic_at_aphelion.epoch > elliptic.epoch

    # test 10 random true anomaly values
    for _ in range(10):
        nu = np.random.uniform(low=0.0, high=2 * np.pi)
        elliptic = elliptic.propagate_to_anomaly(nu * u.rad)
        r, _ = elliptic.rv()
        assert_quantity_allclose(norm(r), a * (1.0 - ecc ** 2) / (1 + ecc * np.cos(nu)))
Beispiel #13
0
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)
Beispiel #14
0
def test_penumbra_event_crossing():
    expected_penumbra_t = Time("2020-01-01 00:04:26.060",
                               scale="utc")  # From Orekit.
    attractor = Earth
    tof = 2 * u.d
    epoch = Time("2020-01-01", scale="utc")
    orbit = Orbit.from_classical(
        attractor=attractor,
        a=6828137.0 * u.m,
        ecc=0.0073 * u.one,
        inc=87.0 * u.deg,
        raan=20.0 * u.deg,
        argp=10.0 * u.deg,
        nu=0 * u.deg,
        epoch=epoch,
    )

    penumbra_event = PenumbraEvent(orbit, terminal=True)
    events = [penumbra_event]

    rr, _ = cowell(
        attractor.k,
        orbit.r,
        orbit.v,
        [tof] * u.s,
        events=events,
    )

    assert expected_penumbra_t.isclose(epoch + penumbra_event.last_t,
                                       atol=1 * u.s)
Beispiel #15
0
def test_geo_cases_beta_dnd_delta_v(ecc_0, inc_f, expected_beta,
                                    expected_delta_V):
    a = 42164  # km
    ecc_f = 0.0
    inc_0 = 0.0  # rad, baseline
    argp = 0.0  # rad, the method is efficient for 0 and 180
    f = 2.4e-7 * (u.km / u.s**2)

    inc_f = np.radians(inc_f)
    expected_beta = np.radians(expected_beta)

    s0 = Orbit.from_classical(
        attractor=Earth,
        a=a * u.km,
        ecc=ecc_0 * u.one,
        inc=inc_0 * u.deg,
        raan=0 * u.deg,
        argp=argp * u.deg,
        nu=0 * u.deg,
    )

    beta = beta_change_ecc_inc(ecc_0=ecc_0,
                               ecc_f=ecc_f,
                               inc_0=inc_0,
                               inc_f=inc_f,
                               argp=argp)
    _, delta_V, _ = change_ecc_inc(ss_0=s0,
                                   ecc_f=ecc_f,
                                   inc_f=inc_f * u.rad,
                                   f=f)

    assert_allclose(delta_V.to_value(u.km / u.s), expected_delta_V, rtol=1e-2)
    assert_allclose(beta, expected_beta, rtol=1e-2)
Beispiel #16
0
def test_geo_cases_numerical(ecc_0, ecc_f):
    a = 42164  # km
    inc_0 = 0.0
    inc_f = 20.0 * u.deg
    argp = 0.0  # rad, the method is efficient for 0 and 180
    f = 2.4e-7 * (u.km / u.s**2)

    # Initial orbit
    s0 = Orbit.from_classical(
        attractor=Earth,
        a=a * u.km,
        ecc=ecc_0 * u.one,
        inc=inc_0 * u.deg,
        raan=0 * u.deg,
        argp=argp * u.deg,
        nu=0 * u.deg,
    )
    a_d, _, t_f = change_ecc_inc(ss_0=s0, ecc_f=ecc_f, inc_f=inc_f, f=f)

    # Propagate orbit
    def f_geo(t0, u_, k):
        du_kep = func_twobody(t0, u_, k)
        ax, ay, az = a_d(t0, u_, k)
        du_ad = np.array([0, 0, 0, ax, ay, az])
        return du_kep + du_ad

    sf = s0.propagate(t_f, method=cowell, f=f_geo, rtol=1e-8)

    assert_allclose(sf.ecc.value, ecc_f, rtol=1e-2, atol=1e-2)
    assert_allclose(sf.inc.to_value(u.rad), inc_f.to_value(u.rad), rtol=1e-1)
Beispiel #17
0
def test_solar_pressure():
    # based on example 12.9 from Howard Curtis
    solar_system_ephemeris.set('de432s')

    j_date = 2438400.5 * u.day
    tof = 600 * u.day
    sun_r = build_ephem_interpolant(Sun, 365 * u.day, (j_date, j_date + tof), rtol=1e-2)
    epoch = Time(j_date, format='jd', scale='tdb')
    drag_force_orbit = [10085.44 * u.km, 0.025422 * u.one, 88.3924 * u.deg,
                        45.38124 * u.deg, 227.493 * u.deg, 343.4268 * u.deg]

    initial = Orbit.from_classical(Earth, *drag_force_orbit, epoch=epoch)
    # in Curtis, the mean distance to Sun is used. In order to validate against it, we have to do the same thing
    sun_normalized = functools.partial(normalize_to_Curtis, sun_r=sun_r)

    r, v = cowell(initial, np.linspace(0, (tof).to(u.s).value, 4000), rtol=1e-8, ad=radiation_pressure,
                  R=Earth.R.to(u.km).value, C_R=2.0, A=2e-4, m=100, Wdivc_s=Sun.Wdivc.value, star=sun_normalized)

    delta_as, delta_eccs, delta_incs, delta_raans, delta_argps, delta_hs = [], [], [], [], [], []
    for ri, vi in zip(r, v):
        orbit_params = rv2coe(Earth.k.to(u.km**3 / u.s**2).value, ri, vi)
        delta_eccs.append(orbit_params[1] - drag_force_orbit[1].value)
        delta_incs.append((orbit_params[2] * u.rad).to(u.deg).value - drag_force_orbit[2].value)
        delta_raans.append((orbit_params[3] * u.rad).to(u.deg).value - drag_force_orbit[3].value)
        delta_argps.append((orbit_params[4] * u.rad).to(u.deg).value - drag_force_orbit[4].value)

    # averaging over 5 last values in the way Curtis does
    for check in solar_pressure_checks:
        index = int(1.0 * check['t_days'] / tof.to(u.day).value * 4000)
        delta_ecc, delta_inc, delta_raan, delta_argp = np.mean(delta_eccs[index - 5:index]), \
            np.mean(delta_incs[index - 5:index]), np.mean(delta_raans[index - 5:index]), \
            np.mean(delta_argps[index - 5:index])
        assert_quantity_allclose([delta_ecc, delta_inc, delta_raan, delta_argp],
                                 check['deltas_expected'], rtol=1e-1, atol=1e-4)
Beispiel #18
0
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

    # Retrieve r and v from initial orbit
    s0 = Orbit.from_classical(
        attractor=Earth,
        a=a_0 * u.km,
        ecc=ecc_0 * u.one,
        inc=0 * u.deg,
        raan=0 * u.deg,
        argp=0 * u.deg,
        nu=0 * u.deg,
    )
    a_d, _, t_f = change_ecc_quasioptimal(s0, ecc_f, f)

    # Propagate orbit
    def f_ss0_disposal(t0, u_, k):
        du_kep = func_twobody(t0, u_, k)
        ax, ay, az = a_d(t0, u_, k)
        du_ad = np.array([0, 0, 0, ax, ay, az])
        return du_kep + du_ad

    sf = s0.propagate(t_f * u.s, method=cowell, f=f_ss0_disposal, rtol=1e-8)

    assert_allclose(sf.ecc.value, ecc_f, rtol=1e-4, atol=1e-4)
Beispiel #19
0
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(Earth, 16000 * u.km, 0.53 * u.one, 5 * u.deg,
                               5 * u.deg, 10 * u.deg, 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)
Beispiel #20
0
def test_3rd_body_Curtis(test_params):
    # based on example 12.11 from Howard Curtis
    body = test_params['body']
    solar_system_ephemeris.set('de432s')

    j_date = 2454283.0 * u.day
    tof = (test_params['tof']).to(u.s).value
    body_r = build_ephem_interpolant(body, test_params['period'], (j_date, j_date + test_params['tof']), rtol=1e-2)

    epoch = Time(j_date, format='jd', scale='tdb')
    initial = Orbit.from_classical(Earth, *test_params['orbit'], epoch=epoch)
    r, v = cowell(initial, np.linspace(0, tof, 400), rtol=1e-10, ad=third_body,
                  k_third=body.k.to(u.km**3 / u.s**2).value, third_body=body_r)

    incs, raans, argps = [], [], []
    for ri, vi in zip(r, v):
        angles = Angle(rv2coe(Earth.k.to(u.km**3 / u.s**2).value, ri, vi)[2:5] * u.rad)  # inc, raan, argp
        angles = angles.wrap_at(180 * u.deg)
        incs.append(angles[0].value)
        raans.append(angles[1].value)
        argps.append(angles[2].value)

    # averaging over 5 last values in the way Curtis does
    inc_f, raan_f, argp_f = np.mean(incs[-5:]), np.mean(raans[-5:]), np.mean(argps[-5:])

    assert_quantity_allclose([(raan_f * u.rad).to(u.deg) - test_params['orbit'][3],
                              (inc_f * u.rad).to(u.deg) - test_params['orbit'][2],
                              (argp_f * u.rad).to(u.deg) - test_params['orbit'][4]],
                             [test_params['raan'], test_params['inc'], test_params['argp']],
                             rtol=1e-1)
Beispiel #21
0
def test_umbra_event_crossing():
    expected_umbra_t = Time("2020-01-01 00:04:51.328",
                            scale="utc")  # From Orekit.
    attractor = Earth
    tof = 2 * u.d
    epoch = Time("2020-01-01", scale="utc")
    coe = (
        6828137.0 * u.m,
        0.0073 * u.one,
        87.0 * u.deg,
        20.0 * u.deg,
        10.0 * u.deg,
        0 * u.deg,
    )
    orbit = Orbit.from_classical(attractor, *coe, epoch=epoch)

    umbra_event = UmbraEvent(orbit, terminal=True)
    events = [umbra_event]

    rr, _ = cowell(
        attractor.k,
        orbit.r,
        orbit.v,
        [tof] * u.s,
        events=events,
    )

    assert expected_umbra_t.isclose(epoch + umbra_event.last_t, atol=1 * u.s)
def test_3rd_body_Curtis(test_params):
    # based on example 12.11 from Howard Curtis
    body = test_params['body']
    with solar_system_ephemeris.set('builtin'):
        j_date = 2454283.0 * u.day
        tof = (test_params['tof']).to(u.s).value
        body_r = build_ephem_interpolant(body, test_params['period'], (j_date, j_date + test_params['tof']), rtol=1e-2)

        epoch = Time(j_date, format='jd', scale='tdb')
        initial = Orbit.from_classical(Earth, *test_params['orbit'], epoch=epoch)
        r, v = cowell(initial, np.linspace(0, tof, 400), rtol=1e-10, ad=third_body,
                      k_third=body.k.to(u.km**3 / u.s**2).value, third_body=body_r)

        incs, raans, argps = [], [], []
        for ri, vi in zip(r, v):
            angles = Angle(rv2coe(Earth.k.to(u.km**3 / u.s**2).value, ri, vi)[2:5] * u.rad)  # inc, raan, argp
            angles = angles.wrap_at(180 * u.deg)
            incs.append(angles[0].value)
            raans.append(angles[1].value)
            argps.append(angles[2].value)

        # averaging over 5 last values in the way Curtis does
        inc_f, raan_f, argp_f = np.mean(incs[-5:]), np.mean(raans[-5:]), np.mean(argps[-5:])

        assert_quantity_allclose([(raan_f * u.rad).to(u.deg) - test_params['orbit'][3],
                                  (inc_f * u.rad).to(u.deg) - test_params['orbit'][2],
                                  (argp_f * u.rad).to(u.deg) - test_params['orbit'][4]],
                                 [test_params['raan'], test_params['inc'], test_params['argp']],
                                 rtol=1e-1)
def test_solar_pressure():
    # based on example 12.9 from Howard Curtis
    with solar_system_ephemeris.set('builtin'):
        j_date = 2438400.5 * u.day
        tof = 600 * u.day
        sun_r = build_ephem_interpolant(Sun, 365 * u.day, (j_date, j_date + tof), rtol=1e-2)
        epoch = Time(j_date, format='jd', scale='tdb')
        drag_force_orbit = [10085.44 * u.km, 0.025422 * u.one, 88.3924 * u.deg,
                            45.38124 * u.deg, 227.493 * u.deg, 343.4268 * u.deg]

        initial = Orbit.from_classical(Earth, *drag_force_orbit, epoch=epoch)
        # in Curtis, the mean distance to Sun is used. In order to validate against it, we have to do the same thing
        sun_normalized = functools.partial(normalize_to_Curtis, sun_r=sun_r)

        r, v = cowell(initial, np.linspace(0, (tof).to(u.s).value, 4000), rtol=1e-8, ad=radiation_pressure,
                      R=Earth.R.to(u.km).value, C_R=2.0, A=2e-4, m=100, Wdivc_s=Sun.Wdivc.value, star=sun_normalized)

        delta_eccs, delta_incs, delta_raans, delta_argps = [], [], [], []
        for ri, vi in zip(r, v):
            orbit_params = rv2coe(Earth.k.to(u.km**3 / u.s**2).value, ri, vi)
            delta_eccs.append(orbit_params[1] - drag_force_orbit[1].value)
            delta_incs.append((orbit_params[2] * u.rad).to(u.deg).value - drag_force_orbit[2].value)
            delta_raans.append((orbit_params[3] * u.rad).to(u.deg).value - drag_force_orbit[3].value)
            delta_argps.append((orbit_params[4] * u.rad).to(u.deg).value - drag_force_orbit[4].value)

        # averaging over 5 last values in the way Curtis does
        for check in solar_pressure_checks:
            index = int(1.0 * check['t_days'] / tof.to(u.day).value * 4000)
            delta_ecc, delta_inc, delta_raan, delta_argp = np.mean(delta_eccs[index - 5:index]), \
                np.mean(delta_incs[index - 5:index]), np.mean(delta_raans[index - 5:index]), \
                np.mean(delta_argps[index - 5:index])
            assert_quantity_allclose([delta_ecc, delta_inc, delta_raan, delta_argp],
                                     check['deltas_expected'], rtol=1e-1, atol=1e-4)
def init_state_obj(seed=None):
    if not (seed == None):
        np.random.seed(seed)
    t_init = time.Time(datetime(2020, 3, 15, 0, 0, 0), scale='utc')
    a = (Earth.R.value + 200000) * u.m  # (Quantity) – Semi-major axis.
    ecc = np.random.uniform(
        0.001, 0.3) * u.dimensionless_unscaled  # (Quantity) – Eccentricity.
    inc = np.random.uniform(0, 180) * u.degree  # (Quantity) – Inclination
    raan = np.random.uniform(
        0,
        360) * u.degree  # (Quantity) – Right ascension of the ascending node.
    argp = np.random.uniform(
        0, 360) * u.degree  # (Quantity) – Argument of the pericenter.
    nu = np.random.uniform(0, 360) * u.degree  # (Quantity) – True anomaly.
    epoch = t_init  # (Time, optional) – Epoch, default to J2000.
    plane = Planes.EARTH_EQUATOR  # Fundamental plane of the frame.
    return Orbit.from_classical(Earth,
                                a,
                                ecc,
                                inc,
                                raan,
                                argp,
                                nu,
                                epoch=epoch,
                                plane=plane)
Beispiel #25
0
def test_perifocal_points_to_perigee():
    _d = 1.0 * u.AU  # Unused distance
    _ = 0.5 * u.one  # Unused dimensionless value
    _a = 1.0 * u.deg  # Unused angle
    ss = Orbit.from_classical(Sun, _d, _, _a, _a, _a, _a)
    p, _, _ = ss.pqw()
    assert_allclose(p, ss.e_vec / ss.ecc)
def _compute_results_array(a, ecc_0, ecc_f, inc_0, inc_f, argp, f):
    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()

    combined_ei_accel = guidance_law(s0, ecc_f, inc_f, f)

    # Propagate orbit
    with ProgressResultsCallback(t_f) as res:
        cowell(
            k, r0.to(u.km).value, v0.to(u.km / u.s).value, t_f,
            ad=combined_ei_accel,
            callback=res,
            nsteps=1000000
        )

    return res.get_results()  # ~70 k rows, 7 columns, 3 MB in memory
Beispiel #27
0
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.to(u.km**3 / u.s**2).value

    a_d, _, t_f = change_argp(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
    )

    # Propagate orbit
    sf = s0.propagate(t_f * u.s, method=cowell, ad=a_d, rtol=1e-8)

    assert_allclose(sf.argp.to(u.rad).value, argp_f, rtol=1e-4)
Beispiel #28
0
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)
Beispiel #29
0
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)
Beispiel #30
0
def validate_coe2rv():

    # Initial COE of the orbit
    a, ecc, inc, raan, argp, nu = 8788e3, 0.1712, 2.6738, 4.4558, 0.3502, 0.4965

    # Build Orekit orbit
    k = C.IAU_2015_NOMINAL_EARTH_GM
    epoch_00 = AbsoluteDate.J2000_EPOCH
    gcrf_frame = FramesFactory.getGCRF()
    ss0_orekit = KeplerianOrbit(a, ecc, inc, argp, raan, nu,
                                PositionAngle.TRUE, gcrf_frame, epoch_00, k)

    # Build poliastro orbit
    ss0_poliastro = Orbit.from_classical(
        Earth,
        a * u.m,
        ecc * u.one,
        inc * u.rad,
        raan * u.rad,
        argp * u.rad,
        nu * u.rad,
    )

    # Retrieve Orekit final state vectors
    r_orekit = ss0_orekit.getPVCoordinates().position.toArray() * u.m
    v_orekit = ss0_orekit.getPVCoordinates().velocity.toArray() * u.m / u.s

    # Retrieve poliastro final state vectors
    r_poliastro, v_poliastro = ss0_poliastro.rv()

    # Assert final state vector
    assert_quantity_allclose(r_poliastro, r_orekit)
    assert_quantity_allclose(v_poliastro, v_orekit)
    def setup(self):
        from poliastro.twobody import Orbit

        self.a_ini = 8970.667 * u.km
        self.ecc_ini = 0.25 * u.one
        self.raan_ini = 1.047 * u.rad
        self.nu_ini = 0.0 * u.rad
        self.argp_ini = 1.0 * u.rad
        self.inc_ini = 0.2618 * u.rad

        self.k = Earth.k.to(u.km**3 / u.s**2).value

        self.orbit = Orbit.from_classical(
            Earth,
            self.a_ini,
            self.ecc_ini,
            self.inc_ini,
            self.raan_ini,
            self.argp_ini,
            self.nu_ini,
        )
        self.tof = [1.0] * u.min
        self.a_J2J3 = lambda t0, u_, k_: J2_perturbation(
            t0, u_, k_, J2=Earth.J2.value, R=Earth.R.to(
                u.km).value) + J3_perturbation(
                    t0, u_, k_, J3=Earth.J3.value, R=Earth.R.to(u.km).value)
Beispiel #32
0
def test_geo_cases_beta_dnd_delta_v(ecc_0, inc_f, expected_beta,
                                    expected_delta_V):
    a = 42164  # km
    ecc_f = 0.0
    inc_0 = 0.0  # rad, baseline
    argp = 0.0  # rad, the method is efficient for 0 and 180
    f = 2.4e-7  # km / s2, unused

    inc_f = np.radians(inc_f)
    expected_beta = np.radians(expected_beta)

    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,
    )

    _, delta_V, beta, _ = change_inc_ecc(s0, ecc_f, inc_f, f)

    assert_allclose(delta_V, expected_delta_V, rtol=1e-2)
    assert_allclose(beta, expected_beta, rtol=1e-2)
Beispiel #33
0
def test_propagating_to_certain_nu_is_correct():
    # take an elliptic orbit
    a = 1.0 * u.AU
    ecc = 1.0 / 3.0 * u.one
    _a = 0.0 * u.rad
    nu = 10 * u.deg
    elliptic = Orbit.from_classical(Sun, a, ecc, _a, _a, _a, nu)

    elliptic_at_perihelion = elliptic.propagate_to_anomaly(0.0 * u.rad)
    r_per, _ = elliptic_at_perihelion.rv()

    elliptic_at_aphelion = elliptic.propagate_to_anomaly(np.pi * u.rad)
    r_ap, _ = elliptic_at_aphelion.rv()

    assert_quantity_allclose(norm(r_per), a * (1.0 - ecc))
    assert_quantity_allclose(norm(r_ap), a * (1.0 + ecc))

    # TODO: Test specific values
    assert elliptic_at_perihelion.epoch > elliptic.epoch
    assert elliptic_at_aphelion.epoch > elliptic.epoch

    # test 10 random true anomaly values
    for _ in range(10):
        nu = np.random.uniform(low=0.0, high=2 * np.pi)
        elliptic = elliptic.propagate_to_anomaly(nu * u.rad)
        r, _ = elliptic.rv()
        assert_quantity_allclose(norm(r), a * (1.0 - ecc ** 2) / (1 + ecc * np.cos(nu)))
Beispiel #34
0
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
Beispiel #35
0
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

    # 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,
    )
    a_d, _, _, t_f = change_inc_ecc(s0, ecc_f, inc_f, f)

    # Propagate orbit
    def f_geo(t0, u_, k):
        du_kep = func_twobody(t0, u_, k)
        ax, ay, az = a_d(t0, u_, k)
        du_ad = np.array([0, 0, 0, ax, ay, az])
        return du_kep + du_ad

    sf = s0.propagate(t_f * u.s, method=cowell, f=f_geo, rtol=1e-8)

    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)
Beispiel #36
0
def test_solar_pressure(t_days, deltas_expected, sun_r):
    # based on example 12.9 from Howard Curtis
    with solar_system_ephemeris.set("builtin"):
        j_date = 2_438_400.5 * u.day
        tof = 600 * u.day
        epoch = Time(j_date, format="jd", scale="tdb")

        initial = Orbit.from_classical(
            Earth,
            10085.44 * u.km,
            0.025422 * u.one,
            88.3924 * u.deg,
            45.38124 * u.deg,
            227.493 * u.deg,
            343.4268 * u.deg,
            epoch=epoch,
        )
        # in Curtis, the mean distance to Sun is used. In order to validate against it, we have to do the same thing
        sun_normalized = functools.partial(normalize_to_Curtis, sun_r=sun_r)

        rr, vv = cowell(
            Earth.k,
            initial.r,
            initial.v,
            np.linspace(0, (tof).to(u.s).value, 4000) * u.s,
            rtol=1e-8,
            ad=radiation_pressure,
            R=Earth.R.to(u.km).value,
            C_R=2.0,
            A_over_m=2e-4 / 100,
            Wdivc_s=Wdivc_sun.value,
            star=sun_normalized,
        )

        delta_eccs, delta_incs, delta_raans, delta_argps = [], [], [], []
        for ri, vi in zip(rr.to(u.km).value, vv.to(u.km / u.s).value):
            orbit_params = rv2coe(Earth.k.to(u.km**3 / u.s**2).value, ri, vi)
            delta_eccs.append(orbit_params[1] - initial.ecc.value)
            delta_incs.append((orbit_params[2] * u.rad).to(u.deg).value -
                              initial.inc.value)
            delta_raans.append((orbit_params[3] * u.rad).to(u.deg).value -
                               initial.raan.value)
            delta_argps.append((orbit_params[4] * u.rad).to(u.deg).value -
                               initial.argp.value)

        # averaging over 5 last values in the way Curtis does
        index = int(1.0 * t_days / tof.to(u.day).value * 4000  # type: ignore
                    )
        delta_ecc, delta_inc, delta_raan, delta_argp = (
            np.mean(delta_eccs[index - 5:index]),
            np.mean(delta_incs[index - 5:index]),
            np.mean(delta_raans[index - 5:index]),
            np.mean(delta_argps[index - 5:index]),
        )
        assert_quantity_allclose(
            [delta_ecc, delta_inc, delta_raan, delta_argp],
            deltas_expected,
            rtol=1e0,  # TODO: Excessively low, rewrite test?
            atol=1e-4,
        )
Beispiel #37
0
def test_propagating_to_certain_nu_is_correct():
    # Take an elliptic orbit
    a = 1.0 * u.AU
    ecc = 1.0 / 3.0 * u.one
    _a = 0.0 * u.rad
    nu = 10 * u.deg
    elliptic = Orbit.from_classical(attractor=Sun,
                                    a=a,
                                    ecc=ecc,
                                    inc=_a,
                                    raan=_a,
                                    argp=_a,
                                    nu=nu)

    elliptic_at_perihelion = elliptic.propagate_to_anomaly(0.0 * u.rad)
    r_per, _ = elliptic_at_perihelion.rv()

    elliptic_at_aphelion = elliptic.propagate_to_anomaly(np.pi * u.rad)
    r_ap, _ = elliptic_at_aphelion.rv()

    assert_quantity_allclose(norm(r_per), a * (1.0 - ecc))
    assert_quantity_allclose(norm(r_ap), a * (1.0 + ecc))

    # TODO: Test specific values
    assert elliptic_at_perihelion.epoch > elliptic.epoch
    assert elliptic_at_aphelion.epoch > elliptic.epoch

    # Test 10 random true anomaly values
    # TODO: Rework this test
    for nu in np.random.uniform(low=-np.pi, high=np.pi, size=10):
        elliptic = elliptic.propagate_to_anomaly(nu * u.rad)
        r, _ = elliptic.rv()
        assert_quantity_allclose(norm(r),
                                 a * (1.0 - ecc**2) / (1 + ecc * np.cos(nu)))
Beispiel #38
0
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_escape_velocity():

    # TEST CASE 1:
    # This is circular orbit, the escape velocity must be the same everywhere.
    # Escape velocity for position on the ground is 11.179km/s (source BMW2, page 30)
    o1 = Orbit.circular(Earth, 0*u.km)
    v,vp,va = interplanetary.escape_vel(o1, False)

    assert v == vp == va
    assert np.abs(v - 11179 * u.m/u.s) < 1 * u.m / u.s
    assert np.abs(vp - 11179 * u.m/u.s) < 1 * u.m / u.s
    assert np.abs(va - 11179 * u.m/u.s) < 1 * u.m / u.s

    # TEST CASE 2:
    # Escape velocity for position at the altitude of 7000km is 7719km/s (source BMW2, page 30)
    o2 = Orbit.circular(Earth, 7000*u.km)
    v,vp,va = interplanetary.escape_vel(o2, False)
    assert v == vp == va
    assert np.abs(v  - 7719 * u.m/u.s) < 1 * u.m / u.s
    assert np.abs(vp - 7719 * u.m/u.s) < 1 * u.m / u.s
    assert np.abs(va - 7719 * u.m/u.s) < 1 * u.m / u.s

    o3 = Orbit.from_classical(Earth, Earth.R + 16000 * u.km, 0.5*u.one, 0*u.deg, 0*u.deg, 0*u.deg, 0*u.deg)
    print_orb(o3)
    v,vp,va = interplanetary.escape_vel(o3, False)
    print(v, vp, va)
Beispiel #40
0
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)
Beispiel #41
0
def test_default_time_for_new_state():
    _d = 1.0 * u.AU  # Unused distance
    _ = 0.5 * u.one  # Unused dimensionless value
    _a = 1.0 * u.deg  # Unused angle
    _body = Sun  # Unused body
    expected_epoch = J2000
    ss = Orbit.from_classical(_body, _d, _, _a, _a, _a, _a)
    assert ss.epoch == expected_epoch
Beispiel #42
0
def test_sample_numpoints():
    _d = 1.0 * u.AU  # Unused distance
    _ = 0.5 * u.one  # Unused dimensionless value
    _a = 1.0 * u.deg  # Unused angle
    _body = Sun  # Unused body
    ss = Orbit.from_classical(_body, _d, _, _a, _a, _a, _a)
    positions = ss.sample(values=50)
    assert len(positions) == 50
Beispiel #43
0
def test_apply_maneuver_changes_epoch():
    _d = 1.0 * u.AU  # Unused distance
    _ = 0.5 * u.one  # Unused dimensionless value
    _a = 1.0 * u.deg  # Unused angle
    ss = Orbit.from_classical(Sun, _d, _, _a, _a, _a, _a)
    dt = 1 * u.h
    dv = [0, 0, 0] * u.km / u.s
    orbit_new = ss.apply_maneuver([(dt, dv)])
    assert orbit_new.epoch == ss.epoch + dt
Beispiel #44
0
def test_apply_zero_maneuver_returns_equal_state():
    _d = 1.0 * u.AU  # Unused distance
    _ = 0.5 * u.one  # Unused dimensionless value
    _a = 1.0 * u.deg  # Unused angle
    ss = Orbit.from_classical(Sun, _d, _, _a, _a, _a, _a)
    dt = 0 * u.s
    dv = [0, 0, 0] * u.km / u.s
    orbit_new = ss.apply_maneuver([(dt, dv)])
    assert_allclose(orbit_new.r.to(u.km).value, ss.r.to(u.km).value)
    assert_allclose(orbit_new.v.to(u.km / u.s).value, ss.v.to(u.km / u.s).value)
Beispiel #45
0
def test_sso_disposal_time_and_delta_v(ecc_0, ecc_f):
    a_0 = Earth.R.to(u.km).value + 900  # km
    f = 2.4e-7  # km / s2, assumed constant

    expected_t_f = 29.697  # days, reverse-engineered
    expected_delta_V = 0.6158  # km / s, lower than actual result
    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)
    _, delta_V, t_f = change_ecc_quasioptimal(s0, ecc_f, f)

    assert_allclose(delta_V, expected_delta_V, rtol=1e-4)
    assert_allclose(t_f / 86400, expected_t_f, rtol=1e-4)
Beispiel #46
0
def test_sample_with_nu_value():
    _d = 1.0 * u.AU  # Unused distance
    _ = 0.5 * u.one  # Unused dimensionless value
    _a = 1.0 * u.deg  # Unused angle
    _body = Sun  # Unused body
    ss = Orbit.from_classical(_body, _d, _, _a, _a, _a, _a)

    expected_r = [ss.r]
    positions = ss.sample(values=ss.nu + [360] * u.deg)
    r = positions.data.xyz.transpose()

    assert_quantity_allclose(r, expected_r, rtol=1.e-7)
def test_3rd_body_Curtis(test_params):
    # based on example 12.11 from Howard Curtis
    body = test_params["body"]
    with solar_system_ephemeris.set("builtin"):
        j_date = 2454283.0 * u.day
        tof = (test_params["tof"]).to(u.s).value
        body_r = build_ephem_interpolant(
            body,
            test_params["period"],
            (j_date, j_date + test_params["tof"]),
            rtol=1e-2,
        )

        epoch = Time(j_date, format="jd", scale="tdb")
        initial = Orbit.from_classical(Earth, *test_params["orbit"], epoch=epoch)
        rr, vv = cowell(
            Earth.k,
            initial.r,
            initial.v,
            np.linspace(0, tof, 400) * u.s,
            rtol=1e-10,
            ad=third_body,
            k_third=body.k.to(u.km ** 3 / u.s ** 2).value,
            third_body=body_r,
        )

        incs, raans, argps = [], [], []
        for ri, vi in zip(rr.to(u.km).value, vv.to(u.km / u.s).value):
            angles = Angle(
                rv2coe(Earth.k.to(u.km ** 3 / u.s ** 2).value, ri, vi)[2:5] * u.rad
            )  # inc, raan, argp
            angles = angles.wrap_at(180 * u.deg)
            incs.append(angles[0].value)
            raans.append(angles[1].value)
            argps.append(angles[2].value)

        # averaging over 5 last values in the way Curtis does
        inc_f, raan_f, argp_f = (
            np.mean(incs[-5:]),
            np.mean(raans[-5:]),
            np.mean(argps[-5:]),
        )

        assert_quantity_allclose(
            [
                (raan_f * u.rad).to(u.deg) - test_params["orbit"][3],
                (inc_f * u.rad).to(u.deg) - test_params["orbit"][2],
                (argp_f * u.rad).to(u.deg) - test_params["orbit"][4],
            ],
            [test_params["raan"], test_params["inc"], test_params["argp"]],
            rtol=1e-1,
        )
Beispiel #48
0
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

    # 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)
    a_d, _, t_f = change_ecc_quasioptimal(s0, ecc_f, f)

    # Propagate orbit
    sf = s0.propagate(t_f * u.s, method=cowell, ad=a_d, rtol=1e-8)

    assert_allclose(sf.ecc.value, ecc_f, rtol=1e-4, atol=1e-4)
Beispiel #49
0
def test_propagation_hyperbolic_zero_time_returns_same_state():
    ss0 = Orbit.from_classical(
        Earth,
        -27112.5464 * u.km,
        1.25 * u.one,
        0 * u.deg,
        0 * u.deg,
        0 * u.deg,
        0 * u.deg,
    )
    r0, v0 = ss0.rv()
    tof = 0 * u.s

    ss1 = ss0.propagate(tof)

    r, v = ss1.rv()

    assert_allclose(r.value, r0.value)
    assert_allclose(v.value, v0.value)
Beispiel #50
0
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

    # 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
    )
    a_d, _, _, t_f = change_inc_ecc(s0, ecc_f, inc_f, f)

    # Propagate orbit
    sf = s0.propagate(t_f * u.s, method=cowell, ad=a_d, rtol=1e-8)

    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)
Beispiel #51
0
def test_geo_cases_beta_dnd_delta_v(ecc_0, inc_f, expected_beta, expected_delta_V):
    a = 42164  # km
    ecc_f = 0.0
    inc_0 = 0.0  # rad, baseline
    argp = 0.0  # rad, the method is efficient for 0 and 180
    f = 2.4e-7  # km / s2, unused

    inc_f = np.radians(inc_f)
    expected_beta = np.radians(expected_beta)

    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
    )

    _, delta_V, beta, _ = change_inc_ecc(s0, ecc_f, inc_f, f)

    assert_allclose(delta_V, expected_delta_V, rtol=1e-2)
    assert_allclose(beta, expected_beta, rtol=1e-2)
def test_J3_propagation_Earth(test_params):
    # Nai-ming Qi, Qilong Sun, Yong Yang, (2018) "Effect of J3 perturbation on satellite position in LEO",
    # Aircraft Engineering and  Aerospace Technology, Vol. 90 Issue: 1,
    # pp.74-86, https://doi.org/10.1108/AEAT-03-2015-0092
    a_ini = 8970.667 * u.km
    ecc_ini = 0.25 * u.one
    raan_ini = 1.047 * u.rad
    nu_ini = 0.0 * u.rad
    argp_ini = 1.0 * u.rad
    inc_ini = test_params['inc']

    k = Earth.k.to(u.km**3 / u.s**2).value

    orbit = Orbit.from_classical(Earth, a_ini, ecc_ini, inc_ini, raan_ini, argp_ini, nu_ini)

    tof = (10.0 * u.day).to(u.s).value
    r_J2, v_J2 = cowell(orbit, np.linspace(0, tof, int(1e+3)), ad=J2_perturbation,
                        J2=Earth.J2.value, R=Earth.R.to(u.km).value, rtol=1e-8)
    a_J2J3 = lambda t0, u_, k_: J2_perturbation(t0, u_, k_, J2=Earth.J2.value, R=Earth.R.to(u.km).value) + \
        J3_perturbation(t0, u_, k_, J3=Earth.J3.value, R=Earth.R.to(u.km).value)

    r_J3, v_J3 = cowell(orbit, np.linspace(0, tof, int(1e+3)), ad=a_J2J3, rtol=1e-8)

    a_values_J2 = np.array([rv2coe(k, ri, vi)[0] / (1.0 - rv2coe(k, ri, vi)[1] ** 2) for ri, vi in zip(r_J2, v_J2)])
    a_values_J3 = np.array([rv2coe(k, ri, vi)[0] / (1.0 - rv2coe(k, ri, vi)[1] ** 2) for ri, vi in zip(r_J3, v_J3)])
    da_max = np.max(np.abs(a_values_J2 - a_values_J3))

    ecc_values_J2 = np.array([rv2coe(k, ri, vi)[1] for ri, vi in zip(r_J2, v_J2)])
    ecc_values_J3 = np.array([rv2coe(k, ri, vi)[1] for ri, vi in zip(r_J3, v_J3)])
    decc_max = np.max(np.abs(ecc_values_J2 - ecc_values_J3))

    inc_values_J2 = np.array([rv2coe(k, ri, vi)[2] for ri, vi in zip(r_J2, v_J2)])
    inc_values_J3 = np.array([rv2coe(k, ri, vi)[2] for ri, vi in zip(r_J3, v_J3)])
    dinc_max = np.max(np.abs(inc_values_J2 - inc_values_J3))

    assert_quantity_allclose(dinc_max, test_params['dinc_max'], rtol=1e-1, atol=1e-7)
    assert_quantity_allclose(decc_max, test_params['decc_max'], rtol=1e-1, atol=1e-7)
    try:
        assert_quantity_allclose(da_max * u.km, test_params['da_max'])
    except AssertionError as exc:
        pytest.xfail('this assertion disagrees with the paper')
Beispiel #53
0
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)
Beispiel #54
0
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)
Beispiel #55
0
"""Example data.

"""
from astropy import time
from astropy import units as u

from poliastro.bodies import Sun, Earth
from poliastro.twobody import Orbit


# Taken from Plyades (c) 2012 Helge Eichhorn (MIT License)
iss = Orbit.from_vectors(
    Earth,
    [8.59072560e2, -4.13720368e3, 5.29556871e3] * u.km,
    [7.37289205, 2.08223573, 4.39999794e-1] * u.km / u.s,
    time.Time("2013-03-18 12:00", scale='utc')
)

molniya = Orbit.from_classical(
    Earth,
    26600 * u.km, 0.75 * u.one, 63.4 * u.deg,
    0 * u.deg, 270 * u.deg, 80 * u.deg
)

churi = Orbit.from_classical(
    Sun,
    3.46250 * u.AU, 0.64 * u.one, 7.04 * u.deg,
    50.1350 * u.deg, 12.8007 * u.deg, 63.89 * u.deg,
    time.Time("2015-11-05 12:00", scale='utc')
)
Beispiel #56
0
from poliastro.twobody import Orbit

iss = Orbit.from_vectors(
    Earth,
    [8.59072560e2, -4.13720368e3, 5.29556871e3] * u.km,
    [7.37289205, 2.08223573, 4.39999794e-1] * u.km / u.s,
    time.Time("2013-03-18 12:00", scale="utc"),
)
"""ISS orbit example

Taken from Plyades (c) 2012 Helge Eichhorn (MIT License)

"""

molniya = Orbit.from_classical(
    Earth, 26600 * u.km, 0.75 * u.one, 63.4 * u.deg, 0 * u.deg, 270 * u.deg, 80 * u.deg
)
"""Molniya orbit example"""

_r_a = Earth.R + 35950 * u.km
_r_p = Earth.R + 250 * u.km
_a = (_r_a + _r_p) / 2
soyuz_gto = Orbit.from_classical(
    Earth, _a, _r_a / _a - 1, 6 * u.deg, 188.5 * u.deg, 178 * u.deg, 0 * u.deg
)
"""Soyuz geostationary transfer orbit (GTO) example

Taken from Soyuz User's Manual, issue 2 revision 0

"""