Dynamic cross correlation for time delay of two signals
19 views (last 30 days)
Show older comments
I have two signals, both recorded at the same sampling frequency, however one has a phase delay. I am currently playing around trying to figure out how to calculate the time delay between these two signals using the cross correlation method. I want to calculate the time delay between these two signals using windows, as I want the dynamic time delay of the signals and not the time delay over the entire spectrum. How do I do this? I am using matlab and for now I have this code, but I am unsure whether or not I am doing the right thing. How would I be able to get the maximum peaks of the correlation of all the columns in my "corr" matrix, and how do I convert this into a time delay?
file_path1 = '\ref trigger new_000_ALL.csv';
file_path2 = '\meas trigger new_000_ALL.csv';
% Read the CSV file skipping the first 17 rows
ref = csvread(file_path1, 16, 0);
meas = csvread(file_path2, 16, 0);
signal_ref = ref(:,2);
signal_meas = meas(:,2);
n = length(signal_ref);
dt = 3.2e-6;
fs = 1/dt;
FFT_ref = fft(signal_ref);
FFT_ref = FFT_ref(1:n/2);
FFT_meas = fft(signal_meas);
FFT_meas = FFT_meas(1:n/2);
FFT_n = length(FFT_meas);
window_size = 46; % Amount of data point used to separate data chunks.
overlap_percentage = 50; % Desired overlap percentage
overlap = window_size * overlap_percentage / 100;
shift = window_size-overlap; % nb of samples between 2 contiguous buffers
% Calculate number of windows
num_windows = fix((FFT_n-window_size)/shift +1);
corr_values = cell(num_windows, 1);
lags_values = cell(num_windows, 1);
% Iterate over the signal with sliding window
for ci = 1:num_windows
% Define start and end indices for the current window
start_index = 1+(ci-1)*shift;
end_index = min(start_index+ window_size-1,FFT_n);
% Extract the current window
window_ref = FFT_ref(start_index:end_index);
window_meas = FFT_meas(start_index:end_index);
ifft_ref = ifft(window_ref);
ifft_meas = ifft(window_meas);
[corr_temp, lags_temp] = xcorr(ifft_ref, ifft_meas);
corr_values{ci} = corr_temp;
lags_values{ci} = lags_temp;
end
% Concatenate all correlation and lags values
corr = cell2mat(corr_values');
lags = cell2mat(lags_values);
lag = lags(1,:);
figure(1)
plot(Time, signal_ref);
xlabel('Time (s)');
ylabel('Voltage (V)');
title('Reference signal')
figure(2)
plot(Time, signal_meas)
xlabel('Time (s)')
ylabel('Voltage (V)')
title('Measured signal')
figure(3)
plot(Freq, real(FFT_ref));
xlabel('Frequency (Hz)');
ylabel('Magnitude');
title('Reference signal')
figure(4)
plot(Freq, real(FFT_meas))
xlabel('Frequency (Hz)')
ylabel('Magnitude')
title('Measured signal')
figure(5)
plot(lag, abs(corr(:,20)));
xlabel('Cross correlation shift (GHz)')
ylabel('Amplitude (A.U.')





8 Comments
Mathieu NOE
on 7 Mar 2024
hmm , ok, I will look at your new code a bit latter (I am a bit busy today)
but just to prove that the FWHM computaion with find_zc function works, here my last code a bit expanded to plot each individual corr FMWH values
see, it works on all data , just I needed to restraint the ZxP,ZxN values to the ones closest to the peak.
that's why you had the issues (should be OK now).
clc
clearvars
close all
% Results obtained with phdiffmeasure and 'dft' argument
% signals
ref = csvread('ref_1.csv', 16, 0);
meas = csvread('meas_1.csv', 16, 0);
% ref = csvread('ref trigger start_000_ALL.csv', 16, 0);
% meas = csvread('meas trigger start_000_ALL.csv', 16, 0);
time_ref = ref(:,1);
signal_ref = ref(:,2);
dt = mean(diff(time_ref));
time_meas = meas(:,1);
signal_meas = meas(:,2);
Fs = 1/dt;
% Define valid common Time vector and interpolate data if needed (on new common Time vector)
% (define which data has time delay and interpolate the other data on
% correct Time vector)
time_ref_min = time_ref(1);
time_meas_min = time_meas(1);
time_ref_max = time_ref(end);
time_meas_max = time_meas(end);
if time_ref_min>time_meas_min
ind = time_ref<=time_meas_max;
Time = time_ref(ind);
signal_ref = signal_ref(ind);
signal_meas = interp1(time_meas,signal_meas,Time);
else
ind = time_meas<=time_ref_max;
Time = time_meas(ind);
signal_meas = signal_meas(ind);
signal_ref = interp1(time_ref,signal_ref,Time);
end
clear time_ref time_meas
% FFT process
N = length(signal_ref);
Fs = 1/dt;
k=0:N-1; %create a vector from 0 to N-1
T=N/Fs; %get the frequency interval
Freq=k/T; %create the frequency range
FFT_ref = fft(signal_ref); % make up for the lack of 1/N in Matlab FFT
FFT_meas = fft(signal_meas);% make up for the lack of 1/N in Matlab FFT
%only want the first half of the FFT, since it is redundant
cutOff = ceil(N/2);
Freq = Freq(1:cutOff);
FFT_ref = FFT_ref(1:cutOff);
FFT_meas = FFT_meas(1:cutOff);
FFT_n = length(FFT_meas);
window_size = 100; % Amount of data point used to separate data chunks.
overlap_percentage = 50; % Desired overlap percentage
overlap = window_size * overlap_percentage / 100;
shift = window_size-overlap; % nb of samples between 2 contiguous buffers
% Calculate number of windows
num_windows = fix((FFT_n-window_size)/shift +1);
corr_values = cell(num_windows, 1);
lags_values = cell(num_windows, 1);
% Iterate over the signal with sliding window
for ci = 1:num_windows
% Define start and end indices for the current window
start_index = 1+(ci-1)*shift;
end_index = min(start_index+ window_size-1,FFT_n);
% Extract the current window
window_ref = FFT_ref(start_index:end_index);
window_meas = FFT_meas(start_index:end_index);
ifft_ref = ifft(window_ref);
ifft_meas = ifft(window_meas);
[corr_temp, lags_temp] = xcorr(ifft_ref, ifft_meas);
corr_values{ci} = corr_temp;
lags_values{ci} = lags_temp;
end
% Concatenate all correlation and lags values
corr = cell2mat(corr_values');
lags = cell2mat(lags_values);
lag = lags(1,:);
figure(1)
plot(Time, signal_ref,Time, signal_meas);
xlabel('Time (s)');
ylabel('Voltage (V)');
title('Time signals')
legend('Reference signal','Measured signal')
figure(2)
plot(Freq, abs(FFT_ref));
xlabel('Frequency (Hz)');
ylabel('Magnitude');
title('Reference signal')
figure(3)
plot(Freq, abs(FFT_meas))
xlabel('Frequency (Hz)')
ylabel('Magnitude')
title('Measured signal')
figure(4)
% plot(lag, abs(corr(:,20)));
m_corr = mean(abs(corr),2);
plot(lag, m_corr);
hold on
xlabel('Cross correlation shift (GHz)')
ylabel('Amplitude (A.U.')
xlim([-20 20])
% FWHM computation (dx of points at 50% of the peak value)
[ZxP,ZxN] = find_zc(lag, m_corr,max(m_corr)/2);
FWHM = ZxN - ZxP;
plot([ZxP ZxN], ones(2,1)*max(m_corr)/2,'r');
hold off
% some extra plots
for ci = 1:num_windows
m_corr = abs(corr(:,ci));
figure
hold on
plot(lag, m_corr);
xlabel('Cross correlation shift (GHz)')
ylabel('Amplitude (A.U.')
% FWHM computation (dx of points at 50% of the peak value)
[ZxP,ZxN] = find_zc(lag, m_corr,max(m_corr)/2);
% take only the values closest to the peak
[pval,indp] = max(m_corr); % peak amplitude and indice
xp = lag(indp); % x position of peak
ind1 = find(ZxP<xp);
ZxP = ZxP(ind1(end)); % last value
ind2 = find(ZxN>xp);
ZxN = ZxN(ind2(1)); % first value
FWHM = ZxN - ZxP;
plot([ZxP ZxN], ones(2,1)*max(m_corr)/2,'r');
hold off
end
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [ZxP,ZxN] = find_zc(x,y,threshold)
% put data in rows
x = x(:);
y = y(:);
% positive slope "zero" crossing detection, using linear interpolation
y = y - threshold;
zci = @(data) find(diff(sign(data))>0); %define function: returns indices of +ZCs
ix=zci(y); %find indices of + zero crossings of x
ZeroX = @(x0,y0,x1,y1) x0 - (y0.*(x0 - x1))./(y0 - y1); % Interpolated x value for Zero-Crossing
ZxP = ZeroX(x(ix),y(ix),x(ix+1),y(ix+1));
% negative slope "zero" crossing detection, using linear interpolation
zci = @(data) find(diff(sign(data))<0); %define function: returns indices of +ZCs
ix=zci(y); %find indices of + zero crossings of x
ZeroX = @(x0,y0,x1,y1) x0 - (y0.*(x0 - x1))./(y0 - y1); % Interpolated x value for Zero-Crossing
ZxN = ZeroX(x(ix),y(ix),x(ix+1),y(ix+1));
end
Answers (0)
See Also
Categories
Find more on Frequency Transformations in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!

