def test_slerp_vec(self): lon0 = np.array([[0, 0], [0, 0]]) lat0 = np.array([[0, 0], [0, 0]]) lon1 = np.array([[0, 0], [0, 0]]) lat1 = np.array([[1, 1], [1, 1]]) res = slerp(lon0, lat0, lon1, lat1, 0.5) self.assertTrue(np.allclose(res[:, :, 0], 0)) self.assertTrue(np.allclose(res[:, :, 1], 0.5)) lon0 = np.array([[183, 0], [-90, 0]]) lat0 = np.array([[0, 89], [89, 89]]) lon1 = np.array([[179, 180], [90, 180]]) lat1 = np.array([[0, 89], [89, 87]]) res = slerp(lon0, lat0, lon1, lat1, 0.5) self.assertTrue(np.allclose(res[0, 0, :] % 360, (181, 0))) self.assertTrue(np.allclose(res[0, 1, 1], 90)) self.assertTrue(np.allclose(res[1, 0, 1], 90)) self.assertTrue(np.allclose(res[1, 1, :], (180, 89)))
def test_slerp_pole(self): lon0, lat0 = (0, 89) lon1, lat1 = (180, 89) res = slerp(lon0, lat0, lon1, lat1, 0.5) self.assertTrue(np.allclose(res[:, :, 1], 90)) lon0, lat0 = (-90, 89) lon1, lat1 = (90, 89) res = slerp(lon0, lat0, lon1, lat1, 0.5) self.assertTrue(np.allclose(res[:, :, 1], 90)) lon0, lat0 = (0, 89) lon1, lat1 = (180, 87) res = slerp(lon0, lat0, lon1, lat1, 0.5) self.assertTrue(np.allclose(res, (180, 89)))
def test_slerp_datum(self): lon0, lat0 = (183, 0) lon1, lat1 = (179, 0) res = slerp(lon0, lat0, lon1, lat1, 0.5) res %= 360 self.assertTrue( np.allclose(res, (181, 0)))
def test_slerp_pole(self): lon0, lat0 = (0, 89) lon1, lat1 = (180, 89) res = slerp(lon0, lat0, lon1, lat1, 0.5) self.assertTrue( np.allclose(res[:, :, 1], 90)) lon0, lat0 = (-90, 89) lon1, lat1 = (90, 89) res = slerp(lon0, lat0, lon1, lat1, 0.5) self.assertTrue( np.allclose(res[:, :, 1], 90)) lon0, lat0 = (0, 89) lon1, lat1 = (180, 87) res = slerp(lon0, lat0, lon1, lat1, 0.5) self.assertTrue( np.allclose(res, (180, 89)))
def test_slerp_tvec(self): lon0 = np.array([[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]) lat0 = np.array([[0, 0], [5, 0], [10, 0], [15, 0], [20, 0], [25, 0], [30, 0]]) lon1 = np.array([[0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0], [0, 0]]) lat1 = np.array([[45, 45], [45, 45], [45, 45], [45, 45], [45, 45], [45, 45], [45, 45]]) t = np.array([[0.5, 0, 0.2, 0.4, 0.6, 0.8, 1]]).T t = t[:, :, np.newaxis] res = slerp(lon0, lat0, lon1, lat1, t) expected = np.array([[22.5, 22.5], [5., 0.], [17., 9.], [27., 18.], [35., 27.], [41., 36.], [45., 45.]]) self.assertTrue(np.allclose(res[:, :, 0], 0)) self.assertTrue(np.allclose(res[:, :, 1], expected))
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))
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))
def test_slerp_datum(self): lon0, lat0 = (183, 0) lon1, lat1 = (179, 0) res = slerp(lon0, lat0, lon1, lat1, 0.5) res %= 360 self.assertTrue(np.allclose(res, (181, 0)))
def test_slerp(self): lon0, lat0 = (0, 0) lon1, lat1 = (0, 1) self.assertTrue( np.allclose(slerp(lon0, lat0, lon1, lat1, 0.5), (0, 0.5)))