如何使用FFTW正确执行多维离散余弦变换?

问题描述

我正在使用FFTW library来执行C ++中的多维II型离散余弦变换(DCT)及其逆变换,即III型DCT。当我分别执行每个变换(沿着每个模式/维度一个)时,一切都按预期工作。但是,当我同时转换所有模式/尺寸时,输出完全不同,并且我也无法正确地转换结果。然而,根据FFTW documentation

通常,FFTW的多维变换只计算沿数组每个维度的给定1d变换的可分离积。

以下示例演示了我的问题:

#include <fftw3.h>
#include <vector>
#include <numeric>
#include <iostream>

template<typename T>
void print_vector(const std::vector<T>& vector) {
    std::cout << "[";
    for (size_t i = 0; i < vector.size(); i++) {
        std::cout << vector[i];
        if (i < vector.size() - 1)
            std::cout << ",";
    }
    std::cout << "]" << std::endl;
}

// Performs multiple DCT's (or their inverses) in-place on one or more modes of the given data
void dct(int modes_to_transform,const int* transform_sizes,int amount,double* data,const int* transform_strides,int element_stride,int distance,bool inverse = false) {
    fftw_r2r_kind kind = inverse ? FFTW_REDFT01 : FFTW_REDFT10;
    fftw_execute(fftw_plan_many_r2r(modes_to_transform,transform_sizes,amount,data,transform_strides,element_stride,distance,&kind,FFTW_ESTIMATE
    ));
}

// Performs a DCT (or its inverse) in-place on one or more modes of the given data
void single_dct(int modes_to_transform,bool inverse = false) {
    fftw_r2r_kind kind = inverse ? FFTW_REDFT01 : FFTW_REDFT10;
    fftw_execute(fftw_plan_r2r(modes_to_transform,FFTW_ESTIMATE));
}

void scale_vector(std::vector<double>& vector,double factor) {
    for (auto& val : vector)
        val *= factor;
}

int main() {
    
    // Initialize data
    size_t size = 9;
    std::vector<double> original_data(size);
    std::iota(original_data.begin(),original_data.end(),0);
    std::cout << "Starting data:" << std::endl;
    print_vector(original_data);
    std::vector<double> data;
    std::vector<int> transform_sizes;
    
    // Method 1: transform each mode separately
    data = original_data;
    transform_sizes = {3};
    dct(1,transform_sizes.data(),3,data.data(),1,3);
    dct(1,1);
    std::cout << "\nMethod 1:" << std::endl;
    print_vector(data);
    dct(1,true);
    dct(1,true);
    std::cout << "Reconstructed:" << std::endl;
    print_vector(data);
    // Each transform + inverse scales the data by 2*transform_size
    scale_vector(data,1.0/(2*2*data.size()));
    std::cout << "Renormalized:" << std::endl;
    print_vector(data);
    
    // Method 2: simultaneously transform both modes
    data = original_data;
    transform_sizes = {3,3};
    dct(2,9);
    std::cout << "\nMethod 2:" << std::endl;
    print_vector(data);
    dct(2,9,1.0/(2*2*data.size()));
    std::cout << "Renormalized:" << std::endl;
    print_vector(data);
    
    // Method 3: simultaneously transform both modes using basic interface
    data = original_data;
    transform_sizes = {3,3};
    single_dct(2,data.data());
    std::cout << "\nMethod 3:" << std::endl;
    print_vector(data);
    single_dct(2,1.0/(2*2*data.size()));
    std::cout << "Renormalized:" << std::endl;
    print_vector(data);
    
    return 0;
    
}

这给了我以下输出

Starting data:
[0,2,4,5,6,7,8]

Method 1:
[144,-20.7846,1.33227e-15,-62.3538,3.55271e-15,0]
Reconstructed:
[-1.42109e-14,36,72,108,144,180,216,252,288]
Renormalized:
[-3.94746e-16,8]

Method 2:
[72,-9,5.19615,-31.1769,1.77636e-15,0]
Reconstructed:
[14.1962,19.9019,12.2942,68.1962,73.9019,122.196,127.902,12.2942]
Renormalized:
[0.394338,0.552831,0.341506,1.89434,2.05283,3.39434,3.55283,0.341506]

Method 3:
[72,0.341506]

方法1给出了预期的输出(并且可以正确地反转),而方法2和方法3(使用更基本的接口)都给出了相同的错误结果。您可以看到,即使转换后的数据中的非零模式也有所不同,因此,不只是将正确的归一化系数应用于每个系数的问题。在此示例代码方法1中,可以将其视为解决该问题的方法,但是在实践中,我正在使用具有任意数量的模式/尺寸的张量,因此这很不方便。

有人看到这个问题吗?我看了很多文档,却找不到我做错了什么...

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)