1

そこで、audacity で生成した DTMF トーンの .raw ファイルを開いています。ウィキペディアの記事にあるものと同様の定型化された goertzel アルゴリズムを入手しました。ただし、正しい数値をデコードしていないようです。

デコードされた数値も、NI のどの値がアルゴリズムに渡されるかに応じて変化します。私が理解している限り、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;
 }
4

3 に答える 3

2

Audacity が生成した音声データがビッグエンディアン形式であると確信していますか? ビッグエンディアンで解釈していますが、x86で実行する場合、通常はリトルエンディアンです。

于 2012-04-27T06:20:38.127 に答える
2

このアルゴリズムは、DTMF トーンを検出するような単純なものであっても、実際には使いにくいものです。これは実際には効果的なバンドパス フィルターです。指定された周波数を中心とした周波数帯域を選び出します。これは実際には良いことです。サンプリングされたトーンが、検出しようとしている周波数と正確に一致するとは限りません。

注意が必要なのは、フィルターの帯域幅を設定しようとすることです。つまり、特定のトーンを検出するためにフィルター処理される周波数範囲の広さです。

この件に関するウィキペディアのページの参照の1 つ(正確にはこれ) では、DSP で Goertzel アルゴリズムを使用した DTMF トーン検出の実装について説明しています。原則は C でも同じです。適切な帯域幅を得るには、提供された定数を適切に組み合わせて使用​​する必要があります。どうやら単純な公式はありません - 紙は力ずくの検索を使用する必要があると述べており、8kHzでサンプリングされたDTMF周波数の最適な定数のリストを提供しています.

于 2012-04-26T08:22:12.973 に答える
0

ここにいくつかの興味深い答えがあります。まず、ゲーツェルは実際には「交感神経」オシレーターです。これは、極が DSP 用語で単位円上にあることを意味します。内部変数 s、s_prev、s_prev2 は、その検出器の予想されるトーン (周波数) を含む長いデータ ブロックに対してコードを実行すると、際限なく大きくなります。これは、結果を得るために一種の統合ダンプ プロセスを実行する必要があることを意味します。goertzel は、一度に約 105 から 110 のサンプルを実行すると、DTMF 桁を区別するのに最適に機能します。したがって、N = 110 に設定し、データを実行しながら goertzel を繰り返し呼び出します。ちなみに、実際の DTMF 数字はわずか 60 ミリ秒しか持続しない場合があり、40 ミリ秒を超える場合はその存在を報告する必要があります。私が言及した 110 個のサンプルについて考えてみてください。つまり、1 回の呼び出しで 110/8000 = 13.75 ミリ秒がカバーされます。運が良ければ、検出器への呼び出しを 4 回連続して繰り返すと、肯定的な出力が表示されます。過去に、1 組の検出器を開始時間をずらして並行して実行すると、非常に短いトーン バーストをより適切にカバーできることがわかりました。

于 2017-09-08T21:16:38.313 に答える