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.
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.
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.
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.
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 !
YIN algorithm, described in a scholarly paper here - http://audition.ens.fr/adc/pdf/2002_JASA_YIN.pdf - and implemented in an Arduino-based guitar tuner, here - The Deambulatory Matrix: Digital Chromatic Guitar Tuner (2008). YIN is similar enough to autocorrelation to call it autocorrelation. A full implemtation of the algorithm may be beyond the Arduino's capabilities, but a partial implementation has yielded satisfactory results at least once.
A whole raft of zero-crossing based methods. Those often don't perform well for complex waveforms.
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^)
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 ?
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.
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
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.