2012-04-25 44 views
2

所以我打开一个在大胆生成的DTMF音的.raw文件。我抓住了一个类似于维基百科文章上的goertzel算法。它似乎并没有解码正确的数字。DTMF Goertzel算法不起作用

解码的数字也会根据传递给算法的N的值而变化。据我所知,N值越高,其准确度越好,但不应该改变解码正确的数字。

下面是代码,

#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; 
} 
+0

尝试验证每个音的长度。 N不能大于你正在测量的音调的长度。 – user877329 2012-04-25 11:26:34

+0

我不知道如何确定这个... – BlackCow 2012-04-25 12:41:15

+0

解码的数字差异很大,取决于N的值,但我尝试的任何值都无法解码我想要的实际数字。这算法可能是错的吗? 如果我们能够弄清楚需要做些什么才能使它工作,那么使用一些可行的工具更新维基百科将是一件很好的事情! – BlackCow 2012-04-25 13:51:46

回答

2

的算法实际上是棘手的使用,即使是作为检测DTMF音频简单的东西。它实际上实际上是一个band-pass filter - 它挑选出一个以给定频率为中心的频带。这实际上是一件好事 - 你不能指望你的采样音是正好你试图检测的频率。

棘手的部分是试图设置过滤器的带宽 - 频率范围有多宽,这些频率范围将被过滤以检测特定音调。

关于该主题的Wikipedia page的其中一篇参考文献(准确地说是this one)谈到了使用DSP中的Goertzel算法实现DTMF音调检测。 C的原理是一样的 - 为了获得带宽,你必须使用提供的常量的正确组合。显然没有简单的公式 - 论文提到必须使用brute force search,并提供了8kHz采样的DTMF频率的最佳常量列表。

2

您确定Audacity生成的音频数据是以big-endian格式吗?你正在用big-endian来解释它,而如果你在x86上运行它们,它们通常是小端的。

0

这里有一些有趣的答案。首先,goertzel实际上是一个“同情”的振荡器。 这意味着极点在DSP方面在单位圆上。 如果您在包含该检测器的预期音调(频率)的长数据块上运行代码,则内部变量s,s_prev,s_prev2将不受限制地增长。 这意味着您需要运行一种集成转储过程来获取结果。 如果您一次运行约105到110个样本,goertzel在区分DTMF数字方面效果最佳。因此,设置N = 110,并在您运行数据时重复调用goertzel。 顺便提一句,实际的DTMF数字只能持续60毫秒,如果发现超过40毫秒,您应该报告它们的存在。 想想我提到的110个样本,意思是一个电话覆盖110/8000 = 13.75毫秒。如果你非常幸运,那么你会看到4次连续的呼叫到检测器的正面输出。 在过去,我发现运行一对探测器与开始时间交错并行,提供更好的覆盖非常短的音调突发。