使用 FFT 计算两个信号之间的相关性
Calculating correlation with FFT between two signals
我在获得两组值之间相关性的正确结果时遇到问题(我知道结果是错误的,因为我已经尝试计算 Octave 中的相关性)(我也在计算 post 说)。
我一直在使用一个库,我发现它是用 C 编写的,位于:http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html
它的文档比较少,我也没有多少计算 FFT 的经验。
该程序的结果示例和 Octave 的结果如下:
这两个向量是:
a = [1 2 1 1 0 0 0 0], b = [0 0 0 0 1 3 1 1]
向量a和b在Octave上的fft结果为:
而相同向量的fft结果为(分为实数和虚数):
函数输出原为:
5
-1
1.70711
3.12132
0
1个
0.292893
1.12132
(实数和虚数的划分是按照文档中的说明进行的)
现在,当我乘以(我正在使用逐元素乘法)包含 DFT 结果的两个向量(我正在使用 Real DFT)时,我的问题就开始了,因为 Octave 的结果与我的程序
我的乘法密码是:
for (j = 0; j < n; j++) {
a[j] = a[j] * b[j];
}
结果是:
这就是我目前卡住的地方。
主要问题在于...鼓声...乘法(根据您的 "my problem starts when I multiply" 陈述,您已经猜到了)!
时域中的卷积(具有足够的零填充)在频域中等效于频谱的 复数 乘法。在 Octave 中,这就是 *
运算符所做的。对于 C 或 C++ 中的 float
或 double
数组,*
运算符仅将实部或虚部相乘。
要将光谱的复数相乘,考虑到指定的数据打包顺序,您可以改用:
a[0] = a[0] * b[0]; // a[0] corresponds to real-valued bin 0
a[1] = a[1] * b[1]; // a[1] corresponds to real-valued bin n/2
for (j = 1; j < n/2; j++) {
tmp = (a[2*j]*b[2*j] - a[2*j+1]*b[2*j+1]); // real-part
a[2*j+1] = (a[2*j]*b[2*j+1] + a[2*j+1]*b[2*j]); // imaginary-part
a[2*j] = tmp;
}
备注:
- C FFT implementation取实值输入,只return频谱的非冗余下半部分(上半部分可以通过对称获得)。逆变换将相应地采用频谱的非冗余下半部分并计算相应的实值序列(因此在这种情况下只处理一半频谱不是问题)。
- 此外,您可能已经注意到,您使用的 C FFT implementation 基于与 Octave 不同的 DFT 定义(它使用带正参数的指数)。只要您还使用一致的逆变换(即指数具有负参数的逆变换),这就不是问题。出于比较目的,您的 C FFT implementation 结果对应于 Octave 结果的复共轭。
我在获得两组值之间相关性的正确结果时遇到问题(我知道结果是错误的,因为我已经尝试计算 Octave 中的相关性)(我也在计算 post 说)。 我一直在使用一个库,我发现它是用 C 编写的,位于:http://www.kurims.kyoto-u.ac.jp/~ooura/fft.html
它的文档比较少,我也没有多少计算 FFT 的经验。
该程序的结果示例和 Octave 的结果如下:
这两个向量是: a = [1 2 1 1 0 0 0 0], b = [0 0 0 0 1 3 1 1]
向量a和b在Octave上的fft结果为:
而相同向量的fft结果为(分为实数和虚数):
函数输出原为:
5 -1 1.70711 3.12132 0 1个 0.292893 1.12132
(实数和虚数的划分是按照文档中的说明进行的)
现在,当我乘以(我正在使用逐元素乘法)包含 DFT 结果的两个向量(我正在使用 Real DFT)时,我的问题就开始了,因为 Octave 的结果与我的程序
我的乘法密码是:
for (j = 0; j < n; j++) {
a[j] = a[j] * b[j];
}
结果是:
这就是我目前卡住的地方。
主要问题在于...鼓声...乘法(根据您的 "my problem starts when I multiply" 陈述,您已经猜到了)!
时域中的卷积(具有足够的零填充)在频域中等效于频谱的 复数 乘法。在 Octave 中,这就是 *
运算符所做的。对于 C 或 C++ 中的 float
或 double
数组,*
运算符仅将实部或虚部相乘。
要将光谱的复数相乘,考虑到指定的数据打包顺序,您可以改用:
a[0] = a[0] * b[0]; // a[0] corresponds to real-valued bin 0
a[1] = a[1] * b[1]; // a[1] corresponds to real-valued bin n/2
for (j = 1; j < n/2; j++) {
tmp = (a[2*j]*b[2*j] - a[2*j+1]*b[2*j+1]); // real-part
a[2*j+1] = (a[2*j]*b[2*j+1] + a[2*j+1]*b[2*j]); // imaginary-part
a[2*j] = tmp;
}
备注:
- C FFT implementation取实值输入,只return频谱的非冗余下半部分(上半部分可以通过对称获得)。逆变换将相应地采用频谱的非冗余下半部分并计算相应的实值序列(因此在这种情况下只处理一半频谱不是问题)。
- 此外,您可能已经注意到,您使用的 C FFT implementation 基于与 Octave 不同的 DFT 定义(它使用带正参数的指数)。只要您还使用一致的逆变换(即指数具有负参数的逆变换),这就不是问题。出于比较目的,您的 C FFT implementation 结果对应于 Octave 结果的复共轭。