2

So I am opening a .raw file of a DTMF tone I generated in audacity. I grabbed a canned goertzel algorithm similar to the one on the wikipedia article. It doesn't seem to decode the correct numbers though.

The decoded number also changes depending on what value of N I pass to the algorithm. As far as I understood a higher value of N gives it better accuracy but should not change what number would get decoded correct?

Here is the code,

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

double goertzel(short samples[], double freq, int N) 
{
double s_prev = 0.0;
double s_prev2 = 0.0;    
double coeff, normalizedfreq, power, s;
int i;
normalizedfreq = freq / 8000;
coeff = 2*cos(2*M_PI*normalizedfreq);
for (i=0; i<N; i++) 
{
    s = samples[i] + coeff * s_prev - s_prev2;
    s_prev2 = s_prev;
    s_prev = s;
}
power = s_prev2*s_prev2+s_prev*s_prev-coeff*s_prev*s_prev2;
return power;
}

int main()
{
FILE *fp = fopen("9.raw", "rb");
short *buffer;
float *sample;
int sample_size;
int file_size;
int i=0, x=0;

float frequency_row[] = {697, 770, 852, 941};
float frequency_col[] = {1209, 1336, 1477};
float magnitude_row[4];
float magnitude_col[4];

double result;

fseek(fp, 0, SEEK_END);
file_size = ftell(fp);
fseek(fp, 0, SEEK_SET);

buffer = malloc(file_size);

buffer[x] = getc(fp);
buffer[x] = buffer[x]<<8;
buffer[x] = buffer[x] | getc(fp);

while(!feof(fp))
{
    x++;
    buffer[x] = getc(fp);
    buffer[x] = buffer[x]<<8;
    buffer[x] = buffer[x] | getc(fp);
}

for(i=0; i<x; i++)
{
    //printf("%#x\n", (unsigned short)buffer[i]);
}
for(i=0; i<4; i++)
{
    magnitude_row[i] = goertzel(buffer, frequency_row[i], 8000);
}
for(i=0; i<3; i++)
{
    magnitude_col[i] = goertzel(buffer, frequency_col[i], 8000);
}

x=0;
for(i=0; i<4; i++)
{
    if(magnitude_row[i] > magnitude_row[x])
    x = i;
}
printf("Freq: %f\t Mag: %f\n", frequency_row[x], magnitude_row[x]);

x=0;
for(i=0; i<3; i++)
{
    if(magnitude_col[i] > magnitude_col[x])
    x = i;
}
printf("Freq: %f\t Mag: %f\n", frequency_col[x], magnitude_col[x]);
return 0;
 }
BlackCow
  • 1,437
  • 2
  • 14
  • 11
  • Try to verify the length of each tone. N cannot be larger than the length of the tone you are measuring. – user877329 Apr 25 '12 at 11:26
  • 1
    I'm not sure how to determine this... – BlackCow Apr 25 '12 at 12:41
  • The decoded number varies widely depending on the value of N, but any value I try I can't get it to decode the actual number I want. Is it possibly the algorithm is just plain wrong? If we could figure out what needs to be done to make it work it would be a nice to update wikipedia with something that works! – BlackCow Apr 25 '12 at 13:51
  • To verify the algorithm use a long signal (1 s) containing only one tone. And where is your spectrum? You should fill a buffer with "time varying" spectrum data. – user877329 Apr 25 '12 at 16:11
  • Have you actually tried to plot the entire spectrum? It would tell you if the algorithm works or not. – user877329 Apr 26 '12 at 05:40

3 Answers3

2

The algorithm is actually tricky to use, even for something as simple as detecting DTMF tones. It is actually effectively a band-pass filter - it singles out a band of frequencies centered around the frequency given. This is actually a good thing - you can't count on your sampled tone to be exactly the frequency you are trying to detect.

The tricky part is attempting to set the bandwidth of the filter - how wide the range of frequencies is that will be filtered to detect a particular tone.

One of the references on the Wikipedia page on the subject (this one to be precise) talks about implementing DTMF tone detection using the Goertzel Algorithm in DSP. The principles are the same for C - to get the bandwidth right you have to use the right combination of provided constants. Apparently there is no simple formula - the paper mentions having to use a brute force search, and provides a list of optimal constants for the DTMF frequencies sampled at 8kHz.

Michael Slade
  • 13,802
  • 2
  • 39
  • 44
2

Are you sure the audio data Audacity generated is in big-endian format? You are interpreting it in big-endian, whereas they are normally in little-endian if you run it on x86.

mtvec
  • 17,846
  • 5
  • 52
  • 83
Rong Shen
  • 21
  • 1
1

There are some interesting answers here. First, the goertzel is in fact a "sympathetic" oscillator. That means that the poles are on the unit circle in DSP terms. The internal variables s, s_prev, s_prev2 will grow without bound if you run the code on a long block of data containing the expected tone (freq) for that detector. This means that you need to run a kind of integrate an dump process to get results. The goertzel works best at discriminating between DTMF digits if you run about 105 to 110 samples into it at a time. So set N = 110 and call the goertzel repeatedly as you run through you data. Incidentally, real DTMF digits may only last as little as 60 msec and you should report their presence if you find more than 40 msec. Think about the 110 samples I mentioned, means one call covers 110/8000 = 13.75 msec. If you are very fortunate, then you will see positive output from 4 consecutive iterations of calls to the detector. In the past I have found that running a pair of detectors in parallel with staggered start times, with provide better coverage of very short tone bursts.