1

1000Hz トーンを追加した Wav オーディオ ファイルのオーディオ データを含む配列に適用された FFT の結果である double の配列があります。

「Numerical Recipes」で定義されている DREALFT を考えて、この配列を取得しました (使用する必要があります)。(元の配列の長さは 2 のべき乗です。)

私の配列には次の構造があります。

array[0] = 複素変換の最初の実数値コンポーネント

array[1] = 複素数変換の最後の実数値コンポーネント

array[2] = 2 番目の要素の実部

array[3] = 2 番目の要素の虚数部

等......

これで、この配列が周波数ドメインを表していることがわかりました。

1000Hzの周波数を特定して殺したい。

1000Hzの周波数を含む配列のインデックスを見つけるために、次の式を試しました。

index = 1000. * NElements /44100;

また、このインデックスは実数値のみを含む配列を参照していると想定しているため、虚数値も含む配列内の正しい (?) 位置を特定しました。

    int correctIndex=2;

for(k=0;k<index;k++){
    correctIndex+=2;
}

(確かにもっと簡単な方法があることは知っていますが、それが最初に思い浮かびました)

次に、16275892957.123705 という値を見つけました。これは、1000Hz 周波数の実部であると思われます。

だから私はそれを抑制しようとしました:

array[index]=-copy[index]*0.1f;

なぜこの式を使用したのか正確にはわかりませんが、いくつかの結果が得られる唯一の式です。実際、1000hz トーンがわずかに減少しているように見えます。

これは、問題のコードの一部です。

    double *copy = malloc( nCampioni * sizeof(double));
    int nSamples;

 /*...Fill copy with audio data...*/

     /*...Apply ZERO PADDING and reach the length of 8388608 samples, 
 or rather 8388608 double values...*/


/*Apply the FFT (Sure this works)*/
drealft(copy - 1, nSamples, 1);

/*I determine the REAL(?) array index*/
i= 1000. * nSamples /44100;

/*I determine MINE(?) array index*/
int j=2;

for(k=0;k<i;k++){
    j+=2;
}

/*I reduce the array value, AND some other values aroud it as an attempt*/
for(i=-12;i<12;i+=2){
    copy[j-i]=-copy[i-j]*0.1f;
    printf("%d\n",j-i);
}

/*Apply the inverse FFT*/
drealft(copy - 1, nSamples, -1);

/*...Write the audio data on the file...*/

注: 簡単にするために、int16_t の配列から double の配列を取得する部分を省略しました

1000Hzの周波数を特定して完全に殺すにはどうすればよいですか?

ありがとうございました!

4

1 に答える 1

2

Oli Charlesworth が書いているように、ターゲット周波数は正確に FFT ビンの 1 つではないため (ターゲット周波数index* NumberOfElements / SamplingRate は正確に整数ではない)、ターゲット周波数のエネルギーはすべてのビンに分散されます。まず、ターゲット周波数に最も近いビンをゼロにすることで、周波数の一部を削除できます。これはもちろん、ターゲットからわずかに外れているため、他の周波数にもいくらか影響します。ターゲット周波数をより適切に抑制するには、より高度なフィルターを検討する必要があります。

ただし、教育目的の場合: ビンに対応する周波数を抑制するには、そのビンをゼロに設定するだけです。ビンの実数成分と虚数成分の両方をゼロに設定する必要があります。これは次の方法で実行できます。

copy[index*2 + 0] = 0;
copy[index*2 + 1] = 1;

これに関する注意事項:

配列内の位置を計算するには、次のコードがありました。

int correctIndex = 2;
for (k = 0; k < index; k++) {
    correctIndex += 2;
}

これは次と同等です。

correctIndex = 2*(index+1);

私はあなたが望ん2*indexでいると信じています2*(index+1)。したがって、間違ったビンを減らしていた可能性があります。

あなたの質問のある時点で、あなたは書いarray[index] = -copy[index]*0.1f;た. 何だかわかりませんarray。あなたは でその場で働いているようcopyです。また、なぜ 10 分の 1 を掛けたのかもわかりません。周波数を除去したい場合は、ゼロに設定してください。これを 1/10 倍しても、元の大きさの 10% に減少するだけです。

Numerical Recipes コードは 1 ベースのインデックスを使用copy-1しているため、 に渡す必要があることを理解しています。drealftただし、C 標準は、あなたが行っている方法をサポートしていません。式の動作はcopy-1、標準では定義されていません。ほとんどの C 実装で動作します。ただし、サポートされている移植可能なコードを記述するには、代わりに次のようにする必要があります。

// Allocate one extra element.
double *memory = malloc((nCampioni+1) * sizeof *memory);

// Make a pointer that is convenient for your work.
double *copy = memory+1;

…

// Pass the necessary base address to drealft.
drealft(memory, nSamples, 1);

// Suppress a frequency.
copy[index*2 + 0] = 0;
copy[index*2 + 1] = 0;

…

// Free the memory.
free(memory);

検討することをお勧めする 1 つの実験は、目的の周波数の正弦波だけで配列を初期化することです。

for (i = 0; i < nSamples; ++i)
    copy[i] = sin(TwoPi * Frequency / SampleRate * i);

TwoPiもちろん2*3.1415926535897932384626433です。)次に、適用drealftして結果を見てください。エネルギーの多くがターゲット周波数に最も近いビンのピークにあることがわかりますが、その多くは他のビンにも広がっています。明らかに、1 つのビンをゼロにして逆 FFT を実行しても、すべての周波数を除去することはできません。また、ピークが に対して計算した同じビンにあることがわかりますindex。そうでない場合は、何かが間違っています。

于 2013-06-19T14:15:22.617 に答える