【问题标题】:Looking for help about a FFT template寻求有关 FFT 模板的帮助
【发布时间】:2017-08-09 08:00:26
【问题描述】:

我目前正在处理一个需要 FFT 进行卷积的问题,但是当我从存档中引入我的 FFT 模板时,我意识到输出有问题。

例如:

输入:(0, 0) (0, 0) (4166667, 0) (1, 0)

正确的输出:(4166668, 0) (-4166667, 1) (4166666, 0) (-4166667, -1)

模板输出:(4166668, 0) (-4166667, -1) (4166666, 0) (-4166667, 1)

代码:

#define MAXN 
#define ld long double
#define op operator

struct base {
   typedef ld T; T re, im;
   base() :re(0), im(0) {}
   base(T re) :re(re), im(0) {}
   base(T re, T im) :re(re), im(im) {}
   base op + (const base& o) const { return base(re + o.re, im + o.im); }
   base op - (const base& o) const { return base(re - o.re, im - o.im); }
   base op * (const base& o) const { return base(re * o.re - im * o.im, re * o.im + im * o.re); }
   base op * (ld k) const { return base(re * k, im * k); }
   base conj() const { return base(re, -im); }
};

base w[MAXN]; //omega lookup table
int rev[MAXN]; //reverse lookup table

void build_rev(int k) {
   static int rk = -1;
   if( k == rk )return ; rk = k;
   for(int i = 1; i < (1<<k); i++) {
       int j = rev[i-1], t = k-1;
       while( t >= 0 && ((j>>t)&1) ) { j ^= 1 << t; --t; }
       if( t >= 0 ) { j ^= 1 << t; --t; }
       rev[i] = j;
   }
}

void fft(base *a, int k) {
   build_rev(k); int n = 1 << k;
   for(int i = 0; i < n; i++) if( rev[i] > i ) swap(a[i], a[rev[i]]);
   for(int l = 2, lll = 1; l <= n; l += l, lll += lll) {
       if( w[lll].re == 0 && w[lll].im == 0 ) {
           ld angle = PI / lll;
           base ww( cosl(angle), sinl(angle) );
           if( lll > 1 ) for(int j = 0; j < lll; ++j) {
               if( j & 1 ) w[lll + j] = w[(lll+j)/2] * ww;
               else w[lll + j] = w[(lll+j)/2];
           } else w[lll] = base(1, 0);
       }
       for(int i = 0; i < n; i += l) 
         for(int j = 0; j < lll; j++){
           base v = a[i + j], u = a[i + j + lll] * w[lll + j];
           a[i + j] = v + u; a[i + j + lll] = v - u;
            }
   }
}

//ideone compiled example: http://ideone.com/8PTjW5

我尝试检查位反转和统一表的根,但我没有发现这两个部分有任何问题。我还检查了一些在线材料以验证步骤,但我觉得没有什么奇怪的。

有人能帮我找出这个模板有什么问题吗?

提前致谢。

编辑:最后我决定依赖另一个模板,谢谢大家的回复。

【问题讨论】:

  • 我怀疑除了你之外的任何人都可以调试这段代码。它非常密集,没有任何 cmets。
  • 使用变量名,例如lll,只要你是唯一读过代码的人就可以了:P
  • 我建议用只有一个非零分量来变换(或逆变换)单位向量,这样你可能会更容易看到哪些系数是关闭的
  • 还有#define op operator?严重地。更不用说重新发明std::complex。这甚至不是 C++11,std::complex 已成为每个 C++ 标准的一部分。
  • 请参阅How to compute Discrete Fourier Transform?,您将在链接的答案中找到我的 C++ 实现,用于一维和二维的 (I)DFT 和 (I)DFFT。我在您的代码中没有看到任何递归,所以我认为它只是 DFT 而不是 DFFT ...

标签: c++ math signal-processing fft


【解决方案1】:

您的权重符号似乎有误(这意味着您可能正在执行逆 FFT 而不是正向 FFT - 请记住对于正向变换 the weights are exp(-j * theta))。尝试改变:

base ww( cosl(angle), sinl(angle) );

到:

base ww( cosl(angle), -sinl(angle) );

这个seems to give the correct results 用于您的简单测试用例。我还没有尝试过要求更高的测试。

巧合的是最近有另一个用户made exactly the same mistake in a MATLAB implementation。我猜- 标志很容易错过。

另请注意,您的代码效率非常低 - 您可能需要考虑使用简单的、经过验证的 FFT 库,例如 KissFFT

【讨论】:

  • 谢谢,现在正向传递工作正常。我继续使用@tobi303 的建议,并尝试使用卷积简单单位向量,但反向传递现在不起作用。你介意再看一看吗? code
  • @haleyk:对不起,我真的没有时间解开代码——它相当简洁和神秘。您需要决定是花几个小时调试它还是改用经过试验和测试(而且效率更高)的第三方库更好,如上所述。
猜你喜欢
  • 1970-01-01
  • 2017-12-12
  • 1970-01-01
  • 1970-01-01
  • 2021-05-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多