def __init_neighbours(self, ij_shift: np.ndarray, coh_ps_len: int) -> np.ndarray: """In StaMPS the init value is zero, I use -1 (DEF_NEIGHBOUR_VAL). Because 0 is correct index value in Python, but not in Matlab. -1 is not index in Python""" def arange_neighbours_select_arr(i, ind): return ArrayUtils.arange_include_last(ij_shift[i, ind] - 2, ij_shift[i, ind]) def make_miss_middle_mask(): miss_middle = np.ones((3, 3), dtype=bool) miss_middle[1, 1] = False return miss_middle neighbour_ind = np.ones( (MatlabUtils.max(ij_shift[:, 0]) + 1, MatlabUtils.max(ij_shift[:, 1]) + 1), self.__IND_ARRAY_TYPE) * self.__DEF_NEIGHBOUR_VAL miss_middle = make_miss_middle_mask() for i in range(coh_ps_len): start = arange_neighbours_select_arr(i, 0) end = arange_neighbours_select_arr(i, 1) # To get len(start) * len(end) array in Numpy we need to select it like that. # You can use neighbour_ind[start, :][:, end] but then you need to add values some other # way neighbours_val = neighbour_ind[np.ix_(start, end)] neighbours_val[(neighbours_val == self.__DEF_NEIGHBOUR_VAL) & (miss_middle == True)] = i neighbour_ind[np.ix_(start, end)] = neighbours_val return neighbour_ind
def __get_nr_trial_wraps(self, bperp_meaned, sort_ind_meaned) -> np.float64: # todo what is k? k = self.__ps_files.wavelength * self.__mean_range * np.sin( sort_ind_meaned) / 4 / math.pi max_k = self.__max_topo_err / k bperp_range = MatlabUtils.max(bperp_meaned) - MatlabUtils.min( bperp_meaned) # todo why such formula? return bperp_range * max_k / (2 * math.pi)
def __clap_filt_for_patch(self, ph, low_pass): """Combined Low-pass Adaptive Phase filtering on 1 patch. In StaMPS this is in separate function clap_filt_patch""" alpha = self.__clap_alpha beta = self.__clap_beta if len(low_pass) == 0: low_pass = np.zeros(len(ph)) ph = np.nan_to_num(ph) # todo This ph_fft its very similar with PhEstGamma function clap_filt # todo There where problems (incorrect value) with this part when calling third time ph_fft = np.fft.fft2(ph) smooth_resp = np.abs(ph_fft) smooth_resp = np.fft.ifftshift( MatlabUtils.filter2(self.__gaussian_window, np.fft.fftshift(smooth_resp))) smooth_resp_mean = np.median(smooth_resp.flatten()) if smooth_resp_mean != 0: smooth_resp /= smooth_resp_mean smooth_resp = np.power(smooth_resp, alpha) smooth_resp -= 1 smooth_resp[smooth_resp < 0] = 0 G = smooth_resp * beta + low_pass ph_filt = np.fft.ifft2(np.multiply(ph_fft, G)) return ph_filt
def __get_max_rand(self, da_max: np.ndarray, xy: np.ndarray): """This function finds variable that in StaMPS is called 'max_percent_rand'. In StaMPS this variable is read in parameters. But in this process we also change it a bit we calculate this here""" DEF_VAL = 20 if self.__select_method is self._SelectMethod.DESINTY: # In Stamps min and max values are in separate arrays with a single element. patch_area = np.prod(MatlabUtils.max(xy) - MatlabUtils.min(xy)) / 1e6 # In km max_rand = DEF_VAL * patch_area / (len(da_max) - 1) else: max_rand = DEF_VAL return max_rand
def ph_path_loop(): # In StaMPS this is the place where to delete 'ph_res' and 'ph_patch' that were found # from last process NR_PS = len(coh_thresh_ind) ph_patch = self.__zero_ph_array(NR_PS, data.nr_ifgs) # Similar logic with 'nr_i' ja 'nr_j' already exists in PsEstGamma process nr_i = MatlabUtils.max(self.__ps_est_gamma.grid_ij[:, 0]) nr_j = MatlabUtils.max(self.__ps_est_gamma.grid_ij[:, 1]) # In StaMPS this variable had '2' at the end of the name ph_filt = np.zeros( (self.__clap_win, self.__clap_win, data.nr_ifgs), np.complex128) for i in range(ph_patch.shape[0]): ps_ij = self.__ps_est_gamma.grid_ij[coh_thresh_ind[i], :] i_min, i_max = get_max_min(ps_ij[0] - 1, nr_i) j_min, j_max = get_max_min(ps_ij[1] - 1, nr_j) # If you don't make copy then changes are made also in ph_grid variable ph_bit = np.copy( self.__ps_est_gamma.ph_grid[i_min:i_max + 1, j_min:j_max + 1, :]) ps_bit_i = int(ps_ij[0] - i_min - 1) ps_bit_j = int(ps_ij[1] - j_min - 1) ph_bit[ps_bit_i, ps_bit_j, :] = 0 # todo Some kind of JJS oversample update ph_bit_len = len(ph_bit) + 1 ph_bit_ind_i = get_ph_bit_ind_array(ps_bit_i, ph_bit_len) ph_bit_ind_j = get_ph_bit_ind_array(ps_bit_j, ph_bit_len) ph_bit[ph_bit_ind_i, ph_bit_ind_j, 0] = 0 # It is similar with PsEstGammas ph_flit process but still not the same for j in range(ph_patch.shape[1]): ph_filt[:, :, j] = self.__clap_filt_for_patch( ph_bit[:, :, j], self.__ps_est_gamma.low_pass) ph_patch[i, :] = np.squeeze(ph_filt[ps_bit_i, ps_bit_j, :]) return ph_patch
def __set_internal_params(self): """In StaMPS these where saved with setparam and getparam. All values are that small_baseline_flag = 'N'. In StaMPS max_desinty_rand ja max_percent_rand where two seperate varaibles, there we get them using function __get_max_rand. """ self.__slc_osf = 1 self.__clap_alpha = 1 self.__clap_beta = 0.3 self.__clap_win = 32 self.__select_method = self._SelectMethod.DESINTY # DESINITY or PERCENT # todo Why is this here self.__gamma_stdev_reject = 0 # TODO This is [] in Stamps self.__drop_ifg_index = np.array([]) self.__low_coh_tresh = 31 # 31/100 self.__gaussian_window = np.multiply( np.asmatrix(MatlabUtils.gausswin(7)), np.asmatrix(MatlabUtils.gausswin(7)).conj().transpose())
def ps_topofit_fun(phase: np.ndarray, bperp_meaned: np.ndarray, nr_trial_wraps: float): # To make sure that the results are correct we transform bperp_meaned into column matrix if (len(bperp_meaned.shape) == 1): bperp_meaned = ArrayUtils.to_col_matrix(bperp_meaned) # The result of get_nr_trial_wraps is not correct in this case, so we need to find it again bperp_range = np.amax(bperp_meaned) - np.amin(bperp_meaned) CONST = 8 * nr_trial_wraps # todo what const? Why 8 trial_multi_start = -np.ceil(CONST) trial_multi_end = np.ceil(CONST) trial_multi = ArrayUtils.arange_include_last(trial_multi_start, trial_multi_end, 1) trial_phase = bperp_meaned / bperp_range * math.pi / 4 trial_phase = np.exp(np.outer(-1j * trial_phase, trial_multi)) # In order to successfully multiply, we need to transform 'phase' array to column matrix phase = ArrayUtils.to_col_matrix(phase) phase_tile = np.tile(phase, (1, len(trial_multi))) phaser = np.multiply(trial_phase, phase_tile) phaser_sum = MatlabUtils.sum(phaser) phase_abs_sum = MatlabUtils.sum(np.abs(phase)) trial_coherence = np.abs(phaser_sum) / phase_abs_sum trial_coherence_max_ind = np.where(trial_coherence == MatlabUtils.max(trial_coherence)) k_0 = (math.pi / 4 / bperp_range) * trial_multi[trial_coherence_max_ind][0] re_phase = np.multiply(phase, np.exp(-1j * (k_0 * bperp_meaned))) phase_offset = MatlabUtils.sum(re_phase) re_phase = np.angle(re_phase * phase_offset.conjugate()) weigth = np.abs(phase) bperp_meaned_weighted = weigth * bperp_meaned re_phase_weighted = weigth * re_phase # Numpy linalg functions work only with 2d array if len(bperp_meaned_weighted.shape) > 2: bperp_meaned_weighted = bperp_meaned_weighted[0] if len(re_phase_weighted.shape) > 2: re_phase_weighted = re_phase_weighted[0] mopt = np.linalg.lstsq(bperp_meaned_weighted, re_phase_weighted)[0][0] # In StaMPS k0 k_0 = k_0 + mopt phase_residual = np.multiply(phase, np.exp(-1j * (k_0 * bperp_meaned))) phase_residual_sum = MatlabUtils.sum(phase_residual) # In StaMPS c0 static_offset = np.angle(phase_residual_sum) # In StaMPS coh0 coherence_0 = np.abs(phase_residual_sum) / MatlabUtils.sum(np.abs(phase_residual)) return phase_residual, coherence_0, static_offset, k_0
def random_dist(): NR_RAND_IFGS = nr_ps # In StaMPS it is 300000 random = np.random.RandomState(2005) rnd_ifgs = 2 * math.pi * random.rand(NR_RAND_IFGS, nr_ifgs) random_coherence = np.zeros((NR_RAND_IFGS, 1)) for i in range(NR_RAND_IFGS - 1, 0, -1): phase = np.exp(1j * rnd_ifgs[i]) # We need only coherence here _, coherence_0, _, _ = PsTopofit.ps_topofit_fun( phase, bperp_meaned, nr_trial_wraps) random_coherence[i] = coherence_0[0] del rnd_ifgs hist, _ = MatlabUtils.hist(random_coherence, self.coherence_bins) rand_dist = hist return rand_dist, np.count_nonzero(hist)
def __get_min_coh_and_da_mean( self, coh_ps: np.ndarray, max_rand: float, data: __DataDTO) -> (np.ndarray, np.ndarray, bool): # Internal parameters because full names are bad to write and read all the time coherence_bins = self.__ps_est_gamma.coherence_bins rand_dist = self.__ps_est_gamma.rand_dist array_size = data.da_max.size - 1 min_coh = np.zeros(array_size) # In StaMPS this is size(da_max, 1) what is same as length(da_max) da_mean = np.zeros(array_size) for i in range(array_size): # You can use np.all or np.logical here too. Bitwize isn't must coh_chunk = coh_ps[(data.da > data.da_max[i]) & (data.da <= data.da_max[i + 1])] da_mean[i] = np.mean(data.da[(data.da > data.da_max[i]) & (data.da <= data.da_max[i + 1])]) # Remove pixels that we could not find coherence coh_chunk = coh_chunk[coh_chunk != 0] # In StaMPS this is called 'Na' hist, _ = MatlabUtils.hist(coh_chunk, coherence_bins) hist_low_coh_sum = MatlabUtils.sum(hist[:self.__low_coh_tresh]) rand_dist_low_coh_sum = MatlabUtils.sum( rand_dist[:self.__low_coh_tresh]) nr = rand_dist * hist_low_coh_sum / rand_dist_low_coh_sum # todo What does this 'nr' mean? # In StaMPS here is also possibility to make graph hist[hist == 0] = 1 # Percent_rand calculate # np.flip allows to use one-dimencional arrays, thats why we don't use np.fliplr nr_cumsum = np.cumsum(np.flip(nr, axis=0), axis=0) if self.__select_method is self._SelectMethod.PERCENT: hist_cumsum = np.cumsum(np.flip(hist, axis=0), axis=0) * 100 percent_rand = np.flip(np.divide(nr_cumsum, hist_cumsum), axis=0) else: percent_rand = np.flip(nr_cumsum, axis=0) ok_ind = np.where(percent_rand < max_rand)[0] if len(ok_ind) == 0: # When coherence is over limit min_coh[i] = 1 else: # Here we don't need to add one to indexes because on 'ok_ind' array it is already # done. This means that all those 'magical constants' are that where in StaMPS min_fit_ind = MatlabUtils.min(ok_ind) - 3 # todo Why 3? if min_fit_ind <= 0: min_coh[i] = np.nan else: max_fit_ind = MatlabUtils.min(ok_ind) + 2 # todo Why 2? # In StaMPS this is just constant 100. Not length of array. if max_fit_ind > len(percent_rand) - 1: max_fit_ind = len(percent_rand) - 1 x_cordinates = percent_rand[min_fit_ind:max_fit_ind + 1] y_cordinates = ArrayUtils.arange_include_last( (min_fit_ind + 1) * 0.01, (max_fit_ind + 1) * 0.01, 0.01) min_coh[i] = MatlabUtils.polyfit_polyval( x_cordinates, y_cordinates, 3, max_rand) # Check if min_coh is unusable (full of nan's # This is bit different on StaMPS. I find min_coh'i ja da_mean in same method and in # same time not_nan_ind = np.where(min_coh != np.nan)[0] is_min_coh_nan_array = sum(not_nan_ind) == 0 # When there isn't differences then we don't need to take subsets of arrays if not is_min_coh_nan_array or (not_nan_ind == array_size): min_coh = min_coh[not_nan_ind] da_mean = da_mean[not_nan_ind] return min_coh, da_mean, is_min_coh_nan_array
def __clap_filt(self, ph: np.ndarray, low_pass: np.ndarray): """CLAP_FILT Combined Low-pass Adaptive Phase filtering. Variables nr_win, nr_pad where inputs in StaMPS but these were multiplied before inputing into function. Here it is done internally. Also clap_alpha ja clap_beta where inputs but in this case those are global class variables so we can use them and don't need for inputs""" def create_grid(nr_win: int): grid_array = ArrayUtils.arange_include_last(0, (nr_win / 2) - 1) grid_x, grid_y = np.meshgrid(grid_array, grid_array) grid = grid_x + grid_y return grid # todo What does wind_func mean? This isn't array of functions def make_wind_func(grid: np.ndarray): WIND_FUNC_TYPE = np.float64 wind_func = np.array(np.append(grid, np.fliplr(grid), axis=1), WIND_FUNC_TYPE) wind_func = np.array( np.append(wind_func, np.flipud(wind_func), axis=0), WIND_FUNC_TYPE) # In order to prevent zeros in corners wind_func += 1e-6 return wind_func def get_indexes(loop_index: int, inc: int, nr_win: int) -> (int, int): i1 = loop_index * inc # We don't do -1 because otherwise last element in array is not selected i2 = i1 + nr_win return i1, i2 FILTERED_TYPE = np.complex128 filtered = np.zeros(ph.shape, FILTERED_TYPE) ph = np.nan_to_num(ph) nr_win = int(self.__clap_win * 0.75) nr_pad = int(self.__clap_win * 0.25) ph_i_len = ph.shape[0] - 1 ph_j_len = ph.shape[1] - 1 nr_inc = int(np.floor(nr_win / 4)) # Indices begin from zero on Python. That's why those values are greater than StaMPS nr_win_i = int(np.ceil(ph_i_len / nr_inc) - 3) nr_win_j = int(np.ceil(ph_j_len / nr_inc) - 3) + 1 wind_func = make_wind_func(create_grid(nr_win)) # To make transpose work like Matlab we need to convert those to matrix # todo: PsSelect has similar thing B = np.multiply(np.asmatrix(MatlabUtils.gausswin(7)), np.asmatrix(MatlabUtils.gausswin(7)).transpose()) nr_win_pad_sum = (nr_win + nr_pad) ph_bit = np.zeros((nr_win_pad_sum, nr_win_pad_sum), FILTERED_TYPE) # Todo: Refactor for i in range(nr_win_i): w_f = wind_func.copy() i1, i2 = get_indexes(i, nr_inc, nr_win) if i2 > ph_i_len: i_shift = i2 - ph_i_len - 1 i2 = ph_i_len + 1 i1 = ph_i_len - nr_win + 1 w_f = np.append(np.zeros((i_shift, nr_win)), w_f[:nr_win - i_shift, :], axis=0).astype(FILTERED_TYPE) for j in range(nr_win_j): w_f2 = w_f j1, j2 = get_indexes(j, nr_inc, nr_win) if j2 > ph_j_len: j_shift = j2 - ph_j_len - 1 # Because array lenghts, ph_i_len and ph_j_len, are already smaller and Numpy # does not take last index when selecting, then we need to add one more j2 = ph_j_len + 1 j1 = ph_j_len - nr_win + 1 w_f2 = np.append(np.zeros((nr_win, j_shift)), w_f2[:, :nr_win - j_shift], axis=1).astype(FILTERED_TYPE) ph_bit[:nr_win, :nr_win] = ph[i1:i2, j1:j2] ph_fft = np.fft.fft2( ph_bit ) # todo Todo from fifth decimal point the values are not equal to Stamps result # ph_fft = fftw.interfaces.numpy_fft.fft2(ph_bit) # todo Todo from fifth decimalpoint the values are not equal to Stamps result smooth_resp = np.abs(ph_fft) # 'H' in Stamps smooth_resp = np.fft.ifftshift( MatlabUtils.filter2(B, np.fft.ifftshift(smooth_resp))) # smooth_resp = fftw.interfaces.numpy_fft.ifftshift( # MatlabUtils.filter2(B, fftw.interfaces.numpy_fft.ifftshift(smooth_resp))) mean_smooth_resp = np.median(smooth_resp) if mean_smooth_resp != 0: smooth_resp /= mean_smooth_resp smooth_resp = np.power(smooth_resp, self.__clap_alpha) # todo Values under median to zero. Why that? smooth_resp -= 1 smooth_resp[smooth_resp < 0] = 0 # todo What is G? G = smooth_resp * self.__clap_beta + low_pass ph_filt = np.fft.ifft2(np.multiply(ph_fft, G)) # ph_filt = fftw.interfaces.numpy_fft.ifft2(np.multiply(ph_fft, G)) ph_filt = np.multiply(ph_filt[:nr_win, :nr_win], w_f2) filtered[i1:i2, j1:j2] += ph_filt return filtered
def __sw_loop(self, ph: np.ndarray, weights: np.ndarray, low_pass: np.ndarray, bprep: np.ndarray, nr_ifgs: int, nr_ps: int, nr_trial_wraps: float): SW_ARRAY_SHAPE = (nr_ps, 1) def zero_ps_array_cont(): """Konstruktor tühja pusivpeegeladajate info massiivi loomiseks""" return np.zeros(SW_ARRAY_SHAPE) def get_ph_weight(bprep, k_ps, nr_ifgs, ph, weights): exped = np.exp( np.multiply((-1j * bprep), np.tile(k_ps, (1, nr_ifgs)))) exp_tiled_weight_multi = np.multiply( exped, np.tile(weights, (1, nr_ifgs))) return np.multiply(ph, exp_tiled_weight_multi) def is_gamma_in_change_delta(): return abs(gamma_change_delta) < self.__gamma_change_convergence def make_ph_grid(ph_grid_shape: tuple, grid_ij: np.ndarray, weights: np.ndarray, loop_nr: int) -> np.ndarray: # np.complex128 is needed because this is the type that pydsm.relab.shiftdim returns. # ph_grid and ph_filt are needed to make again. Otherwise there are old values in those # arrays ph_grid = np.zeros(ph_grid_shape, np.complex128) for id in range(loop_nr): x_ind = int(grid_ij[id, 0]) - 1 y_ind = int(grid_ij[id, 1]) - 1 ph_grid[x_ind, y_ind, :] += pydsm.relab.shiftdim(weights[id, :], -1, nargout=1)[0] return ph_grid def make_ph_filt(ph_grid_shape: tuple, ph_grid: np.ndarray, loop_nr: int, low_pass: np.ndarray) -> np.ndarray: ph_filt = np.zeros(ph_grid_shape, np.complex128) for i in range(loop_nr): ph_filt[:, :, i] = self.__clap_filt(ph_grid[:, :, i], low_pass) return ph_filt def make_ph_path(ph_patch: np.ndarray, ph_filt: np.ndarray, grid_ij: np.ndarray, loop_nr: int) -> np.ndarray: for i in range(loop_nr): x_ind = int(grid_ij[i, 0]) - 1 y_ind = int(grid_ij[i, 1]) - 1 ph_patch[i, :nr_ifgs] = np.squeeze(ph_filt[x_ind, y_ind, :]) not_zero_patches_ind = np.nonzero(ph_patch) ph_patch[not_zero_patches_ind] = np.divide( ph_patch[not_zero_patches_ind], np.abs(ph_patch[not_zero_patches_ind])) return ph_patch nr_i = int(np.max(self.grid_ij[:, 0])) nr_j = int(np.max(self.grid_ij[:, 1])) PH_GRID_SHAPE = (nr_i, nr_j, nr_ifgs) coh_ps_result = zero_ps_array_cont() gamma_change = 0 gamma_change_delta = np.inf ph_patch = np.zeros(ph.shape, np.complex128) k_ps = zero_ps_array_cont() # Est topo error # Initializing variables that are returned in the end c_ps = zero_ps_array_cont() n_opt = zero_ps_array_cont() ph_res = np.zeros((nr_ps, nr_ifgs)) log_i = 0 # Used for logging to see how many cycles we have done self.__logger.debug("is_gamma_in_change_delta loop begin") while not is_gamma_in_change_delta(): log_i += 1 self.__logger.debug("gamma change loop i " + str(log_i)) ph_weight = get_ph_weight(bprep, k_ps, nr_ifgs, ph, weights) ph_grid = make_ph_grid(PH_GRID_SHAPE, self.grid_ij, ph_weight, nr_ps) ph_filt = make_ph_filt(PH_GRID_SHAPE, ph_grid, nr_ifgs, low_pass) self.__logger.debug( "ph_filt found. first row: {0}, last row: {1}".format( ph_filt[0], ph_filt[len(ph_filt) - 1])) ph_patch = make_ph_path(ph_patch, ph_filt, self.grid_ij, nr_ps) self.__logger.debug( "ph_patch found. first row: {0}, last row: {1}".format( ph_patch[0], ph_patch[len(ph_patch) - 1])) del ph_filt # This is the slowest part in this process topofit = PsTopofit(SW_ARRAY_SHAPE, nr_ps, nr_ifgs) topofit.ps_topofit_loop(ph, ph_patch, bprep, nr_trial_wraps) k_ps = topofit.k_ps.copy() c_ps = topofit.c_ps.copy() coh_ps = topofit.coh_ps.copy() n_opt = topofit.n_opt.copy() ph_res = topofit.ph_res.copy() del topofit self.__logger.debug("topofit found") gamma_change_rms = np.sqrt( np.sum(np.power(coh_ps - coh_ps_result, 2) / nr_ps)) gamma_change_delta = gamma_change_rms - gamma_change # Saving gamma and coherence that are returned later to temp variables gamma_change = gamma_change_rms coh_ps_result = coh_ps self.__logger.debug( "is_gamma_in_change_delta() and self.__filter_weighting: " + str(not is_gamma_in_change_delta() and self.__filter_weighting == 'P-square')) if not is_gamma_in_change_delta( ) and self.__filter_weighting == 'P-square': # In Stamps it is named 'Na' hist, _ = MatlabUtils.hist(coh_ps, self.coherence_bins) self.__logger.debug("hist[0:3] " + str(hist[:3])) # The random values are transformed into real values here low_coh_thresh_ind = self.__low_coherence_thresh real_distr = np.sum(hist[:low_coh_thresh_ind]) / np.sum( self.rand_dist[:low_coh_thresh_ind]) self.rand_dist = self.rand_dist * real_distr hist[hist == 0] = 1 p_rand = np.divide(self.rand_dist, hist) p_rand[:low_coh_thresh_ind] = 1 p_rand[ self. nr_max_nz_ind:] = 0 # In Stamps nr_max_nz_ind is incremented by one p_rand[p_rand > 1] = 1 p_rand_added_ones = np.append(np.ones(7), p_rand) filtered = scipy.signal.lfilter(MatlabUtils.gausswin(7), [1], p_rand_added_ones) p_rand = filtered / np.sum(MatlabUtils.gausswin(7)) p_rand = p_rand[7:] # Found that 'quadratic' is bit more accurate than 'cubic' p_rand = MatlabUtils.interp(np.append([1.0], p_rand), 10, 'quadratic')[:-9] # Here we covert coh_ps to indexes array. astype is needed because in Numpy all # indexes must be int type. # reshape is needed because coh_ps is array of arrays. coh_ps_as_ind = np.round(coh_ps * 1000).astype(np.int) if len(coh_ps_as_ind.shape) > 1: coh_ps_as_ind = np.squeeze(coh_ps_as_ind) # In Stamps this is 'Prand_ps' ps_rand = p_rand[coh_ps_as_ind].conj().transpose() weights = np.reshape(np.power(1 - ps_rand, 2), SW_ARRAY_SHAPE) return ph_patch, k_ps, c_ps, coh_ps_result, n_opt, ph_res, ph_grid, low_pass
def __drop_noisy(self, data: __DataDTO, selectable_ps: np.ndarray, ifg_ind: np.ndarray, edges: np.ndarray) -> (np.ndarray, np.ndarray): def get_ph_weed(bperp: np.ndarray, k_ps: np.ndarray, ph: np.ndarray, c_ps: np.ndarray, master_nr: int): exped = np.exp(-1j * (k_ps * bperp.conj().transpose())) ph_weed = np.multiply(ph, exped) ph_weed = np.divide(ph_weed, np.abs(ph_weed)) # Adding master noise. It is done when small_baseline_flag != 'y'. Reshape is needed # because 'c_ps' is array of array's ph_weed[:, (master_nr - 1)] = np.exp(1j * c_ps).reshape(len(ph_weed)) return ph_weed def get_time_deltas_in_days(index: int) -> np.ndarray: """For getting days in ints from date object""" return np.array([(ifg_dates[index] - ifg_dates[x]).days for x in np.nditer(ifg_ind)]) def get_dph_mean(dph_space, edges_len, weight_factor): repmat = np.matlib.repmat(weight_factor, edges_len, 1) dph_mean = np.sum(np.multiply(dph_space, repmat), axis=1) return dph_mean ph_filtered = data.ph[selectable_ps] k_ps_filtered = data.k_ps[selectable_ps] c_ps_filtered = data.c_ps[selectable_ps] bperp_meaned = data.bperp_meaned master_nr = data.master_nr ifg_dates = data.ifg_dates ph_weed = get_ph_weed(bperp_meaned, k_ps_filtered, ph_filtered, c_ps_filtered, master_nr) dph_space = np.multiply(ph_weed[edges[:, 2] - 1], ph_weed[edges[:, 1] - 1].conj()) dph_space = dph_space[:, ifg_ind] #todo drop_ifg_index logic # This all is made when small_baseline_flag != 'y' dph_shape = (len(edges), len(ifg_ind)) dph_smooth = np.zeros(dph_shape).astype(np.complex128) dph_smooth2 = np.zeros(dph_shape).astype(np.complex128) for i in range(len(ifg_ind)): time_delta = get_time_deltas_in_days(i) weight_factor = np.exp(-(np.power(time_delta, 2)) / 2 / math.pow(self.__time_win, 2)) weight_factor = weight_factor / np.sum(weight_factor) dph_mean = get_dph_mean(dph_space, len(edges), weight_factor) repmat = np.matlib.repmat( ArrayUtils.to_col_matrix(dph_mean).conj(), 1, len(ifg_ind)) dph_mean_adj = np.angle(np.multiply(dph_space, repmat)) G = np.array([np.ones(len(ifg_ind)), time_delta]).transpose() # 'm' in Stamps weighted_least_sqrt = MatlabUtils.lscov( G, dph_mean_adj.conj().transpose(), weight_factor) #todo Find better name least_sqrt_G = np.asarray( (np.asmatrix(G) * np.asmatrix(weighted_least_sqrt)).conj().transpose()) dph_mean_adj = np.angle(np.exp(1j * (dph_mean_adj - least_sqrt_G))) # 'm2' in Stamps weighted_least_sqrt2 = MatlabUtils.lscov( G, dph_mean_adj.conj().transpose(), weight_factor) # We don't make transpose for weighted_least_sqrt because it doesn't # do anything in this case dph_smooth_val_exp = np.exp( 1j * (weighted_least_sqrt[0, :] + weighted_least_sqrt2[0, :])) dph_smooth[:, i] = np.multiply(dph_mean, dph_smooth_val_exp) weight_factor[i] = 0 # Let's make ourselves as zero dph_smooth2[:, i] = get_dph_mean(dph_space, len(edges), weight_factor) dph_noise = np.angle(np.multiply(dph_space, dph_smooth2.conj())) ifg_var = np.var(dph_noise, 0) dph_noise = np.angle(np.multiply(dph_space, dph_smooth.conj())) K_weights = np.divide(1, ifg_var) K = MatlabUtils.lscov(bperp_meaned, dph_noise.conj().transpose(), K_weights).conj().transpose() dph_noise -= K * bperp_meaned.transpose() edge_std = MatlabUtils.std(dph_noise, axis=1) edge_max = np.max(np.abs(dph_noise), axis=1) return edge_std, edge_max
def test_sum_single(self): self.assertEqual(MatlabUtils.sum(self.__single_row_array), 6)
def test_sum_multi(self): np.testing.assert_array_equal(MatlabUtils.sum(self.__multi_row_array), np.array([5, 7, 9]))
def test_min_single(self): self.assertEqual(MatlabUtils.min(self.__single_row_array), 1)
def test_min_multi(self): np.testing.assert_array_equal(MatlabUtils.min(self.__multi_row_array), np.array([1, 2, 3]))
def test_max_single(self): self.assertEqual(MatlabUtils.max(self.__single_row_array), 3)
def test_max_multi(self): np.testing.assert_array_equal(MatlabUtils.max(self.__multi_row_array), np.array([4, 5, 6]))