【问题标题】:Computing FFT and IFFT with FFTW library C++使用 FFTW 库 C++ 计算 FFT 和 IFFT
【发布时间】:2011-08-06 20:16:49
【问题描述】:

我正在尝试计算 FFT,然后是 IFFT,只是为了尝试是否可以返回相同的信号,但我不确定如何完成它。这就是我做 FFT 的方式:

    plan = fftw_plan_r2r_1d(blockSize, datas, out, FFTW_R2HC, FFTW_ESTIMATE);
    fftw_execute(plan);

【问题讨论】:

  • 确实如此,但我不确定如何解释结果,如何访问频率?

标签: c++ signal-processing fftw


【解决方案1】:

这是一个例子。它做了两件事。首先,它准备一个输入数组in[N]作为余弦波,频率为3,幅度为1.0,傅里叶对其进行变换。因此,在输出中,您应该在out[3] 看到一个峰值,在out[N-3] 看到另一个峰值。由于余弦波的幅度为 1.0,因此您在 out[3]out[N-3] 处得到 N/2。

其次,它将数组out[N] 逆傅立叶变换回in2[N]。并且经过适当的规范化后,您可以看到in2[N]in[N] 相同。

#include <stdlib.h>
#include <math.h>
#include <fftw3.h>
#define N 16
int main(void) {
  fftw_complex in[N], out[N], in2[N]; /* double [2] */
  fftw_plan p, q;
  int i;

  /* prepare a cosine wave */
  for (i = 0; i < N; i++) {
    in[i][0] = cos(3 * 2*M_PI*i/N);
    in[i][1] = 0;
  }

  /* forward Fourier transform, save the result in 'out' */
  p = fftw_plan_dft_1d(N, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
  fftw_execute(p);
  for (i = 0; i < N; i++)
    printf("freq: %3d %+9.5f %+9.5f I\n", i, out[i][0], out[i][1]);
  fftw_destroy_plan(p);

  /* backward Fourier transform, save the result in 'in2' */
  printf("\nInverse transform:\n");
  q = fftw_plan_dft_1d(N, out, in2, FFTW_BACKWARD, FFTW_ESTIMATE);
  fftw_execute(q);
  /* normalize */
  for (i = 0; i < N; i++) {
    in2[i][0] *= 1./N;
    in2[i][1] *= 1./N;
  }
  for (i = 0; i < N; i++)
    printf("recover: %3d %+9.5f %+9.5f I vs. %+9.5f %+9.5f I\n",
        i, in[i][0], in[i][1], in2[i][0], in2[i][1]);
  fftw_destroy_plan(q);

  fftw_cleanup();
  return 0;
}

这是输出:

freq:   0  -0.00000  +0.00000 I
freq:   1  +0.00000  +0.00000 I
freq:   2  -0.00000  +0.00000 I
freq:   3  +8.00000  -0.00000 I
freq:   4  +0.00000  +0.00000 I
freq:   5  -0.00000  +0.00000 I
freq:   6  +0.00000  -0.00000 I
freq:   7  -0.00000  +0.00000 I
freq:   8  +0.00000  +0.00000 I
freq:   9  -0.00000  -0.00000 I
freq:  10  +0.00000  +0.00000 I
freq:  11  -0.00000  -0.00000 I
freq:  12  +0.00000  -0.00000 I
freq:  13  +8.00000  +0.00000 I
freq:  14  -0.00000  -0.00000 I
freq:  15  +0.00000  -0.00000 I

Inverse transform:
recover:   0  +1.00000  +0.00000 I vs.  +1.00000  +0.00000 I
recover:   1  +0.38268  +0.00000 I vs.  +0.38268  +0.00000 I
recover:   2  -0.70711  +0.00000 I vs.  -0.70711  +0.00000 I
recover:   3  -0.92388  +0.00000 I vs.  -0.92388  +0.00000 I
recover:   4  -0.00000  +0.00000 I vs.  -0.00000  +0.00000 I
recover:   5  +0.92388  +0.00000 I vs.  +0.92388  +0.00000 I
recover:   6  +0.70711  +0.00000 I vs.  +0.70711  +0.00000 I
recover:   7  -0.38268  +0.00000 I vs.  -0.38268  +0.00000 I
recover:   8  -1.00000  +0.00000 I vs.  -1.00000  +0.00000 I
recover:   9  -0.38268  +0.00000 I vs.  -0.38268  +0.00000 I
recover:  10  +0.70711  +0.00000 I vs.  +0.70711  +0.00000 I
recover:  11  +0.92388  +0.00000 I vs.  +0.92388  +0.00000 I
recover:  12  +0.00000  +0.00000 I vs.  +0.00000  +0.00000 I
recover:  13  -0.92388  +0.00000 I vs.  -0.92388  +0.00000 I
recover:  14  -0.70711  +0.00000 I vs.  -0.70711  +0.00000 I
recover:  15  +0.38268  +0.00000 I vs.  +0.38268  +0.00000 I

【讨论】:

    【解决方案2】:

    您是否至少尝试过阅读不仅仅是体面的文档?

    他们有一个完整的教程供你了解 FFTW:

    http://fftw.org/fftw3_doc/Tutorial.html#Tutorial

    更新:我假设您知道如何使用 C 数组,因为这是用作输入和输出的。

    This page 具有 FFT 与 IFFT 所需的信息(请参阅参数->符号)。文档还说 input->FFT->IFFT->n*input。因此,您必须小心正确地缩放数据。

    【讨论】:

    • 我有,但我无法解释输出以及如何在时域内返回。
    【解决方案3】:

    这是我做的。我的专门设计用于提供与 Matlab 相同的输出。这仅适用于列矩阵(您可以将AMatrix 替换为std::vector)。

    AMatrix<complex<double>> FastFourierTransform::Forward1d(const AMatrix<double> &inMat)
    {
        AMatrix<complex<double>> outMat{ inMat.NumRows(), inMat.NumCols() };
        size_t N = inMat.NumElements();
        bool isOdd = N % 2 == 1;
        size_t outSize = (isOdd) ? ceil(N / 2 + 1) : N / 2;
        fftw_plan plan = fftw_plan_dft_r2c_1d(
            inMat.NumRows(),
            reinterpret_cast<double*>(&inMat.mutData()[0]), // mutData here is as same v.data() for std::vector
            reinterpret_cast<fftw_complex*>(&outMat.mutData()[0]),
            FFTW_ESTIMATE);
        fftw_execute(plan);
    
        // mirror
        auto halfWayPoint = outMat.begin() + (outMat.NumRows() / 2) + 1;
        auto startCopyDest = (isOdd) ? halfWayPoint : halfWayPoint - 1;
        std::reverse_copy(outMat.begin() + 1, halfWayPoint, startCopyDest); // skip DC (+1)
        std::for_each(halfWayPoint, outMat.end(), [](auto &c) { return c = std::conj(c);});
    
        return std::move(outMat);
    }
    
    AMatrix<complex<double>> FastFourierTransform::Forward1d(const AMatrix<double> &inMat, size_t points)
    {
        // append zeros to matrix until it's the same size as points
        AMatrix<double> sig = inMat;
        sig.Resize(points, sig.NumCols());
        for (size_t i = inMat.NumRows(); i < points; i++)
        {
            sig(i, 0) = 0;
        }
        return Forward1d(sig);
    }
    
    AMatrix<complex<double>> FastFourierTransform::Inverse1d(const AMatrix<complex<double>> &inMat)
    {
        AMatrix<complex<double>> outMat{ inMat.NumRows(), inMat.NumCols() };
        size_t N = inMat.NumElements();
    
        fftw_plan plan = fftw_plan_dft_1d(
            inMat.NumRows(), 
            reinterpret_cast<fftw_complex*>(&inMat.mutData()[0]),
            reinterpret_cast<fftw_complex*>(&outMat.mutData()[0]),
            FFTW_BACKWARD, 
            FFTW_ESTIMATE);
        fftw_execute(plan);
    
        // Matlab normalizes
        auto normalize = [=](auto &c) { return c *= 1. / N; };
        std::for_each(outMat.begin(), outMat.end(), normalize);
    
        fftw_destroy_plan(plan);
        return std::move(outMat);
    }
    
    // From Matlab documentation: "ifft tests X to see whether vectors in X along the active dimension 
    // are conjugate symmetric. If so, the computation is faster and the output is real. 
    // An N-element vector x is conjugate symmetric if x(i) = conj(x(mod(N-i+1,N)+1)) for each element of x."
    // http://uk.mathworks.com/help/matlab/ref/ifft.html
    AMatrix<double> FastFourierTransform::Inverse1dConjSym(const AMatrix<complex<double>> &inMat)
    {
        AMatrix<double> outMat{ inMat.NumRows(), inMat.NumCols() };
        size_t N = inMat.NumElements();
    
        fftw_plan plan = fftw_plan_dft_c2r_1d(
            inMat.NumRows(), 
            reinterpret_cast<fftw_complex*>(&inMat.mutData()[0]),
            reinterpret_cast<double*>(&outMat.mutData()[0]),
            FFTW_BACKWARD | FFTW_ESTIMATE);
        fftw_execute(plan);
    
        auto normalize = [=](auto &c) { return c *= 1. / N; };
        std::for_each(outMat.begin(), outMat.end(), normalize);
    
        fftw_destroy_plan(plan);
        return std::move(outMat);
    }
    

    【讨论】:

    • 除了我们需要实现AMatrixFastFourierTransform 类之外,您的答案是最好的。如果您可以添加这些类,那就太好了。 (我会尝试实现这些,但对其他人来说,这将非常有帮助/有用)
    【解决方案4】:

    对于放大 2x 行图像非常有用

    如下例所示,将矩形信号放大 2 倍

    int main (void)
    {
      fftw_complex in[N], out[N], in2[N2], out2[N2];        /* double [2] */
      fftw_plan p, q;
      int i;
      int half;
    
      half=(N/2+1);
      /* prepare a cosine wave */
      for (i = 0; i < N; i++)
        {
          //in[i][0] = cos ( 3 * 2 * M_PI * i / N);
          in[i][0] = (i > 3 && i< 12 )?1:0;
          in[i][1] = (i > 3 && i< 12 )?1:0;
          //in[i][1] = 0;
        }
    
      /* forward Fourier transform, save the result in 'out' */
      p = fftw_plan_dft_1d (N, in, out, FFTW_FORWARD, FFTW_ESTIMATE);
      fftw_execute (p);
      for (i = 0; i < N; i++)
        printf ("input: %3d %+9.5f %+9.5f I   %+9.5f %+9.5f I\n", i, in[i][0], in[i][1],out[i][0],out[i][1]);
      fftw_destroy_plan (p);
    
      for (i = 0; i<N2; i++) {out2[i][0]=0.;out2[i][1]=0.;}
    
      for (i = 0; i<half; i++) {
        out2[i][0]=2.*out[i][0];
        out2[i][1]=2.*out[i][1];
      }
      for (i = half;i<N;i++) {
        out2[N+i][0]=2.*out[i][0];
        out2[N+i][1]=2.*out[i][1];
      }
    
    
    
      /* backward Fourier transform, save the result in 'in2' */
      printf ("\nInverse transform:\n");
      q = fftw_plan_dft_1d (N2, out2, in2, FFTW_BACKWARD, FFTW_ESTIMATE);
      fftw_execute (q);
      /* normalize */
      for (i = 0; i < N2; i++)
        {
          in2[i][0] /= N2;
          in2[i][1] /= N2;
        }
      for (i = 0; i < N2; i++)
        printf ("recover: %3d %+9.1f %+9.1f I\n",
                i, in2[i][0], in2[i][1]);
      fftw_destroy_plan (q);
    
      fftw_cleanup ();
      return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-08-14
      • 2014-10-06
      • 1970-01-01
      • 1970-01-01
      • 2010-12-13
      • 1970-01-01
      • 2012-08-11
      • 1970-01-01
      相关资源
      最近更新 更多