Real time FFT

Hey All,

I’m trying to create a software which shows the magnitudes and frequencies of an audio input. I checked all the FFT libraries I found (arduinoFFT, FFT, FHT, fix_fft, etc.), but I can’t figure out how they work… For example in this code, (using the FFT library) I can only get the magnitudes of sine waves if their frequencies are below 128 Hz. How can I get the magnitudes and frequencies of a signal between 20 Hz and 20 kHz?

Thanks,
Adam

fftforum.txt (1.18 KB)

//do #defines BEFORE #includes

/* https://forum.arduino.cc/index.php?topic=358314.15 */

#define LIN_OUT 1 // use the lin output function
#define FFT_N 256 // set to 32 point fft 

#include <FFT.h> // include the library

double sinewave (double A, double F, double Fs, double k)
{
 return A * sin(2*3.14*F*(k/Fs));
}

void setup() {
 Serial.begin(9600); // output on the serial port
}

void loop() {  
 int i,k;
 float f1=3.0,f2=5.0;  
 float f3 = 10000.0;    //the two input frequencies (bin values)
 for (i = 0 ; i < FFT_N ; i++) 
 { 
   k=1000*sin(2*PI*f1*i/FFT_N)+100*sin(2*PI*f3*i/FFT_N);
   fft_input[2*i] = k; // put real data into even bins
   //Serial.println(k);
   fft_input[2*i+1] = 0; // set odd bins to 0
 }
 fft_reorder(); // reorder the data before doing the fft
 fft_run(); // process the data using the fft
 fft_mag_lin(); // calculate the magnitude of the output
 // print the frequency index and amplitudes
 Serial.println("bin  amplitude");
 for (i=0; i<FFT_N/2 ; i++) {
   {
     Serial.print(i); Serial.print("   ");
     Serial.println(fft_lin_out[i]); 
   }
  
 }
 Serial.println("Done");
 while(1); //wait here
}

You are confusing bin number with frequency. For a 256 point transform, you get 128 output bins.

The actual frequencies associated with the bins are determined by the input sample rate.

How can I get the magnitudes and frequencies of a signal between 20 Hz and 20 kHz?

Each bin is a different frequency, the contents of the bin is the amplitude at that frequency. The top bin represents a frequency of half the sampling rate, the next lowest half that, in other words a quarter of the sampling rate and so it goes on. The lowest bin represents DC. To get 20KHz you have to sample the signal at 40KHz which is out of reach of an Arduino Uno. You have to step up to a Due, Zero or teensey to get that high.

It is possible to have the Arduino sample at much higher frequencies than the usual ~ 9.6 kHz, with some tradeoff on accuracy. All you need to do is change the ADC clock prescaler.

Here is some discussion. I've seen various projects on the web where people routinely record the full 20 kHz audio range.

Or use an external ADC. I have a project going here where mono-audio was sampled at CD quality (44100 Hz) and stored to SD card. http://forum.arduino.cc/index.php?topic=180769.0

Watch out for those online sources (ie. websites on the internet) that appear to tell people that the very last 'bin' or frequency point in a FFT plot is exactly associated with the frequency 'fs' (the sampling frequency).

The right-most point in an FFT plot usually represents a frequency of [(N-1)/N] * fs.

N is the number of time domain sampling points. However though, for relatively large 'N', that last frequency is almost the same as "fs".

The gap (frequency resolution) between adjacent frequency points (ie. between two bin frequencies) is equal to fs/N.

So.... if we have N = 100 time domain sample points, then the FFT magnitude plot has 0 to 99 frequency points (ie. still a total of 100 points). Point number [ 0 ] represents 0 Hz (ie. DC). Point number [50] represents a frequency of 5 * gap = 50*fs/100 = fs/2 (ie. half the sampling frequency).

The entire FFT MAGNITUDE plot will look symmetrical about point [50]. Normally, ignore the stuff above the half-way point, ie. point [50]. So, when discussing the magnitude spectrum, bin [ 0 ] to bin [50] are generally the bins (or frequency points) of interest, which represents 0 Hz up to fs/2, with frequency gaps of fs/N between adjacent points.

The above is not correct, or at least not helpful.

The ONLY useful information in the Fourier transform of a [u]real function[/u], as we are discussing in this thread, is in bins 0 to (N/2)-1 (interpreted as complex numbers), N as a power of two for FFT.

Often, bins 0 to (N/2)-1 are transformed into the power spectrum, which gives you the N/2 (real) magnitudes of the frequency components associated with each bin, up to a frequency that is one half the sample frequency.

Frequency components higher than [u]one half[/u] the sampling frequency MUST NOT BE PRESENT in the input data, or they will contaminate the spectrum with artifacts (look up FFT aliasing).

Another way of looking at the Fourier transform of a real function is that N real numbers are converted into N/2 amplitudes and N/2 phases. There is no loss or gain of information in the process.