繁体   English   中英

使用FFTW库C ++计算FFT和IFFT

[英]Computing FFT and IFFT with FFTW library C++

我正在尝试计算FFT然后IFFT只是试试我是否可以得到相同的信号,但我不确定如何实现它。 我就是这样做的FFT:

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

这是一个例子。 它做了两件事。 首先,它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

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

他们有一个完整的教程,让您了解FFTW:

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

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

此页面包含FFT与IFFT所需的信息(请参阅参数 - >符号)。 文档还说输入 - > FFT-> IFFT-> n *输入。 因此,您必须小心正确地扩展数据。

对magnify2x图像行非常有用

如下例所示,放大因子2 rect信号

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;
}

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

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);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM