web-dev-qa-db-ja.com

CでのGoertzelアルゴリズムの実装

DSPプロセッサにBFSK周波数ホッピング通信システムを実装しています。一部のフォーラムメンバーは、特定の周波数での周波数ホッピングの復調にGoertzelアルゴリズムを使用することを提案しました。 Cでgoertzelアルゴリズムを実装しようとしました。コードは次のとおりです。

float goertzel(int numSamples,int TARGET_FREQUENCY,int SAMPLING_RATE, float* data)
{
    int     k,i;
    float   floatnumSamples;
    float   omega,sine,cosine,coeff,q0,q1,q2,result,real,imag;

    floatnumSamples = (float) numSamples;
    k = (int) (0.5 + ((floatnumSamples * TARGET_FREQUENCY) / SAMPLING_RATE));
    omega = (2.0 * M_PI * k) / floatnumSamples;
    sine = sin(omega);
    cosine = cos(omega);
    coeff = 2.0 * cosine;
    q0=0;
    q1=0;
    q2=0;

    for(i=0; i<numSamples; i++)
    {
        q0 = coeff * q1 - q2 + data[i];
        q2 = q1;
        q1 = q0;
    }
    real = (q1 - q2 * cosine);
    imag = (q2 * sine);
    result = sqrtf(real*real + imag*imag);
    return result;
}

関数を使用して特定のデータセットの特定の頻度で結果を計算すると、正しい結果が得られません。ただし、同じデータセットを使用し、MATLAB goertzel()関数を使用してgoertzelの結果を計算すると、結果は完全に得られます。私はインターネットで見つけたいくつかのオンラインチュートリアルの助けを借りて、Cを使用してアルゴリズムを実装しています。関数がgoertzelアルゴリズムを正しく実装している場合は、皆さんの意見を聞きたいだけです。

13
anshu

結果がデータのDFTまたはFFTの頻度の結果と一致するため、Matlabの実装が適切であると言っている場合は、Matlabの実装がFFTで行われるようにスケーリング係数によって結果を正規化していることが原因である可能性があります。

これを考慮してコードを変更し、結果が改善されるかどうかを確認してください。わかりやすくするために、関数と結果の名前も変更して、完全な複雑な結果ではなく、ゲルツェルが大きさを計算していることを反映していることに注意してください。

float goertzel_mag(int numSamples,int TARGET_FREQUENCY,int SAMPLING_RATE, float* data)
{
    int     k,i;
    float   floatnumSamples;
    float   omega,sine,cosine,coeff,q0,q1,q2,magnitude,real,imag;

    float   scalingFactor = numSamples / 2.0;

    floatnumSamples = (float) numSamples;
    k = (int) (0.5 + ((floatnumSamples * TARGET_FREQUENCY) / SAMPLING_RATE));
    omega = (2.0 * M_PI * k) / floatnumSamples;
    sine = sin(omega);
    cosine = cos(omega);
    coeff = 2.0 * cosine;
    q0=0;
    q1=0;
    q2=0;

    for(i=0; i<numSamples; i++)
    {
        q0 = coeff * q1 - q2 + data[i];
        q2 = q1;
        q1 = q0;
    }

    // calculate the real and imaginary results
    // scaling appropriately
    real = (q1 - q2 * cosine) / scalingFactor;
    imag = (q2 * sine) / scalingFactor;

    magnitude = sqrtf(real*real + imag*imag);
    return magnitude;
}
12
K. Brafford

多くの場合、たとえばトーン検出などの計算では、大きさの2乗を使用できます。

Goertzelsのいくつかの優れた例は、アスタリスクPBX DSPコード アスタリスクDSPコード(dsp.c) およびspandspライブラリ SPANDSP DSPライブラリ にあります。 ==

1
Wadester

2つの入力サンプル波形を考えてみましょう。

1)振幅Aと周波数Wの正弦波

2)同じ振幅と周波数の余弦波AとW

Goertzelアルゴリズムは、前述の2つの入力波形に対して同じ結果を生成するはずですが、提供されたコードは異なる戻り値を生成します。コードは次のように修正する必要があると思います。

float goertzel_mag(int numSamples,int TARGET_FREQUENCY,int SAMPLING_RATE, float* data)
{
    int     k,i;
    float   floatnumSamples;
    float   omega,sine,cosine,coeff,q0,q1,q2,magnitude,real,imag;

    float   scalingFactor = numSamples / 2.0;

    floatnumSamples = (float) numSamples;
    k = (int) (0.5 + ((floatnumSamples * TARGET_FREQUENCY) / SAMPLING_RATE));
    omega = (2.0 * M_PI * k) / floatnumSamples;
    sine = sin(omega);
    cosine = cos(omega);
    coeff = 2.0 * cosine;
    q0=0;
    q1=0;
    q2=0;

    for(i=0; i<numSamples; i++)
    {
        q2 = q1;
        q1 = q0;
        q0 = coeff * q1 - q2 + data[i];
    }

    // calculate the real and imaginary results
    // scaling appropriately
    real = (q0 - q1 * cosine) / scalingFactor;
    imag = (-q1 * sine) / scalingFactor;

    magnitude = sqrtf(real*real + imag*imag);
    return magnitude;
}
0
Mohammad Hadi