Minimal Working - seems too good?!

This commit is contained in:
Silas Oettinghaus
2023-05-16 17:43:51 +02:00
parent 709cee9ecd
commit f5c3a1b902
23 changed files with 1476 additions and 260 deletions

View File

@@ -79,7 +79,29 @@ classdef AWG
end
function elec_out = process_channel(obj,data_in)
function signalclass_out = process(obj,signalclass_in)
% actual processing of the signal (steps 1. - 3.)
signalclass_in.signal = obj.process_(signalclass_in.signal);
% 4. Apply LPF on the signal
if obj.lpf_active
lpf = Filter('filtdegree',4,"f_cutoff",obj.f_cutoff,"fsamp",obj.kover*obj.fdac,"filterType",filtertypes.bessel_inp);
signalclass_in = lpf.process(signalclass_in);
end
% cast the inform. signal to electrical signal
signalclass_in = Electricalsignal(signalclass_in,"fs",obj.fdac*obj.kover,"logbook",signalclass_in.logbook);
% append to logbook
signalclass_in = signalclass_in.logbookentry();
% write to output
signalclass_out = signalclass_in;
end
function elec_out = process_(obj,data_in)
%METHOD1 Summary of this method goes here
% Detailed explanation goes here
arguments(Input)
@@ -119,13 +141,7 @@ classdef AWG
elec_out = obj.skew(elec_out);
end
% 4. Apply LPF on the signal
if obj.lpf_active
lpf = Filter('filtdegree',4,"f_cutoff",obj.f_cutoff,"fsamp",obj.kover*obj.fdac,"filterType",filtertypes.bessel_inp);
elec_out = lpf.process(elec_out);
% obj.H_lpf = obj.buildFilter(1);
% data_out = obj.lpf(data_out) ;
end
end

View File

@@ -53,7 +53,22 @@ classdef Amplifier
end
function [y_out,nase] = process(obj,x_in,optional)
function signalclass_out = process(obj,signalclass_in)
% actual processing of the signal (steps 1. - 3.)
signalclass_in.signal = obj.process_(signalclass_in.signal);
% append to logbook
lbdesc = ['Amp '];
signalclass_in = signalclass_in.logbookentry(lbdesc);
% write to output
signalclass_out = signalclass_in;
end
function [y_out,nase] = process_(obj,x_in,optional)
arguments
obj
@@ -98,11 +113,11 @@ classdef Amplifier
if obj.amp_mode == "output_power"
seemsright = pow_out_dbm == obj.amplification_db;
elseif obj.amp_mode == "gain"
seemsright = pow_out_dbm == pow_in_dbm+ obj.amplification_db;
seemsright = pow_out_dbm == pow_in_dbm + obj.amplification_db;
end
if ~seemsright
warning("Amplifier output not correct, please check the reason");
% warning("Amplifier output not correct, please check the reason");
end
end

View File

@@ -64,7 +64,25 @@ classdef EML
end
function [opt_out,obj] = process(obj,elec_in)
function signalclass_out = process(obj,signalclass_in)
% actual processing of the signal (steps 1. - 3.)
signalclass_in.signal = obj.process_(signalclass_in.signal);
% cast the inform. signal to electrical signal
signalclass_in = Opticalsignal(signalclass_in,"fs",obj.fsimu,"logbook",signalclass_in.logbook,"lambda",obj.lambda*1e-9,"nase",0);
% append to logbook
lbdesc = ['EML '];
signalclass_in = signalclass_in.logbookentry(lbdesc);
% write to output
signalclass_out = signalclass_in;
end
function [opt_out,obj] = process_(obj,elec_in)
%METHOD1 Summary of this method goes here
% Detailed explanation goes here
@@ -76,6 +94,8 @@ classdef EML
if obj.linewidth ~= 0
ph_noi = obj.createPhaseNoise;
laserfield = obj.field.*exp(1i*ph_noi);
%remember phase (! you need to receive the altered eml object in you sim program !)
obj.phase = ph_noi(end);
else
laserfield = obj.field;
end
@@ -83,8 +103,7 @@ classdef EML
%modulate the laserfield with the electrical signal
opt_out = obj.externalmodulation(laserfield,elec_in);
%remember phase (! you need to receive the altered eml object in you sim program !)
obj.phase = ph_noi(end);
end

View File

@@ -33,9 +33,24 @@ classdef EQ
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
k0
b
b2
b3
e
e2
e3
coeff_number
constellation_in
end
@@ -44,13 +59,65 @@ classdef EQ
%EQ Construct an instance of this class
% Detailed explanation goes here
arguments(Input)
options
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.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
% alles nochmal mappen
end
function yout = process(obj,data_in,ref_in)
function signalclass_out = 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';
% append to logbook
lbdesc = ['EQ '];
signalclass_in = signalclass_in.logbookentry(lbdesc);
% write to output
signalclass_out = signalclass_in;
end
function yout = process_(obj,data_in,ref_in)
%METHOD1 Summary of this method goes here
% Detailed explanation goes here
@@ -141,107 +208,107 @@ classdef EQ
[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)]);
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
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
e_ = zeros(obj.Ne(1)+N2+N3,1); % initialization of filter coefficients
% e(ceil(obj.Ne(1)/2)) = 1; % set central tap to 1 (better starting point since it's closer to the expected solution)
b = zeros(obj.Nb(1)+Nb2+Nb3,1);
b_ = zeros(obj.Nb(1)+Nb2+Nb3,1);
e_dc = mean(data_in); % initilaization of the dc tap with the mean value of the data
% e_save = NaN(361,8.6e5);
% save_ind = 1;
for trainloops = 1:obj.training_loops
m = state.k0+1; % starting symbol index at the delay compared to the training sequence
for n = obj.K*state.k0+1:obj.K:obj.K*obj.training_length
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 = m+1;
X_1 = data(obj.Ne(1)+n+(obj.K-1):-1:n+obj.K).';
[X_2,X_3] = calc_nl_vecs(X_1,ind_mat_2nd,ind_mat_3rd,norm_fac2,norm_fac3,delta_2,delta_3,cplx);
[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);
D_1 = ref(obj.Nb(1)-state.k0+m-2:-1:m-state.k0-1).';
[D_2,D_3] = calc_nl_vecs(D_1,ind_mat_DFE_2nd,ind_mat_DFE_3rd,norm_fac_DFE2,norm_fac_DFE3,delta_DFE2,delta_DFE3,cplx);
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);
input_vec = [X_1;X_2;X_3];
reference_vec = [D_1;D_2;D_3];
error = e_dc + e.'*input_vec - b.'*reference_vec - ref_in(m-state.k0); % error = e_dc + e.'*input_vec - b.'*reference_vec - ref_in(m-state.k0);
error = e_dc + e_.'*input_vec - b_.'*reference_vec - 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;
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;
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; %e = e - error*conj(input_vec)*obj.FFEmu; %e = e - error*input_vec*obj.FFEmu;
e_ = e_ - error*conj(input_vec)*obj.FFEmu; %e = e - error*conj(input_vec)*obj.FFEmu; %e = e - error*input_vec*obj.FFEmu;
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);
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);
e_ = e_ - error*input_vec/(input_vec.'*input_vec);
end
end
% e_save(:,save_ind) = e;
% save_ind = save_ind+1;
e_dc = e_dc - obj.dcmu*error;
e_dc = e_dc - obj.DCmu*error;
if obj.Nb(1) > 0
b = b + obj.DFEmu*error*reference_vec; % Seems like normalized DFE has worse performance
b_ = b_ + obj.DFEmu*error*reference_vec; % Seems like normalized DFE has worse performance
end
end
end
%%
% Plot the intermediate coefficients after training mode
state.b = b(1:obj.Nb(1));
state.b2 = b(obj.Nb(1)+1:obj.Nb(1)+Nb2);
state.b3 = b(obj.Nb(1)+Nb2+1:end);
state.e = e(1:obj.Ne(1));
state.e2 = e(obj.Ne(1)+1:obj.Ne(1)+N2);
state.e3 = e(obj.Ne(1)+N2+1: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);
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)
subplot(2,3,1); stem(abs(state.e),'Markersize',2);
subplot(2,3,1); stem(abs(obj.e),'Markersize',2);
title('FFE coeff linear')
xlabel('coefficient index'); ylabel('value'); set(gca,'Fontsize',12)
subplot(2,3,2); stem(state.e2,'Markersize',2);
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(state.e3,'Markersize',2);
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(state.b,'Markersize',2);
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(state.b2,'Markersize',2);
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(state.b3,'Markersize',2);
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(state.e) < obj.thres(1));
neg_2nd = find(abs(state.e2) < obj.thres(2));
neg_3rd = find(abs(state.e3) < obj.thres(3));
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(state.e) >= obj.thres(1));
rel_2nd = find(abs(state.e2) >= obj.thres(2));
rel_3rd = find(abs(state.e3) >= obj.thres(3));
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));
state.coeff_number = length(rel_lin)+2*length(rel_2nd)+3*length(rel_3rd);
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;
e_(neg) = 0;
ind_mat_2nd(neg_2nd,:) = [];
@@ -250,24 +317,25 @@ classdef EQ
%% decision directed mode
if ~obj.DB_aim
constellation_in = unique(ref_in); % getting the symbol constellation from reference data
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;
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;
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;
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);
constellation_in_ = unique(ref_in);
end
end
state.constellation_in = constellation_in;
obj.constellation_in = constellation_in_;
if obj.l1act
coeff = [e(rel);b]; % combine FFE and DFE coefficient vectors for DD mode
coeff = [e_(rel);b_]; % combine FFE and DFE coefficient vectors for DD mode
else
coeff = [e;b];
coeff = [e_;b_];
end
for dd_loop = 1:obj.dd_loops
@@ -277,20 +345,21 @@ classdef EQ
D_2 = zeros(Nb2,1);
D_3 = zeros(Nb3,1);
if all(obj.mu == obj.mu(1))
mu_mat = obj.mu(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.mu(1) ones(1,length(rel_2nd))*obj.mu(2) ones(1,length(rel_3rd))*obj.mu(3) ones(1,obj.Nb)*obj.mu(4)]);
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.mu(1) ones(1,N2)*obj.mu(2) ones(1,N3)*obj.mu(3) ones(1,obj.Nb(1)+Nb2+Nb3)*obj.mu(4)]);
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']) ;
eval(['dd_out_vals = temp.', 'a', ';']) ;
%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;
else
@@ -300,7 +369,7 @@ classdef EQ
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] = calc_nl_vecs(X_1,ind_mat_2nd,ind_mat_3rd,norm_fac2,norm_fac3,delta_2,delta_3,cplx);
[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];
@@ -311,18 +380,18 @@ classdef EQ
output_vec(m) = e_dc + input_vec.'*coeff;
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);
[~,dd_idx] = min(abs(output_vec(m) - constellation_in_)); % decision for closest constellation point
dd_out(k) = constellation_in_(dd_idx);
end
if obj.Nb(1) > 0
dd_DFE(2:end) = dd_DFE(1:end-1);
dd_DFE(1) = dd_out(k);
if obj.error_free && m > state.k0
dd_DFE(1) = ref_in(m-state.k0);
if obj.ideal_dfe && m > obj.k0
dd_DFE(1) = ref_in(m-obj.k0);
end
[D_2,D_3] = 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 dd_loop ~= 21
error = output_vec(m) - dd_out(k);
@@ -335,18 +404,96 @@ classdef EQ
% save_ind = save_ind+1;
if mu_mat ~= 0
e_dc = e_dc - obj.dcmu*error;
e_dc = e_dc - obj.DCmu*error;
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
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
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 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
else
yout = data_in;
end
end
function [X_2,X_3] = calc_nl_vecs(X_1,ind_mat_2,ind_mat_3,norm_fac2,norm_fac3,delta_2,delta_3,cplx)
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
@@ -370,7 +517,7 @@ classdef EQ
end
end
function [ind_mat_2nd,ind_mat_3rd] = calc_ind(Ne2,N2,Ne3,N3,mode2nd,mode3rd,len_2nd,len_3rd,cplx)
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);
@@ -498,7 +645,7 @@ classdef EQ
end
function [ind_mat_2nd,ind_mat_3rd] = calc_DFE_ind(Ne2,N2,Ne3,N3)
function [ind_mat_2nd,ind_mat_3rd] = calc_DFE_ind(obj,Ne2,N2,Ne3,N3)
if Ne2 > 0
ind_mat_2nd = NaN(N2,2);

View File

@@ -1,25 +1,45 @@
classdef Electricalsignal < Signal
%ELECTRICALSIGNAL Summary of this class goes here
% Detailed explanation goes here
properties
fs
end
methods
function obj = Electricalsignal(signal)
function obj = Electricalsignal(signal, options)
%ELECTRICALSIGNAL Construct an instance of this class
% Detailed explanation goes here
arguments
signal
options.fs
options.logbook
end
obj = obj@Signal(signal);
fn = fieldnames(options);
for l = 1:numel(fn)
obj.(fn{l}) = options.(fn{l});
end
end
function outputArg = method1(obj,inputArg)
%METHOD1 Summary of this method goes here
% Detailed explanation goes here
outputArg = obj.Property1 + inputArg;
function pow = power(obj)
pow = mean(abs(obj.signal),"all") ;
end
function obj = normalize(obj)
obj.signal = obj.signal/sqrt(mean(abs(obj.signal),"all"));
end
end
end

View File

@@ -51,7 +51,21 @@ classdef Fiber
end
function opt_out = process(obj,opt_in)
function signalclass_out = process(obj,signalclass_in)
% actual processing of the signal (steps 1. - 3.)
signalclass_in.signal = obj.process_(signalclass_in.signal);
% append to logbook
lbdesc = ['Fiber '];
signalclass_in = signalclass_in.logbookentry(lbdesc);
% write to output
signalclass_out = signalclass_in;
end
function opt_out = process_(obj,opt_in)
%METHOD1 Summary of this method goes here
% Detailed explanation goes here
@@ -62,7 +76,6 @@ classdef Fiber
obj.linstep = -obj.alpha_lin/2 - 2*1j*pi^2*obj.b2*faxis.^2 - 4/3*1j*pi^3*obj.b3*faxis.^3;
opt_out = obj.NLSE(opt_in);
%attenuate nase

View File

@@ -40,7 +40,21 @@ classdef Filter
end
function yout = process(obj,xin)
function signalclass_out = process(obj,signalclass_in)
% actual processing of the signal
signalclass_in.signal = obj.process_(signalclass_in.signal);
% append to logbook
filterdesc = [num2str(obj.filtdegree),'. order ',char(obj.filterType),' filter with f_cutoff at ', num2str(obj.f_cutoff*1e-9), ' GHz.'];
signalclass_in = signalclass_in.logbookentry(filterdesc);
% write to output
signalclass_out = signalclass_in;
end
function yout = process_(obj,xin)
obj.signal_length = length(xin);

View File

@@ -3,8 +3,8 @@ classdef Informationsignal < Signal
% Detailed explanation goes here
properties
nase
lambda_nm
end
methods
@@ -15,11 +15,18 @@ classdef Informationsignal < Signal
end
function outputArg = method1(obj,inputArg)
%METHOD1 Summary of this method goes here
% Detailed explanation goes here
outputArg = obj.Property1 + inputArg;
function pow = power(obj)
pow = mean(abs(obj.signal),"all") ;
end
function obj = normalize(obj)
obj.signal = obj.signal/sqrt(mean(abs(obj.signal),"all"));
end
end
end

View File

@@ -4,24 +4,45 @@ classdef Opticalsignal < Signal
properties
nase
lambda_nm
lambda
fs
end
methods
function obj = Opticalsignal(signal, fsym, fsimu)
function obj = Opticalsignal(signal, options)
%OPTICALSIGNAL Construct an instance of this class
% Detailed explanation goes here
obj = obj@Signal(signal, fsym, fsimu);
arguments
signal
options.fs
options.logbook
options.lambda
options.nase
end
obj = obj@Signal(signal);
fn = fieldnames(options);
for l = 1:numel(fn)
obj.(fn{l}) = options.(fn{l});
end
obj.nase = 0;
obj.lambda_nm = [];
end
function outputArg = method1(obj,inputArg)
%METHOD1 Summary of this method goes here
% Detailed explanation goes here
outputArg = obj.Property1 + inputArg;
function obj = normalize(obj)
obj.signal = obj.signal/sqrt(mean(abs(obj.signal).^2));
end
function pow = power(obj)
pow = mean(abs(obj.signal.^2)) ;
end
end
end

183
Classes/PAMmapper.m Normal file
View File

@@ -0,0 +1,183 @@
classdef PAMmapper
%PAMMAPPER Summary of this class goes here
% Detailed explanation goes here
properties
M
unipolar
thresholds
end
methods
function obj = PAMmapper(M, unipolar)
%PAMMAPPER Construct an instance of this class
% Detailed explanation goes here
obj.M = M;
obj.unipolar = unipolar;
obj.thresholds = obj.get_demodulation_thresholds();
end
function signalclass_out = map(obj,signalclass_in)
signalclass_in.signal = obj.map_(signalclass_in.signal);
signalclass_in = signalclass_in.logbookentry();
signalclass_out = signalclass_in;
end
function signalclass_out = demap(obj,signalclass_in)
signalclass_in.signal = obj.demap_(signalclass_in.signal);
signalclass_in = signalclass_in.logbookentry();
signalclass_out = signalclass_in;
end
function pam_sig = map_(obj,bitpattern)
switch log2(obj.M)
case 1
% 2-ASK: BPSK / OOK
pam_sig=bitpattern(:,1);
if obj.unipolar==0
pam_sig=2*pam_sig-1;
end
case 2
% 4-ASK:
pam_sig=2*bitpattern(:,1)+(bitpattern(:,1)==bitpattern(:,2));
if obj.unipolar==0
pam_sig=2*pam_sig-3;
end
case 3
% 8-ASK:
x1 = bitpattern(:,1);
x2 = (bitpattern(:,1)==bitpattern(:,3));
x3 = x2~=bitpattern(:,2);
pam_sig = 4*x1 + 2*x2 + x3;
if obj.unipolar==0
pam_sig=2*pam_sig-7;
end
case 4
% 16-ASK:
x1 = bitpattern(:,1);
x2 = (bitpattern(:,1)==bitpattern(:,4));
x3 = x2~=bitpattern(:,3);
x4 = x3~=bitpattern(:,2);
pam_sig = 8*x1 + 4*x2 + 2*x3 + x4;
if obj.unipolar==0
pam_sig=2*pam_sig-15;
end
end
end
function thres = get_demodulation_thresholds(obj)
%simply get the obj.thresholdseshold values for PAM
%28.03.2023 - Silas Oett. - Extracted from digi_demod.m
%
obj.thresholds = 0;
switch log2(obj.M)
case 1
% 2-ASK
if obj.unipolar
thres=0.5;
else %bi polar
thres=0;
end
case 2
% 4-ASK
if obj.unipolar==0
thres=[-2,0,2];
elseif obj.unipolar==1
thres=[0.5,1.5,2.5];
end
case 3
% 8-ASK
if obj.unipolar==0
thres=-6:2:6;
elseif obj.unipolar==1
thres=0.5:6.5;
end
case 4
% 16-ASK
if obj.unipolar==0 && scale_mode==1
thres=-14:2:14;
elseif obj.unipolar==1 && scale_mode==1
thres=0.5:14.5;
end
end
end
function [data_out] = demap_(obj,data_in)
data_in= data_in';
% create output
if ~isempty(obj.thresholds)
a = squeeze(repmat(real(data_in),[1 1 length(obj.thresholds)])); %Eingangssignal in 3 spalten
b = squeeze(repmat(reshape(obj.thresholds(:).',[1 1 length(obj.thresholds)]),[1 length(data_in) 1])); %Threshold in 3 Spalten
comp_real = a > b; %check for each symbol/ sampling if it exeeds the obj.thresholdseshold 1, 2 or 3
comp_real=repmat(real(data_in),[1 1 length(obj.thresholds)]) > repmat(reshape(obj.thresholds(:).',[1 1 length(obj.thresholds)]),[1 length(data_in) 1]);
else
comp_real=[];
end
s1=size(comp_real,1);
s2=size(comp_real,2);
switch log2(obj.M)
case 1
% 2-ASK
data_out=comp_real(:,:,1);
case 2
% 4-ASK
data_out=[comp_real(:,:,2); ones(s1,s2)-comp_real(:,:,1)+comp_real(:,:,3)];
case 3
% 8-ASK
data_out=[comp_real(:,:,4);
comp_real(:,:,1)-comp_real(:,:,3)+comp_real(:,:,5)-comp_real(:,:,7);
1-comp_real(:,:,2)+comp_real(:,:,6)];
case 4
% 16-ASK
data_out=[comp_real(:,:,8);
comp_real(:,:,1)-comp_real(:,:,3)+comp_real(:,:,5)-comp_real(:,:,7)+comp_real(:,:,9)-comp_real(:,:,11)+comp_real(:,:,13)-comp_real(:,:,15);
comp_real(:,:,2)-comp_real(:,:,6)+comp_real(:,:,10)-comp_real(:,:,14);
1-comp_real(:,:,4)+comp_real(:,:,12)];
end
end
end
end

View File

@@ -28,7 +28,24 @@ classdef Photodiode
end
function yout = process(obj,xin)
function signalclass_out = process(obj,signalclass_in)
% actual processing of the signal (steps 1. - 3.)
signalclass_in.signal = obj.process_(signalclass_in.signal);
% cast the inform. signal to electrical signal
[signalclass_in, nase, lambda] = Electricalsignal(signalclass_in,"fs",obj.fsimu,"logbook",signalclass_in.logbook);
% append to logbook
lbdesc = ['Photo Diode '];
signalclass_in = signalclass_in.logbookentry(lbdesc);
% write to output
signalclass_out = signalclass_in;
end
function yout = process_(obj,xin)
%METHOD1 Summary of this method goes here
% Detailed explanation goes here

View File

@@ -68,18 +68,32 @@ classdef Scope
end
function yout = process(obj,xin)
%METHOD1 Summary of this method goes here
% Detailed explanation goes here
function signalclass_out = process(obj,signalclass_in)
% apply LPF
lpf = Filter('filtdegree',4,"f_cutoff",obj.lpf_bw,"fsamp",obj.fsimu,"filterType",obj.filtertype);
yout = lpf.process(xin);
signalclass_in = lpf.process(signalclass_in);
% actual processing of the signal
signalclass_in.signal = obj.process_(signalclass_in.signal);
% append to logbook
lbdesc = ['Scope '];
signalclass_in = signalclass_in.logbookentry(lbdesc);
% write to output
signalclass_out = signalclass_in;
end
function yout = process_(obj,xin)
%METHOD1 Summary of this method goes here
% Detailed explanation goes here
% sample signal
% TODO: implement and test the delays. Also look for delay of
% lpf filter
yout = obj.sampleSignal(yout);
yout = obj.sampleSignal(xin);
% quantize signal
yout = obj.quantize(yout);
@@ -118,7 +132,7 @@ classdef Scope
%calc number of samples after down-sampling no offset
obj.Nout = ceil((Tsig - fracdelay)*obj.fadc) ;
%build a jitter vector
%build a jitter vector
jitvec = obj.buildSamplingJitterVector();
% Create the index vector of the sampling instances for the real and imaginary part

View File

@@ -1,47 +1,152 @@
classdef Signal
%SIGNAL Summary of this class goes here
% Detailed explanation goes here
properties
signal
fsym
fsimu
logbook
end
methods
function obj = Signal(signal)
%SIGNAL Construct an instance of this class
% Detailed explanation goes here
obj.signal = signal;
obj.fsym = 0;
obj.fsimu = 0;
SignalType = [];
TimeStamp = [];
Length = [];
SignalPower = [];
Nase = [];
Description = [];
obj.logbook = table(SignalType,TimeStamp,Length,SignalPower,Nase,Description);
end
function [e_sig, nase, lambda_nm] = Electricalsignal(obj)
function [i_sig, varargout] = Informationsignal(obj)
if isa(obj,'Electricalsignal')
%convert to optical
disp("Convert signal: elec. -> info.!");
varargout{1} = obj.fs;
i_sig = Informationsignal(obj.signal);
elseif isa(obj,'Opticalsignal')
error("Cannot convert from optical- to informationsignal. Use O/E conversion first.");
end
end
function [e_sig, varargout] = Electricalsignal(obj,options)
arguments
obj
options.fs
options.logbook
end
obj.logbook = options.logbook;
if isa(obj,'Opticalsignal')
%convert to electrical
disp("Convert signal: opt. -> elec. Fetch all properties (e.g. nase)!");
nase = obj.nase;
lambda_nm = obj.lambda_nm;
e_sig = Electricalsignal(obj.signal,obj.fsym, obj.fsimu);
varargout{1} = obj.nase;
varargout{2} = obj.lambda;
e_sig = Electricalsignal(obj.signal,"fs",obj.fs,"logbook",obj.logbook);
elseif isa(obj,'Informationsignal')
try
% specify fs at varargin{1}
e_sig = Electricalsignal(obj.signal,"fs",options.fs,"logbook",options.logbook);
catch
error("Signal Conversion failed [I -> E] ");
end
end
end
function o_sig = Opticalsignal(obj)
function o_sig = Opticalsignal(obj, options)
arguments
obj
options.fs
options.logbook
options.nase
options.lambda
end
fn = fieldnames(options);
for l = 1:numel(fn)
try
obj.(fn{l}) = options.(fn{l});
end
end
if isa(obj,'Electricalsignal')
%convert to optical
disp("Convert signal: elec. -> opt.!");
o_sig = Opticalsignal(obj.signal,obj.fsym, obj.fsimu);
o_sig = Opticalsignal(obj.signal,"fs",obj.fs,"lambda",options.lambda,"logbook",obj.logbook,"nase",options.nase);
elseif isa(obj,'Informationsignal')
error("Cannot convert from information- to opticalsignal. Use E/O conversion first.");
end
end
function normalizedsignal = signal_(obj)
normalizedsignal = obj.signal / norm(obj.signal);
function return_length = length(obj)
%METHOD1 Summary of this method goes here
% Detailed explanation goes here
return_length = length(obj.signal);
end
function obj = logbookentry(obj,varargin)
if nargin > 1
Description = varargin{1};
else
Description = "";
end
SignalType = [string(class(obj))];
TimeStamp = [(datetime('now','TimeZone','local','Format','HH:mm:ss'))];
Length = [obj.length];
SignalPower = [obj.power];
Nase = [0];
cell = {SignalType , TimeStamp , Length , SignalPower , Nase, Description};
obj.logbook = [obj.logbook;cell];
end
function obj = resample(obj,options)
arguments
obj Signal
options.fs_in double
options.fs_out double
end
obj.signal = resample(obj.signal,options.fs_out,options.fs_in);
desc = ['resample signal from ', num2str(options.fs_in*1e-9), ' GHz to ', num2str(options.fs_out*1e-9), ' GHz' ];
obj = obj.logbookentry(desc);
end
end