Programming for finding fft of a voltage signal

Hi all members,

I am new to arduino.I want to know how to do the fft of an analog signal using arduino.The analog signal will be in the range 0-5v. Initially I will be doing the programming by manually giving the values(0-5v) instead of connecting the reading to analog pins.Let me know is it possible to do this?

Thanks & Regards,
BISNI

Here is a library you can use for FFT:
http://wiki.openmusiclabs.com/wiki/ArduinoFFT

Thank you Johnwasser for your reply.Let me try this library.

Regards,
BISNI

I installed this library.I am using arduino UNO for my experiment.And I compiled the following program.Ii complied and uploaded successfully. But am not getting the display in the serial monitor as expected.Its showing some unreadable characters.It also happened for some other programs also.But it gave me the correct input when i changed the baud rate in the serial monitor.But for the fft program it remains as it is.Let me know how it can be rectified?Is there any other codes for doing the FFT?

Thanks & Regards,
BISNI

program.pdf (83.9 KB)

bisni:
But am not getting the display in the serial monitor as expected.Its showing some unreadable characters.

Usually that means your Serial Monitor is set to a different baud rate than your Arduino sketch.

That program does not display the result. Instead, it uses Serial.write to send the data to a PC program for display. Change the Serial.write portion to a loop that uses Serial.print, for example:

/*
 fft_test_sine
 example sketch for testing the fft library.
 This generates a simple sine wave data set, transforms it, 
 calculates and prints the amplitude of the transform.
 */

// do #defines BEFORE #includes
#define LIN_OUT 1 // use the lin output function
#define FFT_N 32 // set to 32 point fft

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

void setup() {
  Serial.begin(115200); // use the serial port
}

void loop() {
  int i,k;
  float f1=2,f2=5;  //two input frequencies
  for (i = 0 ; i < 32 ; i++) { // create 32 samples
    k=1000*sin(2*PI*f1*i/32.)+500.*sin(2*PI*f2*i/32.);
    fft_input[2*i] = k; // put real data into even bins
    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 in the fft
  fft_mag_lin(); // take the output of the fft
  // print the frequency index and amplitudes
  for (i=0; i<16; i++) { 
    Serial.print(i);
    Serial.print(" ");
    Serial.println(fft_lin_out[i]);
  }
  Serial.println("Done");
  while(1); //hang here
}

Thank you for your suggestions and corrections.I changed the code as below.I didn’t connect analog input to the pins.But still am getting some values in the serial monitor.Can you say how the values come?


#define LOG_OUT 1 // use the log output function
#define FFT_N 256 // set to 256 point fft

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

void setup() {
Serial.begin(115200); // use the serial port
TIMSK0 = 0; // turn off timer0 for lower jitter
ADCSRA = 0xe5; // set the adc to free running mode
ADMUX = 0x40; // use adc0
DIDR0 = 0x01; // turn off the digital input for adc0
}

void loop() {
while(1) { // reduces jitter
cli(); // UDRE interrupt slows this way down on arduino1.0
for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples
while(!(ADCSRA & 0x10)); // wait for adc to be ready
ADCSRA = 0xf5; // restart adc
byte m = ADCL; // fetch adc data
byte j = ADCH;
int k = (j << 8) | m; // form into an int
k -= 0x0200; // form into a signed int
k <<= 6; // form into a 16b signed int
fft_input = k; // put real data into even bins

  • fft_input[i+1] = 0; // set odd bins to 0*
  • }*
  • fft_window(); // window the data for better frequency response*
  • fft_reorder(); // reorder the data before doing the fft*
  • fft_run(); // process the data in the fft*
  • fft_mag_log(); // take the output of the fft*
  • sei();*
  • Serial.println(“start”);*
  • for (byte i = 0 ; i < FFT_N/2 ; i++) {*
    Serial.println(fft_log_out*); // send out the data*
    * }*
    * }*
    }
    These are the values from serial monitor:
    start
    224
    208
    74
    56
    44
    43
    37
    37
    24
    30
    30
    30
    30
    30
    30
    35
    8
    24
    24
    24
    24
    27
    24
    30
    24
    24
    30
    27
    27
    30
    27
    30
    0
    8
    19
    19
    8
    8
    24
    24
    0
    19
    19
    27
    8
    19
    19
    27
    0
    24
    24
    19
    8
    0
    24
    19
    19
    19
    19
    19
    0
    19
    19
    19
    0
    8
    0
    0
    8
    8
    8
    0
    8
    0
    0
    0
    8
    0
    0
    19
    0
    19
    8
    19
    0
    0
    8
    0
    8
    8
    0
    19
    24
    8
    8
    0
    8
    0
    0
    0
    0
    0
    0
    0
    0
    8
    8
    8
    0
    0
    0
    19
    8
    0
    0
    8
    0
    8
    8
    8
    8
    8
    8
    8
    19
    8
    8
    0

You left the pin unconnected, so it's picking up noise. Also please use code tags, as explained in the first few forum topics at the top of the forum.

Thank you for the reply.I Will post correctly next time. :slight_smile: .Is there any options to check the output are correct?Is it possible to compare the output with already known values?

bisni:
I will post correctly next time.

For everyone's convenience, you might consider editing your post so that it's correct this time. Your code, as it appears, won't compile. That's because the forum's web software interprets the places where you index an array using the variable i as a formatting code that means, "begin italics." Consequently, the brackets and index aren't shown, and everything afterward is italicized. You're likely to get more participation from the community if your code is obvious, and if the readers don't have to fix it to test it on their own Arduinos.

... any options to check the output are correct?Is it possible to compare the output with already known values?

Indeed, there are many options. The quickest way to test the code will be to give it data for which you know the expected outcome. For the FFT, that typically means a known sinusoidal function, or the sum of several of those. With the code you're using, the easiest way might be to overwrite the acquired analog value with some known data, like this:

      fft_input[i] = k; // put real data into even bins
      const float pi = 3.14159265359;
      const float h = 5;
      fft_input[i] = round(32000 * cos(h * pi * i / FFT_N));
      fft_input[i+1] = 0; // set odd bins to 0

That should result in a sharp peak in bin 5. You can try other values for h, as well. I'll note that a value of h that's close to or equal to 1 may yield unexpected results. That appears to be an artifact of windowing - when there's only one cycle to examine, the window has a greater effect on the calculations than when there are multiple cycles. For testing, you may want to turn windowing off, and you may want to see how things look on a linear scale.

Be sure you read the information at this page - http://wiki.openmusiclabs.com/wiki/FFTFunctions - and at this one - Defines - Open Music Labs Wiki, since they explain some of the internal workings of the FFT program, and some of the ways to use it..

I am new to this forum.Sorry for the wrong way of posting my code.I am posting it again in the correct way as tmd3 mentioned for everyone’s convenience.

#define LOG_OUT 1 // use the log output function
#define FFT_N 256 // set to 256 point fft

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

void setup() {
  Serial.begin(115200); // use the serial port
  TIMSK0 = 0; // turn off timer0 for lower jitter
  ADCSRA = 0xe5; // set the adc to free running mode
  ADMUX = 0x40; // use adc0
  DIDR0 = 0x01; // turn off the digital input for adc0
}

void loop() {
  while(1) { // reduces jitter
    cli();  // UDRE interrupt slows this way down on arduino1.0
    for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples
      while(!(ADCSRA & 0x10)); // wait for adc to be ready
      ADCSRA = 0xf5; // restart adc
      byte m = ADCL; // fetch adc data
      byte j = ADCH;
      int k = (j << 8) | m; // form into an int
      k -= 0x0200; // form into a signed int
      k <<= 6; // form into a 16b signed int
      fft_input = k; // put real data into even bins
      fft_input[i+1] = 0; // set odd bins to 0
    }
    fft_window(); // window the data for better frequency response
    fft_reorder(); // reorder the data before doing the fft
    fft_run(); // process the data in the fft
    fft_mag_log(); // take the output of the fft
    sei();
    Serial.println("start");
    for (byte i = 0 ; i < FFT_N/2 ; i++) { 
      Serial.println(fft_log_out); // send out the data
    }
  }
}

Actually I am not connecting the output to any display units.I will check the results from only the serial monitor.

That should result in a sharp peak in bin 5

bisni:
... giving the values(0-5v) instead of connecting the reading to analog pins.Let me know is it possible to do this?

It's still possible. That information showed up a few posts ago. Are you having trouble with it?

What I exactly meant is that the input supposed to give to the analog pin is 0-5 V. Instead of connecting the analog pin, can I give this values directly as an array and find the fft values of that?Is there any special format for doing this code?

http://wiki.openmusiclabs.com/wiki/FFTFunctionsBy reading the link I understood if am giving the values to the array myself ,I can give it in the following way:

fft_input[0] = real1, fft_input[1] = imaginary1
fft_input[2] = real2, fft_input[3] = imaginary2

Now let me know how to enter this in to my code.

Have you tried compiling the code you posted? It doesn't compile for me. Is this the code you used to generate your results?

bisni:
Now let me know how to enter this in to my code.

OK. I'll refer you again to reply #9 in this thread.

The code that you posted is largely the example code from Open Music Labs, here - http://wiki.openmusiclabs.com/wiki/Example - with the only difference being the way the results are output from the program. The example code Serial.write()'s the results, expecting a computer to interpret them, while your code Serial.print's them, to be displayed in the terminal window and read by a human.

The Open Music Labs example gets data from the ADC, and stores it in the array fft_input. If you want to use test data instead, I think that the simplest way is to write over the acquired data with test data. The changes to the original program are small, and you can easily identify and remove them when you're done testing and troubleshooting. Here's the code from reply #9 again, with some annotations that might be helpful:

      fft_input[i] = k; // put real data into even bins      // This line is IN YOUR CODE
      const float pi = 3.14159265359;                        // This line is ADDED
      const float h = 5;                                     // This line is ADDED
      fft_input[i] = round(32000 * cos(h * pi * i / FFT_N)); // This line is ADDED
      fft_input[i+1] = 0; // set odd bins to 0               // This line is IN YOUR CODE

For this application, the imaginary parts of the input data are all zero. You'll note that the example program sets all the imaginary values - the odd-numbered elements of the input array - to zero. If you think that you have a need for using something other than zero for the imaginary parts of the input data, then you're not doing what I think you're doing.

Can you tell us what you hope to accomplish with the FFT?

My aim is to find the fft of an anaolg signal[0-5v] using atmega microcontroller and to extract some parameters from it.I will be doing the simulation using arduino with UNO and also avrstudio.Actually am not familiar with fft and these softwares.I want to know what will be FFT of some values,so that I can put that values in the code and check the result in serial monitor and verify the code is correct.And I got the code from the FFT library -examples
.I understood the code in #9 mentioned and I tried it .But its showing errors and I couldn't compile it.

Can you tell us what you hope to accomplish with the FFT?

Try the example I posted in reply #5, which generates a signal with two sine waves, transforms that and shows you the power spectrum.

If you don’t understand the Fourier transform, there are a number of useful overviews and tutorials on the web. The FFT is just a fast way of calculating it.

bisni:
... its showing errors and I couldn't compile it.

The code compiled, ran, and produced the expected results, after I added the indexes that didn't show in the original code post. If you show us what you're trying to compile, we might be able to help. Without seeing that code, we can't.

The code I used is in #10,If you want I will post again.

[I added the indexes that didn't show in the original code post]