使用英特尔 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_COMPLEX
和 DFTI_REAL
,但没有混合转换的选项。
编辑
我发现相位其实等于atan(imaginary/real)
。我不想误导任何从问题中获取信息的人。
编辑
刚知道最好用atan2(imaginary,real)
。更多信息在评论中。
每个实数都是复数:ℝ ⊂ ℤ。因此,从时域中的 float
或 double
前进到 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++ 库中有些东西过于复杂,以至于您必须打开引用,否则您将不记得如何使用它。参见例如混乱称为随机数支持。啊。但是复数支持相对健全,甚至遵循复数算术教学中使用的符号:)
我正在编写一个音频插件,我想将代表样本值的一系列实数转换为代表频率和相位的复杂数组。然后我希望能够做相反的事情,将一个复杂的频率和相位数组变成一系列实数,重建原始数据。
我正在使用英特尔 MKL,我只看到了执行实数->实数转换或复数->复数转换的可能性。这是我正在使用的参考:Intel MKL FFT Functions。
在该参考文献中,有两个重载函数:DftiComputeForward 和 DftiComputeBackward。所以,我想用这些来做转换。在 DftiCreateDescriptor
的参考中,DFTI_FORWARD_DOMAIN
可用的选项只有 DFTI_COMPLEX
和 DFTI_REAL
,但没有混合转换的选项。
编辑
我发现相位其实等于atan(imaginary/real)
。我不想误导任何从问题中获取信息的人。
编辑
刚知道最好用atan2(imaginary,real)
。更多信息在评论中。
每个实数都是复数:ℝ ⊂ ℤ。因此,从时域中的 float
或 double
前进到 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++ 库中有些东西过于复杂,以至于您必须打开引用,否则您将不记得如何使用它。参见例如混乱称为随机数支持。啊。但是复数支持相对健全,甚至遵循复数算术教学中使用的符号:)