Sentinel-1 d4b86eeb349141d5915f4cf038b22314

Keywords data used; sentinel-1,:index:datasets; sentinel-1, index:SAR


The Sentinel-1 mission is composed of a constellation of two Synthetic Aperture Radar (SAR) satellites, Sentinel-1A and Sentinel-1B, sharing the same orbital plane. Sentinel-1 provides dual polarisation capability, very short revisit times, and rapid product delivery. The mission currently collects data every 12 days over Africa at a spatial resolution of approximately 20m. Sentinel-1A was launched on 3 April 2014 and Sentinel-1B followed on 25 April 2016. Two other spacecraft (Sentinel-1C and Sentinel-1D) are planned to replace the first two satellites at the end of their operational lifespan. For more information on the Sentinel-1 platforms and applications, check out the European Space Agency website.

SAR data has the advantage of operating at wavelengths not impeded by cloud cover and can acquire data over a site during the day or night. The Sentinel-1 mission is the European Radar Observatory for the Copernicus joint initiative of the European Commission (EC) and the European Space Agency (ESA) that can offer reliable and repeated wide area monitoring with its SAR instrument.

Radar backscatter measures the amount of microwave radiation reflected back to the centre from the ground surface. This measurement is sensitive to surface roughness, moisture content, and viewing geometry. DEAfrica provides Sentinel-1 backscatter as Radiometric Terrain Corrected (RTC) gamma-0 (γ0) where variation due to changing observation geometries has been mitigated.

DE Africa provides Sentinel-1 data acquired in Interferometric Wide Swath (IW) mode and with dual polarisation (VV and VH). The dual polarisation backscatter timeseries can be used in applications for forests, agriculture, wetlands, and land cover classification. SAR’s ability to see through clouds makes it critical for mapping and monitoring land cover changes in the wet tropics.

DEAfrica Sentinel-1 backscatter is processed to be compliant with the CEOS Analysis Ready Data for Land (CARD4L) specification. More technical information can be found in the DE Africa User Guide.


In this notebook we will load sentinel-1 Radiometric Terrain Corrected (RTC) SAR backscatter data.

Topics covered include: 1. Inspecting the Sentinel-1 product and measurements available in the datacube 2. Using the native dc.load() function to load in Sentinel-1 data 3. Using the load_ard wrapper function to load masked Sentinel-1 data

Getting started

To run this analysis, run all the cells in the notebook, starting with the “Load packages” cell.

Load packages

%matplotlib inline
import datacube
import sys
import math
import numpy as np
import matplotlib.pyplot as plt
from deafrica_tools.plotting import rgb
from deafrica_tools.plotting import display_map
from deafrica_tools.datahandling import load_ard
/env/lib/python3.6/site-packages/geopandas/ UserWarning: The Shapely GEOS version (3.7.2-CAPI-1.11.0 ) is incompatible with the GEOS version PyGEOS was compiled with (3.9.0-CAPI-1.16.2). Conversions between both will be slow.
  shapely_geos_version, geos_capi_version_string

Connect to the datacube

dc = datacube.Datacube(app="Sentinel_1")

Available products and measurements

List products

We can use datacube’s list_products functionality to inspect DE Africa’s SAR products that are available in the datacube. The table below shows the product names that we will use to load the data, a brief description of the data, and the satellite instrument that acquired the data.

name description label lat time lon format region_code product_family creation_time product_type dataset_maturity instrument platform crs resolution tile_size spatial_dimensions
3 s1_rtc Sentinel 1 Gamma0 normalised radar backscatter None None None None None NaN NaN None NaN NaN None None NaN NaN NaN NaN
product = "s1_rtc"

List measurements

We can further inspect the data available for each SAR product using datacube’s list_measurements functionality. The table below lists each of the measurements available in the data.

measurements = dc.list_measurements()
name dtype units nodata aliases flags_definition
vv vv float32 1 NaN [VV] NaN
vh vh float32 1 NaN [VH] NaN
angle angle uint8 1 255 [ANGLE, local_incidence_angle] NaN
area area float32 1 NaN [AREA, normalised_scattering_area] NaN
mask mask uint8 1 0 [MASK] {'qa': {'bits': [0, 1, 2, 3, 4, 5, 6, 7], 'val...

The Sentinel-1 product has five measurements: * Backscatter in two polarisations,VV and VH. The two letters correspond to the polarisations of the light sent and received by the satellite. VV refers to the satellite sending out vertically-polarised light and receiving vertically-polarised light back, whereas VH refers to the satellite sending out vertically-polarised light and receiving horizontally-polarised light back. * A data mask, with 0 for no-data, 1 for valid data, and 2 for in/near radar shadow. * Scattering area, the normalization that has been calcuated using a digital elevation model and been applied to obtain radiometric terrain correction. * Local incidence angle.

Load Sentinel-1 dataset using dc.load()

Now that we know what products and measurements are available for the product, we can load data from the datacube using dc.load.

In the example below, we will load Sentinel-1 for part of Ghana in 2021.

We will load data from two polarisation bands,VV and VH, as well as the data mask ('mask'). The data is loaded in native EPSG:4326 coordinate reference system (CRS). It can be reprojected if output_crs and resolution are defined in the query.

Note: For a more general discussion of how to load data using the datacube, refer to the Introduction to loading data notebook.

# Define the area of interest
latitude = 5.423
longitude = -0.464
buffer = 0.02
time = ('2020-12')
#add spatio-temporal extent to the query
query = {
    'x': (longitude-buffer, longitude+buffer),
    'y': (latitude+buffer, latitude-buffer),

Visualise the selected area

display_map(x=(longitude-buffer, longitude+buffer), y=(latitude+buffer, latitude-buffer))
#loading the data with the mask band included
bands = ['vv','vh','mask']
ds_S1 = dc.load(product='s1_rtc',

Dimensions:      (latitude: 200, longitude: 200, time: 5)
  * time         (time) datetime64[ns] 2020-12-06T18:18:24.900676 ... 2020-12...
  * latitude     (latitude) float64 5.443 5.443 5.443 ... 5.404 5.403 5.403
  * longitude    (longitude) float64 -0.4839 -0.4837 -0.4835 ... -0.4443 -0.4441
    spatial_ref  int32 4326
Data variables:
    vv           (time, latitude, longitude) float32 0.074473426 ... 0.011447344
    vh           (time, latitude, longitude) float32 0.015363921 ... 0.000331...
    mask         (time, latitude, longitude) uint8 1 1 1 1 1 1 1 ... 1 1 1 1 1 1
    crs:           EPSG:4326
    grid_mapping:  spatial_ref
# Plot all VV observations for the year, and apply data mask to exclude pixels in and near radar shadow
ds_S1.vv.where(ds_S1.mask==1).plot(cmap="Greys_r", robust=True, col="time", col_wrap=4);
# Plot all VH observations for the year, and apply data mask to exclude pixels in and near radar shadow
ds_S1.vh.where(ds_S1.mask==1).plot(cmap="Greys_r", robust=True, col="time", col_wrap=4);
# Plot the average of all VV observations
mean_vv = ds_S1.vv.where(ds_S1.mask==1).mean(dim="time")

fig = plt.figure(figsize=(8, 7))
mean_vv.plot(cmap="Greys_r", robust=True)
plt.title("Average VV");
# Plot the average of all VH observations
mean_vh = ds_S1.vh.mean(dim="time")

fig = plt.figure(figsize=(8, 7))
mean_vh.plot(cmap="Greys_r", robust=True)
plt.title("Average VH");

Low backscatter is measured over water due to specular reflection.

You may have noticed that the water in the individual VV and VH images isn’t a consistent colour. The distortion you’re seeing is a type of noise known as speckle, which gives the images a grainy appearence. Speckle noise can be reduced through filtering. Applying a speckle filter will reduce noise and improve our ability to distinguish water from land. If interested, you can find a technical introduction to speckle filtering here.

#creation of a new band (VH/VV=vhvv) for RGB display
ds_S1['vhvv'] = ds_S1.vh.where(ds_S1.mask==1) / ds_S1.vv.where(ds_S1.mask==1)
# Set the timesteps to visualise
timesteps = [0,1,3]

# Generate RGB plots at each timestep
rgb(ds_S1.where(ds_S1.mask==1), bands=['vh','vv','vhvv'], index=timesteps)

In the above false color composites, low backscatter is measured over water which appears black or dark blue. High backscatter is measured in urban areas which appear green. The salt and pepper a.k.a speckle noise over water is also visible.

Load Sentinel-1 using load_ard

This function will load images from Sentinel-1 and apply a pixel-quality mask. The result is an analysis ready dataset free of shadow, and missing data.

You can find more information on this function from the Using load ard notebook.

ds = load_ard(dc=dc,
              measurements=['vv', 'vh'],
              y=(latitude+buffer, latitude-buffer),
              x=(longitude-buffer, longitude+buffer),

Using pixel quality parameters for Sentinel 1
Finding datasets
Applying pixel quality/cloud mask
Loading 5 time steps
Dimensions:      (latitude: 200, longitude: 200, time: 5)
  * time         (time) datetime64[ns] 2020-12-06T18:18:24.900676 ... 2020-12...
  * latitude     (latitude) float64 5.443 5.443 5.443 ... 5.404 5.403 5.403
  * longitude    (longitude) float64 -0.4839 -0.4837 -0.4835 ... -0.4443 -0.4441
    spatial_ref  int32 4326
Data variables:
    vv           (time, latitude, longitude) float32 0.074473426 ... 0.011447344
    vh           (time, latitude, longitude) float32 0.015363921 ... 0.000331...
    crs:           EPSG:4326
    grid_mapping:  spatial_ref

Below we plot the masked Sentinel-1 data with high quality.

# Plot all VV observations for the year in which pixels in and near radar shadow have been excluded
ds.vv.plot(cmap="Greys_r", robust=True, col="time", col_wrap=4);

Histogram Analysis for Sentinel-1 Dataset

Histrograms below show bimodal distributions where low backscatter is measured over water.

#plotting each polorisation bands following converting to dB values
fig, ax = plt.subplots(1, 3, figsize=(10, 4))
ds_S1.vh.where(ds_S1.mask==1).plot.hist(ax=ax[0], bins=np.arange(0, 0.1, 0.002), facecolor='red')
ds_S1.vv.where(ds_S1.mask==1).plot.hist(ax=ax[1], bins=np.arange(0, 0.3, 0.006), facecolor='green')
ds_S1.vhvv.plot.hist(ax=ax[2], bins=20, facecolor='blue')

Additional information

License: The code in this notebook is licensed under the Apache License, Version 2.0. Digital Earth Africa data is licensed under the Creative Commons by Attribution 4.0 license.

Contact: If you need assistance, please post a question on the Open Data Cube Slack channel or on the GIS Stack Exchange using the open-data-cube tag (you can view previously asked questions here). If you would like to report an issue with this notebook, you can file one on Github.

Compatible datacube version:


Last Tested:

from datetime import datetime'%Y-%m-%d')