Skip to content

Sentinel-1 RTC - offsets between S1A and S1C platforms #492

Description

@natborn2

I've come across what appear to be systematic and persistent shifts in the geolocation or terrain correction of some Sentinel-1 RTC scenes.

The example below is in relative orbit 69 in Peru. The shift seems to affect large areas of the scene but is only at the level of a few pixels so is not immediately obvious unless you focus on sharp-edged landscape features, particularly in areas of steep slopes.

The shift appears to occur quite suddenly around May 2025. I have analysed several locations around this region of Peru and found similar issues occurring around the same time, at least in orbit 69 and orbit 120, but possibly others too.

When we look at the platform information from the stac items it becomes clear that the shift is associated with scenes from Sentinel-1C, while scenes from Sentinel-1A after May 2025 appear to be consistent with earlier ones. The more recent scenes from Sentinel-1D appear to be split between both S1C-like and S1A-like examples.

Is there anything that can be done to fix these differences? Although subtle, they are significant for change detection algorithms. In the example shown, there is data from S1A throughout the time series, but in other examples there is a gap in S1A data after May 2025 so if we were to exclude S1C then it would lead to significant data gaps.

Minimal reproducible example

import planetary_computer
import numpy as np
import odc.stac
import pystac_client
import matplotlib.pyplot as plt
import xarray as xr

bbox = [-76.95838, -6.89814, -76.95626, -6.89612]
daterange = "2023-01-01/2026-07-16"

catalog = pystac_client.Client.open(
    "https://planetarycomputer.microsoft.com/api/stac/v1",
    modifier=planetary_computer.sign_inplace)

rtc_items = catalog.search(
    collections=["sentinel-1-rtc"],
    bbox = bbox,
    datetime=daterange,
    query = {"sar:instrument_mode":{"eq":"IW"},
             "sar:polarizations":{"eq":["VV","VH"]},
             "sat:relative_orbit":{"eq":69}}
).item_collection()

ds = odc.stac.load(rtc_items,
              bands = ["vv"],
              groupby="solar_day",
              bbox = bbox,
             )

baseline = ds.isel(time=slice(None,10)).mean(dim="time")
deltas = np.abs( ds.isel(time=slice(10, None)) - baseline ).mean(dim=["x","y"])

# Create an array of platform values for each time point
ds['platform'] = xr.DataArray(
    [item.properties['platform'] for item in rtc_items.items],
    coords={"time": [np.datetime64(item.properties['datetime']) 
                     for item in rtc_items.items]},
    )

# Plot VV by platform
fig, ax = plt.subplots(figsize=(12, 5))
platforms = ds['platform'].sel(time=deltas.time)
unique_platforms = sorted(set(platforms.values))
colors = plt.cm.tab10.colors
platform_colors = {p: colors[i] for i, p in enumerate(unique_platforms)}

for platform in unique_platforms:
    mask = platforms.values == platform
    ax.scatter(deltas.time.values[mask], deltas.vv.values[mask],
               label=platform, s=10, color=platform_colors[platform])

ax.set_title("Average absolute shift in VV")
ax.legend()
fig.autofmt_xdate()

# Plot mean VV image for each platform
fig, axes = plt.subplots(2,2, figsize=(12, 10), sharex=True, sharey=True)

for ax, platform in zip(axes.flatten(), unique_platforms):
    mask = ds['platform'].values == platform
    ds.sel(time=ds.time.values[mask]).vv.mean(dim='time').plot(ax=ax, vmin=0, vmax=1)
    ax.set_title(f"{platform} mean VV")
    ax.grid(visible=True, which='major', axis='both')

Outputs

Image Image

Additional context

At first glance this looks similar to #404 and I initially thought it was the same issue. That issue actually discussed two very similar issues, one affecting scenes over the Philipines in late 2024 (which was fixed) and a second (apparently unrelated issue) affecting scenes over Kenya in 2022. However, the shift seen in Kenya is involving scenes that are exclusively from S1A. I plotted the time series in the Kenya AOI up to 2026 and found that there is no offset between S1A and S1C (but I still reproduce the jump seen in 2022). So there are some differences from what I'm seeing here in Peru, although the sudden and persistent nature of the shift are similar.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions