Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Exploring UAVSAR L1 Single Look Complex (SLC) Product

In this tutorial, we will explore Level 1 Single Look Complex (SLC) dataset, collected by Uninhabited Aerial Vehicle Synthetic Aperture Radar (UAVSAR), a polarimetric L-band synthetic aperture radar flown on the NASA Gulfstream-III aircraft as part of NASA Delta-X campaign. This tutorial is modified from a jupyter notebook developed by Talib Oliver-Cabrera of NASA JPL for Delta-X Applications Workshop.

import earthaccess
import numpy as np
import pandas as pd
import geopandas as gpd
import xarray as xr
import hvplot.xarray
from os import path
import warnings
# suppress future warnings
warnings.filterwarnings('ignore', category=FutureWarning)
Loading...
Loading...
Loading...
Loading...

Authentication

We recommend authenticating your Earthdata Login (EDL) information using the earthaccess python library as follows:

# works if the EDL login already been persisted to a netrc
try:
    auth = earthaccess.login(strategy="netrc")
except FileNotFoundError:
    # ask for EDL credentials and persist them in a .netrc file
    auth = earthaccess.login(strategy="interactive", persist=True)

Search granules

We will using the earthaccess module to search the granules within the UAVSAR dataset.

doi = '10.3334/ORNLDAAC/1984' # UAVSAR SLC dataset
granules = earthaccess.search_data(
    doi=doi
)
print(f'Granules found: {len(granules)}')
Granules found: 2392

Let’s plot the bounding boxes of the datas

gdf = gpd.GeoDataFrame(granules, 
                       geometry=gpd.GeoSeries(granules, crs=4326))
gdf.explore(color='red', alpha=0.9,
            tiles='https://mt1.google.com/vt/lyrs=s&x={x}&y={y}&z={z}', 
            attr='Google')
Loading...

Let’s print the first few granules link.

# print the first 15 granules
[path.basename(g.data_links()[0]) for g in granules][:15]
['atchaf_19809_02_BU_s1_2x8.llh', 'atchaf_19809_02_BU.dop', 'atchaf_19809_21023_000_210327_L090VV_02_BU_s1_1x1.slc', 'atchaf_19809_21023_000_210327_L090VV_02_BU.ann', 'atchaf_19809_21023_000_210327_L090HV_02_BU.ann', 'atchaf_19809_21023_000_210327_L090HH_02_BU.ann', 'atchaf_19809_21023_000_210327_L090HH_02_BU_s1_1x1.slc', 'atchaf_19809_21023_000_210327_L090HV_02_BU_s1_1x1.slc', 'atchaf_19809_21023_000_210327_L090VH_02_BU.ann', 'atchaf_19809_02_BU_s1_2x8.lkv', 'atchaf_19809_21023_000_210327_L090VH_02_BU_s1_1x1.slc', 'atchaf_06309_21023_001_210327_L090VV_02_BU_s1_1x1.slc', 'atchaf_06309_21023_001_210327_L090VV_02_BU.ann', 'atchaf_06309_21023_001_210327_L090HH_02_BU.ann', 'atchaf_06309_21023_001_210327_L090VH_02_BU.ann']

As we see above, there are five different kinds of file extensions in the dataset. Each flight ID contains 4 slant range single look complex (SLC) with corresponding 4 metadata files (ANN) There are also additional a latitude/longitude/height (LLH), a look vector (LKV), a doppler (DOP) files for each line ID, as shown in the table below. The same area was sampled at approximately 30-minute intervals. The SLCs are not corrected for residual baseline (BU).

File nameDescription
*.slcSLC stacks in the HH, HV, VH, and VV polarizations
*.annAnnotation files with metadata for each SLC files
*.llhLatitude, longitude, and height corresponding to SLC pixels
*lkvLook vector (east, north, up) at the target pointing from the aircraft to the ground
*.dopDoppler centroid versus slant range

Download granules

Let’s download granules from only one flight ID (4 slc and 4 ann), with sitename wterre, line id as 34202, flight id as 21028, data take counter as 017, and polarization VV.

granules = earthaccess.search_data(
    granule_name = f"*wterre_34202_21028_017*VV_*", # retrieve only one flight ID
    doi=doi
)
# print file name
print(f'Granules found: {len(granules)}')
Granules found: 3

Let’s print the filenames and the file size of these 3 granules.

# granule name and size
g_name = [path.basename(g.data_links()[0]) for g in granules]
g_size = [g.size()*0.001 for g in granules]

# print as table
pd.set_option('display.max_colwidth', None)
pd.DataFrame({'FileName': g_name, 'Size(GB)': g_size})
Loading...

Using the earthaccess, we will now download ~10 GB worth of data to your local directory data. This step will take a while to complete.

earthaccess.download(granules, local_path="data")
Loading...

Loading...

Loading...

[PosixPath('data/wterre_34202_21028_017_210407_L090VV_02_BU_s2_1x1.slc'), PosixPath('data/wterre_34202_21028_017_210407_L090VV_02_BU_s1_1x1.slc'), PosixPath('data/wterre_34202_21028_017_210407_L090VV_02_BU.ann')]

Annotation file

Let’s take a look at annotation file with VV polarization.

slc_f = "data/wterre_34202_21028_017_210407_L090VV_02_BU"
with open(f"{slc_f}.ann", "r") as f:
    print(f.read())
Fetching long content....

File size parameters

In the above file, take a note of “File size parameters” section, which we will use to create SLC images in the next section.

slc_1_1x1 Columns                                        (pixels)        = 9900                   ; samples in SLC 1x1 segment 1
slc_1_1x1 Rows                                           (pixels)        = 66664                  ; lines in SLC 1x1 segment 1
slc_1_1x4 Columns                                        (pixels)        = 9900                   ; samples in SLC 1x4 segment 1
slc_1_1x4 Rows                                           (pixels)        = 16666                  ; lines in SLC 1x4 segment 1
slc_1_2x8 Columns                                        (pixels)        = 4950                   ; samples in SLC 2x8 segment 1
slc_1_2x8 Rows                                           (pixels)        = 8333                   ; lines in SLC 2x8 segment 1
llh_1_2x8 Columns                                        (pixels)        = 4950                   ; samples in LLH segment 1
llh_1_2x8 Rows                                           (pixels)        = 8333                   ; lines in LLH segment 1
lkv_1_2x8 Columns                                        (pixels)        = 4950                   ; samples in LKV segment 1
lkv_1_2x8 Rows                                           (pixels)        = 8333                   ; lines in LKV segment 1
slc_2_1x1 Columns                                        (pixels)        = 9900                   ; samples in SLC 1x1 segment 2
slc_2_1x1 Rows                                           (pixels)        = 55408                  ; lines in SLC 1x1 segment 2
slc_2_1x4 Columns                                        (pixels)        = 9900                   ; samples in SLC 1x4 segment 2
slc_2_1x4 Rows                                           (pixels)        = 13852                  ; lines in SLC 1x4 segment 2
slc_2_2x8 Columns                                        (pixels)        = 4950                   ; samples in SLC 2x8 segment 2
slc_2_2x8 Rows                                           (pixels)        = 6926                   ; lines in SLC 2x8 segment 2
llh_2_2x8 Columns                                        (pixels)        = 4950                   ; samples in LLH segment 2
llh_2_2x8 Rows                                           (pixels)        = 6926                   ; lines in LLH segment 2
lkv_2_2x8 Columns                                        (pixels)        = 4950                   ; samples in LKV segment 2
lkv_2_2x8 Rows                                           (pixels)        = 6926                   ; lines in LKV segment 2

Read and visualize SLC image

Let’s read the Segment 1 SLC image.

cols_seg1 = 9900
rows_seg1 = 66664  
# Read files
slc_seg1 = np.memmap(f"{slc_f}_s1_1x1.slc",
                     dtype=np.complex64).reshape(rows_seg1, cols_seg1)
# Extract backscatter and phase
backscatter_seg1 = np.abs(slc_seg1)
phase_seg_1 = np.angle(slc_seg1)

Now, let’s read the Segment 2 SLC image.

cols_seg2 = 9900
rows_seg2 = 55408  
# Read files
slc_seg2 = np.memmap(f"{slc_f}_s2_1x1.slc",
               dtype=np.complex64).reshape(rows_seg2, cols_seg2)
# Extract backscatter and phase
backscatter_seg2 = np.abs(slc_seg2)
phase_seg_2 = np.angle(slc_seg2)

Let’s plot backscatter and phase images from both Segments 1 and 2.

# backscatter segment 1
da = xr.DataArray(backscatter_seg1, dims=("y", "x"))
p1 = da.hvplot.image(
    x='x', y='y', rasterize=True, data_aspect=1, frame_width=100,
    cmap='gray', title='backscatter segment1'
)
# phase  segment 1
da = xr.DataArray(phase_seg_1, dims=("y", "x"))
p2 = da.hvplot.image(
    x='x', y='y', rasterize=True, data_aspect=1, frame_width=100,
    cmap='hsv', title='phase segment1'
)

# backscatter segment 2
da = xr.DataArray(backscatter_seg2, dims=("y", "x"))
p3 = da.hvplot.image(
    x='x', y='y', rasterize=True, data_aspect=1, frame_width=100,
    cmap='gray', title='backscatter segment2'
)
# phase  segment 1
da = xr.DataArray(phase_seg_2, dims=("y", "x"))
p4 = da.hvplot.image(
    x='x', y='y', rasterize=True, data_aspect=1, frame_width=100,
    cmap='hsv', title='phase segment2'
)

(p1 + p2 + p3 + p4).cols(4)
Loading...

Generate a single array using the acquisition segments

Let’s take the backscatter from both Segments 1 and 2 and generate one full array.

merged_backscatter = np.concatenate((backscatter_seg1, backscatter_seg2), axis=0)
# print merged backscatter dims
merged_backscatter.shape
(122072, 9900)
da = xr.DataArray(merged_backscatter, dims=("y", "x"))
da.hvplot.image(
    x='x', y='y', rasterize=True, data_aspect=1, frame_width=100,
    cmap='gray', title='phase segment2'
)
Loading...
References
  1. Jones, C., Simard, M., Lou, Y., & Oliver-Cabrera, T. (2022). Delta-X: UAVSAR L1 Single Look Complex (SLC) Stack Products, MRD, Louisiana, 2021. ORNL Distributed Active Archive Center. 10.3334/ORNLDAAC/1984