Go Down

Topic: Goertzel for reliable DTMF Decoding (Read 5 times) previous topic - next topic

SexualMoose

Yup that's my problem too. Well, if anyone else has any ideas or even another library, let me know. Thanks for giving it a try pete !

SexualMoose

Alright so I made a few changes and made a little progress. It provides predictable results and is accurate to some degree. I found a couple errors in his code and then started making equation adjustments along the way. Since I'm rather poor at math I used this document http://www.ti.com/lit/an/spra066/spra066.pdf to help a tad and just tweaked things to as close of a reading as possible.

Here is the .ino
Code: [Select]
/*
  Blinks a light on a 16mhz Arduino when it detects an A4 (440 hz), tone
the tuning fork pitch and something easily generated by the Tone library
  or a google search.

  The Goertzel algorithm is long standing so see
  http://en.wikipedia.org/wiki/Goertzel_algorithm for a full description.
  It is often used in DTMF tone detection as an alternative to the Fast
  Fourier Transform because it is quick with low overheard because it
  is only searching for a single frequency rather than showing the
  occurrence of all frequencies.
 
  This work is entirely based on the Kevin Banks code found at
  http://www.eetimes.com/design/embedded/4024443/The-Goertzel-Algorithm
  so full credit to him for his generic implementation and breakdown. I've
  simply massaged it into an Arduino library. I recommend reading his article
  for a full description of whats going on behind the scenes.

  Created by Jacob Rosenthal, June 20, 2012.
  Released into the public domain.
*/


/*
Crudely Revised By: SexualMoose
Frequencies generated by iPhone/iPod at full volume
Frequencies are found in a 80Hz range proportional to the target.
When looking for 697 Frequency recognition starts ~70Hz below target and stop about ~10Hz above
this range shifts down proportional to the increase in the target frequency
i.e. when looking for 1633 its starts ~1480Hz and ends ~1560Hz
*/
#include <Goertzel.h>

int sensorPin = 0;
int led = 13;

float target_freq=1633.0; //must be an integer of 9000/N and be less than
                         //sampling_frequency/2 (thanks to Nyquist)
float n=115.0;
float sampling_freq=9000;

Goertzel goertzel = Goertzel(target_freq,n,sampling_freq);

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

void loop()
{
  delay(10);
  sensorPin = analogRead(0);
  Serial.println(sensorPin);
  goertzel.sample(sensorPin); //Will take n samples
 
  float magnitude = goertzel.detect();  //check them for target_freq
 
  if(magnitude>1000) //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
   
  Serial.println(magnitude);
}


Here is the Goertzel.cpp
Code: [Select]
/*
  The Goertzel algorithm is long standing so see
  http://en.wikipedia.org/wiki/Goertzel_algorithm for a full description.
  It is often used in DTMF tone detection as an alternative to the Fast
  Fourier Transform because it is quick with low overheard because it
  is only searching for a single frequency rather than showing the
  occurrence of all frequencies.

  This work is entirely based on the Kevin Banks code found at
  http://www.eetimes.com/design/embedded/4024443/The-Goertzel-Algorithm
  so full credit to him for his generic implementation and breakdown. I've
  simply massaged it into an Arduino library. I recommend reading his article
  for a full description of whats going on behind the scenes.

  Created by Jacob Rosenthal, June 20, 2012.
  Released into the public domain.
*/
// include core Wiring API
#include "Arduino.h"

// include this library's description file
#include "Goertzel.h"

float SAMPLING_RATE;
float TARGET;
float N;
float coeff;
float Q1;
float Q2;
float sine;
float cosine;

byte testData[160];

Goertzel::Goertzel(float TARGET_FREQUENCY, float BLOCK)
{
#if F_CPU == 16000000L
Goertzel(TARGET_FREQUENCY, BLOCK, 9000.0);
#else
Goertzel(TARGET_FREQUENCY, BLOCK, 9000.0);
#endif
}

Goertzel::Goertzel(float TARGET_FREQUENCY,float BLOCK,float SAMPLING_FREQ)
{

  SAMPLING_RATE=SAMPLING_FREQ; //on 16mhz, ~8928.57142857143, on 8mhz ~44444
  TARGET=TARGET_FREQUENCY; //must be integer of SAMPLING_RATE/N
  N=BLOCK; //Block size
  int k;
  float omega;

  k = (int) (N * (TARGET_FREQUENCY / SAMPLING_RATE) + 0.93);
  omega = (2.0 * PI * k) / N;
  sine = sin(omega);
  cosine = cos(omega);
  coeff = 2.0 * cosine;

  ResetGoertzel();
}


/* Call this routine before every "block" (size=N) of samples. */
void Goertzel::ResetGoertzel(void)
{
  Q2 = 0;
  Q1 = 0;
}


/* Call this routine for every sample. */
void Goertzel::ProcessSample(byte sample)
{
  float Q0;
  Q0 = coeff * Q1 - Q2 + (float) sample;
  Q2 = Q1;
  Q1 = Q0;
}


/* Basic Goertzel */
/* Call this routine after every block to get the complex result. */
void Goertzel::GetRealImag(float *realPart, float *imagPart)
{
  *realPart = (Q1 - Q2 * cosine);
  *imagPart = (Q2 * sine);
}


/* Sample some test data. */
void Goertzel::sample(int sensorPin)
{
  for (int index = 0; index < N; index++)
  {
    testData[index] = (byte) analogRead(0);
  }
}


float Goertzel::detect()
{

  int index;

  float magnitudeSquared;
  float magnitude;
  float real;
  float imag;

  /* Process the samples. */
  for (index = 0; index < N; index++)
  {
    ProcessSample(testData[index]);
  }

  /* Do the "standard Goertzel" processing. */
  GetRealImag(&real, &imag);

  magnitudeSquared = real*real + imag*imag;
  magnitude = (sqrt(magnitudeSquared)/2);

  ResetGoertzel();
  return magnitude;
}



And here is a link to test out the modified library:
https://www.dropbox.com/sh/9lmbik1v6k1tgt3/Wl2xlBTypU


Here's what I'd like to do:
I need help turning the equations in this document into arduino  code http://www.ti.com/lit/an/spra066/spra066.pdf. If anyone could help me out with that I'd super appreciate it. It doesn't have to be much, just a frame work so I know where to put the variables. Thanks for your help!

pito

TMS320 is a special DSP processor, you can hardly apply that equations to atmega, though..

SexualMoose

#13
Sep 03, 2012, 12:08 am Last Edit: Sep 03, 2012, 12:15 am by SexualMoose Reason: 1
While yes, the formula was modified for that chip, the formula should still be sound if you change the sample rate to 9000 and "N" to 115

SexualMoose

Literally all I need is the formula(s) in order and the inputs labeled so I know where to put them. I am able to modify parts but understanding the whole thing is beyond me. I do know that the basic modified equations still apply if you change N to 115 and the sample rate to 9000

Go Up