mos*_*tar 10 java fft time-series correlation
我正在尝试使用下面的代码计算时间序列中的样本窗口的自相关.我正在对该窗口应用FFT,然后计算实部和虚部的大小并将虚部设置为零,最后对其进行逆变换以获得自相关:
DoubleFFT_1D fft = new DoubleFFT_1D(magCnt);
fft.realForward(magFFT);
magFFT[0] = (magFFT[0] * magFFT[0]);
for (int i = 1; i < (magCnt - (magCnt%2)) / 2; i++) {
magFFT[2*i] = magFFT[2*i] * magFFT[2*i] + magFFT[2*i + 1] * magFFT[2*i + 1];
magFFT[2*i + 1] = 0.0;
}
if (magCnt % 2 == 0) {
magFFT[1] = (magFFT[1] * magFFT[1]);
} else {
magFFT[magCnt/2] = (magFFT[magCnt-1] * magFFT[magCnt-1] + magFFT[1] * magFFT[1]);
}
autocorr = new double[magCnt];
System.arraycopy(magFFT, 0, autocorr, 0, magCnt);
DoubleFFT_1D ifft = new DoubleFFT_1D(magCnt);
ifft.realInverse(autocorr, false);
for (int i = 1; i < autocorr.length; i++)
autocorr[i] /= autocorr[0];
autocorr[0] = 1.0;
Run Code Online (Sandbox Code Playgroud)
第一个问题是:可以看出这个代码将自相关结果映射到[0,1]范围,虽然相关性应该在-1和1之间.当然很容易将结果映射到[-1,1]范围,但我不确定这个映射是正确的.我们如何解释结果autocorr数组中的值?
其次,使用这段代码,我对某些周期序列产生了良好的结果,即根据信号周期得到特定自相关指数的更高值.然而,当我将它应用于非周期性信号时,结果很奇怪:autocorr数组中的所有值看起来都非常接近1.这是什么原因?
为了使基于 FFT 的算法发挥作用,您必须仔细注意定义,包括您正在使用的库的约定。您似乎混淆了 AC 的“信号处理”约定和“统计”约定。然后是 FFT 环绕和零填充。
这是适用于偶数 N 情况(信号处理约定)的代码。它针对强力包装自相关进行了测试。注释显示了如何将其转换为信号处理约定。对于统计 ac,减去数据的平均值。这只需将 FFT 的“0Hz”分量清零即可完成。那么 ac 的第 0 个元素就是方差,您可以通过除以该量来进行归一化。正如你所说,结果值将落在 -1..1 内。
您的代码似乎正在进行除法,但没有忽略数据的 0 Hz 分量。所以它正在计算某种约定的混搭。
import edu.emory.mathcs.jtransforms.fft.DoubleFFT_1D;
import java.util.Arrays;
public class TestFFT {
void print(String msg, double [] x) {
System.out.println(msg);
for (double d : x) System.out.println(d);
}
/**
* This is a "wrapped" signal processing-style autocorrelation.
* For "true" autocorrelation, the data must be zero padded.
*/
public void bruteForceAutoCorrelation(double [] x, double [] ac) {
Arrays.fill(ac, 0);
int n = x.length;
for (int j = 0; j < n; j++) {
for (int i = 0; i < n; i++) {
ac[j] += x[i] * x[(n + i - j) % n];
}
}
}
private double sqr(double x) {
return x * x;
}
public void fftAutoCorrelation(double [] x, double [] ac) {
int n = x.length;
// Assumes n is even.
DoubleFFT_1D fft = new DoubleFFT_1D(n);
fft.realForward(x);
ac[0] = sqr(x[0]);
// ac[0] = 0; // For statistical convention, zero out the mean
ac[1] = sqr(x[1]);
for (int i = 2; i < n; i += 2) {
ac[i] = sqr(x[i]) + sqr(x[i+1]);
ac[i+1] = 0;
}
DoubleFFT_1D ifft = new DoubleFFT_1D(n);
ifft.realInverse(ac, true);
// For statistical convention, normalize by dividing through with variance
//for (int i = 1; i < n; i++)
// ac[i] /= ac[0];
//ac[0] = 1;
}
void test() {
double [] data = { 1, -81, 2, -15, 8, 2, -9, 0};
double [] ac1 = new double [data.length];
double [] ac2 = new double [data.length];
bruteForceAutoCorrelation(data, ac1);
fftAutoCorrelation(data, ac2);
print("bf", ac1);
print("fft", ac2);
double err = 0;
for (int i = 0; i < ac1.length; i++)
err += sqr(ac1[i] - ac2[i]);
System.out.println("err = " + err);
}
public static void main(String[] args) {
new TestFFT().test();
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6684 次 |
| 最近记录: |