Skip to content

Commit

Permalink
sensor: add UAVSAR-L (#1320)
Browse files Browse the repository at this point in the history
+ `objects/sensor`: add UAVSAR-L info

+ `utils.network.py`:
   - refactor `critical_perp_baseline()` to incorporate different near_range value of different sensors
   - `simulate_coherence_v2()`: add SNR as an input argument

+ `utils.ptime.get_date_range()`: ensure output dt_list is within the input `[dmin, dmax]`
  • Loading branch information
yunjunz authored Feb 10, 2025
1 parent a0079f9 commit 42aa7b5
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 18 deletions.
34 changes: 33 additions & 1 deletion src/mintpy/objects/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
'env' : ['env', 'envisat', 'asar'],
'ers' : ['ers', 'ers1', 'ers2', 'ers12'],
'gf3' : ['gfen3', 'gaofen3', 'g3', 'gaofen'],
'hj1c' : ['hj1', 'huanjing1c'],
'jers' : ['jers', 'jers1'],
'ksat5' : ['ksat5', 'kompsat5', 'kompsat', 'kmps5'],
'lt1' : ['lt1', 'lt', 'lutan', 'lutan1'],
Expand Down Expand Up @@ -569,11 +570,39 @@ def get_unavco_mission_name(meta_dict):
'pulse_repetition_frequency' : 2934, # Hz
'chirp_bandwidth' : 80.0e6, # Hz
'azimuth_pixel_size' : 2.35, # m
'range_pixel_size' : 1.67, # m
'azimuth_resolution' : 7.15, # m
'range_pixel_size' : 1.67, # m
'range_resolution' : 2.50, # m
}

# UAVSAR-L
# Reference:
# https://earth.jpl.nasa.gov/estd-missions/airborne/uavsar/
# https://airbornescience.nasa.gov/instrument/Uninhabited_Aerial_Vehicle_Synthetic_Aperture_Radar
# https://www.eoportal.org/other-space-activities/uavsar
# Fore et al. (2015) at https://doi.org/10.1109/TGRS.2014.2377637
# Hu et al. (2020) at https://doi.org/10.1038/s41467-020-16617-7
# Parameters:
# swath width = 16e3 m
# fly path accuracy <= 10 m
# instrument power = 3.1e3 W
# noise equivalent sigma zero < -50 dB
# operating altitude range = 2e3 - 18e3 m
# ground speed range = 100 - 250 m/s
UAV_L = {
# orbit
'altitude' : 13.8e3, # m, 2 - 18 km
# sar / antenna
'carrier_frequency' : 1.2575e9, # Hz
'antenna_length' : 1.6, # m
'antenna_width' : 0.5, # m
'chirp_bandwidth' : 80e6, # Hz
'range_resolution' : 1.8, # m
'range_pixel_size' : 1.67, # m
'azimuth_resolution' : 0.8, # m
'azimuth_pixel_size' : 0.6, # m
}

# NISAR
# https://nisar.jpl.nasa.gov/system/documents/files/26_NISAR_FINAL_9-6-19.pdf
NISAR_L = {
Expand Down Expand Up @@ -608,11 +637,14 @@ def get_unavco_mission_name(meta_dict):
'rsat2' : RSAT2,
'rcm' : RCM,
'gf3' : GF3,
# S-band
'hj1c' : HJ1C,
# L-band
'jers' : JERS,
'alos' : ALOS,
'alos2' : ALOS2,
'alos4' : ALOS4,
'lt1' : LT1,
'uav' : UAV_L,
'ni' : NISAR_L,
}
54 changes: 37 additions & 17 deletions src/mintpy/utils/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from matplotlib.tri import Triangulation
from scipy import sparse

from mintpy.constants import SPEED_OF_LIGHT
from mintpy.objects import ifgramStack, sensor
from mintpy.utils import ptime, readfile

Expand Down Expand Up @@ -183,19 +184,37 @@ def get_date12_list(fname, dropIfgram=False):
return date12_list


def critical_perp_baseline(sensor_name, inc_angle, print_msg=False):
"""Critical Perpendicular Baseline for each satellite"""
# Jers: 5.712e3 m (near_range=688849.0551m)
# Alos: 6.331e3 m (near_range=842663.2917m)
# Tsx : 8.053e3 m (near_range=634509.1271m)
sensor_dict = sensor.SENSOR_DICT[sensor_name.lower()]
wvl = SPEED_OF_LIGHT / sensor_dict['carrier_frequency']
near_range = 688849 # Yunjun 5/2016, case for Jers, need a automatic way to get this number
rg_bandwidth = sensor_dict['chirp_bandwidth']
bperp_c = wvl * (rg_bandwidth / SPEED_OF_LIGHT) * near_range * np.tan(inc_angle * np.pi / 180.0)
if print_msg:
print(f'Critical Perpendicular Baseline: {bperp_c} m')
return bperp_c
def critical_perp_baseline(sensor_name, inc_angle=30, print_msg=False):
"""Calculate the critical Perpendicular Baseline for each satellite.
Parameters: sensor_name - str, SAR sensor name
inc_angle - float, LOS incidence angle in degrees
Returns: bperp_crit - float, critical perpendicular baseline in meters
typical values: LT1 : 26.6 km
TSX : 8.1 km
ALOS: 6.3 km
JERS: 5.7 km
"""
sensor_name = sensor_name.lower()
if sensor_name not in sensor.SENSOR_DICT.keys():
raise ValueError(f'Un-recognized sensor_name: {sensor_name}')

# sensor parameters
near_range = {
# typical values
'lt1' : 725702,
'tsx' : 634509,
'alos': 842663,
'jers': 688849,
}[sensor_name]
wvl = SPEED_OF_LIGHT / sensor.SENSOR_DICT[sensor_name]['carrier_frequency']
range_bandwidth = sensor.SENSOR_DICT[sensor_name]['chirp_bandwidth']

# calculate critical perpendicular baseline
bperp_crit = wvl * (range_bandwidth / SPEED_OF_LIGHT) * near_range * np.tan(np.deg2rad(inc_angle))
print(f'critical perpendicular baseline: {bperp_crit} m') if print_msg else None

return bperp_crit


def calculate_doppler_overlap(dop_a, dop_b, bandwidth_az):
Expand Down Expand Up @@ -227,14 +246,16 @@ def calculate_doppler_overlap(dop_a, dop_b, bandwidth_az):
return dop_overlap


def simulate_coherence_v2(date12_list, decor_time=200.0, coh_resid=0.2, inc_angle=40, sensor_name='Sen',
display=False):
def simulate_coherence_v2(date12_list, decor_time=200.0, coh_resid=0.2, inc_angle=40,
SNR=22, sensor_name='Sen', display=False):
"""Simulate coherence version 2 (without using bl_list.txt file).
Parameters: date12_list - list of string in YYYYMMDD_YYYYMMDD format, indicating pairs configuration
decor_time - float, decorrelation rate in days, time for coherence to drop to 1/e of its initial value
coh_resid - float, long-term coherence, minimum attainable coherence value
inc_angle - float, incidence angle in degrees
sensor_name - string, SAR sensor name
SNR - float, signal-to-noise ratio in dB
NESZ = -22 dB from Table 1 in https://sentinels.copernicus.eu/web/sentinel
display - bool, display result as matrix or not
Returns: coh - 2D np.array in size of (ifgram_num)
"""
Expand All @@ -244,8 +265,7 @@ def simulate_coherence_v2(date12_list, decor_time=200.0, coh_resid=0.2, inc_angl
date_list = sorted(list(set(date1s + date2s)))
tbase_list = ptime.date_list2tbase(date_list)[0]

SNR = 10 ** (22 / 10) # NESZ = -22 dB from Table 1 in https://sentinels.copernicus.eu/web/sentinel/
coh_thermal = 1. / (1. + 1./SNR)
coh_thermal = 1. / ( 1. + 1. / 10**(SNR / 10) )

# bperp
rng = np.random.default_rng(2)
Expand Down
6 changes: 6 additions & 0 deletions src/mintpy/utils/ptime.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,12 @@ def get_date_range(dmin, dmax, dstep=1, dunit='D', out_fmt='%Y%m%d'):

# prepare date range
dt_objs = np.arange(t1, t2+tstep, tstep, dtype='datetime64').astype('O')

# ensure output dt_list is within [dmin, dmax]
if dt_objs[-1] > t2:
dt_objs = dt_objs[:-1]

# convert datetime.datetime object into given string format
dt_list = [obj.strftime(out_fmt) for obj in dt_objs]

return dt_list
Expand Down

0 comments on commit 42aa7b5

Please sign in to comment.