2017-05-21 54 views
1

FFT工作正常,但是当我想采用IFFT时,我总是从其结果中看到相同的图形。无论原始信号如何,结果都很复杂,图形总是相同的。ifft结果不同于原始信号

在实部图表

是与虚部段=帧大小

一个-sin它与同期

在哪里可以是一个问题一个-cos?

原始信号: original signal

IFFT真正的价值(在照片是唯一的帧的一半): IFFT real value

FFT算法,我使用。

double** FFT(double** f, int s, bool inverse) { 
    if (s == 1) return f; 
    int sH = s/2; 

    double** fOdd = new double*[sH]; 
    double** fEven = new double*[sH]; 
    for (int i = 0; i < sH; i++) { 
     int j = 2 * i; 
     fOdd[i] = f[j]; 
     fEven[i] = f[j + 1]; 
    } 

    double** sOdd = FFT(fOdd, sH, inverse); 
    double** sEven = FFT(fEven, sH, inverse); 

    double**spectr = new double*[s]; 

    double arg = inverse ? DoublePI/s : -DoublePI/s; 
    double*oBase = new double[2]{ cos(arg),sin(arg) }; 
    double*o = new double[2]{ 1,0 }; 

    for (int i = 0; i < sH; i++) { 
     double* sO1 = Mul(o, sOdd[i]); 

     spectr[i] = Sum(sEven[i], sO1); 
     spectr[i + sH] = Dif(sEven[i], sO1); 

     o = Mul(o, oBase); 
    } 

    return spectr; 
} 
+3

侧面说明:您的代码分配大量使用'new'堆中的对象,但你的代码永远不会调用'delete'不改变对象的所有权才离开范围 - 所以你的程序会泄漏内存。 – Dai

+0

@戴,谢谢你的回答,我会尽力解决它的工作。但现在这不是我的最大问题。 –

+1

imho它是最大的问题。所有这些指针和'新'使代码不必要的难以阅读和发现像你所拥有的错误 – user463035818

回答

2

的 “蝴蝶” 部分错误地应用系数:

for (int i = 0; i < sH; i++) { 
    double* sO1 = sOdd[i]; 
    double* sE1 = Mul(o, sEven[i]); 

    spectr[i] = Sum(sO1, sE1); 
    spectr[i + sH] = Dif(sO1, sE1); 

    o = Mul(o, oBase); 
} 

侧面说明:

我一直在你的格式,但它使事情混乱:

fOdd有索引0,2,4,6,...所以它应该是fEven

fEven具有索引1,3,5,7,...所以它应该是fOdd

sOdd应该是sLowersEvensUpper,因为它们分别对应于频谱的0:s/2s/2:s-1元素:

sLower = FFT(fEven, sH, inverse); // fEven is 0, 2, 4, ... 
sUpper = FFT(fOdd, sH, inverse); // fOdd is 1, 3, 5, ... 

然后蝶形变为:

for (int i = 0; i < sH; i++) { 
    double* sL1 = sLower[i]; 
    double* sU1 = Mul(o, sUpper[i]); 

    spectr[i] = Sum(sL1, sU1); 
    spectr[i + sH] = Dif(sL1, sU1); 

    o = Mul(o, oBase); 
} 

当这样写时,比较容易与pseudocode example on wikipedia比较。

而且@Dai是正确的你会泄漏大量的内存

+0

我优化了内存: \t'.... ................ for(int i = 0; i

+2

您可能仍然有内存问题,因为我猜你在'Mul','Sum'和'Dif'函数内有'new',而'new' 'fOdd'和'fEven'。如果仔细考虑操作的顺序,实际上可以对FFT进行数学运算。至少对于代码中的每个新代码都应该有一个删除 – Robb

1

关于内存,你可以使用std::vector封装动态分配的数组,并确保在执行离开范围他们释放。您可以使用unique_ptr<double[]>,但性能提升不值得IMO和您失去at()方法的安全性。

(基于@罗布的回答)

一些其他提示:

  • 避免含义模糊的标识 - 程序应该是可读的,名称,如“f”和“s”使你的程序更难阅读和维护。
  • 由于现代编辑器自动显示类型信息,因此基于类型的匈牙利符号被忽视,因此它为标识符名称添加了不必要的复杂性。
  • 使用size_t索引,而不是int
  • STL是你的朋友,使用它!
  • 使用const预防性地防止错误以防止只读数据的意外突变。

像这样:

#include <vector> 

using namespace std; 

vector<double> fastFourierTransform(const vector<double> signal, const bool inverse) { 

    if(signal.size() < 2) return signal; 
    const size_t half = signal.size()/2; 

    vector<double> lower; lower.reserve(half); 
    vector<double> upper; upper.reserve(half); 

    bool isEven = true; 
    for(size_t i = 0; i < signal.size(); i++) { 
     if(isEven) lower.push_back(signal.at(i)); 
     else   upper.push_back(signal.at(i)); 

     isEven = !isEven; 
    } 

    vector<double> lowerFft = fastFourierTransform(lower, inverse); 
    vector<double> upperFft = fastFourierTransform(upper, inverse); 

    vector<double> result; 
    result.reserve(signal.size()); 

    double arg = (inverse ? 1 : -1) * (DoublePI/signal.size()); 

    // Ideally these should be local `double` values passed directly into `Mul`. 
    unique_ptr<double[]> oBase = make_unique<double[]>(2); 
    oBase[0] = cos(arg); 
    oBase[1] = sin(arg); 

    unique_ptr<double[]> o = make_unique<double[]>(2); 
    o[0] = 0; 
    o[1] = 0; 

    for(size_t i = 0; i < half; i++) { 

     double* lower1 = lower.at(i); 
     double* upper1 = Mul(o, upper.at(i)); 

     result.at(i  ) = Sum(lower1, upper1); 
     result.at(i + half) = Dif(lower1, upper1); 

     o = Mul(o, oBase); 
    } 

    // My knowledge of move-semantics of STL containers is a bit rusty - so there's probably a better way to return the output 'result' vector. 
    return result; 
} 
+0

我使用了<复制>而不是复制和复杂而不是unique_ptr 。 然后我不需要像Mul,Sum,Dif这样的功能。 但速度比双**慢4倍(〜1000ms vs〜250ms或〜52ms vs〜13ms) –