Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Autocorrelation and autocovariance

Binder

Autocorrelation and autocovariance

Look at the speech signal segment below. On a large scale it is hard to discern a structure, but on a small scale, the signal seems continuous. Speech signals typically have such structure that samples near in time to each other are similar in amplitude. Such structure is often called short-term temporal structure.

More specifically, samples of the signal are correlated with the preceding and following samples. Such structures are in statistics measured by covariance and correlation, defined for zero-mean variables x and y as

covariance: σxy=E[xy]correlation: ρxy=E[xy]E[x2]E[y2],\begin{split} \text{covariance: } & \sigma_{xy} = E[xy] \\ \text{correlation: } & \rho_{xy} = \frac{E[xy]}{\sqrt{E[x^2]E[y^2]}}, \end{split}

where E[]E[ \cdot ] is the expectation operator.

Source
import numpy as np
import matplotlib.pyplot as plt
from scipy.io import wavfile
import scipy


# read from storage
filename = 'sounds/test.wav'
fs, data = wavfile.read(filename)

window_length_ms = 20
window_length = int(np.round(fs*window_length_ms/1000))

n = np.linspace(0.5,window_length-0.5,num=window_length)

#windowpos = np.random.randint(int((len(data)-window_length)))
windowpos = 92274

datawin = data[windowpos:(windowpos+window_length)]
datawin = datawin/np.max(np.abs(datawin)) # normalize

plt.plot(n*1000/fs,datawin)
plt.xlabel('Time (ms)')
plt.ylabel('Amplitude')
plt.title('A window of a signal')
plt.tight_layout()
plt.show()
<Figure size 432x288 with 1 Axes>

For a speech signal xnx_{n}, where nn is the time-index, we would like to measure the correlation between two time-indices xnx_{n} and xhx_{h}. Since the structure which we are interested in appears when nn and hh are near each other, it is better to measure the correlation between xnx_{n} and xnkx_{n-k}. The scalar kk is known as the lag. Furthermore, we can assume that the correlation is uniform over all nn within the segment. The self-correlation and -covariances, known as the autocorrelation and autocovariance are defined as

autocovariance: rk=En[xnxnk]autocorrelation: ck=En[xnxnk]En[xn2]=rkr0.\begin{split} \text{autocovariance: } & r_{k} = E_n[x_nx_{n-k}] \\ \text{autocorrelation: } & c_{k} = \frac{E_n[x_nx_{n-k}]}{E_n[x_n^2]} = \frac{r_k}{r_0}. \end{split}

The figure below illustrates the autocovariance of the above speech signal. We can immediately see that the short-time correlations are preserved - on a small scale, the autocovariance looks similar to the original speech signal. The oscillating structure is also accurately preserved.

Because we assume that the signal is stationary, and as a consequence of the above formulations, we can readily see that autocovariances and -correlations are symmetric

rk=En[xnxnk]=En[xn+kxn+kk]=En[xn+kxn]=rk.r_k = E_n[x_nx_{n-k}] = E_n[x_{n+k}x_{n+k-k}] = E_n[x_{n+k}x_{n}] = r_{-k}.

This symmetry is clearly visible in the figure below, where the curve is mirrored around lag 0.

Source
import numpy as np
import matplotlib.pyplot as plt
from scipy.io import wavfile
import scipy
import scipy.fft


# read from storage
filename = 'sounds/test.wav'
fs, data = wavfile.read(filename)

window_length_ms = 20
window_length = int(np.round(fs*window_length_ms/1000))

n = np.linspace(0.5,window_length-0.5,num=window_length)
n2 = np.linspace(1-window_length,window_length-1,num=window_length*2)

# windowing function
windowing_fn = np.sin(np.pi*n/window_length)**2 # sine-window


#windowpos = np.random.randint(int((len(data)-window_length)))
windowpos = 92274

datawin = data[windowpos:(windowpos+window_length)]
datawin = datawin/np.max(np.abs(datawin)) # normalize

spectrum = scipy.fft.rfft(datawin*windowing_fn,n=2*window_length)
autocovariance = scipy.fft.irfft(np.abs(spectrum**2))
autocovariance = np.concatenate((autocovariance[window_length:],autocovariance[0:window_length]))

plt.figure(figsize=[10,6])
plt.subplot(211)
plt.plot(n*1000/fs,datawin)
plt.xlabel('Time (ms)')
plt.ylabel('Amplitude')
plt.title('A window of a signal')
plt.subplot(212)
plt.plot(n2*1000/fs,autocovariance)
plt.xlabel('Lag (ms)')
plt.ylabel('Autocovaraince $r_k$')
plt.title('The autocovariance')
plt.tight_layout()
plt.show()
<Figure size 720x432 with 2 Axes>

The above formulas use the expectation operator E[]E[\cdot ] to define the autocovariance and -correlation. It is an abstract tool, which needs to be replaced by a proper estimator for practical implementations. Specifically, to estimate the autocovariance from a segment of length NN, we use

rk1N1k=1N1xnxnk.r_k \approx \frac1{N-1} \sum_{k=1}^{N-1} x_n x_{n-k}.

Observe that the speech signal xnx_{n} has to be windowed before using the above formula.

We can also make an on-line estimate (a.k.a. leaky integrator) of the autocovariance for sample position nn with lag kk as

r^k(n):=αxnxnk+(1α)r^k(n1),\hat r_k(n) := \alpha x_n x_{n-k} + (1-\alpha) \hat r_k(n-1),

where α[0,1]\alpha\in[0,1] is a small positive constant which determines how rapidly the estimate converges.

It is often easier to work with vector notation instead of scalars, whereby we need the corresponding definitions for autocovariances. Suppose

x=[x0x1xN1].x = \begin{bmatrix}x_0\\x_1\\\vdots\\x_{N-1}\end{bmatrix}.

We can then define the autocovariance matrix as

Rx:=E[xxT]=[E[x02]E[x0x1]E[x0xN1]E[x1x0]E[x12]E[x1xN1]E[xN1x0]E[xN1x1]E[xN12]]=[r0r1rN1r1r0rN2rN1rN1r0].R_x := E[x x^T] = \begin{bmatrix}E[x_0^2] & E[x_0x_1] & \dots & E[x_0x_{N-1}]\\E[x_1x_0] & E[x_1^2] & \dots & E[x_1x_{N-1}]\\\vdots&\vdots&\ddots&\vdots\\E[x_{N-1}x_0] & E[x_{N-1}x_1] & \dots & E[x_{N-1}^2]\end{bmatrix} = \begin{bmatrix}r_0 & r_1 & \dots & r_{N-1}\\ r_1 & r_0 & \dots & r_{N-2}\\\vdots&\vdots&\ddots&\vdots\\r_{N-1} & r_{N-1} & \dots & r_0\end{bmatrix}.

Clearly RxR_{x} is thus a symmetric Toeplitz matrix. Moreover, since it is a product of xx with itself, RxR_{x} is also positive (semi-)definite.