Issues Compiling Goertzel Sketch

Trying to use a Goertzel library for a sketch to detect two frequencies, 50 and 55Hz although I don’t know if it can resolve them.

The Goertzel library was obtained from:
https://github.com/jacobrosenthal/Goertzel

When I use the example detect.ino from this site, I get “nan” for “magnitude”.

The sketch from different example code is…

/*
  Released into the public domain.
*/
#include <Goertzel.h>

int sensorPin = 0;
int led = 13;

// ideally an integer of SAMPLING_FREQUENCY/N to center the bins around your content so if you're
// looking for 700hz, frequencies below and above it equally contribute. Read up on Kevin's article 
// for more info.
// Nyquist says the highest frequency we can target is SAMPLING_FREQUENCY/2 
const float TARGET_FREQUENCY = 700; 
const float TARGET_FREQUENCY2 = 425; 

// if you're trying to detect several different drum hits all within low frequency like
// ~100-200hz you'll need a small bin size like 25 or 50 to distinguish them.
// If however you're just trying to find ANY bass hit you might want something
// basically equal to frequency youre looking for like ~100
 
// If Im detecting a frequency much higher with no care about nearby tones, like 2000hz
// Ill set to a round divisor like 200 So 1900 to 2100 could trigger, but not less or more
// Max is 200 as we have limited ram in the Arduino, and sampling longer would make us less 
// responsive anyway
const int N = 100; 	

// This is what will trigger the led. Its INCREDIBLY squishy based on volume of your source, 
// frequency, etc. You'll just need to get in your environment and look at the serial console
// to start. Then pick something that triggers pleasantly to your eye.
const float THRESHOLD = 4000;	

// Again, the highest frequency we can target is SAMPLING_FREQUENCY/2. So Since Arduino is 
// relatively slow in terms of audio, we sample literally as fast as we can
// This is generally around ~8900hz for a 16mhz Arduino and 4400hz for an 8mhz Arduino.
// User nicola points out these rates are for stock arduino firmware and that on a board 
// by board basis you can juice the adc rates. For Arduino Uno you could move that rate up to 
// 22khz by adding somthing like this to your setup:
//  _SFR_BYTE(ADCSRA) |=  _BV(ADPS2); // Set ADPS2
//  _SFR_BYTE(ADCSRA) &= ~_BV(ADPS1); // Clear ADPS1
//  _SFR_BYTE(ADCSRA) &= ~_BV(ADPS0); // Clear ADPS0
const float SAMPLING_FREQUENCY = 8900; 

Goertzel goertzel = Goertzel(TARGET_FREQUENCY, N, SAMPLING_FREQUENCY);

void setup(){
  pinMode(led, OUTPUT);     
  Serial.begin(9600); 
}

void loop()
{
  goertzel.sample(sensorPin);

  goertzel.Goertzel(TARGET_FREQUENCY, N, SAMPLING_FREQUENCY);
  float magnitude = goertzel.detect();  //check them for target_freq
  goertzel.Goertzel(TARGET_FREQUENCY2, N, SAMPLING_FREQUENCY);
  float magnitude2 = goertzel.detect();  //check them for target_freq
  
  if(magnitude>THRESHOLD || magnitude2>THRESHOLD) //if you're getting false hits or no hits adjust this
    digitalWrite(led, HIGH); //if found, enable led
  else
    digitalWrite(led, LOW); //if not found, or lost, disable led

  static char buffer[256];  // make sure this is big enough!!!
  snprintf(buffer, sizeof(buffer), "Magnitude(%dHz) %d\n", (u16)TARGET_FREQUENCY,(u16)magnitude);
  Serial.print(buffer);
  snprintf(buffer, sizeof(buffer), "Magnitude(%dHz) %d\n", (u16)TARGET_FREQUENCY2,(u16)magnitude2);  
  Serial.print(buffer);
  delay(400);
}

When compiled (using the same Goertzel library) gives…

GoertzelMultiTone.ino: In function 'void loop()':
GoertzelMultiTone:54: error: invalid use of 'Goertzel::Goertzel'
GoertzelMultiTone:56: error: invalid use of 'Goertzel::Goertzel'

What does “invalid use of ‘Goertzel::Goertzel’” mean?
Also, is there another source of a Goertzel library and code examples? Am I naive in expecting that code examples should just work?

It works for me.
Did you change the name of the folder from Goertzel-master to just Goertzel before you put it in the libraries folder?
And have you restarted the IDE?

Did you change the name of the folder from Goertzel-master to just Goertzel before you put it in the libraries folder?

Well, no. There were only the .h and .cpp at that site, so I put them in the "libraries" folder in a "Goertzel" folder. Didn't see a "Goertzel-master". Did I use the wrong library? The other functions are found though, and no errors about a missing library.

And have you restarted the IDE?

Yes.

Actually, from what I've been reading, a well-resolved Goertzel at low frequencies requires up to 100 analogReads at 100us each or 10ms. Looking to keep response time below 2-3ms. Is a DFT or IIR filter going to be faster than a Goertzel or should I start thinking about using analog of switched-capacitor filters instead of digital?

no. There were only the .h and .cpp at that site

I downloaded the files as zip and when I unzipped them they were in a folder with a -Master postfix. I removed it and popped it in the libraries folder. It then compiles. Sounds like you didn't do exactly this.

Looking to keep response time below 2-3ms.

That is faster than the tones you are trying to pick out, so there is no way you can do that in hardware or software. You need at least one cycle before you can say what it is.

I downloaded the files as zip and when I unzipped them they were in a folder with a -Master postfix. I removed it and popped it in the libraries folder. It then compiles. Sounds like you didn't do exactly this.

I had not done this, but now found the "Download" button and downloaded and re-named the library. Still the same errors...

GoertzelMultiTone.ino: In function 'void loop()':
GoertzelMultiTone:55: error: invalid use of 'Goertzel::Goertzel'
GoertzelMultiTone:57: error: invalid use of 'Goertzel::Goertzel'

I just don't understand what the error means and what's invalid about...

 goertzel.Goertzel(TARGET_FREQUENCY, N, SAMPLING_FREQUENCY);
and
goertzel.Goertzel(TARGET_FREQUENCY2, N, SAMPLING_FREQUENCY);

That is faster than the tones you are trying to pick out, so there is no way you can do that in hardware or software. You need at least one cycle before you can say what it is.

True... for 50Hz, t = 1/f = 1/50 = .02 or a period of 20msec. Maybe can't do faster than that digitally, but using a 50 Hz filter followed by a peak detector appears to be detecting the rise in level (first 90 degrees of the waveform) in less than 20msec.

just don't understand what the error means and what's invalid about...

These sorts of errors mean that you haven't installed the library correctly.

The example supplied with the library compiles fine if the library is installed correctly so try loading and compiling the ‘detect’ example to confirm the library is where it should be.

The example you posted in your initial post does not compile due to several errors in the code so try and correct them to fix your problem. Instead of trying to alter the frequency parameters it might be better to set up 2x instances of the class and switch between them.

You aren’t using the library correctly. You need to instantiate another Goertzel object for the second frequency. I haven’t tested this code but it is closer to what you should be doing.

/*
  Released into the public domain.
*/
#include <Goertzel.h>

int sensorPin = 0;
int led = 13;

// ideally an integer of SAMPLING_FREQUENCY/N to center the bins around your content so if you're
// looking for 700hz, frequencies below and above it equally contribute. Read up on Kevin's article
// for more info.
// Nyquist says the highest frequency we can target is SAMPLING_FREQUENCY/2
const float TARGET_FREQUENCY = 700;
const float TARGET_FREQUENCY2 = 425;

// if you're trying to detect several different drum hits all within low frequency like
// ~100-200hz you'll need a small bin size like 25 or 50 to distinguish them.
// If however you're just trying to find ANY bass hit you might want something
// basically equal to frequency youre looking for like ~100
 
// If Im detecting a frequency much higher with no care about nearby tones, like 2000hz
// Ill set to a round divisor like 200 So 1900 to 2100 could trigger, but not less or more
// Max is 200 as we have limited ram in the Arduino, and sampling longer would make us less
// responsive anyway
const int N = 100; 

// This is what will trigger the led. Its INCREDIBLY squishy based on volume of your source,
// frequency, etc. You'll just need to get in your environment and look at the serial console
// to start. Then pick something that triggers pleasantly to your eye.
const float THRESHOLD = 4000; 

// Again, the highest frequency we can target is SAMPLING_FREQUENCY/2. So Since Arduino is
// relatively slow in terms of audio, we sample literally as fast as we can
// This is generally around ~8900hz for a 16mhz Arduino and 4400hz for an 8mhz Arduino.
// User nicola points out these rates are for stock arduino firmware and that on a board
// by board basis you can juice the adc rates. For Arduino Uno you could move that rate up to
// 22khz by adding somthing like this to your setup:
//  _SFR_BYTE(ADCSRA) |=  _BV(ADPS2); // Set ADPS2
//  _SFR_BYTE(ADCSRA) &= ~_BV(ADPS1); // Clear ADPS1
//  _SFR_BYTE(ADCSRA) &= ~_BV(ADPS0); // Clear ADPS0
const float SAMPLING_FREQUENCY = 8900;

Goertzel goertzel = Goertzel(TARGET_FREQUENCY, N, SAMPLING_FREQUENCY);
Goertzel goertzel2 = Goertzel(TARGET_FREQUENCY2, N, SAMPLING_FREQUENCY);

void setup(){
  pinMode(led, OUTPUT);     
  Serial.begin(9600);
}

void loop()
{
  goertzel.sample(sensorPin);
  float magnitude = goertzel.detect();  //check them for target_frequency
  goertzel2.sample(sensorPin);
  float magnitude2 = goertzel.detect();  //check them for target_frequency2
 
  if(magnitude>THRESHOLD || magnitude2>THRESHOLD) //if you're getting false hits or no hits adjust this
    digitalWrite(led, HIGH); //if found, enable led
  else
    digitalWrite(led, LOW); //if not found, or lost, disable led

  static char buffer[256];  // make sure this is big enough!!!
  snprintf(buffer, sizeof(buffer), "Magnitude(%dHz) %d\n", (u16)TARGET_FREQUENCY,(u16)magnitude);
  Serial.print(buffer);
  snprintf(buffer, sizeof(buffer), "Magnitude(%dHz) %d\n", (u16)TARGET_FREQUENCY2,(u16)magnitude2); 
  Serial.print(buffer);
  delay(400);
}

Note that the way that the Goertzel library is written it can only do one tone detection at a time. The first call to sample will read N samples and then do a detection for the first frequency. Then it will read another N samples and do the detection of the second frequency.

Pete

You need to instantiate another Goertzel object for the second frequency.

Thanks, Pete... the two instantiations make sense.

Note that the way that the Goertzel library is written it can only do one tone detection at a time.

Yes, not the most efficient. Assume there's a way to read N samples once then do multiple detections on those samples. Worth considering if I need to detect a bunch of frequencies. Guessing that the DTMF examples read the N samples only once.

Wonder where multiple single-frequency detections take as long as a single FHT/FFT?

So the code works…

/*
  Released into the public domain.
*/
#include <Goertzel.h>

int sensorPin = 0;
int led = 13;

// ideally an integer of SAMPLING_FREQUENCY/N to center the bins around your content so if you're
// looking for 700hz, frequencies below and above it equally contribute. Read up on Kevin's article
// for more info.
// Nyquist says the highest frequency we can target is SAMPLING_FREQUENCY/2
const float TARGET_FREQUENCY = 700;
const float TARGET_FREQUENCY2 = 425;

// if you're trying to detect several different drum hits all within low frequency like
// ~100-200hz you'll need a small bin size like 25 or 50 to distinguish them.
// If however you're just trying to find ANY bass hit you might want something
// basically equal to frequency youre looking for like ~100
 
// If Im detecting a frequency much higher with no care about nearby tones, like 2000hz
// Ill set to a round divisor like 200 So 1900 to 2100 could trigger, but not less or more
// Max is 200 as we have limited ram in the Arduino, and sampling longer would make us less
// responsive anyway
const int N = 100;

// This is what will trigger the led. Its INCREDIBLY squishy based on volume of your source,
// frequency, etc. You'll just need to get in your environment and look at the serial console
// to start. Then pick something that triggers pleasantly to your eye.
const float THRESHOLD = 4000;

// Again, the highest frequency we can target is SAMPLING_FREQUENCY/2. So Since Arduino is
// relatively slow in terms of audio, we sample literally as fast as we can
// This is generally around ~8900hz for a 16mhz Arduino and 4400hz for an 8mhz Arduino.
// User nicola points out these rates are for stock arduino firmware and that on a board
// by board basis you can juice the adc rates. For Arduino Uno you could move that rate up to
// 22khz by adding somthing like this to your setup:
//  _SFR_BYTE(ADCSRA) |=  _BV(ADPS2); // Set ADPS2
//  _SFR_BYTE(ADCSRA) &= ~_BV(ADPS1); // Clear ADPS1
//  _SFR_BYTE(ADCSRA) &= ~_BV(ADPS0); // Clear ADPS0
const float SAMPLING_FREQUENCY = 8900;

Goertzel goertzel = Goertzel(TARGET_FREQUENCY, N, SAMPLING_FREQUENCY);
Goertzel goertzel2 = Goertzel(TARGET_FREQUENCY2, N, SAMPLING_FREQUENCY);

void setup(){
  pinMode(led, OUTPUT);    
  Serial.begin(38400);
}

void loop()
{
  goertzel.sample(sensorPin);
  float magnitude = goertzel.detect();  //check them for target_frequency
  goertzel2.sample(sensorPin);
  float magnitude2 = goertzel.detect();  //check them for target_frequency2
 
  if(magnitude>THRESHOLD || magnitude2>THRESHOLD) //if you're getting false hits or no hits adjust this
    digitalWrite(led, HIGH); //if found, enable led
  else
    digitalWrite(led, LOW); //if not found, or lost, disable led

  static char buffer[256];  // make sure this is big enough!!!
  snprintf(buffer, sizeof(buffer), "Magnitude(%dHz) %d\n", (u16)TARGET_FREQUENCY,(u16)magnitude);
  Serial.print(buffer);
  snprintf(buffer, sizeof(buffer), "Magnitude(%dHz) %d\n", (u16)TARGET_FREQUENCY2,(u16)magnitude2);
  Serial.print(buffer);
  
  Serial.println();
  delay(400);
}

but with unexpected results…
With 700Hz and 0Hz, the levels (5490 and 450) do change, but both output levels are the same even though TARGET_FREQUENCY = 700 and TARGET_FREQUENCY2 = 425. With 425Hz in, both levels are ~450-650.

Magnitude(700Hz) 5494
Magnitude(425Hz) 5494

Magnitude(700Hz) 5487
Magnitude(425Hz) 5487

Magnitude(700Hz) 5476
Magnitude(425Hz) 5476

Magnitude(700Hz) 708
Magnitude(425Hz) 708

Magnitude(700Hz) 401
Magnitude(425Hz) 401

Magnitude(700Hz) 454
Magnitude(425Hz) 454

Something’s not right but I don’t see what it is.
Also, why is SAMPLING_FREQUENCY = 8900 when I thought the default Sampling Rate was 9600Hz?

The sampling rate has nothing to do with the Serial baud rate.

Pete

The sampling rate has nothing to do with the Serial baud rate.

Yes... "const float SAMPLING_FREQUENCY = 8900;" and "Serial.begin(38400);" are different things. But shouldn't SAMPLING_FREQUENCY match the default sample rate of the Arduino which I thought was 9600?

But shouldn't SAMPLING_FREQUENCY match the default sample rate of the Arduino which I thought was 9600?

While the Arduino is capable of an average of 9600 samples a second, but this is not guaranteed. I suppose it has been reduced so that every sample can be at a constant interval.

the default sample rate of the Arduino

What default sampling rate?

If you want to sample an analog input, there is no default rate.

The sampling rate of 8900Hz was determined by measuring, or approximating, how often the sampling loop in the Goertzel library can obtain a new sample.

Pete

If you want to sample an analog input, there is no default rate.

Well there is if you consider that the analogRead function returns in just over 100uS you can consider 9600 samples per second as "default".
Yes it can go faster if you twiddle with the ADC clock or put it in free running mode.

Yes it can go faster if you twiddle with the ADC clock or put it in free running mode.

You can change the ADC clock by changing the ADC prescaler, ADPS2,1,0, correct? If default prescaler is 128 and the prescaler is set to 16 by ADPS2,1,0, then the sampling rate increases by 128/16 or 8 times?

In some FHT code, assuming the default rate was 9600Hz and changing the prescaler from 128 to 64 and 32 for rates of 19.2kHz and 38.4kHz respectively, gave exactly the expected bin spacing based on a defined N point FHT. Bin spacing was determined by generating tones at the expected bins and observing a change in value at that bin. If the default "prescaler = 128" sample rate were really 8900, then wouldn't the bin spacing be something different?

These are the bin widths I'm seeing given the expected sample rate (SR), the resulting bandwidth (BW) of SR/2, and a #Bins FHT:

SR(Hz) BW #Bins Bin Width(Hz


9,600 4,800 32 150
19,200 9,600 32 300
38,400 19,200 32 600

9,600 4,800 64 75
19,200 9,600 64 150
38,400 19,200 64 300

9,600 4,800 128 37.5
19,200 9,600 128 75
38,400 19,200 128 150

These are the bin widths I'm seeing given the expected sample rate (SR), the resulting bandwidth (BW) of SR/2, and a #Bins FHT:

Yes if you are seeing those bin widths that is indeed correct.