有关于如何使用英特尔MKL FFT的简单C ++示例吗?

时间:2015-04-22 18:15:14

标签: c++ fft intel-mkl dft

我需要执行FFT和逆FFT变换。输入将是double的向量和矩阵。理想情况下,输出应该是std :: complex的数组,但我可以使用double _Complex。

我还没有找到任何简单的例子,所有英特尔示例都会在没有足够评论的情况下同时做很多事情。

我只想在C ++中使用一个简单的示例,将double的向量(或矩阵)作为输入并输出FFT转换结果(理想情况下使用std :: complex)。

3 个答案:

答案 0 :(得分:8)

我最终测试了几件事情,最后我最终得到了这三个功能,这些功能可以满足我的需求,我考虑过简单的例子。

我对一些输入进行了测试,结果很好。我还没有做过广泛的测试。

//Note after each operation status should be 0 on success 

std::vector<std::complex<float>> fft_complex(std::vector<std::complex<float>>& in){
    std::vector<std::complex<float>> out(in.size());

    DFTI_DESCRIPTOR_HANDLE descriptor;
    MKL_LONG status;

    status = DftiCreateDescriptor(&descriptor, DFTI_SINGLE, DFTI_COMPLEX, 1, in.size()); //Specify size and precision
    status = DftiSetValue(descriptor, DFTI_PLACEMENT, DFTI_NOT_INPLACE); //Out of place FFT
    status = DftiCommitDescriptor(descriptor); //Finalize the descriptor
    status = DftiComputeForward(descriptor, in.data(), out.data()); //Compute the Forward FFT
    status = DftiFreeDescriptor(&descriptor); //Free the descriptor

    return out;
}

std::vector<std::complex<float>> fft_real(std::vector<float>& in_real){
    std::vector<std::complex<float>> in(in_real.size());

    std::copy(in_real.begin(), in_real.end(), in.begin());

    return fft_complex(in);
}

std::vector<float> ifft(std::vector<std::complex<float>>& in){
    std::vector<std::complex<float>> out(in.size());

    DFTI_DESCRIPTOR_HANDLE descriptor;
    MKL_LONG status;

    status = DftiCreateDescriptor(&descriptor, DFTI_SINGLE, DFTI_COMPLEX, 1, in.size()); //Specify size and precision
    status = DftiSetValue(descriptor, DFTI_PLACEMENT, DFTI_NOT_INPLACE); //Out of place FFT
    status = DftiSetValue(descriptor, DFTI_BACKWARD_SCALE, 1.0f / in.size()); //Scale down the output
    status = DftiCommitDescriptor(descriptor); //Finalize the descriptor
    status = DftiComputeBackward(descriptor, in.data(), out.data()); //Compute the Forward FFT
    status = DftiFreeDescriptor(&descriptor); //Free the descriptor

    std::vector<float> output(out.size());

    for(std::size_t i = 0; i < out.size(); ++i){
        output[i] = out[i].real();
    }

    return output;
}

答案 1 :(得分:0)

尝试使用Developer Reference for Intel® Math Kernel Library - C的INTEL。有将FFT函数与Intel MKL以及OpenMP一起使用的示例。

答案 2 :(得分:0)

虽然 Baptiste's answer 有效,但在将傅立叶变换应用于实数值时,通常人们希望使用更高效的版本。

对于实数值的傅立叶变换 F,以下成立:

F(k) = conj(F(-k))

因此只需要计算大约一半的值。使用 mkl 的实傅立叶变换得到以下代码:

//helper function for fft and ifft:
DFTI_DESCRIPTOR* create_descriptor(MKL_LONG length) {
    DFTI_DESCRIPTOR* handle = nullptr;
    // using DFTI_DOUBLE for double precision
    // using DFTI_REAL for using the real version
    bool valid = (DFTI_NO_ERROR == DftiCreateDescriptor(&handle, DFTI_DOUBLE, DFTI_REAL, 1, length)) &&
        // the result should not be inplace:
        (DFTI_NO_ERROR == DftiSetValue(handle, DFTI_PLACEMENT, DFTI_NOT_INPLACE)) &&
        // make clear that the result should be a vector of complex:
        (DFTI_NO_ERROR == DftiSetValue(handle, DFTI_CONJUGATE_EVEN_STORAGE, DFTI_COMPLEX_COMPLEX));
        // chosen normalization is fft(constant)[0] = constant:
        (DFTI_NO_ERROR == DftiSetValue(handle, DFTI_FORWARD_SCALE, 1. / length)) &&
        (DFTI_NO_ERROR == DftiCommitDescriptor(handle));
    if (!valid) {
        DftiFreeDescriptor(&handle);
        return nullptr; //nullptr means error
    }
    return handle;
}

std::vector<std::complex<double>> real_fft(std::vector<double>& in) {
    size_t out_size = in.size() / 2 + 1; //so many complex numbers needed
    std::vector<std::complex<double>> result(out_size);
    DFTI_DESCRIPTOR* handle = create_descriptor(static_cast<MKL_LONG>(in.size()));
    bool valid = handle &&
        (DFTI_NO_ERROR == DftiComputeForward(handle, in.data(), result.data()));
    if (handle) {
        valid &= (DFTI_NO_ERROR == DftiFreeDescriptor(&handle));
    }
    if (!valid) {
        result.clear(); //empty vector -> error
    }
    return result;
}

对于逆版本,我们需要知道原始向量的大小——这个信息不能从傅立叶变换中恢复。虽然我们知道,如果原始实向量具有偶数个元素,则傅立叶变换中的最后一个元素为实数,但我们不能从傅立叶变换的最后一个元素为实数得出原始实向量具有偶数个元素!这就是反函数签名有点奇怪的原因:

std::vector<double> real_fft(std::vector<std::complex<double>> & in, size_t original_size) {
    size_t expected_size = original_size / 2 + 1;
    if (expected_size != in.size()) {
        return {};// empty vector -> error
    }
    std::vector<double> result(original_size);
    DFTI_DESCRIPTOR* handle = create_descriptor(static_cast<MKL_LONG>(original_size));
    bool valid = handle &&
        (DFTI_NO_ERROR == DftiComputeBackward(handle, in.data(), result.data()));
    if (handle) {
        valid &= (DFTI_NO_ERROR == DftiFreeDescriptor(&handle));
    }
    if (!valid) {
        result.clear(); //empty vector -> error
    }
    return result;
}

注意:向前和向后转换使用相同的描述符。