Files
imdd_silas/Classes/04_DSP/Equalizer/EQ.m
magf 3676d92b30 +++ Changes +++
+ duobinary_target now supports memoryless decoding (FFE targets DB response without MLSE)
+ PAMmapper.quantize now supports custom constellations for quantization
+ Added a new folder 'Documentations' for pdfs, slides, etc.
+ Added new FSO evaluation scripts in projects/FSO transmission/Evaluation Scripts
+ Added ffe_db (rudimentary module, not important anymore)
2026-03-05 10:41:36 +01:00

775 lines
32 KiB
Matlab

classdef EQ < handle
%EQ Summary of this class goes here
% Detailed explanation goes here
properties
Ne %Number of feed forward coefficients (1st, 2nd and 3rd order)
Nb %Number of decision feedback coefficients (1st, 2nd and 3rd order)
K %Number of samples per symbol
delay %Delay of incoming signal
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 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
M %Order of the PAM constellation (only relevant in case of DB aim)
FFEmu %mu parameter for FFE part in training mode (0 means normalized LMS)
DFEmu % mu parameter for DFE part in training mode
dd_loops % Number of loops through sequence for DD mode
DDmu % mu parameters for DD mode (individual value for each order)
DCmu % mu parameter for the dc tap
l1act %Activate/deactive l1 regularization
rho %Parameter for speed of coeff shrinking
epsilon %Reciprocal value of the magnitude of the coeff to converge to zero (1st,2nd,3rd order)
thres %Theshold for neglecting coefficienties (1st,2nd,3rd order)
static_act %Activate/deactive static coefficient reduction
mode2nd %0: no reduction | 1: polynomial | 2: restricted to interval
len_2nd %length of the interval (only for 2nd order mode = 2)
mode3rd %0: no reduction | 1: polynomial | 2: restricted to interval
len_3rd %length of the interval (only for 3rd order mode = 3/4)
plottrain
plotfinal
load_decisions
save_taps
%during simulation
k0
b
b2
b3
e
e2
e3
coeff_number
constellation_in
error_log
end
methods
function obj = EQ(options)
%EQ Construct an instance of this class
% Detailed explanation goes here
arguments(Input)
options.Ne = [10 0 0] %Number of feed forward coefficients (1st, 2nd and 3rd order)
options.Nb = [10 0 0]%Number of decision feedback coefficients (1st, 2nd and 3rd order)
options.K = 1 %Number of samples per symbol
options.delay = 0 %Delay of incoming signal
options.training_length = 1024 %Number of training symbols
options.training_loops = 1 %Number of loops through sequence for training mode
options.ideal_dfe = 0 %Error free DFE decisions
options.weighted_DFE = 0;
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
options.M = 1 %Order of the PAM constellation (only relevant in case of DB aim)
options.FFEmu = 0 %mu parameter for FFE part in training mode (0 means normalized LMS)
options.DFEmu = 0.005 % mu parameter for DFE part in training mode
options.dd_loops = 1% Number of loops through sequence for DD mode
options.DDmu = [0.0004 0.0004 0.0004 0.0004 ] % mu parameters for DD mode (individual value for each order)
options.DCmu = 0.005 % mu parameter for the dc tap
options.l1act = 0 %Activate/deactive l1 regularization
options.rho = 5e-4%Parameter for speed of coeff shrinking
options.epsilon = [10 100 1000] %Reciprocal value of the magnitude of the coeff to converge to zero (1st,2nd,3rd order)
options.thres = [5e-3 4e-3 5e-4]%Theshold for neglecting coefficienties (1st,2nd,3rd order)
options.static_act = 0 %Activate/deactive static coefficient reduction
options.mode2nd = 1%0: no reduction | 1: polynomial | 2: restricted to interval
options.len_2nd = 1 %length of the interval (only for 2nd order mode = 2)
options.mode3rd = 1%0: no reduction | 1: polynomial | 2: restricted to interval
options.len_3rd = 1%length of the interval (only for 3rd order mode = 3/4)
options.plottrain = 0
options.plotfinal = 0
options.load_decisions = 0
options.save_taps = 0
end
fn = fieldnames(options);
for n = 1:numel(fn)
obj.(fn{n}) = options.(fn{n});
end
end
function [signalclass_out,noi] = process(obj,signalclass_in, reference_signalclass_in)
% actual processing of the signal (steps 1. - 3.)
[signalclass_in.signal] = obj.process_(signalclass_in.signal', reference_signalclass_in.signal');
signalclass_in.signal = signalclass_in.signal';
signalclass_in.fs = reference_signalclass_in.fs;
% append to logbook
lbdesc = ['EQ '];
signalclass_in = signalclass_in.logbookentry(lbdesc);
% write to output
signalclass_out = signalclass_in;
noi = signalclass_out;
noi = signalclass_out - reference_signalclass_in;
end
function [yout,error_log] = process_(obj,data_in,ref_in)
%METHOD1 Summary of this method goes here
% Detailed explanation goes here
if obj.DB_aim
ref_DB = zeros(size(ref_in));
for k = 1:length(ref_in)
if k == 1
ref_DB(k) = ref_in(k);
else
ref_DB(k) = ref_in(k) + ref_in(k-1);
end
end
ref_in = ref_DB;
end
ref = [zeros(1,obj.Nb(1)-1) ref_in zeros(1,obj.Nb(1))];
if isreal(ref)
cplx = 0;
else
cplx = 1;
end
if obj.static_act
obj.mode2nd = obj.mode2nd + 1;
obj.mode3rd = obj.mode3rd + 1;
else
obj.mode2nd = 1;
obj.mode3rd = 1;
end
if obj.mode2nd == 1
N2 = (obj.Ne(2)*(obj.Ne(2)+1))/2; % Number of coefficients for second order
elseif obj.mode2nd == 2
N2 = obj.Ne(2);
elseif obj.mode2nd == 3
N2 = (obj.len_2nd+1)*(2*obj.Ne(2)-obj.len_2nd)/2;
elseif obj.mode2nd == 4
N2 = (ceil(obj.Ne(2)/2)+1)*(2*obj.Ne(2)-ceil(obj.Ne(2)/2))/2;
end
if obj.mode3rd == 1
if cplx
N3 = obj.Ne(3)^2*(obj.Ne(3)+1)/2;
else
N3 = obj.Ne(3)*(obj.Ne(3)+1)*(obj.Ne(3)+2)/6; % Number of coefficients for third order
end
elseif obj.mode3rd == 2
N3 = obj.Ne(3);
elseif obj.mode3rd == 3
N3 = obj.Ne(3)^2;
elseif obj.mode3rd == 4
N3 = round(1/6*(obj.len_3rd+1)*(obj.len_3rd+2)*(3*obj.Ne(3)-2*obj.len_3rd));
elseif obj.mode3rd == 5
N3 = 2*obj.Ne(3)*obj.len_3rd-obj.len_3rd*(obj.len_3rd+1)+obj.Ne(3);
end
Nb2 = (obj.Nb(2)*(obj.Nb(2)+1))/2;
Nb3 = obj.Nb(3)*(obj.Nb(3)+1)*(obj.Nb(3)+2)/6;
data_in = data_in/sqrt(mean(abs(data_in).^2)); % power normalization of input sequence
if obj.FFEmu == 0
norm_fac2 = sqrt(mean(abs(data_in.^2).^2)); % power normalization for second and third order terms
norm_fac3 = sqrt(mean(abs(data_in.^3).^2)); % (not necessary, but seems to be more stable if applied --> same as different mu values for linear and nl terms)
else
norm_fac2 = 1;
norm_fac3 = 1;
end
norm_fac_DFE2 = sqrt(mean(abs(ref_in.^2).^2)); % same for DFE input (reference)
norm_fac_DFE3 = sqrt(mean(abs(ref_in.^3).^2));
data = [zeros(1,floor(obj.Ne(1)/2)) data_in zeros(1,obj.Ne(1))];
delta_2 = round((obj.Ne(1)-obj.Ne(2))/2);
delta_3 = round((obj.Ne(1)-obj.Ne(3))/2);
delta_DFE2 = 1;%round((obj.Nb-obj.Nb(2))/2);
delta_DFE3 = 1;%round((obj.Nb-obj.Nb(3))/2);
% calculate the indices for the combination of second and third order symbols
% - done in advance because it's the same for each iteration, so time
% can be saved
[ind_mat_2nd,ind_mat_3rd] = obj.calc_ind(obj.Ne(2),N2,obj.Ne(3),N3,obj.mode2nd,obj.mode3rd,obj.len_2nd,obj.len_3rd,cplx);
[ind_mat_DFE_2nd,ind_mat_DFE_3rd] = obj.calc_DFE_ind(obj.Nb(2),Nb2,obj.Nb(3),Nb3);
if obj.l1act
epsilon_ = diag([ones(1,obj.Ne(1))*obj.epsilon(1) ones(1,N2)*obj.epsilon(2) ones(1,N3)*obj.epsilon(3)]);
end
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
e_ = zeros(obj.Ne(1)+N2+N3,1); % initialization of filter coefficients
b_ = zeros(obj.Nb(1)+Nb2+Nb3,1);
e_dc = mean(data_in); % initilaization of the dc tap with the mean value of the whole data
for trainloops = 1:obj.training_loops
cnt = 1;
m = obj.k0+1; % starting symbol index at the delay compared to the training sequence
for n = obj.K*obj.k0+1:obj.K:obj.K*obj.training_length
% m => index in reference sequence
m = m+1;
% cut symbols from rx data sequence
X_1 = data(obj.Ne(1)+n+(obj.K-1):-1:n+obj.K).';
[X_2,X_3] = obj.calc_nl_vecs(X_1,ind_mat_2nd,ind_mat_3rd,norm_fac2,norm_fac3,delta_2,delta_3,cplx);
input_vec = [X_1;X_2;X_3];
% cut symbols from desired data sequence (correct symbols in training mode)
D_1 = ref(obj.Nb(1)-obj.k0+m-2:-1:m-obj.k0-1).';
[D_2,D_3] = obj.calc_nl_vecs(D_1,ind_mat_DFE_2nd,ind_mat_DFE_3rd,norm_fac_DFE2,norm_fac_DFE3,delta_DFE2,delta_DFE3,cplx);
reference_vec = [D_1;D_2;D_3];
e_ffe = e_.'*input_vec;
e_dfe = b_.'*reference_vec;
error = e_dc + e_ffe - e_dfe - ref_in(m-obj.k0);
if real(obj.FFEmu)
if obj.l1act
sgn_e = e_;
sgn_e(e_~=0) = e_(e_~=0)./abs(e_(e_~=0));
e_ = e_ - obj.rho*sgn_e./(1+epsilon_*abs(e_)) - error*input_vec*obj.FFEmu;
else
e_ = e_ - error*conj(input_vec)*obj.FFEmu; %classic LMS gradient decay
end
else
if obj.l1act
sgn_e = e_;
sgn_e(e_~=0) = e_(e_~=0)./abs(e_(e_~=0));
e_ = e_ - obj.rho*sgn_e./(1+epsilon_*abs(e_)) - error*input_vec/(input_vec.'*input_vec);
else
e_ = e_ - error*input_vec/(input_vec.'*input_vec);
end
end
e_dc = e_dc - obj.DCmu*error;
cnt = cnt+1;
if obj.Nb(1) > 0
b_ = b_ + obj.DFEmu*error*reference_vec; % Seems like normalized DFE has worse performance
end
end
end
%%
% Plot the intermediate coefficients after training mode
obj.b = b_(1:obj.Nb(1));
obj.b2 = b_(obj.Nb(1)+1:obj.Nb(1)+Nb2);
obj.b3 = b_(obj.Nb(1)+Nb2+1:end);
obj.e = e_(1:obj.Ne(1));
obj.e2 = e_(obj.Ne(1)+1:obj.Ne(1)+N2);
obj.e3 = e_(obj.Ne(1)+N2+1:end);
if obj.plottrain
figure(8052)
sgtitle('Training Coeff')
subplot(2,3,1); stem((obj.e),'Markersize',2);
title('FFE coeff linear')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
subplot(2,3,2); stem(obj.e2,'Markersize',2);
title('FFE coeff nl 2nd')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
subplot(2,3,3); stem(obj.e3,'Markersize',2);
title('FFE coeff nl 3rd')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
subplot(2,3,4);stem(obj.b,'Markersize',2);
title('DFE coeff linear')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
subplot(2,3,5);stem(obj.b2,'Markersize',2);
title('DFE coeff nl 2nd')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
subplot(2,3,6);stem(obj.b3,'Markersize',2);
title('DFE coeff nl 3rd')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
end
if obj.l1act
neg_lin = find(abs(obj.e) < obj.thres(1));
neg_2nd = find(abs(obj.e2) < obj.thres(2));
neg_3rd = find(abs(obj.e3) < obj.thres(3));
neg = [neg_lin;neg_2nd+obj.Ne(1);neg_3rd+obj.Ne(1)+N2]; % indices of the neglected coefficients
rel_lin = find(abs(obj.e) >= obj.thres(1));
rel_2nd = find(abs(obj.e2) >= obj.thres(2));
rel_3rd = find(abs(obj.e3) >= obj.thres(3));
obj.coeff_number = length(rel_lin)+2*length(rel_2nd)+3*length(rel_3rd);
rel = [rel_lin;rel_2nd+obj.Ne(1);rel_3rd+obj.Ne(1)+N2]; % indices of the relevant coefficients
e_(neg) = 0;
ind_mat_2nd(neg_2nd,:) = [];
ind_mat_3rd(neg_3rd,:) = [];
end
%% decision directed mode
if ~obj.DB_aim
constellation_in_ = unique(ref_in); % getting the symbol constellation from reference data
else
if obj.M == 2
constellation_in_ = [-3 -2 -1 0 1 2 3]/sqrt(5)*2;
elseif obj.M == 2.5
constellation_in_ = [-5 -4 -3 -2 -1 0 1 2 3 4 5]/sqrt(10)*2;
elseif obj.M == 3
constellation_in_ = [-7 -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6 7]/sqrt(21)*2;
else
constellation_in_ = unique(ref_in);
end
end
obj.constellation_in = constellation_in_;
if obj.l1act
coeff = [e_(rel);b_]; % combine FFE and DFE coefficient vectors for DD mode
else
coeff = [e_;b_];
end
for dd_loop = 1:obj.dd_loops
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);
if all(obj.DDmu == obj.DDmu(1))
mu_mat = obj.DDmu(1);
else
if obj.l1act
mu_mat = diag([ones(1,length(rel_lin))*obj.DDmu(1) ones(1,length(rel_2nd))*obj.DDmu(2) ones(1,length(rel_3rd))*obj.DDmu(3) ones(1,obj.Nb)*obj.DDmu(4)]);
else
mu_mat = diag([ones(1,obj.Ne(1))*obj.DDmu(1) ones(1,N2)*obj.DDmu(2) ones(1,N3)*obj.DDmu(3) ones(1,obj.Nb(1)+Nb2+Nb3)*obj.DDmu(4)]);
end
end
if obj.load_decisions
pathn = evalin('base','modeldir');
temp = load([pathn, 'MLSE_out', '.mat']) ;
dd_out_vals=temp.a;
dd_out = zeros(size(data_in));
dd_out(1:2:length(data_in)) = dd_out_vals;
else
dd_out = zeros(size(data_in));
end
for k = 1:obj.K:length(data_in)
m=m+1; % Symbol index
X_1 = data(obj.Ne(1)+k-1:-1:k).';
[X_2,X_3] = obj.calc_nl_vecs(X_1,ind_mat_2nd,ind_mat_3rd,norm_fac2,norm_fac3,delta_2,delta_3,cplx);
if obj.l1act
input_vec = [X_1(rel_lin);X_2;X_3;-dd_DFE;-D_2;-D_3];
else
input_vec = [X_1;X_2;X_3;-dd_DFE;-D_2;-D_3];
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
% ---------- WDFE / PDFE ----------
fb_sym = dd_out(k);
if obj.weighted_DFE ~= 0
% Get constellation
const = obj.constellation_in;
% 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))/halfStep;
gamma_k = max(0, min(1, gamma_k)); % clamp to [0,1]
else
gamma_k = 1;
end
% 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
% 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
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) = 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);
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
coeff = coeff - mu_mat*error*conj(input_vec);
if 1 % mu_mat ~= 0
e_dc = e_dc - obj.DCmu*error;
cnt = cnt+1;
end
end
end
% shifting the output sequence by k0 symbols
yout = (circshift(output_vec.',-(obj.k0))).'; %(circshift(dd_out.',-(obj.k0))).';
e_ = coeff(1:end-obj.Nb(1)-Nb2-Nb3);
b_ = coeff(end-obj.Nb(1)-Nb2-Nb3+1:end);
if obj.l1act
obj.e = e_(1:length(rel_lin));
obj.e2 = e_(length(rel_lin)+1:length(rel_lin)+length(rel_2nd));
obj.e3 = e_(length(rel_lin)+length(rel_2nd)+1:end);
else
obj.e = e_(1:obj.Ne(1));
obj.e2 = e_(obj.Ne(1)+1:obj.Ne(1)+N2);
obj.e3 = e_(obj.Ne(1)+N2+1:end);
end
obj.b = b_(1:obj.Nb(1));
obj.b2 = b_(obj.Nb(1)+1:obj.Nb(1)+Nb2);
obj.b3 = b_(obj.Nb(1)+Nb2+1:end);
% plot the final coefficients after DD mode
if obj.plotfinal
figure(8054)
if obj.l1act
sgtitle('Final Coeff')
subplot(2,3,1); stem(rel_lin,obj.e,'Markersize',2);
title('FFE coeff linear')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
subplot(2,3,2); stem(rel_2nd,obj.e2,'Markersize',2);
title('FFE coeff nl 2nd')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
subplot(2,3,3); stem(rel_3rd,obj.e3,'Markersize',2);
title('FFE coeff nl 3rd')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
subplot(2,3,4);stem(obj.b,'Markersize',2);
title('DFE coeff linear')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
subplot(2,3,5);stem(obj.b2,'Markersize',2);
title('DFE coeff nl 2nd')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
subplot(2,3,6);stem(obj.b3,'Markersize',2);
title('DFE coeff nl 3rd')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
else
sgtitle('Final Coeff')
subplot(2,3,1); stem(obj.e/max(e_),'Markersize',2);
title('FFE coeff linear')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
subplot(2,3,2); stem(obj.e2,'Markersize',2);
title('FFE coeff nl 2nd')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
subplot(2,3,3); stem(obj.e3,'Markersize',2);
title('FFE coeff nl 3rd')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
subplot(2,3,4);stem(obj.b,'Markersize',2);
title('DFE coeff linear')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
subplot(2,3,5);stem(obj.b2,'Markersize',2);
title('DFE coeff nl 2nd')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
subplot(2,3,6);stem(obj.b3,'Markersize',2);
title('DFE coeff nl 3rd')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
end
set(gcf,'Position',[1000 500 700 400])
end
% save frequency response to the work space
if obj.save_taps
save("coefficients",obj.e, obj.b);
end
else
yout = data_in;
end
end
function [X_2,X_3] = calc_nl_vecs(obj,X_1,ind_mat_2,ind_mat_3,norm_fac2,norm_fac3,delta_2,delta_3,cplx)
% calculation of the vectors containing all combinations of input symbols
% of second and third order based on the linear symbols
if ind_mat_2(1) > 0
input_vec_se = X_1(delta_2:end)/norm_fac2;%(K*(k0-1):end)
X_2 = input_vec_se(ind_mat_2(:,1)).*input_vec_se(ind_mat_2(:,2));
else
X_2 = [];
end
if ind_mat_3(1) > 0
if cplx
input_vec_th = X_1(delta_3:end)/norm_fac3;
X_3 = input_vec_th(ind_mat_3(:,1)).*input_vec_th(ind_mat_3(:,2)).*conj(input_vec_th(ind_mat_3(:,3)));
else
input_vec_th = X_1(delta_3:end)/norm_fac3;
X_3 = input_vec_th(ind_mat_3(:,1)).*input_vec_th(ind_mat_3(:,2)).*input_vec_th(ind_mat_3(:,3));
end
else
X_3 = [];
end
end
function [ind_mat_2nd,ind_mat_3rd] = calc_ind(obj,Ne2,N2,Ne3,N3,mode2nd,mode3rd,len_2nd,len_3rd,cplx)
if Ne2 > 0
ind_mat_2nd = NaN(N2,2);
count=1;
if mode2nd == 1
for t = 1:Ne2
for u = t:Ne2
ind_mat_2nd(count,:) = [t u];
count = count + 1 ;
end
end
elseif mode2nd == 2
for t = 1:Ne2
ind_mat_2nd(t,:) = [t t];
end
elseif mode2nd == 3
for t = 1:Ne2
for u = t:Ne2
if u-t<=len_2nd
ind_mat_2nd(count,:) = [t u];
count = count + 1 ;
end
end
end
elseif mode2nd == 4
for t = 1:Ne2
for u = t:Ne2
if u-t<=ceil(Ne2/2)
ind_mat_2nd(count,:) = [t u];
count = count + 1 ;
end
end
end
end
else
ind_mat_2nd = 0;
end
if Ne3 > 0
ind_mat_3rd = NaN(N3,3);
count=1;
if mode3rd == 1
if cplx
for t = 1:Ne3
for u = t:Ne3
for v = 1:Ne3
ind_mat_3rd(count,:) = [t u v];
count = count + 1 ;
end
end
end
else
for t = 1:Ne3
for u = t:Ne3
for v = u:Ne3
ind_mat_3rd(count,:) = [t u v];
count = count + 1 ;
end
end
end
end
elseif mode3rd == 2
for t = 1:Ne3
ind_mat_3rd(t,:) = [t t t];
end
elseif mode3rd == 3
for t = 1:Ne3
for u = t:Ne3
ind_mat_3rd(count,:) = [t t u];
if t ~= u
count = count + 1;
ind_mat_3rd(count,:) = [t u u];
end
count = count + 1;
end
end
elseif mode3rd == 4
for t = 1:Ne3
for u = t:Ne3
for v = u:Ne3
if u-t<=len_3rd && v-t<=len_3rd
ind_mat_3rd(count,:) = [t u v];
count = count + 1 ;
end
end
end
end
elseif mode3rd == 5
for t = 1:Ne3
for u = t:Ne3
if u-t<=len_3rd
ind_mat_3rd(count,:) = [t t u];
if t ~= u
count = count + 1;
ind_mat_3rd(count,:) = [t u u];
end
count = count + 1;
end
end
end
ind_mat_3rd2 = NaN(N3,3);
count = 1;
for t = 1:Ne3
for u = t:min(Ne3,t+len_3rd)
for v = unique([t u])
ind_mat_3rd2(count,:) = [t v u];
count = count + 1;
end
end
end
end
else
ind_mat_3rd = 0;
end
end
function [ind_mat_2nd,ind_mat_3rd] = calc_DFE_ind(obj,Ne2,N2,Ne3,N3)
if Ne2 > 0
ind_mat_2nd = NaN(N2,2);
count=1;
for t = 1:Ne2
for u = t:Ne2
ind_mat_2nd(count,:) = [t u];
count = count + 1 ;
end
end
else
ind_mat_2nd = 0;
end
if Ne3 > 0
ind_mat_3rd = NaN(N3,3);
count=1;
for t = 1:Ne3
for u = t:Ne3
for v = u:Ne3
ind_mat_3rd(count,:) = [t u v];
count = count + 1 ;
end
end
end
else
ind_mat_3rd = 0;
end
end
end
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