Ejemplo n.º 1
0
 def _generate_time_values(self, nu_vals):
     # Subtract current anomaly to start from the desired point
     M_vals = np.array([
         nu_to_M(nu_val, self.ecc).value - nu_to_M(self.nu, self.ecc).value
         for nu_val in nu_vals
     ]) * u.rad
     time_values = self.epoch + (M_vals / self.n).decompose()
     return time_values
Ejemplo n.º 2
0
    def propagate(self, value, method=mean_motion, rtol=1e-10, **kwargs):
        """Propagates an orbit.

        If value is true anomaly, propagate orbit to this anomaly and return the result.
        Otherwise, if time is provided, propagate this `Orbit` some `time` and return the result.

        Parameters
        ----------
        value : Multiple options
            True anomaly values or time values. If given an angle, it will always propagate forward.
        rtol : float, optional
            Relative tolerance for the propagation algorithm, default to 1e-10.
        method : function, optional
            Method used for propagation
        **kwargs
            parameters used in perturbation models

        """
        if hasattr(value, "unit") and value.unit in ("rad", "deg"):
            p, ecc, inc, raan, argp, _ = 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,
            )

            # Compute time of flight for correct epoch
            M = nu_to_M(self.nu, self.ecc)
            new_M = nu_to_M(value, self.ecc)
            time_of_flight = Angle(new_M - M).wrap_at(360 * u.deg) / self.n

            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,
                epoch=self.epoch + time_of_flight,
                plane=self._plane,
            )
        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,
                             **kwargs)
Ejemplo n.º 3
0
def test_orbit_from_spk_id_has_proper_values(mock_get, mock_response):
    mock_orbital_data = {
        'orbital_data': {
            'eccentricity': '.2225889698301071',
            'semi_major_axis': '1.457940027185708',
            'inclination': '10.82759100494802',
            'ascending_node_longitude': '304.3221633898424',
            'perihelion_argument': '178.8165910886752',
            'mean_anomaly': '71.28027812836476',
            'epoch_osculation': '2458000.5',
        }
    }

    mock_response.json.return_value = mock_orbital_data
    mock_get.return_value = mock_response
    ss = neows.orbit_from_spk_id('')

    assert ss.ecc == mock_orbital_data['orbital_data']['eccentricity'] * u.one
    assert ss.a == mock_orbital_data['orbital_data']['semi_major_axis'] * u.AU
    assert ss.inc == mock_orbital_data['orbital_data']['inclination'] * u.deg
    assert ss.raan == mock_orbital_data['orbital_data'][
        'ascending_node_longitude'] * u.deg
    assert ss.argp == mock_orbital_data['orbital_data'][
        'perihelion_argument'] * u.deg
    assert nu_to_M(
        ss.nu,
        ss.ecc) == mock_orbital_data['orbital_data']['mean_anomaly'] * u.deg
Ejemplo n.º 4
0
def test_true_to_mean():
    # Data from Schlesinger & Udick, 1912
    data = [
        # ecc, M (deg), nu (deg)
        (0.0, 0.0, 0.0),
        (0.05, 10.0, 11.06),
        (0.06, 30.0, 33.67),
        (0.04, 120.0, 123.87),
        (0.14, 65.0, 80.50),
        (0.19, 21.0, 30.94),
        (0.35, 65.0, 105.71),
        (0.48, 180.0, 180.0),
        (0.75, 125.0, 167.57)
    ]
    for row in data:
        ecc, expected_M, nu = row
        ecc = ecc * u.one
        expected_M = expected_M * u.deg
        nu = nu * u.deg

        M = angles.nu_to_M(nu, ecc)

        assert_almost_equal(M.to(u.rad).value,
                            expected_M.to(u.rad).value,
                            decimal=3)
Ejemplo n.º 5
0
def test_orbit_from_spk_id_has_proper_values(mock_get, mock_response):
    mock_orbital_data = {
        "orbital_data": {
            "eccentricity": ".2225889698301071",
            "semi_major_axis": "1.457940027185708",
            "inclination": "10.82759100494802",
            "ascending_node_longitude": "304.3221633898424",
            "perihelion_argument": "178.8165910886752",
            "mean_anomaly": "71.28027812836476",
            "epoch_osculation": "2458000.5",
        }
    }

    mock_response.json.return_value = mock_orbital_data
    mock_get.return_value = mock_response
    ss = neows.orbit_from_spk_id("")

    assert ss.frame.is_equivalent_frame(
        HeliocentricEclipticJ2000(obstime=ss.epoch))
    assert ss.ecc == mock_orbital_data["orbital_data"]["eccentricity"] * u.one
    assert ss.a == mock_orbital_data["orbital_data"]["semi_major_axis"] * u.AU
    assert ss.inc == mock_orbital_data["orbital_data"]["inclination"] * u.deg
    assert (ss.raan ==
            mock_orbital_data["orbital_data"]["ascending_node_longitude"] *
            u.deg)
    assert ss.argp == mock_orbital_data["orbital_data"][
        "perihelion_argument"] * u.deg
    assert (nu_to_M(
        ss.nu,
        ss.ecc) == mock_orbital_data["orbital_data"]["mean_anomaly"] * u.deg)
Ejemplo n.º 6
0
def test_true_to_mean():
    for row in ANGLES_DATA:
        ecc, expected_M, nu = row
        ecc = ecc * u.one
        expected_M = expected_M * u.deg
        nu = nu * u.deg

        M = angles.nu_to_M(nu, ecc)

        assert_quantity_allclose(M, expected_M, rtol=1e-4)
Ejemplo n.º 7
0
def test_true_to_mean_hyperbolic():
    # Data from Curtis, H. (2013). *Orbital mechanics for engineering students*.
    # Example 3.5
    nu = 100 * u.deg
    ecc = 2.7696 * u.one
    expected_M = 11.279 * u.rad

    M = angles.nu_to_M(nu, ecc)

    assert_quantity_allclose(M, expected_M, rtol=1e-4)
Ejemplo n.º 8
0
def test_true_to_mean():
    for row in ANGLES_DATA:
        ecc, expected_M, nu = row
        ecc = ecc * u.one
        expected_M = expected_M * u.deg
        nu = nu * u.deg

        M = angles.nu_to_M(nu, ecc)

        assert_quantity_allclose(M, expected_M, rtol=1e-4)
Ejemplo n.º 9
0
def test_true_to_mean_hyperbolic():
    # Data from Curtis, H. (2013). *Orbital mechanics for engineering students*.
    # Example 3.5
    nu = 100 * u.deg
    ecc = 2.7696 * u.one
    expected_M = 11.279 * u.rad

    M = angles.nu_to_M(nu, ecc)

    assert_quantity_allclose(M, expected_M, rtol=1e-4)
Ejemplo n.º 10
0
    def time_to_anomaly(self, value):
        """ Returns time required to be in a specific true anomaly.

        Parameters
        ----------
        value : ~astropy.units.Quantity

        Returns
        -------
        tof: ~astropy.units.Quantity
            Time of flight required.
        """

        # Compute time of flight for correct epoch
        M = nu_to_M(self.nu, self.ecc)
        new_M = nu_to_M(value, self.ecc)
        tof = Angle(new_M - M).wrap_at(360 * u.deg) / self.n

        return tof
Ejemplo n.º 11
0
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)
Ejemplo n.º 12
0
def Earth_to_Jupiter(delta_v):
	"""
	Calculates the manuever and the launch windows from Earth to Jupiter,
	assuming tangential impulsive maneuver from Earth orbit around the Sun

	Earth_to_Jupiter(dv):

	    'dv' is given with velocity units (u.m/u.s)

	    Returns:
	        ss_transfer = trasfer orbit object
		  t = time to the first next launch window
		  T = period between possible launch windows
		  t_transfer = time of transfer from launch to Jupiter arrival
	"""
	dv = delta_v * v_Earth_dir

	# Initial transfer orbit calculation (to obtain transfer time)
	man_tmp = Maneuver.impulse(dv)
	transfer = ss_Earth.apply_maneuver(man_tmp)

	# Angles calculation
	# nu_Jupiter: nu of transfer orbit where it crosses Jupiter
	nu_Jupiter = (np.math.acos((transfer.p/R_J - 1)/transfer.ecc)*u.rad)
	ang_vel_Earth = (norm(v_Earth).value / R_E.value)*u.rad/u.s
	ang_vel_Jupiter = (norm(v_Jupiter).value / R_J.value)*u.rad/u.s

	# Transfer time
	M = nu_to_M(nu_Jupiter, transfer.ecc)
	t_transfer = M/transfer.n
	# Delta_nu at launch (Final nu - nu that Jupiter walks during transfer)
	delta_nu_at_launch = nu_Jupiter - ang_vel_Jupiter * t_transfer

	# Angles in radians
	nu_init = angle(r_Earth, r_Jupiter)*u.rad
	# Next launch window in t:
	t = (nu_init - delta_nu_at_launch) / (ang_vel_Earth - ang_vel_Jupiter)
	# Time between windows
	T = (2*np.pi*u.rad) / (ang_vel_Earth - ang_vel_Jupiter)

	# If time to the windows is negative (in the past), we should wait until next window
	while t < 0:
		t = t + T

	# Earth at launch
	ss_Earth_launch = ss_Earth.propagate(t)
	launch_dir = ss_Earth_launch.v / norm(ss_Earth_launch.v)
	dv = delta_v * launch_dir

	# Maneuver calculation
	man = Maneuver((t, dv))
	ss_transfer = ss_Earth.apply_maneuver(man)

	return ss_transfer, t, T, t_transfer
Ejemplo n.º 13
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)
Ejemplo n.º 14
0
    def propagate(self, value, method=mean_motion, rtol=1e-10, **kwargs):
        """Propagates an orbit.

        If value is true anomaly, propagate orbit to this anomaly and return the result.
        Otherwise, if time is provided, propagate this `Orbit` some `time` and return the result.

        Parameters
        ----------
        value : Multiple options
            True anomaly values or time values. If given an angle, it will always propagate forward.
        rtol : float, optional
            Relative tolerance for the propagation algorithm, default to 1e-10.
        method : function, optional
            Method used for propagation
        **kwargs
            parameters used in perturbation models

        """
        if hasattr(value, "unit") and value.unit in ('rad', 'deg'):
            p, ecc, inc, raan, argp, _ = 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)

            # Compute time of flight for correct epoch
            M = nu_to_M(self.nu, self.ecc)
            new_M = nu_to_M(value, self.ecc)
            time_of_flight = Angle(new_M - M).wrap_at(360 * u.deg) / self.n

            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,
                                       epoch=self.epoch + time_of_flight, plane=self._plane)
        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, **kwargs)
Ejemplo n.º 15
0
    def propagate_to_anomaly(self, value):
        """Propagates an orbit to a specific true anomaly.

        Parameters
        ----------
        value : ~astropy.units.Quantity

        Returns
        -------
        Orbit
            Resulting orbit after propagation.

        """
        # TODO: Avoid repeating logic with mean_motion?
        p, ecc, inc, raan, argp, _ = 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,
        )

        # Compute time of flight for correct epoch
        M = nu_to_M(self.nu, self.ecc)
        new_M = nu_to_M(value, self.ecc)
        time_of_flight = Angle(new_M - M).wrap_at(360 * u.deg) / self.n

        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,
            epoch=self.epoch + time_of_flight,
            plane=self.plane,
        )
Ejemplo n.º 16
0
    def propagate_to_anomaly(self, value):
        """Propagates an orbit to a specific true anomaly.

        Parameters
        ----------
        value : ~astropy.units.Quantity

        Returns
        -------
        Orbit
            Resulting orbit after propagation.

        """
        # TODO: Avoid repeating logic with mean_motion?
        p, ecc, inc, raan, argp, _ = 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,
        )

        # Compute time of flight for correct epoch
        M = nu_to_M(self.nu, self.ecc)
        new_M = nu_to_M(value, self.ecc)
        time_of_flight = Angle(new_M - M).wrap_at(360 * u.deg) / self.n

        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,
            epoch=self.epoch + time_of_flight,
            plane=self.plane,
        )
Ejemplo n.º 17
0
def test_true_to_mean():
    # Data from Schlesinger & Udick, 1912
    data = [
        # ecc, M (deg), nu (deg)
        (0.0, 0.0, 0.0),
        (0.05, 10.0, 11.06),
        (0.06, 30.0, 33.67),
        (0.04, 120.0, 123.87),
        (0.14, 65.0, 80.50),
        (0.19, 21.0, 30.94),
        (0.35, 65.0, 105.71),
        (0.48, 180.0, 180.0),
        (0.75, 125.0, 167.57)
    ]
    for row in data:
        ecc, expected_M, nu = row

        M = angles.nu_to_M(np.deg2rad(nu), ecc)

        assert_almost_equal(M, np.deg2rad(expected_M), decimal=3)
Ejemplo n.º 18
0
def test_true_to_mean():
    # Data from Schlesinger & Udick, 1912
    data = [
        # ecc, M (deg), nu (deg)
        (0.0, 0.0, 0.0),
        (0.05, 10.0, 11.06),
        (0.06, 30.0, 33.67),
        (0.04, 120.0, 123.87),
        (0.14, 65.0, 80.50),
        (0.19, 21.0, 30.94),
        (0.35, 65.0, 105.71),
        (0.48, 180.0, 180.0),
        (0.75, 125.0, 167.57)
    ]
    for row in data:
        ecc, expected_M, nu = row
        ecc = ecc * u.one
        expected_M = expected_M * u.deg
        nu = nu * u.deg

        M = angles.nu_to_M(nu, ecc)

        assert_quantity_allclose(M, expected_M, rtol=1e-4)
Ejemplo n.º 19
0
def test_true_to_mean():
    # Data from Schlesinger & Udick, 1912
    data = [
        # ecc, M (deg), nu (deg)
        (0.0, 0.0, 0.0),
        (0.05, 10.0, 11.06),
        (0.06, 30.0, 33.67),
        (0.04, 120.0, 123.87),
        (0.14, 65.0, 80.50),
        (0.19, 21.0, 30.94),
        (0.35, 65.0, 105.71),
        (0.48, 180.0, 180.0),
        (0.75, 125.0, 167.57)
    ]
    for row in data:
        ecc, expected_M, nu = row
        ecc = ecc * u.one
        expected_M = expected_M * u.deg
        nu = nu * u.deg

        M = angles.nu_to_M(nu, ecc)

        assert_quantity_allclose(M, expected_M, rtol=1e-4)
Ejemplo n.º 20
0
def test_true_to_mean():
    # Data from Schlesinger & Udick, 1912
    data = [
        # ecc, M (deg), nu (deg)
        (0.0, 0.0, 0.0),
        (0.05, 10.0, 11.06),
        (0.06, 30.0, 33.67),
        (0.04, 120.0, 123.87),
        (0.14, 65.0, 80.50),
        (0.19, 21.0, 30.94),
        (0.35, 65.0, 105.71),
        (0.48, 180.0, 180.0),
        (0.75, 125.0, 167.57)
    ]
    for row in data:
        ecc, expected_M, nu = row
        ecc = ecc * u.one
        expected_M = expected_M * u.deg
        nu = nu * u.deg

        M = angles.nu_to_M(nu, ecc)

        assert_almost_equal(M.to(u.rad).value, expected_M.to(u.rad).value,
                            decimal=3)
Ejemplo n.º 21
0
def test_mean_to_true_hyperbolic_highecc(expected_nu, ecc):
    M = angles.nu_to_M(expected_nu, ecc)
    print(M, ecc, M.value, ecc.value)
    nu = angles.M_to_nu(M, ecc)
    assert_quantity_allclose(nu, expected_nu, rtol=1e-4)
Ejemplo n.º 22
0
def test_mean_to_true_hyperbolic_highecc(expected_nu, ecc):
    M = angles.nu_to_M(expected_nu, ecc)
    print(M, ecc, M.value, ecc.value)
    nu = angles.M_to_nu(M, ecc)
    assert_quantity_allclose(nu, expected_nu, rtol=1e-4)
Ejemplo n.º 23
0
 def _generate_time_values(self, nu_vals):
     # Subtract current anomaly to start from the desired point
     M_vals = nu_to_M(nu_vals, self.ecc) - nu_to_M(self.nu, self.ecc)
     time_values = self.epoch + (M_vals / self.n).decompose()
     return time_values
Ejemplo n.º 24
0
 def _generate_time_values(self, nu_vals):
     M_vals = nu_to_M(nu_vals, self.ecc)
     time_values = self.epoch + (M_vals / self.n).decompose()
     return time_values
Ejemplo n.º 25
0
 def M(self):
     """Mean anomaly. """
     return nu_to_M(self.nu, self.ecc)