反fft产生接近但错误的输出

时间:2013-12-07 07:34:16

标签: c++ math fft

我正在执行基数-2 dif反向fft。我正在使用共轭和缩放的属性来返回结果。我将输入矢量共轭,执行常规基数-2 fft(而不是ifft),将结果共轭,然后按1.0 / N进行缩放。但是,我没有得到正确的结果:

int main(){ 
    const int n = 4;
    complex<double> x[n];

        // Test signal

    x[0] = complex<double>(10,0);
    x[1] = complex<double>(-2,0);
    x[2] = complex<double>(-2,2);
    x[3] = complex<double>(-2,-2);

        print(x,n);

    fft_inverse(x,n); 

    print(x,n); 

}
//dif fft. works
void fft(complex<double> X[], int N){
        if(N == 1){return;} 

    complex<double> *temp = new complex<double>[N]; 
    for(int i=0; i<N; i++){
        temp[i]=X[i];
        }   
        for(int i = 0; i<N/2; i++){
        complex<double> tw(cos(-2*M_PI*i/N),sin(-2*M_PI*i/N)); 
            X[i] = temp[i] + temp[i+N/2];
            X[i+N/2] = temp[i]-temp[i+N/2];
            X[i+N/2] = X[i+N/2]*tw;   
        }

        fft(X,N/2);
        fft(X+N/2,N/2);
}
void fft_inverse(complex<double> X[], int N){
    //conjugate
    for(int i = 0; i<N;i++){
        X[i] = conj(X[i]);
    }
    //perform fft
    fft(X,N);
    //conjugate again
    for(int i = 0; i<N;i++){
        X[i] = conj(X[i]);
    }
    //scale by 1.0/N
    double norm_N = 1.0/N;
    for(int i = 0; i<N;i++){
        X[i] *= norm_N;
    }
}

以下是我的结果: 输入:

  

(10,0)       (-2,0)       (-2,2)       (-2,-2)

输出:

  

(1,-O)       (3,1)       (2.5,-0.5)       (3.5,-0.5)

输出应为:

  

(1,0)       (2,0)       (3,0)       (4,0)

发生了什么事?我已经测试了我的fft输出应该是什么并得到了正确的结果,所以我不确定是什么问题。

2 个答案:

答案 0 :(得分:1)

看起来您的代码提供了正确的输出但是这些分区的顺序错误:

octave> X = [ 10, -2, -2+2i, -2-2i ] 
X =

   10 +  0i   -2 +  0i   -2 +  2i   -2 -  2i

octave> x = ifft(X)
x =

   1.00000 + 0.00000i   2.50000 - 0.50000i   3.00000 + 1.00000i   3.50000 - 0.50000i

fft_inverse()看起来不错,所以我怀疑fft()可以使用一些进一步的测试/调试 - 可能需要为索引做一些反转。

答案 1 :(得分:1)

让我们回顾一下基础知识:长度为2N的逆fft在p(z)的统一q^i的根处评估2N度的多项式q^N = -1。为了快速做到这一点,多项式被分成偶数和奇数部分p(z)=pe(z^2)+z*po(z^2)。然后

p(q^i)    =pe(q^2i)+q^i*po(q^2i)
p(q^(N+i))=pe(q^2i)-q^i*po(q^2i)

在实现中,pe和po的值是通过递归调用长度为N的ifft获得的。

前向fft现在是逆操作,从其值计算多项式的系数。为此,通过颠倒上述公式,将p(q^i)的值转换为pe(q^2i)po(q^2i)的值,

pe(q^2i)=0.5*(p(q^i)+p(q^(N+i)))
po(q^2i)=0.5*(p(q^i)-p(q^(N+i)))*q^(-i)

您应该从代码中识别出来。然后递归地调用fft以从它们现在计算的值确定pe和po的系数。因子0.5通常被省略,并且应用fft例程之外的数组长度作为除法收集。

现在出错的地方在于pe和po的系数在p的系数序列中出现交替,交错。着名的蝴蝶图案。

void fft(complex<double> X[], int N){
    fft_internal(X,N,1);
}

void fft_internal(complex<double> X[], int N, int step){
    if(N == 1){return;} 

    complex<double> *temp = new complex<double>[N]; 
    for(int i=0; i<N; i++){
        temp[i]=X[step*i];
    }   
    for(int i = 0; i<N/2; i++){
    complex<double> tw(cos(-2*M_PI*i/N),sin(-2*M_PI*i/N)); 
        X[2*step*i     ] =  temp[i] + temp[i+N/2];
        X[2*step*i+step] = (temp[i] - temp[i+N/2])*tw;   
    }

    fft_internal(X     ,N/2, 2*step);
    fft_internal(X+step,N/2, 2*step);
}

使用正确重新排序的输入([2]&lt; - &gt; [1]),

// Test signal

x[0] = complex<double>(10,0);
x[1] = complex<double>(-2,2);
x[2] = complex<double>(-2,0);
x[3] = complex<double>(-2,-2);

这会返回预期的结果。