示例#1
0
    def _run_propagation(self, init_coords, time_list):
        """Solves the ODE or runs the actual propagation.

        Parameters
        ----------
        init_coords : SkyCoord
            Initial coordinates (the first value is used)
        time_list : Time
            Time list for outputs
        Returns
        -------
        SkyCoord
            The output coordinates corresponding to `time_list`
        """

        # generate the time list since epoch (in seconds)
        t_list_epoch = (time_list - time_list[0]).to_value(u.s)

        # concat the init vector
        rv_init = [
            *init_coords.cartesian.without_differentials().xyz.to_value(u.km),
            *init_coords.velocity.d_xyz.to_value(u.km / u.s),
        ]

        # noinspection PyTypeChecker
        solver = solve_ivp(
            self._ode_diff_eqns,
            (t_list_epoch[0], t_list_epoch[-1]),
            rv_init,
            method=self._solver_type.value,
            dense_output=True,
            rtol=self.rtol,
            atol=self.atol,
        )

        r_list = np.empty((3, len(t_list_epoch)))
        v_list = np.empty((3, len(t_list_epoch)))
        # Fill the raw output data
        i = 0
        for t in t_list_epoch:
            rv = solver.sol(t)
            r_list[:, i] = rv[:3]
            v_list[:, i] = rv[3:]
            i = i + 1

        # Load the time, pos, vel info into astropy objects (shallow copied)
        rv_list = CartesianRepresentation(
            r_list, unit=u.km).with_differentials(
                CartesianDifferential(v_list, unit=u.km / u.s))

        coords_list = init_pvt(self.central_body.inert_coord,
                               time_list,
                               rv_list,
                               copy=False)

        return coords_list
示例#2
0
    def __call__(self, t):
        """
        Computes the interpolated coordinates at the given time(s).

        Parameters
        ----------
        t : Time
            Time or list of times where an interpolated coordinate is required

        Returns
        -------
        coords : SkyCoord
           A `SkyCoord` object with the requested coordinate(s), in the
           original frame

        Raises
        ------
        ValueError
            If the requested `t` value is out of bounds for the interpolator

        """
        if not self._interpolators_initialised:
            # Lazy init interpolators only when required
            self._init_interpolators()

        # **** get coords at requested time ****

        # compute raw r and v vectors and
        # fill Astropy cartesian vectors (with velocities if available)
        if t.isscalar:
            # there is a single time instance
            coords = CartesianRepresentation(self._compute_pos(t), copy=False)
            if self._has_velocity:
                v = CartesianDifferential(self._compute_vel(t), copy=False)
                coords = coords.with_differentials(v)
        else:
            # there is more than one time instance
            r = [self._compute_pos(time) for time in t]
            coords = CartesianRepresentation(
                np.asarray(r), unit=r[0].unit, copy=False, xyz_axis=1
            )

            if self._has_velocity:
                v = [self._compute_vel(time) for time in t]
                v = CartesianDifferential(
                    np.asarray(v), unit=v[0].unit, copy=False, xyz_axis=1
                )
                coords = coords.with_differentials(v)

        return init_pvt(self._frame_name, t, coords)
def test_init_cart():
    """Tests the cartesian initialisation convenience method."""

    rv_gcrs_true_sky = SkyCoord(rv_gcrs_true)

    # easy init
    rv_gcrs_0 = init_pvt(GCRS, time, r_gcrs_true, v_gcrs_true)

    # init with str frame name (should be lowercase letters)
    rv_gcrs_1 = init_pvt("GCRS", time, r_gcrs_true, v_gcrs_true)

    # init without velocity
    rv_gcrs_2 = init_pvt(GCRS, time, r_gcrs_true, copy=False)

    assert rv_gcrs_0 == rv_gcrs_true_sky
    assert rv_gcrs_1 == rv_gcrs_true_sky
    assert rv_gcrs_2 == SkyCoord(
        GCRS(
            r_gcrs_true,
            obstime=time,
            representation_type="cartesian",
            differential_type="cartesian",
        ))
def test_cb_crs_to_icrs_sun():
    """Check the basic quasi-round-trip accuracy for the generic Central Body Celestial
    Reference System, using Sun (equal to HCRS). Converts Sun CRS to ICRS, then ICRS to
    HCRS."""
    allowable_pos_diff = 5e-4 * u.mm
    allowable_vel_diff = 0.0001 * u.mm / u.s

    rv_suncrs_true = init_pvt(_SunCRS, time,
                              r_gcrs_true.with_differentials(v_gcrs_true))

    rv_icrs = rv_suncrs_true.transform_to(ICRS)

    rv_hcrs = rv_icrs.transform_to(HCRS)

    r_diff = pos_err(rv_hcrs, rv_suncrs_true)
    v_diff = vel_err(rv_hcrs, rv_suncrs_true)

    # print(f"r {rv_hcrs.name} diff      :  {r_diff}")
    # print(f"v {rv_hcrs.name} diff      :  {v_diff}")

    assert r_diff < allowable_pos_diff
    assert v_diff < allowable_vel_diff
示例#5
0
def parse_rv_line(rv_line, coord_sys):
    """Converts a line of t, r, v string into a SkyCoord object."""

    rv_items = [elem for elem in rv_line.strip().split(" ") if elem]

    time = Time(rv_items[0], scale="utc")

    v = CartesianDifferential(
        [float(rv_items[4]),
         float(rv_items[5]),
         float(rv_items[6])],
        unit=u.km / u.s,
    )
    r = CartesianRepresentation(
        [float(rv_items[1]),
         float(rv_items[2]),
         float(rv_items[3])],
        unit=u.km)

    rv_init = init_pvt(coord_sys, time, r.with_differentials(v))

    return rv_init
示例#6
0
def propagation_engine(line1, line2, time_list):
    """Tests the interpolation accuracy for a given TLE."""

    # Init satellite object from the TLE
    sat = Satrec.twoline2rv(line1, line2)

    # ****** Generate the pos, vel vectors for each time instant ******

    # Run the propagation and init pos and vel vectors in TEME
    e, r_list, v_list = sat.sgp4_array(time_list.jd1, time_list.jd2)

    # Load the time, pos, vel info into astropy objects (shallow copied)
    vel_list = CartesianDifferential(v_list, unit=u.km / u.s, xyz_axis=1)
    pos_list = CartesianRepresentation(r_list, unit=u.km,
                                       xyz_axis=1).with_differentials(vel_list)

    # trajectory in astropy
    traj_astropy = init_pvt(TEME, time_list, pos_list)

    # Init trajectory in Trajectory object
    trajectory = Trajectory(traj_astropy)

    return {"traj": trajectory, "sat": sat}
def test_equatorial_mars():
    """NASA HORIZONS/GMAT testing between CRS and TOD & J2000 Equatorial
    as well as Body Fixed (GMAT).

    GMAT and HORIZONS use a different model in the IAU polar rotation parameters
    (IAU 2000). Therefore test setup uses this version but not IAU 2015 versions.

    Satellite orbit is taken from Mars Reconnaissance Orbiter,
    using the NASA Horizons Web Interface (https://ssd.jpl.nasa.gov/horizons.cgi)."""

    obstime = Time("2020-01-10T11:30:00.0003", scale="tdb")

    v_eq_horz = CartesianDifferential(
        [-2.061955207079347, -2.671302888480574, 0.269551765393186],
        unit=u.km / u.s,
    )
    r_eq_horz = CartesianRepresentation(
        [322.259677663235, 120.3781499221643, 3676.074343158492], unit=u.km)
    rv_eq_horz = init_pvt(_MarsIAU2000TODEquatorial, obstime, r_eq_horz,
                          v_eq_horz)

    v_inert_horz = CartesianDifferential(
        [-2.062805178080304, -2.670750348642094, 0.2685217398016297],
        unit=u.km / u.s,
    )
    r_inert_horz = CartesianRepresentation(
        [321.472501283011, 119.500545946684, 3676.171898278387], unit=u.km)
    rv_inert_horz = init_pvt(_MarsIAU2000J2000Equatorial, obstime,
                             r_inert_horz, v_inert_horz)

    v_body_fixed_gmat = CartesianDifferential(
        [0.622659762445902, 3.329753468204519, 0.2695517652769852],
        unit=u.km / u.s,
    )
    r_body_fixed_gmat = CartesianRepresentation(
        [-233.7124768823157, -252.4295484193542, 3676.074343157078], unit=u.km)
    rv_body_fixed_gmat = init_pvt(_MarsIAU2000BodyFixed, obstime,
                                  r_body_fixed_gmat, v_body_fixed_gmat)

    allowable_pos_diff = 800 * u.mm
    allowable_vel_diff = 0.35 * u.mm / u.s

    # init CRS - modify frame name to point at test coords
    pvt_crs = _init_orbit_mars()
    pvt_crs.frame.body_name = "Mars_IAU_2000"

    # Convert to TOD Equatorial
    pvt_tod_eq = pvt_crs.transform_to(_MarsIAU2000TODEquatorial)
    # Convert to J2000 Equatorial
    pvt_j2000_eq = pvt_crs.transform_to(_MarsIAU2000J2000Equatorial)
    # Convert to Body Fixed
    pvt_body_fixed = pvt_crs.transform_to(_MarsIAU2000BodyFixed)

    print(pvt_crs)
    print(pvt_tod_eq)
    print(pvt_j2000_eq)
    print(pvt_body_fixed)

    print(pos_err(pvt_body_fixed, rv_body_fixed_gmat))
    print(vel_err(pvt_body_fixed, rv_body_fixed_gmat))

    # Diff between TOD Eq values
    assert pos_err(pvt_tod_eq, rv_eq_horz) < allowable_pos_diff
    assert vel_err(pvt_tod_eq, rv_eq_horz) < allowable_vel_diff

    # Diff between J2000 Eq (Inertial) values
    assert pos_err(pvt_j2000_eq, rv_inert_horz) < allowable_pos_diff
    assert vel_err(pvt_j2000_eq, rv_inert_horz) < allowable_vel_diff

    # Diff between Body Fixed values
    assert pos_err(pvt_body_fixed, rv_body_fixed_gmat) < allowable_pos_diff
    assert vel_err(pvt_body_fixed, rv_body_fixed_gmat) < allowable_vel_diff
def test_init_cart_wrong_time():
    """Tests cartesian init with incorrect frame name."""
    with pytest.raises(TypeError):
        # noinspection PyTypeChecker
        init_pvt("GCRS", "2004-04-06T07:51:28.386009", r_gcrs_true,
                 v_gcrs_true)
def test_init_cart_wrong_frame():
    """Tests cartesian init with incorrect frame name."""
    with pytest.raises(ValueError):
        init_pvt("GCRSx", time, r_gcrs_true, v_gcrs_true)
示例#10
0
    def to_cartesian(self):
        """
        Converts the orbital elements to the cartesian coordinates in the
        local inertial frame of the central body.

        Returns
        -------
        SkyCoord
            cartesian coordinates in the local inertial frame of the central body

        Raises
        ------
        ValueError
            Parabolic orbits or singularity
        """

        # shorthands
        a = self.sm_axis
        i = self.inclination
        e = self.eccentricity
        argp = self.arg_periapsis
        raan = self.raan
        nu = self.true_anomaly
        node = argp + nu
        mu = self.central_body.mu

        p = a * (1 - e**2)

        r = p / (1 + e * np.cos(nu))

        # compute position components
        x = r * (np.cos(node) * np.cos(raan) -
                 np.cos(i) * np.sin(node) * np.sin(raan))
        y = r * (np.cos(node) * np.sin(raan) +
                 np.cos(i) * np.sin(node) * np.cos(raan))
        z = r * (np.sin(node) * np.sin(i))

        # If orbit is too close to parabolic, raise error.
        if np.abs(p) < 1e-30 * u.km:
            raise ValueError(
                "Orbit eccentricity is close to 1. Parabolic orbits are not allowed."
            )

        sqrt_mup = np.sqrt(mu / p)

        # compute velocity components
        v_x = sqrt_mup * (np.cos(nu) + e) * (
            -np.sin(argp) * np.cos(raan) -
            np.cos(i) * np.sin(raan) * np.cos(argp)
        ) - sqrt_mup * np.sin(nu) * (np.cos(argp) * np.cos(raan) -
                                     np.cos(i) * np.sin(raan) * np.sin(argp))

        v_y = sqrt_mup * (np.cos(nu) + e) * (
            -np.sin(argp) * np.sin(raan) +
            np.cos(i) * np.cos(raan) * np.cos(argp)
        ) - sqrt_mup * np.sin(nu) * (np.cos(argp) * np.sin(raan) +
                                     np.cos(i) * np.cos(raan) * np.sin(argp))
        v_z = sqrt_mup * ((np.cos(nu) + e) * np.sin(i) * np.cos(argp) -
                          np.sin(i) * np.sin(nu) * np.sin(argp))

        # collate the SkyCoord object
        time = self.epoch.replicate()
        r = CartesianRepresentation([x, y, z], unit=u.km)
        v = CartesianDifferential(
            [v_x, v_y, v_z],
            unit=u.km / u.s,
        )

        rv_init = init_pvt(self.central_body.inert_coord, time,
                           r.with_differentials(v))

        return rv_init