def estimate_DOA(self): #print("[ INFO ] Python DSP: Estimating DOA") iq_samples = self.module_receiver.iq_samples[:, 0:self.DOA_sample_size] # Calculating spatial correlation matrix R = de.corr_matrix_estimate(iq_samples.T, imp="fast") if self.en_DOA_FB_avg: R = de.forward_backward_avg(R) M = np.size(iq_samples, 0) if self.DOA_ant_alignment == "UCA": self.DOA_theta = np.linspace(0, 360, 361) #scanning_vectors = de.gen_uca_scanning_vectors(M, self.DOA_inter_elem_space, self.DOA_theta) x = self.DOA_inter_elem_space * np.cos( 2 * np.pi / M * np.arange(M)) y = self.DOA_inter_elem_space * np.sin( -2 * np.pi / M * np.arange(M)) # For this specific array only scanning_vectors = de.gen_scanning_vectors(M, x, y, self.DOA_theta) # DOA estimation if self.en_DOA_Bartlett: self.DOA_Bartlett_res = de.DOA_Bartlett(R, scanning_vectors) if self.en_DOA_Capon: self.DOA_Capon_res = de.DOA_Capon(R, scanning_vectors) if self.en_DOA_MEM: self.DOA_MEM_res = de.DOA_MEM(R, scanning_vectors, column_select=0) if self.en_DOA_MUSIC: self.DOA_MUSIC_res = de.DOA_MUSIC(R, scanning_vectors, signal_dimension=1) elif self.DOA_ant_alignment == "ULA": self.DOA_theta = np.linspace(-90, 90, 181) x = np.zeros(M) y = np.arange(M) * self.DOA_inter_elem_space scanning_vectors = de.gen_scanning_vectors(M, x, y, self.DOA_theta) # DOA estimation if self.en_DOA_Bartlett: self.DOA_Bartlett_res = de.DOA_Bartlett(R, scanning_vectors) if self.en_DOA_Capon: self.DOA_Capon_res = de.DOA_Capon(R, scanning_vectors) if self.en_DOA_MEM: self.DOA_MEM_res = de.DOA_MEM(R, scanning_vectors, column_select=0) if self.en_DOA_MUSIC: self.DOA_MUSIC_res = de.DOA_MUSIC(R, scanning_vectors, signal_dimension=1) print(self.DOA_MUSIC_res)
def target_DOA_estimation(rd_maps, hit_list, DOA_method, array_alignment): """ Performs DOA (Direction of Arrival) estimation for the given hits. To speed up the calculation for multiple hits this function requires the calculated range-Doppler maps from all the surveillance channels. Parameters: ----------- :param: rd_maps: range-Doppler matrices from which the azimuth vector can be extracted :param: hit_list: Contains the delay and Doppler coordinates of the targets. :param: DOA_method: Name of the required algorithm to use for the estimation :param: array_alignment: One dimensional array, which describes the active antenna positions :type : rd_maps: complex valued numpy array with the size of Μ x D x R , where R is equal to the number of range cells, and D denotes the number of Doppler cells. :type: hit_list: Python list [[delay1, Doppler1],[delay2, Doppler2]...]. :type: DOA_method: string :type: array_alignment: real valued numpy array with size of 1 x M, where M is the number of surveillance antenna channels. Return values: -------------- target_doa : Measured incident angles of the targets TODO: Extend with decorrelation support """ doa_list = [] # This list will contains the measured DOA values # Generate scanning vectors thetas = np.arange(0, 180, 1) scanning_vectors = de.gen_ula_scanning_vectors(array_alignment, thetas) for hit in hit_list: azimuth_vector = rd_maps[:, hit[1], hit[0]] R = np.outer(azimuth_vector, azimuth_vector.conj()) if DOA_method == "Fourier": doa_res = de.DOA_Bartlett(R, scanning_vectors) elif DOA_method == "Capon": doa_res = de.DOA_Capon(R, scanning_vectors) elif DOA_method == "MEM": doa_res = de.DOA_MEM(R, scanning_vectors, column_select=0) elif DOA_method == "MUSIC": doa_res = de.DOA_MUSIC(R, scanning_vectors, signal_dimension=1) hit_doa = thetas[np.argmax(doa_res)] doa_list.append(hit_doa) #print("Estimating DOA for hit-> r:{:d} D:{:.2f} Az:{:.2f} ".format(hit[0], hit[1], hit_doa)) return doa_list
def estimate_doa(self, rx_signal): R = directionEstimation.corr_matrix_estimate(rx_signal.T, imp="mem_eff") if self.__estimator == "Bartlett": estimate = directionEstimation.DOA_Bartlett( R, self.__scanning_vectors) elif self.__estimator == "Capon": estimate = directionEstimation.DOA_Capon(R, self.__scanning_vectors) elif self.__estimator == "MEM": estimate = directionEstimation.DOA_MEM(R, self.__scanning_vectors, column_select=0) logging.warning( "Column select is not yet implemented. Set to default (0)") elif self.__estimator == "MUSIC": raise NotImplementedError elif self.__estimator == "MD-MUSIC": raise NotImplementedError return estimate
def DOA_demo(self): self.logger.debug("-> Running simulation <-") soi_theta = self.horizontalSlider_source_DOA.value() M = self.spinBox_noa.value() # Number of antenna elements N = 2**self.spinBox_sample_size.value() r = self.doubleSpinBox_UCA_r.value() d = self.doubleSpinBox_ULA_d.value() K = 1 + self.spinBox_multipath_components.value() alphas = [1.0] thetas = [soi_theta] phases = [0] try: multipath_alphas_str= self.lineEdit_multipath_amplitudes.text().split(',') if self.checkBox_multipath_random_angles.isChecked(): multipath_angles_str = "" for k in range(K-1): theta_rnd=np.random.uniform(0,360) multipath_angles_str += "{:3.1f},".format(theta_rnd) if self.checkBox_multipath_random_phases.isChecked(): multipath_phases_str = "" for k in range(K-1): phase_rnd=np.random.uniform(0,360) multipath_phases_str += "{:3.1f},".format(phase_rnd) self.lineEdit_multipath_phases.setText(multipath_phases_str[:len(multipath_phases_str)-1]) multipath_angles_str= self.lineEdit_multipath_angles.text().split(',') multipath_phases_str= self.lineEdit_multipath_phases.text().split(',') # Add multipath parameters for k in range(K-1): alphas.append(float(multipath_alphas_str[k])) thetas.append(float(multipath_angles_str[k])) phases.append(float(multipath_phases_str[k])) logging.debug("k: {:d}, alpha:{:f} phi:{:f} theta:{:f}".format(k,alphas[k+1],phases[k+1], thetas[k+1])) self.label_status.setText("<span style=\" font-size:8pt; font-weight:600; color:#01df01;\" >Running simulation</span>") except: K=1 alphas = [1.0] phases = [0] thetas = [soi_theta] self.label_status.setText("<span style=\" font-size:8pt; font-weight:600; color:#ff0000;\" >Improper multipath parameters</span>") alphas = 10**(np.array(alphas)/10) * np.exp(1j*np.deg2rad(np.array(phases))) noise_pow = 10**(-1*self.spinBox_snr_dB.value()/10) # Generate the signal of interest soi = np.random.normal(0,1,N) +1j* np.random.normal(0,1,N) # Generate multichannel uncorrelated noise noise = np.random.normal(0, np.sqrt(noise_pow), (M,N) ) +1j* np.random.normal(0, np.sqrt(noise_pow), (M,N) ) """ SNR debug display pn = np.average(np.abs(noise**2)) ps = np.average(np.abs(soi**2)) logging.info("SNR: {:.2f}".format(10*np.log10(ps/pn))) """ self.axes_DOA.clear() legend=[] if self.checkBox_en_UCA.checkState(): #---------------- U C A------------------- A = np.zeros((M, K), dtype=complex) for k in range(K): A[:,k] = np.exp(1j*2*np.pi*r*np.cos(np.radians(thetas[k]-np.arange(0,M,1)*(360)/M))) # UCA soi_matrix = (np.outer( soi, np.inner(A, alphas))).T # Create received signal rec_signal = soi_matrix + noise # Calulcate cross-correlation matrix R = de.corr_matrix_estimate(rec_signal.T, imp="fast") #R = forward_backward_avg(R) # Generate array alignment vector array_alignment = np.arange(0, M, 1) * d scanning_vectors = de.gen_uca_scanning_vectors(M, r, self.thetas) # DOA estimation alias_highlight = False # Track thaht aliase regions are already shown if self.checkBox_en_Bartlett.checkState(): Bartlett = de.DOA_Bartlett(R, scanning_vectors) de.DOA_plot(Bartlett, self.thetas, log_scale_min = -50, axes=self.axes_DOA) legend.append("UCA - Bartlett") self.label_Bartlett_UCA_res.setText("{:.1f}".format(np.argmax(Bartlett))) else: self.label_Bartlett_UCA_res.setText("-") if self.checkBox_en_Capon.checkState(): Capon = de.DOA_Capon(R, scanning_vectors) de.DOA_plot(Capon, self.thetas, log_scale_min = -50, axes=self.axes_DOA) legend.append("UCA - Capon") self.label_Capon_UCA_res.setText("{:.1f}".format(np.argmax(Capon))) else: self.label_Capon_UCA_res.setText("-") if self.checkBox_en_MEM.checkState(): MEM = de.DOA_MEM(R, scanning_vectors, column_select = 0) de.DOA_plot(MEM, self.thetas, log_scale_min = -50, axes=self.axes_DOA) legend.append("MEM") self.label_MEM_UCA_res.setText("{:.1f}".format(np.argmax(MEM))) else: self.label_MEM_UCA_res.setText("-") if self.checkBox_en_MUSIC.checkState(): MUSIC = de.DOA_MUSIC(R, scanning_vectors, signal_dimension = 1) de.DOA_plot(MUSIC, self.thetas, log_scale_min = -50, axes=self.axes_DOA) legend.append("MUSIC") self.label_MUSIC_UCA_res.setText("{:.1f}".format(np.argmax(MUSIC))) else: self.label_MUSIC_UCA_res.setText("-") if self.checkBox_en_ULA.checkState(): #---------------- U L A------------------- # Prepare Array-response matrix A = np.zeros((M, K), dtype=complex) for k in range(K): A[:,k] = np.exp(np.arange(0,M,1)*1j*2*np.pi*d*np.cos(np.deg2rad(thetas[k]))) soi_matrix = (np.outer( soi, np.inner(A, alphas))).T # Create received signal rec_signal = soi_matrix + noise ## R matrix calculation R = de.corr_matrix_estimate(rec_signal.T, imp="fast") if self.checkBox_en_FBavg.isChecked(): R = de.forward_backward_avg(R) # Generate array alignment vector array_alignment = np.arange(0, M, 1) * d scanning_vectors = de.gen_ula_scanning_vectors(array_alignment, self.thetas) # DOA estimation alias_highlight = True # Track thaht aliase regions are already shown if self.checkBox_en_Bartlett.checkState(): Bartlett = de.DOA_Bartlett(R, scanning_vectors) de.DOA_plot(Bartlett, self.thetas, log_scale_min = -50, axes=self.axes_DOA, alias_highlight=alias_highlight, d=d) legend.append("ULA - Bartlett") alias_highlight = False self.label_Bartlett_ULA_res.setText("{:.1f}".format(np.argmax(Bartlett[0:180]))) else: self.label_Bartlett_ULA_res.setText("-") if self.checkBox_en_Capon.checkState(): Capon = de.DOA_Capon(R, scanning_vectors) de.DOA_plot(Capon, self.thetas, log_scale_min = -50, axes=self.axes_DOA, alias_highlight=alias_highlight, d=d) legend.append("ULA - Capon") alias_highlight = False self.label_Capon_ULA_res.setText("{:.1f}".format(np.argmax(Capon[0:180]))) else: self.label_Capon_ULA_res.setText("-") if self.checkBox_en_MEM.checkState(): MEM = de.DOA_MEM(R, scanning_vectors, column_select = 0) de.DOA_plot(MEM, self.thetas, log_scale_min = -50, axes=self.axes_DOA, alias_highlight=alias_highlight, d=d) legend.append("ULA - MEM") alias_highlight = False self.label_MEM_ULA_res.setText("{:.1f}".format(np.argmax(MEM[0:180]))) else: self.label_MEM_ULA_res.setText("-") if self.checkBox_en_MUSIC.checkState(): MUSIC = de.DOA_MUSIC(R, scanning_vectors, signal_dimension = 1) de.DOA_plot(MUSIC, self.thetas, log_scale_min = -50, axes=self.axes_DOA, alias_highlight=alias_highlight, d=d) legend.append("ULA - MUSIC") alias_highlight = False self.label_MUSIC_ULA_res.setText("{:.1f}".format(np.argmax(MUSIC[0:180]))) else: self.label_MUSIC_ULA_res.setText("-") self.axes_DOA.legend(legend) self.canvas_DOA.draw()