AudioFrequencyMeter.h only returns integers

Hi,

I am trying to use AudioFrequencyMeter.h and it kinda works, but it will only return integers. The serial monitor will show decimals, but they’re always .00

float frequency = meter.getFrequency(); which is in the sample file, suggests to me that it should return floats.
I also checked the file AudioFrequencyMeter.cpp of GitHub and the declaration of the function also suggests to me that is should return floats.
float AudioFrequencyMeter::getFrequency()

Anyone has an idea what is wrong here?

This is my code, which is kinda like the example, but tkane out the stuff I don’t need. I only need the bare numbers.

#include <AudioFrequencyMeter.h>

AudioFrequencyMeter meter;

void setup() {

  Serial.begin(115200);
  meter.setBandwidth(20.00, 5000);    // Ignore frequency out of this range
  meter.begin(A1, 45000);             // Intialize A1 at sample rate of 45kHz

}

void loop() {

  delay(250);
  float frequency = meter.getFrequency();

  Serial.println(frequency);

}

This behavior appears to be a "feature" (aka "bug") of the AudioFrequencyMeter library.

On line 126 of the library source code the returned frequency is calculated with two integers resulting in an integer and then converted to float:

frequency = (float)(sampleRate / period);

To get a non-zero decimal part, one or both of "sampleRate" and "period" should be converted to float prior to division.

Even with that, because both these operands are integer, the result will take on discrete float values. A way to improve on this behavior by interpolating the correlation peak is discussed here (post #24), but that's not in the AudioFrequencymeter library either.

So at least I learned something. Although I spied into libray source files at some times, I never realized that I could actually modify them.

So I changed:

frequency = (float)(sampleRate / period);

to:

frequency = (float)sampleRate / (float)period;

And now I have decimals.

I do not grasp that "autocorrelation and peak detection" stuff yet. But I will read through and study it a bit.

Thanks a lot.

I know nothing about AudioFrequencyMeter.h but I have quite a bit of audio experience and you're probably not going to get integer (1Hz) accuracy anyway.

DVDdoug:
I know nothing about AudioFrequencyMeter.h but I have quite a bit of audio experience and you're probably not going to get integer (1Hz) accuracy anyway.

I believe the code in post #42 of this this forum discussion link is capable of sub 1 Hz accuracy with an accurate master oscillator. That code runs on an Arduino Uno (or equivalent) whereas the AudioFrequencyMeter library is for the Arduino Zero.

I don't have a Zero on which to test the AudioFrequencyMeter library, but it is derived from the same original code as the linked discussion thread. As such it has a couple issues.

  • It doesn't interpolate between correlation peaks as discussed in the linked discussion thread. This is mitigated slightly by the faster analogRead() of the Zero, but is still the biggest error term.
  • It uses an timer interrupt driven ADC collection scheme rather than a free running ADC. This design choice has the benefit of allowing more or less arbitrary sample rates, but induces sample jitter. In my experiments with the Uno this ADC sample jitter resulted in a few Hertz jitter in the frequency measurement.
  • It has the integer truncation issue discovered by the original poster in this thread, but that's certainly overwhelmed by issue 1 and perhaps issue 2.

For what it's worth, I posted a problem report on the GitHub for issue 3 including a link to this thread, so perhaps they'll look into addressing issue 1 as an enhancement. When I find the time, I'd like to port their library to the Uno and can offer tested code in a library format, but the prototype code in post #42 of the discussion thread shows the algorithm change.

DVDdoug:
I know nothing about AudioFrequencyMeter.h but I have quite a bit of audio experience and you're probably not going to get integer (1Hz) accuracy anyway.

That would be a bummer.. :wink:
But thanks for your feedback.

MrMark:
I believe the code in post #42 of this this forum discussion link is capable of sub 1 Hz accuracy with an accurate master oscillator. That code runs on an Arduino Uno (or equivalent) whereas the AudioFrequencyMeter library is for the Arduino Zero.

I don't have a Zero on which to test the AudioFrequencyMeter library, but it is derived from the same original code as the linked discussion thread. As such it has a couple issues.

  • It doesn't interpolate between correlation peaks as discussed in the linked discussion thread. This is mitigated slightly by the faster analogRead() of the Zero, but is still the biggest error term.
  • It uses an timer interrupt driven ADC collection scheme rather than a free running ADC. This design choice has the benefit of allowing more or less arbitrary sample rates, but induces sample jitter. In my experiments with the Uno this ADC sample jitter resulted in a few Hertz jitter in the frequency measurement.
  • It has the integer truncation issue discovered by the original poster in this thread, but that's certainly overwhelmed by issue 1 and perhaps issue 2.

On closer inspection of the AudioFrequencyMeter library, it looks like it uses a form of "zero crossing" frequency detection, rather than autocorrelation as I'd thought when I wrote post #4. Zero crossing will work with simple waveforms (sine, square, triangle, etc), but it won't be robust against harmonic waveforms with random relative phases (e.g. stringed musical instruments).

The autocorrelation code traces back to this thread and was apparently originally written by "akellyirl" when the zero crossing approach wasn't up to the task.