使用英特尔 MKL 将实时域数据转换为复杂的频率和相位数据以及逆向数据

Using Intel MKL to convert real time domain data to complex frequency and phase data and the inverse as well

我正在编写一个音频插件,我想将代表样本值的一系列实数转换为代表频率和相位的复杂数组。然后我希望能够做相反的事情,将一个复杂的频率和相位数组变成一系列实数,重建原始数据。

我正在使用英特尔 MKL,我只看到了执行实数->实数转换或复数->复数转换的可能性。这是我正在使用的参考:Intel MKL FFT Functions

在该参考文献中,有两个重载函数:DftiComputeForward 和 DftiComputeBackward。所以,我想用这些来做转换。在 DftiCreateDescriptor 的参考中,DFTI_FORWARD_DOMAIN 可用的选项只有 DFTI_COMPLEXDFTI_REAL,但没有混合转换的选项。

编辑 我发现相位其实等于atan(imaginary/real)。我不想误导任何从问题中获取信息的人。

编辑 刚知道最好用atan2(imaginary,real)。更多信息在评论中。

每个实数都是复数:ℝ ⊂ ℤ。因此,从时域中的 floatdouble 前进到 complex 是微不足道的。该语言会为您做到这一点!

#include <complex>
#include <iostream>
int main() {
    double d = 42.0;
    std::complex<double> z = d;
    std::cout << d << " = " << z << '\n';
}

输出:42 = (42,0)

而且 C++ 标准库还可以完成其他所有工作。事实上,这很简单。这一次,该库几乎完全按照包装盒上的说明进行操作。

更好:std::complex 提供数组访问。您可以通过引用或指针将 std::complex<T> 重新解释为 T[2]。因此,std::complex 可以是其身份的 "stripped",并传递到需要成对浮点数或成对双精度数的任何较低级别 API。

复数频域数据可以进行幅度和相位的相互转换,如下:

#include <complex>
#include <iostream>
int main() {
    std::complex<double> z{0.7071, 0.7071};
    double magnitude = abs(z);
    double phase = arg(z); // in radians

    std::cout << z << " ≈ (" << magnitude << "∠" << phase*180.0/M_PI << "°)\n";

    std::complex<double> z2 = std::polar(magnitude, phase);
    std::cout << " ≈ " << z2 << '\n';
}

输出:

(0.7071,0.7071) ≈ (0.99999∠45°)
 ≈ (0.7071,0.7071)

一旦您获得 "real" 数据,时域数据的虚部不太可能为零 - 这取决于您将对频域数据进行何种处理。您要转换回的是每个复杂时间样本的幅度,使用 abs 函数。

C++ 库中有些东西过于复杂,以至于您必须打开引用,否则您将不记得如何使用它。参见例如混乱称为随机数支持。啊。但是复数支持相对健全,甚至遵循复数算术教学中使用的符号:)