繁体   English   中英

fftw:为什么我的 2D DFT 输出与每行的 1D DFT 输出不同?

[英]fftw: Why is my 2D DFT output not the same as the output from taking 1D DFT of each row?

对于我的项目,我必须对大型 2D 输入矩阵进行 DFT,对其进行处理,然后使用 IDFT 将其转换回并将结果与​​输入矩阵进行比较。 我的问题出在 2D DFT 步骤中。 我用一个小的简单数据集写了一个测试,我在main()执行。 我将Eigen库用于矩阵和向量。 输出是这样的:

Using testM in a myTransform object:
1 2 3
4 5 6
7 8 9
calculateDFT took 33 Microseconds
DFT
          (6,0)
(-1.5,0.866025)
(-1.5,0.866025)
         (15,0)
(-1.5,0.866025)
(-1.5,0.866025)
         (24,0)
(-1.5,0.866025)
(-1.5,0.866025)
IDFT
1 2 3 4 5 6 7 8 9
Using testM in a myTransform2D object:
1 2 3
4 5 6
7 8 9
Default myTransform object created
DFT2D
          (45,0)  (-4.5,-2.59808)          (45,-0)
          (45,0) (-13.5,-7.79423)          (45,-0)
          (45,0)           (0,-0)          (45,-0)
IDFT
27.5 -0.5 -1.5 -8.5  8.5  7.5   -7   10    9

在下面的片段中, this->N = this->nRows * this->nCols 测试 1 和测试 2 的结果应该是相同的,但它们明显不同。 我一遍又一遍地阅读文档,但仍然找不到为什么会出错。 fftw 进行行主多维变换, in矩阵的每一行中填充。 transfer_output函数不会对值本身做任何事情,只会将标准数组转换为Eigen::Matrix 我哪里错了? 任何帮助将不胜感激。 我也试图在这里找到类似的帖子,但据我所知,没有一个有我的问题。

void test()
{
    RowVectorXf test(9);
    test << 1, 2, 3, 4, 5, 6, 7, 8, 9;
    // Prep matrix 
    Map<Matrix<float, 3, 3, RowMajor>> testM(test.data()); // convert test to rowmajor matrix

    // Test 1: feed the matrix to a myTransform object and take 1D DFTs and 1D IDFTs 
    std::cout << "Using testM in a myTransform object:\n" << testM << std::endl;
    myTransform testX1D(testM, 0);
    testX1D.vectorise();
    testX1D.calculateDFT();
    testX1D.calculateIDFT();
    std::cout << "DFT" << std::endl << testX1D.dft << std::endl;
    std::cout << "IDFT" << std::endl << testX1D.idft << std::endl; // works, too.

    .. Test 2: Feed the matrix to a myTransform2D object and take the 2D DFT and IDFT.
    std::cout << "Using testM in a myTransform2D object:\n" << testM << std::endl;
    myTransform2D testX(testM, 0); // 2D version 
    testX.vectorise(); // stored in testX.m which will hold the same as test but in a colmajor vector.
    testX.calculateDFT(); // where it goes wrong?
    std::cout << "DFT2D" << std::endl << testX.dft2D << std::endl;
    testX.calculateIDFT();
    std::cout << "IDFT" << std::endl << testX.idft << std::endl;
}

这就是我在每种情况下计算 DFT 的方式,使用 fftw 库(fftwf 因为我使用单精度来节省内存,并且非测试数据的值在 -10000 到 10000 的数量级上,所以我认为这不是一个问题)。

void myTransform::calculateDFT()
/// Calculates discrete fourier transform of vectorised data `m`.
/** uses the FFTW library (https://fftw.org). The dft is stored in myTransform::dft*/
{
    //std::cout << m << std::endl;
    fftwf_complex* out;
    fftwf_plan p;
    out = (fftwf_complex*)fftw_malloc(sizeof(fftwf_complex) * this->nCols);
    float* in = new float[static_cast<const float&>(this->nCols)];
    p = fftwf_plan_dft_r2c_1d(this->nCols, in, out, FFTW_ESTIMATE);
    // calculate DFT for each trace and assign it to a segment of this->dft
    unsigned int factor = 0;
    auto check = std::chrono::high_resolution_clock::now();
    for (int k = 0; k < this->nRows; k++)
    {
        factor = k * this->nCols;
        //TODO: if possible, fix this slow in[i] = ... part. 
        for (int i = 0; i < this->nCols; i++)
        {
            in[i] = this->m[factor + i];
        }
        p = fftwf_plan_dft_r2c_1d(this->nCols, in, out, FFTW_ESTIMATE);
        fftwf_execute(p);
        this->transfer_output(out, k); // does nothing but add the output to a vector dft. 
    }
    delete [] in;
    fftwf_free(out);
    fftwf_destroy_plan(p);
}

对于 2D DFT 情况:这里我使用fftw.org 上指定的 std::complex 。 我按照此处的说明分配nRows * (nCols/2 + 1)单精度浮点数。 对于一维情况,这是在一维transfer_output函数中完成的,其中dftout[this->nCols - i] for i > this->nCols/2

void myTransform2D::calculateDFT()
/// Should calculate the DFT in 2D with fftwf_plan_dft_r2c_2d(n0, n1, *in, *out, flags).
{
    std::complex<float>* out;
    fftwf_plan p;
    out = (std::complex<float>*)fftwf_malloc(sizeof(std::complex<float>) * this->nRows * (this->nCols/2+1)); // Hermitian symmetry for r2c transforms
    float* in = new float[this->N];
    in = (float*)fftwf_malloc(sizeof(float) * this->N);
    p = fftwf_plan_dft_r2c_2d(this->nRows, this->nCols, in, reinterpret_cast<fftwf_complex*>(out), FFTW_ESTIMATE);
    // Fill input array
    for (int i = 0; i < this->nRows; i++)
    {
        int factor = i * this->nCols;
        for (int j = 0; j < this->nCols; j++)
        {
            in[factor + j] = this->m[factor + j];
        }
    }
    fftwf_execute(p);
    transfer_output(out);
    fftwf_free(in);
    fftwf_free(out);
    fftwf_destroy_plan(p);
}

我使用 IDFT 转换回时域,同样是 1D 和 2D。 我不确定 2D 版本是否有效,因为 DFT 出错了。 一维案例有效,所以我只展示二维案例。

void myTransform2D::calculateIDFT()
/// Calculates inverse fourier transform of `this->dft2D`.
/** Also uses the FFTW library. Results might not be perfect as we use floats
    instead of doubles because of large data sizes. */
{
    float* out = new float[this->N];
    std::complex<float>* in; 
    fftwf_plan pr;
    in = (std::complex<float>*)fftwf_malloc(sizeof(std::complex<float>) * this->N);
    out = (float*)fftwf_malloc(sizeof(float) * this->N);
    pr = fftwf_plan_dft_c2r_2d(this->nRows, this->nCols, reinterpret_cast<fftwf_complex*>(in), out, FFTW_ESTIMATE);

    for (int i = 0; i < this->nRows; i++)
    {
        for (int j = 0; j < this->nCols; j++)
        {
            in[i * this->nCols + j] = this->dft2D(i, j);
        }
    }

    fftwf_execute(pr);

    for (int i = 0; i < this->N; i++)
    {
        this->idft[i] = out[i] / this->N; // fftw does unnormalized inverse transforms.
    }

    fftwf_free(out);
    fftwf_free(in);
    fftwf_destroy_plan(pr);
}

编辑:按照建议删除了一些代码 EDIT2:删除了图像,将内容添加为文本。

如果没有任何人都可以编译和测试的完全可重现的示例,就很难回答这个问题。 所以我将给出执行2D向前和向后变换的代码和参考结果。

向前。

const auto fft_size = n * (n / 2 + 1);
auto out = (std::complex<float>*)fftwf_malloc(sizeof(std::complex<float>) * fft_size);
auto p = fftwf_plan_dft_r2c_2d(n, n, in, (fftwf_complex*)(out), FFTW_ESTIMATE);
fftwf_execute(p);

for (std::size_t i = 0; i < fft_size; ++i)
    std::cout << *(out + i) << ' ';

对于行主序的矩阵

1 2 3
4 5 6
7 8 9

正确的输出是:

(45,0) (-4.5,2.59808) (-13.5,7.79423) (0,0) (-13.5,-7.79423) (0,0)

落后。

auto in2 = (float*)fftwf_malloc(sizeof(float) * n * n);
auto p2 = fftwf_plan_dft_c2r_2d(n, n, (fftwf_complex*)(out), in2, FFTW_ESTIMATE);
fftwf_execute(p2);

for (std::size_t row = 0; row < n; ++row) {
    for (std::size_t col = 0; col < n; ++col)
        std::cout << *(in2 + col + row * n) / (n * n) << ' ';
    std::cout << std::endl;
}

这将输出原始矩阵。


请注意,正向变换 ( fft_size ) 的输出大小是n * (n / 2 + 1)而不是n * n 在输出我看到9个复杂条目,而不是6的大小in的功能calculateIDFT()也错了,你的值复制到它的方式也许是错误的,太。

暂无
暂无

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

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