Computing Autocorrelation with FFT Using JTransforms Library

前端 未结 1 1054
旧时难觅i
旧时难觅i 2021-02-08 12:34

I\'m trying to calculate autocorrelation of sample windows in a time series using the code below. I\'m applying FFT to that window, then computing magnitudes of real and imagina

1条回答
  •  有刺的猬
    2021-02-08 13:20

    For FFT-based algorithms to work, you must pay careful attention to the definitions, including conventions of the library you are using. You seem to be confusing the "signal processing" convention for AC and the "statistical" one. And then there is FFT wrapping and zero padding.

    Here is a code that's working for the even N case, signal processing convention. It's tested against a brute force wrapped autocorrelation. The comments show how to convert it to the signal processing convention. For statistical ac, the mean of the data is subtracted out. This can be done merely by zeroing out the "0Hz" component of the FFT. Then the zero'th element of the ac is the variance, and you can normalize by dividing through by this quantity. The resulting values will fall in -1..1 as you say.

    Your code seems to be doing the dividing through, but not ignoring the 0 Hz component of the data. So it's computing some kind of mashup of the conventions.

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

    0 讨论(0)
提交回复
热议问题