GNSS¶
GNSS stations next to DISP, with geepers
as the engine (install the gnss extra). geepers loads, caches and reads the
station series; disp_xr.gnss returns them as xarray and aligns them with
DISP.
gps = dxr.gnss.load(ds, start="2017-01-01") # (station, time) E/N/U
gps = dxr.gnss.to_los(gps, dxr.open_static(ds)) # + los, sigma_los
insar = dxr.gnss.sample(ds, gps, buffer_m=100) # DISP at the stations
gps_on_disp = dxr.gnss.align(gps["los"], insar.time) # DISP epochs and reference
residual = insar - gps_on_disp
GNSS stations next to DISP, with geepers as the engine (PRD F10, task T25).
geepers (https://github.com/opera-adt/geepers, the gnss extra) loads the
GNSS series: its sources (UNR, UNR grid, sideshow) download, cache and read
station files, and its sampler reads DISP around each station. This module
adapts them to xarray and to DISP:
- :func:
get_sourcepicks a geepers source; :func:stationslists the stations over a frame; - :func:
loadreturns a(station, time)Dataset of east, north and up motion with sigmas and correlations, and station coordinates in lon/lat and in the frame's CRS; - :func:
to_losprojects them onto the line of sight with the static layers (sigma from geepersget_sigma_los); - :func:
samplereads DISP at the stations (median in a window, geeperssample_insar); - :func:
alignputs GNSS on the DISP epochs and on the DISP reference date. - :func:
centredstamps daily solutions at the centre of their UTC day. - :func:
drop_relocationskeeps each station's longest record between monument moves (applied by :func:load).
Typical use::
gps = dxr.gnss.load(ds, start="2017-01-01")
gps_los = dxr.gnss.to_los(gps, dxr.open_static(ds))
insar = dxr.gnss.sample(ds, gps, buffer_m=100)
gps_aligned = dxr.gnss.align(gps_los["los"], insar.time)
load ¶
load(target: Union[Dataset, DataArray, Bbox, list[str]], *, source: Union[str, Any] = 'unr', start: Optional[str] = None, end: Optional[str] = None, cache_dir: Optional[str] = None, max_workers: int = 8, max_step_m: Optional[float] = 10.0) -> xr.Dataset
Load GNSS series as a (station, time) Dataset.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
xr.Dataset, (west, south, east, north) or list of str
|
A DISP dataset (its stations, with |
required |
source
|
str or geepers source
|
See :func: |
'unr'
|
start
|
str
|
Dates (ISO) to keep. |
None
|
end
|
str
|
Dates (ISO) to keep. |
None
|
cache_dir
|
str
|
geepers cache directory. |
None
|
max_workers
|
int
|
Stations downloaded in parallel by geepers. |
8
|
max_step_m
|
float or None
|
Largest 3-D position change between consecutive solutions that a
station can make and keep its record. A larger one is not ground
motion (near-field coseismic steps reach about 5 m) but a monument moved
under the same id: the record is split there and only the segment
with the most solutions is kept (:func: |
10.0
|
Returns:
| Type | Description |
|---|---|
Dataset
|
|
Examples:
stations ¶
stations(target: Union[Dataset, DataArray, Bbox], *, source: Union[str, Any] = 'unr', cache_dir: Optional[str] = None)
Return the GNSS stations over a frame or a lon/lat box.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
target
|
(Dataset, DataArray or (west, south, east, north))
|
A DISP dataset (stations inside its grid, with |
required |
source
|
str or geepers source
|
See :func: |
'unr'
|
cache_dir
|
str
|
geepers cache directory. |
None
|
Returns:
| Type | Description |
|---|---|
GeoDataFrame
|
geepers station table ( |
Examples:
get_source ¶
Return a geepers GNSS source.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
('unr', 'unr_grid', 'sideshow')
|
A source name, or an instance of a geepers |
"unr"
|
cache_dir
|
str
|
Where geepers caches downloads (its default otherwise). |
None
|
Examples:
to_los ¶
Project GNSS east, north and up onto the line of sight.
The LOS unit vector is read at each station's pixel (nearest) in the
static layers; the LOS sigma propagates the E/N/U sigmas and
correlations (geepers get_sigma_los).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
gnss
|
Dataset
|
Output of :func: |
required |
static
|
Dataset
|
|
required |
Returns:
| Type | Description |
|---|---|
Dataset
|
|
Examples:
sample ¶
sample(ds: Dataset, gnss: Union[Dataset, Any], *, buffer_m: float = 0.0, layer: str = 'displacement') -> xr.DataArray
Read DISP at the stations: the median in a window around each one.
Uses geepers' XarrayReader.read_window (as its sample_insar
does), with the station's pixel found by flooring (geepers rounds, which
reads the neighboring pixel for half the stations). With buffer_m,
geepers releases that have buffer_meters take a circular window of
that radius; older ones (0.3) a square window of the same half-width in
pixels.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
ds
|
Dataset
|
DISP data with a CRS. |
required |
gnss
|
Dataset or DataFrame
|
Output of :func: |
required |
buffer_m
|
float
|
Window radius in meters (0 reads the station's pixel). |
0.0
|
layer
|
str
|
Layer to read. |
'displacement'
|
Returns:
| Type | Description |
|---|---|
DataArray
|
|
Examples:
align ¶
align(gnss: DataArray, times: Union[DataArray, DatetimeIndex, ndarray], *, reference: Optional[Any] = None, method: Literal['nearest', 'linear'] = 'nearest', tolerance: str = '1D') -> xr.DataArray
Put a GNSS series on the DISP epochs and the DISP reference date.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
gnss
|
DataArray
|
|
required |
times
|
array of datetimes
|
DISP epochs ( |
required |
reference
|
date - like
|
DISP reference date; default the first epoch (a chained stack is relative to it). |
None
|
method
|
('nearest', 'linear')
|
Nearest GNSS solution within |
"nearest"
|
tolerance
|
str
|
Largest distance in time for |
'1D'
|
Returns:
| Type | Description |
|---|---|
DataArray
|
GNSS at |
Examples:
DISP against GNSS¶
dxr.residuals.compare reads DISP at the stations (or the downsampled cell
holding each one), puts GNSS on the DISP epochs and reference, and lets
geepers compute the metrics.
result = dxr.residuals.compare(ds, gps, static, buffer_m=100,
requirement=lambda d: (3 + 0.5 * d**0.5) / 1000)
result.stations # velocities, normalized residuals, chi2, outliers
result.profile # pairwise RMSE against distance, with the requirement
result.plot_velocities()
compare ¶
compare(data: Any, gnss: Dataset, static: Dataset, *, buffer_m: float = 0.0, layer: str = 'displacement', velocity_method: str = 'lsq', tolerance: str = '1D', min_common_dates: int = 3, min_stations: int = 3, min_epochs: int = 10, min_span_years: float = 2.0, n_bins: int = 10, requirement: Optional[Any] = DISP_S1_DISPLACEMENT, velocity_requirement: Optional[Requirement] = DISP_S1_VELOCITY, outlier_sigma: float = 3.0, epoch_flag: float = 3.0, disp_sigma: Optional[float] = None) -> Comparison
Compare DISP with GNSS at the stations (or the cells holding them).
geepers computes the metrics (velocities from one estimator applied to both series, pairwise differential RMSE against distance, its binned profile and semivariogram, epoch RMSE, agreement statistics); disp-xr prepares the series and adds normalized velocity residuals, reduced χ² per station and flags.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
data
|
xr.Dataset, point table or Quadtree
|
DISP at 30 m (read at each station with :func: |
required |
gnss
|
Dataset
|
:func: |
required |
static
|
Dataset
|
LOS layers for :func: |
required |
buffer_m
|
float
|
Window radius for sampling 30 m data. |
0.0
|
layer
|
str
|
DISP layer. |
'displacement'
|
velocity_method
|
('lsq', 'midas', 'trend')
|
Estimator for both series (geepers |
"lsq"
|
tolerance
|
str
|
Largest gap between a DISP epoch and a GNSS day. |
'1D'
|
min_common_dates
|
int
|
Passed to geepers (pairs, epochs, profile). |
3
|
min_stations
|
int
|
Passed to geepers (pairs, epochs, profile). |
3
|
n_bins
|
int
|
Passed to geepers (pairs, epochs, profile). |
3
|
min_epochs
|
int
|
Least number of epochs with both series, and least time between
the first and last of them, for a station's velocities to count.
A rate from a few epochs says nothing about the product, yet it
would enter the velocity residuals, the outlier flag and the GNSS
tie. Below either, the velocities and their sigmas are NaN and
|
10
|
min_span_years
|
int
|
Least number of epochs with both series, and least time between
the first and last of them, for a station's velocities to count.
A rate from a few epochs says nothing about the product, yet it
would enter the velocity residuals, the outlier flag and the GNSS
tie. Below either, the velocities and their sigmas are NaN and
|
10
|
requirement
|
Requirement or callable
|
Threshold of the pairwise relative displacement RMSE against
distance, drawn on the profile with geepers' |
DISP_S1_DISPLACEMENT
|
velocity_requirement
|
Requirement
|
Threshold of the relative velocity: every station pair's difference
of velocity residuals is scored against it ( |
DISP_S1_VELOCITY
|
outlier_sigma
|
float
|
Stations with |
3.0
|
disp_sigma
|
float
|
Noise of one DISP epoch at a station, in the units of |
None
|
epoch_flag
|
float
|
Epochs whose RMSE exceeds the median plus this many MADs are flagged. |
3.0
|
Returns:
| Type | Description |
|---|---|
Comparison
|
|
Examples:
Comparison
dataclass
¶
DISP against GNSS at the stations; the metrics come from geepers.
Attributes are filled by :func:compare.
Examples:
>>> result = compare(ds, gps, static)
>>> result.summary["velocity_fraction_passing"]
>>> result.plot_velocities()
series
instance-attribute
¶
(station, time): insar, gnss (on the DISP epochs and
reference), residual (insar - gnss) and sigma_gnss.
stations
instance-attribute
¶
DataFrame per station: velocities of both series from the same
estimator (geepers fit_velocities) with sigmas, velocity_residual,
relative_residual (less the datum offset), velocity_sigma
(combined), normalized_residual (relative residual over its sigma),
chi2 (reduced, of the displacement residual against the GNSS and
DISP sigmas in quadrature), n_dates, outlier,
velocity_usable (enough shared epochs and time span for the
velocities, which are NaN otherwise) and
reference_epoch (the first epoch with both series, where both are
zero: the DISP reference date unless the station has no GNSS that day).
pairs
instance-attribute
¶
geepers pairwise_differential_rmse: RMSE of the relative misfit of
every station pair against distance.
profile
instance-attribute
¶
geepers binned_rmse_profile of pairs (with requirement
and fraction_passing when a requirement is given).
epochs
instance-attribute
¶
geepers epoch_rmse per DISP epoch, with flag for epochs above
the median plus epoch_flag x MAD of the RMSE.
summary
instance-attribute
¶
geepers comparison_stats of the station velocities (bias, MAD,
RMSE, r², n), datum_offset (median velocity residual: DISP is
relative to its reference, GNSS absolute), disp_sigma (the DISP
noise used in chi2), with velocity_fraction_passing and the
requirement names when requirements are given.
velocity_pairs
class-attribute
instance-attribute
¶
Per station pair: distance, difference of the velocity residuals,
the velocity requirement there, applies (inside its distance
range) and passing; None without a velocity requirement.
plot_velocities ¶
Scatter GNSS against DISP velocities (geepers plot_velocity_scatter).
to_dataset ¶
to_zarr ¶
plot_semivariogram ¶
Plot the misfit semivariogram (geepers plot_semivariogram).
residual_spectra ¶
residual_spectra(source: Any, *, frequencies: Optional[ndarray] = None, detrend: bool = True) -> xr.DataArray
Return the Lomb-Scargle power spectrum of each station's residual series.
Lomb-Scargle handles the irregular DISP epochs (gaps, 12 and 24 day revisits) without resampling. Peaks at 1 and 2 cycles per year are seasonal signal one series has and the other lacks; a red spectrum (power rising to low frequencies) is correlated error.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
Comparison or DataArray
|
:func: |
required |
frequencies
|
array
|
Frequencies in cycles per year; default from one cycle over the record to the Nyquist frequency of the median epoch spacing. |
None
|
detrend
|
bool
|
Remove each series' linear trend first. |
True
|
Returns:
| Type | Description |
|---|---|
DataArray
|
|
Examples:
common_mode ¶
Return the common-mode residual across stations (geepers estimate_cme).
A signal shared by all stations' residuals (a reference or datum shift, a frame-wide atmospheric or orbit error) is a product error that the station-by-station metrics miss.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
source
|
Comparison or DataArray
|
:func: |
required |
n_components
|
int
|
Principal components to keep. |
1
|
min_coverage
|
float
|
Stations observed in fewer than this share of epochs are left out. |
0.5
|
Returns:
| Type | Description |
|---|---|
Dataset
|
|
Examples:
An EOF analysis of trajectory residuals with xeofs (eof extra) is in
examples/eof_residuals.py; it runs in its own CI job.