Go Down

Topic: Issues Compiling Goertzel Sketch (Read 1 time) previous topic - next topic

rickso234

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...
Code: [Select]
/*
  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...
Code: [Select]

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?

 

Grumpy_Mike

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?

rickso234

Quote
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.
Quote
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?

Grumpy_Mike

Quote
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.

Quote
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.

rickso234

Quote
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...
Code: [Select]
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...
Code: [Select]
goertzel.Goertzel(TARGET_FREQUENCY, N, SAMPLING_FREQUENCY);
and
goertzel.Goertzel(TARGET_FREQUENCY2, N, SAMPLING_FREQUENCY);


Quote
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.

Grumpy_Mike

Quote
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.

Riva

#6
Aug 08, 2016, 10:54 am Last Edit: Aug 08, 2016, 10:54 am by Riva
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.
Don't PM me for help as I will ignore it.

el_supremo

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.
Code: [Select]
/*
  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
Don't send me technical questions via Private Message.

rickso234

Quote
You need to instantiate another Goertzel object for the second frequency.
Thanks, Pete... the two instantiations make sense.

Quote
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?

rickso234

So the code works...
Code: [Select]
/*
  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.
Code: [Select]
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?

el_supremo

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

Pete
Don't send me technical questions via Private Message.

rickso234

Quote
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?

Grumpy_Mike

#12
Aug 16, 2016, 01:47 pm Last Edit: Aug 16, 2016, 01:48 pm by Grumpy_Mike
Quote
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.

el_supremo

#13
Aug 16, 2016, 05:44 pm Last Edit: Aug 16, 2016, 05:47 pm by el_supremo
Quote
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
Don't send me technical questions via Private Message.

Grumpy_Mike

Quote
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.

Go Up