Additions:

- Correction of the weighted DFE function in EQ.m
- Some evaluation scripts for FSO Data
This commit is contained in:
magf
2026-02-09 13:04:20 +01:00
parent 58e72070d9
commit 3edd64d365
22 changed files with 759 additions and 186 deletions

View File

@@ -10,10 +10,12 @@ classdef EQ < handle
training_length %Number of training symbols
training_loops %Number of loops through sequence for training mode
ideal_dfe %Error free DFE decisions
weighted_DFE %Weighted DFE on/off
weighted_DFE %Weighted DFE off (0)/on (1)/PDFE (2)
weighted_DFE_mode %Weighted DFE mode
weighted_DFE_d_min %d_min threshold parameter for weighted DFE mode 1
weighted_DFE_I_mode %[a_s, b_s, I_max]-parameters for the weighted DFE
PDFE_coefficient %Coefficient for PDFE
weighted_error %error based on hard- or weighted decision
DB_aim %Aim at duobinary output sequence
@@ -43,7 +45,6 @@ classdef EQ < handle
save_taps
%during simulation
k0
b
@@ -76,6 +77,8 @@ classdef EQ < handle
options.weighted_DFE_mode = 'R1';
options.weighted_DFE_d_min = 0.5;
options.weighted_DFE_I_mode = [5,0.5,0.6];
options.PDFE_coefficient = 0.5;
options.weighted_error = 0; %0: Error based on hard-decision. 1: Error based on weighted decision.
options.DB_aim %Aim at duobinary output sequence
@@ -120,7 +123,7 @@ classdef EQ < handle
signalclass_in.signal = signalclass_in.signal';
signalclass_in.fs = reference_signalclass_in.fs;
% append to logbook
lbdesc = ['EQ '];
signalclass_in = signalclass_in.logbookentry(lbdesc);
@@ -229,7 +232,7 @@ classdef EQ < handle
obj.k0 = obj.delay; % input delay compared to training sequence
error_log = [];
if 1 % obj.active
%% Calculation of the filter coefficients in training based LMS mode
@@ -243,19 +246,11 @@ classdef EQ < handle
cnt = 1;
m = obj.k0+1; % starting symbol index at the delay compared to the training sequence
% n => index in rx data sequence
%Step From: Oversampling(=2) * Startdelay + 1
%Step Width: Oversampling(=2)
%Step To: Oversampling(=2) * Training Length
for n = obj.K*obj.k0+1:obj.K:obj.K*obj.training_length
% m => index in reference sequence
m = m+1;
%
%dc_ = mean(data(obj.Ne(1)+n+(obj.K-1):-1:n+obj.K).');
% cut symbols from rx data sequence
X_1 = data(obj.Ne(1)+n+(obj.K-1):-1:n+obj.K).';
@@ -274,9 +269,7 @@ classdef EQ < handle
e_dfe = b_.'*reference_vec;
error = e_dc + e_ffe - e_dfe - ref_in(m-obj.k0);
%error = e_dc + e_.'*input_vec - b_.'*reference_vec - ref_in(m-obj.k0);
if real(obj.FFEmu)
if obj.l1act
sgn_e = e_;
@@ -297,28 +290,13 @@ classdef EQ < handle
e_dc = e_dc - obj.DCmu*error;
% obj.error_log.e_ffe(cnt,trainloops) = e_ffe;
% obj.error_log.e_dfe(cnt,trainloops) = e_dfe;
% obj.error_log.e_(cnt,trainloops) = error;
cnt = cnt+1;
if obj.Nb(1) > 0
b_ = b_ + obj.DFEmu*error*reference_vec; % Seems like normalized DFE has worse performance
end
% figure(111);stem((e_),'Markersize',2);ylim([-1 1]);title('FFE Filter Taps');
%
% figure(222);
% stem(input_vec);ylim([-3 3]);
% hold on;
% stem(reference_vec);ylim([-3 3]);
% yline(error,'LineWidth',2); title('Input Vector');
% hold off
end
end
%%
% Plot the intermediate coefficients after training mode
obj.b = b_(1:obj.Nb(1));
@@ -349,10 +327,8 @@ classdef EQ < handle
subplot(2,3,6);stem(obj.b3,'Markersize',2);
title('DFE coeff nl 3rd')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
%set(gcf,'Position',[200 500 700 400])
end
if obj.l1act
neg_lin = find(abs(obj.e) < obj.thres(1));
neg_2nd = find(abs(obj.e2) < obj.thres(2));
@@ -401,6 +377,7 @@ classdef EQ < handle
cnt = 1;
m = 0;
output_vec = zeros(1,floor(length(data_in)/obj.K)); % initilaization of the output vector
output_vec_weighted = zeros(size(output_vec));
dd_DFE = zeros(obj.Nb(1),1);
D_2 = zeros(Nb2,1);
D_3 = zeros(Nb3,1);
@@ -418,7 +395,6 @@ classdef EQ < handle
if obj.load_decisions
pathn = evalin('base','modeldir');
temp = load([pathn, 'MLSE_out', '.mat']) ;
%eval(['dd_out_vals = temp.', 'a', ';']) ;
dd_out_vals=temp.a;
dd_out = zeros(size(data_in));
dd_out(1:2:length(data_in)) = dd_out_vals;
@@ -440,79 +416,103 @@ classdef EQ < handle
end
output_vec(m) = e_dc + input_vec.'*coeff;
y_raw = output_vec(m); % ungeweighteter Equalizer-Ausgang
if ~obj.load_decisions
[~,dd_idx] = min(abs(output_vec(m) - constellation_in_)); % decision for closest constellation point
dd_out(k) = constellation_in_(dd_idx);
end
% Implementation of a weighted DFE in
% order to prevent error propagation.
% For further details, study [1], chapter 3.2.2 -
% Modifications of DFE
% ---------- WDFE / PDFE ----------
fb_sym = dd_out(k);
if obj.weighted_DFE
% define new constellations
const = unique(ref_in);
if obj.weighted_DFE ~= 0
% Get constellation
const = obj.constellation_in;
% determine reliability factor gamma_k
% Half minimum symbol distance (for normalization of |x - xhat|)
const_s = sort(const(:).');
d = diff(const_s);
dmin = min(d(d>0));
halfStep = dmin/2;
% Reliability gamma_k
if output_vec(m) > min(const) && output_vec(m) < max(const)
gamma_k = 1 - abs(output_vec(m) - dd_out(k));
gamma_k = 1 - abs(output_vec(m) - dd_out(k))/halfStep;
gamma_k = max(0, min(1, gamma_k)); % clamp to [0,1]
else
gamma_k = 1;
end
% select mode
if strcmp(obj.weighted_DFE_mode,'R1')
if gamma_k >= obj.weighted_DFE_d_min
f_gamma_k = 1;
else
f_gamma_k = 0;
% f(gamma_k)
if obj.weighted_DFE == 1
switch obj.weighted_DFE_mode
case 'R1'
f_gamma_k = double(gamma_k >= obj.weighted_DFE_d_min);
case 'R2'
f_gamma_k = gamma_k;
case 'I1'
a_s = obj.weighted_DFE_I_mode(1);
b_s = obj.weighted_DFE_I_mode(2);
t = a_s*((gamma_k/b_s) - 1);
f_gamma_k = 0.5*(tanh(t) + 1);
case 'I2'
a_s = obj.weighted_DFE_I_mode(1);
b_s = obj.weighted_DFE_I_mode(2);
Imax = obj.weighted_DFE_I_mode(3);
t = a_s*((gamma_k/b_s) - 1);
f_gamma_k = (Imax/2)*(tanh(t) + 1);
otherwise
error('Unknown weighted_DFE_mode');
end
elseif strcmp(obj.weighted_DFE_mode,'R2')
f_gamma_k = gamma_k;
elseif strcmp(obj.weighted_DFE_mode,'I1')
nom = 1-exp(-obj.weighted_DFE_I_mode(1)*((gamma_k/obj.weighted_DFE_I_mode(2))-1));
denom = 1+exp(-obj.weighted_DFE_I_mode(1)*((gamma_k/obj.weighted_DFE_I_mode(2))-1));
f_gamma_k = (1/2)*((nom/denom) - 1);
elseif strcmp(obj.weighted_DFE_mode,'I2')
nom = 1-exp(-obj.weighted_DFE_I_mode(1)*((gamma_k/obj.weighted_DFE_I_mode(2))-1));
denom = 1+exp(-obj.weighted_DFE_I_mode(1)*((gamma_k/obj.weighted_DFE_I_mode(2))-1));
f_gamma_k = (obj.weighted_DFE_I_mode(3)/2)*((nom/denom) - 1);
% Weighted decision
xbar = f_gamma_k*dd_out(k) + (1 - f_gamma_k)*output_vec(m);
elseif obj.weighted_DFE == 2
% PDFE
xbar = obj.PDFE_coefficient*dd_out(k) + (1 - obj.PDFE_coefficient)*output_vec(m);
end
% calculate weighted output
output_vec(m) = f_gamma_k.*dd_out(k)+(1-f_gamma_k).*output_vec(m);
output_vec_weighted(m) = xbar;
fb_sym = xbar;
output_vec(m) = xbar;
end
if obj.Nb(1) > 0
dd_DFE(2:end) = dd_DFE(1:end-1);
dd_DFE(1) = dd_out(k);
dd_DFE(1) = fb_sym;
if obj.ideal_dfe && m > obj.k0
dd_DFE(1) = ref_in(m-obj.k0);
end
[D_2,D_3] = obj.calc_nl_vecs(dd_DFE,ind_mat_DFE_2nd,ind_mat_DFE_3rd,norm_fac_DFE2,norm_fac_DFE3,delta_DFE2,delta_DFE3,cplx);
[D_2,D_3] = obj.calc_nl_vecs(dd_DFE,ind_mat_DFE_2nd,ind_mat_DFE_3rd,...
norm_fac_DFE2,norm_fac_DFE3,delta_DFE2,delta_DFE3,cplx);
end
if obj.weighted_DFE ~= 0 && obj.weighted_error
% Error weighted decision
error = y_raw - output_vec(m);
else
% Error hard decision
error = y_raw - dd_out(k);
end
% if dd_loop ~= 21
error = output_vec(m) - dd_out(k);
% else
% error = 0;
% end
coeff = coeff - mu_mat*error*conj(input_vec);
% e_save(:,save_ind) = coeff;
% save_ind = save_ind+1;
if 1%mu_mat ~= 0
e_dc = e_dc - obj.DCmu*error;
% error_log(cnt,dd_loop) = e_dc;
cnt = cnt+1;
if 1 % mu_mat ~= 0
e_dc = e_dc - obj.DCmu*error;
cnt = cnt+1;
end
end
end
%figure(2023);plot(error_log(:,1))
% shifting the output sequence by k0 symbols
yout = (circshift(output_vec.',-(obj.k0))).'; %(circshift(dd_out.',-(obj.k0))).';
@@ -581,12 +581,6 @@ classdef EQ < handle
% save frequency response to the work space
if obj.save_taps
% save the FFE coefficients to the work space
% pathn = evalin('base','modeldir');
% eval([obj.field_ffe, ' = obj.e ;']) ;
% eval([obj.field_dfe, ' = b ;']) ;
% eval(['save(''', pathn, '\',obj.filen,''', ''', obj.field_ffe,''', ''',obj.field_dfe,''') ;']) ;
save("coefficients",obj.e, obj.b);
end
@@ -726,19 +720,11 @@ classdef EQ < handle
ind_mat_3rd2 = NaN(N3,3);
count = 1;
% for t = 1:Ne3
% ind_mat_3rd2(count,:) = [t t t];
% count = count + 1;
% end
for t = 1:Ne3
% ind_mat_3rd2(count,:) = [t t t];
% count = count + 1;
for u = t:min(Ne3,t+len_3rd)
for v = unique([t u])
ind_mat_3rd2(count,:) = [t v u];
count = count + 1;
% ind_mat_3rd2(count,:) = [t u u];
% count = count + 1;
end
end
end
@@ -785,5 +771,5 @@ classdef EQ < handle
end
% References
% [1] T. J. Wettlin, Experimental Evaluation of Advanced Digital Signal Processing for Intra-Datacenter Systems using Direct-Detection, 2023. [Online]. Available: https://nbn-resolving.org/urn:nbn:de:gbv:8:3-2023-00703-8
% [1] T. J. Wettlin, Experimental Evaluation of Advanced Digital Signal Processing for Intra-Datacenter Systems using Direct-Detection, 2023.
% [Online]. Available: https://nbn-resolving.org/urn:nbn:de:gbv:8:3-2023-00703-8

View File

@@ -621,7 +621,8 @@ classdef ML_MLSE < handle
% --- Initialize weights
if isempty(obj.w) || any(size(obj.w) ~= [obj.Nf+1,obj.nFeasible])
obj.w = randn(obj.Nf+1,obj.nFeasible);
% obj.w = randn(obj.Nf+1,obj.nFeasible);
obj.w = zeros(obj.Nf+1,obj.nFeasible);
end
% --- Fast lookup tables

View File

@@ -1,6 +1,7 @@
classdef Timing_Recovery < handle
properties(Access=public)
modulation
timing_error_detector
sps
damping_factor
@@ -12,6 +13,7 @@ classdef Timing_Recovery < handle
function obj = Timing_Recovery(options)
arguments(Input)
options.modulation = 'PAM/PSK/QAM'
options.timing_error_detector = 'Gardner';
options.sps = 2;
options.damping_factor = 1.0;
@@ -32,6 +34,7 @@ classdef Timing_Recovery < handle
function [data_out,timing_error] = process(obj, data_in)
timing_synchronization = comm.SymbolSynchronizer( ...
"Modulation", obj.modulation, ...
"TimingErrorDetector", obj.timing_error_detector, ...
"SamplesPerSymbol", obj.sps, ...
"DampingFactor", obj.damping_factor, ...