def parabolic(cls, attractor, p, inc, raan, argp, nu, epoch=J2000): """Return parabolic `Orbit`. Parameters ---------- attractor : Body Main attractor. p : ~astropy.units.Quantity Semilatus rectum or parameter. inc : ~astropy.units.Quantity, optional Inclination. raan : ~astropy.units.Quantity Right ascension of the ascending node. argp : ~astropy.units.Quantity Argument of the pericenter. nu : ~astropy.units.Quantity True anomaly. epoch: ~astropy.time.Time, optional Epoch, default to J2000. """ k = attractor.k.to(u.km**3 / u.s**2) ecc = 1.0 * u.one r, v = classical.coe2rv( k.to(u.km**3 / u.s**2).value, p.to(u.km).value, ecc.value, inc.to(u.rad).value, raan.to(u.rad).value, argp.to(u.rad).value, nu.to(u.rad).value) ss = cls.from_vectors(attractor, r * u.km, v * u.km / u.s, epoch) return ss
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)
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)
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)
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)