def main():
    code_1 = ca_code.generate(prn=1) | np.roll(ca_code.generate(prn=2), 100)
    code_2 = ca_code.generate(prn=1)

    # code_2 = np.roll(code_2, 100)

    # fftshift(ifft(fft(a,corrLength).*conj(fft(b,corrLength))))

    q = 2
    code_1 = sfft_aliasing.execute(code_1, q)
    code_2 = sfft_aliasing.execute(code_2, q)

    code_1_fft = fourier_transforms.fft(code_1)
    code_2_fft = fourier_transforms.fft(code_2)

    multiplied = code_1_fft * np.conj(code_2_fft)

    print multiplied.size

    params = Parameters(
        n=multiplied.size/2,
        k=1,
        B_k_location=2,
        B_k_estimation=2,
        estimation_loops=8,
        location_loops=5,
        loop_threshold=4,
        tolerance_location=1e-8,
        tolerance_estimation=1e-8
    )
    result = sfft_inverse.execute(params=params, x=multiplied)
    result = fourier_transforms.fftshift(result)

    result_actual = fourier_transforms.ifft(multiplied)
    result_actual = fourier_transforms.fftshift(result_actual)

    print 'sfft size', result.size
    print 'original size', result_actual.size

    fig = plt.figure()
    ax = fig.gca()
    ax.plot(np.linspace(-1, 1, result.size), np.abs(result))
    ax.plot(np.linspace(-1, 1, result_actual.size), np.abs(result_actual))
    plt.show()
def acquisition(x, settings,
                plot_graphs=False,
                plot_3d_graphs=False,
                performance_counter=PerformanceCounter()):
    # Calculate number of samples per spreading code (corresponding to 1ms of data)
    samples_per_code = int(round(settings['sampling_frequency'] * settings['code_length'] / settings['code_frequency']))
    print 'samples_per_code = %s' % repr(samples_per_code)

    # p = int(np.round(np.sqrt(np.log(samples_per_code))))
    # print 'p = ', p
    p = settings['sfft_subsampling_factor']
    n__samples_to_alias = samples_per_code * p
    x_1 = x[0:n__samples_to_alias]
    x_2 = x[n__samples_to_alias:n__samples_to_alias*2]
    x_1 = sfft_aliasing.execute(x_1, p)
    x_2 = sfft_aliasing.execute(x_2, p)

    # print n__samples_to_alias
    # print x_1.shape


    print 'x_1.shape = %s' % repr(x_1.shape)
    print 'x_2.shape = %s' % repr(x_2.shape)

    # Calculate sampling period
    sampling_period = 1.0 / settings['sampling_frequency']
    print 'sampling_period = %s' % repr(sampling_period)

    # Generate phase points of the local carrier
    phases = np.arange(0, samples_per_code) * 2 * np.pi * sampling_period
    print 'phases(%s) = %s' % (repr(phases.shape), repr(phases))

    # Calculate number of frequency bins depending on search frequency band and frequency step
    assert settings['acquisition_search_frequency_band'] % settings['acquisition_search_frequency_step'] == 0, \
        'acquisition_search_frequency_band should be divisible by acquisition_search_frequency_step'
    n_frequency_bins = int(settings['acquisition_search_frequency_band'] / settings['acquisition_search_frequency_step']) + 1
    print 'n_frequency_bins = %s' % repr(n_frequency_bins)

    # Generate and store C/A lookup table
    ca_codes__time = ca_code.generate_table(settings)

    # SFFT
    ca_codes__freq = np.conjugate(fft(ca_codes__time))
    print 'ca_codes__time(%s) = %s' % (repr(ca_codes__time.shape), repr(ca_codes__time))

    # Allocate memory for the 2D search
    all_results = np.empty(shape=(n_frequency_bins, samples_per_code))

    # Generate all frequency bins
    frequency_bins = (
        settings['intermediate_frequency'] - \
        (settings['acquisition_search_frequency_band'] / 2) + \
        settings['acquisition_search_frequency_step'] * np.arange(n_frequency_bins)
    ).astype(int)
    print 'frequency_bins(%s) = %s' % (repr(frequency_bins.shape), repr(frequency_bins))

    # Allocate memory for output dictionary
    satellites_to_search__shape = settings['satellites_to_search'].shape
    output = {
        'frequency_shifts': np.zeros(satellites_to_search__shape),
        'code_shifts': np.zeros(satellites_to_search__shape),
        'peak_ratios': np.zeros(satellites_to_search__shape),
        'found': np.zeros(satellites_to_search__shape, dtype=np.bool),
    }

    for idx, prn in enumerate(settings['satellites_to_search']):
        print '* searching PRN = %s' % (repr(prn),)

        #
        # Scan all Doppler shifts
        #
        for freq_bin_i in xrange(n_frequency_bins):
            # Generate local sine and cosine carriers
            carrier_sin = np.sin(frequency_bins[freq_bin_i] * phases)
            carrier_cos = np.cos(frequency_bins[freq_bin_i] * phases)

            # Demodulation
            I1 = carrier_sin * x_1
            Q1 = carrier_cos * x_1
            I2 = carrier_sin * x_2
            Q2 = carrier_cos * x_2

            # Reconstruct baseband signal
            IQ1 = I1 + 1j*Q1
            IQ2 = I2 + 1j*Q2

            # if settings['use_sfft']:
            #     IQ1 = sfft_aliasing.execute(IQ1, settings['sfft_subsampling_factor'])
            #     IQ2 = sfft_aliasing.execute(IQ2, settings['sfft_subsampling_factor'])
            #     performance_counter.increase(additions=IQ1.size * settings['sfft_subsampling_factor'])
            #     performance_counter.increase(additions=IQ2.size * settings['sfft_subsampling_factor'])

            # Convert to frequency domain
            IQ1_freq = fft(IQ1)
            IQ2_freq = fft(IQ2)
            performance_counter.fft(IQ1.size)
            performance_counter.fft(IQ2.size)

            # Multiplication in the frequency domain corresponds to convolution in the time domain
            conv_code_IQ1 = IQ1_freq * ca_codes__freq[prn-1]
            conv_code_IQ2 = IQ2_freq * ca_codes__freq[prn-1]
            performance_counter.increase(multiplications=IQ1_freq.size)
            performance_counter.increase(multiplications=IQ2_freq.size)

            # IFFT to obtain correlation
            corr_result_1 = np.abs(ifft(conv_code_IQ1)) ** 2
            corr_result_2 = np.abs(ifft(conv_code_IQ2)) ** 2

            # assert all_results[freq_bin_i, :].shape == corr_result_1.shape == corr_result_2.shape

            if np.max(corr_result_1) > np.max(corr_result_2):
                all_results[freq_bin_i, :] = corr_result_1
            else:
                all_results[freq_bin_i, :] = corr_result_2

        # Get the peak location for every frequency bins
        peak_values = all_results.max(axis=1)
        assert all_results.max() in peak_values

        # Find the Doppler shift index
        frequency_shift_idx = peak_values.argmax()
        print 'frequency_shift_idx = %s' % repr(frequency_shift_idx)

        # Select the frequency bin that corresponds to this frequency shift index
        located_frequency_bin = all_results[frequency_shift_idx]

        # Find the code shift in the correct frequency bin
        code_shift = located_frequency_bin.argmax()
        output['code_shifts'][idx] = code_shift
        print 'code_shift = %s' % repr(code_shift)

        peak_value = all_results[frequency_shift_idx][code_shift]
        assert all_results.max() == peak_value
        print 'peak_value = %s' % repr(peak_value)

        if plot_3d_graphs:
            fig = plt.figure()
            doppler_shifts__khz = (
                (settings['acquisition_search_frequency_step'] * np.arange(n_frequency_bins)) -
                (settings['acquisition_search_frequency_band'] / 2)
            ) / 1000

            ax = fig.gca(projection='3d')
            surf = ax.plot_surface(
                X=np.arange(samples_per_code).reshape((1, -1)),
                Y=doppler_shifts__khz.reshape((-1, 1)),
                Z=all_results,
                rstride=1,
                cstride=1,
                cmap=matplotlib.cm.coolwarm,
                linewidth=0,
                antialiased=False,
            )
            ax.set_xlabel('Code shift')
            ax.set_ylabel('Doppler shift (kHz)')
            ax.set_zlabel('Magnitude')

        # Calculate code phase range
        samples_per_code_chip = int(round(settings['sampling_frequency'] / settings['code_frequency']))


        print 'samples_per_code_chip = %s' % repr(samples_per_code_chip)

        #
        # Get second largest peak value outside the chip where the maximum peak is located
        #

        # Calculate excluded range
        excluded_range_1 = code_shift - samples_per_code_chip
        excluded_range_2 = code_shift + samples_per_code_chip
        print 'excluded_range_1 = %s' % repr(excluded_range_1)
        print 'excluded_range_2 = %s' % repr(excluded_range_2)

        # Excluded range boundary correction
        if excluded_range_1 < 1:
            print 'excluded_range_1 < 1'
            code_phase_range = np.arange(excluded_range_2, samples_per_code + excluded_range_1)
        elif excluded_range_2 >= samples_per_code:
            print 'excluded_range_2 >= samples_per_code'
            code_phase_range = np.arange(excluded_range_2 - samples_per_code, excluded_range_1)
        else:
            code_phase_range = np.concatenate((
                np.arange(0, excluded_range_1),
                np.arange(excluded_range_2, samples_per_code)
            ))

        assert code_shift not in code_phase_range
        print 'code_phase_range(%s) = %s' % (repr(code_phase_range.shape), repr(code_phase_range))

        # Get second largest peak value
        second_peak_value = all_results[frequency_shift_idx, code_phase_range].max()
        print 'second_peak_value = %s' % repr(second_peak_value)

        # Calculate ratio between the largest peak value and the second largest peak value
        peak_ratio = peak_value / second_peak_value
        print 'peak_ratio = %s' % repr(peak_ratio)
        output['peak_ratios'][idx] = peak_ratio

        #
        # Thresholding
        #

        if peak_ratio > settings['acquisition_threshold']:
            output['found'][idx] = True
            print '-> %s FOUND' % repr(prn)
        else:
            output['found'][idx] = False
            print '-> %s NOT FOUND' % repr(prn)

    if plot_graphs:
        plt.figure()
        colors = ['r' if found else 'b' for found in output['found']]
        plt.bar(settings['satellites_to_search'], output['peak_ratios'], color=colors, align='center')
        plt.ylabel('Acquisition quality')
        plt.xlabel('PRN number')

        artist__not_acquired = plt.Rectangle((0, 0), 1, 1, fc='b')
        artist__acquired = plt.Rectangle((0, 0), 1, 1, fc='r')
        plt.legend((
            artist__not_acquired,
            artist__acquired
        ), (
            'Not acquired',
            'Acquired'
        ))
        plt.xlim(0, settings['satellites_total'] + 1)

        plt.grid()
        plt.tight_layout()

    return output, performance_counter
def acquisition(x, settings, plot_graphs=False, plot_3d_graphs=False, performance_counter=PerformanceCounter()):
    # Calculate number of samples per spreading code (corresponding to 1ms of data)
    samples_per_code = int(round(settings["sampling_frequency"] * settings["code_length"] / settings["code_frequency"]))
    print "samples_per_code = %s" % repr(samples_per_code)

    # SFFT
    aliased_samples_per_code = int(samples_per_code / settings["sfft_subsampling_factor"])

    if settings["use_sfft"]:
        actual_samples_per_code = aliased_samples_per_code
    else:
        actual_samples_per_code = samples_per_code

    # Two consecutive 2ms reading
    # x_1 = x[(settings['code_offset']*samples_per_code):(settings['code_offset']*samples_per_code + samples_per_code)]
    # x_2 = x[(settings['code_offset']*samples_per_code + samples_per_code):(settings['code_offset']*samples_per_code + 2*samples_per_code)]
    x_1 = x[0:samples_per_code]
    x_2 = x[samples_per_code : 2 * samples_per_code]

    print "x_1.shape = %s" % repr(x_1.shape)
    print "x_2.shape = %s" % repr(x_2.shape)
    assert x_1.shape == x_2.shape

    # Calculate sampling period
    sampling_period = 1.0 / settings["sampling_frequency"]
    print "sampling_period = %s" % repr(sampling_period)

    # Generate phase points of the local carrier
    phases = np.arange(0, samples_per_code) * 2 * np.pi * sampling_period
    print "phases(%s) = %s" % (repr(phases.shape), repr(phases))

    # Calculate number of frequency bins depending on search frequency band and frequency step
    assert (
        settings["acquisition_search_frequency_band"] % settings["acquisition_search_frequency_step"] == 0
    ), "acquisition_search_frequency_band should be divisible by acquisition_search_frequency_step"
    n_frequency_bins = (
        int(settings["acquisition_search_frequency_band"] / settings["acquisition_search_frequency_step"]) + 1
    )
    print "n_frequency_bins = %s" % repr(n_frequency_bins)

    # Generate and store C/A lookup table
    ca_codes__time = ca_code.generate_table(settings)

    # SFFT
    if settings["use_sfft"]:
        aliased_ca_codes__time = np.empty(shape=(settings["satellites_total"], aliased_samples_per_code))

        for i in xrange(ca_codes__time.shape[0]):
            aliased_ca_codes__time[i] = sfft_aliasing.execute(ca_codes__time[i], settings["sfft_subsampling_factor"])

        ca_codes__time = aliased_ca_codes__time

    ca_codes__freq = np.conjugate(fft(ca_codes__time))
    print "ca_codes__time(%s) = %s" % (repr(ca_codes__time.shape), repr(ca_codes__time))

    # Allocate memory for the 2D search
    all_results = np.empty(shape=(n_frequency_bins, actual_samples_per_code))

    # Generate all frequency bins
    frequency_bins = (
        settings["intermediate_frequency"]
        - (settings["acquisition_search_frequency_band"] / 2)
        + settings["acquisition_search_frequency_step"] * np.arange(n_frequency_bins)
    ).astype(int)
    print "frequency_bins(%s) = %s" % (repr(frequency_bins.shape), repr(frequency_bins))

    # Allocate memory for output dictionary
    satellites_to_search__shape = settings["satellites_to_search"].shape
    output = {
        "frequency_shifts": np.zeros(satellites_to_search__shape),
        "frequency_offsets": np.zeros(satellites_to_search__shape),
        "code_shifts": np.zeros(satellites_to_search__shape),
        "peak_ratios": np.zeros(satellites_to_search__shape),
        "found": np.zeros(satellites_to_search__shape, dtype=np.bool),
    }

    for idx, prn in enumerate(settings["satellites_to_search"]):
        print "* searching PRN = %s" % (repr(prn),)

        #
        # Scan all Doppler shifts
        #
        for freq_bin_i in xrange(n_frequency_bins):
            # Generate local sine and cosine carriers
            carrier_sin = np.sin(frequency_bins[freq_bin_i] * phases)
            carrier_cos = np.cos(frequency_bins[freq_bin_i] * phases)

            # Demodulation
            I1 = carrier_sin * x_1
            Q1 = carrier_cos * x_1
            I2 = carrier_sin * x_2
            Q2 = carrier_cos * x_2

            # Reconstruct baseband signal
            IQ1 = I1 + 1j * Q1
            IQ2 = I2 + 1j * Q2

            if settings["use_sfft"]:
                IQ1 = sfft_aliasing.execute(IQ1, settings["sfft_subsampling_factor"])
                IQ2 = sfft_aliasing.execute(IQ2, settings["sfft_subsampling_factor"])
                performance_counter.increase(additions=IQ1.size * settings["sfft_subsampling_factor"])
                performance_counter.increase(additions=IQ2.size * settings["sfft_subsampling_factor"])

            # Convert to frequency domain
            IQ1_freq = fft(IQ1)
            IQ2_freq = fft(IQ2)
            performance_counter.fft(IQ1.size)
            performance_counter.fft(IQ2.size)

            # Multiplication in the frequency domain corresponds to convolution in the time domain
            conv_code_IQ1 = IQ1_freq * ca_codes__freq[prn - 1]
            conv_code_IQ2 = IQ2_freq * ca_codes__freq[prn - 1]
            performance_counter.increase(multiplications=IQ1_freq.size)
            performance_counter.increase(multiplications=IQ2_freq.size)

            # IFFT to obtain correlation
            corr_result_1 = np.abs(ifft(conv_code_IQ1)) ** 2
            corr_result_2 = np.abs(ifft(conv_code_IQ2)) ** 2

            # assert all_results[freq_bin_i, :].shape == corr_result_1.shape == corr_result_2.shape

            if np.max(corr_result_1) > np.max(corr_result_2):
                all_results[freq_bin_i, :] = corr_result_1
            else:
                all_results[freq_bin_i, :] = corr_result_2

        # Get the peak location for every frequency bins
        peak_values = all_results.max(axis=1)
        assert all_results.max() in peak_values

        # Find the Doppler shift index
        frequency_shift_idx = peak_values.argmax()
        print "frequency_shift_idx = %s" % repr(frequency_shift_idx)

        # Select the frequency bin that corresponds to this frequency shift index
        located_frequency_bin = all_results[frequency_shift_idx]

        # Find the code shift in the correct frequency bin
        code_shift = located_frequency_bin.argmax()
        output["code_shifts"][idx] = code_shift
        print "code_shift = %s" % repr(code_shift)

        peak_value = all_results[frequency_shift_idx][code_shift]
        assert all_results.max() == peak_value
        print "peak_value = %s" % repr(peak_value)

        # Doppler shifts
        doppler_shifts__khz = (settings["acquisition_search_frequency_step"] * np.arange(n_frequency_bins)) - (
            settings["acquisition_search_frequency_band"] / 2
        )
        output["frequency_shifts"][idx] = frequency_bins[frequency_shift_idx]
        output["frequency_offsets"][idx] = doppler_shifts__khz[frequency_shift_idx]

        if plot_3d_graphs:
            fig = plt.figure()

            ax = fig.gca(projection="3d")
            surf = ax.plot_surface(
                X=np.arange(actual_samples_per_code).reshape((1, -1)),
                Y=doppler_shifts__khz.reshape((-1, 1)) / 1000,
                Z=all_results,
                rstride=1,
                cstride=1,
                cmap=matplotlib.cm.coolwarm,
                linewidth=0,
                antialiased=False,
            )
            ax.set_xlabel("Code shift")
            ax.set_ylabel("Doppler shift (kHz)")
            ax.set_zlabel("Magnitude")

        # Calculate code phase range
        samples_per_code_chip = int(round(settings["sampling_frequency"] / settings["code_frequency"]))

        # SFFT
        if settings["use_sfft"]:
            samples_per_code_chip = int(samples_per_code_chip / settings["sfft_subsampling_factor"])

        print "samples_per_code_chip = %s" % repr(samples_per_code_chip)

        #
        # Get second largest peak value outside the chip where the maximum peak is located
        #

        # Calculate excluded range
        excluded_range_1 = code_shift - samples_per_code_chip
        excluded_range_2 = code_shift + samples_per_code_chip
        print "excluded_range_1 = %s" % repr(excluded_range_1)
        print "excluded_range_2 = %s" % repr(excluded_range_2)

        # Excluded range boundary correction
        if excluded_range_1 < 1:
            print "excluded_range_1 < 1"
            code_phase_range = np.arange(excluded_range_2, actual_samples_per_code + excluded_range_1)
        elif excluded_range_2 >= actual_samples_per_code:
            print "excluded_range_2 >= samples_per_code"
            code_phase_range = np.arange(excluded_range_2 - actual_samples_per_code, excluded_range_1)
        else:
            code_phase_range = np.concatenate(
                (np.arange(0, excluded_range_1), np.arange(excluded_range_2, actual_samples_per_code))
            )

        assert code_shift not in code_phase_range
        print "code_phase_range(%s) = %s" % (repr(code_phase_range.shape), repr(code_phase_range))

        # Get second largest peak value
        second_peak_value = all_results[frequency_shift_idx, code_phase_range].max()
        print "second_peak_value = %s" % repr(second_peak_value)

        # Calculate ratio between the largest peak value and the second largest peak value
        peak_ratio = peak_value / second_peak_value
        print "peak_ratio = %s" % repr(peak_ratio)
        output["peak_ratios"][idx] = peak_ratio

        #
        # Thresholding
        #

        if peak_ratio > settings["acquisition_threshold"]:
            output["found"][idx] = True
            print "-> %s FOUND" % repr(prn)
        else:
            output["found"][idx] = False
            print "-> %s NOT FOUND" % repr(prn)

    if plot_graphs:
        plt.figure()
        colors = ["r" if found else "b" for found in output["found"]]
        plt.bar(settings["satellites_to_search"], output["peak_ratios"], color=colors, align="center")
        plt.ylabel("Acquisition quality")
        plt.xlabel("PRN number")

        artist__not_acquired = plt.Rectangle((0, 0), 1, 1, fc="b")
        artist__acquired = plt.Rectangle((0, 0), 1, 1, fc="r")
        plt.legend((artist__not_acquired, artist__acquired), ("Signal not acquired", "Signal acquired"))
        plt.xlim(0, settings["satellites_total"] + 1)

        plt.tight_layout()

    return output, performance_counter
Example #4
0
def acquisition(x,
                settings,
                plot_graphs=False,
                plot_3d_graphs=False,
                performance_counter=PerformanceCounter()):
    # Calculate number of samples per spreading code (corresponding to 1ms of data)
    samples_per_code = int(
        round(settings['sampling_frequency'] * settings['code_length'] /
              settings['code_frequency']))
    # print 'samples_per_code = %s' % repr(samples_per_code)

    # SFFT
    aliased_samples_per_code = int(samples_per_code /
                                   settings['sfft_subsampling_factor'])

    if settings['use_sfft']:
        actual_samples_per_code = aliased_samples_per_code
    else:
        actual_samples_per_code = samples_per_code

    # Calculate sampling period
    sampling_period = 1.0 / settings['sampling_frequency']
    # print 'sampling_period = %s' % repr(sampling_period)

    # Generate phase points of the local carrier
    phases = np.arange(0, samples_per_code) * 2 * np.pi * sampling_period
    # print 'phases(%s) = %s' % (repr(phases.shape), repr(phases))

    # Calculate number of frequency bins depending on search frequency band and frequency step
    assert settings['acquisition_search_frequency_band'] % settings['acquisition_search_frequency_step'] == 0, \
        'acquisition_search_frequency_band should be divisible by acquisition_search_frequency_step'
    n_frequency_bins = int(settings['acquisition_search_frequency_band'] /
                           settings['acquisition_search_frequency_step']) + 1
    # print 'n_frequency_bins = %s' % repr(n_frequency_bins)

    # Generate and store C/A lookup table
    ca_codes__time = ca_code.generate_table(settings)

    # SFFT
    if settings['use_sfft']:
        aliased_ca_codes__time = np.empty(shape=(settings['satellites_total'],
                                                 aliased_samples_per_code))

        for i in xrange(ca_codes__time.shape[0]):
            aliased_ca_codes__time[i] = sfft_aliasing.execute(
                ca_codes__time[i], settings['sfft_subsampling_factor'])

        ca_codes__time = aliased_ca_codes__time

    ca_codes__freq = np.conjugate(fft(ca_codes__time))
    # print 'ca_codes__time(%s) = %s' % (repr(ca_codes__time.shape), repr(ca_codes__time))

    # Allocate memory for the 2D search
    all_results = np.empty(shape=(n_frequency_bins, actual_samples_per_code))

    # Generate all frequency bins
    frequency_bins = (
        settings['intermediate_frequency'] - \
        (settings['acquisition_search_frequency_band'] / 2) + \
        settings['acquisition_search_frequency_step'] * np.arange(n_frequency_bins)
    ).astype(int)
    # print 'frequency_bins(%s) = %s' % (repr(frequency_bins.shape), repr(frequency_bins))

    # Allocate memory for output dictionary
    satellites_to_search__shape = settings['satellites_to_search'].shape
    output = {
        'frequency_shifts': np.zeros(satellites_to_search__shape, dtype=int),
        'code_shifts': np.zeros(satellites_to_search__shape, dtype=int),
        'peak_ratios': np.zeros(satellites_to_search__shape),
        'found': np.zeros(satellites_to_search__shape, dtype=np.bool),
    }

    correct_runs = 0
    run_number = 0

    for idx, prn in enumerate(settings['satellites_to_search']):
        print '* searching PRN = %s' % (repr(prn), )

        # correct_runs = 0
        # run_number = 0

        summed_corr_result_magnitudes = np.zeros(actual_samples_per_code)

        counter = 10
        while counter > 0:
            counter -= 1

            # Two consecutive 2ms reading
            # x_1 = x[(settings['code_offset']*samples_per_code):(settings['code_offset']*samples_per_code + samples_per_code)]
            # x_2 = x[(settings['code_offset']*samples_per_code + samples_per_code):(settings['code_offset']*samples_per_code + 2*samples_per_code)]
            x_1 = x[run_number *
                    samples_per_code:(run_number * samples_per_code +
                                      samples_per_code)]
            # print 'x_1.shape = %s' % repr(x_1.shape)

            run_number += 1
            print 'run_number = %s' % repr(run_number)

            #
            # Scan all Doppler shifts
            #
            for freq_bin_i in xrange(n_frequency_bins):
                # Generate local sine and cosine carriers
                carrier_sin = np.sin(frequency_bins[freq_bin_i] * phases)
                carrier_cos = np.cos(frequency_bins[freq_bin_i] * phases)

                # Demodulation
                I1 = carrier_sin * x_1
                Q1 = carrier_cos * x_1
                # I2 = carrier_sin * x_2
                # Q2 = carrier_cos * x_2

                # Reconstruct baseband signal
                IQ1 = I1 + 1j * Q1
                # IQ2 = I2 + 1j*Q2

                if settings['use_sfft']:
                    IQ1 = sfft_aliasing.execute(
                        IQ1, settings['sfft_subsampling_factor'])
                    # IQ2 = sfft_aliasing.execute(IQ2, settings['sfft_subsampling_factor'])
                    performance_counter.increase(
                        additions=IQ1.size *
                        settings['sfft_subsampling_factor'])
                    # performance_counter.increase(additions=IQ2.size * settings['sfft_subsampling_factor'])

                # Convert to frequency domain
                IQ1_freq = fft(IQ1)
                # IQ2_freq = fft(IQ2)
                performance_counter.fft(IQ1.size)
                # performance_counter.fft(IQ2.size)

                # Multiplication in the frequency domain corresponds to convolution in the time domain
                conv_code_IQ1 = IQ1_freq * ca_codes__freq[prn - 1]
                # conv_code_IQ2 = IQ2_freq * ca_codes__freq[prn-1]
                performance_counter.increase(multiplications=IQ1_freq.size)
                # performance_counter.increase(multiplications=IQ2_freq.size)

                # IFFT to obtain correlation
                corr_result = np.abs(ifft(conv_code_IQ1))**2
                # corr_result_2 = np.abs(ifft(conv_code_IQ2)) ** 2

                # assert all_results[freq_bin_i, :].shape == corr_result_1.shape == corr_result_2.shape

                # if np.max(corr_result_1) > np.max(corr_result_2):
                all_results[freq_bin_i, :] = corr_result
                # else:
                #     all_results[freq_bin_i, :] = corr_result_2

            # Get the peak location for every frequency bins
            peak_values = all_results.max(axis=1)
            assert all_results.max() in peak_values

            # Find the Doppler shift index
            frequency_shift_idx = peak_values.argmax()
            # print 'frequency_shift_idx = %s' % repr(frequency_shift_idx)

            # Select the frequency bin that corresponds to this frequency shift index
            located_frequency_bin = all_results[frequency_shift_idx]

            # Find the code shift in the correct frequency bin
            code_shift = located_frequency_bin.argmax()
            # output['code_shifts'][idx] = code_shift
            # print 'code_shift = %s' % repr(code_shift)

            peak_value = located_frequency_bin[code_shift]
            assert all_results.max() == peak_value
            # print 'peak_value = %s' % repr(peak_value)

            print np.abs(code_shift - settings['actual_satellite_shifts'][idx])

            if np.abs(code_shift -
                      settings['actual_satellite_shifts'][idx]) < 40:
                correct_runs += 1
                print 'CORRECT RUN!'

            # # New Threshold calculation
            # summed_corr_result_magnitudes += np.abs(located_frequency_bin)
            # # print 'here', summed_corr_result_magnitudes.argmax()
            # snr = get_snr(summed_corr_result_magnitudes)
            # print 'snr', snr
            # if snr > settings['snr_threshold']:
            #     output['found'][idx] = True
            #     print 'summed_corr_result_magnitudes', summed_corr_result_magnitudes
            #     output['code_shifts'][idx] = summed_corr_result_magnitudes.argmax()
            #     break
            #
            # if plot_3d_graphs:
            #     fig = plt.figure()
            #     doppler_shifts__khz = (
            #         (settings['acquisition_search_frequency_step'] * np.arange(n_frequency_bins)) -
            #         (settings['acquisition_search_frequency_band'] / 2)
            #     ) / 1000
            #
            #     ax = fig.gca(projection='3d')
            #     surf = ax.plot_surface(
            #         X=np.arange(actual_samples_per_code).reshape((1, -1)),
            #         Y=doppler_shifts__khz.reshape((-1, 1)),
            #         Z=all_results,
            #         rstride=1,
            #         cstride=1,
            #         cmap=matplotlib.cm.coolwarm,
            #         linewidth=0,
            #         antialiased=False,
            #     )
            #     ax.set_xlabel('Code shift')
            #     ax.set_ylabel('Doppler shift (kHz)')
            #
            # # Calculate code phase range
            # samples_per_code_chip = int(round(settings['sampling_frequency'] / settings['code_frequency']))
            #
            # # SFFT
            # if settings['use_sfft']:
            #     samples_per_code_chip = int(samples_per_code_chip / settings['sfft_subsampling_factor'])
            #
            # print 'samples_per_code_chip = %s' % repr(samples_per_code_chip)
            #
            # #
            # # Get second largest peak value outside the chip where the maximum peak is located
            # #
            #
            # # Calculate excluded range
            # excluded_range_1 = code_shift - samples_per_code_chip
            # excluded_range_2 = code_shift + samples_per_code_chip
            # print 'excluded_range_1 = %s' % repr(excluded_range_1)
            # print 'excluded_range_2 = %s' % repr(excluded_range_2)
            #
            # # Excluded range boundary correction
            # if excluded_range_1 < 1:
            #     print 'excluded_range_1 < 1'
            #     code_phase_range = np.arange(excluded_range_2, actual_samples_per_code + excluded_range_1)
            # elif excluded_range_2 >= actual_samples_per_code:
            #     print 'excluded_range_2 >= samples_per_code'
            #     code_phase_range = np.arange(excluded_range_2 - actual_samples_per_code, excluded_range_1)
            # else:
            #     code_phase_range = np.concatenate((
            #         np.arange(0, excluded_range_1),
            #         np.arange(excluded_range_2, actual_samples_per_code)
            #     ))
            #
            # assert code_shift not in code_phase_range
            # print 'code_phase_range(%s) = %s' % (repr(code_phase_range.shape), repr(code_phase_range))
            #
            # # Get second largest peak value
            # second_peak_value = all_results[frequency_shift_idx, code_phase_range].max()
            # print 'second_peak_value = %s' % repr(second_peak_value)
            #
            # # Calculate ratio between the largest peak value and the second largest peak value
            # peak_ratio = peak_value / second_peak_value
            # print 'peak_ratio = %s' % repr(peak_ratio)
            # output['peak_ratios'][idx] = peak_ratio
            #
            # #
            # # Thresholding
            # #
            #
            # if peak_ratio > settings['acquisition_threshold']:
            #     output['found'][idx] = True
            #     print '-> %s FOUND' % repr(prn)
            # else:
            #     output['found'][idx] = False
            #     print '-> %s NOT FOUND' % repr(prn)

    if plot_graphs:
        plt.figure()
        colors = ['r' if found else 'b' for found in output['found']]
        plt.bar(settings['satellites_to_search'],
                output['peak_ratios'],
                color=colors,
                align='center')
        plt.ylabel('Acquisition quality')
        plt.xlabel('PRN number')

        artist__not_acquired = plt.Rectangle((0, 0), 1, 1, fc='b')
        artist__acquired = plt.Rectangle((0, 0), 1, 1, fc='r')
        plt.legend((artist__not_acquired, artist__acquired),
                   ('Signal not acquired', 'Signal acquired'))
        plt.xlim(0, settings['satellites_total'] + 1)

        plt.tight_layout()

    if run_number == 0:
        output['success_probability'] = 0
    else:
        output['success_probability'] = correct_runs / run_number

    print output['success_probability']

    return output, performance_counter
def main():
    # (a) Input
    code = ca_code.generate(prn=1, repeats=10)
    # rx = np.roll(ca_code.generate(prn=1, repeats=10), -10230/6*1) | ca_code.generate(prn=2, repeats=10)
    rx = np.roll(ca_code.generate(prn=1, repeats=10), 1000) | ca_code.generate(prn=2, repeats=10)

    noise_std = 1
    noise = np.random.normal(
        scale=noise_std,
        size=code.size,
    )

    rx = np.add(rx, noise)

    # (b) Aliasing
    q = 2
    code_aliased = sfft_aliasing.execute(code, q)
    rx_aliased = sfft_aliasing.execute(rx, q)

    # (c) FFT
    code_f = fft(code_aliased)
    rx_f = fft(rx_aliased)

    # (d) Multiply
    code_rx_f = np.multiply(np.conjugate(code_f), rx_f)

    # (e) IFFT
    code_rx = np.real(ifft(code_rx_f))

    print 'arg max is', np.argmax(code_rx)

    plt.figure('Local C/A code')
    plt.step(np.arange(code.size), code)
    plt.xlim(0, code.size-1)
    plt.title('Local C/A code')
    plt.xlabel('Time')
    plt.setp(plt.gca().get_xticklabels(), visible=False)
    plt.setp(plt.gca().get_yticklabels(), visible=False)

    plt.figure('Received signal')
    plt.plot(rx)
    plt.xlim(0, code.size-1)
    plt.title('Received signal')
    plt.xlabel('Time')
    plt.setp(plt.gca().get_xticklabels(), visible=False)
    plt.setp(plt.gca().get_yticklabels(), visible=False)

    plt.figure('Aliased Local C/A code')
    plt.step(np.arange(code_aliased.size), code_aliased)
    plt.xlim(0, code_aliased.size-1)
    plt.title('Local C/A code (Aliased)')
    plt.xlabel('Time')
    plt.setp(plt.gca().get_xticklabels(), visible=False)
    plt.setp(plt.gca().get_yticklabels(), visible=False)

    plt.figure('Aliased Received signal')
    plt.plot(rx_aliased)
    plt.xlim(0, rx_aliased.size-1)
    plt.title('Received signal (Aliased)')
    plt.xlabel('Time')
    plt.setp(plt.gca().get_xticklabels(), visible=False)
    plt.setp(plt.gca().get_yticklabels(), visible=False)

    plt.figure('FFT of Local CA code')
    plt.plot(np.abs(fftshift(code_f)))
    plt.title('FFT of Local C/A code')
    plt.xlabel('Frequency')
    plt.xlim(1000, 4000)
    plt.ylim(0, 500)
    plt.setp(plt.gca().get_xticklabels(), visible=False)
    plt.setp(plt.gca().get_yticklabels(), visible=False)

    plt.figure('FFT of Received signal')
    plt.plot(np.abs(fftshift(rx_f)))
    plt.title('FFT of Received signal')
    plt.xlabel('Frequency')
    plt.xlim(1000, 4000)
    plt.ylim(0, 500)
    plt.setp(plt.gca().get_xticklabels(), visible=False)
    plt.setp(plt.gca().get_yticklabels(), visible=False)

    plt.figure('Multiply')
    plt.plot(np.abs(fftshift(code_rx_f)))
    plt.title('Multiply')
    plt.xlabel('Frequency')
    plt.xlim(1500, 3500)
    plt.ylim(0, 100000)
    plt.setp(plt.gca().get_xticklabels(), visible=False)
    plt.setp(plt.gca().get_yticklabels(), visible=False)

    plt.figure('IFFT')
    plt.plot(code_rx)
    plt.title('IFFT')
    plt.xlim(0, code_rx.size-1)
    plt.setp(plt.gca().get_xticklabels(), visible=False)
    plt.setp(plt.gca().get_yticklabels(), visible=False)

    plt.show()
def acquisition(x,
                settings,
                plot_graphs=False,
                plot_3d_graphs=False,
                performance_counter=PerformanceCounter()):
    # Calculate number of samples per spreading code (corresponding to 1ms of data)
    samples_per_code = int(
        round(settings['sampling_frequency'] * settings['code_length'] /
              settings['code_frequency']))
    print 'samples_per_code = %s' % repr(samples_per_code)

    assert samples_per_code % settings['sfft_subsampling_factor'] == 0
    aliased_samples_per_code = int(samples_per_code /
                                   settings['sfft_subsampling_factor'])

    # Calculate sampling period
    sampling_period = 1.0 / settings['sampling_frequency']
    print 'sampling_period = %s' % repr(sampling_period)

    # Generate phase points of the local carrier
    phases = np.arange(0,
                       aliased_samples_per_code) * 2 * np.pi * sampling_period
    print 'phases(%s) = %s' % (repr(phases.shape), repr(phases))

    # Calculate number of frequency bins depending on search frequency band and frequency step
    assert settings['acquisition_search_frequency_band'] % settings['acquisition_search_frequency_step'] == 0, \
        'acquisition_search_frequency_band should be divisible by acquisition_search_frequency_step'
    n_frequency_bins = int(settings['acquisition_search_frequency_band'] /
                           settings['acquisition_search_frequency_step']) + 1
    print 'n_frequency_bins = %s' % repr(n_frequency_bins)

    # Generate and store C/A lookup table
    ca_codes__time = ca_code.generate_table(settings)

    # SFFT
    # ca_codes__freq = np.conjugate(fft(ca_codes__time))
    # print 'ca_codes__time(%s) = %s' % (repr(ca_codes__time.shape), repr(ca_codes__time))

    # Allocate memory for the 2D search
    all_results = np.empty(shape=(n_frequency_bins, aliased_samples_per_code))

    # Generate all frequency bins
    frequency_bins = (
        settings['intermediate_frequency'] - \
        (settings['acquisition_search_frequency_band'] / 2) + \
        settings['acquisition_search_frequency_step'] * np.arange(n_frequency_bins)
    ).astype(int)
    print 'frequency_bins(%s) = %s' % (repr(
        frequency_bins.shape), repr(frequency_bins))

    # Allocate memory for output dictionary
    satellites_to_search__shape = settings['satellites_to_search'].shape
    output = {
        'frequency_shifts': np.zeros(satellites_to_search__shape),
        'code_shifts': np.zeros(satellites_to_search__shape),
        'peak_ratios': np.zeros(satellites_to_search__shape),
        'found': np.zeros(satellites_to_search__shape, dtype=np.bool),
    }

    for idx, prn in enumerate(settings['satellites_to_search']):
        print '* searching PRN = %s' % (repr(prn), )

        result_summation = np.zeros(aliased_samples_per_code)

        for sum_idx in xrange(settings['sfft_sum_results']):
            # Get data
            x_1 = x[sum_idx * samples_per_code:sum_idx * samples_per_code +
                    samples_per_code]
            assert x_1.size == samples_per_code
            x_1 = sfft_aliasing.execute(x_1,
                                        settings['sfft_subsampling_factor'])
            assert x_1.size == aliased_samples_per_code

            x_2 = x[sum_idx * samples_per_code +
                    samples_per_code:sum_idx * samples_per_code +
                    2 * samples_per_code]
            assert x_2.size == samples_per_code
            x_2 = sfft_aliasing.execute(x_2,
                                        settings['sfft_subsampling_factor'])
            assert x_2.size == aliased_samples_per_code

            #
            # Scan all Doppler shifts
            #
            for freq_bin_i in xrange(n_frequency_bins):
                # Generate local sine and cosine carriers
                carrier_sin = np.sin(frequency_bins[freq_bin_i] * phases)
                carrier_cos = np.cos(frequency_bins[freq_bin_i] * phases)

                # Demodulation
                I1 = carrier_sin * x_1
                Q1 = carrier_cos * x_1
                I2 = carrier_sin * x_2
                Q2 = carrier_cos * x_2

                # Reconstruct baseband signal
                IQ1 = I1 + 1j * Q1
                IQ2 = I2 + 1j * Q2

                # if settings['use_sfft']:
                #     IQ1 = sfft_aliasing.execute(IQ1, settings['sfft_subsampling_factor'])
                #     IQ2 = sfft_aliasing.execute(IQ2, settings['sfft_subsampling_factor'])
                #     performance_counter.increase(additions=IQ1.size * settings['sfft_subsampling_factor'])
                #     performance_counter.increase(additions=IQ2.size * settings['sfft_subsampling_factor'])

                # Convert to frequency domain
                IQ1_freq = fft(IQ1)
                IQ2_freq = fft(IQ2)
                performance_counter.fft(IQ1.size)
                performance_counter.fft(IQ2.size)

                # Multiplication in the frequency domain corresponds to convolution in the time domain
                aliased_ca_code__time = sfft_aliasing.execute(
                    ca_codes__time[prn - 1],
                    settings['sfft_subsampling_factor'])
                assert aliased_ca_code__time.size == aliased_samples_per_code
                aliased_ca_code__freq = fft(aliased_ca_code__time)
                conv_code_IQ1 = IQ1_freq * aliased_ca_code__freq
                conv_code_IQ2 = IQ2_freq * aliased_ca_code__freq
                performance_counter.increase(multiplications=IQ1_freq.size)
                performance_counter.increase(multiplications=IQ2_freq.size)

                # IFFT to obtain correlation
                corr_result_1 = np.abs(ifft(conv_code_IQ1))**2
                corr_result_2 = np.abs(ifft(conv_code_IQ2))**2

                # assert all_results[freq_bin_i, :].shape == corr_result_1.shape == corr_result_2.shape

                if np.max(corr_result_1) > np.max(corr_result_2):
                    all_results[freq_bin_i, :] = corr_result_1
                else:
                    all_results[freq_bin_i, :] = corr_result_2

            # Get the peak location for every frequency bins
            peak_values = all_results.max(axis=1)
            assert all_results.max() in peak_values

            # Find the Doppler shift index
            frequency_shift_idx = peak_values.argmax()
            print 'frequency_shift_idx = %s' % repr(frequency_shift_idx)

            # Select the frequency bin that corresponds to this frequency shift index
            located_frequency_bin = all_results[frequency_shift_idx]

            result_summation += located_frequency_bin

        plt.figure()
        plt.plot(result_summation / result_summation.max())
        plt.ylabel('Normalised magnitude')
        plt.xlabel('Code shift (chips)')
        plt.title('Summing %d results' % settings['sfft_sum_results'])
        plt.show()
        exit()

        # Find the code shift in the correct frequency bin
        code_shift = result_summation.argmax()
        output['code_shifts'][idx] = code_shift
        print 'code_shift = %s' % repr(code_shift)

        peak_value = result_summation[code_shift]
        assert result_summation.max() == peak_value
        print 'peak_value = %s' % repr(peak_value)

        if plot_3d_graphs:
            fig = plt.figure()
            doppler_shifts__khz = (
                (settings['acquisition_search_frequency_step'] *
                 np.arange(n_frequency_bins)) -
                (settings['acquisition_search_frequency_band'] / 2)) / 1000

            ax = fig.gca(projection='3d')
            surf = ax.plot_surface(
                X=np.arange(samples_per_code).reshape((1, -1)),
                Y=doppler_shifts__khz.reshape((-1, 1)),
                Z=all_results,
                rstride=1,
                cstride=1,
                cmap=matplotlib.cm.coolwarm,
                linewidth=0,
                antialiased=False,
            )
            ax.set_xlabel('Code shift')
            ax.set_ylabel('Doppler shift (kHz)')

        # Calculate code phase range
        samples_per_code_chip = int(
            round(settings['sampling_frequency'] / settings['code_frequency']))

        print 'samples_per_code_chip = %s' % repr(samples_per_code_chip)

        #
        # Get second largest peak value outside the chip where the maximum peak is located
        #

        # Calculate excluded range
        excluded_range_1 = code_shift - samples_per_code_chip
        excluded_range_2 = code_shift + samples_per_code_chip
        print 'excluded_range_1 = %s' % repr(excluded_range_1)
        print 'excluded_range_2 = %s' % repr(excluded_range_2)

        # Excluded range boundary correction
        if excluded_range_1 < 1:
            print 'excluded_range_1 < 1'
            code_phase_range = np.arange(
                excluded_range_2, aliased_samples_per_code + excluded_range_1)
        elif excluded_range_2 >= aliased_samples_per_code:
            print 'excluded_range_2 >= samples_per_code'
            code_phase_range = np.arange(
                excluded_range_2 - aliased_samples_per_code, excluded_range_1)
        else:
            code_phase_range = np.concatenate(
                (np.arange(0, excluded_range_1),
                 np.arange(excluded_range_2, aliased_samples_per_code)))

        assert code_shift not in code_phase_range
        print 'code_phase_range(%s) = %s' % (repr(
            code_phase_range.shape), repr(code_phase_range))

        # Get second largest peak value
        second_peak_value = all_results[frequency_shift_idx,
                                        code_phase_range].max()
        print 'second_peak_value = %s' % repr(second_peak_value)

        # Calculate ratio between the largest peak value and the second largest peak value
        peak_ratio = peak_value / second_peak_value
        print 'peak_ratio = %s' % repr(peak_ratio)
        output['peak_ratios'][idx] = peak_ratio

        #
        # Thresholding
        #

        if peak_ratio > settings['acquisition_threshold']:
            output['found'][idx] = True
            print '-> %s FOUND' % repr(prn)
        else:
            output['found'][idx] = False
            print '-> %s NOT FOUND' % repr(prn)

    if plot_graphs:
        plt.figure()
        colors = ['r' if found else 'b' for found in output['found']]
        plt.bar(settings['satellites_to_search'],
                output['peak_ratios'],
                color=colors,
                align='center')
        plt.ylabel('Acquisition quality')
        plt.xlabel('PRN number')

        artist__not_acquired = plt.Rectangle((0, 0), 1, 1, fc='b')
        artist__acquired = plt.Rectangle((0, 0), 1, 1, fc='r')
        plt.legend((artist__not_acquired, artist__acquired),
                   ('Not acquired', 'Acquired'))
        plt.xlim(0, settings['satellites_total'] + 1)

        plt.grid()
        plt.tight_layout()

    return output, performance_counter
Example #7
0
def single_acquisition(x,
                       prn,
                       settings,
                       plot_3d_graphs=False,
                       performance_counter=PerformanceCounter()):

    # Calculate number of samples per spreading code (corresponding to 1ms of data)
    samples_per_code = int(
        round(settings['sampling_frequency'] * settings['code_length'] /
              settings['code_frequency']))
    print 'samples_per_code = %s' % repr(samples_per_code)

    # SFFT
    aliased_samples_per_code = int(samples_per_code /
                                   settings['sfft_subsampling_factor'])

    if settings['use_sfft']:
        actual_samples_per_code = aliased_samples_per_code
    else:
        actual_samples_per_code = samples_per_code

    # Two consecutive 2ms reading
    x_1 = x[(settings['code_offset'] *
             samples_per_code):((settings['code_offset'] * samples_per_code) +
                                samples_per_code)]
    x_2 = x[(settings['code_offset'] * samples_per_code +
             samples_per_code):(settings['code_offset'] * samples_per_code +
                                2 * samples_per_code)]

    if x_1.size != samples_per_code:
        return False, performance_counter

    print 'x_1.shape = %s' % repr(x_1.shape)
    print 'x_2.shape = %s' % repr(x_2.shape)

    # Calculate sampling period
    sampling_period = 1.0 / settings['sampling_frequency']
    print 'sampling_period = %s' % repr(sampling_period)

    # Generate phase points of the local carrier
    phases = np.arange(0, samples_per_code) * 2 * np.pi * sampling_period
    print 'phases(%s) = %s' % (repr(phases.shape), repr(phases))

    # Calculate number of frequency bins depending on search frequency band and frequency step
    assert settings['acquisition_search_frequency_band'] % settings['acquisition_search_frequency_step'] == 0, \
        'acquisition_search_frequency_band should be divisible by acquisition_search_frequency_step'
    n_frequency_bins = int(settings['acquisition_search_frequency_band'] /
                           settings['acquisition_search_frequency_step']) + 1
    print 'n_frequency_bins = %s' % repr(n_frequency_bins)

    # Generate C/A code
    ca_code__time = ca_code.generate_from_settings(settings, prn=prn)

    # SFFT
    if settings['use_sfft']:
        ca_code__time = sfft_aliasing.execute(
            ca_code__time, settings['sfft_subsampling_factor'])

    ca_codes__freq = np.conjugate(fft(ca_code__time))
    print 'ca_codes__time(%s) = %s' % (repr(
        ca_code__time.shape), repr(ca_code__time))

    # Allocate memory for the 2D search
    all_results = np.empty(shape=(n_frequency_bins, actual_samples_per_code))

    # Generate all frequency bins
    frequency_bins = (
        settings['intermediate_frequency'] - \
        (settings['acquisition_search_frequency_band'] / 2) + \
        settings['acquisition_search_frequency_step'] * np.arange(n_frequency_bins)
    ).astype(int)
    print 'frequency_bins(%s) = %s' % (repr(
        frequency_bins.shape), repr(frequency_bins))

    # Allocate memory for output dictionary
    output = {
        'frequency_shift': None,
        'code_shift': None,
        'peak_value': None,
        'peak_ratio': None,
        'corr_result': None,
        'found': None,
    }

    print '* searching PRN = %s' % (repr(prn), )

    #
    # Scan all Doppler shifts
    #
    for freq_bin_i in xrange(n_frequency_bins):
        # Generate local sine and cosine carriers
        carrier_sin = np.sin(frequency_bins[freq_bin_i] * phases)
        carrier_cos = np.cos(frequency_bins[freq_bin_i] * phases)

        # Demodulation
        I1 = carrier_sin * x_1
        Q1 = carrier_cos * x_1
        # I2 = carrier_sin * x_2
        # Q2 = carrier_cos * x_2

        # Reconstruct baseband signal
        IQ1 = I1 + 1j * Q1
        # IQ2 = I2 + 1j*Q2

        if settings['use_sfft']:
            IQ1 = sfft_aliasing.execute(IQ1,
                                        settings['sfft_subsampling_factor'])
            # IQ2 = sfft_aliasing.execute(IQ2, settings['sfft_subsampling_factor'])
            performance_counter.increase(additions=IQ1.size *
                                         settings['sfft_subsampling_factor'])
            # performance_counter.increase(additions=IQ2.size * settings['sfft_subsampling_factor'])

        # Convert to frequency domain
        IQ1_freq = fft(IQ1)
        # IQ2_freq = fft(IQ2)
        performance_counter.fft(IQ1.size)
        # performance_counter.fft(IQ2.size)

        # Multiplication in the frequency domain corresponds to convolution in the time domain
        conv_code_IQ1 = IQ1_freq * ca_codes__freq
        # conv_code_IQ2 = IQ2_freq * ca_codes__freq[prn-1]
        performance_counter.increase(multiplications=IQ1_freq.size)
        # performance_counter.increase(multiplications=IQ2_freq.size)

        # IFFT to obtain correlation
        corr_result_1 = np.abs(ifft(conv_code_IQ1))**2
        # corr_result_2 = np.abs(ifft(conv_code_IQ2)) ** 2

        # assert all_results[freq_bin_i, :].shape == corr_result_1.shape == corr_result_2.shape

        # if np.max(corr_result_1) > np.max(corr_result_2):
        all_results[freq_bin_i, :] = corr_result_1
        # else:
        #     all_results[freq_bin_i, :] = corr_result_2

    # Get the peak location for every frequency bins
    peak_values = all_results.max(axis=1)
    assert all_results.max() in peak_values

    # Find the Doppler shift index
    frequency_shift_idx = peak_values.argmax()
    print 'frequency_shift_idx = %s' % repr(frequency_shift_idx)

    # Select the frequency bin that corresponds to this frequency shift index
    located_frequency_bin = all_results[frequency_shift_idx]
    output['corr_result'] = located_frequency_bin

    # Find the code shift in the correct frequency bin
    code_shift = located_frequency_bin.argmax()
    output['code_shift'] = code_shift
    print 'code_shift = %s' % repr(code_shift)

    peak_value = all_results[frequency_shift_idx][code_shift]
    output['peak_value'] = peak_value
    assert all_results.max() == peak_value
    print 'peak_value = %s' % repr(peak_value)

    if plot_3d_graphs:
        fig = plt.figure()
        doppler_shifts__khz = (
            (settings['acquisition_search_frequency_step'] *
             np.arange(n_frequency_bins)) -
            (settings['acquisition_search_frequency_band'] / 2)) / 1000

        ax = fig.gca(projection='3d')
        surf = ax.plot_surface(
            X=np.arange(samples_per_code).reshape((1, -1)),
            Y=doppler_shifts__khz.reshape((-1, 1)),
            Z=all_results,
            rstride=1,
            cstride=1,
            cmap=matplotlib.cm.coolwarm,
            linewidth=0,
            antialiased=False,
        )
        ax.set_xlabel('Code shift')
        ax.set_ylabel('Doppler shift (kHz)')

    # Calculate code phase range
    samples_per_code_chip = int(
        round(settings['sampling_frequency'] / settings['code_frequency']))

    # SFFT
    if settings['use_sfft']:
        samples_per_code_chip = int(samples_per_code_chip /
                                    settings['sfft_subsampling_factor'])

    print 'samples_per_code_chip = %s' % repr(samples_per_code_chip)

    #
    # Threshold calculation 2
    #
    # located_frequency_bin__without_peak = np.delete(located_frequency_bin, code_shift)
    # assert peak_value.max() not in located_frequency_bin__without_peak
    # output['noise_var'] = (located_frequency_bin__without_peak - located_frequency_bin__without_peak.mean()).var()
    # output['snr'] = peak_value**2 / output['noise_var']

    #
    # Get second largest peak value outside the chip where the maximum peak is located
    #

    # Calculate excluded range
    excluded_range_1 = code_shift - samples_per_code_chip
    excluded_range_2 = code_shift + samples_per_code_chip
    print 'excluded_range_1 = %s' % repr(excluded_range_1)
    print 'excluded_range_2 = %s' % repr(excluded_range_2)

    # Excluded range boundary correction
    if excluded_range_1 < 1:
        print 'excluded_range_1 < 1'
        code_phase_range = np.arange(
            excluded_range_2, actual_samples_per_code + excluded_range_1)
    elif excluded_range_2 >= actual_samples_per_code:
        print 'excluded_range_2 >= samples_per_code'
        code_phase_range = np.arange(
            excluded_range_2 - actual_samples_per_code, excluded_range_1)
    else:
        code_phase_range = np.concatenate((np.arange(0, excluded_range_1),
                                           np.arange(excluded_range_2,
                                                     actual_samples_per_code)))

    assert code_shift not in code_phase_range
    print 'code_phase_range(%s) = %s' % (repr(
        code_phase_range.shape), repr(code_phase_range))

    # Get second largest peak value
    second_peak_value = all_results[frequency_shift_idx,
                                    code_phase_range].max()
    print 'second_peak_value = %s' % repr(second_peak_value)

    # # TEST
    # sorted = np.sort(located_frequency_bin)[::-1]
    # assert sorted[0] == peak_value
    # assert sorted[1] == second_peak_value

    # Calculate ratio between the largest peak value and the second largest peak value
    peak_ratio = peak_value / second_peak_value
    print 'peak_ratio = %s' % repr(peak_ratio)
    output['peak_ratio'] = peak_ratio

    #
    # Thresholding
    #

    if peak_ratio > settings['acquisition_threshold']:
        output['found'] = True
        print '-> %s FOUND' % repr(prn)
    else:
        output['found'] = False
        print '-> %s NOT FOUND' % repr(prn)

    return output, performance_counter
def acquisition(x,
                settings,
                plot_graphs=False,
                plot_3d_graphs=False,
                plot_corr_graphs_for=None,
                performance_counter=PerformanceCounter()):

    # Calculate number of samples per spreading code (corresponding to 1ms of data)
    samples_per_code = int(round(settings['sampling_frequency'] * settings['code_length'] / settings['code_frequency']))
    print 'samples_per_code = %s' % repr(samples_per_code)

    # SFFT
    aliased_samples_per_code = int(samples_per_code / settings['sfft_subsampling_factor'])

    if settings['use_sfft']:
        actual_samples_per_code = aliased_samples_per_code
    else:
        actual_samples_per_code = samples_per_code

    # Calculate sampling period
    sampling_period = 1.0 / settings['sampling_frequency']
    print 'sampling_period = %s' % repr(sampling_period)

    # Generate phase points of the local carrier
    phases = np.arange(0, samples_per_code) * 2 * np.pi * sampling_period
    print 'phases(%s) = %s' % (repr(phases.shape), repr(phases))

    # Calculate number of frequency bins depending on search frequency band and frequency step
    assert settings['acquisition_search_frequency_band'] % settings['acquisition_search_frequency_step'] == 0, \
        'acquisition_search_frequency_band should be divisible by acquisition_search_frequency_step'
    n_frequency_bins = int(settings['acquisition_search_frequency_band'] / settings['acquisition_search_frequency_step']) + 1
    print 'n_frequency_bins = %s' % repr(n_frequency_bins)

    # Generate and store C/A lookup table
    ca_codes__time = ca_code.generate_table(settings)
    original_ca_codes__time = ca_code.generate_table(settings)

    # SFFT
    if settings['use_sfft']:
        aliased_ca_codes__time = np.empty(shape=(settings['satellites_total'], aliased_samples_per_code))

        for i in xrange(ca_codes__time.shape[0]):
            aliased_ca_codes__time[i] = sfft_aliasing.execute(ca_codes__time[i], settings['sfft_subsampling_factor'])

        ca_codes__time = aliased_ca_codes__time

    ca_codes__freq = np.conjugate(fft(ca_codes__time))
    print 'ca_codes__time(%s) = %s' % (repr(ca_codes__time.shape), repr(ca_codes__time))

    # Allocate memory for the 2D search
    all_results = np.empty(shape=(n_frequency_bins, actual_samples_per_code))

    # Generate all frequency bins
    frequency_bins = (
        settings['intermediate_frequency'] - \
        (settings['acquisition_search_frequency_band'] / 2) + \
        settings['acquisition_search_frequency_step'] * np.arange(n_frequency_bins)
    ).astype(int)
    print 'frequency_bins(%s) = %s' % (repr(frequency_bins.shape), repr(frequency_bins))

    # Allocate memory for output dictionary
    satellites_to_search__size = settings['satellites_to_search'].size
    output = {
        'frequency_shifts': np.zeros(satellites_to_search__size),
        'frequency_offsets': np.zeros(satellites_to_search__size),
        'code_shift_candidates': np.zeros(shape=(satellites_to_search__size, settings['sfft_subsampling_factor'])),
        'code_shift_candidate_metrics': np.zeros(shape=(satellites_to_search__size, settings['sfft_subsampling_factor'])),
        'code_shifts': np.zeros(satellites_to_search__size),
        'peak_ratios': np.zeros(satellites_to_search__size),
        'found': np.zeros(satellites_to_search__size, dtype=np.bool),
    }

    for idx, prn in enumerate(settings['satellites_to_search']):
        print '* searching PRN = %s' % (repr(prn),)

        result_summation = np.zeros(actual_samples_per_code)
        for sum_idx in xrange(settings['sum_results']):

            # Two consecutive 2ms reading
            # x_1 = x[(settings['code_offset']*samples_per_code):(settings['code_offset']*samples_per_code + samples_per_code)]
            # x_2 = x[(settings['code_offset']*samples_per_code + samples_per_code):(settings['code_offset']*samples_per_code + 2*samples_per_code)]
            x_1 = x[sum_idx*samples_per_code:sum_idx*samples_per_code+samples_per_code]
            x_2 = x[sum_idx*samples_per_code+samples_per_code:sum_idx*samples_per_code+2*samples_per_code]

            print 'x_1.shape = %s' % repr(x_1.shape)
            print 'x_2.shape = %s' % repr(x_2.shape)
            assert x_1.shape == x_2.shape

            #
            # Scan all Doppler shifts
            #
            for freq_bin_i in xrange(n_frequency_bins):

                # Generate local sine and cosine carriers
                carrier_sin = np.sin(frequency_bins[freq_bin_i] * phases)
                carrier_cos = np.cos(frequency_bins[freq_bin_i] * phases)

                # Demodulation
                I1 = carrier_sin * x_1
                Q1 = carrier_cos * x_1
                I2 = carrier_sin * x_2
                Q2 = carrier_cos * x_2

                # Reconstruct baseband signal
                IQ1 = I1 + 1j*Q1
                IQ2 = I2 + 1j*Q2

                if settings['use_sfft']:
                    IQ1 = sfft_aliasing.execute(IQ1, settings['sfft_subsampling_factor'])
                    IQ2 = sfft_aliasing.execute(IQ2, settings['sfft_subsampling_factor'])
                    performance_counter.increase(additions=IQ1.size * settings['sfft_subsampling_factor'])
                    performance_counter.increase(additions=IQ2.size * settings['sfft_subsampling_factor'])

                # Convert to frequency domain
                IQ1_freq = fft(IQ1)
                IQ2_freq = fft(IQ2)
                performance_counter.fft(IQ1.size)
                performance_counter.fft(IQ2.size)

                # Multiplication in the frequency domain corresponds to convolution in the time domain
                conv_code_IQ1 = IQ1_freq * ca_codes__freq[prn-1]
                conv_code_IQ2 = IQ2_freq * ca_codes__freq[prn-1]
                performance_counter.increase(multiplications=IQ1_freq.size)
                performance_counter.increase(multiplications=IQ2_freq.size)

                # IFFT to obtain correlation
                corr_result_1 = np.abs(ifft(conv_code_IQ1)) ** 2
                corr_result_2 = np.abs(ifft(conv_code_IQ2)) ** 2

                # assert all_results[freq_bin_i, :].shape == corr_result_1.shape == corr_result_2.shape

                if np.max(corr_result_1) > np.max(corr_result_2):
                    all_results[freq_bin_i, :] = corr_result_1
                else:
                    all_results[freq_bin_i, :] = corr_result_2

            # Get the peak location for every frequency bins
            peak_values = all_results.max(axis=1)
            assert all_results.max() in peak_values

            # Find the Doppler shift index
            frequency_shift_idx = peak_values.argmax()
            print 'frequency_shift_idx = %s' % repr(frequency_shift_idx)

            # Select the frequency bin that corresponds to this frequency shift index
            located_frequency_bin = all_results[frequency_shift_idx]

            result_summation += located_frequency_bin

        # Find the code shift in the correct frequency bin
        code_shift = result_summation.argmax()
        output['code_shifts'][idx] = code_shift
        print 'code_shift = %s' % repr(code_shift)

        peak_value = result_summation[code_shift]
        assert result_summation.max() == peak_value
        print 'peak_value = %s' % repr(peak_value)

        if prn in plot_corr_graphs_for:
            plt.figure()
            plt.plot(result_summation / result_summation.max())
            plt.ylabel('Normalised magnitude')
            plt.xlabel('Code shift (chips)')

            title_parts = ['PRN=%d' % prn]

            if settings['use_sfft']:
                title_parts.append('q=%d (Sparse)' % settings['sfft_subsampling_factor'])
            else:
                title_parts.append('(Baseline)' % settings['sfft_subsampling_factor'])

            if settings['sum_results']:
                title_parts.append('Summing %d' % settings['sum_results'])

            plt.title(', '.join(title_parts))

            plt.grid()

        if settings['use_sfft']:
            t_candidates = output['code_shift_candidate_metrics'][idx]

            for p in xrange(settings['sfft_subsampling_factor']):
                # print original_ca_codes__time[prn-1].shape
                candidate_t = code_shift + p * aliased_samples_per_code
                output['code_shift_candidates'][idx][p] = candidate_t

                ca_code__aligned = np.roll(original_ca_codes__time[prn-1], candidate_t)
                x__start = x[0:samples_per_code]

                print ca_code__aligned
                assert ca_code__aligned.shape == x__start.shape

                t_candidates[p] = np.sum(
                    ca_code__aligned * x__start
                    # np.abs(
                    #     ifft(np.conj(fft(ca_code__aligned)) * fft(x__start))
                    # ) ** 2
                )

                print 'candidate_t[%s] = %s, sum = %s' % (repr(p), repr(candidate_t), repr(t_candidates[p]))

            correct_p = t_candidates.argmax()
            correct_code_shift = code_shift + correct_p * aliased_samples_per_code
            output['code_shifts'][idx] = correct_code_shift
            print 'correct_code_shift', correct_code_shift

        # Doppler shifts
        doppler_shifts__khz = (
            (settings['acquisition_search_frequency_step'] * np.arange(n_frequency_bins)) -
            (settings['acquisition_search_frequency_band'] / 2)
        )
        output['frequency_shifts'][idx] = frequency_bins[frequency_shift_idx]
        output['frequency_offsets'][idx] = doppler_shifts__khz[frequency_shift_idx]

        if plot_3d_graphs:
            fig = plt.figure()

            ax = fig.gca(projection='3d')
            surf = ax.plot_surface(
                X=np.arange(actual_samples_per_code).reshape((1, -1)),
                Y=doppler_shifts__khz.reshape((-1, 1)) / 1000,
                Z=all_results,
                rstride=1,
                cstride=1,
                cmap=matplotlib.cm.coolwarm,
                linewidth=0,
                antialiased=False,
            )
            ax.set_xlabel('Code shift (chips)')
            ax.set_ylabel('Doppler shift (kHz)')
            ax.set_zlabel('Magnitude')

        # Calculate code phase range
        samples_per_code_chip = int(round(settings['sampling_frequency'] / settings['code_frequency']))

        # SFFT
        if settings['use_sfft']:
            samples_per_code_chip = int(samples_per_code_chip / settings['sfft_subsampling_factor'])

        print 'samples_per_code_chip = %s' % repr(samples_per_code_chip)

        #
        # Get second largest peak value outside the chip where the maximum peak is located
        #

        # Calculate excluded range
        excluded_range_1 = code_shift - samples_per_code_chip
        excluded_range_2 = code_shift + samples_per_code_chip
        print 'excluded_range_1 = %s' % repr(excluded_range_1)
        print 'excluded_range_2 = %s' % repr(excluded_range_2)

        # Excluded range boundary correction
        if excluded_range_1 < 1:
            print 'excluded_range_1 < 1'
            code_phase_range = np.arange(excluded_range_2, actual_samples_per_code + excluded_range_1)
        elif excluded_range_2 >= actual_samples_per_code:
            print 'excluded_range_2 >= samples_per_code'
            code_phase_range = np.arange(excluded_range_2 - actual_samples_per_code, excluded_range_1)
        else:
            code_phase_range = np.concatenate((
                np.arange(0, excluded_range_1),
                np.arange(excluded_range_2, actual_samples_per_code)
            ))

        assert code_shift not in code_phase_range
        print 'code_phase_range(%s) = %s' % (repr(code_phase_range.shape), repr(code_phase_range))

        # Get second largest peak value
        second_peak_value = all_results[frequency_shift_idx, code_phase_range].max()
        print 'second_peak_value = %s' % repr(second_peak_value)

        # Calculate ratio between the largest peak value and the second largest peak value
        peak_ratio = peak_value / second_peak_value
        print 'peak_ratio = %s' % repr(peak_ratio)
        output['peak_ratios'][idx] = peak_ratio

        #
        # Thresholding
        #

        if peak_ratio > settings['acquisition_threshold']:
            output['found'][idx] = True
            print '-> %s FOUND' % repr(prn)
        else:
            output['found'][idx] = False
            print '-> %s NOT FOUND' % repr(prn)

    if plot_graphs:
        plt.figure()
        colors = ['r' if found else 'b' for found in output['found']]
        plt.bar(settings['satellites_to_search'], output['peak_ratios'], color=colors, align='center')
        plt.ylabel('Acquisition quality')
        plt.xlabel('PRN number')

        artist__not_acquired = plt.Rectangle((0, 0), 1, 1, fc='b')
        artist__acquired = plt.Rectangle((0, 0), 1, 1, fc='r')
        plt.legend((
            artist__not_acquired,
            artist__acquired
        ), (
            'Signal not acquired',
            'Signal acquired'
        ))
        plt.xlim(0, settings['satellites_total'] + 1)

        plt.tight_layout()

    return output, performance_counter
Example #9
0
def acquisition(x, settings, plot_graphs=False):
    # Calculate number of samples per spreading code (corresponding to 1ms of data)
    samples_per_code = int(round(settings['sampling_frequency'] * settings['code_length'] / float(settings['code_frequency'])))
    subsamples_per_code = samples_per_code / settings['subsampling_factor']
    print 'There are %d samples per code' % samples_per_code

    x_1 = x[0:samples_per_code]
    x_2 = x[samples_per_code:2*samples_per_code]

    x_0dc = x - np.mean(x)

    # Calculate sampling period
    sampling_period = 1.0 / settings['sampling_frequency']

    phases = np.arange(0, samples_per_code) * 2 * np.pi * sampling_period

    # Calculate number of frequency bins
    assert settings['acquisition_search_frequency_band'] % settings['acquisition_search_frequency_step'] == 0, \
        'acquisition_search_frequency_band should be divisible by acquisition_search_frequency_step'
    n_frequency_bins = settings['acquisition_search_frequency_band'] / settings['acquisition_search_frequency_step']
    print 'There are %d frequency bins' % n_frequency_bins

    # todo generate ca table

    # SFFT: Aliasing
    all_results = np.zeros(shape=(n_frequency_bins, samples_per_code / settings['subsampling_factor']))
    # all_results = np.zeros(shape=(n_frequency_bins, samples_per_code))

    # Generate all frequency bins
    frequency_bins = settings['intermediate_frequency'] - \
        (settings['acquisition_search_frequency_band'] / 2) + \
        settings['acquisition_search_frequency_step'] * np.arange(n_frequency_bins)

    # Allocate output dictionary
    output = {
        'frequency_shifts': np.zeros(settings['satellites_to_search'].size),
        'code_shifts': np.zeros(settings['satellites_to_search'].size),
        'peak_ratios': np.zeros(settings['satellites_to_search'].size),
        'found': np.zeros(settings['satellites_to_search'].size, dtype=np.bool),
    }

    for idx, prn in enumerate(settings['satellites_to_search']):
        print 'Acquiring satellite PRN = %d' % prn

        ca_code_t = ca_code.generate(prn=prn).repeat(samples_per_code/1023)

        # SFFT: Aliasing
        ca_code_t = sfft_aliasing.execute(ca_code_t, settings['subsampling_factor'])

        ca_code_f = np.conj(np.fft.fft(ca_code_t))

        # Scan Doppler frequencies
        for freq_bin_i in range(n_frequency_bins):
            # Generate local sine and cosine carriers
            carrier_sin = np.sin(frequency_bins[freq_bin_i] * phases)
            carrier_cos = np.cos(frequency_bins[freq_bin_i] * phases)

            # Demodulation
            IQ_1 = carrier_sin*x_1 + 1j*carrier_cos*x_1
            IQ_2 = carrier_sin*x_2 + 1j*carrier_cos*x_2

            # SFFT: Aliasing
            IQ_1 = sfft_aliasing.execute(IQ_1, settings['subsampling_factor'])
            IQ_2 = sfft_aliasing.execute(IQ_2, settings['subsampling_factor'])

            # Baseband signal to frequency domain
            IQ_1_freq = np.fft.fft(IQ_1)
            IQ_2_freq = np.fft.fft(IQ_2)

            # Convolve
            conv_code_IQ_1 = IQ_1_freq * ca_code_f
            conv_code_IQ_2 = IQ_2_freq * ca_code_f

            # IFFT to obtain correlation
            corr_result_1 = np.abs(np.fft.ifft(conv_code_IQ_1)) ** 2
            corr_result_2 = np.abs(np.fft.ifft(conv_code_IQ_2)) ** 2

            # assert all_results[freq_bin_i, :].shape == corr_result_1.shape == corr_result_2.shape

            if np.max(corr_result_1) > np.max(corr_result_2):
                all_results[freq_bin_i, :] = corr_result_1
            else:
                all_results[freq_bin_i, :] = corr_result_2

        # Peak location for each Doppler shift
        peak_values = all_results.max(axis=1)

        assert all_results.max() in peak_values

        frequency_shift = peak_values.argmax()
        print 'Frequency shift is %d' % frequency_shift

        correct_frequency_result = all_results[frequency_shift]

        code_shift = correct_frequency_result.argmax()
        print 'Code shift is %d' % code_shift

        assert all_results.max() == all_results[frequency_shift][code_shift]
        peak_value = all_results[frequency_shift][code_shift]
        print 'Peak value = %f' % peak_value

        # if plot_graphs:
        #     print np.arange(1023*16/settings['subsampling_factor']).reshape((1, -1)).shape, frequency_bins.shape, all_results.shape
        #
        #     fig = plt.figure()
        #     ax = fig.gca(projection='3d')
        #     surf = ax.plot_surface(
        #         X=np.arange(1023*16/settings['subsampling_factor']).reshape((1, -1)),
        #         Y=frequency_bins.reshape((-1, 1)),
        #         Z=all_results,
        #         rstride=1,
        #         cstride=1,
        #         cmap=matplotlib.cm.coolwarm,
        #         linewidth=0,
        #         antialiased=False,
        #     )
        #     plt.show()

        # Calculate code phase range
        samples_per_code_chip = int(round(settings['sampling_frequency'] / settings['code_frequency'] / 2))
        excluded_range_1 = code_shift - samples_per_code_chip
        excluded_range_2 = code_shift + samples_per_code_chip
        print 'code_shift', code_shift
        print 'samples_per_code', samples_per_code
        print 'samples_per_code_chip', samples_per_code_chip
        print 'excluded_range_1', excluded_range_1
        print 'excluded_range_2', excluded_range_2

        if excluded_range_1 < 1:
            code_phase_range = np.arange(excluded_range_2, subsamples_per_code + excluded_range_1)
        elif excluded_range_2 >= subsamples_per_code:
            code_phase_range = np.arange(excluded_range_2 - subsamples_per_code, excluded_range_1)
        else:
            code_phase_range = np.concatenate((
                np.arange(0, excluded_range_1 - 1),
                np.arange(excluded_range_2, subsamples_per_code)
            ))

        print 'code_phase_range', code_phase_range.shape, code_phase_range

        assert code_shift not in code_phase_range

        second_peak_value = all_results[frequency_shift, code_phase_range].max()
        print 'Second peak value = %f' % second_peak_value

        peak_ratio = peak_value / float(second_peak_value)
        print 'peak_ratio = %f' % peak_ratio
        output['peak_ratios'][idx] = peak_ratio

        if peak_ratio > settings['acquisition_threshold']:
            output['found'][idx] = True
            print '* FOUND'
        else:
            output['found'][idx] = False
            print '* NOT FOUND'

    return output
Example #10
0
def main():
    # (a) Input
    code = ca_code.generate(prn=1, repeats=10)
    # rx = np.roll(ca_code.generate(prn=1, repeats=10), -10230/6*1) | ca_code.generate(prn=2, repeats=10)
    rx = np.roll(ca_code.generate(prn=1, repeats=10), 1000) | ca_code.generate(
        prn=2, repeats=10)

    noise_std = 1
    noise = np.random.normal(
        scale=noise_std,
        size=code.size,
    )

    rx = np.add(rx, noise)

    # (b) Aliasing
    q = 2
    code_aliased = sfft_aliasing.execute(code, q)
    rx_aliased = sfft_aliasing.execute(rx, q)

    # (c) FFT
    code_f = fft(code_aliased)
    rx_f = fft(rx_aliased)

    # (d) Multiply
    code_rx_f = np.multiply(np.conjugate(code_f), rx_f)

    # (e) IFFT
    code_rx = np.real(ifft(code_rx_f))

    print 'arg max is', np.argmax(code_rx)

    plt.figure('Local C/A code')
    plt.step(np.arange(code.size), code)
    plt.xlim(0, code.size - 1)
    plt.title('Local C/A code')
    plt.xlabel('Time')
    plt.setp(plt.gca().get_xticklabels(), visible=False)
    plt.setp(plt.gca().get_yticklabels(), visible=False)

    plt.figure('Received signal')
    plt.plot(rx)
    plt.xlim(0, code.size - 1)
    plt.title('Received signal')
    plt.xlabel('Time')
    plt.setp(plt.gca().get_xticklabels(), visible=False)
    plt.setp(plt.gca().get_yticklabels(), visible=False)

    plt.figure('Aliased Local C/A code')
    plt.step(np.arange(code_aliased.size), code_aliased)
    plt.xlim(0, code_aliased.size - 1)
    plt.title('Local C/A code (Aliased)')
    plt.xlabel('Time')
    plt.setp(plt.gca().get_xticklabels(), visible=False)
    plt.setp(plt.gca().get_yticklabels(), visible=False)

    plt.figure('Aliased Received signal')
    plt.plot(rx_aliased)
    plt.xlim(0, rx_aliased.size - 1)
    plt.title('Received signal (Aliased)')
    plt.xlabel('Time')
    plt.setp(plt.gca().get_xticklabels(), visible=False)
    plt.setp(plt.gca().get_yticklabels(), visible=False)

    plt.figure('FFT of Local CA code')
    plt.plot(np.abs(fftshift(code_f)))
    plt.title('FFT of Local C/A code')
    plt.xlabel('Frequency')
    plt.xlim(1000, 4000)
    plt.ylim(0, 500)
    plt.setp(plt.gca().get_xticklabels(), visible=False)
    plt.setp(plt.gca().get_yticklabels(), visible=False)

    plt.figure('FFT of Received signal')
    plt.plot(np.abs(fftshift(rx_f)))
    plt.title('FFT of Received signal')
    plt.xlabel('Frequency')
    plt.xlim(1000, 4000)
    plt.ylim(0, 500)
    plt.setp(plt.gca().get_xticklabels(), visible=False)
    plt.setp(plt.gca().get_yticklabels(), visible=False)

    plt.figure('Multiply')
    plt.plot(np.abs(fftshift(code_rx_f)))
    plt.title('Multiply')
    plt.xlabel('Frequency')
    plt.xlim(1500, 3500)
    plt.ylim(0, 100000)
    plt.setp(plt.gca().get_xticklabels(), visible=False)
    plt.setp(plt.gca().get_yticklabels(), visible=False)

    plt.figure('IFFT')
    plt.plot(code_rx)
    plt.title('IFFT')
    plt.xlim(0, code_rx.size - 1)
    plt.setp(plt.gca().get_xticklabels(), visible=False)
    plt.setp(plt.gca().get_yticklabels(), visible=False)

    plt.show()
def acquisition(x, settings,
                plot_graphs=False,
                plot_3d_graphs=False,
                performance_counter=PerformanceCounter()):
    # Calculate number of samples per spreading code (corresponding to 1ms of data)
    samples_per_code = int(round(settings['sampling_frequency'] * settings['code_length'] / settings['code_frequency']))
    # print 'samples_per_code = %s' % repr(samples_per_code)

    # SFFT
    aliased_samples_per_code = int(samples_per_code / settings['sfft_subsampling_factor'])

    if settings['use_sfft']:
        actual_samples_per_code = aliased_samples_per_code
    else:
        actual_samples_per_code = samples_per_code

    # Calculate sampling period
    sampling_period = 1.0 / settings['sampling_frequency']
    # print 'sampling_period = %s' % repr(sampling_period)

    # Generate phase points of the local carrier
    phases = np.arange(0, samples_per_code) * 2 * np.pi * sampling_period
    # print 'phases(%s) = %s' % (repr(phases.shape), repr(phases))

    # Calculate number of frequency bins depending on search frequency band and frequency step
    assert settings['acquisition_search_frequency_band'] % settings['acquisition_search_frequency_step'] == 0, \
        'acquisition_search_frequency_band should be divisible by acquisition_search_frequency_step'
    n_frequency_bins = int(settings['acquisition_search_frequency_band'] / settings['acquisition_search_frequency_step']) + 1
    # print 'n_frequency_bins = %s' % repr(n_frequency_bins)

    # Generate and store C/A lookup table
    ca_codes__time = ca_code.generate_table(settings)

    # SFFT
    if settings['use_sfft']:
        aliased_ca_codes__time = np.empty(shape=(settings['satellites_total'], aliased_samples_per_code))

        for i in xrange(ca_codes__time.shape[0]):
            aliased_ca_codes__time[i] = sfft_aliasing.execute(ca_codes__time[i], settings['sfft_subsampling_factor'])

        ca_codes__time = aliased_ca_codes__time

    ca_codes__freq = np.conjugate(fft(ca_codes__time))
    # print 'ca_codes__time(%s) = %s' % (repr(ca_codes__time.shape), repr(ca_codes__time))

    # Allocate memory for the 2D search
    all_results = np.empty(shape=(n_frequency_bins, actual_samples_per_code))

    # Generate all frequency bins
    frequency_bins = (
        settings['intermediate_frequency'] - \
        (settings['acquisition_search_frequency_band'] / 2) + \
        settings['acquisition_search_frequency_step'] * np.arange(n_frequency_bins)
    ).astype(int)
    # print 'frequency_bins(%s) = %s' % (repr(frequency_bins.shape), repr(frequency_bins))

    # Allocate memory for output dictionary
    satellites_to_search__shape = settings['satellites_to_search'].shape
    output = {
        'frequency_shifts': np.zeros(satellites_to_search__shape, dtype=int),
        'code_shifts': np.zeros(satellites_to_search__shape, dtype=int),
        'peak_ratios': np.zeros(satellites_to_search__shape),
        'found': np.zeros(satellites_to_search__shape, dtype=np.bool),
    }

    correct_runs = 0
    run_number = 0

    for idx, prn in enumerate(settings['satellites_to_search']):
        print '* searching PRN = %s' % (repr(prn),)

        # correct_runs = 0
        # run_number = 0

        summed_corr_result_magnitudes = np.zeros(actual_samples_per_code)

        counter = 10
        while counter > 0:
            counter -= 1

            # Two consecutive 2ms reading
            # x_1 = x[(settings['code_offset']*samples_per_code):(settings['code_offset']*samples_per_code + samples_per_code)]
            # x_2 = x[(settings['code_offset']*samples_per_code + samples_per_code):(settings['code_offset']*samples_per_code + 2*samples_per_code)]
            x_1 = x[run_number*samples_per_code:(run_number*samples_per_code + samples_per_code)]
            # print 'x_1.shape = %s' % repr(x_1.shape)

            run_number += 1
            print 'run_number = %s' % repr(run_number)

            #
            # Scan all Doppler shifts
            #
            for freq_bin_i in xrange(n_frequency_bins):
                # Generate local sine and cosine carriers
                carrier_sin = np.sin(frequency_bins[freq_bin_i] * phases)
                carrier_cos = np.cos(frequency_bins[freq_bin_i] * phases)

                # Demodulation
                I1 = carrier_sin * x_1
                Q1 = carrier_cos * x_1
                # I2 = carrier_sin * x_2
                # Q2 = carrier_cos * x_2

                # Reconstruct baseband signal
                IQ1 = I1 + 1j*Q1
                # IQ2 = I2 + 1j*Q2

                if settings['use_sfft']:
                    IQ1 = sfft_aliasing.execute(IQ1, settings['sfft_subsampling_factor'])
                    # IQ2 = sfft_aliasing.execute(IQ2, settings['sfft_subsampling_factor'])
                    performance_counter.increase(additions=IQ1.size * settings['sfft_subsampling_factor'])
                    # performance_counter.increase(additions=IQ2.size * settings['sfft_subsampling_factor'])

                # Convert to frequency domain
                IQ1_freq = fft(IQ1)
                # IQ2_freq = fft(IQ2)
                performance_counter.fft(IQ1.size)
                # performance_counter.fft(IQ2.size)

                # Multiplication in the frequency domain corresponds to convolution in the time domain
                conv_code_IQ1 = IQ1_freq * ca_codes__freq[prn-1]
                # conv_code_IQ2 = IQ2_freq * ca_codes__freq[prn-1]
                performance_counter.increase(multiplications=IQ1_freq.size)
                # performance_counter.increase(multiplications=IQ2_freq.size)

                # IFFT to obtain correlation
                corr_result = np.abs(ifft(conv_code_IQ1)) ** 2
                # corr_result_2 = np.abs(ifft(conv_code_IQ2)) ** 2

                # assert all_results[freq_bin_i, :].shape == corr_result_1.shape == corr_result_2.shape

                # if np.max(corr_result_1) > np.max(corr_result_2):
                all_results[freq_bin_i, :] = corr_result
                # else:
                #     all_results[freq_bin_i, :] = corr_result_2

            # Get the peak location for every frequency bins
            peak_values = all_results.max(axis=1)
            assert all_results.max() in peak_values

            # Find the Doppler shift index
            frequency_shift_idx = peak_values.argmax()
            # print 'frequency_shift_idx = %s' % repr(frequency_shift_idx)

            # Select the frequency bin that corresponds to this frequency shift index
            located_frequency_bin = all_results[frequency_shift_idx]

            # Find the code shift in the correct frequency bin
            code_shift = located_frequency_bin.argmax()
            # output['code_shifts'][idx] = code_shift
            # print 'code_shift = %s' % repr(code_shift)

            peak_value = located_frequency_bin[code_shift]
            assert all_results.max() == peak_value
            # print 'peak_value = %s' % repr(peak_value)

            print np.abs(code_shift - settings['actual_satellite_shifts'][idx])

            if np.abs(code_shift - settings['actual_satellite_shifts'][idx]) < 40:
                correct_runs += 1
                print 'CORRECT RUN!'

            # # New Threshold calculation
            # summed_corr_result_magnitudes += np.abs(located_frequency_bin)
            # # print 'here', summed_corr_result_magnitudes.argmax()
            # snr = get_snr(summed_corr_result_magnitudes)
            # print 'snr', snr
            # if snr > settings['snr_threshold']:
            #     output['found'][idx] = True
            #     print 'summed_corr_result_magnitudes', summed_corr_result_magnitudes
            #     output['code_shifts'][idx] = summed_corr_result_magnitudes.argmax()
            #     break
            #
            # if plot_3d_graphs:
            #     fig = plt.figure()
            #     doppler_shifts__khz = (
            #         (settings['acquisition_search_frequency_step'] * np.arange(n_frequency_bins)) -
            #         (settings['acquisition_search_frequency_band'] / 2)
            #     ) / 1000
            #
            #     ax = fig.gca(projection='3d')
            #     surf = ax.plot_surface(
            #         X=np.arange(actual_samples_per_code).reshape((1, -1)),
            #         Y=doppler_shifts__khz.reshape((-1, 1)),
            #         Z=all_results,
            #         rstride=1,
            #         cstride=1,
            #         cmap=matplotlib.cm.coolwarm,
            #         linewidth=0,
            #         antialiased=False,
            #     )
            #     ax.set_xlabel('Code shift')
            #     ax.set_ylabel('Doppler shift (kHz)')
            #
            # # Calculate code phase range
            # samples_per_code_chip = int(round(settings['sampling_frequency'] / settings['code_frequency']))
            #
            # # SFFT
            # if settings['use_sfft']:
            #     samples_per_code_chip = int(samples_per_code_chip / settings['sfft_subsampling_factor'])
            #
            # print 'samples_per_code_chip = %s' % repr(samples_per_code_chip)
            #
            # #
            # # Get second largest peak value outside the chip where the maximum peak is located
            # #
            #
            # # Calculate excluded range
            # excluded_range_1 = code_shift - samples_per_code_chip
            # excluded_range_2 = code_shift + samples_per_code_chip
            # print 'excluded_range_1 = %s' % repr(excluded_range_1)
            # print 'excluded_range_2 = %s' % repr(excluded_range_2)
            #
            # # Excluded range boundary correction
            # if excluded_range_1 < 1:
            #     print 'excluded_range_1 < 1'
            #     code_phase_range = np.arange(excluded_range_2, actual_samples_per_code + excluded_range_1)
            # elif excluded_range_2 >= actual_samples_per_code:
            #     print 'excluded_range_2 >= samples_per_code'
            #     code_phase_range = np.arange(excluded_range_2 - actual_samples_per_code, excluded_range_1)
            # else:
            #     code_phase_range = np.concatenate((
            #         np.arange(0, excluded_range_1),
            #         np.arange(excluded_range_2, actual_samples_per_code)
            #     ))
            #
            # assert code_shift not in code_phase_range
            # print 'code_phase_range(%s) = %s' % (repr(code_phase_range.shape), repr(code_phase_range))
            #
            # # Get second largest peak value
            # second_peak_value = all_results[frequency_shift_idx, code_phase_range].max()
            # print 'second_peak_value = %s' % repr(second_peak_value)
            #
            # # Calculate ratio between the largest peak value and the second largest peak value
            # peak_ratio = peak_value / second_peak_value
            # print 'peak_ratio = %s' % repr(peak_ratio)
            # output['peak_ratios'][idx] = peak_ratio
            #
            # #
            # # Thresholding
            # #
            #
            # if peak_ratio > settings['acquisition_threshold']:
            #     output['found'][idx] = True
            #     print '-> %s FOUND' % repr(prn)
            # else:
            #     output['found'][idx] = False
            #     print '-> %s NOT FOUND' % repr(prn)

    if plot_graphs:
        plt.figure()
        colors = ['r' if found else 'b' for found in output['found']]
        plt.bar(settings['satellites_to_search'], output['peak_ratios'], color=colors, align='center')
        plt.ylabel('Acquisition quality')
        plt.xlabel('PRN number')

        artist__not_acquired = plt.Rectangle((0, 0), 1, 1, fc='b')
        artist__acquired = plt.Rectangle((0, 0), 1, 1, fc='r')
        plt.legend((
            artist__not_acquired,
            artist__acquired
        ), (
            'Signal not acquired',
            'Signal acquired'
        ))
        plt.xlim(0, settings['satellites_total'] + 1)

        plt.tight_layout()

    if run_number == 0:
        output['success_probability'] = 0
    else:
        output['success_probability'] = correct_runs / run_number

    print output['success_probability']

    return output, performance_counter
def single_acquisition(x, prn, settings,
                       plot_3d_graphs=False,
                       performance_counter=PerformanceCounter()):

    # Calculate number of samples per spreading code (corresponding to 1ms of data)
    samples_per_code = int(round(settings['sampling_frequency'] * settings['code_length'] / settings['code_frequency']))
    print 'samples_per_code = %s' % repr(samples_per_code)

    # SFFT
    aliased_samples_per_code = int(samples_per_code / settings['sfft_subsampling_factor'])

    if settings['use_sfft']:
        actual_samples_per_code = aliased_samples_per_code
    else:
        actual_samples_per_code = samples_per_code

    # Two consecutive 2ms reading
    x_1 = x[(settings['code_offset'] * samples_per_code):((settings['code_offset'] * samples_per_code) + samples_per_code)]
    x_2 = x[(settings['code_offset']*samples_per_code + samples_per_code):(settings['code_offset']*samples_per_code + 2*samples_per_code)]

    if x_1.size != samples_per_code:
        return False, performance_counter

    print 'x_1.shape = %s' % repr(x_1.shape)
    print 'x_2.shape = %s' % repr(x_2.shape)

    # Calculate sampling period
    sampling_period = 1.0 / settings['sampling_frequency']
    print 'sampling_period = %s' % repr(sampling_period)

    # Generate phase points of the local carrier
    phases = np.arange(0, samples_per_code) * 2 * np.pi * sampling_period
    print 'phases(%s) = %s' % (repr(phases.shape), repr(phases))

    # Calculate number of frequency bins depending on search frequency band and frequency step
    assert settings['acquisition_search_frequency_band'] % settings['acquisition_search_frequency_step'] == 0, \
        'acquisition_search_frequency_band should be divisible by acquisition_search_frequency_step'
    n_frequency_bins = int(settings['acquisition_search_frequency_band'] / settings['acquisition_search_frequency_step']) + 1
    print 'n_frequency_bins = %s' % repr(n_frequency_bins)

    # Generate C/A code
    ca_code__time = ca_code.generate_from_settings(settings, prn=prn)

    # SFFT
    if settings['use_sfft']:
        ca_code__time = sfft_aliasing.execute(ca_code__time, settings['sfft_subsampling_factor'])

    ca_codes__freq = np.conjugate(fft(ca_code__time))
    print 'ca_codes__time(%s) = %s' % (repr(ca_code__time.shape), repr(ca_code__time))

    # Allocate memory for the 2D search
    all_results = np.empty(shape=(n_frequency_bins, actual_samples_per_code))

    # Generate all frequency bins
    frequency_bins = (
        settings['intermediate_frequency'] - \
        (settings['acquisition_search_frequency_band'] / 2) + \
        settings['acquisition_search_frequency_step'] * np.arange(n_frequency_bins)
    ).astype(int)
    print 'frequency_bins(%s) = %s' % (repr(frequency_bins.shape), repr(frequency_bins))

    # Allocate memory for output dictionary
    output = {
        'frequency_shift': None,
        'code_shift': None,
        'peak_value': None,
        'peak_ratio': None,
        'corr_result': None,
        'found': None,
    }

    print '* searching PRN = %s' % (repr(prn),)

    #
    # Scan all Doppler shifts
    #
    for freq_bin_i in xrange(n_frequency_bins):
        # Generate local sine and cosine carriers
        carrier_sin = np.sin(frequency_bins[freq_bin_i] * phases)
        carrier_cos = np.cos(frequency_bins[freq_bin_i] * phases)

        # Demodulation
        I1 = carrier_sin * x_1
        Q1 = carrier_cos * x_1
        # I2 = carrier_sin * x_2
        # Q2 = carrier_cos * x_2

        # Reconstruct baseband signal
        IQ1 = I1 + 1j*Q1
        # IQ2 = I2 + 1j*Q2

        if settings['use_sfft']:
            IQ1 = sfft_aliasing.execute(IQ1, settings['sfft_subsampling_factor'])
            # IQ2 = sfft_aliasing.execute(IQ2, settings['sfft_subsampling_factor'])
            performance_counter.increase(additions=IQ1.size * settings['sfft_subsampling_factor'])
            # performance_counter.increase(additions=IQ2.size * settings['sfft_subsampling_factor'])

        # Convert to frequency domain
        IQ1_freq = fft(IQ1)
        # IQ2_freq = fft(IQ2)
        performance_counter.fft(IQ1.size)
        # performance_counter.fft(IQ2.size)

        # Multiplication in the frequency domain corresponds to convolution in the time domain
        conv_code_IQ1 = IQ1_freq * ca_codes__freq
        # conv_code_IQ2 = IQ2_freq * ca_codes__freq[prn-1]
        performance_counter.increase(multiplications=IQ1_freq.size)
        # performance_counter.increase(multiplications=IQ2_freq.size)

        # IFFT to obtain correlation
        corr_result_1 = np.abs(ifft(conv_code_IQ1)) ** 2
        # corr_result_2 = np.abs(ifft(conv_code_IQ2)) ** 2

        # assert all_results[freq_bin_i, :].shape == corr_result_1.shape == corr_result_2.shape

        # if np.max(corr_result_1) > np.max(corr_result_2):
        all_results[freq_bin_i, :] = corr_result_1
        # else:
        #     all_results[freq_bin_i, :] = corr_result_2

    # Get the peak location for every frequency bins
    peak_values = all_results.max(axis=1)
    assert all_results.max() in peak_values

    # Find the Doppler shift index
    frequency_shift_idx = peak_values.argmax()
    print 'frequency_shift_idx = %s' % repr(frequency_shift_idx)

    # Select the frequency bin that corresponds to this frequency shift index
    located_frequency_bin = all_results[frequency_shift_idx]
    output['corr_result'] = located_frequency_bin

    # Find the code shift in the correct frequency bin
    code_shift = located_frequency_bin.argmax()
    output['code_shift'] = code_shift
    print 'code_shift = %s' % repr(code_shift)

    peak_value = all_results[frequency_shift_idx][code_shift]
    output['peak_value'] = peak_value
    assert all_results.max() == peak_value
    print 'peak_value = %s' % repr(peak_value)

    if plot_3d_graphs:
        fig = plt.figure()
        doppler_shifts__khz = (
            (settings['acquisition_search_frequency_step'] * np.arange(n_frequency_bins)) -
            (settings['acquisition_search_frequency_band'] / 2)
        ) / 1000

        ax = fig.gca(projection='3d')
        surf = ax.plot_surface(
            X=np.arange(samples_per_code).reshape((1, -1)),
            Y=doppler_shifts__khz.reshape((-1, 1)),
            Z=all_results,
            rstride=1,
            cstride=1,
            cmap=matplotlib.cm.coolwarm,
            linewidth=0,
            antialiased=False,
        )
        ax.set_xlabel('Code shift')
        ax.set_ylabel('Doppler shift (kHz)')

    # Calculate code phase range
    samples_per_code_chip = int(round(settings['sampling_frequency'] / settings['code_frequency']))

    # SFFT
    if settings['use_sfft']:
        samples_per_code_chip = int(samples_per_code_chip / settings['sfft_subsampling_factor'])

    print 'samples_per_code_chip = %s' % repr(samples_per_code_chip)

    #
    # Threshold calculation 2
    #
    # located_frequency_bin__without_peak = np.delete(located_frequency_bin, code_shift)
    # assert peak_value.max() not in located_frequency_bin__without_peak
    # output['noise_var'] = (located_frequency_bin__without_peak - located_frequency_bin__without_peak.mean()).var()
    # output['snr'] = peak_value**2 / output['noise_var']

    #
    # Get second largest peak value outside the chip where the maximum peak is located
    #

    # Calculate excluded range
    excluded_range_1 = code_shift - samples_per_code_chip
    excluded_range_2 = code_shift + samples_per_code_chip
    print 'excluded_range_1 = %s' % repr(excluded_range_1)
    print 'excluded_range_2 = %s' % repr(excluded_range_2)

    # Excluded range boundary correction
    if excluded_range_1 < 1:
        print 'excluded_range_1 < 1'
        code_phase_range = np.arange(excluded_range_2, actual_samples_per_code + excluded_range_1)
    elif excluded_range_2 >= actual_samples_per_code:
        print 'excluded_range_2 >= samples_per_code'
        code_phase_range = np.arange(excluded_range_2 - actual_samples_per_code, excluded_range_1)
    else:
        code_phase_range = np.concatenate((
            np.arange(0, excluded_range_1),
            np.arange(excluded_range_2, actual_samples_per_code)
        ))

    assert code_shift not in code_phase_range
    print 'code_phase_range(%s) = %s' % (repr(code_phase_range.shape), repr(code_phase_range))

    # Get second largest peak value
    second_peak_value = all_results[frequency_shift_idx, code_phase_range].max()
    print 'second_peak_value = %s' % repr(second_peak_value)

    # # TEST
    # sorted = np.sort(located_frequency_bin)[::-1]
    # assert sorted[0] == peak_value
    # assert sorted[1] == second_peak_value

    # Calculate ratio between the largest peak value and the second largest peak value
    peak_ratio = peak_value / second_peak_value
    print 'peak_ratio = %s' % repr(peak_ratio)
    output['peak_ratio'] = peak_ratio

    #
    # Thresholding
    #

    if peak_ratio > settings['acquisition_threshold']:
        output['found'] = True
        print '-> %s FOUND' % repr(prn)
    else:
        output['found'] = False
        print '-> %s NOT FOUND' % repr(prn)

    return output, performance_counter