Tiva C launchpad FFT with real time plotting using pyQtGraph

Circuit Diagram:

Circuit Diagram
Circuit Diagram

The biased signal generator signal is connected to AnalogIn 1 on the Tiva C which is pin PE_2. Signal Gen and Tiva C ground is common. The two 10k resistors from a voltage divider which will halve the 3v input to give a 1.5 v bias. The signal from the signal generator will be 3V peak to peak meaning that now the signal will vary from 0v to 3v using all of the ADCs available range. It’s probably a good idea to add a small capacitor in between the signal generator and the voltage divider to prevent the DC flowing through the signal gen. A 1Khz sample rate means that the highest frequency that we can reliably analyse is 500Hz. This comes from the the nyquist sampling theorem.

Code:

The Energia IDE was used to write and compile the code which runs on the Tiva C. See below for the code:

#include "fix_fft.h"

#define log2N     7
#define N         128     //number of sample points


void setup()
{
  Serial.begin(115200);
  delay(1000);             //give time for serial monitor to start up in Energia
  
  
}

int real[N];
int imag[N];
short i;

void loop()
{
  
  for (i=0; i<N; i++) {            // read ADC pin 128 times at roughly 1KHz
    real[i] = analogRead(A1);
    delay(1);
  }
  
  for( i=0; i<N; i++) imag[i] = 0;   // clear imag array
  
  fix_fft(real, imag, log2N, 0);   // perform fft on sampled points in real[i]
  
  for ( i = 0; i < N/2; i++)         //get the power magnitude in each bin
    {
      real[i] =sqrt((long)real[i] * (long)real[i] + (long)imag[i] * (long)imag[i]);		
    }
  
  Serial.print("*\n");      //send fft results over serial to PC
  for (i=0; i<N/2; i++) {
    Serial.print(real[i]);
    Serial.print("\n");
  }
  
  
}

The reason the code is so short is because all of the fft code is contained in fix_fft.h which is a c implementation on the fft which has been around for over two decades. It was first written by a person called Tom Roberts in 1989 and a google search of “fix_fft.c” will return many mirrors of this code available for download. the fix in “fix_fft.c” refers to the fact that it uses fixed point short integers as opposed to floating point numbers which will result in a loss of accuracy in the fft but a faster execution time.

Here is the python script used to plot the fft data:

#python script to read 64 bytes of data from tiva C and plot them 
#using pyQtGraph on a loop. As soon as 64 bytes arrive plot is updated


from pyqtgraph.Qt import QtGui, QtCore
import pyqtgraph as pg
import pyqtgraph.exporters
import numpy as np


import serial

ser = serial.Serial(
    port='COM4',
    baudrate=115200,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
	timeout=1
)

ser.close()
ser.open()
print (ser.isOpen())

data = np.zeros(64)

app = QtGui.QApplication([])

p = pg.plot()
p.setWindowTitle('FFT')
p.setLabel('bottom', 'Index', units='B')
curve = p.plot()



def update():
	global curve, data, 
	if(ser.readline() == b'*\n'):   # "*" indicates start of transmission from tiva c
		for h in range(63):
			try:
				data[h] = int(ser.readline())  #get 64 bytes from tiva c and plot them
			except:
				pass
		curve.setData(data)
		app.processEvents()  ## force complete redraw for every plot
			
			
	
timer = QtCore.QTimer()
timer.timeout.connect(update)
timer.start(0)


## Start Qt event loop unless running in interactive mode.
if __name__ == '__main__':
    import sys
    if (sys.flags.interactive != 1) or not hasattr(QtCore, 'PYQT_VERSION'):
        QtGui.QApplication.instance().exec_()

20 thoughts on “Tiva C launchpad FFT with real time plotting using pyQtGraph

  1. Wow, I love how simple the code is for this. I’ll definitely be trying out that pyqtgraph.

    Perhaps you would consider adding a DC-blocking capacitor in between the signal source and the bias network with the two 10k resistors? It would mean you don’t need to worry about the DC offset for the input signal – you’d only need to keep the peak-to-peak amplitude of the input below 3V, because the DC level of the input wouldn’t matter any more.

    This is such a useful little recipe!

    Ted

    1. Hey Ted, good idea with the capacitor, I added it to the diagram πŸ™‚
      pyqtgraph is a really handy library for fast updating plots. It comes with loads of cool examples that can be easily modified which is always a good thing!

      Shane

    1. Hey Frank, just measured it there using an oscilloscope. It takes 129 – 129.5ms (the measurement flickers between the two values on the scope) to take 128 samples. This would give 1.0117ms between samples which means a sample rate of 988Hz. Timer interrupts would make this more accurate I’d say. I’ll be stealing your energia timer interrupt code from here in the near future πŸ™‚

  2. Very interesting and useful!!
    Please could you tell me the concrete link to download the same fit_fft.c and .h that you use?
    Thanks!

  3. Great fft adc project! What sample rate and timing variance can you get by reducing or removing the delay? This could have some really cool applications where precice timing is not critical. Can you get to 100 ksps or more?

    1. Hi james, apologies for the delay in getting back to you – I’ll be using this fft setup for another project pretty soon and when I have it all set up again I’ll see how fast it can go. If it helps I do know that the AnalogRead() function takes approximately 1us to run on the TivaC – so it should be able to do 100ksps without to much hassle πŸ™‚

  4. Thanks for this project. This is very helpful.
    I have a question, in the code

    global curve, data,

    next to data,is there any words or blank?

    1. Hi Sae June, Glad you found it useful. It should be global curve, data .That extra comma shouldn’t be there.

      Shane

  5. I’m just now seeing this error …

    fft_tiva_c.cpp: In function ‘void loop()’:
    fft_tiva_c.cpp:28:31: error: cannot convert ‘int*’ to ‘short int*’ for argument ‘1’ to ‘int fix_fft(short int*, short int*, short int, short int)’
    delay(1);

    So I did this change… all to short

    short real[N];
    short imag[N];
    short i;

    Compiled OK, but have not tested yet….

    Binary sketch size: 13,700 bytes (of a 262,144 byte maximum)

Leave a Reply to wattnotions Cancel reply

%d bloggers like this: