From c7e77ccd46c57f0a96cce214a73d4b5dfb9165b5 Mon Sep 17 00:00:00 2001 From: Zhang Yunjun Date: Mon, 11 Nov 2024 18:48:34 +0800 Subject: [PATCH] `gnss`: handle longitude <=-180 or >=360 (#1290) + `utils.utils0.py`: add `standardize_longitude()` to handle the longitude data range - ensure longitude is within (-180, 360) - could specify the data range format, in either [0, 360) or (-180, 180] via `lon_range` arg + `objects.gnss.py`: call `ut.standardize_longitude()` in all the child class of GNSS This error occurs for the GNSS_UNR sites in Japan, where the longitude of G073 can be -229. In the old code, this results in a NaN value for inc/az_angle extraction from the geometry file. --- src/mintpy/objects/gnss.py | 19 +++++++++++++++---- src/mintpy/utils/utils0.py | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/mintpy/objects/gnss.py b/src/mintpy/objects/gnss.py index b4de31d27..89bea2c19 100644 --- a/src/mintpy/objects/gnss.py +++ b/src/mintpy/objects/gnss.py @@ -71,7 +71,8 @@ def search_gnss(SNWE, start_date=None, end_date=None, source='UNR', site_list_fi # ensure that site data formatting is consistent sites['site'] = np.array([site.upper() for site in sites['site']]) - sites['lon'][sites['lon'] > 180] -= 360 # ensure lon values in (-180, 180] + # ensure longitude values in (-180, 180] + sites['lon'] = ut.standardize_longitude(sites['lon'], limit='-180to180') vprint(f'load {len(sites["site"]):d} GNSS sites with fields: {" ".join(sites.keys())}') # limit in space @@ -867,6 +868,9 @@ def get_site_lat_lon(self, print_msg=False) -> (float, float): data = np.loadtxt(self.file, dtype=bytes, skiprows=1, max_rows=10) self.site_lat, self.site_lon = data[0, 20:22].astype(float) + # ensure longitude in the range of (-180, 180] + self.site_lon = ut.standardize_longitude(self.site_lon, limit='-180to180') + return self.site_lat, self.site_lon @@ -987,8 +991,9 @@ def get_site_lat_lon(self, print_msg=False) -> (float, float): # longitude lon_line = [x for x in lines if x.startswith('# East Longitude')][0].strip('\n') self.site_lon = float(lon_line.split()[-1]) - # ensure longitude in the range of (-180, 180] - self.site_lon -= 0 if self.site_lon <= 180 else 360 + + # ensure longitude in the range of (-180, 180] + self.site_lon = ut.standardize_longitude(self.site_lon, limit='-180to180') return self.site_lat, self.site_lon @@ -1094,6 +1099,8 @@ def get_site_lat_lon(self, print_msg=False) -> (float, float): # format self.site_lat = float(site_lat) self.site_lon = float(site_lon) + # ensure longitude in the range of (-180, 180] + self.site_lon = ut.standardize_longitude(self.site_lon, limit='-180to180') if print_msg == True: print(f'\t{self.site_lat:f}, {self.site_lon:f}') @@ -1185,7 +1192,11 @@ def get_site_lat_lon(self, print_msg=False) -> (str, str): """ sites = read_GENERIC_site_list('GenericList.txt') ind = sites['site'].tolist().index(self.site) - return sites['lat'][ind], sites['lon'][ind] + site_lat, site_lon = sites['lat'][ind], sites['lon'][ind] + # ensure longitude in the range of (-180, 180] + site_lon = ut.standardize_longitude(site_lon, limit='-180to180') + + return site_lat, site_lon def read_displacement(self, start_date=None, end_date=None, print_msg=True, display=False): diff --git a/src/mintpy/utils/utils0.py b/src/mintpy/utils/utils0.py index d410a13af..cb7f31594 100644 --- a/src/mintpy/utils/utils0.py +++ b/src/mintpy/utils/utils0.py @@ -267,6 +267,30 @@ def touch(fname_list, times=None): ################################## Coordinate ########################################## +def standardize_longitude(lon, limit='-180to180'): + """Normalize the longitude value range into (-180, 180] or [0, 360). + + Parameters: lon - float / np.ndarray, longitude in degree + limit - str, -180to180 or 0to360 + Returns: lon - float / np.ndarray, longitude in degree + """ + lon = np.asarray(lon) + + # ensure data within (-180, 360) + lon = np.where(lon >= 360, lon - 360, lon) + lon = np.where(lon <= -180, lon + 360, lon) + + # range option 1: ensure data within (-180, 180] + if limit == '-180to180': + lon = np.where(lon > 180, lon - 360, lon) + + # range option 2: ensure data within [0, 360) + elif limit == '0to360' and np.nanmin(lon) < 0: + lon = np.where(lon < 0, lon + 360, lon) + + return float(lon) if np.isscalar(lon) else lon + + def utm_zone2epsg_code(utm_zone): """Convert UTM Zone string to EPSG code.