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)
Example #2
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)))
Example #3
0
    def __init__(self, array_type="ULA", estimator="MUSIC", **kwargs):
        if array_type not in self.VALID_ARRAY_TYPES:
            raise ValueError(
                "{} not a recognized array type. Must be one of ['ULA', 'UCA', 'Other']"
                .format(array_type))

        def required_arg_check(required_args):
            for arg in required_args:
                if arg not in kwargs:
                    raise ValueError(
                        "Missing required argument: {}".format(arg))

        required_arg_check([
            'incident_angles',
        ])
        self.__incident_angles = kwargs['incident_angles']

        if array_type == "ULA":
            required_args = ['array_alignment']
            required_arg_check(required_args)
            self.__scanning_vectors = \
                directionEstimation.gen_ula_scanning_vectors(
                    kwargs['array_alignment'], kwargs['incident_angles']
                )
        elif array_type == "UCA":
            required_args = ['num_elems', 'radius']
            required_arg_check(required_args)
            self.__scanning_vectors = \
                directionEstimation.gen_uca_scanning_vectors(
                    kwargs['num_elems'],
                    kwargs['radius'],
                    kwargs['incident_angles']
                )
        elif array_type == "Other":
            required_args = ['num_elems', 'x', 'y']
            required_arg_check(required_args)
            self.__scanning_vectors = \
                directionEstimation.gen_scanning_vectors(
                    kwargs['num_elems'],
                    kwargs['x'],
                    kwargs['y'],
                    kwargs['incident_angles'],
                )

        if estimator not in self.VALID_ESTIMATORS:
            raise ValueError("Unrecognized estimator: {}".format(estimator))
        self.__estimator = estimator
    def run(self):
        # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        #
        # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        self.run_processing = True

        while self.run_processing:
            start_time = time.time()

            # Download samples
            #if(self.en_sync or self.en_spectrum):
            #time.sleep(0.25) # You can play with this value, but it may affect stability

            self.module_receiver.download_iq_samples()

            self.DOA_sample_size = self.module_receiver.iq_samples[0, :].size
            self.xcorr_sample_size = self.module_receiver.iq_samples[0, :].size
            self.xcorr = np.ones(
                (self.channel_number - 1, self.xcorr_sample_size * 2),
                dtype=np.complex64)

            # Check overdrive
            if self.module_receiver.overdrive_detect_flag:
                self.signal_overdrive.emit(1)
            else:
                self.signal_overdrive.emit(0)

            # Display spectrum
            if self.en_spectrum:
                self.spectrum[0, :] = np.fft.fftshift(
                    np.fft.fftfreq(self.spectrum_sample_size,
                                   1 / self.fs)) / 10**6

                m = self.channel_number
                #self.spectrum[1:m+1,:] = 10*np.log10(np.fft.fftshift(np.abs(np.fft.fft(self.module_receiver.iq_samples[0:m, 0:self.spectrum_sample_size]))))

                for m in range(self.channel_number):
                    self.spectrum[m + 1, :] = 10 * np.log10(
                        np.fft.fftshift(
                            np.abs(
                                np.fft.fft(self.module_receiver.iq_samples[
                                    m, 0:self.spectrum_sample_size]))))
                self.signal_spectrum_ready.emit()

            # Synchronization
            if self.en_sync or self.timed_sync:
                #print("Sync graph enabled")
                self.sample_delay()
                self.signal_sync_ready.emit()

            # Sample offset compensation request
            if self.en_sample_offset_sync:
                self.module_receiver.set_sample_offsets(self.delay_log[:, -1])
                self.en_sample_offset_sync = False

            # IQ calibration request
            if self.en_calib_iq:
                # IQ correction
                for m in range(self.channel_number):
                    self.module_receiver.iq_corrections[m] *= np.size(
                        self.module_receiver.iq_samples[0, :]) / (np.dot(
                            self.module_receiver.iq_samples[m, :],
                            self.module_receiver.iq_samples[0, :].conj()))
                c = np.sqrt(
                    np.sum(np.abs(self.module_receiver.iq_corrections)**2))
                self.module_receiver.iq_corrections = np.divide(
                    self.module_receiver.iq_corrections, c)
                #print("Corrections: ",self.module_receiver.iq_corrections)
                self.en_calib_iq = False

            if self.en_calib_DOA_90:
                #TODO: Experimental only for UCA, implement this properly!
                # This calibration is currently done for 0 deg not 90
                x = self.DOA_inter_elem_space * np.cos(
                    2 * np.pi / 4 * np.arange(4))
                y = self.DOA_inter_elem_space * np.sin(
                    -2 * np.pi / 4 *
                    np.arange(4))  # For this specific array only
                ref_vector = de.gen_scanning_vectors(4, x, y, np.zeros(1))[:,
                                                                           0]
                #ref_vector = np.exp(1j*2*np.pi*0.5*np.cos(np.radians(0-np.arange(self.channel_number)*(360)/self.channel_number))) # UCA
                N = np.size(self.module_receiver.iq_samples[0, :])
                for m in range(self.channel_number):
                    self.module_receiver.iq_corrections[
                        m] *= ref_vector[m] * N / (np.dot(
                            self.module_receiver.iq_samples[m, :],
                            self.module_receiver.iq_samples[0, :].conj()))
                #print("Corrections: ",self.module_receiver.iq_corrections)
                self.en_calib_DOA_90 = False

            # Direction of Arrival estimation
            if self.en_DOA_estimation:
                # Get FFT for squelch
                self.spectrum[1, :] = 10 * np.log10(
                    np.fft.fftshift(
                        np.abs(
                            np.fft.fft(self.module_receiver.iq_samples[
                                0, 0:self.spectrum_sample_size]))))

                self.estimate_DOA()
                self.signal_DOA_ready.emit()

            # Passive Radar processing
            if self.en_PR_processing:
                #                self.module_receiver.channel_number = 2
                self.PR_processing()
                self.signal_PR_ready.emit()
#            else:
#                self.module_receiver.channel_number = 4

# Record IQ samples
            if self.en_record:
                np.save('hydra_samples.npy', self.module_receiver.iq_samples)

# Code to maintain sync
            '''if self.timed_sync and not self.en_sync:
                if not self.noise_checked:
                    self.module_receiver.switch_noise_source(0)
                self.timed_sync = False
                self.en_sample_offset_sync=True
                self.runningSync = 0

            resync_on = True
            if(self.resync_time < 10):
                resync_on = False

            if(((start_time - self.lastTime) > self.resync_time) and not self.en_sync and resync_on):
                self.lastTime = start_time
                self.module_receiver.switch_noise_source(1)
                time.sleep(0.1)
                self.runningSync = 1
                self.timed_sync = True'''

            stop_time = time.time()
            self.signal_period.emit(stop_time - start_time)