I'm trying to make a simple frequency meter using an Arduino Zero.
The application is to read a frequency from an audio input (an oscillator for a modular synth). The code below gets pretty close, but ends up being off by a couple of Hz, enough to not be able to tune an instrument.
Thanks for the quick reply! I gave that library a shot, but the results I got from it were surprisingly inaccurate. I played with config but still didn't have any luck.
m_forum:
The application is to read a frequency from an audio input (an oscillator for a modular synth). The code below gets pretty close, but ends up being off by a couple of Hz, enough to not be able to tune an instrument.
The displayed frequency is also rather noisy. I'm testing it on my oscilloscope at the same time, so I know the issue isn't the input.
Is the frequency error biased in one direction or is it random about the correct value? If the latter you could try averaging some number of measurements or results to provide a smoothed output.
What is the oscillator waveform? pulsein() should work well with square wave input. If it's a sine wave or something with similarly slow rise and fall times then threshold detection with pulsein() might not be as consistent as one might hope. If it's musical note with harmonic content then a pulsein() approach is almost certainly doomed.
The pulsein() function (on Atmega328 boards at least) uses "spin loop" timing so there is potential for it to get screwed up by compiler optimizations or version changes. I don't know how well it's been wrung out on the Zero, but I was surprised when I learned it didn't use hardware timers.
Finally, another poster and I worked through an autocorrelation-based approach to a tuner program that worked pretty well. I was still seeing bias errors, but I believe that was down to the frequency accuracy of the ceramic resonator on the Arduino Uno clone. I believe your Zero has a crystal which should be considerably more accurate.
m_forum:
I'm trying to make a simple frequency meter using an Arduino Zero.
....
The displayed frequency is also rather noisy. I'm testing it on my oscilloscope at the same time, so I know the issue isn't the input.
Any idea why this might be off?
Thanks!
Well you can immediate improve the rounding on that division to be actual round-to-nearest rather than truncation:
frequency = (1000000 + (totalTime>>1)) / totalTime;
// or:
frequency = int (round (1e6 / totalTime)) ;
Another way to improve it is to count the total time for 10 cycles, say, which will both be more accurate and reduce noise due to timing jitter in the system.
Does the Arduino Zero use a quartz crystal or a ceramic resonator for its clock? If the latter you can expect
errors of around 0.5% in any time or frequency measurement due to the crude clock source.
Is the frequency error biased in one direction or is it random about the correct value? If the latter you could try averaging some number of measurements or results to provide a smoothed output.
Unfortunately the error isn't bias, and smoothing (taking the running average) still doesn't result in a high enough accuracy to reliably tune.
Another way to improve it is to count the total time for 10 cycles, say, which will both be more accurate and reduce noise due to timing jitter in the system.
I also tried this for 10, 100, and 500 cycles, but unfortunately the error is still too high and too inconsistent
What is the oscillator waveform?
The waveform is a sinewave, but I would love this to work with sine, square and sawtooth.
If it's musical note with harmonic content then a pulsein() approach is almost certainly doomed.
Yeah it's looking more and more like pulsein() isn't going to be the way to go. A shame.
The waveform is a sinewave, but I would love this to work with sine, square and sawtooth.
Simple wave forms like this are easy to cope with. You just pass it through a voltage comparator before the input. In fact there is a comparator built into the Arduino Uno chip but it is little used here.
However, this only works on simple wave forms, anything like a real sound has the harmonics change over time and that will give you an inconsistent result.