def read_baseline_info(baseline_file, reference_file): """Read date, bperp and/or DOP info Parameters: baseline_file : str, path of bl_list.txt file reference_file : str, path of ifgramStack.h5 file Returns: date_list : list of str in YYMMDD format tbase_list : list of int in days pbase_list : list of float in meter dop_list : None, list of 1D array in size of (3,) """ dop_list = None if baseline_file: date_list, pbase_list, dop_list = pnet.read_baseline_file( baseline_file)[0:3] date_list = ptime.yymmdd(date_list) tbase_list = ptime.date_list2tbase(date_list)[0] elif reference_file: obj = ifgramStack(reference_file) date12_list_all = obj.get_date12_list(dropIfgram=False) date12_list_all = ptime.yymmdd_date12(date12_list_all) m_dates = [i.split('-')[0] for i in date12_list_all] s_dates = [i.split('-')[1] for i in date12_list_all] date_list = sorted(list(set(m_dates + s_dates))) tbase_list = ptime.date_list2tbase(date_list)[0] pbase_list = obj.get_perp_baseline_timeseries( dropIfgram=False).tolist() return date_list, tbase_list, pbase_list, dop_list
def select_pairs_delaunay(date_list, pbase_list, norm=True, date12_format='YYMMDD-YYMMDD'): """Select Pairs using Delaunay Triangulation based on temporal/perpendicular baselines Inputs: date_list : list of date in YYMMDD/YYYYMMDD format pbase_list : list of float, perpendicular spatial baseline norm : normalize temporal baseline to perpendicular baseline Key points 1. Define a ratio between perpendicular and temporal baseline axis units (Pepe and Lanari, 2006, TGRS). 2. Pairs with too large perpendicular / temporal baseline or Doppler centroid difference should be removed after this, using a threshold, to avoid strong decorrelations (Zebker and Villasenor, 1992, TGRS). Reference: Pepe, A., and R. Lanari (2006), On the extension of the minimum cost flow algorithm for phase unwrapping of multitemporal differential SAR interferograms, IEEE TGRS, 44(9), 2374-2383. Zebker, H. A., and J. Villasenor (1992), Decorrelation in interferometric radar echoes, IEEE TGRS, 30(5), 950-959. """ # Get temporal baseline in days date6_list = ptime.yymmdd(date_list) date8_list = ptime.yyyymmdd(date_list) tbase_list = ptime.date_list2tbase(date8_list)[0] # Normalization (Pepe and Lanari, 2006, TGRS) if norm: temp2perp_scale = (max(pbase_list)-min(pbase_list)) / (max(tbase_list)-min(tbase_list)) tbase_list = [tbase*temp2perp_scale for tbase in tbase_list] # Generate Delaunay Triangulation date12_idx_list = Triangulation(tbase_list, pbase_list).edges.tolist() date12_idx_list = [sorted(idx) for idx in sorted(date12_idx_list)] # Convert index into date12 date12_list = [date6_list[idx[0]]+'-'+date6_list[idx[1]] for idx in date12_idx_list] if date12_format == 'YYYYMMDD_YYYYMMDD': date12_list = ptime.yyyymmdd_date12(date12_list) return date12_list
def velocity2timeseries(date_list, vel=0.03, display=False): '''Simulate displacement time-series from linear velocity Inputs: date_list - list of string in YYYYMMDD or YYMMDD format vel - float, velocity in meter per year display - bool, display simulation or not Output: ts - 2D np.array in size of (date_num,1), displacement time-series in m Example: date_list = pnet.read_baseline_file('bl_list.txt')[0] ts0 = simulate_timeseries(date_list, vel=0.03, display=True) ''' tbase_list = ptime.date_list2tbase(date_list)[0] ts = vel / 365.25 * np.array(tbase_list) ts = ts.reshape(-1,1) if display: dates = ptime.date_list2vector(date_list)[0] ## Display marker_size = 5 plt.figure() plt.scatter(dates, ts*100.0, s=marker_size**2) plt.xlabel('Time (years)') plt.ylabel('LOS Displacement (cm)') plt.title('Displacement time-series with velocity = '+str(vel)+' m/yr') plt.show() return ts
def velocity2timeseries(date_list, vel=0.03, display=False): '''Simulate displacement time-series from linear velocity Inputs: date_list - list of string in YYYYMMDD or YYMMDD format vel - float, velocity in meter per year display - bool, display simulation or not Output: ts - 2D np.array in size of (date_num,1), displacement time-series in m Example: date_list = pnet.read_baseline_file('bl_list.txt')[0] ts0 = simulate_timeseries(date_list, vel=0.03, display=True) ''' tbase_list = ptime.date_list2tbase(date_list)[0] ts = vel / 365.25 * np.array(tbase_list) ts = ts.reshape(-1, 1) if display: dates = ptime.date_list2vector(date_list)[0] ## Display marker_size = 5 plt.figure() plt.scatter(dates, ts * 100.0, s=marker_size**2) plt.xlabel('time [years]') plt.ylabel('LOS displacement [cm]') plt.title('displacement time-series with velocity = ' + str(vel) + ' m/yr') plt.show() return ts
def select_master_date(date_list, pbase_list=[]): """Select super master date based on input temporal and/or perpendicular baseline info. Return master date in YYYYMMDD format. """ date8_list = ptime.yyyymmdd(date_list) if not pbase_list: # Choose date in the middle m_date8 = date8_list[int(len(date8_list)/2)] else: # Get temporal baseline list tbase_list = ptime.date_list2tbase(date8_list)[0] # Normalization (Pepe and Lanari, 2006, TGRS) temp2perp_scale = (max(pbase_list)-min(pbase_list)) / (max(tbase_list)-min(tbase_list)) tbase_list = [tbase*temp2perp_scale for tbase in tbase_list] # Get distance matrix ttMat1, ttMat2 = np.meshgrid(np.array(tbase_list), np.array(tbase_list)) ppMat1, ppMat2 = np.meshgrid(np.array(pbase_list), np.array(pbase_list)) ttMat = np.abs(ttMat1 - ttMat2) # temporal distance matrix ppMat = np.abs(ppMat1 - ppMat2) # spatial distance matrix # 2D distance matrix in temp/perp domain disMat = np.sqrt(np.square(ttMat) + np.square(ppMat)) # Choose date minimize the total distance of temp/perp baseline disMean = np.mean(disMat, 0) m_idx = np.argmin(disMean) m_date8 = date8_list[m_idx] return m_date8
def select_master_date(date_list, pbase_list=[]): """Select super master date based on input temporal and/or perpendicular baseline info. Return master date in YYYYMMDD format. """ date8_list = ptime.yyyymmdd(date_list) if not pbase_list: # Choose date in the middle m_date8 = date8_list[int(len(date8_list) / 2)] else: # Get temporal baseline list tbase_list = ptime.date_list2tbase(date8_list)[0] # Normalization (Pepe and Lanari, 2006, TGRS) temp2perp_scale = (max(pbase_list) - min(pbase_list)) / ( max(tbase_list) - min(tbase_list)) tbase_list = [tbase * temp2perp_scale for tbase in tbase_list] # Get distance matrix ttMat1, ttMat2 = np.meshgrid(np.array(tbase_list), np.array(tbase_list)) ppMat1, ppMat2 = np.meshgrid(np.array(pbase_list), np.array(pbase_list)) ttMat = np.abs(ttMat1 - ttMat2) # temporal distance matrix ppMat = np.abs(ppMat1 - ppMat2) # spatial distance matrix # 2D distance matrix in temp/perp domain disMat = np.sqrt(np.square(ttMat) + np.square(ppMat)) # Choose date minimize the total distance of temp/perp baseline disMean = np.mean(disMat, 0) m_idx = np.argmin(disMean) m_date8 = date8_list[m_idx] return m_date8
def threshold_temporal_baseline(date12_list, btemp_max, keep_seasonal=True, btemp_min=0.0): """Remove pairs/interferograms out of min/max/seasonal temporal baseline limits Inputs: date12_list : list of string for date12 in YYMMDD-YYMMDD format btemp_max : float, maximum temporal baseline btemp_min : float, minimum temporal baseline keep_seasonal : keep interferograms with seasonal temporal baseline Output: date12_list_out : list of string for date12 in YYMMDD-YYMMDD format Example: date12_list = threshold_temporal_baseline(date12_list, 200) date12_list = threshold_temporal_baseline(date12_list, 200, False) """ if not date12_list: return [] # Get date list and tbase list m_dates = [date12.split('-')[0] for date12 in date12_list] s_dates = [date12.split('-')[1] for date12 in date12_list] date8_list = sorted(ptime.yyyymmdd(list(set(m_dates + s_dates)))) date6_list = ptime.yymmdd(date8_list) tbase_list = ptime.date_list2tbase(date8_list)[0] # Threshold date12_list_out = [] for date12 in date12_list: date1, date2 = date12.split('-') idx1 = date6_list.index(date1) idx2 = date6_list.index(date2) tbase = int(abs(tbase_list[idx1] - tbase_list[idx2])) if btemp_min <= tbase <= btemp_max: date12_list_out.append(date12) elif keep_seasonal and tbase/30 in [11, 12]: date12_list_out.append(date12) return date12_list_out
def simulate_coherence_v2(date12_list, decor_time=200.0, coh_resid=0.2, inc_angle=40, 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 display - bool, display result as matrix or not Returns: coh - 2D np.array in size of (ifgram_num) """ num_pair = len(date12_list) date1s = [x.split('_')[0] for x in date12_list] date2s = [x.split('_')[1] for x in date12_list] date_list = sorted(list(set(date1s + date2s))) tbase_list = ptime.date_list2tbase(date_list)[0] SNR = 22 # NESZ = -22 dB from Table 1 in https://sentinels.copernicus.eu/web/sentinel/ coh_thermal = 1. / (1. + 1. / SNR) # bperp rng = np.random.default_rng(2) pbase_list = rng.normal(0, 50, num_pair).tolist() pbase_c = critical_perp_baseline(sensor_name, inc_angle) coh = np.zeros(num_pair, dtype=np.float32) for i in range(num_pair): date1, date2 = date12_list[i].split('_') ind1, ind2 = date_list.index(date1), date_list.index(date2) tbase = tbase_list[ind2] - tbase_list[ind1] pbase = pbase_list[ind2] - pbase_list[ind1] coh_geom = (pbase_c - abs(pbase)) / pbase_c coh_temp = np.multiply( (coh_thermal - coh_resid), np.exp( -1 * abs(tbase) / decor_time)) + coh_resid coh[i] = coh_geom * coh_temp if display: print(('critical perp baseline: %.f m' % pbase_c)) coh_mat = coherence_matrix(date12_list, coh) plt.figure() plt.imshow(coh_mat, vmin=0.0, vmax=1.0, cmap='jet') plt.xlabel('Image number') plt.ylabel('Image number') cbar = plt.colorbar() cbar.set_label('Coherence') plt.title('Coherence matrix') plt.show() return coh
def select_master_interferogram(date12_list, date_list, pbase_list, m_date=None): """Select reference interferogram based on input temp/perp baseline info If master_date is specified, select its closest slave_date, which is newer than master_date; otherwise, choose the closest pair among all pairs as master interferogram. Example: master_date12 = pnet.select_master_ifgram(date12_list, date_list, pbase_list) '080211-080326' = pnet.select_master_ifgram(date12_list, date_list, pbase_list, m_date='080211') """ pbase_array = np.array(pbase_list, dtype='float64') # Get temporal baseline date8_list = ptime.yyyymmdd(date_list) date6_list = ptime.yymmdd(date8_list) tbase_array = np.array(ptime.date_list2tbase(date8_list)[0], dtype='float64') # Normalization (Pepe and Lanari, 2006, TGRS) temp2perp_scale = (max(pbase_array) - min(pbase_array)) / ( max(tbase_array) - min(tbase_array)) tbase_array *= temp2perp_scale # Calculate sqrt of temp/perp baseline for input pairs idx1 = np.array( [date6_list.index(date12.split('-')[0]) for date12 in date12_list]) idx2 = np.array( [date6_list.index(date12.split('-')[1]) for date12 in date12_list]) base_distance = np.sqrt((tbase_array[idx2] - tbase_array[idx1])**2 + (pbase_array[idx2] - pbase_array[idx1])**2) # Get master interferogram index if not m_date: # Choose pair with shortest temp/perp baseline m_date12_idx = np.argmin(base_distance) else: m_date = ptime.yymmdd(m_date) # Choose pair contains m_date with shortest temp/perp baseline m_date12_idx_array = np.array([ date12_list.index(date12) for date12 in date12_list if m_date + '-' in date12 ]) min_base_distance = np.min(base_distance[m_date12_idx_array]) m_date12_idx = np.where(base_distance == min_base_distance)[0][0] m_date12 = date12_list[m_date12_idx] return m_date12
def select_pairs_mst(date_list, pbase_list, date12_format='YYMMDD-YYMMDD'): """Select Pairs using Minimum Spanning Tree technique Connection Cost is calculated using the baseline distance in perp and scaled temporal baseline (Pepe and Lanari, 2006, TGRS) plane. Inputs: date_list : list of date in YYMMDD/YYYYMMDD format pbase_list : list of float, perpendicular spatial baseline References: Pepe, A., and R. Lanari (2006), On the extension of the minimum cost flow algorithm for phase unwrapping of multitemporal differential SAR interferograms, IEEE TGRS, 44(9), 2374-2383. Perissin D., Wang T. (2012), Repeat-pass SAR interferometry with partially coherent targets. IEEE TGRS. 271-280 """ # Get temporal baseline in days date6_list = ptime.yymmdd(date_list) date8_list = ptime.yyyymmdd(date_list) tbase_list = ptime.date_list2tbase(date8_list)[0] # Normalization (Pepe and Lanari, 2006, TGRS) temp2perp_scale = (max(pbase_list) - min(pbase_list)) / (max(tbase_list) - min(tbase_list)) tbase_list = [tbase * temp2perp_scale for tbase in tbase_list] # Get weight matrix ttMat1, ttMat2 = np.meshgrid(np.array(tbase_list), np.array(tbase_list)) ppMat1, ppMat2 = np.meshgrid(np.array(pbase_list), np.array(pbase_list)) ttMat = np.abs(ttMat1 - ttMat2) # temporal distance matrix ppMat = np.abs(ppMat1 - ppMat2) # spatial distance matrix # 2D distance matrix in temp/perp domain weightMat = np.sqrt(np.square(ttMat) + np.square(ppMat)) weightMat = sparse.csr_matrix(weightMat) # compress sparse row matrix # MST path based on weight matrix mstMat = sparse.csgraph.minimum_spanning_tree(weightMat) # Convert MST index matrix into date12 list [s_idx_list, m_idx_list] = [ date_idx_array.tolist() for date_idx_array in sparse.find(mstMat)[0:2] ] date12_list = [] for i in range(len(m_idx_list)): idx = sorted([m_idx_list[i], s_idx_list[i]]) date12 = date6_list[idx[0]] + '-' + date6_list[idx[1]] date12_list.append(date12) if date12_format == 'YYYYMMDD_YYYYMMDD': date12_list = ptime.yyyymmdd_date12(date12_list) return date12_list
def select_pairs_mst(date_list, pbase_list, date12_format='YYMMDD-YYMMDD'): """Select Pairs using Minimum Spanning Tree technique Connection Cost is calculated using the baseline distance in perp and scaled temporal baseline (Pepe and Lanari, 2006, TGRS) plane. Inputs: date_list : list of date in YYMMDD/YYYYMMDD format pbase_list : list of float, perpendicular spatial baseline References: Pepe, A., and R. Lanari (2006), On the extension of the minimum cost flow algorithm for phase unwrapping of multitemporal differential SAR interferograms, IEEE TGRS, 44(9), 2374-2383. Perissin D., Wang T. (2012), Repeat-pass SAR interferometry with partially coherent targets. IEEE TGRS. 271-280 """ # Get temporal baseline in days date6_list = ptime.yymmdd(date_list) date8_list = ptime.yyyymmdd(date_list) tbase_list = ptime.date_list2tbase(date8_list)[0] # Normalization (Pepe and Lanari, 2006, TGRS) temp2perp_scale = (max(pbase_list)-min(pbase_list)) / (max(tbase_list)-min(tbase_list)) tbase_list = [tbase*temp2perp_scale for tbase in tbase_list] # Get weight matrix ttMat1, ttMat2 = np.meshgrid(np.array(tbase_list), np.array(tbase_list)) ppMat1, ppMat2 = np.meshgrid(np.array(pbase_list), np.array(pbase_list)) ttMat = np.abs(ttMat1 - ttMat2) # temporal distance matrix ppMat = np.abs(ppMat1 - ppMat2) # spatial distance matrix # 2D distance matrix in temp/perp domain weightMat = np.sqrt(np.square(ttMat) + np.square(ppMat)) weightMat = sparse.csr_matrix(weightMat) # compress sparse row matrix # MST path based on weight matrix mstMat = sparse.csgraph.minimum_spanning_tree(weightMat) # Convert MST index matrix into date12 list [s_idx_list, m_idx_list] = [date_idx_array.tolist() for date_idx_array in sparse.find(mstMat)[0:2]] date12_list = [] for i in range(len(m_idx_list)): idx = sorted([m_idx_list[i], s_idx_list[i]]) date12 = date6_list[idx[0]]+'-'+date6_list[idx[1]] date12_list.append(date12) if date12_format == 'YYYYMMDD_YYYYMMDD': date12_list = ptime.yyyymmdd_date12(date12_list) return date12_list
def get_design_matrix4time_func(date_list, poly_order=2, step_func_dates=[]): """get design matrix for temporal deformation model""" # temporal baseline in the unit of years tbase = ptime.date_list2tbase(date_list)[0] tbase = np.array(tbase, dtype=np.float32) / 365.25 # 1. Polynomial - 2D matrix in size of (numDate, polyOrder+1) A_def = np.ones((len(date_list), 1), np.float32) for i in range(poly_order): Ai = np.array(tbase**(i + 1) / gamma(i + 2), np.float32).reshape(-1, 1) A_def = np.hstack((A_def, Ai)) # 2. Step function - 2D matrix in size of (numDate, len(step_func_dates)) if step_func_dates: t_steps = ptime.yyyymmdd2years(step_func_dates) t = np.array(ptime.yyyymmdd2years(date_list)) for t_step in t_steps: Ai = np.array(t > t_step, np.float32).reshape(-1, 1) A_def = np.hstack((A_def, Ai)) return A_def
def select_master_interferogram(date12_list, date_list, pbase_list, m_date=None): """Select reference interferogram based on input temp/perp baseline info If master_date is specified, select its closest slave_date, which is newer than master_date; otherwise, choose the closest pair among all pairs as master interferogram. Example: master_date12 = pnet.select_master_ifgram(date12_list, date_list, pbase_list) '080211-080326' = pnet.select_master_ifgram(date12_list, date_list, pbase_list, m_date='080211') """ pbase_array = np.array(pbase_list, dtype='float64') # Get temporal baseline date8_list = ptime.yyyymmdd(date_list) date6_list = ptime.yymmdd(date8_list) tbase_array = np.array(ptime.date_list2tbase(date8_list)[0], dtype='float64') # Normalization (Pepe and Lanari, 2006, TGRS) temp2perp_scale = (max(pbase_array)-min(pbase_array)) / (max(tbase_array)-min(tbase_array)) tbase_array *= temp2perp_scale # Calculate sqrt of temp/perp baseline for input pairs idx1 = np.array([date6_list.index(date12.split('-')[0]) for date12 in date12_list]) idx2 = np.array([date6_list.index(date12.split('-')[1]) for date12 in date12_list]) base_distance = np.sqrt((tbase_array[idx2] - tbase_array[idx1])**2 + (pbase_array[idx2] - pbase_array[idx1])**2) # Get master interferogram index if not m_date: # Choose pair with shortest temp/perp baseline m_date12_idx = np.argmin(base_distance) else: m_date = ptime.yymmdd(m_date) # Choose pair contains m_date with shortest temp/perp baseline m_date12_idx_array = np.array([date12_list.index(date12) for date12 in date12_list if m_date+'-' in date12]) min_base_distance = np.min(base_distance[m_date12_idx_array]) m_date12_idx = np.where(base_distance == min_base_distance)[0][0] m_date12 = date12_list[m_date12_idx] return m_date12
def ifgram_inversion_patch(ifgram_file, box=None, ref_phase=None, obs_ds_name='unwrapPhase', weight_func='var', water_mask_file=None, min_norm_velocity=True, mask_ds_name=None, mask_threshold=0.4, min_redundancy=1.0): """Invert one patch of an ifgram stack into timeseries. Parameters: box - tuple of 4 int, indicating (x0, y0, x1, y1) of the area of interest or None for the whole image ifgram_file - str, interferograms stack HDF5 file, e.g. ./inputs/ifgramStack.h5 ref_phase - 1D array in size of (num_ifgram), or None obs_ds_name - str, dataset to feed the inversion. weight_func - str, weight function, choose in ['no', 'fim', 'var', 'coh'] water_mask_file - str, water mask filename if available, to skip inversion on water min_norm_velocity - bool, minimize the residual phase or phase velocity mask_ds_name - str, dataset name in ifgram_file used to mask unwrapPhase pixelwisely mask_threshold - float, min coherence of pixels if mask_dataset_name='coherence' min_redundancy - float, the min number of ifgrams for every acquisition. Returns: ts - 3D array in size of (num_date, num_row, num_col) temp_coh - 2D array in size of (num_row, num_col) num_inv_ifg - 2D array in size of (num_row, num_col) box - tuple of 4 int Example: ifgram_inversion_patch('ifgramStack.h5', box=(0,200,1316,400)) """ stack_obj = ifgramStack(ifgram_file) stack_obj.open(print_msg=False) # debug #y, x = 258, 454 #box = (x, y, x+1, y+1) ## 1. input info # size if box: num_row = box[3] - box[1] num_col = box[2] - box[0] else: num_row = stack_obj.length num_col = stack_obj.width num_pixel = num_row * num_col # get tbase_diff date_list = stack_obj.get_date_list(dropIfgram=True) num_date = len(date_list) tbase = np.array(ptime.date_list2tbase(date_list)[0], np.float32) / 365.25 tbase_diff = np.diff(tbase).reshape(-1, 1) # design matrix date12_list = stack_obj.get_date12_list(dropIfgram=True) A, B = stack_obj.get_design_matrix4timeseries(date12_list=date12_list)[0:2] # prep for decor std time-series #if os.path.isfile('reference_date.txt'): # ref_date = str(np.loadtxt('reference_date.txt', dtype=bytes).astype(str)) #else: # ref_date = date_list[0] #Astd = stack_obj.get_design_matrix4timeseries(date12_list=date12_list, refDate=ref_date)[0] #ref_idx = date_list.index(ref_date) #time_idx = [i for i in range(num_date)] #time_idx.remove(ref_idx) # skip zero value in the network inversion for phase if 'phase' in obs_ds_name.lower(): skip_zero_value = True else: skip_zero_value = False # 1.1 read / calcualte weight if weight_func in ['no', 'sbas']: weight = None else: weight = calc_weight(stack_obj, box, weight_func=weight_func, dropIfgram=True, chunk_size=100000) # 1.2 read / mask unwrapPhase / offset pha_data = read_unwrap_phase(stack_obj, box, ref_phase, obs_ds_name=obs_ds_name, dropIfgram=True) pha_data = mask_unwrap_phase(pha_data, stack_obj, box, dropIfgram=True, mask_ds_name=mask_ds_name, mask_threshold=mask_threshold) # 1.3 mask of pixels to invert mask = np.ones(num_pixel, np.bool_) # 1.3.1 - Water Mask if water_mask_file: print('skip pixels on water with mask from file: {}'.format( os.path.basename(water_mask_file))) atr_msk = readfile.read_attribute(water_mask_file) len_msk, wid_msk = int(atr_msk['LENGTH']), int(atr_msk['WIDTH']) if (len_msk, wid_msk) != (stack_obj.length, stack_obj.width): raise ValueError( 'Input water mask file has different size from ifgramStack file.' ) dsName = [ i for i in readfile.get_dataset_list(water_mask_file) if i in ['waterMask', 'mask'] ][0] waterMask = readfile.read(water_mask_file, datasetName=dsName, box=box)[0].flatten() mask *= np.array(waterMask, dtype=np.bool_) del waterMask # 1.3.2 - Mask for Zero Phase in ALL ifgrams if 'phase' in obs_ds_name.lower(): print('skip pixels with zero/nan value in all interferograms') with warnings.catch_warnings(): # ignore warning message for all-NaN slices warnings.simplefilter("ignore", category=RuntimeWarning) phase_stack = np.nanmean(pha_data, axis=0) mask *= np.multiply(~np.isnan(phase_stack), phase_stack != 0.) del phase_stack # 1.3.3 invert pixels on mask 1+2 num_pixel2inv = int(np.sum(mask)) idx_pixel2inv = np.where(mask)[0] print('number of pixels to invert: {} out of {} ({:.1f}%)'.format( num_pixel2inv, num_pixel, num_pixel2inv / num_pixel * 100)) ## 2. inversion # 2.1 initiale the output matrices ts = np.zeros((num_date, num_pixel), np.float32) #ts_std = np.zeros((num_date, num_pixel), np.float32) temp_coh = np.zeros(num_pixel, np.float32) num_inv_ifg = np.zeros(num_pixel, np.int16) # return directly if there is nothing to invert if num_pixel2inv < 1: ts = ts.reshape(num_date, num_row, num_col) #ts_std = ts_std.reshape(num_date, num_row, num_col) temp_coh = temp_coh.reshape(num_row, num_col) num_inv_ifg = num_inv_ifg.reshape(num_row, num_col) return ts, temp_coh, num_inv_ifg # 2.2 un-weighted inversion (classic SBAS) if weight_func in ['no', 'sbas']: # a. mask for Non-Zero Phase in ALL ifgrams (share one B in sbas inversion) if 'phase' in obs_ds_name.lower(): mask_all_net = np.all(pha_data, axis=0) mask_all_net *= mask else: mask_all_net = np.array(mask) mask_part_net = mask ^ mask_all_net del mask # b. invert once for all pixels with obs in all ifgrams if np.sum(mask_all_net) > 0: print(('inverting pixels with valid phase in all ifgrams' ' ({:.0f} pixels) ...').format(np.sum(mask_all_net))) tsi, tcohi, num_ifgi = estimate_timeseries( A, B, tbase_diff, ifgram=pha_data[:, mask_all_net], weight_sqrt=None, min_norm_velocity=min_norm_velocity, min_redundancy=min_redundancy, skip_zero_value=skip_zero_value) ts[:, mask_all_net] = tsi temp_coh[mask_all_net] = tcohi num_inv_ifg[mask_all_net] = num_ifgi # c. pixel-by-pixel for pixels with obs not in all ifgrams if np.sum(mask_part_net) > 0: print(('inverting pixels with valid phase in some ifgrams' ' ({:.0f} pixels) ...').format(np.sum(mask_part_net))) num_pixel2inv = int(np.sum(mask_part_net)) idx_pixel2inv = np.where(mask_part_net)[0] prog_bar = ptime.progressBar(maxValue=num_pixel2inv) for i in range(num_pixel2inv): idx = idx_pixel2inv[i] tsi, tcohi, num_ifgi = estimate_timeseries( A, B, tbase_diff, ifgram=pha_data[:, idx], weight_sqrt=None, min_norm_velocity=min_norm_velocity, min_redundancy=min_redundancy, skip_zero_value=skip_zero_value) ts[:, idx] = tsi.flatten() temp_coh[idx] = tcohi num_inv_ifg[idx] = num_ifgi prog_bar.update(i + 1, every=2000, suffix='{}/{} pixels'.format( i + 1, num_pixel2inv)) prog_bar.close() # 2.3 weighted inversion - pixel-by-pixel else: print('inverting network of interferograms into time-series ...') prog_bar = ptime.progressBar(maxValue=num_pixel2inv) for i in range(num_pixel2inv): idx = idx_pixel2inv[i] tsi, tcohi, num_ifgi = estimate_timeseries( A, B, tbase_diff, ifgram=pha_data[:, idx], weight_sqrt=weight[:, idx], min_norm_velocity=min_norm_velocity, min_redundancy=min_redundancy, skip_zero_value=skip_zero_value) ts[:, idx] = tsi.flatten() temp_coh[idx] = tcohi num_inv_ifg[idx] = num_ifgi prog_bar.update(i + 1, every=2000, suffix='{}/{} pixels'.format(i + 1, num_pixel2inv)) prog_bar.close() del weight del pha_data ## 3. prepare output # 3.1 reshape ts = ts.reshape(num_date, num_row, num_col) #ts_std = ts_std.reshape(num_date, num_row, num_col) temp_coh = temp_coh.reshape(num_row, num_col) num_inv_ifg = num_inv_ifg.reshape(num_row, num_col) # 3.2 convert displacement unit to meter if obs_ds_name.startswith('unwrapPhase'): phase2range = -1 * float( stack_obj.metadata['WAVELENGTH']) / (4. * np.pi) ts *= phase2range print('converting LOS phase unit from radian to meter') elif obs_ds_name == 'azimuthOffset': az_pixel_size = ut.azimuth_ground_resolution(stack_obj.metadata) ts *= az_pixel_size print('converting azimuth offset unit from pixel ({:.2f} m) to meter'. format(az_pixel_size)) elif obs_ds_name == 'rangeOffset': rg_pixel_size = float(stack_obj.metadata['RANGE_PIXEL_SIZE']) ts *= rg_pixel_size print('converting range offset unit from pixel ({:.2f} m) to meter'. format(rg_pixel_size)) return ts, temp_coh, num_inv_ifg, box
def simulate_coherence(date12_list, baseline_file='bl_list.txt', sensor_name='Env', inc_angle=22.8, decor_time=200.0, coh_resid=0.2, display=False): """Simulate coherence for a given set of interferograms Inputs: date12_list - list of string in YYMMDD-YYMMDD format, indicating pairs configuration baseline_file - string, path of baseline list text file sensor_name - string, SAR sensor name inc_angle - float, incidence angle decor_time - float / 2D np.array in size of (1, pixel_num) decorrelation rate in days, time for coherence to drop to 1/e of its initial value coh_resid - float / 2D np.array in size of (1, pixel_num) long-term coherence, minimum attainable coherence value display - bool, display result as matrix or not Output: cohs - 2D np.array in size of (ifgram_num, pixel_num) Example: date12_list = pnet.get_date12_list('ifgram_list.txt') cohs = simulate_coherences(date12_list, 'bl_list.txt', sensor_name='Tsx') References: Zebker, H. A., & Villasenor, J. (1992). Decorrelation in interferometric radar echoes. IEEE-TGRS, 30(5), 950-959. Hanssen, R. F. (2001). Radar interferometry: data interpretation and error analysis (Vol. 2). Dordrecht, Netherlands: Kluwer Academic Pub. Morishita, Y., & Hanssen, R. F. (2015). Temporal decorrelation in L-, C-, and X-band satellite radar interferometry for pasture on drained peat soils. IEEE-TGRS, 53(2), 1096-1104. Parizzi, A., Cong, X., & Eineder, M. (2009). First Results from Multifrequency Interferometry. A comparison of different decorrelation time constants at L, C, and X Band. ESA Scientific Publications(SP-677), 1-5. """ date_list, pbase_list, dop_list = read_baseline_file(baseline_file)[0:3] tbase_list = ptime.date_list2tbase(date_list)[0] # Thermal decorrelation (Zebker and Villasenor, 1992, Eq.4) SNR = sensor.signal2noise_ratio(sensor_name) coh_thermal = 1. / (1. + 1./SNR) pbase_c = critical_perp_baseline(sensor_name, inc_angle) bandwidth_az = sensor.azimuth_bandwidth(sensor_name) date12_list = ptime.yyyymmdd_date12(date12_list) ifgram_num = len(date12_list) if isinstance(decor_time, (int, float)): pixel_num = 1 decor_time = float(decor_time) else: pixel_num = decor_time.shape[1] if decor_time == 0.: decor_time = 0.01 cohs = np.zeros((ifgram_num, pixel_num), np.float32) for i in range(ifgram_num): if display: sys.stdout.write('\rinterferogram = %4d/%4d' % (i, ifgram_num)) sys.stdout.flush() m_date, s_date = date12_list[i].split('_') m_idx = date_list.index(m_date) s_idx = date_list.index(s_date) pbase = pbase_list[s_idx] - pbase_list[m_idx] tbase = tbase_list[s_idx] - tbase_list[m_idx] # Geometric decorrelation (Hanssen, 2001, Eq. 4.4.12) coh_geom = (pbase_c - abs(pbase)) / pbase_c if coh_geom < 0.: coh_geom = 0. # Doppler centroid decorrelation (Hanssen, 2001, Eq. 4.4.13) if not dop_list: coh_dc = 1. else: coh_dc = calculate_doppler_overlap(dop_list[m_idx], dop_list[s_idx], bandwidth_az) if coh_dc < 0.: coh_dc = 0. # Option 1: Temporal decorrelation - exponential delay model (Parizzi et al., 2009; Morishita and Hanssen, 2015) coh_temp = np.multiply((coh_thermal - coh_resid), np.exp(-1*abs(tbase)/decor_time)) + coh_resid coh = coh_geom * coh_dc * coh_temp cohs[i, :] = coh #epsilon = 1e-3 #cohs[cohs < epsilon] = epsilon if display: print('') if display: print(('critical perp baseline: %.f m' % pbase_c)) cohs_mat = coherence_matrix(date12_list, cohs) plt.figure() plt.imshow(cohs_mat, vmin=0.0, vmax=1.0, cmap='jet') plt.xlabel('Image number') plt.ylabel('Image number') cbar = plt.colorbar() cbar.set_label('Coherence') plt.title('Coherence matrix') plt.show() return cohs
def simulate_coherence(date12_list, baseline_file='bl_list.txt', sensor_name='Env', inc_angle=22.8, decor_time=200.0, coh_resid=0.2, display=False): """Simulate coherence for a given set of interferograms Inputs: date12_list - list of string in YYMMDD-YYMMDD format, indicating pairs configuration baseline_file - string, path of baseline list text file sensor_name - string, SAR sensor name inc_angle - float, incidence angle decor_time - float / 2D np.array in size of (1, pixel_num) decorrelation rate in days, time for coherence to drop to 1/e of its initial value coh_resid - float / 2D np.array in size of (1, pixel_num) long-term coherence, minimum attainable coherence value display - bool, display result as matrix or not Output: cohs - 2D np.array in size of (ifgram_num, pixel_num) Example: date12_list = pnet.get_date12_list('ifgram_list.txt') cohs = simulate_coherences(date12_list, 'bl_list.txt', sensor_name='Tsx') References: Zebker, H. A., & Villasenor, J. (1992). Decorrelation in interferometric radar echoes. IEEE-TGRS, 30(5), 950-959. Hanssen, R. F. (2001). Radar interferometry: data interpretation and error analysis (Vol. 2). Dordrecht, Netherlands: Kluwer Academic Pub. Morishita, Y., & Hanssen, R. F. (2015). Temporal decorrelation in L-, C-, and X-band satellite radar interferometry for pasture on drained peat soils. IEEE-TGRS, 53(2), 1096-1104. Parizzi, A., Cong, X., & Eineder, M. (2009). First Results from Multifrequency Interferometry. A comparison of different decorrelation time constants at L, C, and X Band. ESA Scientific Publications(SP-677), 1-5. """ date_list, pbase_list, dop_list = read_baseline_file(baseline_file)[0:3] tbase_list = ptime.date_list2tbase(date_list)[0] # Thermal decorrelation (Zebker and Villasenor, 1992, Eq.4) SNR = sensor.signal2noise_ratio(sensor_name) coh_thermal = 1. / (1. + 1. / SNR) pbase_c = critical_perp_baseline(sensor_name, inc_angle) bandwidth_az = sensor.azimuth_bandwidth(sensor_name) date12_list = ptime.yyyymmdd_date12(date12_list) ifgram_num = len(date12_list) if isinstance(decor_time, (int, float)): pixel_num = 1 decor_time = float(decor_time) else: pixel_num = decor_time.shape[1] if decor_time == 0.: decor_time = 0.01 cohs = np.zeros((ifgram_num, pixel_num), np.float32) for i in range(ifgram_num): if display: sys.stdout.write('\rinterferogram = %4d/%4d' % (i, ifgram_num)) sys.stdout.flush() m_date, s_date = date12_list[i].split('_') m_idx = date_list.index(m_date) s_idx = date_list.index(s_date) pbase = pbase_list[s_idx] - pbase_list[m_idx] tbase = tbase_list[s_idx] - tbase_list[m_idx] # Geometric decorrelation (Hanssen, 2001, Eq. 4.4.12) coh_geom = (pbase_c - abs(pbase)) / pbase_c if coh_geom < 0.: coh_geom = 0. # Doppler centroid decorrelation (Hanssen, 2001, Eq. 4.4.13) if not dop_list: coh_dc = 1. else: coh_dc = calculate_doppler_overlap(dop_list[m_idx], dop_list[s_idx], bandwidth_az) if coh_dc < 0.: coh_dc = 0. # Option 1: Temporal decorrelation - exponential delay model (Parizzi et al., 2009; Morishita and Hanssen, 2015) coh_temp = np.multiply( (coh_thermal - coh_resid), np.exp( -1 * abs(tbase) / decor_time)) + coh_resid coh = coh_geom * coh_dc * coh_temp cohs[i, :] = coh #epsilon = 1e-3 #cohs[cohs < epsilon] = epsilon if display: print('') if display: print(('critical perp baseline: %.f m' % pbase_c)) cohs_mat = coherence_matrix(date12_list, cohs) plt.figure() plt.imshow(cohs_mat, vmin=0.0, vmax=1.0, cmap='jet') plt.xlabel('Image number') plt.ylabel('Image number') cbar = plt.colorbar() cbar.set_label('Coherence') plt.title('Coherence matrix') plt.show() return cohs