コード例 #1
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)
コード例 #2
0
def test_long_propagation_preserves_orbit_elements(method):
    tof = 100 * u.year
    r_halleys = np.array([-9018878.63569932, -94116054.79839276, 22619058.69943215])  # km
    v_halleys = np.array([-49.95092305, -12.94843055, -4.29251577])  # km/s
    halleys = Orbit.from_vectors(Sun, r_halleys * u.km, v_halleys * u.km / u.s)

    params_ini = rv2coe(Sun.k.to(u.km**3 / u.s**2).value, r_halleys, v_halleys)[:-1]
    r_new, v_new = halleys.propagate(tof, method=method).rv()
    params_final = rv2coe(Sun.k.to(u.km**3 / u.s**2).value,
                          r_new.to(u.km).value, v_new.to(u.km / u.s).value)[:-1]
    print(params_ini, params_final)
    assert_quantity_allclose(params_ini, params_final)
コード例 #3
0
ファイル: orbit.py プロジェクト: sumedhe/poliastro
    def propagate(self, value, method=mean_motion, rtol=1e-10):
        """ if value is true anomaly, propagate orbit to this anomaly and return the result
            if time is provided, propagate this `Orbit` some `time` and return the result.

        Parameters
        ----------
        value : Multiple options
            True anomaly values,
            Time values.
        rtol : float, optional
            Relative tolerance for the propagation algorithm, default to 1e-10.

        """
        if hasattr(value, "unit") and value.unit in ('rad', 'deg'):
            p, ecc, inc, raan, argp, _ = rv.rv2coe(self.attractor.k.to(u.km ** 3 / u.s ** 2).value,
                                                   self.r.to(u.km).value,
                                                   self.v.to(u.km / u.s).value)

            return self.from_classical(self.attractor, p / (1.0 - ecc ** 2) * u.km,
                                       ecc * u.one, inc * u.rad, raan * u.rad,
                                       argp * u.rad, value)
        else:
            if isinstance(value, time.Time) and not isinstance(value, time.TimeDelta):
                time_of_flight = value - self.epoch
            else:
                time_of_flight = time.TimeDelta(value)

            return propagate(self, time_of_flight, method=method, rtol=rtol)
コード例 #4
0
ファイル: coordinates.py プロジェクト: y1ngyang/poliastro
def inertial_body_centered_to_pqw(r, v, source_body):
    """Converts position and velocity from inertial body-centered frame to perifocal frame.

    Parameters
    ----------
    r : ~astropy.units.Quantity
        Position vector in a inertial body-centered reference frame.
    v : ~astropy.units.Quantity
        Velocity vector in a inertial body-centered reference frame.
    source_body : Body
        Source body.

    Returns
    -------
    r_pqw, v_pqw : tuple (~astropy.units.Quantity)
        Position and velocity vectors in ICRS.


    """
    r = r.to('km').value
    v = v.to('km/s').value
    k = source_body.k.to('km^3 / s^2').value

    p, ecc, inc, _, _, nu = rv2coe(k, r, v)

    r_pqw = (np.array([cos(nu), sin(nu), 0 * nu]) * p /
             (1 + ecc * cos(nu))).T * u.km
    v_pqw = (np.array([-sin(nu),
                       (ecc + cos(nu)), 0]) * sqrt(k / p)).T * u.km / u.s

    return r_pqw, v_pqw
コード例 #5
0
def test_solar_pressure():
    # based on example 12.9 from Howard Curtis
    solar_system_ephemeris.set('de432s')

    j_date = 2438400.5
    tof = 600
    sun_r = build_ephem_interpolant(Sun, 365, (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 * u.day).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(check['t_days'] / tof * 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)
コード例 #6
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
    tof = (test_params['tof'] * u.day).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)
コード例 #7
0
ファイル: propagation.py プロジェクト: y1ngyang/poliastro
def mean_motion(k, r0, v0, tof, **kwargs):
    r"""Propagates orbit using mean motion

    Parameters
    ----------
    k : float
        Gravitational constant of main attractor (km^3 / s^2).
    r0 : array
        Initial position (km).
    v0 : array
        Initial velocity (km).
    ad : function(t0, u, k), optional
         Non Keplerian acceleration (km/s2), default to None.
    tof : float
        Time of flight (s).

    Notes
    -----
    This method takes initial :math:`\vec{r}, \vec{v}`, calculates classical orbit parameters,
    increases mean anomaly and performs inverse transformation to get final :math:`\vec{r}, \vec{v}`
    The logic is based on formulae (4), (6) and (7) from http://dx.doi.org/10.1007/s10569-013-9476-9

    """

    # get the initial true anomaly and orbit parameters that are constant over time
    p, ecc, inc, raan, argp, nu0 = rv2coe(k, r0, v0)

    # get the initial mean anomaly
    M0 = nu_to_M(nu0, ecc)
    # elliptic or hyperbolic orbits
    if not np.isclose(ecc, 1.0, rtol=1e-06):
        a = p / (1.0 - ecc**2)
        # given the initial mean anomaly, calculate mean anomaly
        # at the end, mean motion (n) equals sqrt(mu / |a^3|)
        with u.set_enabled_equivalencies(u.dimensionless_angles()):
            M = M0 + tof * np.sqrt(k / np.abs(a**3)) * u.rad
            nu = M_to_nu(M, ecc)

    # parabolic orbit
    else:
        q = p / 2.0
        # mean motion n = sqrt(mu / 2 q^3) for parabolic orbit
        with u.set_enabled_equivalencies(u.dimensionless_angles()):
            M = M0 + tof * np.sqrt(k / (2.0 * q**3))

        # using Barker's equation, which is solved analytically
        # for parabolic orbit, get true anomaly
        B = 3.0 * M / 2.0
        A = (B + np.sqrt(1.0 + B**2))**(2.0 / 3.0)
        D = 2.0 * A * B / (1.0 + A + A**2)

        nu = 2.0 * np.arctan(D)
    with u.set_enabled_equivalencies(u.dimensionless_angles()):
        return coe2rv(k, p, ecc, inc, raan, argp, nu)
コード例 #8
0
def mean_motion(orbit, tof, **kwargs):
    r"""Propagates orbit using mean motion

    .. versionadded:: 0.9.0

    Parameters
    ----------
    orbit : ~poliastro.twobody.orbit.Orbit
        the Orbit object to propagate.
    tof : float
        Time of flight (s).

    Notes
    -----
    This method takes initial :math:`\vec{r}, \vec{v}`, calculates classical orbit parameters,
    increases mean anomaly and performs inverse transformation to get final :math:`\vec{r}, \vec{v}`
    The logic is based on formulae (4), (6) and (7) from http://dx.doi.org/10.1007/s10569-013-9476-9

    """

    k = orbit.attractor.k.to(u.km**3 / u.s**2).value
    r0 = orbit.r.to(u.km).value
    v0 = orbit.v.to(u.km / u.s).value

    # get the initial true anomaly and orbit parameters that are constant over time
    p, ecc, inc, raan, argp, nu0 = rv2coe(k, r0, v0)

    # get the initial mean anomaly
    M0 = nu_to_M(nu0, ecc)
    # elliptic or hyperbolic orbits
    if not np.isclose(ecc, 1.0, rtol=1e-06):
        a = p / (1.0 - ecc**2)
        # given the initial mean anomaly, calculate mean anomaly
        # at the end, mean motion (n) equals sqrt(mu / |a^3|)
        with u.set_enabled_equivalencies(u.dimensionless_angles()):
            M = M0 + tof * np.sqrt(k / np.abs(a**3)) * u.rad
            nu = M_to_nu(M, ecc)

    # parabolic orbit
    else:
        q = p / 2.0
        # mean motion n = sqrt(mu / 2 q^3) for parabolic orbit
        with u.set_enabled_equivalencies(u.dimensionless_angles()):
            M = M0 + tof * np.sqrt(k / (2.0 * q**3))

        # using Barker's equation, which is solved analytically
        # for parabolic orbit, get true anomaly
        B = 3.0 * M / 2.0
        A = (B + np.sqrt(1.0 + B**2))**(2.0 / 3.0)
        D = 2.0 * A * B / (1.0 + A + A**2)

        nu = 2.0 * np.arctan(D)
    with u.set_enabled_equivalencies(u.dimensionless_angles()):
        return coe2rv(k, p, ecc, inc, raan, argp, nu)
コード例 #9
0
def test_convert_between_coe_and_rv_is_transitive():
    k = Earth.k.to(u.km**3 / u.s**2).value  # u.km**3 / u.s**2
    p = 11067.790  # u.km
    ecc = 0.83285  # u.one
    inc = np.deg2rad(87.87)  # u.rad
    raan = np.deg2rad(227.89)  # u.rad
    argp = np.deg2rad(53.38)  # u.rad
    nu = np.deg2rad(92.335)  # u.rad

    expected_res = (p, ecc, inc, raan, argp, nu)

    res = rv2coe(k, *coe2rv(k, *expected_res))

    assert_allclose(res, expected_res)
コード例 #10
0
ファイル: test_twobody.py プロジェクト: yothinix/poliastro
def test_convert_between_coe_and_rv_is_transitive():
    k = Earth.k.to(u.km**3 / u.s**2).value  # u.km**3 / u.s**2
    p = 11067.790  # u.km
    ecc = 0.83285  # u.one
    inc = np.deg2rad(87.87)  # u.rad
    raan = np.deg2rad(227.89)  # u.rad
    argp = np.deg2rad(53.38)  # u.rad
    nu = np.deg2rad(92.335)  # u.rad

    expected_res = (p, ecc, inc, raan, argp, nu)

    res = rv2coe(k, *coe2rv(k, *expected_res))

    assert_array_almost_equal(res, expected_res)
コード例 #11
0
def test_propagation_mean_motion_parabolic():
    # example from Howard Curtis (3rd edition), section 3.5, problem 3.15
    p = 2.0 * 6600 * u.km
    _a = 0.0 * u.deg
    orbit = Orbit.parabolic(Earth, p, _a, _a, _a, _a)
    orbit = orbit.propagate(0.8897 / 2.0 * u.h, method=mean_motion)

    _, _, _, _, _, nu0 = rv2coe(Earth.k.to(u.km**3 / u.s**2).value,
                                orbit.r.to(u.km).value,
                                orbit.v.to(u.km / u.s).value)
    assert_quantity_allclose(nu0, np.deg2rad(90.0), rtol=1e-4)

    orbit = Orbit.parabolic(Earth, p, _a, _a, _a, _a)
    orbit = orbit.propagate(36.0 * u.h, method=mean_motion)
    assert_quantity_allclose(norm(orbit.r.to(u.km).value), 304700.0, rtol=1e-4)
コード例 #12
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')