We are making an automatic guitar tuner that uses ArduinoFFT to process data from a microphone. The lowest string on our guitar is at 80 Hz, but our FFT and Oscilloscope are detecting the major frequency as the 160 Hz overtone. Using the FFT to output all frequency bins, we do find that 80 Hz signal is significant, just not the major peak. So we do not think it is a microphone or sampling frequency/period issue. Measuring at 1024 Hz for 64 data points should give us a frequency range from 16-512 Hz.
Our idea to this solution is that if there is a major signal at half the frequency, the code will divide the peak frequency by two.
Ex: Detects 160 Hz at magnitude of say, 500. Is there 80 Hz signal of magnitude at least (500/2) = 250? Yes. Frequency is 80 Hz.
Ex: Detects 250 Hz at magnitude of 600. Is there 125 Hz signal of magnitude at least (600/2) = 300? No. Frequency is 250 Hz.
This code reads the analog input from the microphone. Then Fourier transforms it. The peak frequency is given by x, and magnitude of this peak is given by v. We want to find the magnitude (v) of half our peak frequency (x/2). Then we would be able to compare the two magnitudes. Any help is appreciated. Please ask questions if I have left something out. Thanks.
That is a common characteristic of musical instruments. The resonant chambers, tubes, etc. reinforce higher harmonics of the fundamental. On stringed instruments, the string almost always vibrates at several harmonic frequencies at once, and not all are related by a factor of two to the fundamental frequency.
The code should report several peaks, along with their amplitudes, then use your best judgement.
I guess our issue is the syntax for the FFT to output us the other peaks. Either that, or ask the code to give us a magnitude of a particular frequency.
This part about harmonics has been understood. Using the neck pickup, we are consistently able to measure the 2nd harmonic on the low 3 strings (E A D). The 3rd string (G) will sometimes show the 2nd harmonic over the fundamental frequency. The high 2 strings (B e) always show us the fundamental frequency.
I'm NOT an FFT expert, but from what I've read most people trying to build tuners fail. And "the rumor is", something called autocorrelation works better than FFT.
Somehow, digital-electronic guitar tuners are available cheaply and I don't know how they do it.
It should be 82.41Hz. (I'm not sure how close you have to be.)
But of course, twice the frequency is the same note one octave up so it's still in-tune and MAYBE you can work with that. It seems unlikely that you'd actually be an octave off. (i.e. Any 'E' reading is probably good for that string).
The oscilloscope should be more accurate.
You'll know this better than me since you've been looking at a 'scope, but I saw a video of a guitar being played into a 'scope once, and after the attack (sometime during the sustain or decay) it started looking more like a pure sine wave.
FFT "filters" the audio into frequency "bins". The bins are linear (they all have the same frequency-width). So if they are 10Hz apart you could be about 10Hz off at 80Hz, which would be terrible. And also you could be 10Hz off at 1kHz which is probably OK... Musically, or to your brain, FFT has less resolution at lower frequencies.
I found this - IF I've done the math correctly, your numbers give you about 15Hz resolution (not enough).
I just noticed that you are using a sample frequency of 1024 Hz. That is very low, and any signal with frequency greater than 512 Hz in the input will cause aliasing, which can make the result of the FFT uninterpretable.
Look up "sampling theorem" and "Nyquist limit" to learn more. You need a good low pass filter between the microphone or pickup and the Arduino input, or increase the sample frequency by a factor of 10 or more.
There is a discussion and working code for fundamental frequency measurement using autocorrelation and peak interpolation at This link. It should provide sub-1-Hertz resolution for guitar running on an Arduino Uno.
It seems the autocorrelation is the consensus for what has the best chance of working. Since we only have 2 more weeks to finish our project (one of those weeks will be fine tuning and robustness), we will be using the 2nd harmonic by playing a harmonic on the 12th fret of each string to tune. This is a little better than playing a pressed 12th fret so that we can avoid intonation issues on a cheap guitar. By changing our sample frequency to 4096, we should be able to read a 660 Hz frequency no problem.
We already have the automatic turning of the pegs working, so our project seems to have few roadblocks ahead. Playing the harmonic will just be a caveat to our tuner. I'll post a video here in about 3 weeks when it's all done.
See if this gets a different result or simply runs way faster;
samplingPeriod = 1000000 / samplingFrequency;
requires an unsigned long division with an unsigned int promoted to unsigned long and the result stuffed into an unsigned int.
requires a conversion to float promoted 6 places and rounded before being stuffed into an unsigned int.
Ouch slow but at least 32 bit floats are good to 6 places in all cases.
If you want you can make a table or tables of values per tone in flash memory (large storage for set text and pre-calculated values) and use those, calibrate/tweak in development. It takes 3 cycles to fetch a byte from flash, 6 for an unsigned int. Compared to UL division, the name flash becomes redundant!