# Plot real-time FFT using matplotlib

I'm trying to plot fft in python. I use pyalsaaudio for capturing audio in PCM (S16_LE) format. I use the ion() and draw() functions in matplotlib to have the fft plotted in real time. This is the program I wrote :

import alsaaudio as alsa
import numpy as np
from matplotlib import pyplot as plot
from matplotlib import animation
import time

#Configuration

card = 'default'
audio = alsa.PCM(alsa.PCM_CAPTURE,alsa.PCM_NONBLOCK, card)

def configure():
plot.ion()
audio.setchannels(1)
audio.setrate(44100)
audio.setformat(alsa.PCM_FORMAT_S16_LE)
audio.setperiodsize(1000)

def run():
loops = 100000
plot.show()
while loops > 0 :
loops-=1

if length:
#converting into a float array
npdata = np.fromstring(data,dtype='<i2')
#Obtaining FFT
freq_list = np.fft.fft(npdata)
plot.plot(freq_list)
plot.draw()
plot.clf()

plot.close()

configure()
run()


1) The entire plot is jumpy. The y axis limits range from -5 t 5 to several tens of thousands. Since the range of y axis keeps changing, so does the location of the plot. How can I fix this?

2) The x axis range is the argument to audio.setperiodsize(). In this case, it is 1000. From the pyalsaaudio documentation, "When the hardware processes data this is done in chunks of frames. The time interval between each processing (A/D or D/A conversion) is known as the period". Hence period is something to do with the time domain. It should have no relevance in the plot since fft is in the frequency domain. So why does the x axis of my plot end at the period size?

3) I believe that the fft function returns a set of complex numbers. What do they mean? The real part signifies the frequency and the imaginary part the amplitude? When I call matplotlib.plot() on the set of fft values, what is being plotted actually?

4) My objective is to determine the dominant frequency of a signal. To do this, I need to know the frequency and the amplitude of the component with that particular frequency. Can I get this from the fft plot?

Thanks for looking into this.

• don't plot repeatedly in a loop. make an empty plot first, like plt_gain = plt.plot(freqs, zeros(len(freqs)))[0] and then update the data points in the loop with plt_gain.set_data(freqs, gain) – endolith Apr 14 '14 at 13:23
• I will do that. But just for the sake of it, why? Is it a programming practice or because it has other advantages? – Kevin Martin Jose Apr 14 '14 at 13:26
• well replotting the whole figure each time is far slower and I think flickers, etc. also here's an example NOT using matplotlib for your reference: swharden.com/blog/… – endolith Apr 14 '14 at 13:29

Since the range of y axis keeps changing, so does the location of the plot. How can I fix this?

Use ylim to set the range of values on the Y axis.

So why does the x axis of my plot end at the period size?

Your input vector is of size 1000 ; so the FFT result is a sequence of 1000 complex numbers. Since you don't specify values / units for the x axis of your plot, you just get an arbitrary index.

To get a frequency scale, label your x axis as arange(0.0, length - 1) / length * 44100

What do they mean? The real part signifies the frequency and the imaginary part the amplitude?

You should really take some time to understand the Fourier transform. The use of freq_list as a variable name makes me think that you are mistaken as to how the FFT works.

The complex number in freq_list[i] represents the complex amplitude at frequency i / length * 44100. The magnitude of a complex amplitude represents actual amplitude, the angle of a complex amplitude represents phase.

You're probably only interested in the (squared) magnitude, and you'll get much nicer plots if you plot it on a logarithmic scale.

My objective is to determine the dominant frequency of a signal. To do this, I need to know the frequency and the amplitude of the component with that particular frequency. Can I get this from the fft plot?

Yes, by looking at the index of the FFT bin with the largest magnitude, but it's a rather terrible method for determining the fundamental frequency of audio signals - it has poor resolution and will provide incorrect results in a variety of common audio signals (for example it is common for speech signals to have lower energy at their fundamental frequency than at one harmonic).

• When I tried using plot(arange(0.0,freq_list.size-1)/freq_list.size * 44100), it raised ValueError: x and y must have same first dimension – Kevin Martin Jose Apr 14 '14 at 13:19
• For some weird reason, it is working now. I do not know what changed! – Kevin Martin Jose Apr 14 '14 at 13:36