예제 #1
0
    def test_welch(self, rand_data_gen, num_samps, fs, nperseg):
        cpu_sig, gpu_sig = rand_data_gen(num_samps)

        _, cPxx_spec = signal.welch(cpu_sig, fs, nperseg=nperseg)
        _, gPxx_spec = cusignal.welch(gpu_sig, fs, nperseg=nperseg)
        gPxx_spec = cp.asnumpy(gPxx_spec)

        assert array_equal(cPxx_spec, gPxx_spec)
예제 #2
0
def test_welch(num_samps, fs, nperseg):
    cpu_sig = np.random.rand(num_samps)
    gpu_sig = cp.asarray(cpu_sig)

    cf, cPxx_spec = signal.welch(cpu_sig, fs, nperseg=nperseg)
    gf, gPxx_spec = cusignal.welch(gpu_sig, fs, nperseg=nperseg)
    gPxx_spec = cp.asnumpy(gPxx_spec)

    assert array_equal(cPxx_spec, gPxx_spec)
예제 #3
0
 def gpu_version(self, sig, fs, nperseg):
     with cp.cuda.Stream.null:
         out = cusignal.welch(sig, fs, nperseg=nperseg)
     cp.cuda.Stream.null.synchronize()
     return out
예제 #4
0
def run_gpu_spectrum_int(num_samp, nbins, gain, rate, fc, t_int):
    '''
    Inputs:
    num_samp: Number of elements to sample from the SDR IQ per call;
              use powers of 2
    nbins:    Number of frequency bins in the resulting power spectrum; powers
              of 2 are most efficient, and smaller numbers are faster on CPU.
    gain:     Requested SDR gain (dB)
    rate:     SDR sample rate, intrinsically tied to bandwidth in SDRs (Hz)
    fc:       Base center frequency (Hz)
    t_int:    Total effective integration time (s)

    Returns:
    freqs:       Frequencies of the resulting spectrum, centered at fc (Hz), 
                 numpy array
    p_avg_db_hz: Power spectral density (dB/Hz) numpy array
    '''
    import cupy as cp
    import cusignal

    # Force a choice of window to allow converting to PSD after averaging
    # power spectra
    WINDOW = 'hann'
    # Force a default nperseg for welch() because we need to get a window
    # of this size later. Use the scipy default 256, but enforce scipy
    # conditions on nbins vs. nperseg when nbins gets small.
    if nbins < 256:
        nperseg = nbins
    else:
        nperseg = 256

    print('Initializing rtl-sdr with pyrtlsdr:')
    sdr = RtlSdr()

    try:
        sdr.rs = rate  # Rate of Sampling (intrinsically tied to bandwidth with SDR dongles)
        sdr.fc = fc
        sdr.gain = gain
        print('  sample rate: %0.6f MHz' % (sdr.rs / 1e6))
        print('  center frequency %0.6f MHz' % (sdr.fc / 1e6))
        print('  gain: %d dB' % sdr.gain)
        print('  num samples per call: {}'.format(num_samp))
        print('  PSD binning: {} bins'.format(nbins))
        print('  requested integration time: {}s'.format(t_int))
        N = int(sdr.rs * t_int)
        num_loops = int(N / num_samp) + 1
        print('  => num samples to collect: {}'.format(N))
        print('  => est. num of calls: {}'.format(num_loops - 1))

        # Set up arrays to store power spectrum calculated from I-Q samples
        freqs = cp.zeros(nbins)
        p_xx_tot = cp.zeros(nbins, dtype=complex)
        # Create mapped, pinned memory for zero copy between CPU and GPU
        gpu_iq = cusignal.get_shared_mem(num_samp, dtype=np.complex128)
        cnt = 0

        # Set the baseline time
        start_time = time.time()
        print('Integration began at {}'.format(
            time.strftime('%a, %d %b %Y %H:%M:%S',
                          time.localtime(start_time))))

        # Time integration loop
        for cnt in range(num_loops):
            # Move USB-collected samples off CPU and onto GPU for calc
            gpu_iq[:] = sdr.read_samples(num_samp)

            freqs, p_xx = cusignal.welch(gpu_iq,
                                         fs=rate,
                                         nperseg=nperseg,
                                         nfft=nbins,
                                         noverlap=0,
                                         scaling='spectrum',
                                         window=WINDOW,
                                         detrend=False,
                                         return_onesided=False)
            p_xx_tot += p_xx

        end_time = time.time()
        print('Integration ended at {} after {} seconds.'.format(
            time.strftime('%a, %d %b %Y %H:%M:%S'), end_time - start_time))
        print('{} spectra were measured at {}.'.format(cnt, fc))
        print('for an effective integration time of {:.2f}s'.format(
            num_samp * cnt / rate))

        half_len = len(freqs) // 2
        # Swap frequencies:
        tmp_first = freqs[:half_len].copy()
        tmp_last = freqs[half_len:].copy()
        freqs[:half_len] = tmp_last
        freqs[half_len:] = tmp_first

        # Swap powers:
        tmp_first = p_xx_tot[:half_len].copy()
        tmp_last = p_xx_tot[half_len:].copy()
        p_xx_tot[:half_len] = tmp_last
        p_xx_tot[half_len:] = tmp_first

        # Compute the average power spectrum based on the number of spectra read
        p_avg = p_xx_tot / cnt

        # Convert to power spectral density
        # See the scipy docs for _spectral_helper().
        win = get_window(WINDOW, nperseg)
        p_avg_hz = p_avg * ((win.sum()**2) / (win * win).sum()) / rate

        p_avg_db_hz = 10. * cp.log10(p_avg_hz)

        # Shift frequency spectra back to the intended range
        freqs = freqs + fc

        # nice and tidy
        sdr.close()

    except OSError as err:
        print("OS error: {0}".format(err))
        raise (err)
    except:
        print('Unexpected error:', sys.exc_info()[0])
        raise
    finally:
        sdr.close()

    return cp.asnumpy(freqs), cp.asnumpy(p_avg_db_hz)