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)
示例#2
0
    def test_doa_estimate_bartlett(self):
        M = 4
        N = 2**12
        d = 0.5
        theta = 60
        ula_alignment = np.arange(0, 4, 1) * 0.5
        incident_angles = np.arange(0, 181, 1)
        scan_vecs = directionEstimation.gen_ula_scanning_vectors(
            ula_alignment,
            incident_angles
        )

        doa_est = ettusdf.DOAEstimator(
            array_type='ULA',
            array_alignment=ula_alignment,
            incident_angles=incident_angles,
            estimator='Bartlett'
        )

        a = np.exp(np.arange(0, M, 1)*1j*2*np.pi*d*np.cos(np.deg2rad(theta)))
        soi = np.random.normal(0, 1, N)
        soi_matrix = np.outer(soi, a).T
        noise = np.random.normal(0, np.sqrt(10**-1), (M,N))
        rx_signal = soi_matrix
        R = directionEstimation.corr_matrix_estimate(rx_signal.T, imp="mem_eff")
        Bartlett = directionEstimation.DOA_Bartlett(R, scan_vecs)

        np.testing.assert_array_equal(Bartlett, doa_est.estimate_doa(rx_signal))
示例#3
0
    def get_doa_estimate(self):
        self.spectrum[1, :] = 10 * np.log10(
            np.fft.fftshift(
                np.abs(
                    np.fft.fft(self.receiver.iq_samples[
                        0, 0:self.spectrum_sample_size]))))
        iq_samples = self.receiver.iq_samples[:, 0:self.doa_sample_size]
        R = de.corr_matrix_estimate(iq_samples.T, imp="fast")
        M = np.size(iq_samples, 0)
        self.doa_theta = np.linspace(0, 360, 361)
        x = DOA_INTER_ELEM_SPACE * np.cos(2 * np.pi / M * np.arange(M))
        y = 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)

        self.doa_bartlett_res = de.DOA_Bartlett(R, scanning_vectors)

        thetas = self.doa_theta
        bartlett = self.doa_bartlett_res
        doa = 0
        doa_results = []
        combined = np.zeros_like(thetas, dtype=np.complex)
        plt = self.doa_plot_helper(bartlett, thetas)
        combined += np.divide(np.abs(bartlett), np.max(np.abs(bartlett)))
        doa_results.append(thetas[np.argmax(bartlett)])

        if len(doa_results) != 0:
            combined_log = self.doa_plot_helper(combined, thetas)
            confidence = scipy.signal.find_peaks_cwt(combined_log,
                                                     np.arange(10, 30),
                                                     min_snr=1)
            maxIndex = confidence[np.argmax(combined_log[confidence])]
            confidence_sum = 0

            for val in confidence:
                if (val != maxIndex
                        and np.abs(combined_log[val] - min(combined_log)) >
                        np.abs(min(combined_log)) * 0.25):
                    confidence_sum += 1 / (np.abs(combined_log[val]))
                elif val == maxIndex:
                    confidence_sum += 1 / np.abs(min(combined_log))
            max_power_level = np.max(self.spectrum[1, :])
            confidence_sum = 10 / confidence_sum
            doa_results = np.array(doa_results)
            doa_results_c = np.exp(1j * np.deg2rad(doa_results))
            doa_avg_c = np.average(doa_results_c)
            doa = np.rad2deg(np.angle(doa_avg_c))

            if doa < 0:
                doa += 360
            print("---------- DOA Estimate ----------")
            print(str(int(doa)))
            print(str(int(confidence_sum)))
            print(str(np.maximum(0, max_power_level)))
示例#4
0
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
示例#5
0
    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()