diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..6f25ac2 Binary files /dev/null and b/.DS_Store differ diff --git a/Classes/AWG.m b/Classes/AWG.m index 0ed6ecb..1eb8a84 100644 --- a/Classes/AWG.m +++ b/Classes/AWG.m @@ -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 diff --git a/Classes/Amplifier.m b/Classes/Amplifier.m index dc90618..4b403bf 100644 --- a/Classes/Amplifier.m +++ b/Classes/Amplifier.m @@ -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 diff --git a/Classes/EML.m b/Classes/EML.m index cfe4efd..92be1e0 100644 --- a/Classes/EML.m +++ b/Classes/EML.m @@ -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 diff --git a/Classes/EQ.m b/Classes/EQ.m index b52f3f1..0306d8d 100644 --- a/Classes/EQ.m +++ b/Classes/EQ.m @@ -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); diff --git a/Classes/Electricalsignal.m b/Classes/Electricalsignal.m index defadb1..61b872c 100644 --- a/Classes/Electricalsignal.m +++ b/Classes/Electricalsignal.m @@ -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 diff --git a/Classes/Fiber.m b/Classes/Fiber.m index 30ff317..3e65728 100644 --- a/Classes/Fiber.m +++ b/Classes/Fiber.m @@ -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 diff --git a/Classes/Filter.m b/Classes/Filter.m index 1ea009f..e5fa121 100644 --- a/Classes/Filter.m +++ b/Classes/Filter.m @@ -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); diff --git a/Classes/Informationsignal.m b/Classes/Informationsignal.m index f204a4e..b3c7940 100644 --- a/Classes/Informationsignal.m +++ b/Classes/Informationsignal.m @@ -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 diff --git a/Classes/Opticalsignal.m b/Classes/Opticalsignal.m index cf2f648..8b58ea9 100644 --- a/Classes/Opticalsignal.m +++ b/Classes/Opticalsignal.m @@ -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 diff --git a/Classes/PAMmapper.m b/Classes/PAMmapper.m new file mode 100644 index 0000000..462b61e --- /dev/null +++ b/Classes/PAMmapper.m @@ -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 + diff --git a/Classes/Photodiode.m b/Classes/Photodiode.m index 9d69308..c48b7cc 100644 --- a/Classes/Photodiode.m +++ b/Classes/Photodiode.m @@ -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 diff --git a/Classes/Scope.m b/Classes/Scope.m index c3506c3..99712a0 100644 --- a/Classes/Scope.m +++ b/Classes/Scope.m @@ -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 diff --git a/Classes/Signal.m b/Classes/Signal.m index f0f4cb1..bdc666f 100644 --- a/Classes/Signal.m +++ b/Classes/Signal.m @@ -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 diff --git a/Functions/.DS_Store b/Functions/.DS_Store new file mode 100644 index 0000000..f7b81c2 Binary files /dev/null and b/Functions/.DS_Store differ diff --git a/Functions/settingsdlg/.gitignore b/Functions/settingsdlg/.gitignore new file mode 100644 index 0000000..5a7ccc8 --- /dev/null +++ b/Functions/settingsdlg/.gitignore @@ -0,0 +1,11 @@ +slprj/ +*.mexw32 +*.mexglx +*.mexmaci +*.mexw64 +*.mexmaci64 +*.mexa64 +*.zip +*.m~ +*.asv + diff --git a/Functions/settingsdlg/License.txt b/Functions/settingsdlg/License.txt new file mode 100644 index 0000000..b808cd3 --- /dev/null +++ b/Functions/settingsdlg/License.txt @@ -0,0 +1,26 @@ +Copyright (c) 2018, Rody Oldenhuis +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of this project. diff --git a/Functions/settingsdlg/README.md b/Functions/settingsdlg/README.md new file mode 100644 index 0000000..4016d9b --- /dev/null +++ b/Functions/settingsdlg/README.md @@ -0,0 +1,114 @@ +[![View Settings dialog on File Exchange](https://www.mathworks.com/matlabcentral/images/matlab-file-exchange.svg)](https://www.mathworks.com/matlabcentral/fileexchange/26312-settings-dialog) + + +[![Donate to Rody](https://i.stack.imgur.com/bneea.png)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4M7RMVNMKAXXQ&source=url) + + +# FEX-settingsdlg + +The function settingsdlg() is a GUI-dialog much like MATLAB's default errordlg(), questiondlg() and warndlg(), which provides a standardized way to assign specific values to a structure. This structure can then be used to insert specific settings +into one of MATLAB's many standard algorithms, or your own. The most basic usage is as follows: + +[ settings, button] = settingsdlg(... +'TolX' , 1e-6,... +'TolFun', 1e-6); +which will produce a nice dialog box with the fields and edit boxes as you'd expect them. After pressing OK or Cancel, the structure settings will be + +settings = + +TolX: 1.0000e-006 +TolFun: 1.0000e-006 +button = +'ok' + +or any relevant values you have assigned. Naturally, you can add as many fields as you want; the dialog will automatically adjust its size to match your input. If you would like the user to not just insert numeric values, but select values from a +string list, use + +settings = settingsdlg(... +'TolX' , 1e-6,... +'TolFun' , 1e-6,... +'Algorithm', {'active-set','interior-point'}); + +which will produce the same dialog, with a popup-list added. The resulting structure in this case is: + +settings = + +TolX: 1.0000e-006 +TolFun: 1.0000e-006 +Algorithm: 'active-set' + +Of course, it isn't always convenient to have the text for each option in the dialog box equal to the fieldname in the resulting structure. If you want the fieldname to be different from the displayed string, you can use something like: + +settings = settingsdlg(... +{'Tolerance X' ;'TolX' }, 1e-6,... +{'Tolerance Fun';'TolFun'}, 1e-6,... +'Algorithm', {'active-set','interior-point'}); + +which produces the dialog displaying the *first* entries in the cell-arrays, but the associated structure has the fieldnames + +settings = + +TolX: 1.0000e-006 +TolFun: 1.0000e-006 +Algorithm: 'active-set' + +Also, you can add separators, a different dialog title, and a brief description: + +settings = settingsdlg(... +'Description', 'This dialog will set the parameters used by FMINCON()',... +'title' , 'FMINCON() options',... +'separator' , 'Unconstrained/General',... +{'Tolerance X' ;'TolX' }, 1e-6,... +{'Tolerance on Function';'TolFun'}, 1e-6,... +'Algorithm' , {'active-set','interior-point'},... +'separator' , 'Constrained',... +{'Tolerance on Constraint';'TolCon'}, 1e-6); + +The 'title' and 'description' options can appear anywhere in the argument list, they will not affect the fields in the output structure. The order of the 'separator' option of course *does* matter, but, it will *not* be added as a field to the output structure. You can also use logicals, which produce checkboxes: + +settings = settingsdlg(... +'Description', 'This dialog will set the parameters used by FMINCON()',... +'title' , 'FMINCON() options',... +'separator' , 'Unconstrained/General',... +{'Tolerance X';'TolX'}, 1e-6,... +{'Tolerance on Function';'TolFun'}, 1e-6,... +'Algorithm' , {'active-set','interior-point'},... +'separator' , 'Constrained',... +{'This is a checkbox'; 'Check'}, true,... +{'Tolerance on Constraints';'TolCon'}, 1e-6); + +which results in + +settings = + +TolX: 1.0000e-006 +TolFun: 1.0000e-006 +Algorithm: 'active-set' +Check: 1 +TolCon: 1.0000e-006 + +You can also assign multiple (logical!) values to a single checkbox, in which case the fields below the checkbox are all disabled/enabled when you check it: + +settings = settingsdlg(... +'Description', 'This dialog will set the parameters used by FMINCON()',... +'title' , 'FMINCON() options',... +'separator' , 'Unconstrained/General',... +{'This is a checkbox'; 'Check'}, [true, true],... +{'Tolerance X';'TolX'}, 1e-6,... +{'Tolerance on Function';'TolFun'}, 1e-6,... +'Algorithm' , {'active-set','interior-point'},... +'separator' , 'Constrained',... +{'Tolerance on Constraints';'TolCon'}, 1e-6); + +Setting the checkbox value to [true, true] will cause the dialog box to appear with all fields below the appropriate separator disabled, whereas a value of [true, false] will have all fields initially enabled. Checking or un-checking the checkbox will simply swap the enabled/disabled states. + +Finally, you can insert a single structure as a (single!) argument, which produces a dialog box according to its settings and fieldnames: + +settings = struct(... +'TolX' , 1e-6,... +'TolFun', 1e-6); +settings = settingsdlg(settings); + +Naturally, since all other information is absent in this last example, the functionality in this case is rather limited. But if the intent is to change a fairly simple structure, it certainly suffices. + +If you like this work, please consider [a donation](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=4M7RMVNMKAXXQ&source=url). diff --git a/Functions/settingsdlg/Screen.png b/Functions/settingsdlg/Screen.png new file mode 100644 index 0000000..394da5c Binary files /dev/null and b/Functions/settingsdlg/Screen.png differ diff --git a/Functions/settingsdlg/settingsdlg.m b/Functions/settingsdlg/settingsdlg.m new file mode 100644 index 0000000..b0098ca --- /dev/null +++ b/Functions/settingsdlg/settingsdlg.m @@ -0,0 +1,488 @@ +function [settings, button] = settingsdlg(varargin) +% SETTINGSDLG Default dialog to produce a settings-structure +% +% settings = SETTINGSDLG('fieldname', default_value, ...) creates a modal +% dialog box that returns a structure formed according to user input. The +% input should be given in the form of 'fieldname', default_value - pairs, +% where 'fieldname' is the fieldname in the structure [settings], and +% default_value the initial value displayed in the dialog box. +% +% SETTINGSDLG uses UIWAIT to suspend execution until the user responds. +% +% settings = SETTINGSDLG(settings) uses the structure [settings] to form +% the various input fields. This is the most basic (and limited) usage of +% SETTINGSDLG. +% +% [settings, button] = SETTINGSDLG(settings) returns which button was +% pressed, in addition to the (modified) structure [settings]. Either 'ok', +% 'cancel' or [] are possible values. The empty output means that the +% dialog was closed before either Cancel or OK were pressed. +% +% SETTINGSDLG('title', 'window_title') uses 'window_title' as the dialog's +% title. The default is 'Adjust settings'. +% +% SETTINGSDLG('description', 'brief_description',...) starts the dialog box +% with 'brief_description', followed by the input fields. +% +% SETTINGSDLG('windowposition', P, ...) positions the dialog box according to +% the string or vector [P]; see movegui() for valid values. +% +% SETTINGSDLG( {'display_string', 'fieldname'}, default_value,...) uses the +% 'display_string' in the dialog box, while assigning the corresponding +% user-input to fieldname 'fieldname'. +% +% SETTINGSDLG(..., 'checkbox_string', true, ...) displays a checkbox in +% stead of the default edit box, and SETTINGSDLG('fieldname', {'string1', +% 'string2'},... ) displays a popup box with the strings given in +% the second cell-array. +% +% Additionally, you can put [..., 'separator', 'seperator_string',...] +% anywhere in the argument list, which will divide all the arguments into +% sections, with section headings 'seperator_string'. +% +% You can also modify the display behavior in the case of checkboxes. When +% defining checkboxes with a 2-element logical array, the second boolean +% determines whether all fields below that checkbox are initially disabled +% (true) or not (false). +% +% Example: +% +% [settings, button] = settingsdlg(... +% 'Description', 'This dialog will set the parameters used by FMINCON()',... +% 'title' , 'FMINCON() options',... +% 'separator' , 'Unconstrained/General',... +% {'This is a checkbox'; 'Check'}, [true true],... +% {'Tolerance X';'TolX'}, 1e-6,... +% {'Tolerance on Function';'TolFun'}, 1e-6,... +% 'Algorithm' , {'active-set','interior-point'},... +% 'separator' , 'Constrained',... +% {'Tolerance on Constraints';'TolCon'}, 1e-6) +% +% See also inputdlg, dialog, errordlg, helpdlg, listdlg, msgbox, questdlg, textwrap, +% uiwait, warndlg. + + +% Please report bugs and inquiries to: +% +% Name : Rody P.S. Oldenhuis +% E-mail : oldenhuis@gmail.com +% Licence: 2-clause BSD (See Licence.txt) + + +% If you find this work useful, please consider a donation: +% https://www.paypal.me/RodyO/3.5 + + %% Initialize + + % errortraps + narg = nargin; + if verLessThan('MATLAB', '8.6') + error(nargchk(1, inf, narg, 'struct')); %#ok + else + narginchk(1, inf); + end + + % parse input (+errortrap) + have_settings = 0; + if isstruct(varargin{1}) + settings = varargin{1}; have_settings = 1; end + if (narg == 1) + if isstruct(varargin{1}) + parameters = fieldnames(settings); + values = cellfun(@(x)settings.(x), parameters, 'UniformOutput', false); + else + error('settingsdlg:incorrect_input',... + 'When pasing a single argument, that argument must be a structure.') + end + else + parameters = varargin(1+have_settings : 2 : end); + values = varargin(2+have_settings : 2 : end); + end + + % Initialize data + button = []; + fields = cell(numel(parameters),1); + tags = fields; + + % Fill [settings] with default values & collect data + for ii = 1:numel(parameters) + + % Extract fields & tags + if iscell(parameters{ii}) + tags{ii} = parameters{ii}{1}; + fields{ii} = parameters{ii}{2}; + else + % More errortraps + if ~ischar(parameters{ii}) + error('settingsdlg:nonstring_parameter',... + 'Arguments should be given as [''parameter'', value,...] pairs.') + end + tags{ii} = parameters{ii}; + fields{ii} = parameters{ii}; + end + + % More errortraps + if ~ischar(fields{ii}) + error('settingsdlg:fieldname_not_char',... + 'Fieldname should be a string.') + end + if ~ischar(tags{ii}) + error('settingsdlg:tag_not_char',... + 'Display name should be a string.') + end + + % NOTE: 'Separator' is now in 'fields' even though + % it will not be used as a fieldname + + % Make sure all fieldnames are properly formatted + % (alternating capitals, no whitespace) + if ~strcmpi(fields{ii}, {'Separator';'Title';'Description'}) + whitespace = isspace(fields{ii}); + capitalize = circshift(whitespace,[0,1]); + fields{ii}(capitalize) = upper(fields{ii}(capitalize)); + fields{ii} = fields{ii}(~whitespace); + % insert associated value in output + if iscell(values{ii}) + settings.(fields{ii}) = values{ii}{1}; + elseif (length(values{ii}) > 1) + settings.(fields{ii}) = values{ii}(1); + else + settings.(fields{ii}) = values{ii}; + end + end + end + + % Avoid (some) confusion + clear parameters + + % Use default colorscheme from the OS + bgcolor = get(0, 'defaultUicontrolBackgroundColor'); + % Default fontsize + fontsize = get(0, 'defaultuicontrolfontsize'); + % Edit-bgcolor is platform-dependent. + % MS/Windows: white. + % UNIX: same as figure bgcolor +% if ispc, edit_bgcolor = 'White'; +% else edit_bgcolor = bgcolor; +% end + +% TODO: not really applicable since defaultUicontrolBackgroundColor +% doesn't really seem to work on Unix... +edit_bgcolor = 'White'; + + % Get basic window properties + title = getValue('Adjust settings', 'Title'); + description = getValue( [], 'Description'); + total_width = getValue(325, 'WindowWidth'); + control_width = getValue(100, 'ControlWidth'); + + % Window positioning: + % Put the window in the center of the screen by default. + % This will usually work fine, except on some multi-monitor setups. + scz = get(0, 'ScreenSize'); + scxy = round(scz(3:4)/2-control_width/2); + scx = min(scz(3),max(1,scxy(1))); + scy = min(scz(4),max(1,scxy(2))); + + % String to pass on to movegui + window_position = getValue('center', 'WindowPosition'); + + + % Calculate best height for all uicontrol() + control_height = max(18, (fontsize+6)); + + % Calculate figure height (will be adjusted later according to description) + total_height = numel(fields)*1.25*control_height + ... % to fit all controls + 1.5*control_height + 20; % to fit "OK" and "Cancel" buttons + + % Total number of separators + num_separators = nnz(strcmpi(fields,'Separator')); + + % Draw figure in background + fighandle = figure(... + 'integerhandle' , 'off',... % use non-integers for the handle (prevents accidental plots from going to the dialog) + 'Handlevisibility', 'off',... % only visible from within this function + 'position' , [scx, scy, total_width, total_height],...% figure position + 'visible' , 'off',... % hide the dialog while it is being constructed + 'backingstore' , 'off',... % DON'T save a copy in the background + 'resize' , 'off', ... % but just keep it resizable + 'renderer' , 'zbuffer', ... % best choice for speed vs. compatibility + 'WindowStyle' ,'modal',... % window is modal + 'units' , 'pixels',... % better for drawing + 'DockControls' , 'off',... % force it to be non-dockable + 'name' , title,... % dialog title + 'menubar' ,'none', ... % no menubar of course + 'toolbar' ,'none', ... % no toolbar + 'NumberTitle' , 'off',... % "Figure 1.4728...:" just looks corny + 'color' , bgcolor); % use default colorscheme + + %% Draw all required uicontrols(), and unhide window + + % Define X-offsets (different when separators are used) + separator_offset_X = 2; + if num_separators > 0 + text_offset_X = 20; + text_width = (total_width-control_width-text_offset_X); + else + text_offset_X = separator_offset_X; + text_width = (total_width-control_width); + end + + % Handle description + description_offset = 0; + if ~isempty(description) + + % create textfield (negligible height initially) + description_panel = uicontrol(... + 'parent' , fighandle,... + 'style' , 'text',... + 'Horizontalalignment', 'left',... + 'position', [separator_offset_X,... + total_height,total_width,1]); + + % wrap the description + description = textwrap(description_panel, {description}); + + % adjust the height of the figure + textheight = size(description,1)*(fontsize+6); + description_offset = textheight + 20; + total_height = total_height + description_offset; + set(fighandle,... + 'position', [scx, scy, total_width, total_height]) + + % adjust the position of the textfield and insert the description + set(description_panel, ... + 'string' , description,... + 'position', [separator_offset_X, total_height-textheight, ... + total_width, textheight]); + end + + % Define Y-offsets (different when descriptions are used) + control_offset_Y = total_height-control_height-description_offset; + + % initialize loop + controls = zeros(numel(tags)-num_separators,1); + ii = 1; sep_ind = 1; + enable = 'on'; separators = zeros(num_separators,1); + + % loop through the controls + if numel(tags) > 0 + while true + + % Should we draw a separator? + if strcmpi(tags{ii}, 'Separator') + + % Print separator + uicontrol(... + 'style' , 'text',... + 'parent' , fighandle,... + 'string' , values{ii},... + 'horizontalalignment', 'left',... + 'fontweight', 'bold',... + 'position', [separator_offset_X,control_offset_Y-4, ... + total_width, control_height]); + + % remove separator, but save its position + fields(ii) = []; + tags(ii) = []; separators(sep_ind) = ii; + values(ii) = []; sep_ind = sep_ind + 1; + + % reset enable (when neccessary) + if strcmpi(enable, 'off') + enable = 'on'; end + + % NOTE: DON'T increase loop index + + % ... or a setting? + else + + % logicals: use checkbox + if islogical(values{ii}) + + % First draw control + controls(ii) = uicontrol(... + 'style' , 'checkbox',... + 'parent' , fighandle,... + 'enable' , enable,... + 'string' , tags{ii},... + 'value' , values{ii}(1),... + 'position', [text_offset_X,control_offset_Y-4, ... + total_width, control_height]); + + % Should everything below here be OFF? + if (length(values{ii})>1) + % turn next controls off when asked for + if values{ii}(2) + enable = 'off'; end + % Turn on callback function + set(controls(ii),... + 'Callback', @(varargin) EnableDisable(ii,varargin{:})); + end + + % doubles : use edit box + % cells : use popup + % cell-of-cells: use table + else + % First print parameter + uicontrol(... + 'style' , 'text',... + 'parent' , fighandle,... + 'string' , [tags{ii}, ':'],... + 'horizontalalignment', 'left',... + 'position', [text_offset_X,control_offset_Y-4, ... + text_width, control_height]); + + % Popup, edit box or table? + style = 'edit'; + draw_table = false; + if iscell(values{ii}) + style = 'popup'; + if all(cellfun('isclass', values{ii}, 'cell')) + draw_table = true; end + end + + % Draw appropriate control + if ~draw_table + controls(ii) = uicontrol(... + 'enable' , enable,... + 'style' , style,... + 'Background', edit_bgcolor,... + 'parent' , fighandle,... + 'string' , values{ii},... + 'position', [text_width,control_offset_Y,... + control_width, control_height]); + else + % TODO + % ...table? ...radio buttons? How to do this? + warning(... + 'settingsdlg:not_yet_implemented',... + 'Treatment of cells is not yet implemented.'); + + end + end + + % increase loop index + ii = ii + 1; + end + + % end loop? + if ii > numel(tags) + break, end + + % Decrease offset + control_offset_Y = control_offset_Y - 1.25*control_height; + end + end + + % Draw cancel button + uicontrol(... + 'style' , 'pushbutton',... + 'parent' , fighandle,... + 'string' , 'Cancel',... + 'position', [separator_offset_X,2, total_width/2.5,control_height*1.5],... + 'Callback', @Cancel) + + % Draw OK button + uicontrol(... + 'style' , 'pushbutton',... + 'parent' , fighandle,... + 'string' , 'OK',... + 'position', [total_width*(1-1/2.5)-separator_offset_X,2, ... + total_width/2.5,control_height*1.5],... + 'Callback', @OK) + + % move to center of screen and make visible + movegui(fighandle, window_position); + set(fighandle, 'Visible', 'on'); + + % WAIT until OK/Cancel is pressed + uiwait(fighandle); + + + + %% Helper funcitons + + % Get a value from the values array: + % - if it does not exist, return the default value + % - if it exists, assign it and delete the appropriate entries from the + % data arrays + function val = getValue(default, tag) + index = strcmpi(fields, tag); + if any(index) + val = values{index}; + values(index) = []; + fields(index) = []; + tags(index) = []; + else + val = default; + end + end + + %% callback functions + + % Enable/disable controls associated with (some) checkboxes + function EnableDisable(which, varargin) %#ok + + % find proper range of controls to switch + if (num_separators > 1) + range = (which+1):(separators(separators > which)-1); + else range = (which+1):numel(controls); + end + + % enable/disable these controls + if strcmpi(get(controls(range(1)), 'enable'), 'off') + set(controls(range), 'enable', 'on') + else + set(controls(range), 'enable', 'off') + end + end + + % OK button: + % - update fields in [settings] + % - assign [button] output argument ('ok') + % - kill window + function OK(varargin) %#ok + + % button pressed + button = 'OK'; + + % fill settings + for i = 1:numel(controls) + + % extract current control's string, value & type + str = get(controls(i), 'string'); + val = get(controls(i), 'value'); + style = get(controls(i), 'style'); + + % popups/edits + if ~strcmpi(style, 'checkbox') + % extract correct string (popups only) + if strcmpi(style, 'popupmenu'), str = str{val}; end + % try to convert string to double + val = str2double(str); + % insert this double in [settings]. If it was not a + % double, insert string instead + if ~isnan(val), settings.(fields{i}) = val; + else settings.(fields{i}) = str; + end + + % checkboxes + else + % we can insert value immediately + settings.(fields{i}) = val; + end + end + + % kill window + delete(fighandle); + end + + % Cancel button: + % - assign [button] output argument ('cancel') + % - delete figure (so: return default settings) + function Cancel(varargin) %#ok + button = 'cancel'; + delete(fighandle); + end + +end diff --git a/Functions/settingsdlg/settingsdlg.odt b/Functions/settingsdlg/settingsdlg.odt new file mode 100644 index 0000000..18e4a1c Binary files /dev/null and b/Functions/settingsdlg/settingsdlg.odt differ diff --git a/Functions/settingsdlg/settingsdlg.pdf b/Functions/settingsdlg/settingsdlg.pdf new file mode 100644 index 0000000..907063f Binary files /dev/null and b/Functions/settingsdlg/settingsdlg.pdf differ diff --git a/comm_tb.m b/comm_tb.m index ce4bd13..d0452d1 100644 --- a/comm_tb.m +++ b/comm_tb.m @@ -1,9 +1,11 @@ -O = 14; %order of prbs +clear all + +O = 17; %order of prbs N = 2^(O-1); %length of prbs [~,seed] = prbs(O,1); %initialize first seed of prbs % Modulation -M = 4; +M = 4; %PAM-M bitpattern = zeros(N,log2(M)); % Symbol Rate @@ -17,168 +19,152 @@ fadc = 256e9; % Simulation frequency in "analog domain" fsimu = kover * fdac ; -%SIMULATE +[settings, button] = settingsdlg(... + 'Description' , ['This dialog will set the ', ... + 'parameters used by FMINCON()'], ... + 'title' , 'FMINCON() options', ... + 'separator' , 'Unconstrained/General', ... + {'This is a checkbox'; 'Check'} , [false, false],... + {'Tolerance X';'TolX'} , 1e-6, ... + {'Tolerance on Function';'TolFun'} , 1e-6, ... + 'Algorithm' , {'active-set','interior-point'}, ... + 'separator' , 'Constrained', ... + {'Tolerance on Constraints';'TolCon'}, 1e-6); -for i = 1:log2(M) - [bitpattern(:,i),seed] = prbs(O,N,seed); -end +%CONSTRUCTION +pam_mapper = PAMmapper(M,0); -Bits = Informationsignal(bitpattern); +awg = AWG('preset','M8196A','fdac',fdac,'kover',kover,'lpf_active',0); -Bits.signal = pam_mapping(Bits.signal,M,0); - -Bits.signal = applyPulseShaping(Bits.signal,fsym,fdac); - - -awg = AWG('preset','M8196A','fdac',fdac,'kover',kover,'lpf_active',1); -awgSignal = awg.process_channel(Bits.signal); - -fil = Filter('filtdegree',4,"f_cutoff",50e9,"fsamp",fdac,"filterType",filtertypes.bessel_bilin); -filtered = fil.process(awgSignal); +fil_tx = Filter('filtdegree',1,"f_cutoff",50e9,"fsamp",fdac,"filterType",filtertypes.bessel_bilin); u_pi = 3.5; vbias = (0.5*u_pi)-u_pi; -extmodlaser = EML("mode",emlmodes.im_cosinus,"power",10,"fsimu",fsimu,"lambda",1550,"bias",vbias,"u_pi",u_pi,"linewidth",1000000); -laserfield = extmodlaser.process(filtered); +extmodlaser = EML("mode",emlmodes.im_cosinus,"power",10,"fsimu",fsimu,"lambda",1550,"bias",vbias,"u_pi",u_pi,"linewidth",0); -att = Amplifier("amplification_db",10,"amp_mode","gain","type","ideal","saturation_mode",0,'saturation_power',10); -att_out = att.process(laserfield); +amp = Amplifier("amplification_db",10,"amp_mode","gain","type","ideal","saturation_mode",0,'saturation_power',10); -fib = Fiber("fsimu",fdac*kover,"fiber_length",0,"alpha",0.2,"D",17,"lambda0",1550); -fib_out = fib.process(att_out); +fib = Fiber("fsimu",fdac*kover,"fiber_length",2,"alpha",0.2,"D",17,"lambda0",1550); phdiode = Photodiode("fsimu",fdac*kover,"dark_current",2e-08,"responsivity",1,"temperature",20); -phdiod_out = phdiode.process(fib_out); - -fil = Filter('filtdegree',4,"f_cutoff",70e9,"fsamp",fdac,"filterType",filtertypes.bessel_bilin); -phdiod_out2 = fil.process(phdiod_out); +fil_diode = Filter('filtdegree',4,"f_cutoff",70e9,"fsamp",fdac,"filterType",filtertypes.bessel_bilin); scp = Scope("fsimu",fdac*kover,"fadc",fadc,... "delay",0,"fixed_delay",0,"lpf_bw",120e9,"filtertype",filtertypes.bessel_inp,... "samplingdelay",0,"rand_samplingdelay",0,"freq_offset",0,"samp_jitter",0,... "adcresolution",6,"quantbuffer",0.1); -scope_out = scp.process(phdiod_out2); +eq = EQ("K",2,"plottrain",0,"plotfinal",1,"training_length",2048,"Ne",[25,5,5],"Nb",[2,0,0],"training_loops",5,"DCmu",0.005,"DDmu",[0.0004 0.0004 0.0004 0.0004 ],"DFEmu",0.005,"FFEmu",0,"thres",[0.005 0.004 0.0005 ]); -resample_out = resample(scope_out,fsym,fadc); +%SIMULATE - - - - -figure; -hold on -plot( nmlze(resample(shapedData,fadc,fdac)),'DisplayName','shapedData Data'); -plot( nmlze(resample(awgSignal,fadc,fdac*kover)),'DisplayName','AWG Data'); -plot( nmlze(scope_out),'DisplayName','scope out out'); -hold off - - - - -% figure; -% hold on -% plot(awgSignal,'DisplayName','skew 0'); -% plot(filtered,'DisplayName','filtered'); -% plot(abs(laserfield),'DisplayName','laser'); -% plot(abs(att_out),'DisplayName','att_out'); -% plot(abs(fib_out),'DisplayName','fiber_out'); -% plot(abs(phdiod_out),'DisplayName','photo diode out'); -% hold off - -% figure; -% hold on -% plot(nmlze(pamData),'DisplayName','PAM Data'); -% plot(nmlze(resample_out),'DisplayName','system out'); -% hold off - - -function y = nmlze(x) - y = (x-min(x)) / max((x-min(x))); +% INFORMATION SIGNAL +for i = 1:log2(M) + [bitpattern(:,i),seed] = prbs(O,N,seed); end -function pam_sig = pam_mapping(bitpattern, M, unipolar) +X = Informationsignal(bitpattern); -switch log2(M) - case 1 - % 2-ASK: BPSK / OOK - pam_sig=bitpattern(:,1); +PAMSIG = pam_mapper.map(X); - if unipolar==0 - pam_sig=2*pam_sig-1; - end +X.signal = applyPulseShaping(PAMSIG.signal,fsym,fdac); - case 2 - % 4-ASK: - pam_sig=2*bitpattern(:,1)+(bitpattern(:,1)==bitpattern(:,2)); +% ELECTRICAL DOMAIN +X = awg.process(X); - if unipolar==0 - pam_sig=2*pam_sig-3; - end +X = fil_tx.process(X); + +% OPTICAL DOMAIN +X = extmodlaser.process(X); + +X = amp.process(X); + +X = fib.process(X); + +X = phdiode.process(X); + +X = fil_diode.process(X); + +% ELECTRICAL DOMAIN +X = scp.process(X); + +X = X.resample("fs_out",2*fsym,"fs_in",fadc); - case 3 - % 8-ASK: - x1 = bitpattern(:,1); - x2 = (bitpattern(:,1)==bitpattern(:,3)); - x3 = x2~=bitpattern(:,2); +% INFORMATION SIGNAL +X = eq.process(X,PAMSIG); - pam_sig = 4*x1 + 2*x2 + x3; +X = pam_mapper.demap(X); - if unipolar==0 - pam_sig=2*pam_sig-7; - end +% BER +[bits,errors,BER] = calc_ber(X.signal(:,10000:end-20),bitpattern(10000:end-20,:)',0); - - 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 unipolar==0 - pam_sig=2*pam_sig-15; - end - -end -end +disp(['BER: ', sprintf('%2E',BER)]); +disp(X.logbook); function yout = applyPulseShaping(xin,fsym,fdac) - if ~rem(fdac,fsym) - %ist ein Vielfaches - sps = fdac / fsym; - up = sps; - dn = 1; - else - %ist kein Vielfaches - up = fdac / gcd(fdac, fsym); - dn = fsym / gcd(fdac, fsym); - sps= up; - end +if ~rem(fdac,fsym) + %ist ein Vielfaches + sps = fdac / fsym; + up = sps; + dn = 1; +else + %ist kein Vielfaches + up = fdac / gcd(fdac, fsym); + dn = fsym / gcd(fdac, fsym); + sps= up; +end - %Bau das Filter (hier rrc) - racos_len = 2048; - alpha = 0.1; - h = rcosdesign(alpha,racos_len,sps); - - %Apply Filter using Matlab build in fctn. - yout = upfirdn(xin,h,up,dn); - - %cut signal, which is longer due to fir filter - st = up/dn*racos_len/2; %we need to cut y_out - en = st + (length(xin)*up/dn) -1; +%Bau das Filter (hier rrc) +racos_len = 2048; +alpha = 0.1; +h = rcosdesign(alpha,racos_len,sps); - yout = yout(st:en); +%Apply Filter using Matlab build in fctn. +yout = upfirdn(xin,h,up,dn); - %Check output integrity - if (up/dn * length(xin)) ~= length(yout) - warning('Check signal length after pulse shaping'); - end +%cut signal, which is longer due to fir filter +st = round(up/dn*racos_len/2); %we need to cut y_out +en = round(st + (length(xin)*up/dn) -1); + +yout = yout(st:en); + +%Check output integrity +if round(up/dn * length(xin)) ~= length(yout) + warning('Check signal length after pulse shaping'); +end + +end + +function [bits,errors,BER] = calc_ber(data_in,data_ref,skip) + +data_ref=logical(data_ref); +data_in = logical(data_in); +bits = 0; +errors=0; + +data_ref_overlap=zeros(size(data_ref,1),skip+(length(data_ref)-size(data_in,2))); +data_ref_pointer=0; +% Determine BER + +bits = bits+size(data_in,2)-skip; +try + errors = sum( data_in(:,skip+1:end,:) ~= data_ref(:,skip+1:end,:),2 ); +catch + %warning('BER calculation not optimal: Arrays have incompatible sizes for this operation.') + errors = NaN; +end +try + errors = sum( data_in(:,skip+1:end,:) ~= data_ref(:,skip+1:end-1,:),2 ); +end +try + errors = sum( data_in(:,skip+1:end,:) ~= data_ref(:,skip+1:end-2,:),2 ); +end + +BER = sum(errors)/sum(bits); + +end -end \ No newline at end of file