使用JTransforms库计算FFT的自相关

我正在尝试使用下面的代码计算时间序列中的样本窗口的自相关。 我正在对该窗口应用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; 

第一个问题是:可以看出这个代码将自相关结果映射到[0,1]范围,尽管相关性应该在-1和1之间。当然很容易将结果映射到[-1,1]范围,但我不确定这种映射是否正确。 我们如何解释生成的autocorr数组中的值?

其次,使用这段代码,我对某些周期序列产生了良好的结果,即根据信号周期得到特定自相关指数的更高值。 然而,当我将它应用于非周期性信号时结果很奇怪: autocorr数组中的所有值似乎都非常接近1.这是什么原因?

要使基于FFT的算法起作用,您必须特别注意定义,包括您正在使用的库的约定。 您似乎混淆了AC的“信号处理”惯例和“统计”惯例。 然后是FFT包装和零填充。

这是一个适用于偶数N情况信号处理惯例的代码。 它是针对powershell包裹的自相关进行测试的。 评论显示了如何将其转换为信号处理惯例。 对于统计ac,减去数据的平均值。 这可以仅通过将FFT的“0Hz”分量归零来完成。 然后ac的第零个元素是方差,你可以通过除以这个数量来标准化。 如你所说,结果值将落在-1..1。

您的代码似乎正在进行分割,但不会忽略数据的0 Hz分量。 所以它正在计算某种约定的mashup。

 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(); } }