Exemple #1
0
def test_dot_constant_for_linear_values(name, ipset_linear):
    """Test that the derivative is constant for linear values"""
    _, y_dot = interpolation.interpolate_with_derivative(*ipset_linear,
                                                         kind=name,
                                                         **IPARGS.get(
                                                             name, {}))
    assert np.allclose(y_dot, y_dot.mean())
Exemple #2
0
def calculate_initial_values(eph, rundate):
    """Computing initial values for position and velocity in GCRS system

    This is for later use in orbit integration, from tables in the prediction files.  Use a lagrange polynomial in
    order to interpolate in the tables.

    Args:
        eph:  Dict containing ephemeris information

    Returns:
        eph:  Dict where the initial position and velocity is added
    """
    pos_gcrs = np.empty((3, 0))
    times = np.empty((0))
    table_of_positions = sorted(eph["positions"].items())
    mjd1, mjd2 = zip(*[t for t, d in table_of_positions])

    for pos_time, (_, data) in zip(time.Time(val=mjd1, val2=mjd2, fmt="mjd", scale="utc"), table_of_positions):
        diffsec = (pos_time.utc.datetime - rundate).total_seconds()
        # Only look at points close to rundate (start of integration)
        # if abs(diffsec) > 4000:
        #    continue
        # Table given in ITRF coordinate system. Convert to GCRS, where the integration of the satellite orbit will
        # be done

        pos_gcrs = np.hstack((pos_gcrs, np.transpose([rotation.trs2gcrs(pos_time) @ data["pos"]])))
        times = np.hstack((times, diffsec))

    log.info("Interpolating data from prediction file in order to get initial pos/vel")
    pos_gcrs_ip, vel_gcrs_ip = interpolation.interpolate_with_derivative(
        times, np.transpose(pos_gcrs), np.array([0.0]), kind="lagrange", window=10, bounds_error=False
    )
    eph["initial_pos"] = pos_gcrs_ip[0]
    eph["initial_vel"] = vel_gcrs_ip[0]
    return eph
Exemple #3
0
def calculate_initial_values(eph, rundate):
    """Computing initial values for position and velocity in GCRS system

    This is for later use in orbit integration, from tables in the prediction files.  Use a lagrange polynomial in
    order to interpolate in the tables.

    Args:
        eph:  Dict containing ephemeris information

    Returns:
        eph:  Dict where the initial position and velocity is added
    """
    data = sorted(eph["positions"].items())
    pos_itrs = np.zeros((len(data), 3))
    mjd1, mjd2 = zip(*[t for t, d in data])
    rotation_mat = rotation.trs2gcrs(
        time.Time(val=mjd1, val2=mjd2, fmt="mjd", scale="utc"))
    tbl = time.Time(val=mjd1, val2=mjd2, fmt="mjd", scale="utc")

    for i in range(0, len(data)):
        pos_itrs[i] = data[i][1]["pos"]

    diffsec = np.array([(t - rundate).total_seconds()
                        for t in tbl.utc.datetime])

    # Table given in ITRF coordinate system. Convert to GCRS, where the integration of the satellite orbit will
    # be done

    pos_gcrs = np.sum(rotation_mat @ pos_itrs[:, :, None], axis=2)
    log.info(
        "Interpolating data from prediction file in order to get initial pos/vel"
    )
    pos_gcrs_ip, vel_gcrs_ip = interpolation.interpolate_with_derivative(
        diffsec,
        pos_gcrs,
        np.array([0.0]),
        kind="lagrange",
        window=10,
        bounds_error=False)
    eph["initial_pos"] = pos_gcrs_ip[0]
    eph["initial_vel"] = vel_gcrs_ip[0]

    return eph
Exemple #4
0
def calculate(stage, dset):
    """
    Integrate differential equation of motion of the satellite

    Args:
        stage:  Name of current stage
        dset:   Dataset containing the data
    """

    iterations = config.tech.iterations.int

    # Run models adjusting station positions
    site.calculate_site("site", dset)
    delta_pos = site.add("site", dset)
    dset.site_pos[:] = (dset.site_pos.gcrs + delta_pos[0].gcrs).trs

    dset.add_float("obs",
                   val=dset.time_of_flight * constant.c / 2,
                   unit="meter")
    dset.add_float("calc", np.zeros(dset.num_obs), unit="meter")
    dset.add_float("residual", np.zeros(dset.num_obs), unit="meter")
    dset.add_float("up_leg", np.zeros(dset.num_obs), unit="second")
    dset.add_posvel("sat_pos",
                    np.zeros((dset.num_obs, 6)),
                    system="gcrs",
                    time=dset.time)
    arc_length = config.tech.arc_length.float

    dset.site_pos.other = dset.sat_pos

    # First guess for up_leg:
    dset.up_leg[:] = dset.time_of_flight / 2

    for iter_num in itertools.count(start=1):
        log.blank()
        log.info(f"Calculating model corrections for iteration {iter_num}")

        sat_time_list = dset.obs_time + dset.time_bias + dset.up_leg
        apriori_orbit_provider = config.tech.apriori_orbit.str
        sat_name = dset.vars["sat_name"]

        rundate = dset.analysis["rundate"]

        if apriori_orbit_provider:
            version = config.tech.apriori_orbit_version.str
            log.info(
                f"Using external orbits from {apriori_orbit_provider}, version {version}"
            )
            apriori_orbit = apriori.get(
                "orbit",
                rundate=rundate + timedelta(days=arc_length),
                time=None,
                day_offset=6,
                satellite=sat_name,
                apriori_orbit="slr",
                file_key="slr_external_orbits",
            )
            dset_external = apriori_orbit._read(dset, apriori_orbit_provider,
                                                version)

            sat_pos = dset_external.sat_pos.gcrs_pos
            t_sec = TimeDelta(
                dset_external.time -
                Time(datetime(rundate.year, rundate.month, rundate.day),
                     scale="utc",
                     fmt="datetime"),
                fmt="seconds",
            )
            t_sec = t_sec.value
        else:
            sat_pos, sat_vel, t_sec = orbit.calculate_orbit(
                datetime(rundate.year, rundate.month, rundate.day),
                sat_name,
                sat_time_list,
                return_full_table=True)

        sat_pos_ip, sat_vel_ip = interpolation.interpolate_with_derivative(
            np.array(t_sec),
            sat_pos,
            sat_time_list,
            kind="interpolated_univariate_spline")
        dset.sat_pos.gcrs[:] = np.concatenate((sat_pos_ip, sat_vel_ip), axis=1)
        delay.calculate_delay("kinematic_models", dset)

        # We observe the time when an observation is done, and the time of flight of the laser pulse. We estimate
        # the up-leg time with Newton's method applied to the equation (8.84) of :cite:'beutler2005' Gerhard Beutler:
        # Methods of Celestial Mechanics, Vol I., 2005.
        for j in range(0, 4):
            reflect_time = dset.time + TimeDelta(
                dset.time_bias + dset.up_leg, fmt="seconds", scale="utc")
            site_pos_reflect_time = (rotation.trs2gcrs(reflect_time)
                                     @ dset.site_pos.trs.val[:, :, None])[:, :,
                                                                          0]
            sta_sat_vector = dset.sat_pos.gcrs.pos.val - site_pos_reflect_time
            unit_vector = sta_sat_vector / np.linalg.norm(sta_sat_vector,
                                                          axis=1)[:, None]

            rho12 = (np.linalg.norm(sta_sat_vector, axis=1) +
                     delay.add("kinematic_models", dset)) / constant.c
            correction = (-dset.up_leg + rho12) / (
                np.ones(dset.num_obs) - np.sum(
                    unit_vector / constant.c * dset.sat_pos.vel.val, axis=1))
            dset.up_leg[:] += correction
            sat_time_list = dset.obs_time + dset.time_bias + dset.up_leg
            sat_pos_ip, sat_vel_ip = interpolation.interpolate_with_derivative(
                np.array(t_sec),
                sat_pos,
                sat_time_list,
                kind="interpolated_univariate_spline")

            dset.sat_pos.gcrs[:] = np.concatenate((sat_pos_ip, sat_vel_ip),
                                                  axis=1)

        delay.calculate_delay("satellite_models", dset)
        dset.calc[:] = delay.add("satellite_models", dset)
        dset.residual[:] = dset.obs - dset.calc
        log.info(
            f"{dset.num_obs} observations, residual = {dset.rms('residual'):.4f}"
        )
        if not apriori_orbit_provider:
            orbit.update_orbit(sat_name, dset.site_pos.gcrs, dset.sat_pos.pos,
                               dset.sat_pos.vel, dset.residual, dset.bin_rms)

        dset.write_as(stage=stage, label=iter_num, sat_name=sat_name)
        if iter_num >= iterations:
            break
Exemple #5
0
    def _calculate(self, dset):
        """Calculate precise orbits and satellite clock correction for given observation epochs

        The satellite position is determined for each observation epoch by interpolating within the given SP3 orbit time
        entries. The satellite velocities are calculated based on satellite positions 0.5 second before and after the
        observation epoch.

        Args:
            dset (Dataset): Dataset representing calculated precise orbits with following fields:

        ========================  ===============  =======  ========================================================
         Field                     Type             Unit     Description
        ========================  ===============  =======  ========================================================
         gnss_satellite_clock     numpy.ndarray     m       Satellite clock correction
         gnss_relativistic_clock  numpy.ndarray     m       Relativistic clock correction due to orbit eccentricity
         sat_posvel               PosVelTable       m       Satellite position and velocity
         satellite                numpy.ndarray             Satellite numbers
         system                   numpy.ndarray             GNSS identifiers
         time                     TimeTable                 Observation epochs
        =======================  ===============  =======  ========================================================
        """
        # Check if satellites are given in SP3 file
        # TODO: Another solution has to be found for satellites not given in SP3 file, e.g. use of broadcast
        #       ephemeris.
        not_available_sat = set(self.satellite) - set(self.dset_edit.satellite)
        if not_available_sat:
            log.fatal(
                "Satellites {} are not given in precise orbit file {}.",
                ", ".join(sorted(not_available_sat)),
                self.dset_edit.meta["parser"]["file_path"],
            )

        log.info(
            "Calculating satellite position/velocity (precise) based on SP3 precise orbit file {}.",
            ", ".join(self.dset_edit.meta["parser"]["file_path"]),
        )

        dset.vars["orbit"] = self.name
        dset.num_obs = len(self.time)
        dset.add_time("time", val=self.time, scale=self.time.scale)
        dset.add_text("satellite", val=self.satellite)
        dset.add_text("system", val=self.system)

        sat_pos = np.zeros((dset.num_obs, 3))
        sat_vel = np.zeros((dset.num_obs, 3))
        ref_time = dset.time[0]  # Reference epoch used for interpolation

        # Loop over all given satellites
        for sat in set(self.satellite):

            log.debug("Interpolation for satellite: {}", sat)

            # Get array with information about, when observation are available for the given satellite (indicated by
            # True)
            idx = dset.filter(satellite=sat)
            orb_idx = self.dset_edit.filter(satellite=sat)

            if np.min(dset.time[idx].gps.mjd) < np.min(
                    self.dset_edit.time[orb_idx].mjd):
                log.fatal(
                    "Interpolation range is exceeded by satellite {} ( {} [epoch] < {} [precise orbit])."
                    "".format(
                        sat, np.max(dset.time[idx].gps.datetime),
                        np.max(self.dset_edit.time[orb_idx].gps.datetime)))

            if np.max(dset.time[idx].gps.mjd) > np.max(
                    self.dset_edit.time[orb_idx].mjd):
                log.fatal(
                    "Interpolation range is exceeded by satellite {} ({} [epoch] > {} [precise orbit])."
                    "".format(
                        sat, np.max(dset.time[idx].gps.datetime),
                        np.max(self.dset_edit.time[orb_idx].gps.datetime)))

            # Interpolation for given observation epochs (transmission time)
            sat_pos[idx], sat_vel[
                idx] = interpolation.interpolate_with_derivative(
                    self.dset_edit.time[orb_idx].gps.sec_to_reference(
                        ref_time),
                    self.dset_edit.sat_pos.itrs[orb_idx],
                    dset.time[idx].gps.sec_to_reference(ref_time),
                    kind="lagrange",
                    window=10,
                    dx=0.5,
                )

            if np.isnan(np.sum(sat_pos[idx])) or np.isnan(np.sum(
                    sat_vel[idx])):
                log.fatal(
                    "NaN occurred by determination of precise satellite position and velocity for satellite {}.",
                    sat)

        # Add satellite clock correction to Dataset
        dset.add_float("gnss_satellite_clock",
                       val=self.satellite_clock_correction(),
                       unit="meter")

        # Add satellite position and velocity to Dataset
        dset.add_posvel("sat_posvel",
                        time="time",
                        itrs=np.hstack((sat_pos, sat_vel)))

        # Add relativistic clock correction to Dataset
        dset.add_float("gnss_relativistic_clock",
                       val=self.relativistic_clock_correction(),
                       unit="meter")

        # +DEBUG
        # for num_obs  in range(0, dset.num_obs):
        #    print('DEBUG: ', dset.satellite[num_obs],
        #                     dset.time.gps.datetime[num_obs],
        #                     dset.time.gps.mjd_frac[num_obs]*24*3600,
        #                     ' '.join([str(v) for v in dset.sat_posvel.itrs_pos[num_obs]]),
        #                     dset.gnss_satellite_clock[num_obs],
        #                     dset.gnss_relativistic_clock[num_obs])
        # -DEBUG

        return dset
Exemple #6
0
    def _calculate(self,
                   dset_out: "Dataset",
                   dset_in: "Dataset",
                   time: str = "time") -> None:
        """Calculate precise orbits and satellite clock correction for given observation epochs

        As a first step observations are removed from unavailable satellites and for exceeding the interpolation
        boundaries. The input Dataset contains observation epochs for which the broadcast ephemeris and satellite
        clock correction should be determined. The satellite position is determined for each observation epoch by
        interpolating within the given SP3 orbit time entries. The satellite velocities are calculated based on
        satellite positions 0.5 second before and after the observation epoch.

        Args:
            dset_out (Dataset): Dataset representing calculated precise orbits with following fields:

        ========================  ===============  =======  ========================================================
         Field                     Type             Unit     Description
        ========================  ===============  =======  ========================================================
         gnss_satellite_clock     numpy.ndarray     m       Satellite clock correction
         gnss_relativistic_clock  numpy.ndarray     m       Relativistic clock correction due to orbit eccentricity
         sat_posvel               PosVelTable       m       Satellite position and velocity
         satellite                numpy.ndarray             Satellite numbers
         system                   numpy.ndarray             GNSS identifiers
         time                     TimeTable                 Observation epochs
        =======================  ===============  =======  ========================================================

            dset_in:  Input Dataset containing model data for which broadcast ephemeris should be determined.
            time: Define time fields to be used. It can be for example 'time' or 'sat_time'. 'time' is related to 
                  observation time and 'sat_time' to satellite transmission time.
        """
        # Clean orbits by removing unavailable satellites, unhealthy satellites and checking interpolation boundaries
        cleaners.apply_remover("gnss_clean_orbit",
                               dset_in,
                               orbit_flag="precise")

        # TODO: Another solution has to be found for satellites not given in SP3 file, e.g. use of broadcast
        #       ephemeris.

        log.info(
            f"Calculating satellite position/velocity (precise) based on SP3 precise orbit file "
            f"{', '.join(self.dset_edit.meta['parser']['file_path'])}")

        sat_pos = np.zeros((dset_in.num_obs, 3))
        sat_vel = np.zeros((dset_in.num_obs, 3))
        ref_time = dset_in[time][0]  # Reference epoch used for interpolation

        # Loop over all given satellites
        for sat in set(dset_in.satellite):

            log.debug(f"Interpolation for satellite: {sat}")

            # Get array with information about, when observation are available for the given satellite (indicated by
            # True)
            idx = dset_in.filter(satellite=sat)
            orb_idx = self.dset_edit.filter(satellite=sat)

            if np.min(dset_in[time][idx].gps.mjd) < np.min(
                    self.dset_edit.time[orb_idx].mjd):
                log.fatal(
                    f"Interpolation range is exceeded by satellite {sat} ({np.max(dset_in[time][idx].gps.datetime)} "
                    f"[epoch] < {np.max(self.dset_edit.time[orb_idx].gps.datetime)} [precise orbit])"
                )

            if np.max(dset_in[time][idx].gps.mjd) > np.max(
                    self.dset_edit.time[orb_idx].mjd):
                log.fatal(
                    f"Interpolation range is exceeded by satellite {sat} ({np.max(dset_in[time][idx].gps.datetime)} "
                    f"[epoch] > {np.max(self.dset_edit.time[orb_idx].gps.datetime)} [precise orbit])"
                )

            # Interpolation for given observation epochs (transmission time)
            diff_time_points = ref_time.gps - self.dset_edit.time.gps[orb_idx]
            diff_time_obs = ref_time.gps - dset_in[time].gps[idx]
            sat_pos[idx], sat_vel[
                idx] = interpolation.interpolate_with_derivative(
                    # self.dset_edit.time[orb_idx].gps.sec_to_reference(ref_time),
                    diff_time_points.seconds,
                    self.dset_edit.sat_pos.trs[orb_idx],
                    # dset_in[time][idx].gps.sec_to_reference(ref_time),
                    diff_time_obs.seconds,
                    kind="lagrange",
                    window=10,
                    dx=0.5,
                )

            if np.isnan(np.sum(sat_pos[idx])) or np.isnan(np.sum(
                    sat_vel[idx])):
                log.fatal(
                    f"NaN occurred by determination of precise satellite position and velocity for satellite {sat}"
                )

        # Copy fields from model data Dataset
        dset_out.num_obs = dset_in.num_obs
        dset_out.add_text("satellite", val=dset_in.satellite)
        dset_out.add_text("system", val=dset_in.system)
        dset_out.add_time("time", val=dset_in[time])
        dset_out.vars["orbit"] = self.name

        # Add float fields
        dset_out.add_float("gnss_relativistic_clock",
                           val=self.relativistic_clock_correction(
                               sat_pos, sat_vel),
                           unit="meter")
        dset_out.add_float("gnss_satellite_clock",
                           val=self.satellite_clock_correction(dset_in,
                                                               time=time),
                           unit="meter")

        # Add satellite position and velocity to Dataset
        dset_out.add_posvel("sat_posvel",
                            time=dset_out.time,
                            system="trs",
                            val=np.hstack((sat_pos, sat_vel)))