Files
imdd_silas/Classes/04_DSP/Timing Recovery/Godard_Timing_Recovery.m
magf 005e821131 Added:
- Class folder 'Timing Recovery' with different timing recoveries
- Minimal example for the timing recovery on the FSO data
- New evaluation scripts in the FSO project folder
2026-02-02 10:56:12 +01:00

113 lines
3.9 KiB
Matlab

classdef Godard_Timing_Recovery < handle
properties(Access=public)
mode
num_blocks
fft_length
sps
rolloff
mu
Ki
end
methods(Access=public)
function obj = Godard_Timing_Recovery(options)
arguments(Input)
options.mode = 0;
options.num_blocks = 1;
options.fft_length = 1024;
options.sps = 2;
options.rolloff = 0;
options.mu = 0;
options.Ki = 1e-3;
end
fn = fieldnames(options);
for n = 1:numel(fn)
obj.(fn{n}) = options.(fn{n});
end
%obj-Initialization here%
end
function [data_out, tau_hat] = process(obj, data_in)
data_out = data_in;
output_vector = zeros(length(data_in),1);
block_length = length(data_in)/obj.num_blocks;
for i = 1:obj.num_blocks
i_start = ((i-1)*block_length)+1;
i_end = i*block_length;
x = data_in.signal(i_start:i_end);
beta = obj.rolloff;
eta = obj.sps;
R = fft(x,obj.fft_length);
R_full = fft(x);
if obj.mode == 0 % Classic Godard
% Calculate time shift
k0 = (1:obj.fft_length/2).';
idx1 = k0;
idx2 = k0+(obj.fft_length/2);
tau_hat = sum(imag(R(idx1) .* conj(R(idx2))));
elseif obj.mode == 1 || obj.mode == 2 % Modified Godard 1
% Calculate Shift for the received signal
shiftBins = (1 - 1/eta) * obj.fft_length;
if abs(shiftBins - round(shiftBins)) > 1e-12
disp('Warning: shiftBins=(1-1/eta)*fft_length is non-integer. Choose compatible values for fft_length and eta.');
end
shiftBins = round(shiftBins);
% Calculate upper and lower bounds
kStart = ((1-beta)/(2*eta)) * obj.fft_length;
kEnd = ((1+beta)/(2*eta)) * obj.fft_length - 1;
if abs(kStart - round(kStart)) > 1e-12 || abs(kEnd - round(kEnd)) > 1e-12
disp('Warning: kStart/kEnd are non-integer. Choose compatible values for fft_length, eta, and beta.');
end
kStart = round(kStart);
kEnd = round(kEnd);
k0 = (kStart:kEnd).';
idx1 = k0 + 1;
idx2 = mod(k0 + shiftBins, obj.fft_length) + 1;
% Calculate time shift
if obj.mode == 1
tau_hat = sum(imag(R(idx1) .* conj(R(idx2))));
elseif obj.mode == 2
tau_hat = sum(angle(R(idx1))-angle(R(idx2)));
end
end
% % Normalization
% denom = floor(log10(abs(tau_hat)));
% tau_hat = tau_hat / 10^denom;
% Calculate mu using a first-order loop filter
mu_block = obj.mu + obj.Ki * tau_hat;
% % Shifting the signal in time domain using interpolation
% x_original = linspace(0,length(x)-1,length(x)).';
% x_new = x_original + mu_block;
% output_vector(i_start:i_end) = interp1(x_original,x,x_new,'linear','extrap');
% Shifting the signal in frequency domain
k = (0:block_length-1).';
phaseRamp = exp(-1j * 2*pi * (k/block_length) * mu_block);
R_shifted = R_full .* phaseRamp;
output_vector(i_start:i_end) = real(ifft(R_shifted));
end
data_out.signal = output_vector;
end
end
end