Exemplo n.º 1
0
def test_LOS_event_raises_warning_if_norm_of_r1_less_than_attractor_radius_during_propagation(
):
    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.

    r1 = (np.array([0, -5010.696, -5102.509]) << u.km
          )  # This position vectors' norm gets less than attractor radius.
    v1 = np.array([736.138, 29899.7, 164.354]) << u.km / u.s
    orb = Orbit.from_vectors(Earth, r1, v1)

    los_event = LosEvent(Earth, pos_coords, terminal=True)
    events = [los_event]
    tofs = [0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.5] << u.s

    with pytest.warns(UserWarning, match="The norm of the position vector"):
        r, v = cowell(
            Earth.k,
            orb.r,
            orb.v,
            tofs,
            events=events,
        )
Exemplo n.º 2
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)
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
Exemplo n.º 4
0
def test_atmospheric_demise():
    # Test an orbital decay that hits Earth. No analytic solution.
    R = Earth.R.to(u.km).value

    orbit = Orbit.circular(Earth, 230 * u.km)
    t_decay = 48.2179 * u.d  # not an analytic value

    # parameters of a body
    C_D = 2.2  # dimentionless (any value would do)
    A_over_m = ((np.pi / 4.0) * (u.m**2) / (100 * u.kg)).to_value(
        u.km**2 / u.kg)  # km^2/kg

    # parameters of the atmosphere
    rho0 = rho0_earth.to(u.kg / u.km**3).value  # kg/km^3
    H0 = H0_earth.to(u.km).value  # km

    tofs = [365] * u.d  # actually hits the ground a bit after day 48

    lithobrake_event = LithobrakeEvent(R)
    events = [lithobrake_event]

    rr, _ = cowell(
        Earth.k,
        orbit.r,
        orbit.v,
        tofs,
        ad=atmospheric_drag_exponential,
        R=R,
        C_D=C_D,
        A_over_m=A_over_m,
        H0=H0,
        rho0=rho0,
        events=events,
    )

    assert_quantity_allclose(norm(rr[0].to(u.km).value), R,
                             atol=1)  # below 1km

    assert_quantity_allclose(lithobrake_event.last_t, t_decay, rtol=1e-2)

    # make sure having the event not firing is ok
    tofs = [1] * u.d
    lithobrake_event = LithobrakeEvent(R)
    events = [lithobrake_event]

    rr, _ = cowell(
        Earth.k,
        orbit.r,
        orbit.v,
        tofs,
        ad=atmospheric_drag_exponential,
        R=R,
        C_D=C_D,
        A_over_m=A_over_m,
        H0=H0,
        rho0=rho0,
        events=events,
    )

    assert lithobrake_event.last_t == tofs[-1]
 def time_J3_propagation(self):
     cowell(
         self.orbit.attractor.k,
         self.orbit.r,
         self.orbit.v,
         self.tof,
         ad=self.a_J2J3,
         rtol=1e-8,
     )
 def time_J2_propagation(self):
     cowell(
         self.orbit.attractor.k,
         self.orbit.r,
         self.orbit.v,
         self.tof,
         ad=J2_perturbation,
         J2=Earth.J2.value,
         R=Earth.R.to(u.km).value,
     )
 def time_atmospheric_drag_exponential(self):
     cowell(
         self.orbit.attractor.k,
         self.orbit.r,
         self.orbit.v,
         self.tof,
         ad=atmospheric_drag_exponential,
         R=self.R,
         C_D=self.C_D,
         A_over_m=self.A_over_m,
         H0=self.H0,
         rho0=self.rho0,
     )
Exemplo n.º 8
0
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)
Exemplo n.º 9
0
    def _propagate_curOrb(self, curOrb):
        # propagate to get an ECI vector at each timestep
        # by default, this produces a list of numpy arrays where the
        if self.prop_method == 'cowell':
            (r_list, v_list) = propagation.cowell(curOrb,
                                                  self.timesteps_arr,
                                                  ad=J23_perturbation,
                                                  J2=Earth.J2.value,
                                                  J3=Earth.J3.value)
        elif self.prop_method == 'kepler':
            r_list = [curOrb.state.r.value]
            v_list = [curOrb.state.v.value]
            for _ in range(1, len(self.timesteps_arr)):

                # propagate assumes input is angular, unless explicity a time object
                curOrb = curOrb.propagate(
                    TimeDelta(self.timestep_s, format='sec'))
                r_list.append(curOrb.state.r.value)
                v_list.append(curOrb.state.v.value)
                # reset back to base epoch
                curOrb = Orbit.from_vectors(Earth, curOrb.state.r.value * u.km,
                                            curOrb.state.v.value * u.km / u.s)
        else:
            raise NotImplementedError(
                'Only cowell and singleStep implemented for poliAstro propagation'
            )

        return (r_list, v_list)
Exemplo n.º 10
0
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)
Exemplo n.º 11
0
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)
Exemplo n.º 12
0
def test_atmospheric_drag():
    # http://farside.ph.utexas.edu/teaching/celestial/Celestialhtml/node94.html#sair (10.148)
    # given the expression for \dot{r} / r, aproximate \Delta r \approx F_r * \Delta t

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

    # parameters of a circular orbit with h = 250 km (any value would do, but not too small)
    orbit = Orbit.circular(Earth, 250 * u.km)
    r0, _ = orbit.rv()
    r0 = r0.to(u.km).value

    # parameters of a body
    C_D = 2.2  # dimentionless (any value would do)
    A = ((np.pi / 4.0) * (u.m**2)).to(u.km**2).value  # km^2
    m = 100  # kg
    B = C_D * A / m

    # parameters of the atmosphere
    rho0 = Earth.rho0.to(u.kg / u.km**3).value  # kg/km^3
    H0 = Earth.H0.to(u.km).value
    tof = 100000  # s

    dr_expected = -B * rho0 * np.exp(-(norm(r0) - R) / H0) * np.sqrt(k * norm(r0)) * tof
    # assuming the atmospheric decay during tof is small,
    # dr_expected = F_r * tof (Newton's integration formula), where
    # F_r = -B rho(r) |r|^2 sqrt(k / |r|^3) = -B rho(r) sqrt(k |r|)

    r, v = cowell(orbit, tof, ad=atmospheric_drag, R=R, C_D=C_D, A=A, m=m, H0=H0, rho0=rho0)

    assert_quantity_allclose(norm(r) - norm(r0), dr_expected, rtol=1e-2)
Exemplo n.º 13
0
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)
Exemplo n.º 14
0
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)
Exemplo n.º 15
0
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)
Exemplo n.º 16
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)
Exemplo n.º 17
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)
Exemplo n.º 18
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)
Exemplo n.º 19
0
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(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)
Exemplo n.º 20
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)
Exemplo n.º 21
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,
        )
Exemplo n.º 22
0
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

    def f(t0, u_, k):
        du_kep = func_twobody(t0, u_, k)
        ax, ay, az = constant_accel(t0, u_, k)
        du_ad = np.array([0, 0, 0, ax, ay, az])

        return du_kep + du_ad

    ss = Orbit.circular(Earth, 500 * u.km)
    tofs = [20] * ss.period

    r, v = cowell(Earth.k, ss.r, ss.v, tofs, f=f)

    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)
Exemplo n.º 23
0
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)
Exemplo n.º 24
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)
Exemplo n.º 25
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)
Exemplo n.º 26
0
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)
Exemplo n.º 27
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)
Exemplo n.º 28
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)
Exemplo n.º 29
0
def test_atmospheric_drag():
    # http://farside.ph.utexas.edu/teaching/celestial/Celestialhtml/node94.html#sair (10.148)
    # given the expression for \dot{r} / r, aproximate \Delta r \approx F_r * \Delta t

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

    # parameters of a circular orbit with h = 250 km (any value would do, but not too small)
    orbit = Orbit.circular(Earth, 250 * u.km)
    r0, _ = orbit.rv()
    r0 = r0.to(u.km).value

    # parameters of a body
    C_D = 2.2  # dimentionless (any value would do)
    A = ((np.pi / 4.0) * (u.m**2)).to(u.km**2).value  # km^2
    m = 100  # kg
    B = C_D * A / m

    # parameters of the atmosphere
    rho0 = Earth.rho0.to(u.kg / u.km**3).value  # kg/km^3
    H0 = Earth.H0.to(u.km).value
    tof = 100000  # s

    dr_expected = -B * rho0 * np.exp(-(norm(r0) - R) / H0) * np.sqrt(k * norm(r0)) * tof
    # assuming the atmospheric decay during tof is small,
    # dr_expected = F_r * tof (Newton's integration formula), where
    # F_r = -B rho(r) |r|^2 sqrt(k / |r|^3) = -B rho(r) sqrt(k |r|)

    r, v = cowell(orbit, tof, ad=atmospheric_drag, R=R, C_D=C_D, A=A, m=m, H0=H0, rho0=rho0)

    assert_quantity_allclose(norm(r) - norm(r0), dr_expected, rtol=1e-2)
Exemplo n.º 30
0
 def _sample(self, time_values, method=mean_motion):
     # if use cowell, propagate to max_time and use other values as intermediate (dense output)
     if method == cowell:
         values, _ = cowell(self, (time_values - self.epoch).to(u.s).value)
         values = values * u.km
     else:
         values = np.zeros((len(time_values), 3)) * self.r.unit
         for ii, epoch in enumerate(time_values):
             rr = self.propagate(epoch, method).r
             values[ii] = rr
     return CartesianRepresentation(values, xyz_axis=1)
Exemplo n.º 31
0
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,
            perturbation_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,
        )
Exemplo n.º 32
0
def test_atmospheric_drag_exponential():
    # http://farside.ph.utexas.edu/teaching/celestial/Celestialhtml/node94.html#sair (10.148)
    # Given the expression for \dot{r} / r, aproximate \Delta r \approx F_r * \Delta t

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

    # Parameters of a circular orbit with h = 250 km (any value would do, but not too small)
    orbit = Orbit.circular(Earth, 250 * u.km)
    r0, _ = orbit.rv()
    r0 = r0.to(u.km).value

    # Parameters of a body
    C_D = 2.2  # dimentionless (any value would do)
    A_over_m = ((np.pi / 4.0) * (u.m**2) / (100 * u.kg)).to_value(
        u.km**2 / u.kg)  # km^2/kg
    B = C_D * A_over_m

    # Parameters of the atmosphere
    rho0 = rho0_earth.to(u.kg / u.km**3).value  # kg/km^3
    H0 = H0_earth.to(u.km).value  # km
    tof = 100000  # s

    dr_expected = -B * rho0 * np.exp(-(norm(r0) - R) / H0) * np.sqrt(
        k * norm(r0)) * tof

    # Assuming the atmospheric decay during tof is small,
    # dr_expected = F_r * tof (Newton's integration formula), where
    # F_r = -B rho(r) |r|^2 sqrt(k / |r|^3) = -B rho(r) sqrt(k |r|)

    def f(t0, u_, k):
        du_kep = func_twobody(t0, u_, k)
        ax, ay, az = atmospheric_drag_exponential(t0,
                                                  u_,
                                                  k,
                                                  R=R,
                                                  C_D=C_D,
                                                  A_over_m=A_over_m,
                                                  H0=H0,
                                                  rho0=rho0)
        du_ad = np.array([0, 0, 0, ax, ay, az])
        return du_kep + du_ad

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

    assert_quantity_allclose(norm(rr[0].to(u.km).value) - norm(r0),
                             dr_expected,
                             rtol=1e-2)
Exemplo n.º 33
0
def _compute_results_array(a_0, a_f, inc_0, i_f, f):
    k = Earth.k.decompose([u.km, u.s]).value

    edelbaum_accel = guidance_law(k, a_0, a_f, inc_0, i_f, f)
    _, t_f = extra_quantities(k, a_0, a_f, inc_0, i_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
    with ProgressResultsCallback(t_f) as res:
        cowell(
            k, r0.to(u.km).value, v0.to(u.km / u.s).value, t_f,
            ad=edelbaum_accel,
            callback=res,
            nsteps=1000000
        )

    return res.get_results()  # ~70 k rows, 7 columns, 3 MB in memory
Exemplo n.º 34
0
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')
Exemplo n.º 35
0
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')
Exemplo n.º 36
0
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,
        )
Exemplo n.º 37
0
def test_atmospheric_demise_coesa76():
    # Test an orbital decay that hits Earth. No analytic solution.
    R = Earth.R.to(u.km).value

    orbit = Orbit.circular(Earth, 250 * u.km)
    t_decay = 7.17 * u.d

    # Parameters of a body
    C_D = 2.2  # Dimensionless (any value would do)
    A_over_m = ((np.pi / 4.0) * (u.m**2) / (100 * u.kg)).to_value(
        u.km**2 / u.kg)  # km^2/kg

    tofs = [365] * u.d

    lithobrake_event = LithobrakeEvent(R)
    events = [lithobrake_event]

    coesa76 = COESA76()

    def f(t0, u_, k):
        du_kep = func_twobody(t0, u_, k)

        # Avoid undershooting H below attractor radius R
        H = max(norm(u_[:3]), R)
        rho = coesa76.density((H - R) * u.km).to_value(u.kg / u.km**3)

        ax, ay, az = atmospheric_drag(
            t0,
            u_,
            k,
            C_D=C_D,
            A_over_m=A_over_m,
            rho=rho,
        )
        du_ad = np.array([0, 0, 0, ax, ay, az])
        return du_kep + du_ad

    rr, _ = cowell(
        Earth.k,
        orbit.r,
        orbit.v,
        tofs,
        events=events,
        f=f,
    )

    assert_quantity_allclose(norm(rr[0].to(u.km).value), R,
                             atol=1)  # Below 1km

    assert_quantity_allclose(lithobrake_event.last_t, t_decay, rtol=1e-2)
Exemplo n.º 38
0
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
Exemplo n.º 39
0
def test_cowell_propagation_with_zero_acceleration_equals_kepler():
    # Data from Vallado, example 2.4
    k = Earth.k.to(u.km**3 / u.s**2).value

    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

    expected_r = np.array([-4219.7527, 4363.0292, -3958.7666])
    expected_v = np.array([3.689866, -1.916735, -6.112511])

    r, v = cowell(k, r0, v0, tof, ad=None)

    assert_array_almost_equal(r, expected_r, decimal=1)
    assert_array_almost_equal(v, expected_v, decimal=4)
Exemplo n.º 40
0
def test_LOS_event_with_lithobrake_event_raises_warning_when_satellite_cuts_attractor(
):
    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.

    r1 = np.array([0, -5010.696, -5102.509]) << u.km
    v1 = np.array([736.138, 2989.7, 164.354]) << u.km / u.s
    orb = Orbit.from_vectors(Earth, r1, v1)

    los_event = LosEvent(Earth, pos_coords, terminal=True)
    tofs = [
        0.003, 0.004, 0.01, 0.02, 0.03, 0.04, 0.07, 0.1, 0.2, 0.3, 0.4, 1, 3
    ] << u.s

    lithobrake_event = LithobrakeEvent(Earth.R.to_value(u.km))
    events = [lithobrake_event, los_event]
    r, v = cowell(
        Earth.k,
        orb.r,
        orb.v,
        tofs,
        events=events,
    )

    assert lithobrake_event.last_t < los_event.last_t
Exemplo n.º 41
0
def test_cowell_propagation_with_zero_acceleration_equals_kepler():
    # Data from Vallado, example 2.4
    k = Earth.k.to(u.km**3 / u.s**2).value

    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

    expected_r = np.array([-4219.7527, 4363.0292, -3958.7666])
    expected_v = np.array([3.689866, -1.916735, -6.112511])

    r, v = cowell(k, r0, v0, tof, ad=None)

    assert_allclose(r, expected_r, rtol=1e-5)
    assert_allclose(v, expected_v, rtol=1e-4)
Exemplo n.º 42
0
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)
Exemplo n.º 43
0
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)
Exemplo n.º 44
0
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)
Exemplo n.º 45
0
def test_cowell_propagation_callback():
    # Data from Vallado, example 2.4
    k = Earth.k.to(u.km**3 / u.s**2).value

    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

    results = []

    def cb(t, u_):
        row = [t]
        row.extend(u_)
        results.append(row)

    r, v = cowell(k, r0, v0, tof, callback=cb)

    assert len(results) == 17
    assert len(results[0]) == 7
    assert results[-1][0] == tof
Exemplo n.º 46
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)
Exemplo n.º 47
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)