Determine the delay between two signals

Hello,
I am trying to find out the delay between two signals. I have the following Python example:

# Cross-correlate 
correlation = correlate(x, y, 'full')

# Get the lag vector that corresponds to the correlation vector
lags = correlation_lags(x.size,  y.size, mode="full")

# Find the lag at the peak of the correlation
lag = lags[np.argmax(correlation)]
print(lag)

My Julia code so far:

using StatsBase

function delay(x, y)
    z = crosscor(x, y)
    ind = argmax(z)
end

But there is still something like the Python function correlation_lags missing, see: scipy.signal.correlation_lags — SciPy v1.12.0 Manual
If I call my delay function with the same vector for both arguments I get a result that is not zero, but the delay in this test case should be zero.

Any idea?

Try DSP.xcorr.

Different result, but not better. I want to get the delay between the two signals in time-steps.

crosscor(x, y)

When left unspecified, the lags used are the integers from `-min(size(x,1)-1, 10*log10(size(x,1)))` to `min(size(x,1), 10*log10(size(x,1)))`

so it means zero lag is in the middle of z if you use delay with the same vector for both arguments.

There probably ought to be a variant of DSP.xcorr that returns an OffsetArray, such that the indices are lags. And that should ideally also work correctly if any of the inputs is OffsetArray. Also a maxlag option to truncate the output would be nice.

using StatsBase

T=0:0.1:10
X=sin.(T)
Y=sin.(T.-0.5)
plot(T,X)
plot(T,Y)

z = StatsBase.crosscor(X, Y)
delay=argmax(z)

println(delay)

This prints a delay of 26, but the expected delay is 0.5s = 5 time steps. How can I get the correct result?

In your case, the answer should probably be:

delay=argmax(z) - length(T)

It is more tricky if length(X) != length(Y), as then there is the question what the zero alignment between the two sequences should be (e.g. at start/end/center).

With the default lags used in corrcor, the zero delay is in the center, so you could just subtract that index:

using StatsBase
T=0:0.1:10
X=sin.(T)
Y=sin.(T.-0.5)


z = StatsBase.crosscor(X, Y)
delay=argmax(z)


println(delay-div((size(z,1)+1),2))
1 Like

Sorry, that doesn’t work.

Something like this?

using StatsBase

function delay(x, y)
    lags = (-length(y)+1):(length(x)-1)
    z = crosscor(x, y, lags)
    ind = argmax(z)
    lags[ind]
end

but scipy’s correlate has more options, this is just an sketch.

2 Likes

Ah, StatsBase.crosscor has a weird default range for lags, which you may need to override for longer inputs.

T=0:0.1:10
X=sin.(T)
Y=sin.(T.-0.5)
z = StatsBase.crosscor(X, Y, -(length(T)-1):(length(T)-1))
delay=argmax(z)-length(T)

5

But note that this may be biased in favour of large overlaps.

See also

for more ways of computing the delay between signals

3 Likes

The cross-correlation method presented above provides an integer delay (whole samples). To refine this and also obtain the fractional delay (fraction of a sample period), a simple method is to fit a parabola around the cross-correlation peak and obtain the abscissa of the apex.