Beispiel #1
0
def test_true_to_eccentric():
    # Data from NASA-TR-R-158
    data = [
        # ecc,E (deg), nu(deg)
        (0.0, 0.0, 0.0),
        (0.05, 10.52321, 11.05994),
        (0.10, 54.67466, 59.49810),
        (0.35, 142.27123, 153.32411),
        (0.61, 161.87359, 171.02189)
    ]
    for row in data:
        ecc, expected_E, nu = row

        E = angles.nu_to_E(np.deg2rad(nu), ecc)

        assert_almost_equal(np.rad2deg(E), expected_E, decimal=4)
Beispiel #2
0
def test_true_to_eccentric():
    # Data from NASA-TR-R-158
    data = [
        # ecc,E (deg), nu(deg)
        (0.0, 0.0, 0.0),
        (0.05, 10.52321, 11.05994),
        (0.10, 54.67466, 59.49810),
        (0.35, 142.27123, 153.32411),
        (0.61, 161.87359, 171.02189)
    ]
    for row in data:
        ecc, expected_E, nu = row
        ecc = ecc * u.one
        expected_E = expected_E * u.deg
        nu = nu * u.deg

        E = angles.nu_to_E(nu, ecc)

        assert_quantity_allclose(E, expected_E, rtol=1e-6)
Beispiel #3
0
def test_true_to_eccentric():
    # Data from NASA-TR-R-158
    data = [
        # ecc,E (deg), nu(deg)
        (0.0, 0.0, 0.0),
        (0.05, 10.52321, 11.05994),
        (0.10, 54.67466, 59.49810),
        (0.35, 142.27123, 153.32411),
        (0.61, 161.87359, 171.02189)
    ]
    for row in data:
        ecc, expected_E, nu = row
        ecc = ecc * u.one
        expected_E = expected_E * u.deg
        nu = nu * u.deg

        E = angles.nu_to_E(nu, ecc)

        assert_almost_equal(E.to(u.rad).value, expected_E.to(u.rad).value,
                            decimal=4)
Beispiel #4
0
def test_eccentric_to_true_range2pi(E, ecc):
    nu = angles.E_to_nu(E, ecc)
    print(E.value, ecc.value, nu.value)
    E1 = angles.nu_to_E(nu, ecc)
    assert_quantity_allclose(E1, E, rtol=1e-8)
Beispiel #5
0
def test_eccentric_to_true_range(E, ecc):
    nu = angles.E_to_nu(E, ecc)
    E1 = angles.nu_to_E(nu, ecc)
    assert_quantity_allclose(E1, E, rtol=1e-8)
Beispiel #6
0
    def propagate(self, duration=43200, step=60):
        """
        Core method for relative trajectory generation. Inputs duration and
        time step (integers), and updates the six state arrays of the object
        (XYZ position and XYZ velocity) for N samples.

        Input:
        - duration - integer number of seconds (optional, default = 12 hours)
        - step - integer time step size (optional, default = 1 minute)
        
        Returns two numpy arrays
        - Nx3 matrix of all position vectors
        - Nx3 matrix of all velocity vector
        """

        # Check if the orbit is an ellipse (closed)
        if self.satC.ecc < 1 and self.satD.ecc < 1:

            # Get the initial mean anomaly of the chief.
            mC = E_to_M(nu_to_E(self.satC.nu, self.satC.ecc), self.satC.ecc)

            # Get the mean anomaly of the deputy.
            mD = E_to_M(nu_to_E(self.satD.nu, self.satD.ecc), self.satD.ecc)

            # Get the mean motion of the chief.
            nC = self.satC.n

            # Get the mean motion of the deputy.
            nD = self.satD.n

            # Initialise relative position and velocity component arrays.
            relPosArrayX, relPosArrayY, relPosArrayZ = [], [], []
            relVelArrayX, relVelArrayY, relVelArrayZ = [], [], []

            # Get the gravitational constant in u.km**3 / u.s**2
            mu = self.satC.attractor.k.to(u.km**3 / u.s**2)

            # Initialise pi in terms of astropy units
            pi = np.pi * 1 * u.rad

            # Get a time step in Astropy units (seconds)
            ts = step * u.s

            # For each sample...
            for t in range(0, duration, step):

                # Update the mean anomaly of the chief (loop over pi).
                mC = ((mC + pi + (nC * ts)) % (2 * pi)) - pi

                # Update the mean anomaly of the deputy (loop over pi).
                mD = ((mD + pi + (nD * ts)) % (2 * pi)) - pi

                # Compute the chief position, velocity and true anomaly.
                pC, vC, nuC = self._solve_posn(self.satC.a, self.satC.ecc,
                                               self.satC.inc, self.satC.argp,
                                               self.satC.raan, mC, mu)

                # Compute the deputy position, velocity and true anomaly.
                pD, vD, nuD = self._solve_posn(self.satD.a, self.satD.ecc,
                                               self.satD.inc, self.satD.argp,
                                               self.satD.raan, mD, mu)

                # Get the argument of latitude of the chief.
                uC = nuC + self.satC.argp
                uC = (uC + pi) % (2 * pi) - pi  # Loop over pi

                # Get the argument of latitude of the deputy.
                uD = nuD + self.satD.argp
                uD = (uD + pi) % (2 * pi) - pi  # Loop over pi

                # Get the relative argument of latitude.
                du = uD - uC
                du = (du + pi) % (2 * pi) - pi  # Loop over pi

                # Save the chief initial argument of latitude.
                if t == 0:
                    uC0 = uC

                # Compute the deputy elapsed argument of latitude.
                uD_elapsed = uD - uC0
                uD_elapsed = (uD_elapsed + pi) % (2 * pi) - pi
                uD_elapsed = uD_elapsed.to_value(u.rad)

                # Compute the velocity magnitude
                vCMag = np.sqrt(vC[0]**2 + vC[1]**2 + vC[2]**2)

                # Initialize the time-dependent input vector
                uVect = np.array([1.0, uD_elapsed, np.cos(uC), np.sin(uC)])

                # Update Row 1 Column 0 of the state transition matrix.
                self.M[1][0] = du.to_value(u.rad) + self.dR

                # We may now compute the normalized relative state vectors
                relPos = np.matmul(self.M[:3], uVect)
                relVel = np.matmul(self.M[3:], uVect)

                # Un-normalize the relative position vectors
                relPosArrayX.append((relPos[0] * self.satC.a).to_value(u.km))
                relPosArrayY.append((relPos[1] * self.satC.a).to_value(u.km))
                relPosArrayZ.append((relPos[2] * self.satC.a).to_value(u.km))

                # Un-normalize the relative velocity vectors
                relVelArrayX.append((relVel[0] * vCMag).to_value(u.km / u.s))
                relVelArrayY.append((relVel[1] * vCMag).to_value(u.km / u.s))
                relVelArrayZ.append((relVel[2] * vCMag).to_value(u.km / u.s))

            # Save the entire relativeEphem matrix.
            self.relPosArrayX = np.array(relPosArrayX) * (1 * u.km)
            self.relPosArrayY = np.array(relPosArrayY) * (1 * u.km)
            self.relPosArrayZ = np.array(relPosArrayZ) * (-1 * u.km)
            self.relVelArrayX = np.array(relVelArrayX) * (1 * u.km / u.s)
            self.relVelArrayY = np.array(relVelArrayY) * (1 * u.km / u.s)
            self.relVelArrayZ = np.array(relVelArrayZ) * (-1 * u.km / u.s)

            # To allow for chaining...
            return self

        # Or if the orbit is a para/hyperbola...
        else:
            print('Error! Formations for non-closed orbits not supported!')
            return self
Beispiel #7
0

if __name__ == "__main__":

    # Display some initial data
    print(f" Orbit: {iss}")
    print(" State vector [poliastro]")
    print(f"     r = {iss.r}")
    print(f"     v = {iss.v}")
    print()

    # Reference epoch
    epoch = Time(iss.epoch, format="datetime", scale="utc")

    # Store poliastro orbital elements (osculating)
    ecc_anomaly = angles.nu_to_E(iss.nu, iss.ecc)
    mean_anomaly = angles.E_to_M(ecc_anomaly, iss.ecc)

    # Compute orbital elements required by spg4 (mean)
    inc, raan, ecc, argp, m_ano, m_mot = rv2el(iss.r, iss.v, iss.epoch)

    # Display differences
    print("                Poliastro(osc)              rv2el(mean)")
    print(f"Ecc            :    {iss.ecc:10.5f}{'':15}{ecc:10.5f}")
    print(
        f"Incl  [deg]    :    {math.degrees(iss.inc.value):10.5f}{'':15}{math.degrees(inc):10.5f}"
    )
    print(
        f"n [deg/min]    :    {math.degrees(iss.n.to(u.rad/u.minute).value):10.5f}{'':15}{math.degrees(m_mot):10.5f}"
    )
    print(
Beispiel #8
0
def test_eccentric_to_true_range(E, ecc):
    nu = E_to_nu(E, ecc)
    E_result = nu_to_E(nu, ecc)
    assert_quantity_allclose(E_result, E, rtol=1e-8)
Beispiel #9
0
def test_eccentric_to_true_range2pi(E, ecc):
    nu = angles.E_to_nu(E, ecc)
    print(E.value, ecc.value, nu.value)
    E1 = angles.nu_to_E(nu, ecc)
    assert_quantity_allclose(E1, E, rtol=1e-8)