Speeding up spectrum analysis I'm trying to speed up this code that loops over an entire spectrum range. It's using a Raspberry Pi, and a rtl-sdr dongle that covers up to around 1.7 GHz. My goal is to be sweep over that spectrum and gather data from it in a timely manner.

#!bin/usr/python

#gathers from the rtl library needed for this program
from rtlsdr import RtlSdr
import math
from pylab import *
import time
from scipy.fftpack import fft, ifft
import pyqtgraph as pg
from pyqtgraph.Qt import QtGui, QtCore
import numpy as np
import os
import sys

os.system("sudo rmmod dvb_usb_rtl28xxu rtl2832")

#RtlSdr set up
##sdr = RtlSdr()
##
##
##num_samples = 4096
##
##freq_range_lo = 50e6     #experimental center freq for now
##freq_range_hi = 600e6  #1750e6
##freq_step = 1e6


##sample_rate = 2e6
##
###Set initial parameters for RTL-SDR Dongle
##sdr.sample_rate = sample_rate
##freq = 512e6
##sdr.center_freq = freq
##
##
##sdr.freq_correction = 102
##sdr.gain = 0



class Spec_Scan(object):

    samples = np.array([])
    samples_temp = np.array([])
    fft_data = np.array([])
    fft_data_temp = np.array([])

    app = QtGui.QApplication([])
    win = pg.GraphicsWindow(title="Basic plotting examples")
    win.resize(1000,600)
    win.setWindowTitle('pyqtgraph example: Plotting')


    def __init__(self, lo, hi, freq, step, samps):
        self.freq_range_lo = lo
        self.freq_range_hi = hi
        self.freq_step = step
        self.freq = freq
        self.num_samples = samps
        self.sample_rate = 2e6

        self.sdr = RtlSdr()
        self.sdr_default()


    def sdr_default(self):
        self.sdr.center_freq = self.freq
        self.sdr.freq_correction = 101
        self.sdr.gain = 0
        self.sdr.sample_rate = self.sample_rate



    def pyqt(self):
        global curve, p6
        # Enable antialiasing for prettier plots
        pg.setConfigOptions(antialias=True)

        self.win.nextRow()
        p6 = self.win.addPlot(title="Freq plot")

        self.curve = p6.plot(pen='y', clear=True)
        #p6.setRange(xRange = [0, (self.num_samples/2)*(1700e6/self.freq_step)], yRange = [-100,100])
        p6.setRange(xRange = [0, (self.num_samples/2)-48], yRange = [-100,100])






        print 'here'
        timer = pg.QtCore.QTimer()
        print'should begin update'
        timer.timeout.connect(self.update)
        timer.timeout.emit()
        print 'update should have finished'
        timer.start(2)

        if __name__ == '__main__':


            if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
                QtGui.QApplication.instance().exec_()



    def update(self):
        global curve, p6


        for self.freq in range(int(self.freq_range_lo), int(self.freq_range_hi), int(self.freq_step)):

            self.sdr.center_freq = self.freq
            self.samples = self.sdr.read_samples(self.num_samples)
            self.fft_data_temp = 20*np.log10(np.abs(np.fft.rfft(self.samples)))
            #self.fft_data_temp = self.fft_data_temp[0:2049]
##            self.fft_data_temp = self.fft_data_temp[1:(self.num_samples/2)]
##            self.fft_data_temp = 2*self.fft_data_temp[2::]
            self.fft_data = np.append(self.fft_data, self.fft_data_temp)
            self.fft_data_temp = 0

        #self.curve.setData(self.fft_data[1::], clear=True)
        self.fft_data = 0       

        print 'refresh'





def main():
    num_samples = 4096

    lo = 50e6     #experimental center freq for now
    hi = 1750e6
    step = 1e6
    freq = 425e6

    test = Spec_Scan(lo, hi, freq, step, num_samples)
##    test.pyqt()
    start = time.time()
    test.update()
    end = time.time()
    print str(end-start)


## Start Qt event loop unless running in interactive mode or using pyside.


main()


When the scan itself was timed, the result yielded around 197 seconds which is entirely too long. Is there a way I can speed up the spectrum scan?
I'll add my small contribution even though I'm not really a Python developer (hopefully some day). I've taken your update method and tested it on my computer (desktop, i3-4360@ 3.70GHz × 4 ), without the SDR bit.  And my intuition was right!

Like in most languages allowing you to do it, don't ever do that: 

self.fft_data = np.append(self.fft_data, self.fft_data_temp)


The reason is pretty simple: your array does not have a predefined size, so for each call to append, it has to re-allocate the memory to fit the new size. And that's terribly slow.

Let's talk numbers. Without this line of code, doing the FFT and converting the data to dB takes 300ms on my computer. Adding that line, it almost reaches 9s.

So now that we have found this, what to do about it for your application ? It seems that you would like to display the spectrum from 50MHz to 1750MHz, by decomposing it into signals with a 1MHz bandwidth. And for each slice, you generate 4096 samples. I don't know what kind of display you have, but displaying 4096 * 1700 FFT bins is gonna be difficult (especially in a 1000*600 window). You should restrict the size of the spectrum you want to display at once. And speaking just about bands, displaying the end of the HF band, the VHF band and part of the UHF band is not really gonna be interesting. Mostly because you're gonna have trouble finding an antenna that can cover all these bands simultaneously.