0

I want to align two signals that are similar but shifted using cross-correlation. While this question has been answered a few times before (see references at the bottom), this situation is slightly different and / or I was unable to get the solutions work in my application.

The main difference is that the signals have different sampling rates and that I am inputting not just two signals, but their corresponding time vectors as well.

I thought I would be able to solve this problem by just interpolating both datasets onto the same time line, but I could not get this to work properly.

Here's what I have tried so far.

  1. Create two signals at different sampling rates, the second being shifted by 7 seconds w.r.t the first signal. They are however the same signals if not for the different sampling rate.
import matplotlib.pyplot as plt 
import numpy as np 
from scipy.signal import correlate
from scipy.interpolate import interp1d

dt1 = 2.4
t1 = np.arange(0,20,dt1)
y1 = np.sin(t1) + t1/10

dt2 = 1
t2 = np.arange(0,20,dt2)
y2 = np.sin(t2) + t2/10
offset_t2 = 7 # would want to recover this eventually.
t2 = t2 + offset_t2
  1. In order to not have to deal with the issue of the different sampling rates, I interpolate the two datasets onto timelines with the same sampling rate (the coarser one).
max_dt = max(dt1,dt2)
t1_resampled = np.arange(t1[0],t1[-1],max_dt)
t2_resampled = np.arange(t2[0],t2[-1],max_dt)

y1_resampled = interp1d(t1,y1)(t1_resampled)
y2_resampled = interp1d(t2,y2)(t2_resampled)
  1. I try to use the maximum of the cross-correlation to get the shift that I need to apply but that does not yield the right result as shown in this plot.
fig,axs=plt.subplots(2,1)
ax = axs[0]
ax.plot(t1,y1,"-o",label='y1')
ax.plot(t2,y2,"-o",label='y2')


xcorr = correlate(y1_resampled,y2_resampled)
argmax_index = np.argmax(xcorr)
shift = (argmax_index-(len(y2_resampled)+1))*max_dt

ax.plot(t2+shift,y2,"-o",label='y2 shifted')

ax = axs[1]
ax.plot(xcorr)
ax.scatter(argmax_index,xcorr[argmax_index],color='red')
axs[0].legend()
print(f"computed shift: {shift}\nexpected shift: {offset_t2}")

enter image description here

Clearly the blue and the green curve do not overlap and the computed shift of -4.8 does not match the offset of 7.

So I wonder if someone could help me implementing the shift function that I need for my example. It should return a value delta_t such that when plotting (t1,y1) and (t2+delta_t,y2) the signals overlap as well as possible.

It should look something like the following snippet, but I am unable to implement it.

def shift(t1,y1,t2,y2)->float:
    
    # If necessary, interpolate to same sampling rate.
    # But this might not be necessary. 
    max_dt = max(dt1,dt2)
    t1_resampled = np.arange(t1[0],t1[-1],max_dt)
    t2_resampled = np.arange(t2[0],t2[-1],max_dt)

    y1_resampled = interp1d(t1,y1)(t1_resampled)
    y2_resampled = interp1d(t2,y2)(t2_resampled)
    
    
    # Do something with the cross correlation ...
    # ...
    # delta_t = ...
    
    
    return delta_t

References that did not help

Use of pandas.shift() to align datasets based on scipy.signal.correlate

Python aligning, stretching and synchronizing array data in python (signal processing)

Python cross correlation - why does shifting a timeseries not change the results (lag)?

Thomas
  • 1,199
  • 1
  • 14
  • 29
  • I think your problem is with resampling, you are not implementing it correctly. I propose to just use `resampy` - it is just one line of code and comes with anti-aliasing filter (which you are missing as well..) – dankal444 Nov 02 '22 at 11:38
  • I will look into `resampy`, but In this case, even when using the same sample rates, the alignment isn't working properly so I wonder what else is going wrong. – Thomas Nov 02 '22 at 11:40
  • Did you already see https://stackoverflow.com/questions/41492882/find-time-shift-of-two-signals-using-cross-correlation and https://stackoverflow.com/questions/64028753/find-signal-or-phase-delay-from-cross-correlation and https://stackoverflow.com/questions/4688715/find-time-shift-between-two-similar-waveforms – Matt Hall Nov 02 '22 at 12:05
  • Thanks! But the first did not work, maybe because of the `delay_array` being used that doesn't translate well to my example. The second didn't have a solution for my problem and the last one differed because of different signal lengths. So far I haven't been able to translate any example into my application. – Thomas Nov 02 '22 at 12:22
  • Your plot is confusing and makes it seem like your code is actually working, since by coincidence `argmax_index` is 7. Instead you should be plotting with `timescale = (np.arange(len(xcorr)) - len(y2_resampled) - 1)*max_dt`. – Reinderien Nov 03 '22 at 00:19

0 Answers0