Esempio n. 1
0
def mikkola(k, r0, v0, tof, rtol=None):
    """Raw algorithm for Mikkola's Kepler solver.

    Parameters
    ----------
    k : float
        Standard gravitational parameter of the attractor.
    r : ~np.array
        Position vector.
    v : ~np.array
        Velocity vector.
    tof : float
        Time of flight.
    rtol: float
        This method does not require tolerance since it is non-iterative.

    Returns
    -------
    rr : ~np.array
        Final velocity vector.
    vv : ~np.array
        Final velocity vector.
    Note
    ----
    Original paper: https://doi.org/10.1007/BF01235850
    """

    # Solving for the classical elements
    p, ecc, inc, raan, argp, nu = rv2coe(k, r0, v0)
    nu = mikkola_coe(k, p, ecc, inc, raan, argp, nu, tof)

    return coe2rv(k, p, ecc, inc, raan, argp, nu)
Esempio n. 2
0
def markley(k, r0, v0, tof):
    """Solves the kepler problem by a non-iterative method. Relative error is
    around 1e-18, only limited by machine double-precision errors.

    Parameters
    ----------
    k : float
        Standar Gravitational parameter.
    r0 : ~np.array
        Initial position vector wrt attractor center.
    v0 : ~np.array
        Initial velocity vector.
    tof : float
        Time of flight.

    Returns
    -------
    rr: ~np.array
        Final position vector.
    vv: ~np.array
        Final velocity vector.

    Note
    ----
    The following algorithm was taken from http://dx.doi.org/10.1007/BF00691917.

    """
    # Solve first for eccentricity and mean anomaly
    p, ecc, inc, raan, argp, nu = rv2coe(k, r0, v0)
    nu = markley_coe(k, p, ecc, inc, raan, argp, nu, tof)

    return coe2rv(k, p, ecc, inc, raan, argp, nu)
Esempio n. 3
0
def mean_motion(k, r0, v0, tof):
    r"""Propagates orbit using mean motion. This algorithm depends on the geometric shape of the
    orbit.

    For the case of the strong elliptic or strong hyperbolic orbits:

    ..  math::

        M = M_{0} + \frac{\mu^{2}}{h^{3}}\left ( 1 -e^{2}\right )^{\frac{3}{2}}t

    .. versionadded:: 0.9.0


    Parameters
    ----------
    k : float
        Standar Gravitational parameter
    r0 : ~astropy.units.Quantity
        Initial position vector wrt attractor center.
    v0 : ~astropy.units.Quantity
        Initial velocity vector.
    tof : float
        Time of flight (s).

    Note
    ----
    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)
    # strong elliptic or strong hyperbolic orbits
    if np.abs(ecc - 1.0) > 1e-2:
        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|)
        M = M0 + tof * np.sqrt(k / np.abs(a ** 3))
        nu = M_to_nu(M, ecc)

    # near-parabolic orbit
    else:
        q = p * np.abs(1.0 - ecc) / np.abs(1.0 - ecc ** 2)
        # mean motion n = sqrt(mu / 2 q^3) for parabolic orbit
        M = M0 + tof * np.sqrt(k / 2.0 / (q ** 3))
        nu = M_to_nu(M, ecc)

    return coe2rv(k, p, ecc, inc, raan, argp, nu)
Esempio n. 4
0
def mean_motion(k, r0, v0, tof):
    r"""Propagates orbit using mean motion. This algorithm depends on the geometric shape of the
    orbit.

    For the case of the strong elliptic or strong hyperbolic orbits:

    ..  math::

        M = M_{0} + \frac{\mu^{2}}{h^{3}}\left ( 1 -e^{2}\right )^{\frac{3}{2}}t

    .. versionadded:: 0.9.0


    Parameters
    ----------
    k : float
        Standar Gravitational parameter
    r0 : ~astropy.units.Quantity
        Initial position vector wrt attractor center.
    v0 : ~astropy.units.Quantity
        Initial velocity vector.
    tof : float
        Time of flight (s).

    Note
    ----
    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)
    # strong elliptic or strong hyperbolic orbits
    if np.abs(ecc - 1.0) > 1e-2:
        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|)
        M = M0 + tof * np.sqrt(k / np.abs(a**3))
        nu = M_to_nu(M, ecc)

    # near-parabolic orbit
    else:
        q = p * np.abs(1.0 - ecc) / np.abs(1.0 - ecc**2)
        # mean motion n = sqrt(mu / 2 q^3) for parabolic orbit
        M = M0 + tof * np.sqrt(k / 2.0 / (q**3))
        nu = M_to_nu(M, ecc)

    return coe2rv(k, p, ecc, inc, raan, argp, nu)
Esempio n. 5
0
    def to_vectors(self):
        """Converts to position and velocity vector representation."""
        r, v = coe2rv(
            self.attractor.k.to_value(u.km ** 3 / u.s ** 2),
            self.p.to_value(u.km),
            self.ecc.value,
            self.inc.to_value(u.rad),
            self.raan.to_value(u.rad),
            self.argp.to_value(u.rad),
            self.nu.to_value(u.rad),
        )

        return RVState(self.attractor, r * u.km, v * u.km / u.s, self.plane)
Esempio n. 6
0
def init_state_vec(orbits='Default', random_state=np.random.RandomState()):
    if orbits == 'Default':
        orbits = [
            'LEO', 'MEO', 'GEO', 'LEO', 'MEO', 'GEO', 'Tundra', 'Molniya'
        ]
    random_state.shuffle(orbits)
    exo_atmospheric = False

    inc = np.radians(random_state.uniform(0, 180))  # (rad) – Inclination
    raan = np.radians(random_state.uniform(
        0, 360))  # (rad) – Right ascension of the ascending node.
    argp = np.radians(random_state.uniform(
        low=0, high=360))  # (rad) – Argument of the pericenter.
    nu = np.radians(random_state.uniform(0, 360))  # (rad) – True anomaly.

    if orbits[-1] == 'LEO':
        while not exo_atmospheric:
            a = random_state.uniform(RE_eq + 300 * 1000, RE_eq +
                                     2000 * 1000)  # (m) – Semi-major axis.
            ecc = random_state.uniform(0, .25)  # (Unit-less) – Eccentricity.
            b = a * np.sqrt(1 - ecc**2)
            if b > RE_eq + 300 * 1000:
                exo_atmospheric = True
    if orbits[-1] == 'MEO':
        while not exo_atmospheric:
            a = random_state.uniform(RE_eq + 2000 * 1000, RE_eq +
                                     35786 * 1000)  # (m) – Semi-major axis.
            ecc = random_state.uniform(0, .25)  # (Unit-less) – Eccentricity.
            b = a * np.sqrt(1 - ecc**2)
            if b > RE_eq + 300 * 1000:
                exo_atmospheric = True
    if orbits[-1] == 'GEO':
        a = 42164 * 1000  # (m) – Semi-major axis.
        stationary = random_state.randint(0, 2)
        ecc = stationary * random_state.uniform(
            0, .25)  # (Unit-less) – Eccentricity.
        inc = stationary * random_state.uniform(
            0, np.radians(0))  # (Unit-less) – Eccentricity.
    if orbits[-1] == 'Molniya':
        a = 26600 * 1000  # (m) – Semi-major axis.
        inc = np.radians(63.4)  # (rad) – Inclination
        ecc = 0.737  # (Unit-less) – Eccentricity.
        argp = np.radians(270)  # (rad) – Argument of the pericenter.
    if orbits[-1] == 'Tundra':
        a = 42164 * 1000  # (m) – Semi-major axis.
        inc = np.radians(63.4)  # (rad) – Inclination
        ecc = 0.2  # (Unit-less) – Eccentricity.
        argp = np.radians(270)  # (rad) – Argument of the pericenter.

    p = a * (1 - ecc**2)  # (km) - Semi-latus rectum or parameter
    return np.concatenate(coe2rv(k, p, ecc, inc, raan, argp, nu))
Esempio n. 7
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)
def init_state_vec(seed=None):
    if not (seed == None):
        np.random.seed(seed)
    k = 398600.4418  # (km^3 / s^2) - Standard gravitational parameter
    a = np.random.uniform((6378.1366 + 200), 42164)  # (km) – Semi-major axis.
    ecc = np.random.uniform(0.001, 0.3)  # (Unitless) – Eccentricity.
    inc = np.radians(np.random.uniform(0, 180))  # (rad) – Inclination
    raan = np.radians(np.random.uniform(
        0, 360))  # (rad) – Right ascension of the ascending node.
    argp = np.radians(np.random.uniform(
        0, 360))  # (rad) – Argument of the pericenter.
    nu = np.radians(np.random.uniform(0, 360))  # (rad) – True anomaly.
    p = a * (1 - ecc**2)  # (km) - Semi-latus rectum or parameter
    return np.concatenate(coe2rv(k, p, ecc, inc, raan, argp, nu))
Esempio n. 9
0
    def to_vectors(self):
        """Converts to position and velocity vector representation.

        """
        r, v = coe2rv(
            self.attractor.k.to(u.km ** 3 / u.s ** 2).value,
            self.p.to(u.km).value,
            self.ecc.value,
            self.inc.to(u.rad).value,
            self.raan.to(u.rad).value,
            self.argp.to(u.rad).value,
            self.nu.to(u.rad).value,
        )

        return RVState(self.attractor, r * u.km, v * u.km / u.s)
Esempio n. 10
0
def recseries(k, r0, v0, tof, method="rtol", order=8, numiter=100, rtol=1e-8):
    """Kepler solver for elliptical orbits with recursive series approximation
    method. The order of the series is a user defined parameter.

    Parameters
    ----------
    k : float
        Standard gravitational parameter of the attractor.
    r0 : numpy.ndarray
        Position vector.
    v0 : numpy.ndarray
        Velocity vector.
    tof : float
        Time of flight.
    method : str
        Type of termination method ('rtol','order')
    order : int, optional
        Order of recursion, defaults to 8.
    numiter : int, optional
        Number of iterations, defaults to 100.
    rtol : float, optional
        Relative error for accuracy of the method, defaults to 1e-8.

    Returns
    -------
    rr : numpy.ndarray
        Final position vector.
    vv : numpy.ndarray
        Final velocity vector.

    Notes
    -----
    This algorithm uses series discussed in the paper *Recursive solution to
    Kepler’s problem for elliptical orbits - application in robust
    Newton-Raphson and co-planar closest approach estimation*
    with DOI: http://dx.doi.org/10.13140/RG.2.2.18578.58563/1
    """

    # Solve first for eccentricity and mean anomaly
    p, ecc, inc, raan, argp, nu = rv2coe(k, r0, v0)
    nu = recseries_coe(k, p, ecc, inc, raan, argp, nu, tof, method, order,
                       numiter, rtol)

    return coe2rv(k, p, ecc, inc, raan, argp, nu)
Esempio n. 11
0
def mean_motion(k, r0, v0, tof):
    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

    """

    # 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)
    # strong elliptic or strong hyperbolic orbits
    if np.abs(ecc - 1.0) > 1e-2:
        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|)
        M = M0 + tof * np.sqrt(k / np.abs(a**3))
        nu = M_to_nu(M, ecc)

    # near-parabolic orbit
    else:
        q = p * np.abs(1.0 - ecc) / np.abs(1.0 - ecc**2)
        # mean motion n = sqrt(mu / 2 q^3) for parabolic orbit
        M = M0 + tof * np.sqrt(k / 2.0 / (q**3))
        nu = M_to_nu(M, ecc)

    return coe2rv(k, p, ecc, inc, raan, argp, nu)
Esempio n. 12
0
def mean_motion(k, r0, v0, tof):
    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

    """

    # 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)
    # strong elliptic or strong hyperbolic orbits
    if np.abs(ecc - 1.0) > 1e-2:
        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|)
        M = M0 + tof * np.sqrt(k / np.abs(a ** 3))
        nu = M_to_nu(M, ecc)

    # near-parabolic orbit
    else:
        q = p * np.abs(1.0 - ecc) / np.abs(1.0 - ecc ** 2)
        # mean motion n = sqrt(mu / 2 q^3) for parabolic orbit
        M = M0 + tof * np.sqrt(k / 2.0 / (q ** 3))
        nu = M_to_nu(M, ecc)

    return coe2rv(k, p, ecc, inc, raan, argp, nu)
Esempio n. 13
0
def danby(k, r0, v0, tof, numiter=20, rtol=1e-8):
    """Kepler solver for both elliptic and parabolic orbits based on Danby's
    algorithm.

    Parameters
    ----------
    k : float
        Standard gravitational parameter of the attractor.
    r0 : ~np.array
        Position vector.
    v0 : ~np.array
        Velocity vector.
    tof : float
        Time of flight.
    numiter: int, optional
        Number of iterations, defaults to 20.
    rtol: float, optional
        Relative error for accuracy of the method, defaults to 1e-8.

    Returns
    -------
    rr : ~np.array
        Final position vector.
    vv : ~np.array
        Final velocity vector.

    Note
    ----
    This algorithm was developed by Danby in his paper *The solution of Kepler
    Equation* with DOI: https://doi.org/10.1007/BF01686811
    """

    # Solve first for eccentricity and mean anomaly
    p, ecc, inc, raan, argp, nu = rv2coe(k, r0, v0)
    nu = danby_coe(k, p, ecc, inc, raan, argp, nu, tof, numiter, rtol)

    return coe2rv(k, p, ecc, inc, raan, argp, nu)
Esempio n. 14
0
def gooding(k, r0, v0, tof, numiter=150, rtol=1e-8):
    """Solves the Elliptic Kepler Equation with a cubic convergence and
    accuracy better than 10e-12 rad is normally achieved. It is not valid for
    eccentricities equal or higher than 1.0.

    Parameters
    ----------
    k : float
        Standard gravitational parameter of the attractor.
    r0 : ~np.array
        Position vector.
    v0 : ~np.array
        Velocity vector.
    tof : float
        Time of flight.
    numiter: int, optional
        Number of iterations, defaults to 150.
    rtol: float, optional
        Relative error for accuracy of the method, defaults to 1e-8.

    Returns
    -------
    rr : ~np.array
        Final position vector.
    vv : ~np.array
        Final velocity vector.
    Note
    ----
    Original paper for the algorithm: https://doi.org/10.1007/BF01238923
    """

    # Solve first for eccentricity and mean anomaly
    p, ecc, inc, raan, argp, nu = rv2coe(k, r0, v0)
    nu = gooding_coe(k, p, ecc, inc, raan, argp, nu, tof, numiter, rtol)

    return coe2rv(k, p, ecc, inc, raan, argp, nu)
Esempio n. 15
0
def farnocchia(k, r0, v0, tof):
    r"""Propagates orbit using mean motion.

    This algorithm depends on the geometric shape of the orbit.
    For the case of the strong elliptic or strong hyperbolic orbits:

    ..  math::

        M = M_{0} + \frac{\mu^{2}}{h^{3}}\left ( 1 -e^{2}\right )^{\frac{3}{2}}t

    .. versionadded:: 0.9.0

    Parameters
    ----------
    k : float
        Standar Gravitational parameter
    r0 : ~np.array
        Initial position vector wrt attractor center.
    v0 : ~np.array
        Initial velocity vector.
    tof : float
        Time of flight (s).

    Note
    ----
    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)
    nu = farnocchia_coe(k, p, ecc, inc, raan, argp, nu0, tof)

    return coe2rv(k, p, ecc, inc, raan, argp, nu)
Esempio n. 16
0
def pimienta(k, r0, v0, tof):
    """Raw algorithm for Adonis' Pimienta and John L. Crassidis 15th order
    polynomial Kepler solver.

    Parameters
    ----------
    k : float
        Standar Gravitational parameter.
    r0 : ~np.array
        Initial position vector wrt attractor center.
    v0 : ~np.array
        Initial velocity vector.
    tof : float
        Time of flight.

    Returns
    -------
    rr: ~np.array
        Final position vector.
    vv: ~np.array
        Final velocity vector.

    Note
    ----
    This algorithm was derived from the original paper:
    Pimienta-Peñalver, A. & Crassidis, John. (2013). Accurate Kepler equation
    solver without transcendental function evaluations. Advances in the Astronautical Sciences. 147. 233-247.
    """

    # TODO: implement hyperbolic case

    # Solve first for eccentricity and mean anomaly
    p, ecc, inc, raan, argp, nu = rv2coe(k, r0, v0)
    nu = pimienta_coe(k, p, ecc, inc, raan, argp, nu, tof)

    return coe2rv(k, p, ecc, inc, raan, argp, nu)
Esempio n. 17
0
def test_convert_between_coe_and_rv_is_transitive(classical):
    k = Earth.k.to(u.km ** 3 / u.s ** 2).value  # u.km**3 / u.s**2
    res = rv2coe(k, *coe2rv(k, *classical))
    assert_allclose(res, classical)
Esempio n. 18
0
def mikkola(k, r0, v0, tof, rtol=None):
    """ Raw algorithm for Mikkola's Kepler solver.

    Parameters
    ----------
    k : ~astropy.units.Quantity
        Standard gravitational parameter of the attractor.
    r : ~astropy.units.Quantity
        Position vector.
    v : ~astropy.units.Quantity
        Velocity vector.
    tofs : ~astropy.units.Quantity
        Array of times to propagate.
    rtol: float
        This method does not require of tolerance since it is non iterative.

    Returns
    -------
    rr : ~astropy.units.Quantity
        Propagated position vectors.
    vv : ~astropy.units.Quantity

    Note
    ----
    Original paper: https://doi.org/10.1007/BF01235850
    """

    # Solving for the classical elements
    p, ecc, inc, raan, argp, nu = rv2coe(k, r0, v0)
    M0 = nu_to_M(nu, ecc, delta=0)
    a = p / (1 - ecc**2)
    n = np.sqrt(k / np.abs(a)**3)
    M = M0 + n * tof

    # Solve for specific geometrical case
    if ecc < 1.0:
        # Equation (9a)
        alpha = (1 - ecc) / (4 * ecc + 1 / 2)
    else:
        alpha = (ecc - 1) / (4 * ecc + 1 / 2)

    beta = M / 2 / (4 * ecc + 1 / 2)

    # Equation (9b)
    if beta >= 0:
        z = (beta + np.sqrt(beta**2 + alpha**3))**(1 / 3)
    else:
        z = (beta - np.sqrt(beta**2 + alpha**3))**(1 / 3)

    s = z - alpha / z

    # Apply initial correction
    if ecc < 1.0:
        ds = -0.078 * s**5 / (1 + ecc)
    else:
        ds = 0.071 * s**5 / (1 + 0.45 * s**2) / (1 + 4 * s**2) / ecc

    s += ds

    # Solving for the true anomaly
    if ecc < 1.0:
        E = M + ecc * (3 * s - 4 * s**3)
        f = E - ecc * np.sin(E) - M
        f1 = 1.0 - ecc * np.cos(E)
        f2 = ecc * np.sin(E)
        f3 = ecc * np.cos(E)
        f4 = -f2
        f5 = -f3
    else:
        E = 3 * np.log(s + np.sqrt(1 + s**2))
        f = -E + ecc * np.sinh(E) - M
        f1 = -1.0 + ecc * np.cosh(E)
        f2 = ecc * np.sinh(E)
        f3 = ecc * np.cosh(E)
        f4 = f2
        f5 = f3

    # Apply Taylor expansion
    u1 = -f / f1
    u2 = -f / (f1 + 0.5 * f2 * u1)
    u3 = -f / (f1 + 0.5 * f2 * u2 + (1.0 / 6.0) * f3 * u2**2)
    u4 = -f / (f1 + 0.5 * f2 * u3 + (1.0 / 6.0) * f3 * u3**2 +
               (1.0 / 24.0) * f4 * (u3**3))
    u5 = -f / (f1 + f2 * u4 / 2 + f3 * (u4 * u4) / 6.0 + f4 *
               (u4 * u4 * u4) / 24.0 + f5 * (u4 * u4 * u4 * u4) / 120.0)

    E += u5

    if ecc < 1.0:
        nu = E_to_nu(E, ecc)
    else:
        if ecc == 1.0:
            # Parabolic
            nu = D_to_nu(E)
        else:
            # Hyperbolic
            nu = F_to_nu(E, ecc)

    return coe2rv(k, p, ecc, inc, raan, argp, nu)
Esempio n. 19
0
def markley(k, r0, v0, tof):
    """ Solves the kepler problem by a non iterative method. Relative error is
    around 1e-18, only limited by machine double-precission errors.

    Parameters
    ----------
    k : float
        Standar Gravitational parameter
    r0 : array
        Initial position vector wrt attractor center.
    v0 : array
        Initial velocity vector.
    tof : float
        Time of flight.

    Returns
    -------
    rf: array
        Final position vector
    vf: array
        Final velocity vector

    Note
    ----
    The following algorithm was taken from http://dx.doi.org/10.1007/BF00691917.
    """

    # Solve first for eccentricity and mean anomaly
    p, ecc, inc, raan, argp, nu = rv2coe(k, r0, v0)

    M0 = nu_to_M(nu, ecc, delta=0)
    a = p / (1 - ecc**2)
    n = np.sqrt(k / a**3)
    M = M0 + n * tof

    # Range between -pi and pi
    M = M % (2 * np.pi)
    if M > np.pi:
        M = -(2 * np.pi - M)

    # Equation (20)
    alpha = (3 * np.pi**2 + 1.6 * (np.pi - np.abs(M)) /
             (1 + ecc)) / (np.pi**2 - 6)

    # Equation (5)
    d = 3 * (1 - ecc) + alpha * ecc

    # Equation (9)
    q = 2 * alpha * d * (1 - ecc) - M**2

    # Equation (10)
    r = 3 * alpha * d * (d - 1 + ecc) * M + M**3

    # Equation (14)
    w = (np.abs(r) + np.sqrt(q**3 + r**2))**(2 / 3)

    # Equation (15)
    E = (2 * r * w / (w**2 + w * q + q**2) + M) / d

    # Equation (26)
    f0 = _kepler_equation(E, M, ecc)
    f1 = _kepler_equation_prime(E, M, ecc)
    f2 = ecc * np.sin(E)
    f3 = ecc * np.cos(E)
    f4 = -f2

    # Equation (22)
    delta3 = -f0 / (f1 - 0.5 * f0 * f2 / f1)
    delta4 = -f0 / (f1 + 0.5 * delta3 * f2 + 1 / 6 * delta3**2 * f3)
    delta5 = -f0 / (f1 + 0.5 * delta4 * f2 + 1 / 6 * delta4**2 * f3 +
                    1 / 24 * delta4**3 * f4)

    E += delta5
    nu = E_to_nu(E, ecc)

    return coe2rv(k, p, ecc, inc, raan, argp, nu)
Esempio n. 20
0
def pimienta(k, r0, v0, tof):
    """ Raw algorithm for Adonis' Pimienta and John L. Crassidis 15th order
    polynomial Kepler solver.

    Parameters
    ----------
    k : float
        Standar Gravitational parameter
    r0 : array
        Initial position vector wrt attractor center.
    v0 : array
        Initial velocity vector.
    tof : float
        Time of flight.

    Returns
    -------
    rf: array
        Final position vector
    vf: array
        Final velocity vector

    Note
    ----
    This algorithm was drived from the original paper: http://hdl.handle.net/10477/50522
    """

    # TODO: implement hyperbolic case

    # Solve first for eccentricity and mean anomaly
    p, ecc, inc, raan, argp, nu = rv2coe(k, r0, v0)

    M0 = nu_to_M(nu, ecc, delta=0)
    semi_axis_a = p / (1 - ecc**2)
    n = np.sqrt(k / np.abs(semi_axis_a)**3)
    M = M0 + n * tof

    # Equation (32a), (32b), (32c) and (32d)
    c3 = 5 / 2 + 560 * ecc
    a = 15 * (1 - ecc) / c3
    b = -M / c3
    y = np.sqrt(b**2 / 4 + a**3 / 27)

    # Equation (33)
    x_bar = (-b / 2 + y)**(1 / 3) - (b / 2 + y)**(1 / 3)

    # Coefficients from equations (34a) and (34b)
    c15 = 3003 / 14336 + 16384 * ecc
    c13 = 3465 / 13312 - 61440 * ecc
    c11 = 945 / 2816 + 92160 * ecc
    c9 = 175 / 384 - 70400 * ecc
    c7 = 75 / 112 + 28800 * ecc
    c5 = 9 / 8 - 6048 * ecc

    # Precompute x_bar powers, equations (35a) to (35d)
    x_bar2 = x_bar**2
    x_bar3 = x_bar2 * x_bar
    x_bar4 = x_bar3 * x_bar
    x_bar5 = x_bar4 * x_bar
    x_bar6 = x_bar5 * x_bar
    x_bar7 = x_bar6 * x_bar
    x_bar8 = x_bar7 * x_bar
    x_bar9 = x_bar8 * x_bar
    x_bar10 = x_bar9 * x_bar
    x_bar11 = x_bar10 * x_bar
    x_bar12 = x_bar11 * x_bar
    x_bar13 = x_bar12 * x_bar
    x_bar14 = x_bar13 * x_bar
    x_bar15 = x_bar14 * x_bar

    # Function f and its derivatives are given by all the (36) equation set
    f = (c15 * x_bar15 + c13 * x_bar13 + c11 * x_bar11 + c9 * x_bar9 +
         c7 * x_bar7 + c5 * x_bar5 + c3 * x_bar3 + 15 * (1 - ecc) * x_bar - M)
    f1 = (15 * c15 * x_bar14 + 13 * c13 * x_bar12 + 11 * c11 * x_bar10 +
          9 * c9 * x_bar8 + 7 * c7 * x_bar6 + 5 * c5 * x_bar4 +
          3 * c3 * x_bar2 + 15 * (1 - ecc))
    f2 = (210 * c15 * x_bar13 + 156 * c13 * x_bar11 + 110 * c11 * x_bar9 +
          72 * c9 * x_bar7 + 42 * c7 * x_bar5 + 20 * c5 * x_bar3 +
          6 * c3 * x_bar)
    f3 = (2730 * c15 * x_bar12 + 1716 * c13 * x_bar10 + 990 * c11 * x_bar8 +
          504 * c9 * x_bar6 + 210 * c7 * x_bar4 + 60 * c5 * x_bar2 + 6 * c3)
    f4 = (32760 * c15 * x_bar11 + 17160 * c13 * x_bar9 + 7920 * c11 * x_bar7 +
          3024 * c9 * x_bar5 + 840 * c7 * x_bar3 + 120 * c5 * x_bar)
    f5 = (360360 * c15 * x_bar10 + 154440 * c13 * x_bar8 +
          55440 * c11 * x_bar6 + 15120 * c9 * x_bar4 + 2520 * c7 * x_bar2 +
          120 * c5)
    f6 = (3603600 * c15 * x_bar9 + 1235520 * c13 * x_bar7 +
          332640 * c11 * x_bar5 + 60480 * c9 * x_bar3 + 5040 * c7 * x_bar)
    f7 = (32432400 * c15 * x_bar8 + 8648640 * c13 * x_bar6 +
          1663200 * c11 * x_bar4 + 181440 * c9 * x_bar2 + 5040 * c7)
    f8 = (259459200 * c15 * x_bar7 + 51891840 * c13 * x_bar5 +
          6652800 * c11 * x_bar3 + 362880 * c9 * x_bar)
    f9 = (1.8162144e9 * c15 * x_bar6 + 259459200 * c13 * x_bar4 +
          19958400 * c11 * x_bar2 + 362880 * c9)
    f10 = (1.08972864e10 * c15 * x_bar5 + 1.0378368e9 * c13 * x_bar3 +
           39916800 * c11 * x_bar)
    f11 = 5.4486432e10 * c15 * x_bar4 + 3.1135104e9 * c13 * x_bar2 + 39916800 * c11
    f12 = 2.17945728e11 * c15 * x_bar3 + 6.2270208e9 * c13 * x_bar
    f13 = 6.53837184 * c15 * x_bar2 + 6.2270208e9 * c13
    f14 = 1.307674368e13 * c15 * x_bar
    f15 = 1.307674368e13 * c15

    # Solving g parameters defined by equations (37a), (37b), (37c) and (37d)
    g1 = 1 / 2
    g2 = 1 / 6
    g3 = 1 / 24
    g4 = 1 / 120
    g5 = 1 / 720
    g6 = 1 / 5040
    g7 = 1 / 40320
    g8 = 1 / 362880
    g9 = 1 / 3628800
    g10 = 1 / 39916800
    g11 = 1 / 479001600
    g12 = 1 / 6.2270208e9
    g13 = 1 / 8.71782912e10
    g14 = 1 / 1.307674368e12

    # Solving for the u_{i} and h_{i} variables defined by equation (38)
    u1 = -f / f1

    h2 = f1 + g1 * u1 * f2
    u2 = -f / h2

    h3 = f1 + g1 * u2 * f2 + g2 * u2**2 * f3
    u3 = -f / h3

    h4 = f1 + g1 * u3 * f2 + g2 * u3**2 * f3 + g3 * u3**3 * f4
    u4 = -f / h4

    h5 = f1 + g1 * u4 * f2 + g2 * u4**2 * f3 + g3 * u4**3 * f4 + g4 * u4**4 * f5
    u5 = -f / h5

    h6 = (f1 + g1 * u5 * f2 + g2 * u5**2 * f3 + g3 * u5**3 * f4 +
          g4 * u5**4 * f5 + g5 * u5**5 * f6)
    u6 = -f / h6

    h7 = (f1 + g1 * u6 * f2 + g2 * u6**2 * f3 + g3 * u6**3 * f4 +
          g4 * u6**4 * f5 + g5 * u6**5 * f6 + g6 * u6**6 * f7)
    u7 = -f / h7

    h8 = (f1 + g1 * u7 * f2 + g2 * u7**2 * f3 + g3 * u7**3 * f4 +
          g4 * u7**4 * f5 + g5 * u7**5 * f6 + g6 * u7**6 * f7 +
          g7 * u7**7 * f8)
    u8 = -f / h8

    h9 = (f1 + g1 * u8 * f2 + g2 * u8**2 * f3 + g3 * u8**3 * f4 +
          g4 * u8**4 * f5 + g5 * u8**5 * f6 + g6 * u8**6 * f7 +
          g7 * u8**7 * f8 + g8 * u8**8 * f9)
    u9 = -f / h9

    h10 = (f1 + g1 * u9 * f2 + g2 * u9**2 * f3 + g3 * u9**3 * f4 +
           g4 * u9**4 * f5 + g5 * u9**5 * f6 + g6 * u9**6 * f7 +
           g7 * u9**7 * f8 + g8 * u9**8 * f9 + g9 * u9**9 * f10)
    u10 = -f / h10

    h11 = (f1 + g1 * u10 * f2 + g2 * u10**2 * f3 + g3 * u10**3 * f4 +
           g4 * u10**4 * f5 + g5 * u10**5 * f6 + g6 * u10**6 * f7 +
           g7 * u10**7 * f8 + g8 * u10**8 * f9 + g9 * u10**9 * f10 +
           g10 * u10**10 * f11)
    u11 = -f / h11

    h12 = (f1 + g1 * u11 * f2 + g2 * u11**2 * f3 + g3 * u11**3 * f4 +
           g4 * u11**4 * f5 + g5 * u11**5 * f6 + g6 * u11**6 * f7 +
           g7 * u11**7 * f8 + g8 * u11**8 * f9 + g9 * u11**9 * f10 +
           g10 * u11**10 * f11 + g11 * u11**11 * f12)
    u12 = -f / h12

    h13 = (f1 + g1 * u12 * f2 + g2 * u12**2 * f3 + g3 * u12**3 * f4 +
           g4 * u12**4 * f5 + g5 * u12**5 * f6 + g6 * u12**6 * f7 +
           g7 * u12**7 * f8 + g8 * u12**8 * f9 + g9 * u12**9 * f10 +
           g10 * u12**10 * f11 + g11 * u12**11 * f12 + g12 * u12**12 * f13)
    u13 = -f / h13

    h14 = (f1 + g1 * u13 * f2 + g2 * u13**2 * f3 + g3 * u13**3 * f4 +
           g4 * u13**4 * f5 + g5 * u13**5 * f6 + g6 * u13**6 * f7 +
           g7 * u13**7 * f8 + g8 * u13**8 * f9 + g9 * u13**9 * f10 +
           g10 * u13**10 * f11 + g11 * u13**11 * f12 + g12 * u13**12 * f13 +
           g13 * u13**13 * f14)
    u14 = -f / h14

    h15 = (f1 + g1 * u14 * f2 + g2 * u14**2 * f3 + g3 * u14**3 * f4 +
           g4 * u14**4 * f5 + g5 * u14**5 * f6 + g6 * u14**6 * f7 +
           g7 * u14**7 * f8 + g8 * u14**8 * f9 + g9 * u14**9 * f10 +
           g10 * u14**10 * f11 + g11 * u14**11 * f12 + g12 * u14**12 * f13 +
           g13 * u14**13 * f14 + g14 * u14**14 * f15)
    u15 = -f / h15

    # Solving for x
    x = x_bar + u15
    w = x - 0.01171875 * x**17 / (1 + ecc)

    # Solving for the true anomaly from eccentricity anomaly
    E = M + ecc * (-16384 * w**15 + 61440 * w**13 - 92160 * w**11 + 70400 *
                   w**9 - 28800 * w**7 + 6048 * w**5 - 560 * w**3 + 15 * w)

    nu = E_to_nu(E, ecc)

    return coe2rv(k, p, ecc, inc, raan, argp, nu)
Esempio n. 21
0
def gooding(k, r0, v0, tof, numiter=150, rtol=1e-8):
    """ Solves the Elliptic Kepler Equation with a cubic convergence and
    accuracy better than 10e-12 rad is normally achieved. It is not valid for
    eccentricities equal or higher than 1.0.

    Parameters
    ----------
    k : float
        Standard gravitational parameter of the attractor.
    r : 1x3 vector
        Position vector.
    v : 1x3 vector
        Velocity vector.
    tof : float
        Time of flight.
    rtol: float
        Relative error for accuracy of the method.

    Returns
    -------
    rr : 1x3 vector
        Propagated position vectors.
     vv : 1x3 vector

    Note
    ----
    Original paper for the algorithm: https://doi.org/10.1007/BF01238923
    """

    # Solve first for eccentricity and mean anomaly
    p, ecc, inc, raan, argp, nu = rv2coe(k, r0, v0)

    # TODO: parabolic and hyperbolic not implemented cases
    if ecc >= 1.0:
        raise NotImplementedError(
            "Parabolic/Hyperbolic cases still not implemented in gooding.")

    M0 = nu_to_M(nu, ecc, delta=0)
    semi_axis_a = p / (1 - ecc**2)
    n = np.sqrt(k / np.abs(semi_axis_a)**3)
    M = M0 + n * tof

    # Start the computation
    n = 0
    c = ecc * np.cos(M)
    s = ecc * np.sin(M)
    psi = s / np.sqrt(1 - 2 * c + ecc**2)
    f = 1.0
    while f**2 >= rtol and n <= numiter:
        xi = np.cos(psi)
        eta = np.sin(psi)
        fd = (1 - c * xi) + s * eta
        fdd = c * eta + s * xi
        f = psi - fdd
        psi = psi - f * fd / (fd**2 - 0.5 * f * fdd)
        n += 1

    E = M + psi
    nu = E_to_nu(E, ecc)

    return coe2rv(k, p, ecc, inc, raan, argp, nu)
Esempio n. 22
0
def danby(k, r0, v0, tof, numiter=20, rtol=1e-8):
    """ Kepler solver for both elliptic and parabolic orbits based on Danby's
    algorithm.

    Parameters
    ----------
    k : float
        Standard gravitational parameter of the attractor.
    r : 1x3 vector
        Position vector.
    v : 1x3 vector
        Velocity vector.
    tof : float
        Time of flight.
    rtol: float
        Relative error for accuracy of the method.

    Returns
    -------
    rr : 1x3 vector
        Propagated position vectors.
    vv : 1x3 vector

    Note
    ----
    This algorithm was developed by Danby in his paper *The solution of Kepler
    Equation* with DOI: https://doi.org/10.1007/BF01686811
    """

    # Solve first for eccentricity and mean anomaly
    p, ecc, inc, raan, argp, nu = rv2coe(k, r0, v0)
    M0 = nu_to_M(nu, ecc, delta=0)
    semi_axis_a = p / (1 - ecc**2)
    n = np.sqrt(k / np.abs(semi_axis_a)**3)
    M = M0 + n * tof

    # Range mean anomaly
    xma = M - 2 * np.pi * np.floor(M / 2 / np.pi)

    if ecc == 0:
        # Solving for circular orbit
        nu = xma
        return coe2rv(k, p, ecc, inc, raan, argp, nu)

    elif ecc < 1.0:
        # For elliptical orbit
        E = xma + 0.85 * np.sign(np.sin(xma)) * ecc

    else:
        # For parabolic and hyperbolic
        E = np.log(2 * xma / ecc + 1.8)

    # Iterations begin
    n = 0
    while n <= numiter:

        if ecc < 1.0:
            s = ecc * np.sin(E)
            c = ecc * np.cos(E)
            f = E - s - xma
            fp = 1 - c
            fpp = s
            fppp = c
        else:
            s = ecc * np.sinh(E)
            c = ecc * np.cosh(E)
            f = s - E - xma
            fp = c - 1
            fpp = s
            fppp = c

        if np.abs(f) <= rtol:

            if ecc < 1.0:
                sta = np.sqrt(1 - ecc**2) * np.sin(E)
                cta = np.cos(E) - ecc
            else:
                sta = np.sqrt(ecc**2 - 1) * np.sinh(E)
                cta = ecc - np.cosh(E)

            nu = np.arctan2(sta, cta)
            return coe2rv(k, p, ecc, inc, raan, argp, nu)

        else:
            delta = -f / fp
            delta_star = -f / (fp + 0.5 * delta * fpp)
            deltak = -f / (fp + 0.5 * delta_star * fpp +
                           delta_star**2 * fppp / 6)
            E = E + deltak
            n += 1

    raise ValueError("Maximum number of iterations has been reached.")
Esempio n. 23
0
def test_convert_between_coe_and_rv_is_transitive(classical):
    k = Earth.k.to(u.km ** 3 / u.s ** 2).value  # u.km**3 / u.s**2
    res = rv2coe(k, *coe2rv(k, *classical))
    assert_allclose(res, classical)
Esempio n. 24
0
def updateDf(df, runHPOP, varyCols, setSunAreaEqualToDragArea):

    if any(col in ['a', 'e', 'i', 'AoP', 'RAAN', 'TA', 'Rp', 'Ra']
           for col in varyCols):

        # absolute e
        df['e'] = abs(df['e'])

        # Update dependant values, based on selection of Rp,Ra,a,e
        # If 2 are varied
        if 'Rp' in varyCols and 'e' in varyCols:
            df['a'] = df['Rp'] / (1 - df['e'])
            df['Ra'] = df['a'] * (1 + df['e'])
            df['p'] = df['a'] * (1 - df['e']**2)

        elif 'Ra' in varyCols and 'e' in varyCols:
            df['a'] = df['Ra'] / (1 + df['e'])
            df['Rp'] = df['a'] * (1 - df['e'])
            df['p'] = df['a'] * (1 - df['e']**2)

        elif 'Rp' in varyCols and 'a' in varyCols:
            df['e'] = 1 - df['Rp'] / df['a']
            df['Ra'] = df['a'] * (1 + df['e'])
            df['p'] = df['a'] * (1 - df['e']**2)

        elif 'Ra' in varyCols and 'a' in varyCols:
            df['e'] = df['Ra'] / df['a'] - 1
            df['Rp'] = df['a'] * (1 - df['e'])
            df['p'] = df['a'] * (1 - df['e']**2)
        # If a,e pair or Rp,Ra pair or just 1 is varied
        else:
            if any(col in ['a', 'e'] for col in varyCols):
                df['Rp'] = df['a'] * (1 - df['e'])
                df['Ra'] = df['a'] * (1 + df['e'])
                df['p'] = df['a'] * (1 - df['e']**2)

            if any(col in ['Rp', 'Ra'] for col in varyCols):
                switchRaRp = df['Ra'] < df['Rp']
                tempRp = df.loc[switchRaRp, 'Rp']
                df.loc[switchRaRp, 'Rp'] = df.loc[switchRaRp, 'Ra']
                df.loc[switchRaRp, 'Ra'] = tempRp
                df['a'] = (df['Rp'] + df['Ra']) / 2
                df['e'] = (df['Ra'] - df['Rp']) / (df['Ra'] + df['Rp'])
                df['p'] = df['a'] * (1 - df['e']**2)

        # Wrap values between 0 and 180 or 0 and 360
        if any(col in ['i', 'AoP', 'RAAN', 'TA'] for col in varyCols):
            df.loc[df['i'] > 180, 'i'] = 180 - (
                df.loc[df['i'] > 180, 'i'] - 180
            )  # if > 180, subtract the amount over from 180
            df.loc[df['i'] < 180, 'i'] = abs(df.loc[df['i'] < 180, 'i'])
            df.loc[df['RAAN'] < 360,
                   'RAAN'] = df.loc[df['RAAN'] < 360, 'RAAN'] + 360
            df.loc[df['RAAN'] > 360,
                   'RAAN'] = df.loc[df['RAAN'] > 360, 'RAAN'] - 360
            df.loc[df['AoP'] < 360,
                   'AoP'] = df.loc[df['AoP'] < 360, 'AoP'] + 360
            df.loc[df['AoP'] > 360,
                   'AoP'] = df.loc[df['AoP'] > 360, 'AoP'] - 360
            df.loc[df['TA'] < 360, 'TA'] = df.loc[df['TA'] < 360, 'TA'] + 360
            df.loc[df['TA'] > 360, 'TA'] = df.loc[df['TA'] > 360, 'TA'] - 360

    # Update Cartesian
        rs = np.zeros((len(df), 3))
        vs = np.zeros((len(df), 3))
        for ii in range(len(df)):
            rs[ii], vs[ii] = coe2rv(GM_earth * 1e-9, df['p'].iloc[ii],
                                    df['e'].iloc[ii],
                                    df['i'].iloc[ii] * np.pi / 180,
                                    df['RAAN'].iloc[ii] * np.pi / 180,
                                    df['AoP'].iloc[ii] * np.pi / 180,
                                    df['TA'].iloc[ii] * np.pi / 180)
        df['x'] = rs[:, 0]
        df['y'] = rs[:, 1]
        df['z'] = rs[:, 2]
        df['Vx'] = vs[:, 0]
        df['Vy'] = vs[:, 1]
        df['Vz'] = vs[:, 2]

    # Update Cartesian and dependant variables
    if any(col in ['x', 'y', 'z', 'Vx', 'Vy', 'Vz'] for col in varyCols):
        # Convert back to classical
        rs = df[['x', 'y', 'z']].to_numpy()
        vs = df[['Vx', 'Vy', 'Vz']].to_numpy()
        oes = np.zeros((len(df), 6))
        for ii in range(len(df)):
            oes[ii,
                0], oes[ii,
                        1], oes[ii,
                                2], oes[ii,
                                        3], oes[ii, 4], oes[ii, 5] = rv2coe(
                                            GM_earth * 1e-9, rs[ii], vs[ii])
        df['p'] = oes[:, 0]
        df['e'] = oes[:, 1]
        df['i'] = oes[:, 2] * 180 / np.pi
        df['RAAN'] = oes[:, 3] * 180 / np.pi
        df['AoP'] = oes[:, 4] * 180 / np.pi
        df['TA'] = oes[:, 5] * 180 / np.pi
        df['a'] = df['p'] / (1 - df['e']**2)
        df['Rp'] = df['a'] * (1 - df['e'])
        df['Ra'] = df['a'] * (1 + df['e'])
        df.loc[df['TA'] < 0, 'TA'] = df.loc[df['TA'] < 0, 'TA'] + 360
        df.loc[df['TA'] > 360, 'TA'] = df.loc[df['TA'] > 360, 'TA'] - 360

    # Update satellite characteristics
    if any(col in ['Cd', 'Cr', 'Drag Area', 'Sun Area', 'Mass']
           for col in varyCols):
        if setSunAreaEqualToDragArea == True:
            df['Sun Area'] = df['Drag Area']
        df['Cd*Drag Area/Mass'] = df['Cd'] * df['Drag Area'] / df['Mass']
        df['Cr*Sun Area/Mass'] = df['Cr'] * df['Sun Area'] / df['Mass']

    # Replace flux sigma with 0
    df.loc[df['SolarFluxFile'] == 'SpaceWeather-v1.2.txt',
           'Flux Sigma Level'] = 0
    # Get rid of -0 values
    df.loc[df['Flux Sigma Level'] == -0, 'Flux Sigma Level'] = 0

    return df
Esempio n. 25
0
def generateTradeStudy(tradeStudy):
    fileName = os.getcwd() + '\\Results\\' + tradeStudy.fileName
    runHPOP = tradeStudy.runHPOP
    epoch = tradeStudy.epoch
    a = tradeStudy.a
    e = tradeStudy.e
    i = tradeStudy.i
    RAAN = tradeStudy.RAAN
    AoP = tradeStudy.AoP
    TA = tradeStudy.TA
    Cd = tradeStudy.Cd
    Cr = tradeStudy.Cr
    DragArea = tradeStudy.DragArea
    SunArea = tradeStudy.SunArea
    Mass = tradeStudy.Mass
    OrbPerCal = tradeStudy.OrbPerCal
    GaussQuad = tradeStudy.GaussQuad
    SigLvl = tradeStudy.SigLvl
    SolFlxFile = tradeStudy.SolFlxFile
    AtmDen = tradeStudy.AtmDen
    SecondOrderOblateness = tradeStudy.SecondOrderOblateness
    numberOfRuns = tradeStudy.numberOfRuns
    howToVary = tradeStudy.howToVary
    varyCols = tradeStudy.varyCols
    varyValues = tradeStudy.varyValues
    setSunAreaEqualToDragArea = tradeStudy.setSunAreaEqualToDragArea
    np.random.seed(seed=1)

    # Generate Additional Columns
    Rp = a * (1 - e)
    Ra = a * (1 + e)
    p = a * (1 - e**2)
    rs, vs = coe2rv(GM_earth * 1e-9, p, e, i * np.pi / 180, RAAN * np.pi / 180,
                    AoP * np.pi / 180, TA * np.pi / 180)
    x = rs[0]
    y = rs[1]
    z = rs[2]
    Vx = vs[0]
    Vy = vs[1]
    Vz = vs[2]
    CdAM = Cd * DragArea / Mass
    CrAM = Cr * SunArea / Mass

    # Generate Dataframe to store all of the runs
    data = [
        epoch, a, e, i, RAAN, AoP, TA, Rp, Ra, p, x, y, z, Vx, Vy, Vz, Cd, Cr,
        DragArea, SunArea, Mass, CdAM, CrAM, OrbPerCal, GaussQuad, SigLvl,
        SolFlxFile, AtmDen, SecondOrderOblateness
    ]

    columns = [
        'epoch', 'a', 'e', 'i', 'RAAN', 'AoP', 'TA', 'Rp', 'Ra', 'p', 'x', 'y',
        'z', 'Vx', 'Vy', 'Vz', 'Cd', 'Cr', 'Drag Area', 'Sun Area', 'Mass',
        'Cd*Drag Area/Mass', 'Cr*Sun Area/Mass', 'Orb Per Calc',
        'Gaussian Quad', 'Flux Sigma Level', 'SolarFluxFile', 'Density Model',
        '2nd Order Oblateness'
    ]

    df = pd.DataFrame(data=data, index=columns).T
    df[df.columns[:-3]] = df[df.columns[:-3]].astype(float)

    # Grid Search
    if howToVary.lower() == 'gridsearch':
        # Create grid search of parameters and update the Dataframe
        numOfLevels = [len(val) for val in varyValues]
        runs = fullfact(numOfLevels).astype(int)
        paramdf = pd.DataFrame()

        for ii in range(len(runs.T)):
            paramdf[varyCols[ii]] = varyValues[ii][runs[:, ii]]

        df = pd.concat([df] * len(runs), ignore_index=True)

        for col in paramdf.columns:
            df[col] = paramdf[col]

    # Latin Hypercube
    elif howToVary.lower() == 'latinhypercube':
        # Generate runs
        lhd = lhs(len(varyCols), samples=numberOfRuns)
        #     lhd = stats.norm(loc=0, scale=1).ppf(lhd) # Convert to a normal distribution
        lhd = pd.DataFrame(lhd)

        adjustEpoch = False
        if 'epoch' in varyCols:
            date1 = yydddToDatetime(varyValues[0][0])
            date2 = yydddToDatetime(varyValues[0][1])
            deltaDays = lhd[0] * (date2 - date1).days
            minDate = [varyValues[0][0] for i in range(numberOfRuns)]
            varyCols.remove('epoch')
            varyValues = varyValues[1:]
            lhd = lhd.drop(0, axis=1)
            adjustEpoch = True

        lhd.columns = varyCols

        # Replace string columns with categories
        strii = [
            ii for ii in range(len(varyValues))
            if isinstance(varyValues[ii][0], str)
        ]
        for ii in strii:
            lhd.iloc[:, ii] = pd.cut(lhd.iloc[:, ii],
                                     len(varyValues[ii]),
                                     labels=varyValues[ii])
        # Replace float columns with values in range
        varyValues = np.array(varyValues)
        floatii = lhd.dtypes == float
        lhsMinMax = varyValues[floatii]
        lhsMinMax = np.concatenate(lhsMinMax, axis=0).reshape(-1, 2)
        lhd.loc[:, floatii] = lhd.loc[:, floatii] * (
            lhsMinMax[:, 1] - lhsMinMax[:, 0]) + lhsMinMax[:, 0]

        indxs = [
            ii for ii in range(len(varyCols)) if varyCols[ii] in
            ['Orb Per Calc', 'Gaussian Quad', 'Flux Sigma Level']
        ]
        lhd.iloc[:, indxs] = lhd.iloc[:, indxs].round()

        # Create df
        df = pd.concat([df] * len(lhd), ignore_index=True)

        if adjustEpoch == True:
            df['epoch'] = [
                adjustDate(yyddd, deltaDay)
                for yyddd, deltaDay in zip(minDate, deltaDays)
            ]

        for col in lhd.columns:
            df[col] = lhd[col]

    # Perturb
    elif howToVary.lower() == 'perturb':
        # Sample from a normal distribution
        rv = stats.norm()
        rvVals = rv.rvs((numberOfRuns, len(varyCols)))

        # Create perturbation df
        pertdf = pd.DataFrame(rvVals) * varyValues
        pertdf.columns = varyCols

        # Duplicate original df by the number of runs
        df = pd.concat([df] * numberOfRuns, ignore_index=True)

        if 'epoch' in varyCols:
            df['epoch'] = [
                adjustDate(yyddd, deltaDay)
                for yyddd, deltaDay in zip(df['epoch'], pertdf['epoch'])
            ]
            varyCols.remove('epoch')
            varyValues = varyValues[1:]

        for col in varyCols:
            df[col] = df[col] + pertdf[col]

    # Update dependant values
    df = updateDf(df, runHPOP, varyCols, setSunAreaEqualToDragArea)

    # Convert all columns to floats and round to the 10th decimal, otherwise there are some numerical rounding issues.
    cols = [
        col for col in df.columns if col not in
        ['SolarFluxFile', 'Density Model', '2nd Order Oblateness']
    ]
    df[cols] = df[cols].astype(float)
    for col in cols:
        df[col] = np.round(df[col], 10)

    # Add results
    df['LT Orbits'] = np.nan
    df['LT Years'] = np.nan
    df['LT Runtime'] = np.nan
    if runHPOP == True:
        df['HPOP Years'] = np.nan
        df['HPOP Runtime'] = np.nan

    df.index.name = 'Run ID'
    df = df.reset_index()

    df.to_csv(fileName)  # Create a new csv to store the results

    return df
Esempio n. 26
0
def test_convert_coe_and_rv_circular_equatorial(circular_equatorial):
    k, expected_res = circular_equatorial
    res = rv2coe(k, *coe2rv(k, *expected_res))
    assert_allclose(res, expected_res, atol=1e-8)
Esempio n. 27
0
def test_convert_coe_and_rv_hyperbolic(hyperbolic):
    k, expected_res = hyperbolic
    res = rv2coe(k, *coe2rv(k, *expected_res))
    assert_allclose(res, expected_res, atol=1e-8)
Esempio n. 28
0
def test_convert_between_coe_and_rv_is_transitive(expected_res):
    k = Earth.k.to(u.km**3 / u.s**2).value  # u.km**3 / u.s**2
    res = rv2coe(k, *coe2rv(k, *expected_res))
    assert_allclose(res, expected_res)