Arduino Forum

Using Arduino => Audio => Topic started by: hongp on Jul 04, 2013, 09:43 pm

Title: Please help with arduino fft library
Post by: hongp on Jul 04, 2013, 09:43 pm
Hello, people,

I've been trying to figure out how to use arduino fft library provided by musical lab for the past two weeks.
I couldn't find any decent documentations on how to use this library. Maybe I should say I really couldn't understand the things in the fft_read_me.txt. I have no where to find working sample code to read. Please help me out.

Here is my problem:
After I upload the first fft sample code provided in arduino 1.0.5 example, it outputs some weird character in the serial monitor. I was expecting some numbers even if they're in dB scale. Do you guys have any ideas what is going here? For all the projects that I looked over, it seemed the output was hooked up to processing to be visualized in graphs. What if I just want the frequency itself as a number? let's say I use a oscilloscope with 2.5DC offset and generate a sine wave with 100 Hz at a sampling frequency of 38.5kHz. How do I go about extracting this 100Hz from the output of the fft?  
      Here is what I found from the readings:
      # of bins = # of samples;
      use the first half bins because the second part is the mirror image of the first part;
      frequency = (sampling frequency / # samples) * bin #
Output available from fft library: fft_lin_out8; fft_mag_lin; fft_mag_log. but they seemed to look like the magnitude of the waveform, not the frequency component which I'm interested in. For the testing purpose, all I wanted to do is to input a sine wave ranges from 10hz to 20khz, and I want to have those frequency outputed to serial port, or store it in a variable or array where I have access to it, I will use it to make a auto tuner.
     Here is the code:
Code: [Select]
/*
/*
fft_adc.pde
guest openmusiclabs.com 8.18.12
example sketch for testing the fft library.
it takes in data on ADC0 (Analog0) and processes them
with the fft. the data is sent out over the serial
port at 115.2kb.  there is a pure data patch for
visualizing the data.
*/

#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[i] = 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.write(255); // send a start byte
   Serial.write(fft_log_out, 128); // send out the data
 }
}


Thank you guys for the help in advance. If I can get this project to work, I will produce a full document and post it to here.


UPDATE 1:
To print out the number from fft_log_out, use a for loop and Serial.print() to print out each element in the array. Thank you all for the help. But I still have more questions on the second page!
Title: Re: Please help with arduino fft library
Post by: AWOL on Jul 04, 2013, 10:15 pm
Quote
it outputs some weird character in the serial monitor. I was expecting some numbers

I don't see where you set the baud rate, and anyway you're printing raw data with "write", not "print"
Title: Re: Please help with arduino fft library
Post by: johnwasser on Jul 04, 2013, 10:17 pm
The code is using Serial.write() to send binary bytes.  To make numbers human readable, use Serial.print().
Title: Re: Please help with arduino fft library
Post by: hongp on Jul 04, 2013, 10:23 pm

I don't see where you set the baud rate, and anyway you're printing raw data with "write", not "print"


I didn't copy the complete code. sorry about that. I copied and pasted it again.
The baud rate is 115200. I also tried 9600.

The code is from the example. I've tried to use serial.print.
but I always get this error:

fft_adc.pde: In function 'void loop()':
fft_adc:44: error: call of overloaded 'print(uint8_t [128], int)' is ambiguous
E:\programming\arduino-1.0.2\hardware\arduino\cores\arduino/Print.h:59: note: candidates are: size_t Print::print(unsigned char, int) <near match>
E:\programming\arduino-1.0.2\hardware\arduino\cores\arduino/Print.h:60: note:                 size_t Print::print(int, int) <near match>
E:\programming\arduino-1.0.2\hardware\arduino\cores\arduino/Print.h:61: note:                 size_t Print::print(unsigned int, int) <near match>
E:\programming\arduino-1.0.2\hardware\arduino\cores\arduino/Print.h:62: note:                 size_t Print::print(long int, int) <near match>
E:\programming\arduino-1.0.2\hardware\arduino\cores\arduino/Print.h:63: note:                 size_t Print::print(long unsigned int, int) <near match>
Title: Re: Please help with arduino fft library
Post by: AWOL on Jul 04, 2013, 10:25 pm
It's unlikely that you'd want to print binary data as a C string, so print it a sample at a time, in a for loop.
Title: Re: Please help with arduino fft library
Post by: hongp on Jul 04, 2013, 10:26 pm

The code is using Serial.write() to send binary bytes.  To make numbers human readable, use Serial.print().

Is it possible to process these binary bytes to get a useful frequency component out? Please point me to the right direction. I don't mind to read more code or concepts.

I tried to use serial.print.
but I always get the error:

fft_adc.pde: In function 'void loop()':
fft_adc:44: error: call of overloaded 'print(uint8_t [128], int)' is ambiguous
E:\programming\arduino-1.0.2\hardware\arduino\cores\arduino/Print.h:59: note: candidates are: size_t Print::print(unsigned char, int) <near match>
E:\programming\arduino-1.0.2\hardware\arduino\cores\arduino/Print.h:60: note:                 size_t Print::print(int, int) <near match>
E:\programming\arduino-1.0.2\hardware\arduino\cores\arduino/Print.h:61: note:                 size_t Print::print(unsigned int, int) <near match>
E:\programming\arduino-1.0.2\hardware\arduino\cores\arduino/Print.h:62: note:                 size_t Print::print(long int, int) <near match>
E:\programming\arduino-1.0.2\hardware\arduino\cores\arduino/Print.h:63: note:                 size_t Print::print(long unsigned int, int) <near match>
Title: Re: Please help with arduino fft library
Post by: AWOL on Jul 04, 2013, 10:28 pm
There is no "print" overload that prints a byte buffer as numeric.
Use a for loop to print each sample.
Title: Re: Please help with arduino fft library
Post by: hongp on Jul 04, 2013, 10:30 pm

It's unlikely that you'd want to print binary data as a C string, so print it a sample at a time, in a for loop.


Can you elaborate a little more please? I'm brand new to arduino, and not that much programming experience.
If I were to print one sample at time, will I be able to print out the frequency or just magnitude of the sample?

Thanks.
Title: Re: Please help with arduino fft library
Post by: hongp on Jul 04, 2013, 10:33 pm

There is no "print" overload that prints a byte buffer as numeric.
Use a for loop to print each sample.


Thank you all so much! I got some numbers out. Let me test it!
Title: Re: Please help with arduino fft library
Post by: johnwasser on Jul 04, 2013, 10:56 pm
The results of the FFT will be a list of amplitudes at a set of frequencies.  The frequency of each sample depends on the sample frequency.

For each 'bin' N the frequency is N * Sample_Rate / FFT_Size

Your sample rate is whatever the free-runing rate of the ADC is.  I don't remember offhand.  It should be in the datasheet.  Let's call it 70 KHz.

Your FFT_Size is 256.

Bin 0 frequency = 0 * 70,000/256 = 0 (DC offset)
Bin 1 frequency = 1 * 70,000/256 = 273.43 Hz (this will also be the step size in your frequency)
Bin 2 frequency = 2 * 70,000/256 = 546.875
Bin 3 frequency = 3 * 70,000/256 = 820.3125
...
Bin 127 frequency = 127 * 70,000/256 = 34,726.56

The top frequency is half the sample rate.
The sample step size is the sample rate divided by the the sample size.
Title: Re: Please help with arduino fft library
Post by: hongp on Jul 04, 2013, 10:58 pm
So I think I can print out the magnitude in dB. Not sure  if it is correct or not, but it feels really good to have some numbers coming out.

How do I go about extracting the frequency?
Just to learn FFT, I tried out kissFFT in C++ a couple days ago. I filled up an array with single sine function, and I passed the array to kissfft, then I output all the numbers from the first half of the bin. The array was set to have size the same as number of samples, so that the bin number = frequency for testing purpose. The output I had was all zero except the bin where the frequency of sine function is.

Can I do the same to fft library in arduino? I tried it. but a lot of the outputs aren't zero. Not sure if it's correct. Please point out any possible error.
Here is the code I used to test fft library:
Code: [Select]
#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(9600); // use the serial port
}

void loop() {
 // put your main code here, to run repeatedly:
  int k = 0;
  int t = 0;
   for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples
     k = 127*sin(2*3.14 * 100 * t );
     t++;
     fft_input[i] = 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
   for(int i = 0; i < 128; i++){
         Serial.println(fft_log_out[i]);
   }
   delay(1000);
}



Title: Re: Please help with arduino fft library
Post by: hongp on Jul 04, 2013, 11:06 pm

The results of the FFT will be a list of amplitudes at a set of frequencies.  The frequency of each sample depends on the sample frequency.

For each 'bin' N the frequency is N * Sample_Rate / FFT_Size

Your sample rate is whatever the free-runing rate of the ADC is.  I don't remember offhand.  It should be in the datasheet.  Let's call it 70 KHz.

Your FFT_Size is 256.

Bin 0 frequency = 0 * 70,000/256 = 0 (DC offset)
Bin 1 frequency = 1 * 70,000/256 = 273.43 Hz (this will also be the step size in your frequency)
Bin 2 frequency = 2 * 70,000/256 = 546.875
Bin 3 frequency = 3 * 70,000/256 = 820.3125
...
Bin 127 frequency = 127 * 70,000/256 = 34,726.56

The top frequency is half the sample rate.
The sample step size is the sample rate divided by the the sample size.


Great explanation! Thank you so much! that clears out a lot of confusion!
So I want to test out fft library by filling up the bins with numbers from one single sine function, but I get many bins with nonzero output. Am I supposed to get only one bin with non-zero number? Because that bin has to be the frequency of the sine function scaled in the way you explained here.
Here is the code I used to test:
Code: [Select]
#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(9600); // use the serial port
}

void loop() {
  // put your main code here, to run repeatedly:
   int k = 0;
   int t = 0;
    for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples
      k = 127*sin(2*3.14 * 100 * t );
      t++;
      fft_input[i] = 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
    for(int i = 0; i < 128; i++){
          Serial.println(fft_log_out[i]);
    }
    delay(1000);
}
Title: Re: Please help with arduino fft library
Post by: johnwasser on Jul 04, 2013, 11:37 pm
If the frequency of the sine wave matches one of the bins then you should get a strong signal in that bin and little or no signal in the other bins.  If the frequency is between bins you should get signals in the two bins on either side.
Title: Re: Please help with arduino fft library
Post by: Magician on Jul 04, 2013, 11:44 pm
Quote
If the frequency of the sine wave matches one of the bins then you should get a strong signal in that bin and little or no signal in the other bins.  If the frequency is between bins you should get signals in the two bins on either side.

True, if "float" math involved, better 64-bits. For 8/16-bits integer microprocessor w/o floating coprocessor truncation error would get into scene, don't expect clean output.
To OP: What kind of arduino board do you have?
What you are trying to achieve, resolution, freq. range, nature of the input signal?
Title: Re: Please help with arduino fft library
Post by: hongp on Jul 05, 2013, 12:10 am

Quote
If the frequency of the sine wave matches one of the bins then you should get a strong signal in that bin and little or no signal in the other bins.  If the frequency is between bins you should get signals in the two bins on either side.

True, if "float" math involved, better 64-bits. For 8/16-bits integer microprocessor w/o floating coprocessor truncation error would get into scene, don't expect clean output.
To OP: What kind of arduino board do you have?
What you are trying to achieve, resolution, freq. range, nature of the input signal?


I'm using arduino UNO. Frequency range = human detectable range; input signal = instrument sound, but for testing purpose, it is oscilloscope with 2.5DC offset, 4Vpp, frequency ranges from 10hz to the limit when output frequency is not accurate anymore, hopefully close to 20khz;
I'm going to make a frequency auto-tuner. I've seen people make the guitar frequency tuner, mine is different, but the concept is the same.

Do you guys know what the free running sampling frequency is? I'm really new to arduino, did a few search. Didn't find the one correspond to UNO.
Also, if you have a link to a tutorial that explains what those parameters are, it would be great!
Title: Re: Please help with arduino fft library
Post by: hongp on Jul 05, 2013, 12:16 am

If the frequency of the sine wave matches one of the bins then you should get a strong signal in that bin and little or no signal in the other bins.  If the frequency is between bins you should get signals in the two bins on either side.


It makes sense.
Can you look at my test code to see if I coded it correctly? I think the sine wave I used has 256 samples = #bins. And the frequency is set at 100hz.
I should get some numbers in bin#100, but I got zero in it, and a lot of other numbers in most of the bins.

Here is the output:
bin #: 0   log mag: 32
bin #: 1   log mag: 43
bin #: 2   log mag: 39
bin #: 3   log mag: 43
bin #: 4   log mag: 35
bin #: 5   log mag: 39
bin #: 6   log mag: 39
bin #: 7   log mag: 39
bin #: 8   log mag: 30
......

bin #: 84   log mag: 27
bin #: 85   log mag: 8
bin #: 86   log mag: 19
bin #: 87   log mag: 19
bin #: 88   log mag: 0
bin #: 89   log mag: 19
bin #: 90   log mag: 0
bin #: 91   log mag: 8
bin #: 92   log mag: 19
bin #: 93   log mag: 0
bin #: 94   log mag: 8
bin #: 95   log mag: 8
bin #: 96   log mag: 8
bin #: 97   log mag: 8
bin #: 98   log mag: 8
bin #: 99   log mag: 8
bin #: 100   log mag: 0
bin #: 101   log mag: 8
bin #: 102   log mag: 8
bin #: 103   log mag: 0
bin #: 104   log mag: 0
bin #: 105   log mag: 0
bin #: 106   log mag: 0
bin #: 107   log mag: 8
Title: Re: Please help with arduino fft library
Post by: el_supremo on Jul 05, 2013, 12:57 am
I don't think your test code is generating a useful sine wave. Have a look at the code I reference in this thread:
http://forum.arduino.cc/index.php?topic=96562.0 (http://forum.arduino.cc/index.php?topic=96562.0)

Pete
Title: Re: Please help with arduino fft library
Post by: johnwasser on Jul 05, 2013, 01:01 am

Can you look at my test code to see if I coded it correctly? I think the sine wave I used has 256 samples = #bins. And the frequency is set at 100hz.
I should get some numbers in bin#100, but I got zero in it, and a lot of other numbers in most of the bins.


What is the (simulated) sample rate in Hz?  In order to get 100 Hz to be in Bin 100 you have to have sampleRate == sampleCount.

100 * sampleRate (Hz) / sampleCount = 100 (Hz)

Title: Re: Please help with arduino fft library
Post by: Magician on Jul 05, 2013, 01:34 am
Quote
I'm using arduino UNO.
You hardly can get FFT-256 on UNO, check on memory specification. 512 only with 8-bits word size.

Frequency range = human detectable range; input signal = instrument sound, but for testing purpose, it is oscilloscope with 2.5DC offset, 4Vpp, frequency ranges from 10hz to the limit when output frequency is not accurate anymore, hopefully close to 20khz;
Free running arduno samples ~9 kHz, upper limit 4.5 kHz, you have to use your own sampling subroutine with tweaking ADC registers.

I'm going to make a frequency auto-tuner. I've seen people make the guitar frequency tuner, mine is different, but the concept is the same.
You can't get better than 4 Hz resolution, too pure for instrument tunning.


You 'd be better with http://interface.khm.de/index.php/lab/experiments/frequency-measurement-library/ (http://interface.khm.de/index.php/lab/experiments/frequency-measurement-library/)
Title: Re: Please help with arduino fft library
Post by: hongp on Jul 05, 2013, 02:03 am

Quote
I'm using arduino UNO.
You hardly can get FFT-256 on UNO, check on memory specification. 512 only with 8-bits word size.

Frequency range = human detectable range; input signal = instrument sound, but for testing purpose, it is oscilloscope with 2.5DC offset, 4Vpp, frequency ranges from 10hz to the limit when output frequency is not accurate anymore, hopefully close to 20khz;
Free running arduno samples ~9 kHz, upper limit 4.5 kHz, you have to use your own sampling subroutine with tweaking ADC registers.

I'm going to make a frequency auto-tuner. I've seen people make the guitar frequency tuner, mine is different, but the concept is the same.
You can't get better than 4 Hz resolution, too pure for instrument tunning.


You 'd be better with http://interface.khm.de/index.php/lab/experiments/frequency-measurement-library/ (http://interface.khm.de/index.php/lab/experiments/frequency-measurement-library/)

I have access to other arduinos. Most of them. Can you suggest one that has the juice to get the job done?
I saw a tutorial before, that a girl was able to set the sampling rate to 38.5kHz. I was hoping that's the rate I will use.
When you say the resolution is too pure for instrument tunning, is that good or bad?  4Hz difference sounds very reasonable.
How did you find out free running sampling frequency is 9 kHz for UNO? Can you post a link here, please? I want to know where or how to find those infos. Also, I looked at arduino reference page, UNO has 16 MHz ceramic resonator. Why does it only sample at a max rate of 9kHz? Can you teach me how to figure it out?
Thanks
Title: Re: Please help with arduino fft library
Post by: hongp on Jul 05, 2013, 02:14 am


What is the (simulated) sample rate in Hz?  In order to get 100 Hz to be in Bin 100 you have to have sampleRate == sampleCount.

100 * sampleRate (Hz) / sampleCount = 100 (Hz)




This is the code I used to generate sine wave data:
Code: [Select]
  for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples
    k = 127*sin(2*3.14 * 100 * t );
    t++;
    fft_input[i] = k; // put real data into even bins
    fft_input[i+1] = 0; // set odd bins to 0
  }

I have 256 samples = sampleCount; I have no idea what the simulated sampling rate is. How can I find out? I thought all I need was to filled up the array with numbers. Please help!
     If I change " k = 127*sin(2*3.14 * 100 * t ) " to "k = 127*sin(2*3.14 * 100 * 256 * t )" would that make a difference?
     I thought I understood a little about this stuff. Now I'm really confused.
    Thank you
Title: Re: Please help with arduino fft library
Post by: Magician on Jul 05, 2013, 02:27 am
Quote
Can you suggest one that has the juice to get the job done?
More memory, Mega - 8K 'd make 4x difference in resolution, compare to UNO.
I saw a tutorial before, that a girl was able to set the sampling rate to 38.5kHz. I was hoping that's the rate I will use.
Rate is not an obstacle, memory is.
When you say the resolution is too pure for instrument tunning, is that good or bad?  4Hz difference sounds very reasonable.
Do your research, I think it's about 1%, 100Hz note 'd requre 1Hz

http://en.wikipedia.org/wiki/Piano_key_frequencies
http://coolarduino.wordpress.com/2011/09/03/arduino-musical-note-recognition-pushing-the-limits/ (http://coolarduino.wordpress.com/2011/09/03/arduino-musical-note-recognition-pushing-the-limits/)
Title: Re: Please help with arduino fft library
Post by: hongp on Jul 05, 2013, 02:35 am

I don't think your test code is generating a useful sine wave. Have a look at the code I reference in this thread:
http://forum.arduino.cc/index.php?topic=96562.0 (http://forum.arduino.cc/index.php?topic=96562.0)

Pete

Hey, Pete, I posted a question back in your original post. Please take a look at it. Thanks
Title: Re: Please help with arduino fft library
Post by: hongp on Jul 05, 2013, 02:48 am

Quote
Can you suggest one that has the juice to get the job done?
More memory, Mega - 8K 'd make 4x difference in resolution, compare to UNO.
I saw a tutorial before, that a girl was able to set the sampling rate to 38.5kHz. I was hoping that's the rate I will use.
Rate is not an obstacle, memory is.
When you say the resolution is too pure for instrument tunning, is that good or bad?  4Hz difference sounds very reasonable.
Do your research, I think it's about 1%, 100Hz note 'd requre 1Hz

http://en.wikipedia.org/wiki/Piano_key_frequencies
http://coolarduino.wordpress.com/2011/09/03/arduino-musical-note-recognition-pushing-the-limits/ (http://coolarduino.wordpress.com/2011/09/03/arduino-musical-note-recognition-pushing-the-limits/)



Thank you for the help! I'm reading the links you posted here.
How did you find out free running sampling frequency is 9 kHz for UNO? Can you post a link here, please? I want to know where or how to find those infos. Also, I looked at arduino reference page, UNO has 16 MHz ceramic resonator. Why does it only sample at a max rate of 9kHz? Can you teach me how to figure it out?
Why would you think sampling rate is not a problem? Even if I used UNO, it still isn't a problem or you meant that if I use mega, It won't be a problem anymore? It looks like mega has the same cpu speed as UNO, it does have a lot bigger memory. You think the memory is a problem, is it because I need to get better frequency resolutions?
thanks
Title: Re: Please help with arduino fft library
Post by: johnwasser on Jul 05, 2013, 04:34 am
From the ATmega data sheet:

"By default, the successive approximation circuitry requires an input clock frequency between 50 kHz and 200 kHz to get maximum resolution. If a lower resolution than 10 bits is needed, the input clock frequency to the ADC can be higher than 200 kHz to get a higher sample rate."

"To get full resolution you need to run the ADC at 15,000 samples per second or slower."

"You can get 76,900 samples per second at reduced resolution."

In free-running mode it takes 13.5 cycles to per sample.  The pre-scaler options are:

2 = 8 MHz = 592,592 samples per second (too fast)
4 = 4 MHz = 296,296 samples per second (too fast)
8 = 2 MHz = 148,148 samples per second (too fast)
16 = 1 MHz = 74,074 samples per second (low resolution)
32 = 500 KHz = 37,037 samples per second (reduced resolution)
64 = 250 KHz = 18,518 samples per second (reduced resolution)
128 = 125 KHz = 9,259 samples per second (full resolution)

Looks like your loose a couple of digits of accuracy if you run at 1 MHz (74,074 samples per second)
Absolute accuracy, ADC clock = 200 kHz: 2 LSB
Absolute accuracy, ADC clock = 1 MHz: 4.5 LSB
Title: Re: Please help with arduino fft library
Post by: hongp on Jul 05, 2013, 05:06 am

Quote
Can you suggest one that has the juice to get the job done?
More memory, Mega - 8K 'd make 4x difference in resolution, compare to UNO.
I saw a tutorial before, that a girl was able to set the sampling rate to 38.5kHz. I was hoping that's the rate I will use.
Rate is not an obstacle, memory is.
When you say the resolution is too pure for instrument tunning, is that good or bad?  4Hz difference sounds very reasonable.
Do your research, I think it's about 1%, 100Hz note 'd requre 1Hz

http://en.wikipedia.org/wiki/Piano_key_frequencies
http://coolarduino.wordpress.com/2011/09/03/arduino-musical-note-recognition-pushing-the-limits/ (http://coolarduino.wordpress.com/2011/09/03/arduino-musical-note-recognition-pushing-the-limits/)



I see your point. accuracy is very important for piano tuning, maybe for all the musical tuning. From the wiki page, piano only produces frequencies from 27.5hz up 4186hz, which means I need to have at lease 8372hz sampling  rate to do this type of tuning. I read that sometime it requires a little bit higher than twice of highest frequency to get the optimum result somewhere. But that's a lot lower than what I intended to set at.
According to john from reply #24, if I set pre-scaler = 128, I can have a sample rate of  9259 hz and full-resolution. The frequency is enough for piano tuning, right? but for resoolution, I hope full-resolution is at least 10bits, do I still need larger memory?

Thank you.
Title: Re: Please help with arduino fft library
Post by: hongp on Jul 05, 2013, 05:18 am

From the ATmega data sheet:

"By default, the successive approximation circuitry requires an input clock frequency between 50 kHz and 200 kHz to get maximum resolution. If a lower resolution than 10 bits is needed, the input clock frequency to the ADC can be higher than 200 kHz to get a higher sample rate."

"To get full resolution you need to run the ADC at 15,000 samples per second or slower."

"You can get 76,900 samples per second at reduced resolution."

In free-running mode it takes 13.5 cycles to per sample.  The pre-scaler options are:

2 = 8 MHz = 592,592 samples per second (too fast)
4 = 4 MHz = 296,296 samples per second (too fast)
8 = 2 MHz = 148,148 samples per second (too fast)
16 = 1 MHz = 74,074 samples per second (low resolution)
32 = 500 KHz = 37,037 samples per second (reduced resolution)
64 = 250 KHz = 18,518 samples per second (reduced resolution)
128 = 125 KHz = 9,259 samples per second (full resolution)

Looks like your loose a couple of digits of accuracy if you run at 1 MHz (74,074 samples per second)
Absolute accuracy, ADC clock = 200 kHz: 2 LSB
Absolute accuracy, ADC clock = 1 MHz: 4.5 LSB

Hey, john, thank you for the great explanation.
I found out that I don't need to go all the way up to 20kHz for musical tuning. For piano, I need to have at least 8372 hz sampling rate. According to your calculation, I can use pre-scaler 128 and get the full resolution. Magician from reply #18 pointed that out! which is a great news for me.

Could you also help me out on set the simulation sampling frequency rate, please?

"I have 256 samples = sampleCount; I have no idea what the simulated sampling rate is. How can I find out? I thought all I need was to filled up the array with numbers. Please help!
     If I change " k = 127*sin(2*3.14 * 100 * t ) " to "k = 127*sin(2*3.14 * 100 * 256 * t )" would that make a difference?
     I thought I understood a little about this stuff. Now I'm really confused."

Thank you
Title: Re: Please help with arduino fft library
Post by: Magician on Jul 05, 2013, 12:35 pm
Quote
How did you find out free running sampling frequency is 9 kHz for UNO? Can you post a link here, please? I want to know where or how to find those infos. Also, I looked at arduino reference page, UNO has 16 MHz ceramic resonator. Why does it only sample at a max rate of 9kHz? Can you teach me how to figure it out?
Download datasheet AtMega328 from atmel.com look into ADC section, you will find all information
Why would you think sampling rate is not a problem? Even if I used UNO, it still isn't a problem or you meant that if I use mega, It won't be a problem anymore? It looks like mega has the same cpu speed as UNO, it does have a lot bigger memory. You think the memory is a problem, is it because I need to get better frequency resolutions?
Exactly, don't confuse ADC resolution (which is least of your worry, as low as 8-bit o'k), and FFT resolution, that defined as Freq. range / Bin numbers. Having 4 kHz sampling and / 512-fft = 8 Hz. Paradox is  , you need to lower sampling rate, to get better resolution! (I mention this in musical note recognition post). Other parameter, increasing fft-size, isn't an option , except you have Due board.


Title: Re: Please help with arduino fft library
Post by: johnwasser on Jul 05, 2013, 02:56 pm
The wikipedia article shows note frequencies with six significant digits.  In the low notes that's a resolution of 0.0001 Hz.  To get that resolution at 9,259 samples per second you would need an FFT size of 92.5 million samples (185 megabytes). That is not going to happen on an Arduino in any reasonable amount of time.

Perhaps you can use zero crossings to measure the frequency.  Have you looked at any frequency counter sketches?

http://interface.khm.de/index.php/lab/experiments/arduino-frequency-counter-library/
Title: Re: Please help with arduino fft library
Post by: hongp on Jul 06, 2013, 12:24 am

How did you find out free running sampling frequency is 9 kHz for UNO? Can you post a link here, please? I want to know where or how to find those infos. Also, I looked at arduino reference page, UNO has 16 MHz ceramic resonator. Why does it only sample at a max rate of 9kHz? Can you teach me how to figure it out?

Download datasheet AtMega328 from atmel.com look into ADC section, you will find all information

This is what I found in the datasheet:
"Using the ADC Interrupt Flag as a trigger source makes the ADC start a new conversion as soon
as the ongoing conversion has finished. The ADC then operates in Free Running mode, constantly
sampling and updating the ADC Data Register."
It doesn't talk about how fast the free running mode is. Did you use some conversion factor? I'm completely new to micro-controllers. Look like I have a lot reading to do. Can you suggest a good place to start?


Why would you think sampling rate is not a problem? Even if I used UNO, it still isn't a problem or you meant that if I use mega, It won't be a problem anymore? It looks like mega has the same cpu speed as UNO, it does have a lot bigger memory. You think the memory is a problem, is it because I need to get better frequency resolutions?

Exactly, don't confuse ADC resolution (which is least of your worry, as low as 8-bit o'k), and FFT resolution, that defined as Freq. range / Bin numbers. Having 4 kHz sampling and / 512-fft = 8 Hz. Paradox is  , you need to lower sampling rate, to get better resolution! (I mention this in musical note recognition post). Other parameter, increasing fft-size, isn't an option , except you have Due board.


I I think arduino FFT library only provide max # of bin of 256 to filled in the real data. It doesn't go up to 512. I was definitely confused by ADC resolution and FFT resolution. Thank you for clear that out. Amanda from instructable.com was able to turn down ADC resolution to 8 bit in order to speed up the sampling rate, but you're saying to lower it down to get better resolution, and I can clearly see your point. If I were to lower it down, how would I be able to cover all the frequency range? from 27hz to 4186hz.
I read your blog about pushing arduino to the limit. That was a very impressive project you made! A few questions after reading your blog:
1. How could you have 1024 bins for the FFT? The one comes with arduino IDE is limited to 512 bins as the max. Half of the bins are filled with the data taken from analog input, the other half is set to zero manually. Do you use different library?
2.The shadow masking technique you used, is it setting a range for the detected frequencies to fall in, and then light up corresponding LED even though the resolution limited to 7.8hz?
3. If you already pushed arduino mega to the limit in that project, does it mean I have to either get a Due board or call off my project, or do something similar to yours just to understand how micro-controllers works? What if I use multiple mega boards? having each of them detecting different frequency ranges?
4.From arduino FFT documentation, it suggests to set imaginary part to zero if the samples are taken from analog input. Is that what you did?

I know it's a lot of questions, but I'm really into micro-controller now, especially this topic. Please bear with me if I ask something that is too trivial.
Thank you

Title: Re: Please help with arduino fft library
Post by: hongp on Jul 06, 2013, 01:04 am

The wikipedia article shows note frequencies with six significant digits.  In the low notes that's a resolution of 0.0001 Hz.  To get that resolution at 9,259 samples per second you would need an FFT size of 92.5 million samples (185 megabytes). That is not going to happen on an Arduino in any reasonable amount of time.

Perhaps you can use zero crossings to measure the frequency.  Have you looked at any frequency counter sketches?

http://interface.khm.de/index.php/lab/experiments/arduino-frequency-counter-library/


Thank you for the suggestion. I've tried a code made by Amanda from instructable.com. It works really well up until the frequency gets up to 1khz. I will definitely look into the one you suggested here.

I also want to know how FFT works. I've read many article about how it works, but it seems like I didn't really understand everything.
Can you explain how you get 92.5 million samples is necessary to have six digits of resolution at 9259hz sampling rate? and how you figure out the size if 185 mB?

Can you also please teach me how to set the simulated frequency? I think that's what I was missing when I tested out the FFT library. I thought I was filling up the array with sine wave data generated by  k = 127*sin(2*3.14 * 100 * t ), where t was incremented 256 times, which was the same size of the FFT real bin, imaginary bins were filled with zeros. I thought with this method, the only bin that will contain numbers greater than zero is bin 100, but it is not the case. I have a lot numbers in other bins.

Thank you
Title: Re: Please help with arduino fft library
Post by: Magician on Jul 06, 2013, 01:08 am
Quote
I I think arduino FFT library only provide max # of bin of 256 to filled in the real data. It doesn't go up to 512. I was definitely confused by ADC resolution and FFT resolution. Thank you for clear that out. Amanda from instructable.com was able to turn down ADC resolution to 8 bit in order to speed up the sampling rate, but you're saying to lower it down to get better resolution, and I can clearly see your point. If I were to lower it down, how would I be able to cover all the frequency range? from 27hz to 4186hz.
No, you wouldn't. My project covers 4 octaves only
I read your blog about pushing arduino to the limit. That was a very impressive project you made! A few questions after reading your blog:
1. How could you have 1024 bins for the FFT? The one comes with arduino IDE is limited to 512 bins as the max. Half of the bins are filled with the data taken from analog input, the other half is set to zero manually. Do you use different library?
Code is linked, not a library, written by myself.
2.The shadow masking technique you used, is it setting a range for the detected frequencies to fall in, and then light up corresponding LED even though the resolution limited to 7.8hz?
Requirements to distinguish two notes and for tunning are different
3. If you already pushed arduino mega to the limit in that project, does it mean I have to either get a Due board or call off my project, or do something similar to yours just to understand how micro-controllers works? What if I use multiple mega boards? having each of them detecting different frequency ranges?
You may try Due, I used UNO btw, not Mega.
4.From arduino FFT documentation, it suggests to set imaginary part to zero if the samples are taken from analog input. Is that what you did?
Yes

Using fft may be appropriate if there are a few notes play simultaneously, which is not the case for you project. Freq. measuremets library linked in reply #18 and #28 is better approach for tunning.
Title: Re: Please help with arduino fft library
Post by: johnwasser on Jul 06, 2013, 02:02 am

Can you explain how you get 92.5 million samples is necessary to have six digits of resolution at 9259hz sampling rate? and how you figure out the size if 185 mB?


It's the formula I showed earlier.  The resolution of the FFT is sampleRate/sampleCount.  To get resolution of 0.0001 Hz (1/10,000th Hz) you need sampleCount to be 10,000 times the sampleRate.

If each sample is a 2-byte integer you need 2*sampleCount bytes to store them.
Title: Re: Please help with arduino fft library
Post by: hongp on Jul 06, 2013, 02:56 am

It's the formula I showed earlier.  The resolution of the FFT is sampleRate/sampleCount.  To get resolution of 0.0001 Hz (1/10,000th Hz) you need sampleCount to be 10,000 times the sampleRate.

If each sample is a 2-byte integer you need 2*sampleCount bytes to store them.

Got it! 2*10000*9259/(2^20) = 176 mB. 
Thank you so much!
Title: Re: Please help with arduino fft library
Post by: johnwasser on Jul 06, 2013, 04:39 am
To have "bin 100" represent 100 Hz you have to use a sample rate equal to the FFT size:

512 sample FFT at 512 samples per second.

I think the code would be something like this:
Code: [Select]

    for (int i = 0 ; i < 512 ; i += 2) {
      float time = i/512.0;       // Time in seconds from start of sample
      float cycle = time * 100;  // Cycles since start of samples
      fft_input[i] = 127 * sin(2 * Pi * cycle);; // put real data into even bins
      fft_input[i+1] = 0; // set odd bins to 0
    }
Title: Re: Please help with arduino fft library
Post by: hongp on Feb 10, 2014, 07:14 am
Yo, I got a few messages asking about the same problem I had with fft library.
If you still have problems getting the correct output from that library, look at my code.
This is the working code that I demo to my professor.
Code: [Select]

#define LOG_OUT 1 // use the log output function
#define FFT_N 256 // set to 256 point fft
#include <FFT.h> // include the library

//UNO clock Frequency = 16 MHz
//It takes 13 clock cycles to finish analog reading
int refFrequency = 0;
int currentFrequency = 0;
int previousFrequency = 0;
int errorFrequency = 0;
int refState = 0;
int currentState = 0;
int tunningState = 0;
boolean inRange = false;
float P = 0;
float I = 0.0;
float D = 0.0;
float drive = 0;
int pwmDrive = 0;
const int refInput = 8;  //reference pin
const int currentInput = 9;  //final pin
const int ForMotorControl = 10;  //pump control pin PWM
const int BacMotorControl = 11;  //pump control pin PWM
const int tunning = 12;  //tuning control pin
int bin = 0;
int frequency = 0;
int resolution = 9615 / 256;
int maxLogOut = 0;


void setup() {
  Serial.begin(9600); // use the serial port
  pinMode(refInput, INPUT);
  pinMode(currentInput, INPUT);
  pinMode(tunning, INPUT);
  pinMode(ForMotorControl, OUTPUT);
  pinMode(BacMotorControl, OUTPUT);
  ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0); //set adc prescaler=128
  ADMUX = 0x40; // use adc0
  ADCSRA |= (1<<ADATE);  //enable auto trigger
  ADCSRA |= (1<<ADEN);  //enable ADC
  ADCSRA |= (1<<ADSC);  //start ADC measurements
}

void loop() {
  while(1) { // reduces jitter
    cli();  // UDRE interrupt slows this way down on arduino1.0
    //sampling
    for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples
      while(!(ADCSRA & 0x10)); // wait for adc to be ready
      ADCSRA |=(1<<ADSC); //start ADC measurements
      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[i] = k; // put real data into even bins
      fft_input[i+1] = 0; // set odd bins to 0
    }//end of for
   
    //FFT
    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();
    maxLogOut = 0;
    for(int i = 1; i < 128; i++){
      if(fft_log_out[i] > maxLogOut && fft_log_out[i] > 150){
          maxLogOut = fft_log_out[i];
          bin = i;
      }//end of if
    }//end of for
    frequency = bin * resolution;
    if(frequency > 1500 && frequency < 2700){
      inRange = true;
    } else {
      inRange = false;
    }
   
    //if digital pin 8 is high, set the reference frequency
    //if digital pin 9 is high, set the current frequency
    //if digital pin 12 is high, set tunning state = high
    refState = digitalRead(refInput);
    currentState = digitalRead(currentInput);
    tunningState = digitalRead(tunning);
    if(refState == HIGH && inRange == true){
      refFrequency = frequency;
    } else if(currentState == HIGH && inRange == true){
      currentFrequency = frequency;
    } //end of else if
   
    //error tracking
    //highest frequency = (2405)2479 hz  lowest frequency = (1517) 1628 hz
    errorFrequency = refFrequency - currentFrequency;
    P = errorFrequency;  //proportional term
   // I = Integral * 0;  //intergral term
   // D = (previousFrequency - currentFrequency) * 0;  //derivative term
   // previousFrequency = currentFrequency; 
    drive = P * (255.0/888.0); //scaleFactor = 255 * 888;

    //start tuning if tunning state = high
    if(tunningState == HIGH){
    //motor control
      if(errorFrequency > 30){      //pump liquid out
        //digitalWrite();  //pump in one direction
        digitalWrite(BacMotorControl, HIGH);
        analogWrite(ForMotorControl, 0);
      } else if (errorFrequency < -30){  //pump liquid in
        //digitalWrite();  //pump in another direction
        digitalWrite(BacMotorControl, LOW);
        pwmDrive = (int)abs(drive);
        if(pwmDrive < 80){ pwmDrive = pwmDrive + 80;}
        analogWrite(ForMotorControl, pwmDrive);
      } else {  //stop pumping
        analogWrite(ForMotorControl, 0);  //stop the motor
        digitalWrite(BacMotorControl, LOW);
      }
    } else {
      analogWrite(ForMotorControl, 0);  //stop the motor
      digitalWrite(BacMotorControl, LOW);
    }
   
    //debug
    Serial.print("frequency: ");
    Serial.print(frequency);
    Serial.print(" | ");
    Serial.print("reference frequency: ");
    Serial.print(refFrequency);
    Serial.print(" | ");
    Serial.print("Current frequency: ");
    Serial.print(currentFrequency);
    Serial.print(" | ");
    Serial.print("error frequency: ");
    Serial.println(errorFrequency);
  }//end of while
}//end of loop
Title: Re: Please help with arduino fft library
Post by: rexhex on Nov 10, 2015, 07:58 am
hongp, thank you brother.
Title: Re: Please help with arduino fft library
Post by: funfrancis on Mar 02, 2016, 03:46 am
Can I do the same to fft library in arduino? I tried it. but a lot of the outputs aren't zero. Not sure if it's correct. Please point out any possible error.
Here is the code I used to test fft library:
Code: [Select]
#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(9600); // use the serial port
}

void loop() {
  // put your main code here, to run repeatedly:
   int k = 0;
   int t = 0;
    for (int i = 0 ; i < 512 ; i += 2) { // save 256 samples
      k = 127*sin(2*3.14 * 100 * t );
      t++;
      fft_input[i] = 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
    for(int i = 0; i < 128; i++){
          Serial.println(fft_log_out[i]);
    }
    delay(1000);
}




I used your codes based on fft library but where is it mentioned that the input is from A0.

I tried them with my hydrophone, pre-amp setup and I get the same answer:
Code: [Select]

32 43 39 43 35 39 39 39 30 30 30 35 59 82 58 35 19 19 24 27 27 27 30 19 27 24 30 27 24 24 27 27
32 43 39 43 35 39 39 39 30 30 30 35 59 82 58 35 19 19 24 27 27 27 30 19 27 24 30 27 24 24 27 27
32 43 39 43 35 39 39 39 30 30 30 35 59 82 58 35 19 19 24 27 27 27 30 19 27 24 30 27 24 24 27 27

where am I going wrong


Title: Re: Please help with arduino fft library
Post by: rexhex on Mar 02, 2016, 07:18 am
in setup ( ADMUX = 0x40; // use adc0 ) this is using assembly language, a very basic level code. I took a class on it and its not easy or fun.
https://en.wikipedia.org/wiki/Assembly_language

https://en.wikipedia.org/wiki/ADC

whats a hydrophone?
Title: Re: Please help with arduino fft library
Post by: funfrancis on Mar 02, 2016, 01:36 pm
in setup ( ADMUX = 0x40; // use adc0 ) this is using assembly language, a very basic level code. I took a class on it and its not easy or fun.
https://en.wikipedia.org/wiki/Assembly_language

https://en.wikipedia.org/wiki/ADC

whats a hydrophone?
Hydrophone is an underwater mic
Title: Re: Please help with arduino fft library
Post by: AWOL on Mar 02, 2016, 01:54 pm
in setup ( ADMUX = 0x40; // use adc0 ) this is using assembly language, a very basic level code. I took a class on it and its not easy or fun.
https://en.wikipedia.org/wiki/Assembly_language

https://en.wikipedia.org/wiki/ADC

whats a hydrophone?
https://en.wikipedia.org/wiki/Hydrophone
Title: Re: Please help with arduino fft library
Post by: rexhex on Mar 03, 2016, 03:33 am
AWOL lol
Title: Re: Please help with arduino fft library
Post by: funfrancis on Mar 05, 2016, 12:17 am
Hi

I managed to get a sine curve using the codes.

Code: [Select]
void setup() {
 Serial.begin(9600);
}

void loop() {
  int a[250];  //250 refers sample number
  for (int i=0; i<250; i++) {
  a[i] = analogRead(0);
  int k = 250*sin(2*3.14*0.006*i);
  Serial.println(k);
  }
Serial.println();
}


Now, if the sine curve varies with output from A0, I will obtain a FFT curve.
How do i accomplish this ?