- 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
113 lines
3.9 KiB
Matlab
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
|
|
|