【问题标题】:DTMF Goertzel Algorithm Not WorkingDTMF Goertzel 算法不工作
【发布时间】:2023-03-16 22:37:01
【问题描述】:

所以我打开了一个我大胆生成的 DTMF 音调的 .raw 文件。我抓住了一个类似于维基百科文章中的罐头 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;
 }

【问题讨论】:

  • 尝试验证每个音调的长度。 N 不能大于您正在测量的音调长度。
  • 我不确定如何确定这个...
  • 解码后的数字根据 N 的值变化很大,但我尝试的任何值都无法解码我想要的实际数字。算法可能是完全错误的吗?如果我们能弄清楚需要做些什么来让它工作,那么用一些有用的东西来更新维基百科会很不错!
  • 要验证算法,请使用仅包含一个音调的长信号 (1 s)。你的频谱在哪里?您应该用“时变”光谱数据填充缓冲区。
  • 你真的尝试过绘制整个光谱吗?它会告诉你算法是否有效。

标签: c dtmf


【解决方案1】:

该算法实际上很难使用,即使对于检测 DTMF 音调这样简单的事情也是如此。它实际上是一个band-pass filter - 它挑选出以给定频率为中心的频带。这实际上是一件好事 - 你不能指望你的采样音正是你试图检测的频率。

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

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

【讨论】:

  • 2022年还是这样吗?与 OP 有类似的问题。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-19
      • 1970-01-01
      • 1970-01-01
      • 2023-03-06
      相关资源
      最近更新 更多