FFT Library

Hello!

For a school project, we are looking for an Arduino FFT library able to give the fundamental frequency of a single music notes (no chord).

I tried with this fix_fft . The problem is that it doesn't give a constant specific result, for example a constant frequency of 82.41 Hz (which corresponds to a E1, the low string of a guitar) the library returned a fundamental which varies between the 1, 2 and 3 place in the array (data[]).

I also found a library, which seems more official. The problem is that I didn't understand how it's work.

If you have a library or a means, using the two mentioned ones above, to obtain a single output value, it would help us a lot.

Thank you for your help and sorry for the bad english.

Unfortunately there is no "single output value". There is simply how accurate your microphone is picking up the frequency and how fast your arduino is sampling it.

I used that 2nd library you found (except I used the FFT version, which is pretty much the same)
The way it works is this. If you sample at 10,000 hz, then you can map frequencies 0-5,000 hz. Depending on your FFT_N size, you can get more and more accurate readings. Example: If you sample at 10Khz, you can map 0-5Khz, if your FFT_N size is 256, then the first 128 (maybe 127) bins contain useful information. This means that you have 128 bins to represent 5000hz. Thus you can calculte that each bin represents (5000 / 128) = 39hz.

So the problem with your 82.41hz is that it is so low that it is hard to pin down which bin it belongs to.

If you really needed to detect 1 specific frequency, then you may consider using an online calculator to calculate capacitor values for a low-pass and a high-pass filter. These filters will block out higher/lower frequencies.

Please read this thread for more information, I have some good code in 2 posts, so read all of it
http://forum.arduino.cc/index.php?topic=292834.msg2046136#msg2046136

Does your assignment require you to use the Fourier transform to determine the frequency, or can you use other techniques?

What's the sound source? Is it a sine input, or the signal from a musical instrument?

The method I proposed was using the FFT, however there are other techniques to detecting frequencies, each with their own pros and cons. My program used a standard electret microphone and an op-amp and performed the FFT on each 128 samples, but yes, it was basically a sine wave, it was sound.

Asking the original poster:

Do you have to use the Fourier transform to estimate frequency, or do you have some latitude in selecting your method? I'm concerned about Fourier, because I've never seen a post where anyone claimed that it worked well as a method frequency estimation. I've seen a lot that echoed your concerns - it gave inconsistent results. Another method - maybe autocorrelation - might be better in your application.

You mention getting inconsistent results for an input frequency of 82.4 Hz, and you mention a guitar string. That makes me wonder what the input source will be. Is it a pure sine input, like from a signal generator, or is the source a musical instrument, or a recording of one? A sine signal will be easier to analyze. A musical instrument will normally have considerable harmonic content, and low-order harmonics will often have a higher magnitude than the fundamental - sometimes a lot higher. If you use the Fourier transform, you may have to look for the lowest-frequency peak with significant content, rather than the highest peak. And, you'll likely have to empirically determine what "significant" means. I think that it may vary for different instruments. This notion is strictly conceptual, and speculative at that; I've never tried it.

Autocorrelation analysis can work better than Fourier methods to determine the fundamental frequency of a musical note, and was discussed in this thread. Reliable Frequency Measurment Using Autocorrelation - Science and Measurement - Arduino Forum

jremington:
Autocorrelation analysis can work better than Fourier methods ...

Indeed. I'd recommend reviewing the sketch at the referenced link carefully. It looks to me that it returns a value that's one larger than the advertised value. And, I'm dubious about the value of examining lag values larger than half the number of samples.

And, I'm dubious about the value of examining lag values larger than half the number of samples.

Agreed. In addition to abusing the procedure, the original sketch was not normalized correctly for the lag.

tmd3:
Does your assignment require you to use the Fourier transform to determine the frequency, or can you use other techniques?

What's the sound source? Is it a sine input, or the signal from a musical instrument?

No, we don't need to use FFT to determine the frequency, but it's the only one we have heard of, we can use other technique.
The sound source is a musical instrument, a guitar but for the moment we only simulate it with ISIS with a sine input.

Is there any other way to detect a note of music based on a sound?

Thanks for your suggestions, we're gonna study it !

Some other techniques are:

The Wikipedia article on pitch detection algorithms lists several ways to estimate pitch.

Is my memory accurate? Have we ever seen an Arduino implementation of the Fourier transform give usable results in estimating pitch?

I am currently using an FFT and while I know what frequencies I am using, they always show up in the same bins. Of course, I am using 4,000,000 points. 8^)

KeithRB: Do you use the fix_fft library ? And if so, how do you do to increase the number of points ?

And for the fix_fft library, what is the utility of the second array (for imaginary numbers) ?

No, I am using a PC and MatLab.

The arduino's memory won't allow for 4,000,000 points! Note the smiley in my post.

So it is not possible to increase the number of points with fix_fft library ? Can't it be possible to be more specific than that ?
And I wanted to know, I understood how the library worked but the second argument, the array of imaginary numbers, what it is ?

Thanks

You can have as many points as your RAM allows, which aren't many.

The imaginary array contains the imaginary part of your signal, which in your case is 0. In my case I was using a 1 bit ADC with quadrature output so I used the quadrature data from the ADC for the imaginary data.

The input imaginary array should be 0, while the output is important. To calculate the real bin value you must take sqrt(rere + imim). The imaginary represents the phase shift of the signal.

Okay, thank you all for your responses.
We found a guitar has its lowest note to 82.4Hz and most acute in 1318.52Hz.

Is it possible to adjust the Fourier analysis for more accurate values between 0Hz and 2000Hz ?
I understood what is the imaginary array. But, what is the third argument, "7"? I know this is 2**7=128 but I do not know what it is.

Thank you !

The 7 is to limit your results to that of a "char" which is only 8 bits, otherwise you would have an overflow and your results would be useless.

To accurately sample between 0-2000, your best bet is to sample at 4000 times a second and set your FFT_N to 256 (or the max), this would mean your accuracy would be (4000 / 2) / (256 / 2) = 15 hz per bin

To really accurately sample between 0-2000hz you will need a new chip altogether or get creative. As a new chip, you would be better off using an Arduino Due or if you want something cheaper an ATmega1284P because they have much more memory to work with. If this is not an option, then maybe try using some of the flash memory as your memory to get larger FFT_N sizes

The only library I used that actually worked was OpenMusicLabs FFT

PS991 thank you very much, it's perfect!

We changed our Arduino Uno to an Arduino MEGA2560 and adjusted the FFT_N to 256 bits.
This is much more accurate!

A new question:
for lines

val = analogRead(A0);
data[i] = val / 4 - 128;

What is the point of dividing val by 4 and subtract it 128 ?

Thank you all for your help

Please be sure to use code tags when posting code, because this

array[i] = 0; //this text is not italic

now becomes
array = 0; //this text IS italic, also notice the [ i ] is now missing

back on track

if (millis() > tt){
     if (i < 128){
       val = analogRead(pin_adc);
       data[i] = val / 4 - 128;
       im[i] = 0;
       i++;   
       
     }

the reason it is divided by 4 and subtracted by 128 is because the "data" is of type "char" which is an 8 bit variable (-128 to 127). So because analogRead returns 0-1023, dividing it by 4 gives you 0-255, subtracting it by 128 gives you -128-127.

You will notice that a (sine wave)/(audio wave) has positive and negative values, so this is why you see it centered around 0.