12

そこで、実際の32ビット浮動小数点wavファイルで動作するように離散フーリエ変換をCで記述しようとしています。一度に2フレームで読み取ります(チャネルごとに1つですが、私の目的では、両方が同じであると想定しているため、frame [0]を使用します)。このコードは、入力ファイルを周波数20、40、60、...、10000でプローブすることにより、入力ファイルの振幅スペクトルを書き出すことになっています。入力フレームでハニングウィンドウを使用しています。できれば複素数の使用は避けたいです。これを実行すると、非常に奇妙な振幅が発生し(そのほとんどは非常に小さく、正しい周波数に関連付けられていません)、計算で根本的な間違いを犯していると思います。誰かがここで何が起こっているのかについての洞察を提供できますか?これが私のコードです:

int windowSize = 2205;
int probe[500];
float hann[2205];
int j, n;
// initialize probes to 20,40,60,...,10000
for (j=0; j< len(probe); j++) {
    probe[j] = j*20 + 20;
    fprintf(f, "%d\n", probe[j]);
}
fprintf(f, "-1\n");
// setup the Hann window
for (n=0; n< len(hann); n++) {
    hann[n] = 0.5*(cos((2*M_PI*n/(float)windowSize) + M_PI))+0.5;
}

float angle = 0.0;
float w = 0.0; // windowed sample
float realSum[len(probe)]; // stores the real part of the probe[j] within a window
float imagSum[len(probe)]; // stores the imaginary part of probe[j] within window
float mag[len(probe)]; // stores the calculated amplitude of probe[j] within a window
for (j=0; j<len(probe);j++) {
    realSum[j] = 0.0;
    imagSum[j] = 0.0;
    mag[j] = 0.0;
}

n=0; //count number of samples within current window
framesread = psf_sndReadFloatFrames(ifd,frame,1);
totalread = 0;
while (framesread == 1){
    totalread++;

    // window the frame with hann value at current sample
    w = frame[0]*hann[n];

    // determine both real and imag product values at sample n for all probe freqs times the windowed signal
    for (j=0; j<len(probe);j++) {
        angle = (2.0 * M_PI * probe[j] * n) / windowSize;
        realSum[j] = realSum[j] + (w * cos(angle));
        imagSum[j] = imagSum[j] + (w * sin(angle));
    }
    n++;
    // checks to see if current window has ended
    if (totalread % windowSize == 0) {
        fprintf(f, "B(%f)\n", totalread/44100.0);
        printf("%f breakpoint written\n", totalread/44100.0);
        for (j=0; j < len(mag); j++) { // print out the amplitudes 
            realSum[j] = realSum[j]/windowSize;
            imagSum[j] = imagSum[j]/windowSize;
            mag[j] = sqrt(pow((double)realSum[j],2)+pow((double)imagSum[j],2))/windowSize;
            fprintf(f, "%d\t%f\n", probe[j], mag[j]);
            realSum[j] = 0.0;
            imagSum[j] = 0.0;
        }
        n=0;
    }
    framesread = psf_sndReadFloatFrames(ifd,frame,1);
}
4

2 に答える 2

1

角度の計算に誤差があると思います。各サンプルの角度の増分は、サンプリング周波数に依存します。このようなもの(あなたは44100Hzを持っているようです):

angle = (2.0 * M_PI * probe[j] * n) / 44100;

サンプルウィンドウには、最低プローブ周波数20Hzの完全なサイクルが1つ含まれます。nを2205までループすると、その角度は2*M_PIになります。参照の周波数が2205Hzで、1102Hzを超えるすべての周波数がより低い周波数にエイリアシングされたため、おそらくエイリアシングが見られました。

于 2013-02-14T12:12:18.777 に答える
0

以下のコードでは、偽のサンプルをコンパイルして作成するためにわずかに再編成されているだけですが、すべてゼロにはなりません。最後に出力呼び出しを次のように変更しました。

fprintf(f, "%d\t%f\n", probe[j], mag[j] );

if (mag[j] > 1e-7)
    fprintf(f, "%d\t%f\n", probe[j], mag[j] * 10000);

これにより、ゼロ以外のデータが見やすくなります。多分唯一の問題はスケールファクターを理解することですか?テスト ケースとして、どのように入力を偽装して純粋なトーンを生成したかに注意してください。

#include <math.h>

#include <stdio.h>

#define M_PI 3.1415926535

#define SAMPLE_RATE 44100.0f

#define len(array) (sizeof array/sizeof *array)


unsigned psf_sndReadFloatFrames(FILE* inFile,float* frame,int framesToRead)
{
    static float counter = 0;   
    float frequency = 1000;
    float time = counter++;
    float phase = time/SAMPLE_RATE*frequency;
    *frame = (float)sin(phase);
    return counter < SAMPLE_RATE;
}

void discreteFourier(FILE* f)                    
{
    FILE* ifd = 0;
    float frame[1];
    int windowSize = 2205;
    int probe[500];
    float hann[2205];


    float angle = 0.0;
    float w = 0.0; // windowed sample
    float realSum[len(probe)]; // stores the real part of the probe[j] within a window
    float imagSum[len(probe)]; // stores the imaginary part of probe[j] within window
    float mag[len(probe)]; // stores the calculated amplitude of probe[j] within a window

    int j, n;

    unsigned framesread = 0;
    unsigned totalread = 0;

    for (j=0; j<len(probe);j++) {
        realSum[j] = 0.0;
        imagSum[j] = 0.0;
        mag[j] = 0.0;
    }

    // initialize probes to 20,40,60,...,10000
    for (j=0; j< len(probe); j++) {
        probe[j] = j*20 + 20;
        fprintf(f, "%d\n", probe[j]);
    }
    fprintf(f, "-1\n");
    // setup the Hann window
    for (n=0; n< len(hann); n++) 
    {
        hann[n] = 0.5*(cos((2*M_PI*n/(float)windowSize) + M_PI))+0.5;
    }
    n=0; //count number of samples within current window
    framesread = psf_sndReadFloatFrames(ifd,frame,1);
    totalread = 0;
    while (framesread == 1){
        totalread++;

        // window the frame with hann value at current sample
        w = frame[0]*hann[n];

        // determine both real and imag product values at sample n for all probe freqs times the windowed signal
        for (j=0; j<len(probe);j++) {
            angle = (2.0 * M_PI * probe[j] * n) / windowSize;
            realSum[j] = realSum[j] + (w * cos(angle));
            imagSum[j] = imagSum[j] + (w * sin(angle));
        }
        n++;
        // checks to see if current window has ended
        if (totalread % windowSize == 0) {
            fprintf(f, "B(%f)\n", totalread/SAMPLE_RATE);
            printf("%f breakpoint written\n", totalread/SAMPLE_RATE);
            for (j=0; j < len(mag); j++) { // print out the amplitudes 
                realSum[j] = realSum[j]/windowSize;
                imagSum[j] = imagSum[j]/windowSize;
                mag[j] = sqrt(pow((double)realSum[j],2)+pow((double)imagSum[j],2))/windowSize;
                if (mag[j] > 1e-7)
                    fprintf(f, "%d\t%f\n", probe[j], mag[j] * 10000);
                realSum[j] = 0.0;
                imagSum[j] = 0.0;
            }
            n=0;
        }
        framesread = psf_sndReadFloatFrames(ifd,frame,1);
    }
}
于 2012-12-22T00:08:23.560 に答える