Esempio n. 1
0
    def compute_lonlat(self, width, utcs=None, clock_drift_adjust=True):
        """Compute lat/lon coordinates.

        Args:
            width: Number of coordinates per scanlines
            utcs: Scanline timestamps
            clock_drift_adjust: If True, adjust clock drift.
        """
        tle1, tle2 = self.get_tle_lines()

        scan_points = np.arange(3.5, 2048, 5)

        if utcs is None:
            utcs = self.get_times()

        # adjusting clock for drift
        tic = datetime.datetime.now()
        if clock_drift_adjust:
            from pygac.clock_offsets_converter import get_offsets
            try:
                offset_times, clock_error = get_offsets(self.spacecraft_name)
            except KeyError:
                LOG.info("No clock drift info available for %s",
                         self.spacecraft_name)
            else:
                offset_times = np.array(offset_times, dtype='datetime64[ms]')
                offsets = np.interp(utcs.astype(np.uint64),
                                    offset_times.astype(np.uint64),
                                    clock_error)
                utcs -= (offsets * 1000).astype('timedelta64[ms]')

        t = utcs[0].astype(datetime.datetime)

        if "constant_yaw_attitude_error" in self.head.dtype.fields:
            rpy = np.deg2rad([
                self.head["constant_roll_attitude_error"] / 1e3,
                self.head["constant_pitch_attitude_error"] / 1e3,
                self.head["constant_yaw_attitude_error"] / 1e3
            ])
        else:
            rpy = [0, 0, 0]

        LOG.info("Using rpy: %s", str(rpy))

        from pyorbital.geoloc_instrument_definitions import avhrr_gac
        from pyorbital.geoloc import compute_pixels, get_lonlatalt
        sgeom = avhrr_gac(utcs.astype(datetime.datetime), scan_points, 55.385)
        s_times = sgeom.times(t)

        pixels_pos = compute_pixels((tle1, tle2), sgeom, s_times, rpy)
        pos_time = get_lonlatalt(pixels_pos, s_times)

        toc = datetime.datetime.now()

        LOG.warning("Computation of geolocation: %s", str(toc - tic))

        lons, lats = pos_time[:2]

        return lons.reshape(-1, width), lats.reshape(-1, width)
Esempio n. 2
0
    def _adjust_clock_drift(self):
        """Adjust the geolocation to compensate for the clock error."""
        tic = datetime.datetime.now()
        self.get_times()
        try:
            error_utcs, clock_error = get_offsets(self.spacecraft_name)
        except KeyError:
            LOG.info("No clock drift info available for %s",
                     self.spacecraft_name)
            return

        error_utcs = np.array(error_utcs, dtype='datetime64[ms]')
        # interpolate to get the clock offsets at the scan line utcs
        # the clock_error is given in seconds, so offsets are in seconds, too.
        offsets = np.interp(self.utcs.astype(np.uint64),
                            error_utcs.astype(np.uint64),
                            clock_error)
        LOG.info("Adjusting for clock drift of %s to %s seconds.",
                 str(min(offsets)),
                 str(max(offsets)))

        # For the interpolation of geolocations, we need to prepend/append
        # lines. The conversion from offset to line numbers is given by the
        # scan rate = 1/scan frequency.
        scan_rate = datetime.timedelta(milliseconds=1/self.scan_freq)
        offset_lines = offsets / scan_rate.total_seconds()

        # To avoid trouble with missing lines, we will construct an
        # array that covers the whole interpolation range.
        scan_lines = self.scans["scan_line_number"]
        shifted_lines = scan_lines - offset_lines
        shifted_lines_floor = np.floor(shifted_lines).astype(int)
        # compute the line range, note that the max requires a "+1"
        # to cover the interpolation range because of the floor.
        min_line = min(scan_lines.min(), shifted_lines_floor.min())
        max_line = max(scan_lines.max(), shifted_lines_floor.max()+1)
        num_lines = max_line - min_line + 1
        missed_lines = np.setdiff1d(np.arange(min_line, max_line+1), scan_lines)
        missed_utcs = ((missed_lines - scan_lines[0])*np.timedelta64(scan_rate, "ms")
                       + self.utcs[0])
        # calculate the missing geo locations
        missed_lons, missed_lats = self._compute_missing_lonlat(missed_utcs)

        # create arrays of lons and lats for interpolation. The locations
        # correspond to not yet corrected utcs, i.e. the time difference from
        # one line to the other should be equal to the scan rate.
        pixels_per_line = self.lats.shape[1]
        complete_lons = np.full((num_lines, pixels_per_line), np.nan,
                                dtype=np.float)
        complete_lats = np.full((num_lines, pixels_per_line), np.nan,
                                dtype=np.float)

        complete_lons[scan_lines - min_line] = self.lons
        complete_lats[scan_lines - min_line] = self.lats
        complete_lons[missed_lines - min_line] = missed_lons
        complete_lats[missed_lines - min_line] = missed_lats

        # perform the slerp interpolation to the corrected utc times
        slerp_t = shifted_lines - shifted_lines_floor  # in [0, 1)
        slerp_res = slerp(complete_lons[shifted_lines_floor - min_line, :],
                          complete_lats[shifted_lines_floor - min_line, :],
                          complete_lons[shifted_lines_floor - min_line + 1, :],
                          complete_lats[shifted_lines_floor - min_line + 1, :],
                          slerp_t[:, np.newaxis, np.newaxis])

        # set corrected values
        self.lons = slerp_res[:, :, 0]
        self.lats = slerp_res[:, :, 1]
        self.utcs -= (offsets * 1000).astype('timedelta64[ms]')

        toc = datetime.datetime.now()
        LOG.debug("clock drift adjustment took %s", str(toc - tic))
Esempio n. 3
0
    def adjust_clock_drift(self):
        """Adjust the geolocation to compensate for the clock error.

        TODO: bad things might happen when scanlines are skipped.
        """
        tic = datetime.datetime.now()
        self.get_times()
        from pygac.clock_offsets_converter import get_offsets
        try:
            offset_times, clock_error = get_offsets(self.spacecraft_name)
        except KeyError:
            LOG.info("No clock drift info available for %s",
                     self.spacecraft_name)
        else:
            offset_times = np.array(offset_times, dtype='datetime64[ms]')
            offsets = np.interp(self.utcs.astype(np.uint64),
                                offset_times.astype(np.uint64), clock_error)
            LOG.info("Adjusting for clock drift of %s to %s",
                     str(min(offsets)), str(max(offsets)))
            self.times = (self.utcs + offsets.astype('timedelta64[s]')).astype(
                datetime.datetime)
            offsets *= -2

            int_offsets = np.floor(offsets).astype(np.int)

            # filling out missing geolocations with computation from pyorbital.
            line_indices = (self.scans["scan_line_number"] + int_offsets)

            missed = sorted((set(line_indices) | set(line_indices + 1)) -
                            set(self.scans["scan_line_number"]))

            min_idx = min(line_indices)
            max_idx = max(max(line_indices),
                          max(self.scans["scan_line_number"] - min_idx)) + 1
            idx_len = max_idx - min_idx + 2

            complete_lons = np.zeros((idx_len, 409), dtype=np.float) * np.nan
            complete_lats = np.zeros((idx_len, 409), dtype=np.float) * np.nan

            complete_lons[self.scans["scan_line_number"] - min_idx] = self.lons
            complete_lats[self.scans["scan_line_number"] - min_idx] = self.lats

            missed_utcs = ((np.array(missed) - 1) * np.timedelta64(500, "ms") +
                           self.utcs[0])

            mlons, mlats = self.compute_lonlat(missed_utcs, True)

            complete_lons[missed - min_idx] = mlons
            complete_lats[missed - min_idx] = mlats

            from pygac.slerp import slerp
            off = offsets - np.floor(offsets)
            res = slerp(complete_lons[line_indices - min_idx, :],
                        complete_lats[line_indices - min_idx, :],
                        complete_lons[line_indices - min_idx + 1, :],
                        complete_lats[line_indices - min_idx + 1, :],
                        off[:, np.newaxis, np.newaxis])

            self.lons = res[:, :, 0]
            self.lats = res[:, :, 1]
            self.utcs += offsets.astype('timedelta64[s]')

        toc = datetime.datetime.now()
        LOG.debug("clock drift adjustment took %s", str(toc - tic))
Esempio n. 4
0
    def compute_lonlat(self, width, utcs=None, clock_drift_adjust=True):
        """Compute lat/lon coordinates.

        Args:
            width: Number of coordinates per scanlines
            utcs: Scanline timestamps
            clock_drift_adjust: If True, adjust clock drift.

        """
        if utcs is None:
            utcs = self.get_times()

        # adjusting clock for drift
        tic = datetime.datetime.now()
        if clock_drift_adjust:
            from pygac.clock_offsets_converter import get_offsets
            try:
                offset_times, clock_error = get_offsets(self.spacecraft_name)
            except KeyError:
                LOG.info("No clock drift info available for %s",
                         self.spacecraft_name)
            else:
                offset_times = np.array(offset_times, dtype='datetime64[ms]')
                offsets = np.interp(utcs.astype(np.uint64),
                                    offset_times.astype(np.uint64),
                                    clock_error)
                utcs = utcs - (offsets * 1000).astype('timedelta64[ms]')

        t = utcs[0].astype(datetime.datetime)

        if "constant_yaw_attitude_error" in self.head.dtype.fields:
            rpy = np.deg2rad([
                self.head["constant_roll_attitude_error"] / 1e3,
                self.head["constant_pitch_attitude_error"] / 1e3,
                self.head["constant_yaw_attitude_error"] / 1e3
            ])
        else:
            try:
                # This needs to be checked thoroughly first
                # rpy_spacecraft = rpy_coeffs[self.spacecraft_name]
                # rpy = [rpy_spacecraft['roll'],
                #        rpy_spacecraft['pitch'],
                #        rpy_spacecraft['yaw']]
                # LOG.debug("Using static attitude correction")
                raise KeyError
            except KeyError:
                LOG.debug("Not applying attitude correction")
                rpy = [0, 0, 0]

        LOG.info("Using rpy: %s", str(rpy))

        from pyorbital.geoloc_instrument_definitions import avhrr_gac
        from pyorbital.geoloc import compute_pixels, get_lonlatalt
        # TODO: Are we sure all satellites have this scan width in degrees ?
        sgeom = avhrr_gac(utcs.astype(datetime.datetime), self.scan_points,
                          55.385)
        s_times = sgeom.times(t)
        tle1, tle2 = self.get_tle_lines()

        pixels_pos = compute_pixels((tle1, tle2), sgeom, s_times, rpy)
        pos_time = get_lonlatalt(pixels_pos, s_times)

        toc = datetime.datetime.now()

        LOG.warning("Computation of geolocation: %s", str(toc - tic))

        lons, lats = pos_time[:2]

        return lons.reshape(-1, width), lats.reshape(-1, width)