15

Is it possible to perform circular cross-/auto-correlation on 1D arrays with a numpy/scipy/matplotlib function? I have looked at numpy.correlate() and matplotlib.pyplot.xcorr (based on the numpy function), and both seem to not be able to do circular cross-correlation.

To illustrate the difference, I will use the example of an array of [1, 2, 3, 4]. With circular correlation, a periodic assumption is made, and a lag of 1 looks like [2, 3, 4, 1]. The python functions I've found only seem to use zero-padding, i.e., [2, 3, 4, 0]. Is there a way to get these functions to do circular correlation? If not, is there a standard workaround for circular correlations?

Lambert_W
  • 155
  • 1
  • 9

2 Answers2

21

You can implement the periodic (a.k.a. circular) cross correlation using the FFT:

from numpy.fft import fft, ifft

def periodic_corr(x, y):
    """Periodic correlation, implemented using the FFT.

    x and y must be real sequences with the same length.
    """
    return ifft(fft(x) * fft(y).conj()).real

You can also implement it using np.correlate, if you don't mind the overhead incurred by np.hstack((y[1:], y)):

import numpy as np

def periodic_corr_np(x, y):
    """Periodic correlation, implemented using np.correlate.

    x and y must be real sequences with the same length.
    """
    return np.correlate(x, np.hstack((y[1:], y)), mode='valid')
Warren Weckesser
  • 110,654
  • 19
  • 194
  • 214
  • 1
    Not only does the fft version rids you of the overhead of hstack, it also makes the calculation in n*log(n) complexity as opposed to n^2 in the case of correlation. – Mr.WorshipMe Dec 21 '15 at 09:20
  • 2
    According to [1] and some [other sources](http://mathworld.wolfram.com/Cross-Correlation.html) the first term should be conjugated: `ifft(fft(x).conj() * fft(y)).real` [1] Papoulis, A. The Fourier Integral and Its Applications. New York: McGraw-Hill, pp. 244-245 and 252-253, 1962. [Google Books Link](https://books.google.de/books?id=txMIAQAAIAAJ) – Stefan D. May 17 '16 at 12:34
  • @StefanD. The result seems to be the same but reflected and shifted by 1 position. So maybe you're talking about the difference between cross-correlation and convolution. I haven't checked in detail. – root Feb 27 '22 at 13:00
  • The FFT solution also seems to work for higher dimensions, for example using `fft2` and `ifft2`. Moreover, note that multidimensional cross-correlation can be used to "apply the same filter to several arrays at once" if some of the dimensions of the filter have size 1. – root Feb 27 '22 at 13:00
2
from numpy import roll, correlate
x = [1,2,3,4] 
roll(x, 1) #[4,1,2,3]
roll(x, 2) #[3,4,1,2]
roll(x, 3) #[2,3,4,1]

To correlate x with x circularly shifted by k, you could do

k = 2
correlate(x, roll(x,k))
Jeroen
  • 21
  • 1