diff --git a/src/mintpy/objects/sensor.py b/src/mintpy/objects/sensor.py index e095d7065..c0e576cad 100644 --- a/src/mintpy/objects/sensor.py +++ b/src/mintpy/objects/sensor.py @@ -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'], @@ -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 = { @@ -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, } diff --git a/src/mintpy/utils/network.py b/src/mintpy/utils/network.py index 754ff04c3..21c53f42c 100644 --- a/src/mintpy/utils/network.py +++ b/src/mintpy/utils/network.py @@ -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 @@ -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): @@ -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) """ @@ -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) diff --git a/src/mintpy/utils/ptime.py b/src/mintpy/utils/ptime.py index d0b8cb631..05c13f450 100644 --- a/src/mintpy/utils/ptime.py +++ b/src/mintpy/utils/ptime.py @@ -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