From 0080cb2264aed028a7c7dda745134100b190bf7b Mon Sep 17 00:00:00 2001 From: Silas Oettinghaus Date: Wed, 12 Nov 2025 09:24:02 +0100 Subject: [PATCH] ML Equalizer works now. Not yet perfectly integrated into all the routines --- Classes/04_DSP/Equalizer/ML_MLSE.m | 235 +++-- Classes/04_DSP/Sequence Detection/MLSE.m | 2 +- Classes/DataBaseHandler/Metricstruct.m | 4 +- .../fwm_plots/CompleteRoutine.m | 502 +++++------ .../CompleteRoutine_DifferentChannels_Fig3.m | 500 +++++------ .../fwm_plots/automate_JLT_plots.m | 830 +++++++++--------- .../fwm_plots/automate_PTL_plot_new.m | 0 .../fwm_plots/dispersion_only.m | 166 ++-- .../dispersion_validation_miniskript.m | 102 +-- .../fwm_plots/generatePlots.m | 120 +-- .../fwm_plots/plot3dCurve.m | 496 +++++------ .../fwm_plots/plotBerVsZDW.m | 598 ++++++------- .../fwm_plots/plotBerVsZdwFailureRate.m | 312 +++---- .../fwm_plots/plotChannelSpacingAna.m | 102 +-- .../fwm_plots/plotCurve.m | 588 ++++++------- .../fwm_plots/plotHistogram.m | 300 +++---- .../fwm_plots/plotViolin.m | 410 ++++----- .../fwm_plots/plot_ber_distribution.m | 114 +-- Datatypes/equalizer_structure.m | 1 + Functions/EQ_structures/dsp_runid.m | 48 +- Functions/EQ_structures/duobinary_signaling.m | 5 +- Functions/EQ_structures/ml_mlse.m | 113 +++ .../configureEqualizers_remove.m | 40 - Functions/Job_Processing/preprocessSignal.m | 6 +- Functions/Job_Processing/submitJobs.m | 1 + Functions/beautifyBERplot.m | 124 ++- .../Auswertung_JLT/ber_vs_dispersion.m | 2 +- .../Auswertung_JLT/plot_measurements_gpt.m | 23 +- .../Auswertung_JLT/run_dsp_from_db.m | 150 +++- .../Auswertung_JLT/run_plot_measurements.m | 22 +- .../ML_based_MLSE/analyze_filter_length.m | 164 ++++ projects/ML_based_MLSE/analyze_mu.m | 113 +++ projects/ML_based_MLSE/experimental_data.m | 162 ++++ projects/ML_based_MLSE/interp_fec_cross.m | 13 + .../ML_based_MLSE/minimal_example_huawei.zip | Bin 0 -> 14741 bytes .../minimal_example_huawei/bcjr_pam.m | 555 ++++++++++++ .../minimal_example_huawei/minimal_example.m | 193 ++++ .../minimal_example_huawei/ml_mlse_pam.m | 473 ++++++++++ projects/ML_based_MLSE/rate_evaluation.m | 23 +- projects/ML_based_MLSE/read_csv.m | 30 + projects/ML_based_MLSE/rop_evaluation.m | 208 +++-- .../ML_based_MLSE/rrop_vs_length_evaluation.m | 140 +++ projects/ML_based_MLSE/standard_link_model.m | 10 +- .../theoretic_channel_evaluation.m | 157 ++++ 44 files changed, 5289 insertions(+), 2868 deletions(-) rename Classes/Warehouse_class/functions/{ => phase_predist_plots}/fwm_plots/CompleteRoutine.m (96%) rename Classes/Warehouse_class/functions/{ => phase_predist_plots}/fwm_plots/CompleteRoutine_DifferentChannels_Fig3.m (96%) rename Classes/Warehouse_class/functions/{ => phase_predist_plots}/fwm_plots/automate_JLT_plots.m (96%) rename Classes/Warehouse_class/functions/{ => phase_predist_plots}/fwm_plots/automate_PTL_plot_new.m (100%) rename Classes/Warehouse_class/functions/{ => phase_predist_plots}/fwm_plots/dispersion_only.m (96%) rename Classes/Warehouse_class/functions/{ => phase_predist_plots}/fwm_plots/dispersion_validation_miniskript.m (96%) rename Classes/Warehouse_class/functions/{ => phase_predist_plots}/fwm_plots/generatePlots.m (96%) rename Classes/Warehouse_class/functions/{ => phase_predist_plots}/fwm_plots/plot3dCurve.m (97%) rename Classes/Warehouse_class/functions/{ => phase_predist_plots}/fwm_plots/plotBerVsZDW.m (97%) rename Classes/Warehouse_class/functions/{ => phase_predist_plots}/fwm_plots/plotBerVsZdwFailureRate.m (96%) rename Classes/Warehouse_class/functions/{ => phase_predist_plots}/fwm_plots/plotChannelSpacingAna.m (96%) rename Classes/Warehouse_class/functions/{ => phase_predist_plots}/fwm_plots/plotCurve.m (97%) rename Classes/Warehouse_class/functions/{ => phase_predist_plots}/fwm_plots/plotHistogram.m (96%) rename Classes/Warehouse_class/functions/{ => phase_predist_plots}/fwm_plots/plotViolin.m (96%) rename Classes/Warehouse_class/functions/{ => phase_predist_plots}/fwm_plots/plot_ber_distribution.m (96%) create mode 100644 Functions/EQ_structures/ml_mlse.m delete mode 100644 Functions/Job_Processing/configureEqualizers_remove.m create mode 100644 projects/ML_based_MLSE/analyze_filter_length.m create mode 100644 projects/ML_based_MLSE/analyze_mu.m create mode 100644 projects/ML_based_MLSE/experimental_data.m create mode 100644 projects/ML_based_MLSE/interp_fec_cross.m create mode 100644 projects/ML_based_MLSE/minimal_example_huawei.zip create mode 100644 projects/ML_based_MLSE/minimal_example_huawei/bcjr_pam.m create mode 100644 projects/ML_based_MLSE/minimal_example_huawei/minimal_example.m create mode 100644 projects/ML_based_MLSE/minimal_example_huawei/ml_mlse_pam.m create mode 100644 projects/ML_based_MLSE/read_csv.m create mode 100644 projects/ML_based_MLSE/rrop_vs_length_evaluation.m create mode 100644 projects/ML_based_MLSE/theoretic_channel_evaluation.m diff --git a/Classes/04_DSP/Equalizer/ML_MLSE.m b/Classes/04_DSP/Equalizer/ML_MLSE.m index bb327b1..4539f62 100644 --- a/Classes/04_DSP/Equalizer/ML_MLSE.m +++ b/Classes/04_DSP/Equalizer/ML_MLSE.m @@ -1,13 +1,41 @@ classdef ML_MLSE < handle - % Implementation of plain and simple FFE. - % 1) Training mode (stable performance when you use NLMS) - % 2) Decision directed mode - % - %LMS: mu in order of 0.0001 for acceptable convergence speed - %NLMS: mu in order of 0.01 for acceptable convergence speed - %RLS: mu is lambda -> 0.99 -> 1 (has a strong dependency on this! use a loop to find out best values) - % - % FFE("epochs_tr",5,"epochs_dd",2,"len_tr",2^13,"mu_dd",mu_dd,"mu_tr",mu_tr,"order",25,"sps",2,"decide",0, "adaption",adaption_method(adaption),"dd_mode",use_dd_mode); + % ALGORITHM DESCRIBED IN: + % W. Lanneer and Y. Lefevre, “Machine Learning-Based Pre-Equalizers for + % Maximum Likelihood Sequence Estimation in High-Speed PONs,” + % in 2023 31st European Signal Processing Conference + + % Further ML Refs: + % https://machinelearningmastery.com/cross-entropy-for-machine-learning/ + % https://docs.pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html + + % The central idea is to overcome the (white-) noise assumption within the previously described + % Viterbi algorithm, more precisely a closed-loop optimization is proposed that finds a suitable + % filter-set to directly compute the branch metrics c_k (s,s^' ). These can directly be used to + % carry out the conventional Viterbi algorithm. The system consists of S^L S=F linear FIR filters, + % combined with one bias coefficient respectively. These filters take the received input samples to + % compute the branch metrics estimates (c_k ) ̂(s,s^' ) according toThe central idea is to overcome + % the (white-) noise assumption within the previously described Viterbi algorithm, more precisely + % a closed-loop optimization is proposed that finds a suitable filter-set to directly compute the + % branch metrics c_k (s,s^' ). These can directly be used to carry out the conventional Viterbi + % algorithm. The system consists of S^L S=F linear FIR filters, combined with one bias coefficient + % respectively. These filters take the received input samples to compute the branch metrics + % estimates. Finally, the usual Viterbi is carried out... + + % Recommended Settings and some findings: + + % Requires many training epochs. According to ML people, 100,200 or + % even up to 1000 epochs are normal for ML-convergence + + % The mu parameter _can_ be adaptive - using the cross entropy and when + % analyzing the isolated training it looks very promisig. However, is + % later use I found this is not as stable as a fixed learning rate. + % mu = 0.1 worked good for me + + % Longer orders/ filter length are not always better. For me order=11 + % was good. + + % Delay factor (delta) is good when the order is also increased. With + % order = 11, a delta of =4 shows good results properties sps % usually 2 @@ -24,6 +52,8 @@ classdef ML_MLSE < handle mu_dd %weight update in dd mode epochs_dd + adaptive_mu + constellation L %viterbi memory length @@ -50,11 +80,13 @@ classdef ML_MLSE < handle w % --- New: fast state lookup --- + true_to_state_idx state_dict % containers.Map: key(sequence)->state index key_fmt = '%.8g_'; % key format for sequence strings nSym % |constellation| ber = [] + ce = ones(1,1); end methods @@ -72,6 +104,8 @@ classdef ML_MLSE < handle options.mu_dd = 1e-5; options.epochs_dd = 5; + options.adaptive_mu = 1; + options.delta = 0; options.traceback_depth = 1024; @@ -180,11 +214,12 @@ classdef ML_MLSE < handle X_viterbi = X_viterbi.logbookentry(lbdesc); % append to logbook end - function [y,y_vit] = equalize(obj,x,d,mu,epochs,N,training) + function [y,y_ref] = equalize(obj,x,d,mu,epochs,N,training) % ============================================================== % FFE + Whitening + ML-Based Branch Metric Estimation + Viterbi % ============================================================== debug = 1; + showPlots = 1; % --- Input padding and preallocation y = zeros(N,1); @@ -200,7 +235,8 @@ classdef ML_MLSE < handle v_tilde = zeros(1,obj.nFeasible); pred = zeros(nSymbols, obj.nStates, 'uint32'); pm_sto = nan(obj.nStates, nSymbols,'like',pm); - + CE_accum = 0; + %%% START IDX if training @@ -210,7 +246,7 @@ classdef ML_MLSE < handle start_sample = 1; end_sample = start_sample + (ceil(N/obj.sps)-1)*obj.sps; else - start_sample = 1; + start_sample = 1;%obj.len_tr; end_sample = N; end @@ -251,34 +287,72 @@ classdef ML_MLSE < handle % ===== Gradient update (Algorithm 1) ===== if 1 %training - % previous "to" becomes current "from" (shift-register) - true_from_state_idx = true_to_state_idx; - - % --- Build current "to" state from ABSOLUTE symbol index - if sym_idx >= obj.L - curr_seq = d(sym_idx-obj.L+1 : sym_idx); % [d_k-L+1 ... d_k] - key_to = obj.seq_key(flip(curr_seq)); % -> [d_k ... d_k-L+1] - if isKey(obj.state_dict, key_to) - true_to_state_idx = obj.state_dict(key_to); - else - % Fall back safely (should not happen with proper constellation) - true_to_state_idx = true_from_state_idx; - end - else - % Not enough history yet for a full L-symbol state - % keep previous 'to' and 'from' - true_to_state_idx = true_to_state_idx; - true_from_state_idx = true_from_state_idx; + % --- allocate storage once + if epoch == 1 && symbol == 1 + obj.true_to_state_idx = ones(ceil(N/obj.sps),1,'uint32'); end - % Dirac delta over correct extended transition (from,to) + % --- previous "to" becomes current "from" + if symbol > 1 + true_from_state_idx = obj.true_to_state_idx(symbol-1); + else + true_from_state_idx = 1; + end + + % --- compute or reuse "to" state + if epoch == 1 + % only compute in first epoch + if sym_idx >= obj.L + key_to = obj.seq_key(flip(d(sym_idx-obj.L+1 : sym_idx))); + if isKey(obj.state_dict, key_to) + obj.true_to_state_idx(symbol) = obj.state_dict(key_to); + else + obj.true_to_state_idx(symbol) = true_from_state_idx; + end + else + obj.true_to_state_idx(symbol) = true_from_state_idx; + end + end + + % --- reuse cached state from second epoch onward + true_to_state_idx = obj.true_to_state_idx(symbol); + + % --- ensure valid (from,to) dirac = zeros(obj.nFeasible,1); - dirac(obj.valid_from_idx==true_from_state_idx & ... - obj.valid_to_idx ==true_to_state_idx) = 1; + mask = obj.valid_from_idx==true_from_state_idx & ... + obj.valid_to_idx ==true_to_state_idx; + if any(mask) + dirac(mask) = 1; + else + idx = find(obj.valid_from_idx==true_from_state_idx,1,'first'); + dirac(idx) = 1; + obj.true_to_state_idx(symbol) = obj.valid_to_idx(idx); + end + + + % softmax over -v_tilde (numerically safe shift) - p = exp(-(v_tilde - max(v_tilde))); - p = p./(sum(p)+eps); + v_shift = -(v_tilde - min(v_tilde)); % shift to small positive numbers + v_shift = min(v_shift, 100); % clamp exponent argument (≈ exp(50)=3e21) + expv = exp(v_shift); + p = expv ./ (sum(expv) + eps); + + % for logging only: + CE_symbol(symbol) = -log(p(dirac==1) + eps); + + if sym_idx > obj.L + CE_smooth(symbol) = 0.01*CE_symbol(symbol) + 0.99*CE_smooth(symbol-1); + else + if epoch > 1 + CE_smooth(symbol) = obj.ce(end); %use ce from last epoch or =1 for very first round?! + else + CE_smooth(symbol) = CE_symbol(symbol); + end + end + + CE_accum = CE_symbol(symbol) + CE_accum; + % gradient term (t - p) dmp = (dirac - p)'; % 1×nFeasible @@ -288,10 +362,14 @@ classdef ML_MLSE < handle % Start updates only when the ABSOLUTE symbol index has ≥ L history if sym_idx >= obj.L + if obj.adaptive_mu + mu_eff = CE_smooth(sym_idx); + mu_eff = max(min(mu_eff, 0.2), 1e-4); + else + mu_eff = mu; + end - - obj.w = obj.w - ones(size(dL_Dw,1),1).*mu .* dL_Dw; % (Nf+1)×nFeasible - % obj.w = obj.w - mu * dL_Dw; % (Nf+1)×nFeasible + obj.w = obj.w - mu_eff .* dL_Dw; % (Nf+1)×nFeasible end % if debug && epoch > 2 @@ -335,42 +413,69 @@ classdef ML_MLSE < handle viterbi_path(n-1) = pred(n, viterbi_path(n)); end - y_vit = obj.first_sym(viterbi_path); + y_ref = d(start_symbol:end); y = obj.first_sym(viterbi_path); - if debug %&& training + if debug && training sym_start = start_symbol; sym_end = start_symbol + symbol - 1; ref_slice = d(sym_start : sym_end); err = sum(y ~= ref_slice(1:numel(y))); - ref_bits = PAMmapper(obj.S,0).demap(ref_slice); - eq_bits = PAMmapper(obj.S,0).demap(y); - [~, ~, ber, ~] = calc_ber(ref_bits, eq_bits, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1); - fprintf('Epoch: %d - BER: %.1e \n',epoch, ber); - - obj.ber(epoch) = ber; + try + ref_bits = PAMmapper(obj.S,0).demap(ref_slice); + eq_bits = PAMmapper(obj.S,0).demap(y); + [~, ~, ber, ~] = calc_ber(ref_bits, eq_bits, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1); + fprintf('Epoch: %d - BER: %.1e \n',epoch, ber); + obj.ber(epoch) = ber; + catch + ser = err./length(y); + fprintf('Epoch: %d - SER: %.1e \n',epoch, ser); + end - % ser = err./length(y); - % fprintf('Epoch: %d - SER: %.1e \n',epoch, ser); + obj.ce(epoch) = CE_accum./symbol; - figure(10); - subplot(2,2,1:2); - heatmap(obj.w); - title('Filter') - - subplot(2,2,3); - v_tildemat = NaN(obj.nStates, obj.nStates); - v_tildemat(obj.valid) = v_tilde; % log-domain scores - heatmap(v_tildemat); - title('Path Metrics (v_tilde)') - - subplot(2,2,4); - scatter(1:symbol,pm_sto,1,'.') - % plot(1:symbol,pm_sto,'LineStyle','none') - title('Path Metric Winners') - - drawnow + if showPlots + figure(10);clf + subplot(3,2,1:2); + heatmap(obj.w); + title('Filter') + + subplot(3,2,3); + v_tildemat = NaN(obj.nStates, obj.nStates); + v_tildemat(obj.valid) = v_tilde; % log-domain scores + heatmap(v_tildemat); + title('Path Metrics (v_tilde)') + + subplot(3,2,4); + scatter(1:symbol,pm_sto,1,'.') + title('Path Metric Winners') + + subplot(3,2,5);hold on + scatter(1:symbol,CE_symbol,1,'.'); + scatter(1:symbol,CE_smooth,1,'.') + title('Cross Entropy') + + subplot(3,2,6); hold on + + % Left y-axis: Cross Entropy (linear) + yyaxis left + scatter(1:length(obj.ce), obj.ce, 10, 's', 'filled') + ylabel('Cross Entropy') + + % Right y-axis: BER (logarithmic) + yyaxis right + scatter(1:length(obj.ber), obj.ber, 10, 'd', 'filled') + set(gca, 'YScale', 'log') + ylabel('BER (log scale)') + + xlim([1, epochs]) + xlabel('Epoch') + title('Cross Entropy // BER') + grid on + + drawnow + end end end end diff --git a/Classes/04_DSP/Sequence Detection/MLSE.m b/Classes/04_DSP/Sequence Detection/MLSE.m index fabee6f..59ef211 100644 --- a/Classes/04_DSP/Sequence Detection/MLSE.m +++ b/Classes/04_DSP/Sequence Detection/MLSE.m @@ -118,7 +118,7 @@ classdef MLSE < handle elseif trellis_state_mode == 2 %simply use the states from the ref signal (should be a robust option) - obj.trellis_states = reshape(unique(data_ref),size(obj.trellis_states)); + obj.trellis_states = reshape(unique(data_ref),1,length(unique(data_ref))); elseif trellis_state_mode == 3 %use_statistical_levels diff --git a/Classes/DataBaseHandler/Metricstruct.m b/Classes/DataBaseHandler/Metricstruct.m index 403e90c..f95311c 100644 --- a/Classes/DataBaseHandler/Metricstruct.m +++ b/Classes/DataBaseHandler/Metricstruct.m @@ -16,9 +16,9 @@ classdef Metricstruct SNR (1,1) double {mustBeNumeric} = NaN SNR_level (:,1) double {mustBeNumeric} = [] STD (1,1) double {mustBeNumeric} = NaN - STD_level (:,1) double {mustBeNumeric, mustBeNonnegative} = [] + STD_level (:,1) double = [] STDrx (1,1) double {mustBeNumeric} = NaN - STDrx_level (:,1) double {mustBeNumeric, mustBeNonnegative} = [] + STDrx_level (:,1) double = [] EVM (1,1) double {mustBeNumeric} = NaN EVM_level (:,1) double {mustBeNumeric} = [] diff --git a/Classes/Warehouse_class/functions/fwm_plots/CompleteRoutine.m b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/CompleteRoutine.m similarity index 96% rename from Classes/Warehouse_class/functions/fwm_plots/CompleteRoutine.m rename to Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/CompleteRoutine.m index 86cbe93..f55c95f 100644 --- a/Classes/Warehouse_class/functions/fwm_plots/CompleteRoutine.m +++ b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/CompleteRoutine.m @@ -1,251 +1,251 @@ -% Script, that shows the data management routine :-) - -loadExistingWareHouse = 0; - -if loadExistingWareHouse - - [file, path] = uigetfile(); - wh = load([path filesep file]); - wh = wh.wh; - wh.showInfo; - -else - - % 1) Define all your parameters, best practice directly constructs a - % structure - - params = struct; - - params.l = [2,10]; - - params.dispersion = [0]; - - params.sgm = [0]; - -% params.pol = ["YXYXYXYX","YXXYYXXY","YYYYYYYY"]; - params.pol = ["alternated","paired","copolarized"]; - - params.p_in = [3]; - - params.p_out = [-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2]; - - params.pmd = [0.1]; - - params.gamma = [0.0023]; - - params.realization = [1:20]; - - params.numchannels = [16]; - - params.center_wavelength = floor([getSweepWavelengths(35, 50e9, 1310)] .* 1000) ./ 1000 ; - params.center_wavelength = [1285 1287 1290 1292 1295]; - params.center_wavelength = 1310; - - params.channelspacing = [400e9]; - - params.random_zdw = [0]; - - %wh = warehouse :-) - wh = DataStorage(params); - - wh.showInfo; - - wh.addStorage("ber"); - - wh.addStorage("totalBer"); - -end - - - -%2) Simulate a bunch of data - TO BE IMPLEMENTED HERE - for now use scripts -%from Sebastian - -%3) Once the simulation folder is around, specifiy path and analyze dirs - -path = uigetdir('C:\Users\Silas\Documents\MATLAB\Raw_Cluster_Simulations'); - -allMat = getAllFilesInFolder(path,'.mat'); -allErr = getAllFilesInFolder(path,'.err'); - -%allMat = dir([path filesep '*.mat']); - -%allErr = dir([path filesep '*.err']); - -if numel(allMat) == 0 - warning('You defined an empty folder. Could not locate any .mat file.') -else - fprintf('%-20s', 'Err Files:'); fprintf('%-12s', num2str(numel(allErr))); fprintf('\n'); - fprintf('%-20s', 'Mat Files:'); fprintf('%-12s', num2str(numel(allMat))); fprintf('\n'); - fprintf('%-20s', 'Missing Mat Files:'); fprintf('%-12s', num2str(numel(allErr)-numel(allMat))); fprintf('\n'); -end - -%4) Now load that data - -f = waitbar(0,'Please wait...'); -cnt = 0; - -for num = 1:numel(allMat) - - fileName = allMat(num).name; - fileFolder = allMat(num).path; - fileExt = allMat(num).ext; -% - matFile = load([fileFolder filesep fileName fileExt]); - matFile = matFile.loop_data; - - % ____________________________________ - % FIND THE DATAPOINT CURRENTLY LOADED - zdw = 1310; - - channelplan = "symmetric"; - - channelspacing = str2double(strrep(regexp(fileName,'(_chsp)+([\d]*)','match'),'_chsp','')).*1e9; - - numchannels = str2double(strrep(regexp(fileName,'(ch)+(_)+([\d]*)','match'),'ch_','')); - - center_wavelength = str2double(insertAfter(strrep(regexp(fileName,'(lambda)+([\d]*)','match'),'lambda',''),4,'.')); - - center_wavelength = floor(center_wavelength * 1000) / 1000; - - if center_wavelength == 2192 - continue - end - - center_wavelength = 1310; - - random_zdw = str2double(strrep(regexp(fileName,'(rzwd)+([\d])','match'),'rzwd','')); - - l = str2double(strrep(regexp(fileName,'([L])+(_)+([\d]*)','match'),'L_','')); - - d = str2double(strrep(regexp(fileName,'([D])+(_)+([\d]*)','match'),'D_','')); - - if d == 0 - sgm = false; - else - sgm = true; - end - - - if numel(regexp(fileName,'(YYYY)','match')) > 1 - pol = "copolarized"; - elseif numel(regexp(fileName,'(YXXY)','match')) > 1 - pol = "paired"; - elseif numel(regexp(fileName,'(YXYX)','match')) > 1 - pol = "alternated"; - else - pol = "copolarized"; - end - - p_in = str2double(strrep(regexp(fileName,'(pow_)+([-,\d]{1})','match'),'pow_','')); - - pmd = 0.1; - - gamma = 0.0023; - - realiz = str2double(strrep(regexp(fileName,'(r)+([-,\d]{1,3})','match'),'r','')); - - - - % ____________________________________ - % Get the information you want from current file - rop=[]; - ber = []; - for pow = 2:12 - - module_number = ''; - for p = 1:11 %11 because there are 11 ROP branches in model - - % get ROP - if p == 1 - p_out = matFile.dp_optatten_para.atten; - else - p_out = matFile.("dp_optatten__"+(p)+"_para").atten; - end - - p_out = round(p_out-10*log10(numel(matFile.config.parameters.common.wavelengthPlan))); - - for c = 1:numel(matFile.config.parameters.common.wavelengthPlan) - - ber(c) = matFile.("prms_compare_wdm__"+(p+1)+"_out"){1,c}.ber; - - end - - totalBer = matFile.("prms_compare_wdm__"+(p+1)+"_out"){1,end}.totalBer; - - if totalBer > 0.2 && channelspacing == 400e9 && pol == "alternated" - disp("stopping here"); - pause; - end - - - % ____________________________________ - % Add value to warehouse at the correct position - - - - wh.addValueToStorage(ber,'ber',l,d,sgm,pol,p_in,p_out,pmd,gamma,realiz,numchannels, center_wavelength,channelspacing,random_zdw); - wh.getStoValue('ber',l,d,sgm,pol,p_in,p_out,pmd,gamma,realiz,numchannels, center_wavelength,channelspacing,random_zdw); - wh.addValueToStorage(totalBer,'totalBer',l,d,sgm,pol,p_in,p_out,pmd,gamma,realiz,numchannels,center_wavelength,channelspacing,random_zdw); - - end - - end - waitbar(num/numel(allMat),f,'Loading your data'); -end - -close(f) - - - - - -% 4) Hey! the warehouse is here and (hopefully) filled with data :-) - -% Create a save dialog -defaultDir = 'C:\Users\Silas\Documents\MATLAB\Raw_Cluster_Simulations\'; -defaultExt = '*.mat'; -[filename, pathname] = uiputfile(fullfile(defaultDir, defaultExt),'', 'wh.mat'); - -% Check if the user pressed Cancel -if isequal(filename, 0) || isequal(pathname, 0) - disp('Save operation canceled.'); -else - % Save the variable to the selected file - save(fullfile(pathname, filename), 'wh'); - disp(['Variable "wh" saved to: ', fullfile(pathname, filename)]); -end - - - - -function matFileStructArray = getAllFilesInFolder(folderPath,extension) - % Get a list of all files in the current folder - currentFolderFiles = dir(fullfile(folderPath, '*')); - - % Exclude '.' and '..' directories - currentFolderFiles = currentFolderFiles(~ismember({currentFolderFiles.name}, {'.', '..'})); - - % Initialize the structure array for .mat files - matFileStructArray = struct('path', {}, 'name', {}, 'ext', {}); - - % Loop over each file in the current folder - for i = 1:length(currentFolderFiles) - currentFile = currentFolderFiles(i); - - % Check if the current item is a file and has a .mat extension - if ~currentFile.isdir && endsWith(currentFile.name, extension, 'IgnoreCase', true) - % If it's a .mat file, add it to the structure array - [matFileStructArray(end + 1).path,matFileStructArray(end+1).name, matFileStructArray(end+1).ext] = fileparts(fullfile(folderPath, currentFile.name)); - elseif currentFile.isdir - % If it's a directory, recursively call the function - subfolderPath = fullfile(folderPath, currentFile.name); - subfolderMatFiles = getAllFilesInFolder(subfolderPath,extension); - - % Add .mat files from the subfolder to the structure array - matFileStructArray = [matFileStructArray, subfolderMatFiles]; - end - end -end - - +% Script, that shows the data management routine :-) + +loadExistingWareHouse = 0; + +if loadExistingWareHouse + + [file, path] = uigetfile(); + wh = load([path filesep file]); + wh = wh.wh; + wh.showInfo; + +else + + % 1) Define all your parameters, best practice directly constructs a + % structure + + params = struct; + + params.l = [2,10]; + + params.dispersion = [0]; + + params.sgm = [0]; + +% params.pol = ["YXYXYXYX","YXXYYXXY","YYYYYYYY"]; + params.pol = ["alternated","paired","copolarized"]; + + params.p_in = [3]; + + params.p_out = [-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2]; + + params.pmd = [0.1]; + + params.gamma = [0.0023]; + + params.realization = [1:20]; + + params.numchannels = [16]; + + params.center_wavelength = floor([getSweepWavelengths(35, 50e9, 1310)] .* 1000) ./ 1000 ; + params.center_wavelength = [1285 1287 1290 1292 1295]; + params.center_wavelength = 1310; + + params.channelspacing = [400e9]; + + params.random_zdw = [0]; + + %wh = warehouse :-) + wh = DataStorage(params); + + wh.showInfo; + + wh.addStorage("ber"); + + wh.addStorage("totalBer"); + +end + + + +%2) Simulate a bunch of data - TO BE IMPLEMENTED HERE - for now use scripts +%from Sebastian + +%3) Once the simulation folder is around, specifiy path and analyze dirs + +path = uigetdir('C:\Users\Silas\Documents\MATLAB\Raw_Cluster_Simulations'); + +allMat = getAllFilesInFolder(path,'.mat'); +allErr = getAllFilesInFolder(path,'.err'); + +%allMat = dir([path filesep '*.mat']); + +%allErr = dir([path filesep '*.err']); + +if numel(allMat) == 0 + warning('You defined an empty folder. Could not locate any .mat file.') +else + fprintf('%-20s', 'Err Files:'); fprintf('%-12s', num2str(numel(allErr))); fprintf('\n'); + fprintf('%-20s', 'Mat Files:'); fprintf('%-12s', num2str(numel(allMat))); fprintf('\n'); + fprintf('%-20s', 'Missing Mat Files:'); fprintf('%-12s', num2str(numel(allErr)-numel(allMat))); fprintf('\n'); +end + +%4) Now load that data + +f = waitbar(0,'Please wait...'); +cnt = 0; + +for num = 1:numel(allMat) + + fileName = allMat(num).name; + fileFolder = allMat(num).path; + fileExt = allMat(num).ext; +% + matFile = load([fileFolder filesep fileName fileExt]); + matFile = matFile.loop_data; + + % ____________________________________ + % FIND THE DATAPOINT CURRENTLY LOADED + zdw = 1310; + + channelplan = "symmetric"; + + channelspacing = str2double(strrep(regexp(fileName,'(_chsp)+([\d]*)','match'),'_chsp','')).*1e9; + + numchannels = str2double(strrep(regexp(fileName,'(ch)+(_)+([\d]*)','match'),'ch_','')); + + center_wavelength = str2double(insertAfter(strrep(regexp(fileName,'(lambda)+([\d]*)','match'),'lambda',''),4,'.')); + + center_wavelength = floor(center_wavelength * 1000) / 1000; + + if center_wavelength == 2192 + continue + end + + center_wavelength = 1310; + + random_zdw = str2double(strrep(regexp(fileName,'(rzwd)+([\d])','match'),'rzwd','')); + + l = str2double(strrep(regexp(fileName,'([L])+(_)+([\d]*)','match'),'L_','')); + + d = str2double(strrep(regexp(fileName,'([D])+(_)+([\d]*)','match'),'D_','')); + + if d == 0 + sgm = false; + else + sgm = true; + end + + + if numel(regexp(fileName,'(YYYY)','match')) > 1 + pol = "copolarized"; + elseif numel(regexp(fileName,'(YXXY)','match')) > 1 + pol = "paired"; + elseif numel(regexp(fileName,'(YXYX)','match')) > 1 + pol = "alternated"; + else + pol = "copolarized"; + end + + p_in = str2double(strrep(regexp(fileName,'(pow_)+([-,\d]{1})','match'),'pow_','')); + + pmd = 0.1; + + gamma = 0.0023; + + realiz = str2double(strrep(regexp(fileName,'(r)+([-,\d]{1,3})','match'),'r','')); + + + + % ____________________________________ + % Get the information you want from current file + rop=[]; + ber = []; + for pow = 2:12 + + module_number = ''; + for p = 1:11 %11 because there are 11 ROP branches in model + + % get ROP + if p == 1 + p_out = matFile.dp_optatten_para.atten; + else + p_out = matFile.("dp_optatten__"+(p)+"_para").atten; + end + + p_out = round(p_out-10*log10(numel(matFile.config.parameters.common.wavelengthPlan))); + + for c = 1:numel(matFile.config.parameters.common.wavelengthPlan) + + ber(c) = matFile.("prms_compare_wdm__"+(p+1)+"_out"){1,c}.ber; + + end + + totalBer = matFile.("prms_compare_wdm__"+(p+1)+"_out"){1,end}.totalBer; + + if totalBer > 0.2 && channelspacing == 400e9 && pol == "alternated" + disp("stopping here"); + pause; + end + + + % ____________________________________ + % Add value to warehouse at the correct position + + + + wh.addValueToStorage(ber,'ber',l,d,sgm,pol,p_in,p_out,pmd,gamma,realiz,numchannels, center_wavelength,channelspacing,random_zdw); + wh.getStoValue('ber',l,d,sgm,pol,p_in,p_out,pmd,gamma,realiz,numchannels, center_wavelength,channelspacing,random_zdw); + wh.addValueToStorage(totalBer,'totalBer',l,d,sgm,pol,p_in,p_out,pmd,gamma,realiz,numchannels,center_wavelength,channelspacing,random_zdw); + + end + + end + waitbar(num/numel(allMat),f,'Loading your data'); +end + +close(f) + + + + + +% 4) Hey! the warehouse is here and (hopefully) filled with data :-) + +% Create a save dialog +defaultDir = 'C:\Users\Silas\Documents\MATLAB\Raw_Cluster_Simulations\'; +defaultExt = '*.mat'; +[filename, pathname] = uiputfile(fullfile(defaultDir, defaultExt),'', 'wh.mat'); + +% Check if the user pressed Cancel +if isequal(filename, 0) || isequal(pathname, 0) + disp('Save operation canceled.'); +else + % Save the variable to the selected file + save(fullfile(pathname, filename), 'wh'); + disp(['Variable "wh" saved to: ', fullfile(pathname, filename)]); +end + + + + +function matFileStructArray = getAllFilesInFolder(folderPath,extension) + % Get a list of all files in the current folder + currentFolderFiles = dir(fullfile(folderPath, '*')); + + % Exclude '.' and '..' directories + currentFolderFiles = currentFolderFiles(~ismember({currentFolderFiles.name}, {'.', '..'})); + + % Initialize the structure array for .mat files + matFileStructArray = struct('path', {}, 'name', {}, 'ext', {}); + + % Loop over each file in the current folder + for i = 1:length(currentFolderFiles) + currentFile = currentFolderFiles(i); + + % Check if the current item is a file and has a .mat extension + if ~currentFile.isdir && endsWith(currentFile.name, extension, 'IgnoreCase', true) + % If it's a .mat file, add it to the structure array + [matFileStructArray(end + 1).path,matFileStructArray(end+1).name, matFileStructArray(end+1).ext] = fileparts(fullfile(folderPath, currentFile.name)); + elseif currentFile.isdir + % If it's a directory, recursively call the function + subfolderPath = fullfile(folderPath, currentFile.name); + subfolderMatFiles = getAllFilesInFolder(subfolderPath,extension); + + % Add .mat files from the subfolder to the structure array + matFileStructArray = [matFileStructArray, subfolderMatFiles]; + end + end +end + + diff --git a/Classes/Warehouse_class/functions/fwm_plots/CompleteRoutine_DifferentChannels_Fig3.m b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/CompleteRoutine_DifferentChannels_Fig3.m similarity index 96% rename from Classes/Warehouse_class/functions/fwm_plots/CompleteRoutine_DifferentChannels_Fig3.m rename to Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/CompleteRoutine_DifferentChannels_Fig3.m index aaec117..170fee9 100644 --- a/Classes/Warehouse_class/functions/fwm_plots/CompleteRoutine_DifferentChannels_Fig3.m +++ b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/CompleteRoutine_DifferentChannels_Fig3.m @@ -1,250 +1,250 @@ -% Script, that shows the data management routine :-) - -loadExistingWareHouse = 0; - -if loadExistingWareHouse - - [file, path] = uigetfile(); - wh = load([path filesep file]); - wh = wh.wh; - wh.showInfo; - -else - - % 1) Define all your parameters, best practice directly constructs a - % structure - - params = struct; - - params.l = [2, 10]; - - params.dispersion = [0, 3]; - - params.sgm = [0, 1]; - -% params.pol = ["YXYXYXYX","YXXYYXXY","YYYYYYYY"]; - params.pol = ["alternated","paired","copolarized"]; - - params.p_in = [3]; - - params.p_out = [-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2]; - - params.pmd = [0.1]; - - params.gamma = [0.0023]; - - params.realization = [1:20]; - - params.numchannels = [1,2,4,8,16]; - - params.center_wavelength = floor([getSweepWavelengths(35, 50e9, 1310)] .* 1000) ./ 1000 ; - params.center_wavelength = [1285 1287 1290 1292 1295]; - params.center_wavelength = 1310; - - params.channelspacing = [400e9]; - - params.random_zdw = [0,1]; - - %wh = warehouse :-) - wh = DataStorage(params); - - wh.showInfo; - - wh.addStorage("ber"); - - wh.addStorage("totalBer"); - -end - - - -%2) Simulate a bunch of data - TO BE IMPLEMENTED HERE - for now use scripts -%from Sebastian - -%3) Once the simulation folder is around, specifiy path and analyze dirs - -path = uigetdir('C:\Users\Silas\Documents\MATLAB\Raw_Cluster_Simulations'); - -allMat = getAllFilesInFolder(path,'.mat'); -allErr = getAllFilesInFolder(path,'.err'); - -%allMat = dir([path filesep '*.mat']); - -%allErr = dir([path filesep '*.err']); - -if numel(allMat) == 0 - warning('You defined an empty folder. Could not locate any .mat file.') -else - fprintf('%-20s', 'Err Files:'); fprintf('%-12s', num2str(numel(allErr))); fprintf('\n'); - fprintf('%-20s', 'Mat Files:'); fprintf('%-12s', num2str(numel(allMat))); fprintf('\n'); - fprintf('%-20s', 'Missing Mat Files:'); fprintf('%-12s', num2str(numel(allErr)-numel(allMat))); fprintf('\n'); -end - -%4) Now load that data - -f = waitbar(0,'Please wait...'); -cnt = 0; - -for num = 1:numel(allMat) - - fileName = allMat(num).name; - fileFolder = allMat(num).path; - fileExt = allMat(num).ext; -% - matFile = load([fileFolder filesep fileName fileExt]); - matFile = matFile.loop_data; - - % ____________________________________ - % FIND THE DATAPOINT CURRENTLY LOADED - zdw = 1310; - - channelplan = "symmetric"; - - channelspacing = str2double(strrep(regexp(fileName,'(_chsp)+([\d]*)','match'),'_chsp','')).*1e9; - - numchannels = str2double(strrep(regexp(fileName,'(ch)+(_)+([\d]*)','match'),'ch_','')); - - center_wavelength = str2double(insertAfter(strrep(regexp(fileName,'(lambda)+([\d]*)','match'),'lambda',''),4,'.')); - - center_wavelength = floor(center_wavelength * 1000) / 1000; - - if center_wavelength == 2192 - continue - end - - center_wavelength = 1310; - - random_zdw = str2double(strrep(regexp(fileName,'(rzwd)+([\d])','match'),'rzwd','')); - - l = str2double(strrep(regexp(fileName,'([L])+(_)+([\d]*)','match'),'L_','')); - - d = str2double(strrep(regexp(fileName,'([D])+(_)+([\d]*)','match'),'D_','')); - - if d == 0 - sgm = false; - else - sgm = true; - end - - - if numel(regexp(fileName,'(YYYY)','match')) > 1 - pol = "copolarized"; - elseif numel(regexp(fileName,'(YXXY)','match')) > 1 - pol = "paired"; - elseif numel(regexp(fileName,'(YXYX)','match')) > 1 - pol = "alternated"; - else - pol = "copolarized"; - end - - p_in = str2double(strrep(regexp(fileName,'(pow_)+([-,\d]{1})','match'),'pow_','')); - - pmd = 0.1; - - gamma = 0.0023; - - realiz = str2double(strrep(regexp(fileName,'(r)+([-,\d]{1,3})','match'),'r','')); - - - - % ____________________________________ - % Get the information you want from current file - rop=[]; - ber = []; - for pow = 2:12 - - module_number = ''; - for p = 1:11 %11 because there are 11 ROP branches in model - - % get ROP - if p == 1 - p_out = matFile.dp_optatten_para.atten; - else - p_out = matFile.("dp_optatten__"+(p)+"_para").atten; - end - - p_out = round(p_out-10*log10(numel(matFile.config.parameters.common.wavelengthPlan))); - - for c = 1:numel(matFile.config.parameters.common.wavelengthPlan) - - ber(c) = matFile.("prms_compare_wdm__"+(p+1)+"_out"){1,c}.ber; - - end - - totalBer = matFile.("prms_compare_wdm__"+(p+1)+"_out"){1,end}.totalBer; - - if totalBer > 0.2 && channelspacing == 400e9 && pol == "alternated" - disp("stopping here"); - pause; - end - - % ____________________________________ - % Add value to warehouse at the correct position - - - - wh.addValueToStorage(ber,'ber',l,d,sgm,pol,p_in,p_out,pmd,gamma,realiz,numchannels, center_wavelength,channelspacing,random_zdw); - wh.getStoValue('ber',l,d,sgm,pol,p_in,p_out,pmd,gamma,realiz,numchannels, center_wavelength,channelspacing,random_zdw); - wh.addValueToStorage(totalBer,'totalBer',l,d,sgm,pol,p_in,p_out,pmd,gamma,realiz,numchannels,center_wavelength,channelspacing,random_zdw); - - end - - end - waitbar(num/numel(allMat),f,'Loading your data'); -end - -close(f) - - - - - -% 4) Hey! the warehouse is here and (hopefully) filled with data :-) - -% Create a save dialog -defaultDir = 'C:\Users\Silas\Documents\MATLAB\Raw_Cluster_Simulations\'; -defaultExt = '*.mat'; -[filename, pathname] = uiputfile(fullfile(defaultDir, defaultExt),'', 'wh.mat'); - -% Check if the user pressed Cancel -if isequal(filename, 0) || isequal(pathname, 0) - disp('Save operation canceled.'); -else - % Save the variable to the selected file - save(fullfile(pathname, filename), 'wh'); - disp(['Variable "wh" saved to: ', fullfile(pathname, filename)]); -end - - - - -function matFileStructArray = getAllFilesInFolder(folderPath,extension) - % Get a list of all files in the current folder - currentFolderFiles = dir(fullfile(folderPath, '*')); - - % Exclude '.' and '..' directories - currentFolderFiles = currentFolderFiles(~ismember({currentFolderFiles.name}, {'.', '..'})); - - % Initialize the structure array for .mat files - matFileStructArray = struct('path', {}, 'name', {}, 'ext', {}); - - % Loop over each file in the current folder - for i = 1:length(currentFolderFiles) - currentFile = currentFolderFiles(i); - - % Check if the current item is a file and has a .mat extension - if ~currentFile.isdir && endsWith(currentFile.name, extension, 'IgnoreCase', true) - % If it's a .mat file, add it to the structure array - [matFileStructArray(end + 1).path,matFileStructArray(end+1).name, matFileStructArray(end+1).ext] = fileparts(fullfile(folderPath, currentFile.name)); - elseif currentFile.isdir - % If it's a directory, recursively call the function - subfolderPath = fullfile(folderPath, currentFile.name); - subfolderMatFiles = getAllFilesInFolder(subfolderPath,extension); - - % Add .mat files from the subfolder to the structure array - matFileStructArray = [matFileStructArray, subfolderMatFiles]; - end - end -end - - +% Script, that shows the data management routine :-) + +loadExistingWareHouse = 0; + +if loadExistingWareHouse + + [file, path] = uigetfile(); + wh = load([path filesep file]); + wh = wh.wh; + wh.showInfo; + +else + + % 1) Define all your parameters, best practice directly constructs a + % structure + + params = struct; + + params.l = [2, 10]; + + params.dispersion = [0, 3]; + + params.sgm = [0, 1]; + +% params.pol = ["YXYXYXYX","YXXYYXXY","YYYYYYYY"]; + params.pol = ["alternated","paired","copolarized"]; + + params.p_in = [3]; + + params.p_out = [-12,-11,-10,-9,-8,-7,-6,-5,-4,-3,-2]; + + params.pmd = [0.1]; + + params.gamma = [0.0023]; + + params.realization = [1:20]; + + params.numchannels = [1,2,4,8,16]; + + params.center_wavelength = floor([getSweepWavelengths(35, 50e9, 1310)] .* 1000) ./ 1000 ; + params.center_wavelength = [1285 1287 1290 1292 1295]; + params.center_wavelength = 1310; + + params.channelspacing = [400e9]; + + params.random_zdw = [0,1]; + + %wh = warehouse :-) + wh = DataStorage(params); + + wh.showInfo; + + wh.addStorage("ber"); + + wh.addStorage("totalBer"); + +end + + + +%2) Simulate a bunch of data - TO BE IMPLEMENTED HERE - for now use scripts +%from Sebastian + +%3) Once the simulation folder is around, specifiy path and analyze dirs + +path = uigetdir('C:\Users\Silas\Documents\MATLAB\Raw_Cluster_Simulations'); + +allMat = getAllFilesInFolder(path,'.mat'); +allErr = getAllFilesInFolder(path,'.err'); + +%allMat = dir([path filesep '*.mat']); + +%allErr = dir([path filesep '*.err']); + +if numel(allMat) == 0 + warning('You defined an empty folder. Could not locate any .mat file.') +else + fprintf('%-20s', 'Err Files:'); fprintf('%-12s', num2str(numel(allErr))); fprintf('\n'); + fprintf('%-20s', 'Mat Files:'); fprintf('%-12s', num2str(numel(allMat))); fprintf('\n'); + fprintf('%-20s', 'Missing Mat Files:'); fprintf('%-12s', num2str(numel(allErr)-numel(allMat))); fprintf('\n'); +end + +%4) Now load that data + +f = waitbar(0,'Please wait...'); +cnt = 0; + +for num = 1:numel(allMat) + + fileName = allMat(num).name; + fileFolder = allMat(num).path; + fileExt = allMat(num).ext; +% + matFile = load([fileFolder filesep fileName fileExt]); + matFile = matFile.loop_data; + + % ____________________________________ + % FIND THE DATAPOINT CURRENTLY LOADED + zdw = 1310; + + channelplan = "symmetric"; + + channelspacing = str2double(strrep(regexp(fileName,'(_chsp)+([\d]*)','match'),'_chsp','')).*1e9; + + numchannels = str2double(strrep(regexp(fileName,'(ch)+(_)+([\d]*)','match'),'ch_','')); + + center_wavelength = str2double(insertAfter(strrep(regexp(fileName,'(lambda)+([\d]*)','match'),'lambda',''),4,'.')); + + center_wavelength = floor(center_wavelength * 1000) / 1000; + + if center_wavelength == 2192 + continue + end + + center_wavelength = 1310; + + random_zdw = str2double(strrep(regexp(fileName,'(rzwd)+([\d])','match'),'rzwd','')); + + l = str2double(strrep(regexp(fileName,'([L])+(_)+([\d]*)','match'),'L_','')); + + d = str2double(strrep(regexp(fileName,'([D])+(_)+([\d]*)','match'),'D_','')); + + if d == 0 + sgm = false; + else + sgm = true; + end + + + if numel(regexp(fileName,'(YYYY)','match')) > 1 + pol = "copolarized"; + elseif numel(regexp(fileName,'(YXXY)','match')) > 1 + pol = "paired"; + elseif numel(regexp(fileName,'(YXYX)','match')) > 1 + pol = "alternated"; + else + pol = "copolarized"; + end + + p_in = str2double(strrep(regexp(fileName,'(pow_)+([-,\d]{1})','match'),'pow_','')); + + pmd = 0.1; + + gamma = 0.0023; + + realiz = str2double(strrep(regexp(fileName,'(r)+([-,\d]{1,3})','match'),'r','')); + + + + % ____________________________________ + % Get the information you want from current file + rop=[]; + ber = []; + for pow = 2:12 + + module_number = ''; + for p = 1:11 %11 because there are 11 ROP branches in model + + % get ROP + if p == 1 + p_out = matFile.dp_optatten_para.atten; + else + p_out = matFile.("dp_optatten__"+(p)+"_para").atten; + end + + p_out = round(p_out-10*log10(numel(matFile.config.parameters.common.wavelengthPlan))); + + for c = 1:numel(matFile.config.parameters.common.wavelengthPlan) + + ber(c) = matFile.("prms_compare_wdm__"+(p+1)+"_out"){1,c}.ber; + + end + + totalBer = matFile.("prms_compare_wdm__"+(p+1)+"_out"){1,end}.totalBer; + + if totalBer > 0.2 && channelspacing == 400e9 && pol == "alternated" + disp("stopping here"); + pause; + end + + % ____________________________________ + % Add value to warehouse at the correct position + + + + wh.addValueToStorage(ber,'ber',l,d,sgm,pol,p_in,p_out,pmd,gamma,realiz,numchannels, center_wavelength,channelspacing,random_zdw); + wh.getStoValue('ber',l,d,sgm,pol,p_in,p_out,pmd,gamma,realiz,numchannels, center_wavelength,channelspacing,random_zdw); + wh.addValueToStorage(totalBer,'totalBer',l,d,sgm,pol,p_in,p_out,pmd,gamma,realiz,numchannels,center_wavelength,channelspacing,random_zdw); + + end + + end + waitbar(num/numel(allMat),f,'Loading your data'); +end + +close(f) + + + + + +% 4) Hey! the warehouse is here and (hopefully) filled with data :-) + +% Create a save dialog +defaultDir = 'C:\Users\Silas\Documents\MATLAB\Raw_Cluster_Simulations\'; +defaultExt = '*.mat'; +[filename, pathname] = uiputfile(fullfile(defaultDir, defaultExt),'', 'wh.mat'); + +% Check if the user pressed Cancel +if isequal(filename, 0) || isequal(pathname, 0) + disp('Save operation canceled.'); +else + % Save the variable to the selected file + save(fullfile(pathname, filename), 'wh'); + disp(['Variable "wh" saved to: ', fullfile(pathname, filename)]); +end + + + + +function matFileStructArray = getAllFilesInFolder(folderPath,extension) + % Get a list of all files in the current folder + currentFolderFiles = dir(fullfile(folderPath, '*')); + + % Exclude '.' and '..' directories + currentFolderFiles = currentFolderFiles(~ismember({currentFolderFiles.name}, {'.', '..'})); + + % Initialize the structure array for .mat files + matFileStructArray = struct('path', {}, 'name', {}, 'ext', {}); + + % Loop over each file in the current folder + for i = 1:length(currentFolderFiles) + currentFile = currentFolderFiles(i); + + % Check if the current item is a file and has a .mat extension + if ~currentFile.isdir && endsWith(currentFile.name, extension, 'IgnoreCase', true) + % If it's a .mat file, add it to the structure array + [matFileStructArray(end + 1).path,matFileStructArray(end+1).name, matFileStructArray(end+1).ext] = fileparts(fullfile(folderPath, currentFile.name)); + elseif currentFile.isdir + % If it's a directory, recursively call the function + subfolderPath = fullfile(folderPath, currentFile.name); + subfolderMatFiles = getAllFilesInFolder(subfolderPath,extension); + + % Add .mat files from the subfolder to the structure array + matFileStructArray = [matFileStructArray, subfolderMatFiles]; + end + end +end + + diff --git a/Classes/Warehouse_class/functions/fwm_plots/automate_JLT_plots.m b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/automate_JLT_plots.m similarity index 96% rename from Classes/Warehouse_class/functions/fwm_plots/automate_JLT_plots.m rename to Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/automate_JLT_plots.m index cc2c8d6..801c0e8 100644 --- a/Classes/Warehouse_class/functions/fwm_plots/automate_JLT_plots.m +++ b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/automate_JLT_plots.m @@ -1,415 +1,415 @@ - - -%automate plots -[file, path] = uigetfile("C:\Users\Silas\Documents\MATLAB\Datensätze\Raw_Cluster_Simulations\session_februar_24\wh_mi_nacht.mat"); -wh = load([path filesep file]); -wh = wh.wh; - -% fields = fieldnames(wh.parameter); -% for k = 1:numel(fields) -% oldParam = wh.parameter.(fields{k}); -% % copy over the properties to your new class -% wh.parameter.(fields{k}) = StorageParameter(... -% oldParam.Name, oldParam.values); -% end -% - - -plotJob = struct(); -width = 350; -height = 200; -plotJob.Position = [100 100 width 100+height]; -cols = cbrewer2("paired",12); -plotJob.color = cols(1,:); -plotJob.l = 2; -plotJob.ch = 16; -plotJob.d = 0; -plotJob.sgm = 0; -plotJob.pol = "copolarized"; -plotJob.p_in = 3; -plotJob.gamma = 0.0023; -plotJob.pmd = 0.1; -plotJob.channelspacing = 400e9; -plotJob.randzdw = 0; - - -plotJob.plot_ber_curve = 0; -plotJob.plot_3dber_curve = 0; -plotJob.plot_violin = 1; -plotJob.plot_wavelength_sweep = 0; -plotJob.plot_wavelength_sweep_failure_rate = 0; - - -plotJob.dataStatArg = 'Lineplot with quartiles'; -plotJob.plotTypeArg = 'Lines'; -plotJob.displayname = 'a'; -plotJob.title = 'title'; -plotJob.figName = '16 Chann'; -plotJob.xAxisLabel = 'ROP per Channel in dBm'; -plotJob.yAxisLabel = 'BER'; - -%% - - % createbercurves(wh,plotJob) - - P = [3,6]; - for i = 1:2 - plotJob.p_in = P(i); - createviolinplots(wh,plotJob); - end - % createsweepplots(wh,plotJob); - - -%% 1 -function createbercurves(wh,plotJob) -width = 1650; -height = 400; -s = 100; -e = 100; - -cols = cbrewer2("paired",12); -numRows = 2; -numCols = 4; - -plotJob.figName = '16 Chann_200G'; -plotJob.channelspacing = 400e9; -plotJob.ch = 16; -Len = [2,2,2,2,10,10,10,10]; -Pol = ["copolarized","alternated","paired","copolarized","copolarized","alternated","paired","copolarized"]; -Title = ["Co Polarized","Alternating Pol. Interl.","Paired Pol. Interl.","Link Segmentation",]; -D = [0,0,0,3,0,0,0,3]; -Sgm = [0,0,0,1,0,0,0,1]; - -colidx = [4,8,6]; -P_launch = [3,6]; - -fig = figure('Name',plotJob.figName); -fig.Position = plotJob.Position; -fig.Units = "centimeters"; -fig.Position = [0 0 18 7]; -t = tiledlayout(numRows,numCols,'TileSpacing','compact','Padding','compact'); -for idx = 1:(numRows * numCols) - % Create subplot - % sp = subplot(numRows, numCols, idx); - nexttile; - plotJob.l = Len(idx); - plotJob.pol = Pol(idx); - plotJob.d = D(idx); - plotJob.sgm = Sgm(idx); - plotJob.randzdw = 1; - - for i = 1:length(P_launch) - - plotJob.p_in = P_launch(i); - plotJob.color = cols(colidx(i),:); - hold on - plotCurve(wh, plotJob); - - end - % - if idx ~= 1 && idx ~= 5 % For example, hide y-axis for subplot 1 - set(gca, 'YTickLabel',[]); % Hide y-axis ticks and labels - set(gca,'YGrid','on'); - set(gca, 'YLabel', []); - end - if idx ~= 5 && idx ~= 6 && idx ~= 7 && idx ~= 8 - set(gca, 'XLabel', []); - set(gca, 'XTickLabel', []); - - end - grid on - - g = gca; - pos = g.Position; - if idx <= 4 - title(Title(idx),'FontSize',8); - % a = annotation('textbox', pos-[0.0020 -0.1434 0.0947 0.3121], 'String', "FEC: 3.8e-3","LineStyle","none","FontSize",8,'LineWidth',0.1,'Interpreter','latex',"FontUnits","points",'Vert','middle','FitBoxToText','on'); - % a = annotation('textbox', pos, 'String', "2 km","LineStyle","none","FontSize",8,'LineWidth',0.1,'Interpreter','latex',"FontUnits","points",'Vert','bottom','FitBoxToText','on'); - else - % a = annotation('textbox', pos, 'String', "FEC: 3.8e-3","LineStyle","none","FontSize",8,'LineWidth',0.1,'Interpreter','latex',"FontUnits","points",'Vert','middle','FitBoxToText','on'); - % a = annotation('textbox', pos, 'String', "10 km","LineStyle","none","FontSize",8,'LineWidth',0.1,'Interpreter','latex',"FontUnits","points",'Vert','bottom','FitBoxToText','on'); - end - -end - -% Create textbox -annotation(fig,'textbox',... - [0.0696078431372547 0.246851385390432 0.0656862745098043 0.0453400503778337],... - 'String','10 km',... - 'LineStyle','none',... - 'Interpreter','latex',... - 'FontSize',8,... - 'FitBoxToText','off'); - -% Create textbox -annotation(fig,'textbox',... - [0.288235294117647 0.239294710327459 0.0656862745098043 0.0453400503778338],... - 'String','10 km',... - 'LineStyle','none',... - 'Interpreter','latex',... - 'FontSize',8,... - 'FitBoxToText','off'); - -% Create textbox -annotation(fig,'textbox',... - [0.516666666666666 0.241813602015117 0.0656862745098042 0.0453400503778338],... - 'String','10 km',... - 'LineStyle','none',... - 'Interpreter','latex',... - 'FontSize',8,... - 'FitBoxToText','off'); - -% Create textbox -annotation(fig,'textbox',... - [0.742156862745097 0.236775818639802 0.0656862745098042 0.0453400503778339],... - 'String','10 km',... - 'LineStyle','none',... - 'Interpreter','latex',... - 'FontSize',8,... - 'FitBoxToText','off'); - -% Create textbox -annotation(fig,'textbox',... - [0.071996471804854 0.578899159967702 0.0656862745098039 0.0453400503778341],... - 'String',{'2 km'},... - 'LineStyle','none',... - 'Interpreter','latex',... - 'FontSize',8,... - 'FitBoxToText','off'); - -% Create textbox -annotation(fig,'textbox',... - [0.29596893566113 0.576253721089996 0.0656862745098041 0.0453400503778341],... - 'String',{'2 km'},... - 'LineStyle','none',... - 'Interpreter','latex',... - 'FontSize',8,... - 'FitBoxToText','off'); - -% Create textbox -annotation(fig,'textbox',... - [0.524883914268912 0.580785315705112 0.0656862745098041 0.0453400503778341],... - 'String',{'2 km'},... - 'LineStyle','none',... - 'Interpreter','latex',... - 'FontSize',8,... - 'FitBoxToText','off'); - -% Create textbox -annotation(fig,'textbox',... - [0.753758338909501 0.581291504465311 0.0656862745098037 0.0453400503778341],... - 'String',{'2 km'},... - 'LineStyle','none',... - 'Interpreter','latex',... - 'FontSize',8,... - 'FitBoxToText','off'); - -a=sgtitle(['N=',num2str(plotJob.ch),'; $\Delta f_{\mathrm{ch}}$= ',num2str(plotJob.channelspacing*1e-9),' GHz'],'FontSIze',10); -a.Interpreter = "latex"; - -lgd = legend('$P_{\mathrm{in}}=0$ dBm','$P_{\mathrm{in}}=3$ dBm','$P_{\mathrm{in}}=6$ dBm','Interpreter','latex'); -lgd.NumColumns = 3; -lgd.Layout.Tile = 'south'; - -copygraphics(t,'BackgroundColor','none'); -end - -%% 2 -function createviolinplots(wh,plotJob) - -width = 350; -height = 200; -s = 100; -e = 100; - -cols = cbrewer2("paired",12); -numRows = 1; -numCols = 4; - -plotJob.ch = 16; -plotJob.randzdw = 1; - -Pol = ["copolarized","copolarized","alternated","paired",]; -Title = ["Co Pol.","Link Segmentation","Paired Pol. Interl.","Alternating Pol. Interl."]; -D = [0,3,0,0]; -Sgm = [0,1,0,0]; - -colidx = [3]; -Len = [10]; - -fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName); -if isvalid(fig) - figure(fig) - % fig = get(fig); - AxesMain = fig.CurrentAxes; - hold on - % t = tiledlayout(1,4,'TileSpacing','compact','Padding','compact'); -else - fig = figure('name',char(plotJob.figName)); - AxesMain = gca; - hold on; grid on; - % t = tiledlayout(1,4,'TileSpacing','compact','Padding','compact'); -end - -for idx = 1:(numRows * numCols) - % Create subplot - subplot(numRows, numCols, idx); - - plotJob.pol = Pol(idx); - plotJob.d = D(idx); - plotJob.sgm = Sgm(idx); - - for i = 1 - - plotJob.color = cols(colidx(i),:); - plotJob.l = Len(i); - hold on - plotViolin(wh, plotJob); - - end - - if idx ~= 1 % For example, hide y-axis for subplot 1 - %set(gca, 'YTickLabel',[]); % Hide y-axis ticks and labels - set(gca, 'YGrid','on'); - set(gca, 'YLabel', []); - end - - if idx <= 4 - title(Title(idx)); - end - - -end - -% Create textbox -annotation(fig,'textbox',... - [0.300019607843137 0.816120906801009 0.108803921568628 0.0906801007556676],... - 'String','$P_{\mathrm{in}}=3$ dBm',... - 'LineStyle','none',... - 'Interpreter','latex',... - 'FontSize',8,... - 'FitBoxToText','off'); - -% Create textbox -annotation(fig,'textbox',... - [0.530411764705882 0.81612090680101 0.108803921568628 0.0906801007556676],... - 'String','$P_{\mathrm{in}}=3$ dBm',... - 'LineStyle','none',... - 'Interpreter','latex',... - 'FontSize',8,... - 'FitBoxToText','off'); - -% Create textbox -annotation(fig,'textbox',... - [0.755901960784313 0.816120906801011 0.108803921568628 0.0906801007556676],... - 'String','$P_{\mathrm{in}}=3$ dBm',... - 'LineStyle','none',... - 'Interpreter','latex',... - 'FontSize',8,... - 'FitBoxToText','off'); - -% Create textbox -annotation(fig,'textbox',... - [0.0696274509803918 0.584382871536529 0.108803921568628 0.0906801007556676],... - 'String','$P_{\mathrm{in}}=3$ dBm',... - 'LineStyle','none',... - 'Interpreter','latex',... - 'FontSize',8,... - 'FitBoxToText','off'); - -% lgd = legend('$P_{\mathrm{in}}=0$ dBm','$P_{\mathrm{in}}=3$ dBm','$P_{\mathrm{in}}=6$ dBm','Interpreter','latex'); -% lgd.NumColumns = 3; -% lgd.Layout.Tile = 'south'; - -end - -%% 3 -function createsweepplots(wh,plotJob) - -width = 650; -height = 200; -s = 100; -e = 100; -plotJob.Position = [0 0 width e+height]; - -cols = cbrewer2("paired",12); -numRows = 1; -numCols = 4; - - -plotJob.channelspacing = 200e9; -plotJob.ch = 16; -plotJob.randzdw = 1; -plotJob.l = 10; - -plotJob.p_in = 3; - -Pol = ["copolarized","alternated","paired","copolarized"]; -Title = ["Co Polarized","Alternating Pol. Interl.","Paired Pol. Interl.","Link Segmentation",]; -D = [0,0,0,3]; -Sgm = [0,0,0,1]; -Channelspacing = [200e9, 200e9]; -PlotTypeArg = ["--","-"]; -colidx = [6,8,2,4]; -Len = [2,10]; - -plotJob.figName = [num2str(plotJob.ch),num2str(plotJob.channelspacing*1e-9),num2str(plotJob.p_in),'...']; -plotJob.figName = "10km 400ghz"; - - - - -fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName); - -if isvalid(fig) - figure(fig) - fig = get(fig); - AxesMain = fig.CurrentAxes; - hold on -else - fig = figure('name',char(plotJob.figName)); - AxesMain = gca; - hold on -end - -fig.Position = plotJob.Position; -fig.Units = "centimeters"; -fig.Position = [0 0 18 7]; - -for j = 1 - - plotJob.channelspacing = Channelspacing(j); - plotJob.plotTypeArg = PlotTypeArg(j); - - for idx = 1:4 - - plotJob.color = cols(colidx(idx),:); - plotJob.pol = Pol(idx); - plotJob.d = D(idx); - plotJob.sgm = Sgm(idx); - plotJob.displayname = [char(plotJob.pol)]; - hold on - plotBerVsZdwFailureRate(wh, plotJob); - - end -end -legend('Location', 'southoutside', 'Orientation', 'horizontal'); - - -%plot channel positions -hold on -chpos = calcWavelengthPlan(plotJob.ch, plotJob.channelspacing, 1310); -xline(chpos,'LineWidth',2,'Alpha',0.4,'HandleVisibility','off'); - -chpos = calcWavelengthPlan(plotJob.ch, plotJob.channelspacing, chpos(4)); -xline(chpos,'LineWidth',2,'LineStyle','--','Alpha',0.1,'HandleVisibility','off'); - -title(['N=',num2str(plotJob.ch),' $\Delta f_{\mathrm{ch}}$= ',num2str(plotJob.channelspacing*1e-9),' GHz'],'FontSize',10,'Interpreter','latex'); - - - - -end - - - + + +%automate plots +[file, path] = uigetfile("C:\Users\Silas\Documents\MATLAB\Datensätze\Raw_Cluster_Simulations\session_februar_24\wh_mi_nacht.mat"); +wh = load([path filesep file]); +wh = wh.wh; + +% fields = fieldnames(wh.parameter); +% for k = 1:numel(fields) +% oldParam = wh.parameter.(fields{k}); +% % copy over the properties to your new class +% wh.parameter.(fields{k}) = StorageParameter(... +% oldParam.Name, oldParam.values); +% end +% + + +plotJob = struct(); +width = 350; +height = 200; +plotJob.Position = [100 100 width 100+height]; +cols = cbrewer2("paired",12); +plotJob.color = cols(1,:); +plotJob.l = 2; +plotJob.ch = 16; +plotJob.d = 0; +plotJob.sgm = 0; +plotJob.pol = "copolarized"; +plotJob.p_in = 3; +plotJob.gamma = 0.0023; +plotJob.pmd = 0.1; +plotJob.channelspacing = 400e9; +plotJob.randzdw = 0; + + +plotJob.plot_ber_curve = 0; +plotJob.plot_3dber_curve = 0; +plotJob.plot_violin = 1; +plotJob.plot_wavelength_sweep = 0; +plotJob.plot_wavelength_sweep_failure_rate = 0; + + +plotJob.dataStatArg = 'Lineplot with quartiles'; +plotJob.plotTypeArg = 'Lines'; +plotJob.displayname = 'a'; +plotJob.title = 'title'; +plotJob.figName = '16 Chann'; +plotJob.xAxisLabel = 'ROP per Channel in dBm'; +plotJob.yAxisLabel = 'BER'; + +%% + + % createbercurves(wh,plotJob) + + P = [3,6]; + for i = 1:2 + plotJob.p_in = P(i); + createviolinplots(wh,plotJob); + end + % createsweepplots(wh,plotJob); + + +%% 1 +function createbercurves(wh,plotJob) +width = 1650; +height = 400; +s = 100; +e = 100; + +cols = cbrewer2("paired",12); +numRows = 2; +numCols = 4; + +plotJob.figName = '16 Chann_200G'; +plotJob.channelspacing = 400e9; +plotJob.ch = 16; +Len = [2,2,2,2,10,10,10,10]; +Pol = ["copolarized","alternated","paired","copolarized","copolarized","alternated","paired","copolarized"]; +Title = ["Co Polarized","Alternating Pol. Interl.","Paired Pol. Interl.","Link Segmentation",]; +D = [0,0,0,3,0,0,0,3]; +Sgm = [0,0,0,1,0,0,0,1]; + +colidx = [4,8,6]; +P_launch = [3,6]; + +fig = figure('Name',plotJob.figName); +fig.Position = plotJob.Position; +fig.Units = "centimeters"; +fig.Position = [0 0 18 7]; +t = tiledlayout(numRows,numCols,'TileSpacing','compact','Padding','compact'); +for idx = 1:(numRows * numCols) + % Create subplot + % sp = subplot(numRows, numCols, idx); + nexttile; + plotJob.l = Len(idx); + plotJob.pol = Pol(idx); + plotJob.d = D(idx); + plotJob.sgm = Sgm(idx); + plotJob.randzdw = 1; + + for i = 1:length(P_launch) + + plotJob.p_in = P_launch(i); + plotJob.color = cols(colidx(i),:); + hold on + plotCurve(wh, plotJob); + + end + % + if idx ~= 1 && idx ~= 5 % For example, hide y-axis for subplot 1 + set(gca, 'YTickLabel',[]); % Hide y-axis ticks and labels + set(gca,'YGrid','on'); + set(gca, 'YLabel', []); + end + if idx ~= 5 && idx ~= 6 && idx ~= 7 && idx ~= 8 + set(gca, 'XLabel', []); + set(gca, 'XTickLabel', []); + + end + grid on + + g = gca; + pos = g.Position; + if idx <= 4 + title(Title(idx),'FontSize',8); + % a = annotation('textbox', pos-[0.0020 -0.1434 0.0947 0.3121], 'String', "FEC: 3.8e-3","LineStyle","none","FontSize",8,'LineWidth',0.1,'Interpreter','latex',"FontUnits","points",'Vert','middle','FitBoxToText','on'); + % a = annotation('textbox', pos, 'String', "2 km","LineStyle","none","FontSize",8,'LineWidth',0.1,'Interpreter','latex',"FontUnits","points",'Vert','bottom','FitBoxToText','on'); + else + % a = annotation('textbox', pos, 'String', "FEC: 3.8e-3","LineStyle","none","FontSize",8,'LineWidth',0.1,'Interpreter','latex',"FontUnits","points",'Vert','middle','FitBoxToText','on'); + % a = annotation('textbox', pos, 'String', "10 km","LineStyle","none","FontSize",8,'LineWidth',0.1,'Interpreter','latex',"FontUnits","points",'Vert','bottom','FitBoxToText','on'); + end + +end + +% Create textbox +annotation(fig,'textbox',... + [0.0696078431372547 0.246851385390432 0.0656862745098043 0.0453400503778337],... + 'String','10 km',... + 'LineStyle','none',... + 'Interpreter','latex',... + 'FontSize',8,... + 'FitBoxToText','off'); + +% Create textbox +annotation(fig,'textbox',... + [0.288235294117647 0.239294710327459 0.0656862745098043 0.0453400503778338],... + 'String','10 km',... + 'LineStyle','none',... + 'Interpreter','latex',... + 'FontSize',8,... + 'FitBoxToText','off'); + +% Create textbox +annotation(fig,'textbox',... + [0.516666666666666 0.241813602015117 0.0656862745098042 0.0453400503778338],... + 'String','10 km',... + 'LineStyle','none',... + 'Interpreter','latex',... + 'FontSize',8,... + 'FitBoxToText','off'); + +% Create textbox +annotation(fig,'textbox',... + [0.742156862745097 0.236775818639802 0.0656862745098042 0.0453400503778339],... + 'String','10 km',... + 'LineStyle','none',... + 'Interpreter','latex',... + 'FontSize',8,... + 'FitBoxToText','off'); + +% Create textbox +annotation(fig,'textbox',... + [0.071996471804854 0.578899159967702 0.0656862745098039 0.0453400503778341],... + 'String',{'2 km'},... + 'LineStyle','none',... + 'Interpreter','latex',... + 'FontSize',8,... + 'FitBoxToText','off'); + +% Create textbox +annotation(fig,'textbox',... + [0.29596893566113 0.576253721089996 0.0656862745098041 0.0453400503778341],... + 'String',{'2 km'},... + 'LineStyle','none',... + 'Interpreter','latex',... + 'FontSize',8,... + 'FitBoxToText','off'); + +% Create textbox +annotation(fig,'textbox',... + [0.524883914268912 0.580785315705112 0.0656862745098041 0.0453400503778341],... + 'String',{'2 km'},... + 'LineStyle','none',... + 'Interpreter','latex',... + 'FontSize',8,... + 'FitBoxToText','off'); + +% Create textbox +annotation(fig,'textbox',... + [0.753758338909501 0.581291504465311 0.0656862745098037 0.0453400503778341],... + 'String',{'2 km'},... + 'LineStyle','none',... + 'Interpreter','latex',... + 'FontSize',8,... + 'FitBoxToText','off'); + +a=sgtitle(['N=',num2str(plotJob.ch),'; $\Delta f_{\mathrm{ch}}$= ',num2str(plotJob.channelspacing*1e-9),' GHz'],'FontSIze',10); +a.Interpreter = "latex"; + +lgd = legend('$P_{\mathrm{in}}=0$ dBm','$P_{\mathrm{in}}=3$ dBm','$P_{\mathrm{in}}=6$ dBm','Interpreter','latex'); +lgd.NumColumns = 3; +lgd.Layout.Tile = 'south'; + +copygraphics(t,'BackgroundColor','none'); +end + +%% 2 +function createviolinplots(wh,plotJob) + +width = 350; +height = 200; +s = 100; +e = 100; + +cols = cbrewer2("paired",12); +numRows = 1; +numCols = 4; + +plotJob.ch = 16; +plotJob.randzdw = 1; + +Pol = ["copolarized","copolarized","alternated","paired",]; +Title = ["Co Pol.","Link Segmentation","Paired Pol. Interl.","Alternating Pol. Interl."]; +D = [0,3,0,0]; +Sgm = [0,1,0,0]; + +colidx = [3]; +Len = [10]; + +fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName); +if isvalid(fig) + figure(fig) + % fig = get(fig); + AxesMain = fig.CurrentAxes; + hold on + % t = tiledlayout(1,4,'TileSpacing','compact','Padding','compact'); +else + fig = figure('name',char(plotJob.figName)); + AxesMain = gca; + hold on; grid on; + % t = tiledlayout(1,4,'TileSpacing','compact','Padding','compact'); +end + +for idx = 1:(numRows * numCols) + % Create subplot + subplot(numRows, numCols, idx); + + plotJob.pol = Pol(idx); + plotJob.d = D(idx); + plotJob.sgm = Sgm(idx); + + for i = 1 + + plotJob.color = cols(colidx(i),:); + plotJob.l = Len(i); + hold on + plotViolin(wh, plotJob); + + end + + if idx ~= 1 % For example, hide y-axis for subplot 1 + %set(gca, 'YTickLabel',[]); % Hide y-axis ticks and labels + set(gca, 'YGrid','on'); + set(gca, 'YLabel', []); + end + + if idx <= 4 + title(Title(idx)); + end + + +end + +% Create textbox +annotation(fig,'textbox',... + [0.300019607843137 0.816120906801009 0.108803921568628 0.0906801007556676],... + 'String','$P_{\mathrm{in}}=3$ dBm',... + 'LineStyle','none',... + 'Interpreter','latex',... + 'FontSize',8,... + 'FitBoxToText','off'); + +% Create textbox +annotation(fig,'textbox',... + [0.530411764705882 0.81612090680101 0.108803921568628 0.0906801007556676],... + 'String','$P_{\mathrm{in}}=3$ dBm',... + 'LineStyle','none',... + 'Interpreter','latex',... + 'FontSize',8,... + 'FitBoxToText','off'); + +% Create textbox +annotation(fig,'textbox',... + [0.755901960784313 0.816120906801011 0.108803921568628 0.0906801007556676],... + 'String','$P_{\mathrm{in}}=3$ dBm',... + 'LineStyle','none',... + 'Interpreter','latex',... + 'FontSize',8,... + 'FitBoxToText','off'); + +% Create textbox +annotation(fig,'textbox',... + [0.0696274509803918 0.584382871536529 0.108803921568628 0.0906801007556676],... + 'String','$P_{\mathrm{in}}=3$ dBm',... + 'LineStyle','none',... + 'Interpreter','latex',... + 'FontSize',8,... + 'FitBoxToText','off'); + +% lgd = legend('$P_{\mathrm{in}}=0$ dBm','$P_{\mathrm{in}}=3$ dBm','$P_{\mathrm{in}}=6$ dBm','Interpreter','latex'); +% lgd.NumColumns = 3; +% lgd.Layout.Tile = 'south'; + +end + +%% 3 +function createsweepplots(wh,plotJob) + +width = 650; +height = 200; +s = 100; +e = 100; +plotJob.Position = [0 0 width e+height]; + +cols = cbrewer2("paired",12); +numRows = 1; +numCols = 4; + + +plotJob.channelspacing = 200e9; +plotJob.ch = 16; +plotJob.randzdw = 1; +plotJob.l = 10; + +plotJob.p_in = 3; + +Pol = ["copolarized","alternated","paired","copolarized"]; +Title = ["Co Polarized","Alternating Pol. Interl.","Paired Pol. Interl.","Link Segmentation",]; +D = [0,0,0,3]; +Sgm = [0,0,0,1]; +Channelspacing = [200e9, 200e9]; +PlotTypeArg = ["--","-"]; +colidx = [6,8,2,4]; +Len = [2,10]; + +plotJob.figName = [num2str(plotJob.ch),num2str(plotJob.channelspacing*1e-9),num2str(plotJob.p_in),'...']; +plotJob.figName = "10km 400ghz"; + + + + +fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName); + +if isvalid(fig) + figure(fig) + fig = get(fig); + AxesMain = fig.CurrentAxes; + hold on +else + fig = figure('name',char(plotJob.figName)); + AxesMain = gca; + hold on +end + +fig.Position = plotJob.Position; +fig.Units = "centimeters"; +fig.Position = [0 0 18 7]; + +for j = 1 + + plotJob.channelspacing = Channelspacing(j); + plotJob.plotTypeArg = PlotTypeArg(j); + + for idx = 1:4 + + plotJob.color = cols(colidx(idx),:); + plotJob.pol = Pol(idx); + plotJob.d = D(idx); + plotJob.sgm = Sgm(idx); + plotJob.displayname = [char(plotJob.pol)]; + hold on + plotBerVsZdwFailureRate(wh, plotJob); + + end +end +legend('Location', 'southoutside', 'Orientation', 'horizontal'); + + +%plot channel positions +hold on +chpos = calcWavelengthPlan(plotJob.ch, plotJob.channelspacing, 1310); +xline(chpos,'LineWidth',2,'Alpha',0.4,'HandleVisibility','off'); + +chpos = calcWavelengthPlan(plotJob.ch, plotJob.channelspacing, chpos(4)); +xline(chpos,'LineWidth',2,'LineStyle','--','Alpha',0.1,'HandleVisibility','off'); + +title(['N=',num2str(plotJob.ch),' $\Delta f_{\mathrm{ch}}$= ',num2str(plotJob.channelspacing*1e-9),' GHz'],'FontSize',10,'Interpreter','latex'); + + + + +end + + + diff --git a/Classes/Warehouse_class/functions/fwm_plots/automate_PTL_plot_new.m b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/automate_PTL_plot_new.m similarity index 100% rename from Classes/Warehouse_class/functions/fwm_plots/automate_PTL_plot_new.m rename to Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/automate_PTL_plot_new.m diff --git a/Classes/Warehouse_class/functions/fwm_plots/dispersion_only.m b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/dispersion_only.m similarity index 96% rename from Classes/Warehouse_class/functions/fwm_plots/dispersion_only.m rename to Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/dispersion_only.m index a0e8a98..47e5566 100644 --- a/Classes/Warehouse_class/functions/fwm_plots/dispersion_only.m +++ b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/dispersion_only.m @@ -1,83 +1,83 @@ -%automate plots -[file, path] = uigetfile("C:\Users\Silas\Documents\MATLAB\Datensätze\Raw_Cluster_Simulations\"); -wh = load([path filesep file]); -wh = wh.wh; - -plotJob = struct(); -width = 350; -height = 200; -plotJob.Position = [100 100 width 100+height]; -cols = cbrewer2("paired",12); -plotJob.color = cols(1,:); -plotJob.l = 1; -plotJob.ch = 1; - -plotJob.sgm = 1; -plotJob.pol = "copolarized"; -plotJob.p_in = 3; -plotJob.gamma = 0.0023; -plotJob.pmd = 0.1; -plotJob.channelspacing = 400e9; -plotJob.randzdw = 0; - - -plotJob.plot_ber_curve = 1; -plotJob.plot_3dber_curve = 0; -plotJob.plot_violin = 0; -plotJob.plot_wavelength_sweep = 0; -plotJob.plot_wavelength_sweep_failure_rate = 0; - - -plotJob.dataStatArg = 'Lineplot with quartiles'; -plotJob.plotTypeArg = 'Lines'; -plotJob.displayname = 'a'; -plotJob.title = 'title'; -plotJob.figName = '1 Chann__'; -plotJob.xAxisLabel = 'ROP per Channel in dBm'; -plotJob.yAxisLabel = 'BER'; - - -plotJob.d = 0; - -xAxis = wh.parameter.p_out.values; -D = wh.parameter.dispersion.values; - -figure() -ber_ = []; -for d_ = 0:39 - if d_ == 0 - plotJob.sgm = 0; - ber_(d_+1,:) = wh.getStoValue('ber',plotJob.l,d_,plotJob.sgm,string(plotJob.pol),plotJob.p_in,xAxis,plotJob.pmd,plotJob.gamma,1,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw)'; - else - plotJob.sgm = 1; - ber_(d_+1,:) = wh.getStoValue('ber',plotJob.l,d_,plotJob.sgm,string(plotJob.pol),plotJob.p_in,xAxis,plotJob.pmd,plotJob.gamma,1,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw)'; - end - hold on - plot(xAxis,ber_(d_+1,:)) - set(gca,'yscale','log'); -end -yline(3.8e-3); - - -hdfec = 3.8e-3.*ones(size(xAxis)); -for i = 1:size(ber_,1) - ber_series = ber_(i,:); - a = InterX([hdfec(:)';xAxis],[ber_series;xAxis]); - cross(i) = a(2); -end - -col = cbrewer2('Paired',8); -figure() -plot(D,cross,'Marker','o','MarkerSize',5,'MarkerEdgeColor',[1,1,1],'MarkerFaceColor',col(2,:),'Color',col(1,:),'LineWidth',1); -grid minor -xlabel('Accumulated Dispersion') -ylabel('Required ROP to reach FEC limit in dB') -line([D(16),D(16)],[-10,cross(16)],'linestyle','--') -line([0,D(16)],[cross(16),cross(16)],'linestyle','--') - -line([D(29),D(29)],[-10,cross(29)],'linestyle','--') -line([0,D(29)],[cross(29),cross(29)],'linestyle','--') - - - - +%automate plots +[file, path] = uigetfile("C:\Users\Silas\Documents\MATLAB\Datensätze\Raw_Cluster_Simulations\"); +wh = load([path filesep file]); +wh = wh.wh; + +plotJob = struct(); +width = 350; +height = 200; +plotJob.Position = [100 100 width 100+height]; +cols = cbrewer2("paired",12); +plotJob.color = cols(1,:); +plotJob.l = 1; +plotJob.ch = 1; + +plotJob.sgm = 1; +plotJob.pol = "copolarized"; +plotJob.p_in = 3; +plotJob.gamma = 0.0023; +plotJob.pmd = 0.1; +plotJob.channelspacing = 400e9; +plotJob.randzdw = 0; + + +plotJob.plot_ber_curve = 1; +plotJob.plot_3dber_curve = 0; +plotJob.plot_violin = 0; +plotJob.plot_wavelength_sweep = 0; +plotJob.plot_wavelength_sweep_failure_rate = 0; + + +plotJob.dataStatArg = 'Lineplot with quartiles'; +plotJob.plotTypeArg = 'Lines'; +plotJob.displayname = 'a'; +plotJob.title = 'title'; +plotJob.figName = '1 Chann__'; +plotJob.xAxisLabel = 'ROP per Channel in dBm'; +plotJob.yAxisLabel = 'BER'; + + +plotJob.d = 0; + +xAxis = wh.parameter.p_out.values; +D = wh.parameter.dispersion.values; + +figure() +ber_ = []; +for d_ = 0:39 + if d_ == 0 + plotJob.sgm = 0; + ber_(d_+1,:) = wh.getStoValue('ber',plotJob.l,d_,plotJob.sgm,string(plotJob.pol),plotJob.p_in,xAxis,plotJob.pmd,plotJob.gamma,1,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw)'; + else + plotJob.sgm = 1; + ber_(d_+1,:) = wh.getStoValue('ber',plotJob.l,d_,plotJob.sgm,string(plotJob.pol),plotJob.p_in,xAxis,plotJob.pmd,plotJob.gamma,1,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw)'; + end + hold on + plot(xAxis,ber_(d_+1,:)) + set(gca,'yscale','log'); +end +yline(3.8e-3); + + +hdfec = 3.8e-3.*ones(size(xAxis)); +for i = 1:size(ber_,1) + ber_series = ber_(i,:); + a = InterX([hdfec(:)';xAxis],[ber_series;xAxis]); + cross(i) = a(2); +end + +col = cbrewer2('Paired',8); +figure() +plot(D,cross,'Marker','o','MarkerSize',5,'MarkerEdgeColor',[1,1,1],'MarkerFaceColor',col(2,:),'Color',col(1,:),'LineWidth',1); +grid minor +xlabel('Accumulated Dispersion') +ylabel('Required ROP to reach FEC limit in dB') +line([D(16),D(16)],[-10,cross(16)],'linestyle','--') +line([0,D(16)],[cross(16),cross(16)],'linestyle','--') + +line([D(29),D(29)],[-10,cross(29)],'linestyle','--') +line([0,D(29)],[cross(29),cross(29)],'linestyle','--') + + + + diff --git a/Classes/Warehouse_class/functions/fwm_plots/dispersion_validation_miniskript.m b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/dispersion_validation_miniskript.m similarity index 96% rename from Classes/Warehouse_class/functions/fwm_plots/dispersion_validation_miniskript.m rename to Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/dispersion_validation_miniskript.m index 802db0a..e0d6843 100644 --- a/Classes/Warehouse_class/functions/fwm_plots/dispersion_validation_miniskript.m +++ b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/dispersion_validation_miniskript.m @@ -1,52 +1,52 @@ - -wh = load("C:\Users\Silas\Documents\MATLAB\Datensätze\Raw_Cluster_Simulations\session_dispersion_validation\wh_with_variation.mat"); -wh = wh.wh; - -lambda = 1295; - -figure(3) -plot(xAxis,getber(wh,lambda),'DisplayName',['w:', num2str(lambda), 'variation']); -yline(3.8e-3,'HandleVisibility','off'); -legend -set(gca,'yscale','log'); -grid(gca,'on'); -grid(gca,'minor'); -grid minor -fontsize(gca,8,"points") -fig.Units = "centimeters"; -fig.Position = [2 2 8.5 7]; -set(gca,'TickLabelInterpreter','latex') -ylim([1e-5,0.5]); -xlim([min(xAxis),-3]); - -wh = load("C:\Users\Silas\Documents\MATLAB\Datensätze\Raw_Cluster_Simulations\session_dispersion_validation\wh_no_variation.mat"); -wh = wh.wh; - - -figure(3) -hold on -plot(xAxis,getber(wh,lambda),'DisplayName',['w:', num2str(lambda), 'no variation']); -yline(3.8e-3,'HandleVisibility','off'); -legend -set(gca,'yscale','log'); -grid(gca,'on'); -grid(gca,'minor'); -grid minor -fontsize(gca,8,"points") -fig.Units = "centimeters"; -fig.Position = [2 2 8.5 7]; -set(gca,'TickLabelInterpreter','latex') -ylim([1e-5,0.5]); -xlim([min(xAxis),-3]); - - -function ber = getber(wh,lambda) - realization = wh.parameter.realization.values(1:end); - xAxis = wh.parameter.p_out.values; - ber = []; - for xl = 1:numel(xAxis) - p_out = xAxis(xl); - temp = wh.getStoValue('ber',10,0,0,"copolarized",3,p_out,0.1,0.0023,realization,1,lambda,400e9,1); - ber(xl) = mean(temp,'all'); - end + +wh = load("C:\Users\Silas\Documents\MATLAB\Datensätze\Raw_Cluster_Simulations\session_dispersion_validation\wh_with_variation.mat"); +wh = wh.wh; + +lambda = 1295; + +figure(3) +plot(xAxis,getber(wh,lambda),'DisplayName',['w:', num2str(lambda), 'variation']); +yline(3.8e-3,'HandleVisibility','off'); +legend +set(gca,'yscale','log'); +grid(gca,'on'); +grid(gca,'minor'); +grid minor +fontsize(gca,8,"points") +fig.Units = "centimeters"; +fig.Position = [2 2 8.5 7]; +set(gca,'TickLabelInterpreter','latex') +ylim([1e-5,0.5]); +xlim([min(xAxis),-3]); + +wh = load("C:\Users\Silas\Documents\MATLAB\Datensätze\Raw_Cluster_Simulations\session_dispersion_validation\wh_no_variation.mat"); +wh = wh.wh; + + +figure(3) +hold on +plot(xAxis,getber(wh,lambda),'DisplayName',['w:', num2str(lambda), 'no variation']); +yline(3.8e-3,'HandleVisibility','off'); +legend +set(gca,'yscale','log'); +grid(gca,'on'); +grid(gca,'minor'); +grid minor +fontsize(gca,8,"points") +fig.Units = "centimeters"; +fig.Position = [2 2 8.5 7]; +set(gca,'TickLabelInterpreter','latex') +ylim([1e-5,0.5]); +xlim([min(xAxis),-3]); + + +function ber = getber(wh,lambda) + realization = wh.parameter.realization.values(1:end); + xAxis = wh.parameter.p_out.values; + ber = []; + for xl = 1:numel(xAxis) + p_out = xAxis(xl); + temp = wh.getStoValue('ber',10,0,0,"copolarized",3,p_out,0.1,0.0023,realization,1,lambda,400e9,1); + ber(xl) = mean(temp,'all'); + end end \ No newline at end of file diff --git a/Classes/Warehouse_class/functions/fwm_plots/generatePlots.m b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/generatePlots.m similarity index 96% rename from Classes/Warehouse_class/functions/fwm_plots/generatePlots.m rename to Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/generatePlots.m index 2e720ff..911b79e 100644 --- a/Classes/Warehouse_class/functions/fwm_plots/generatePlots.m +++ b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/generatePlots.m @@ -1,61 +1,61 @@ -function generatePlots(wh,plotJob) - -% 0) Test for valid query: -p_out = wh.parameter.p_out.values(1); -realization = 9; - - -if 1 %~isempty(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310)) - % test violin - - baseName = plotJob.figName; - - width = 350; - height = 200; - s = 100; - e = 100; - - if plotJob.plot_ber_curve - plotJob.Position = [100 100 width e+height]; - plotJob.figName = [baseName, ' zdwvsber']; - plotCurve(wh, plotJob); - end - - if plotJob.plot_3dber_curve - plotJob.Position = [100 100 width e+height]; - plotJob.figName = [baseName, ' zdwvsber']; - plot3dCurve(wh, plotJob); - end - - if plotJob.plot_wavelength_sweep - plotJob.Position = [100 100 width e+height]; - plotJob.figName = [baseName, ' zdwvsber']; - plotBerVsZDW(wh, plotJob); - end - - if plotJob.plot_wavelength_sweep_failure_rate - plotJob.Position = [100 100 width e+height]; - plotJob.figName = [baseName, ' zdwvsber']; - plotBerVsZdwFailureRate(wh, plotJob); - end - - if plotJob.plot_violin - plotJob.Position = [s+width 100 width e+height]; - plotJob.figName = [baseName, ' violin']; - plotViolin(wh, plotJob); - end - - - if 0 - %2) plotHistogram - plotJob.Position = [s+2*width 100 width e+height]; - plotJob.figName = [baseName, ' FEC crossing']; - plotHistogram(wh,plotJob) - end - - -else - warndlg('The requested Datapoint is not available... This can occur for some edgecase constellations... ') -end - +function generatePlots(wh,plotJob) + +% 0) Test for valid query: +p_out = wh.parameter.p_out.values(1); +realization = 9; + + +if 1 %~isempty(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310)) + % test violin + + baseName = plotJob.figName; + + width = 350; + height = 200; + s = 100; + e = 100; + + if plotJob.plot_ber_curve + plotJob.Position = [100 100 width e+height]; + plotJob.figName = [baseName, ' zdwvsber']; + plotCurve(wh, plotJob); + end + + if plotJob.plot_3dber_curve + plotJob.Position = [100 100 width e+height]; + plotJob.figName = [baseName, ' zdwvsber']; + plot3dCurve(wh, plotJob); + end + + if plotJob.plot_wavelength_sweep + plotJob.Position = [100 100 width e+height]; + plotJob.figName = [baseName, ' zdwvsber']; + plotBerVsZDW(wh, plotJob); + end + + if plotJob.plot_wavelength_sweep_failure_rate + plotJob.Position = [100 100 width e+height]; + plotJob.figName = [baseName, ' zdwvsber']; + plotBerVsZdwFailureRate(wh, plotJob); + end + + if plotJob.plot_violin + plotJob.Position = [s+width 100 width e+height]; + plotJob.figName = [baseName, ' violin']; + plotViolin(wh, plotJob); + end + + + if 0 + %2) plotHistogram + plotJob.Position = [s+2*width 100 width e+height]; + plotJob.figName = [baseName, ' FEC crossing']; + plotHistogram(wh,plotJob) + end + + +else + warndlg('The requested Datapoint is not available... This can occur for some edgecase constellations... ') +end + end \ No newline at end of file diff --git a/Classes/Warehouse_class/functions/fwm_plots/plot3dCurve.m b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plot3dCurve.m similarity index 97% rename from Classes/Warehouse_class/functions/fwm_plots/plot3dCurve.m rename to Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plot3dCurve.m index 37d8fcf..5929aa6 100644 --- a/Classes/Warehouse_class/functions/fwm_plots/plot3dCurve.m +++ b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plot3dCurve.m @@ -1,248 +1,248 @@ -function plotCurve(wh,plotJob) -%PLOTCURVE Summary of this function goes here -% Detailed explanation goes here - -fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName); - -if isvalid(fig) - figure(fig) - fig = get(fig); - AxesMain = fig.CurrentAxes; - hold on -else - fig = figure('name',char(plotJob.figName)); - AxesMain = gca; - hold on -end - -col = plotJob.color; - -% we want to fetch all realizations -if plotJob.pmd == 0 - realization = 499; - % realization = 0:7; -else - realization = wh.parameter.realization.values(1:end); -end -realization = wh.parameter.realization.values(1:end); -% get all xAxis values -xAxis = wh.parameter.p_out.values; - -% Fetch Data from Warehouse -for xl = 1:numel(xAxis) - p_out = xAxis(xl); - if string(plotJob.dataStatArg) == "Worst" - temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); - temp = removeZeros(temp); - ber(xl) = max(temp,[],'all'); - linew = 1.0; - markersz = 3; - linestyle = '-'; - elseif string(plotJob.dataStatArg) == "AVG" - temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); - temp = removeZeros(temp); - ber(xl) = mean(temp,'all'); - linew = 1.0; - markersz = 3; - linestyle = '-'; - elseif string(plotJob.dataStatArg) == "Best" - temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); - temp = removeZeros(temp); - ber(xl) = min(temp,[],'all'); - linew = 1.0; - markersz = 3; - linestyle = '-'; - - elseif string(plotJob.dataStatArg) == "All Channels; mean(PMD Realizations)" - temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); - temp = removeZeros(temp); - - ber(:,xl) = mean(temp,1,"omitnan").'; - - linew = 1; - markersz = 3; - linestyle = '--'; - - elseif string(plotJob.dataStatArg) == "Lineplot with quartiles" - - temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); - temp = removeZeros(temp); - ber(xl) = mean(temp,"all","omitnan").'; - - - upperq(xl) = quantile(temp,0.9,"all"); - lowerq(xl) = quantile(temp,0.1,"all"); - - if lowerq(xl) == 0 - lowerq(xl) = lowerq(xl-1); - end - % upperq(xl) = 0.5*std(tmp,1,'all','omitnan'); - % lowerq(xl) = 0.5*std(tmp,1,'all','omitnan'); - - % upperq(xl) = max(dataNoNans); - % lowerq(xl) = min(dataNoNans); - - % upperq(xl) = mean(tmp,"all","omitnan") + 1.96 * (std(tmp,1,'all','omitnan')/sqrt(numel(tmp))); - % lowerq(xl) = mean(tmp,"all","omitnan") - 1.96 * (std(tmp,1,'all','omitnan')/sqrt(numel(tmp))); - - linew = 1; - markersz = 1; - linestyle = '-'; - - elseif string(plotJob.dataStatArg) == "All Channels ;All PMD Realizations" - - tmp = reshape(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw).',[],1); - ber(1:size(tmp,1),xl) = tmp; - - linew = 0.3; - markersz = 2; - linestyle = ':'; - end -end - -xAxis = xAxis; - -% Plot Data -if string(plotJob.plotTypeArg) == "Scatter" - for rlz = 1:size(ber,1) - - if rlz < size(ber,1) - scatter(xAxis,ber(rlz,:),markersz,'MarkerEdgeColor',col,'MarkerFaceColor',col,'Parent', AxesMain(1),'HandleVisibility','off'); - else - scatter(xAxis,ber(rlz,:),markersz,'MarkerEdgeColor',col,'MarkerFaceColor',col,'Parent', AxesMain(1),'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]); - end - - end - -elseif string(plotJob.plotTypeArg) == "Lines" - - % if ~anynan(ber) - % [xAxis,ber] = interpCurve(xAxis, ber); - % end - - for rlz = 1:size(ber,1) -% - if (string(plotJob.dataStatArg) == "All Channels ;All PMD Realizations")||(string(plotJob.dataStatArg) == "All Channels; mean(PMD Realizations)") - ch = mod(rlz,plotJob.ch); - if ch == 0; ch = plotJob.ch; end - else - ch = plotJob.dataStatArg; - end - - if rlz <= size(ber,1) - - - s = plot3(xAxis,repmat(ch,1,numel(xAxis)),ber(rlz,:),linestyle,'Marker',"o",'MarkerSize',markersz,'MarkerFaceColor',plotJob.color,'LineWidth',linew,'Color',col,'Parent', AxesMain,'HandleVisibility','off'); - - s.DataTipTemplate.Interpreter = "latex"; - s.DataTipTemplate.DataTipRows(1).Label = "Ch: "; - s.DataTipTemplate.DataTipRows(1).Value = repmat(ch,size(ber)); - s.DataTipTemplate.DataTipRows(1); - s.DataTipTemplate.DataTipRows(2) = []; - - - else - - if string(plotJob.dataStatArg) == "Lineplot with quartiles" - [hl,hp] = boundedline(xAxis,ber(rlz,:),([(ber(rlz,:)-lowerq(rlz,:));upperq(rlz,:)-ber(rlz,:)]'),'-*', 'alpha','Color',col,'transparency', 0.2); - hp.LineWidth = 1.2; - - ho = outlinebounds(hl,hp); - set(ho, 'linestyle', ':', 'color', col); - else - - s = plot(xAxis,ber(rlz,:),linestyle,'Marker',"o",'MarkerFaceColor',col,'MarkerSize',markersz,'LineWidth',linew,'Color',col,'Parent', AxesMain,'DisplayName',[plotJob.displayname]); - - s.DataTipTemplate.Interpreter = "latex"; - s.DataTipTemplate.DataTipRows(1).Label = "Ch: "; - s.DataTipTemplate.DataTipRows(1).Value = repmat(string(ch),size(ber)); - s.DataTipTemplate.DataTipRows(1) - s.DataTipTemplate.DataTipRows(2) = []; - end - - end - - end -end - -% Draw FEC Threshold Line -%get x data of first children: -%get all linear Values -if 0 - linear = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,wh.parameter.p_out.values,0,0,499,"symmetric"); - linear = mean(linear,2); - lincurve = findall(AxesMain, 'Type', 'line','DisplayName','Linear Baseline'); - % - if isempty(lincurve) - xdata = AxesMain.Children(1).XData; - hdfec = 3.8e-3.*ones(size(xdata)); - plot(xdata,linear,'-','Marker',"o",'MarkerSize',3,'LineWidth',4,'Color',[0.6400 0.6400 0.6400],'MarkerFaceColor',[0.6400 0.6400 0.6400],'Parent', AxesMain,'DisplayName','Linear Baseline'); - %h = get(gca,'Children'); - %set(gca,'Children',[h(2) h(1)]) - end -end - -feccurve = findall(AxesMain, 'Type', 'line','DisplayName','FEC $3.8*10^{-3}$'); -% -if isempty(feccurve) - xdata = xAxis; - hdfec = 3.8e-3.*ones(size(xdata)); - for ch = 1:plotJob.ch - plot3(xdata,repmat(ch,1,numel(xAxis)),hdfec,':','MarkerSize',4,'Color','black','MarkerFaceColor','black','LineWidth',0.5,'Parent', AxesMain,'DisplayName','FEC $3.8*10^{-3}$','HandleVisibility','off'); - end - %h = get(gca,'Children'); - %set(gca,'Children',[h(2) h(1)]) -end - -% Figure Settings -%title(AxesMain,plotJob.title,"Interpreter","none"); - -xlabel(AxesMain,plotJob.xAxisLabel,"Interpreter","none"); - -ylabel(AxesMain,plotJob.yAxisLabel,"Interpreter","none"); - -set(AxesMain,'zscale','log'); - -grid(AxesMain,'on'); - -grid(AxesMain,'minor'); - -grid minor - -view(AxesMain,[42.0619302949062 23.4176470588235]); -%legend(AxesMain); - -fontsize(AxesMain,8,"points") -fontname(AxesMain,"Arial") - -fig.Position = plotJob.Position; -fig.Units = "centimeters"; -fig.Position = [2 2 8.5 7]; - -set(AxesMain,'TickLabelInterpreter','none') - -set(AxesMain.Legend,'Interpreter','none') -% set(gcf,'Units','centimeters') -% set(gcf,'Position',[2 2 9 4.5]) - -zlim([1e-4,0.3]); - -xlim([min(xAxis),-3]); - - -annotation('textbox', [0.125, 0.32, 0.1, 0.1], 'String', "FEC 3.8e-3","LineStyle","none","FontSize",8,"FontUnits","points") - - -hold off - - -end - - -function vec = removeZeros(vec) - % Find rows that contain only zeros - rows_to_remove = all(vec == 0, 2); - - % Remove rows with only zeros - vec(rows_to_remove, :) = []; -end +function plotCurve(wh,plotJob) +%PLOTCURVE Summary of this function goes here +% Detailed explanation goes here + +fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName); + +if isvalid(fig) + figure(fig) + fig = get(fig); + AxesMain = fig.CurrentAxes; + hold on +else + fig = figure('name',char(plotJob.figName)); + AxesMain = gca; + hold on +end + +col = plotJob.color; + +% we want to fetch all realizations +if plotJob.pmd == 0 + realization = 499; + % realization = 0:7; +else + realization = wh.parameter.realization.values(1:end); +end +realization = wh.parameter.realization.values(1:end); +% get all xAxis values +xAxis = wh.parameter.p_out.values; + +% Fetch Data from Warehouse +for xl = 1:numel(xAxis) + p_out = xAxis(xl); + if string(plotJob.dataStatArg) == "Worst" + temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); + temp = removeZeros(temp); + ber(xl) = max(temp,[],'all'); + linew = 1.0; + markersz = 3; + linestyle = '-'; + elseif string(plotJob.dataStatArg) == "AVG" + temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); + temp = removeZeros(temp); + ber(xl) = mean(temp,'all'); + linew = 1.0; + markersz = 3; + linestyle = '-'; + elseif string(plotJob.dataStatArg) == "Best" + temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); + temp = removeZeros(temp); + ber(xl) = min(temp,[],'all'); + linew = 1.0; + markersz = 3; + linestyle = '-'; + + elseif string(plotJob.dataStatArg) == "All Channels; mean(PMD Realizations)" + temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); + temp = removeZeros(temp); + + ber(:,xl) = mean(temp,1,"omitnan").'; + + linew = 1; + markersz = 3; + linestyle = '--'; + + elseif string(plotJob.dataStatArg) == "Lineplot with quartiles" + + temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); + temp = removeZeros(temp); + ber(xl) = mean(temp,"all","omitnan").'; + + + upperq(xl) = quantile(temp,0.9,"all"); + lowerq(xl) = quantile(temp,0.1,"all"); + + if lowerq(xl) == 0 + lowerq(xl) = lowerq(xl-1); + end + % upperq(xl) = 0.5*std(tmp,1,'all','omitnan'); + % lowerq(xl) = 0.5*std(tmp,1,'all','omitnan'); + + % upperq(xl) = max(dataNoNans); + % lowerq(xl) = min(dataNoNans); + + % upperq(xl) = mean(tmp,"all","omitnan") + 1.96 * (std(tmp,1,'all','omitnan')/sqrt(numel(tmp))); + % lowerq(xl) = mean(tmp,"all","omitnan") - 1.96 * (std(tmp,1,'all','omitnan')/sqrt(numel(tmp))); + + linew = 1; + markersz = 1; + linestyle = '-'; + + elseif string(plotJob.dataStatArg) == "All Channels ;All PMD Realizations" + + tmp = reshape(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw).',[],1); + ber(1:size(tmp,1),xl) = tmp; + + linew = 0.3; + markersz = 2; + linestyle = ':'; + end +end + +xAxis = xAxis; + +% Plot Data +if string(plotJob.plotTypeArg) == "Scatter" + for rlz = 1:size(ber,1) + + if rlz < size(ber,1) + scatter(xAxis,ber(rlz,:),markersz,'MarkerEdgeColor',col,'MarkerFaceColor',col,'Parent', AxesMain(1),'HandleVisibility','off'); + else + scatter(xAxis,ber(rlz,:),markersz,'MarkerEdgeColor',col,'MarkerFaceColor',col,'Parent', AxesMain(1),'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]); + end + + end + +elseif string(plotJob.plotTypeArg) == "Lines" + + % if ~anynan(ber) + % [xAxis,ber] = interpCurve(xAxis, ber); + % end + + for rlz = 1:size(ber,1) +% + if (string(plotJob.dataStatArg) == "All Channels ;All PMD Realizations")||(string(plotJob.dataStatArg) == "All Channels; mean(PMD Realizations)") + ch = mod(rlz,plotJob.ch); + if ch == 0; ch = plotJob.ch; end + else + ch = plotJob.dataStatArg; + end + + if rlz <= size(ber,1) + + + s = plot3(xAxis,repmat(ch,1,numel(xAxis)),ber(rlz,:),linestyle,'Marker',"o",'MarkerSize',markersz,'MarkerFaceColor',plotJob.color,'LineWidth',linew,'Color',col,'Parent', AxesMain,'HandleVisibility','off'); + + s.DataTipTemplate.Interpreter = "latex"; + s.DataTipTemplate.DataTipRows(1).Label = "Ch: "; + s.DataTipTemplate.DataTipRows(1).Value = repmat(ch,size(ber)); + s.DataTipTemplate.DataTipRows(1); + s.DataTipTemplate.DataTipRows(2) = []; + + + else + + if string(plotJob.dataStatArg) == "Lineplot with quartiles" + [hl,hp] = boundedline(xAxis,ber(rlz,:),([(ber(rlz,:)-lowerq(rlz,:));upperq(rlz,:)-ber(rlz,:)]'),'-*', 'alpha','Color',col,'transparency', 0.2); + hp.LineWidth = 1.2; + + ho = outlinebounds(hl,hp); + set(ho, 'linestyle', ':', 'color', col); + else + + s = plot(xAxis,ber(rlz,:),linestyle,'Marker',"o",'MarkerFaceColor',col,'MarkerSize',markersz,'LineWidth',linew,'Color',col,'Parent', AxesMain,'DisplayName',[plotJob.displayname]); + + s.DataTipTemplate.Interpreter = "latex"; + s.DataTipTemplate.DataTipRows(1).Label = "Ch: "; + s.DataTipTemplate.DataTipRows(1).Value = repmat(string(ch),size(ber)); + s.DataTipTemplate.DataTipRows(1) + s.DataTipTemplate.DataTipRows(2) = []; + end + + end + + end +end + +% Draw FEC Threshold Line +%get x data of first children: +%get all linear Values +if 0 + linear = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,wh.parameter.p_out.values,0,0,499,"symmetric"); + linear = mean(linear,2); + lincurve = findall(AxesMain, 'Type', 'line','DisplayName','Linear Baseline'); + % + if isempty(lincurve) + xdata = AxesMain.Children(1).XData; + hdfec = 3.8e-3.*ones(size(xdata)); + plot(xdata,linear,'-','Marker',"o",'MarkerSize',3,'LineWidth',4,'Color',[0.6400 0.6400 0.6400],'MarkerFaceColor',[0.6400 0.6400 0.6400],'Parent', AxesMain,'DisplayName','Linear Baseline'); + %h = get(gca,'Children'); + %set(gca,'Children',[h(2) h(1)]) + end +end + +feccurve = findall(AxesMain, 'Type', 'line','DisplayName','FEC $3.8*10^{-3}$'); +% +if isempty(feccurve) + xdata = xAxis; + hdfec = 3.8e-3.*ones(size(xdata)); + for ch = 1:plotJob.ch + plot3(xdata,repmat(ch,1,numel(xAxis)),hdfec,':','MarkerSize',4,'Color','black','MarkerFaceColor','black','LineWidth',0.5,'Parent', AxesMain,'DisplayName','FEC $3.8*10^{-3}$','HandleVisibility','off'); + end + %h = get(gca,'Children'); + %set(gca,'Children',[h(2) h(1)]) +end + +% Figure Settings +%title(AxesMain,plotJob.title,"Interpreter","none"); + +xlabel(AxesMain,plotJob.xAxisLabel,"Interpreter","none"); + +ylabel(AxesMain,plotJob.yAxisLabel,"Interpreter","none"); + +set(AxesMain,'zscale','log'); + +grid(AxesMain,'on'); + +grid(AxesMain,'minor'); + +grid minor + +view(AxesMain,[42.0619302949062 23.4176470588235]); +%legend(AxesMain); + +fontsize(AxesMain,8,"points") +fontname(AxesMain,"Arial") + +fig.Position = plotJob.Position; +fig.Units = "centimeters"; +fig.Position = [2 2 8.5 7]; + +set(AxesMain,'TickLabelInterpreter','none') + +set(AxesMain.Legend,'Interpreter','none') +% set(gcf,'Units','centimeters') +% set(gcf,'Position',[2 2 9 4.5]) + +zlim([1e-4,0.3]); + +xlim([min(xAxis),-3]); + + +annotation('textbox', [0.125, 0.32, 0.1, 0.1], 'String', "FEC 3.8e-3","LineStyle","none","FontSize",8,"FontUnits","points") + + +hold off + + +end + + +function vec = removeZeros(vec) + % Find rows that contain only zeros + rows_to_remove = all(vec == 0, 2); + + % Remove rows with only zeros + vec(rows_to_remove, :) = []; +end diff --git a/Classes/Warehouse_class/functions/fwm_plots/plotBerVsZDW.m b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plotBerVsZDW.m similarity index 97% rename from Classes/Warehouse_class/functions/fwm_plots/plotBerVsZDW.m rename to Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plotBerVsZDW.m index bebc5b5..d0d5f06 100644 --- a/Classes/Warehouse_class/functions/fwm_plots/plotBerVsZDW.m +++ b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plotBerVsZDW.m @@ -1,300 +1,300 @@ -function plotBerVsZDW(wh,plotJob) - - fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName); - - if isvalid(fig) - figure(fig) - fig = get(fig); - AxesMain = fig.CurrentAxes; - hold on - else - fig = figure('name',char(plotJob.figName)); - AxesMain = gca; - hold on - end - - - col = plotJob.color; - - % we want to fetch all realizations - realization = wh.parameter.realization.values(1:end); - - % get all xAxis values - xAxis = wh.parameter.p_out.values; - - % get all center wavelengths - wavelengths = wh.parameter.center_wavelength.values; - -% totber = NaN(numel(realization),1,numel(xAxis),numel(wavelengths)); -% ber = zeros(numel(realization),plotJob.ch,numel(xAxis),numel(wavelengths)); - - %get BER values for query - for w = 2:numel(wavelengths) - - for xl = 1:numel(xAxis) - - c_wavelen = wavelengths(w); - p_out = xAxis(xl); - - % dim1 : realiz; dim2: channels, dim3: rop, dim4, c_wavelength - temp = removeZeros(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,c_wavelen,plotJob.channelspacing,plotJob.randzdw)); - ber(1:size(temp,1),:,xl,w) = temp; - - end - end - - hdfec = 3.8e-3.*ones(size(xAxis)); - zdw_ = []; - zdw_chann = []; - zdw_tot = []; - cf_tot = []; - cf_ = []; - S = []; - Stot = []; - S_chann = []; - cf_chann = []; - - cnt = 0; - %get fec thresholds - %linear = squeeze(linear); - for c_wavelen = 1:size(ber,4) - for realiz = 1:size(ber,1) - for chann = 1:size(ber,2) - - %finde Schnittpunkt zwischen FEC und BER Kurve - temp_ber = squeeze(ber(realiz,chann,:,c_wavelen)).'; - if ~all(temp_ber == 0) - %nur wenn nicht alles nullen sind - crossing_ch = InterX([hdfec;xAxis],[temp_ber;xAxis]); - else - continue - end - - %Req. FEC Ergebnis einsortieren - if ~isempty(crossing_ch) - if crossing_ch(2) == 0 - print("d") - end - S(realiz,chann,c_wavelen) = crossing_ch(2); - else - S(realiz,chann,c_wavelen) = -1; - cnt = cnt +1; - end - - - end - end - end - - temp_max = -inf; - for i = 1:plotJob.ch - hold on - %S:: 1.dim: realiz; 2.dim: channel; 3.dim: center wavelength - %squeeze a channel: - temp_data = squeeze(S(:,i,:)); - - %remove realizations that have no entry (only zero) - temp_data = removeZeros(temp_data); - - %replace zeros with NAN (e.g. for the wavelengths that have missing realizations) - temp_data(temp_data==0) = NaN; - - %plot required ROP for channel and all realizations that cross the - %FEC limit - scatter(wavelengths,temp_data ,5,plotJob.color,'Marker','.'); - -% %plot mean per channel -% temp_mean = mean(temp_data,'omitnan'); -% hold on -% plot(wavelengths,temp_mean,'Marker','*'); - - %get max overall value - temp_max = max(temp_max,max(temp_data)); - end - - - - %plot mean overall - mean_overall = squeeze(mean(S,2)); - mean_overall(mean_overall==0) = NaN; - %mean_overall(mean_overall==-1) = NaN; - mean_overall=mean(mean_overall,1,'omitnan'); - plot(wavelengths,mean_overall,'Color',plotJob.color); - - %plot max overall - scatter(wavelengths,temp_max ,35,plotJob.color,'Marker','v'); - - - %plot channel positions - hold on - chpos = calcWavelengthPlan(plotJob.ch, 400e9, 1310); - xline(chpos,'LineWidth',2,'Alpha',0.2); - chpos = calcWavelengthPlan(plotJob.ch, 400e9, chpos(4)); - xline(chpos,'LineWidth',2,'Alpha',0.2); - - fig.Position = plotJob.Position; - - ylabel('Penalty in dB'); - xlabel('Wavelength in nm'); - - xlim([min(wavelengths),max(wavelengths) ]); - - grid minor; - set(gca, 'color', 'none'); - legend = []; - - fontsize(AxesMain,8,"points") - - fig.Position = plotJob.Position; - fig.Units = "centimeters"; - fig.Position = [2 2 8.5 7]; - - set(AxesMain,'TickLabelInterpreter','latex') - - set(AxesMain.Legend,'Interpreter','latex') - - - - - - - % - % - % - % - % - % distinct_cf = unique(cf_chann); - % - % for i = 1:length(distinct_cf) - % indices = find(cf_chann==distinct_cf(i)); - % cf(i) = distinct_cf(i); - % worst_fec_cross(i) = max(S_chann(indices)); - % avg_fec_cross(i) = mean(S_chann(indices)); - % end - % - % avg_fec_cross = smooth(avg_fec_cross,5); - % - % figure(224) - % hold on - % scatter(cf_,S,10.*abs(S-mean(S)).*ones(size(S)),'DisplayName',['AVG'],'MarkerEdgeColor',col,'MarkerFaceColor',col,'Marker','.'); - % hold on - % scatter(cf(2:end),worst_fec_cross(2:end),15,'DisplayName',['Worst'],'MarkerEdgeColor',col,'MarkerFaceColor',col,'Marker','.','HandleVisibility','off'); - % plot(cf(2:end),avg_fec_cross(2:end),'DisplayName',['AVG'],'LineWidth',1,'LineStyle','-','Color',col,'Marker','none','MarkerFaceColor',col,'MarkerSize',2); - % plot(cf(2:end),worst_fec_cross(2:end),'DisplayName',['AVG'],'LineWidth',0.5,'LineStyle','-','Color',col,'Marker','none','MarkerFaceColor',col,'MarkerSize',2); - % ghzgrid = hz2nm(nm2hz(1310)+[0:1:20].*400e9); - % set(gca,'xtick',sort(ghzgrid)) - % xlim([min(cf(cf~=0)), 1310.1]); - % - % - % % With matlab internal errorbar function... - % figure(221) - % %plot(cf,avg_fec_cross,'DisplayName',['AVG'],'LineWidth',1,'Color',col,'Marker','none','MarkerFaceColor',col,'MarkerSize',2); - % hold on - % %plot(cf_tot,min(S_chann(1:length(cf_tot),:),[],2),'DisplayName',['AVG'],'LineWidth',1,'LineStyle',':','Color',col,'Marker','^','MarkerFaceColor',col,'MarkerSize',2); - % plot(cf,worst_fec_cross,'DisplayName',['AVG'],'LineWidth',2,'LineStyle','-','Color',col,'Marker','none','MarkerFaceColor',col,'MarkerSize',2); - % ghzgrid = hz2nm(nm2hz(1310)+[0:1:20].*400e9); - % set(gca,'xtick',sort(ghzgrid)) - % xlim([1302, 1310.1]); - % xline(ghzgrid,'LineStyle',':','Color',[.7 .7 .7]); - - - %with - % Stot = movmean(Stot,5); - % figure(222) - % [hl,hp] = boundedline(cf_tot,Stot,[(Stot'-min(S_chann(1:length(cf_tot),:),[],2)),(max(S_chann(1:length(cf_tot),:),[],2)-Stot')], 'alpha','Color',col,'transparency', 0.05); - % ho = outlinebounds(hl,hp); - % set(ho, 'linestyle', ':', 'color', col, 'marker', '.','linewidth',0.5); - % hold on - % - % ghzgrid = hz2nm(nm2hz(1310)+[0:1:12].*400e9); - % xline(ghzgrid); - - - - - %plot the total ber - - % %figure(22); - % hold on; - % b= movmean(Stot,3); - % plot(AxesMain,cf_tot,b,'LineWidth',2,'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname],'Color',col,'Marker','o'); - % hold on - - - - - - %scatter(AxesMain,zdw_,S,'Marker','+','MarkerEdgeColor',col,'MarkerFaceAlpha',0.4,'MarkerEdgeAlpha',0.4,'LineWidth',0.5,'Parent', AxesMain(1),'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]); - %ylim(AxesMain,[-9.3 -7]); - - % for i = 1:numel(chp) - % hold on - % xline(AxesMain,chp(i),'Color',colr(i,:),'DisplayName',['CH: ', num2str(i)],'LineWidth',1.5); - % hold off - % end - - - - - % - % a = movmean(sortrows([zdw_; S]'),10,'Endpoints','discard'); - % - % sorted = sortrows([zdw_; S]'); - % figure(2) - % scatter(sorted(:,1),sorted(:,2)) - % - % ber_sorted = sort(S); - % mean(ber_sorted); - % std(ber_sorted); - % z1 = []; - % penalty = mean(ber_sorted):0.01:mean(ber_sorted)+2; - % for i = 1:length(penalty) - % l = penalty(i); - % if i == 1 - % z1 = [z1 sum(ber_sorted(1,:)l-0.01) / length(ber_sorted) ]; - % end - % - % end - % - % penalty_higherthan = 0.5; - % probability = sum(z1(find(penalty>mean(ber_sorted)+penalty_higherthan))); - % disp(['A penalty of more than 1dB has a probability of: ', num2str(probability)]); - % % - % stem(AxesMain,penalty,z1,"filled",'Marker','o','MarkerSize',2,'Color',col); - % - % - % [f1,x1]=ecdf(S(end,:)); - % %figure(23);plot(AxesMain,x1,f1,'r','LineWidth',3, 'Color',col); - % - % %plot(AxesMain,a(:,1),a(:,2),'Color',col+1,'Parent', AxesMain(1)); - % - % % histogram(AxesMain,S,1000,'EdgeColor','none','FaceAlpha',0.4); - % - % - % - % % - % %scatter(AxesMain,zdw_,S,'Marker','+','MarkerEdgeColor',col,'MarkerFaceAlpha',0.4,'MarkerEdgeAlpha',0.4,'LineWidth',0.5,'Parent', AxesMain(1),'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]); - % hold on - % %scatter(AxesMain,zdw_chann(:,1),mean(S_chann,2),'Marker','diamond','MarkerEdgeColor',col,'MarkerFaceAlpha',0.6,'LineWidth',7,'MarkerFaceColor',col,'Parent', AxesMain(1),'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]); - % hold off - % % - % % for rlz = 1:size(S,2) - % % zdwval = zdw_(rlz); - % % feccrossing = S(rlz); - % % scatter(AxesMain,zdwval,feccrossing,10,'MarkerEdgeColor',col,'MarkerFaceColor',col,'Parent', AxesMain(1),'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]); - % % end - % - % xline([1302.03471732576,1304.30061112288,1306.57440520904,1308.85614097425,1311.14586009814,1313.44360455251,1315.74941660391,1318.06333881618]); - - -end - -function vec = removeZeros(vec) - % Find rows that contain only zeros - rows_to_remove = all(vec == 0, 2); - - % Remove rows with only zeros - vec(rows_to_remove, :) = []; +function plotBerVsZDW(wh,plotJob) + + fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName); + + if isvalid(fig) + figure(fig) + fig = get(fig); + AxesMain = fig.CurrentAxes; + hold on + else + fig = figure('name',char(plotJob.figName)); + AxesMain = gca; + hold on + end + + + col = plotJob.color; + + % we want to fetch all realizations + realization = wh.parameter.realization.values(1:end); + + % get all xAxis values + xAxis = wh.parameter.p_out.values; + + % get all center wavelengths + wavelengths = wh.parameter.center_wavelength.values; + +% totber = NaN(numel(realization),1,numel(xAxis),numel(wavelengths)); +% ber = zeros(numel(realization),plotJob.ch,numel(xAxis),numel(wavelengths)); + + %get BER values for query + for w = 2:numel(wavelengths) + + for xl = 1:numel(xAxis) + + c_wavelen = wavelengths(w); + p_out = xAxis(xl); + + % dim1 : realiz; dim2: channels, dim3: rop, dim4, c_wavelength + temp = removeZeros(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,c_wavelen,plotJob.channelspacing,plotJob.randzdw)); + ber(1:size(temp,1),:,xl,w) = temp; + + end + end + + hdfec = 3.8e-3.*ones(size(xAxis)); + zdw_ = []; + zdw_chann = []; + zdw_tot = []; + cf_tot = []; + cf_ = []; + S = []; + Stot = []; + S_chann = []; + cf_chann = []; + + cnt = 0; + %get fec thresholds + %linear = squeeze(linear); + for c_wavelen = 1:size(ber,4) + for realiz = 1:size(ber,1) + for chann = 1:size(ber,2) + + %finde Schnittpunkt zwischen FEC und BER Kurve + temp_ber = squeeze(ber(realiz,chann,:,c_wavelen)).'; + if ~all(temp_ber == 0) + %nur wenn nicht alles nullen sind + crossing_ch = InterX([hdfec;xAxis],[temp_ber;xAxis]); + else + continue + end + + %Req. FEC Ergebnis einsortieren + if ~isempty(crossing_ch) + if crossing_ch(2) == 0 + print("d") + end + S(realiz,chann,c_wavelen) = crossing_ch(2); + else + S(realiz,chann,c_wavelen) = -1; + cnt = cnt +1; + end + + + end + end + end + + temp_max = -inf; + for i = 1:plotJob.ch + hold on + %S:: 1.dim: realiz; 2.dim: channel; 3.dim: center wavelength + %squeeze a channel: + temp_data = squeeze(S(:,i,:)); + + %remove realizations that have no entry (only zero) + temp_data = removeZeros(temp_data); + + %replace zeros with NAN (e.g. for the wavelengths that have missing realizations) + temp_data(temp_data==0) = NaN; + + %plot required ROP for channel and all realizations that cross the + %FEC limit + scatter(wavelengths,temp_data ,5,plotJob.color,'Marker','.'); + +% %plot mean per channel +% temp_mean = mean(temp_data,'omitnan'); +% hold on +% plot(wavelengths,temp_mean,'Marker','*'); + + %get max overall value + temp_max = max(temp_max,max(temp_data)); + end + + + + %plot mean overall + mean_overall = squeeze(mean(S,2)); + mean_overall(mean_overall==0) = NaN; + %mean_overall(mean_overall==-1) = NaN; + mean_overall=mean(mean_overall,1,'omitnan'); + plot(wavelengths,mean_overall,'Color',plotJob.color); + + %plot max overall + scatter(wavelengths,temp_max ,35,plotJob.color,'Marker','v'); + + + %plot channel positions + hold on + chpos = calcWavelengthPlan(plotJob.ch, 400e9, 1310); + xline(chpos,'LineWidth',2,'Alpha',0.2); + chpos = calcWavelengthPlan(plotJob.ch, 400e9, chpos(4)); + xline(chpos,'LineWidth',2,'Alpha',0.2); + + fig.Position = plotJob.Position; + + ylabel('Penalty in dB'); + xlabel('Wavelength in nm'); + + xlim([min(wavelengths),max(wavelengths) ]); + + grid minor; + set(gca, 'color', 'none'); + legend = []; + + fontsize(AxesMain,8,"points") + + fig.Position = plotJob.Position; + fig.Units = "centimeters"; + fig.Position = [2 2 8.5 7]; + + set(AxesMain,'TickLabelInterpreter','latex') + + set(AxesMain.Legend,'Interpreter','latex') + + + + + + + % + % + % + % + % + % distinct_cf = unique(cf_chann); + % + % for i = 1:length(distinct_cf) + % indices = find(cf_chann==distinct_cf(i)); + % cf(i) = distinct_cf(i); + % worst_fec_cross(i) = max(S_chann(indices)); + % avg_fec_cross(i) = mean(S_chann(indices)); + % end + % + % avg_fec_cross = smooth(avg_fec_cross,5); + % + % figure(224) + % hold on + % scatter(cf_,S,10.*abs(S-mean(S)).*ones(size(S)),'DisplayName',['AVG'],'MarkerEdgeColor',col,'MarkerFaceColor',col,'Marker','.'); + % hold on + % scatter(cf(2:end),worst_fec_cross(2:end),15,'DisplayName',['Worst'],'MarkerEdgeColor',col,'MarkerFaceColor',col,'Marker','.','HandleVisibility','off'); + % plot(cf(2:end),avg_fec_cross(2:end),'DisplayName',['AVG'],'LineWidth',1,'LineStyle','-','Color',col,'Marker','none','MarkerFaceColor',col,'MarkerSize',2); + % plot(cf(2:end),worst_fec_cross(2:end),'DisplayName',['AVG'],'LineWidth',0.5,'LineStyle','-','Color',col,'Marker','none','MarkerFaceColor',col,'MarkerSize',2); + % ghzgrid = hz2nm(nm2hz(1310)+[0:1:20].*400e9); + % set(gca,'xtick',sort(ghzgrid)) + % xlim([min(cf(cf~=0)), 1310.1]); + % + % + % % With matlab internal errorbar function... + % figure(221) + % %plot(cf,avg_fec_cross,'DisplayName',['AVG'],'LineWidth',1,'Color',col,'Marker','none','MarkerFaceColor',col,'MarkerSize',2); + % hold on + % %plot(cf_tot,min(S_chann(1:length(cf_tot),:),[],2),'DisplayName',['AVG'],'LineWidth',1,'LineStyle',':','Color',col,'Marker','^','MarkerFaceColor',col,'MarkerSize',2); + % plot(cf,worst_fec_cross,'DisplayName',['AVG'],'LineWidth',2,'LineStyle','-','Color',col,'Marker','none','MarkerFaceColor',col,'MarkerSize',2); + % ghzgrid = hz2nm(nm2hz(1310)+[0:1:20].*400e9); + % set(gca,'xtick',sort(ghzgrid)) + % xlim([1302, 1310.1]); + % xline(ghzgrid,'LineStyle',':','Color',[.7 .7 .7]); + + + %with + % Stot = movmean(Stot,5); + % figure(222) + % [hl,hp] = boundedline(cf_tot,Stot,[(Stot'-min(S_chann(1:length(cf_tot),:),[],2)),(max(S_chann(1:length(cf_tot),:),[],2)-Stot')], 'alpha','Color',col,'transparency', 0.05); + % ho = outlinebounds(hl,hp); + % set(ho, 'linestyle', ':', 'color', col, 'marker', '.','linewidth',0.5); + % hold on + % + % ghzgrid = hz2nm(nm2hz(1310)+[0:1:12].*400e9); + % xline(ghzgrid); + + + + + %plot the total ber + + % %figure(22); + % hold on; + % b= movmean(Stot,3); + % plot(AxesMain,cf_tot,b,'LineWidth',2,'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname],'Color',col,'Marker','o'); + % hold on + + + + + + %scatter(AxesMain,zdw_,S,'Marker','+','MarkerEdgeColor',col,'MarkerFaceAlpha',0.4,'MarkerEdgeAlpha',0.4,'LineWidth',0.5,'Parent', AxesMain(1),'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]); + %ylim(AxesMain,[-9.3 -7]); + + % for i = 1:numel(chp) + % hold on + % xline(AxesMain,chp(i),'Color',colr(i,:),'DisplayName',['CH: ', num2str(i)],'LineWidth',1.5); + % hold off + % end + + + + + % + % a = movmean(sortrows([zdw_; S]'),10,'Endpoints','discard'); + % + % sorted = sortrows([zdw_; S]'); + % figure(2) + % scatter(sorted(:,1),sorted(:,2)) + % + % ber_sorted = sort(S); + % mean(ber_sorted); + % std(ber_sorted); + % z1 = []; + % penalty = mean(ber_sorted):0.01:mean(ber_sorted)+2; + % for i = 1:length(penalty) + % l = penalty(i); + % if i == 1 + % z1 = [z1 sum(ber_sorted(1,:)l-0.01) / length(ber_sorted) ]; + % end + % + % end + % + % penalty_higherthan = 0.5; + % probability = sum(z1(find(penalty>mean(ber_sorted)+penalty_higherthan))); + % disp(['A penalty of more than 1dB has a probability of: ', num2str(probability)]); + % % + % stem(AxesMain,penalty,z1,"filled",'Marker','o','MarkerSize',2,'Color',col); + % + % + % [f1,x1]=ecdf(S(end,:)); + % %figure(23);plot(AxesMain,x1,f1,'r','LineWidth',3, 'Color',col); + % + % %plot(AxesMain,a(:,1),a(:,2),'Color',col+1,'Parent', AxesMain(1)); + % + % % histogram(AxesMain,S,1000,'EdgeColor','none','FaceAlpha',0.4); + % + % + % + % % + % %scatter(AxesMain,zdw_,S,'Marker','+','MarkerEdgeColor',col,'MarkerFaceAlpha',0.4,'MarkerEdgeAlpha',0.4,'LineWidth',0.5,'Parent', AxesMain(1),'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]); + % hold on + % %scatter(AxesMain,zdw_chann(:,1),mean(S_chann,2),'Marker','diamond','MarkerEdgeColor',col,'MarkerFaceAlpha',0.6,'LineWidth',7,'MarkerFaceColor',col,'Parent', AxesMain(1),'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]); + % hold off + % % + % % for rlz = 1:size(S,2) + % % zdwval = zdw_(rlz); + % % feccrossing = S(rlz); + % % scatter(AxesMain,zdwval,feccrossing,10,'MarkerEdgeColor',col,'MarkerFaceColor',col,'Parent', AxesMain(1),'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]); + % % end + % + % xline([1302.03471732576,1304.30061112288,1306.57440520904,1308.85614097425,1311.14586009814,1313.44360455251,1315.74941660391,1318.06333881618]); + + +end + +function vec = removeZeros(vec) + % Find rows that contain only zeros + rows_to_remove = all(vec == 0, 2); + + % Remove rows with only zeros + vec(rows_to_remove, :) = []; end \ No newline at end of file diff --git a/Classes/Warehouse_class/functions/fwm_plots/plotBerVsZdwFailureRate.m b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plotBerVsZdwFailureRate.m similarity index 96% rename from Classes/Warehouse_class/functions/fwm_plots/plotBerVsZdwFailureRate.m rename to Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plotBerVsZdwFailureRate.m index 480641f..069dbc8 100644 --- a/Classes/Warehouse_class/functions/fwm_plots/plotBerVsZdwFailureRate.m +++ b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plotBerVsZdwFailureRate.m @@ -1,157 +1,157 @@ -function plotBerVsZdwFailureRate(wh,plotJob) - - fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName); - - if isvalid(fig) - figure(fig) - fig = get(fig); - AxesMain = fig.CurrentAxes; - hold on - else - fig = figure('name',char(plotJob.figName)); - AxesMain = gca; - hold on - end - - - col = plotJob.color; - - % we want to fetch all realizations - realization = wh.parameter.realization.values(1:end); - - % get all xAxis values - xAxis = wh.parameter.p_out.values; - - % get all center wavelengths - wavelengths = wh.parameter.center_wavelength.values; - %wavelengths = wavelengths(2:end); -% totber = NaN(numel(realization),1,numel(xAxis),numel(wavelengths)); -% ber = zeros(numel(realization),plotJob.ch,numel(xAxis),numel(wavelengths)); - - %get BER values for query - for w = 1:numel(wavelengths) - - for xl = 1:numel(xAxis) - - c_wavelen = wavelengths(w); - p_out = xAxis(xl); - - % dim1 : realiz; dim2: channels, dim3: rop, dim4, c_wavelength - temp = removeZeros(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,c_wavelen,plotJob.channelspacing,plotJob.randzdw)); - ber(1:size(temp,1),:,xl,w) = temp; - - end - end - - hdfec = 3.8e-3.*ones(size(xAxis)); - zdw_ = []; - zdw_chann = []; - zdw_tot = []; - cf_tot = []; - cf_ = []; - S = []; - Stot = []; - S_chann = []; - cf_chann = []; - - cnt = 0; - %get fec thresholds - %linear = squeeze(linear); - for c_wavelen = 1:size(ber,4) - for realiz = 1:size(ber,1) - for chann = 1:size(ber,2) - - %finde Schnittpunkt zwischen FEC und BER Kurve - temp_ber = squeeze(ber(realiz,chann,:,c_wavelen)).'; - if ~all(temp_ber == 0) - %nur wenn nicht alles nullen sind - crossing_ch = InterX([hdfec;xAxis],[temp_ber;xAxis]); - else - continue - end - - %Req. FEC Ergebnis einsortieren - if ~isempty(crossing_ch) - if crossing_ch(2) == 0 - print("d") - end - S(realiz,chann,c_wavelen) = crossing_ch(2); - else - S(realiz,chann,c_wavelen) = -1; - cnt = cnt +1; - end - - - end - end - end - - temp_max = -inf; - sum_FEC_not_crossed=[]; - sum_FEC_crossed=[]; - - threshold = plotJob.p_in - 10; - - for i = 1:plotJob.ch - hold on - %S:: 1.dim: realiz; 2.dim: channel; 3.dim: center wavelength - %squeeze a channel: - temp_data = squeeze(S(:,i,:)); - - %remove realizations that have no entry (only zero) - temp_data = removeZeros(temp_data); - - %replace zeros with NAN (e.g. for the wavelengths that have missing realizations) - temp_data(temp_data==0) = NaN; - - %for current channel - FEC_crossed = temp_data < threshold & ~isnan(temp_data); - FEC_not_crossed = temp_data >= threshold & ~isnan(temp_data); - - %sum over channels for overall picture - sum_FEC_not_crossed(i,:) = sum(FEC_not_crossed); - sum_FEC_crossed(i,:) = sum(FEC_crossed); - - failure_rate_channelwise(i,:) = sum_FEC_not_crossed(i,:)./ ( sum_FEC_crossed(i,:) + sum_FEC_not_crossed(i,:)); - - end - - failure_rate_total = sum(sum_FEC_not_crossed,1) ./ ( sum(sum_FEC_crossed,1) + sum(sum_FEC_not_crossed,1) ); - % plot failure rate (nbetween 0 and 1) - - plot(wavelengths,failure_rate_total,'Color',plotJob.color,'LineWidth',1,'LineStyle',plotJob.plotTypeArg,'Marker','x','MarkerSize',5,'MarkerFaceColor',plotJob.color,'DisplayName',plotJob.displayname); - - %plot max overall - %scatter(wavelengths,failure_rate_channelwise ,35,plotJob.color,'Marker','.'); - - ylabel('Failure Rate of Link'); - xlabel('Wavelength in nm'); - - xlim([min(wavelengths),max(wavelengths) ]); - ylim([0,1]); - - grid minor; - set(gca, 'color', 'none'); - legend = []; - -% fontsize(AxesMain,8,"points") - - fig.Position = plotJob.Position; - fig.Units = "centimeters"; - fig.Position = [0 0 12 5 7]; - - try - set(AxesMain,'TickLabelInterpreter','latex') - - set(AxesMain.Legend,'Interpreter','latex') - end - -end - -function vec = removeZeros(vec) - % Find rows that contain only zeros - rows_to_remove = all(vec == 0, 2); - - % Remove rows with only zeros - vec(rows_to_remove, :) = []; +function plotBerVsZdwFailureRate(wh,plotJob) + + fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName); + + if isvalid(fig) + figure(fig) + fig = get(fig); + AxesMain = fig.CurrentAxes; + hold on + else + fig = figure('name',char(plotJob.figName)); + AxesMain = gca; + hold on + end + + + col = plotJob.color; + + % we want to fetch all realizations + realization = wh.parameter.realization.values(1:end); + + % get all xAxis values + xAxis = wh.parameter.p_out.values; + + % get all center wavelengths + wavelengths = wh.parameter.center_wavelength.values; + %wavelengths = wavelengths(2:end); +% totber = NaN(numel(realization),1,numel(xAxis),numel(wavelengths)); +% ber = zeros(numel(realization),plotJob.ch,numel(xAxis),numel(wavelengths)); + + %get BER values for query + for w = 1:numel(wavelengths) + + for xl = 1:numel(xAxis) + + c_wavelen = wavelengths(w); + p_out = xAxis(xl); + + % dim1 : realiz; dim2: channels, dim3: rop, dim4, c_wavelength + temp = removeZeros(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,c_wavelen,plotJob.channelspacing,plotJob.randzdw)); + ber(1:size(temp,1),:,xl,w) = temp; + + end + end + + hdfec = 3.8e-3.*ones(size(xAxis)); + zdw_ = []; + zdw_chann = []; + zdw_tot = []; + cf_tot = []; + cf_ = []; + S = []; + Stot = []; + S_chann = []; + cf_chann = []; + + cnt = 0; + %get fec thresholds + %linear = squeeze(linear); + for c_wavelen = 1:size(ber,4) + for realiz = 1:size(ber,1) + for chann = 1:size(ber,2) + + %finde Schnittpunkt zwischen FEC und BER Kurve + temp_ber = squeeze(ber(realiz,chann,:,c_wavelen)).'; + if ~all(temp_ber == 0) + %nur wenn nicht alles nullen sind + crossing_ch = InterX([hdfec;xAxis],[temp_ber;xAxis]); + else + continue + end + + %Req. FEC Ergebnis einsortieren + if ~isempty(crossing_ch) + if crossing_ch(2) == 0 + print("d") + end + S(realiz,chann,c_wavelen) = crossing_ch(2); + else + S(realiz,chann,c_wavelen) = -1; + cnt = cnt +1; + end + + + end + end + end + + temp_max = -inf; + sum_FEC_not_crossed=[]; + sum_FEC_crossed=[]; + + threshold = plotJob.p_in - 10; + + for i = 1:plotJob.ch + hold on + %S:: 1.dim: realiz; 2.dim: channel; 3.dim: center wavelength + %squeeze a channel: + temp_data = squeeze(S(:,i,:)); + + %remove realizations that have no entry (only zero) + temp_data = removeZeros(temp_data); + + %replace zeros with NAN (e.g. for the wavelengths that have missing realizations) + temp_data(temp_data==0) = NaN; + + %for current channel + FEC_crossed = temp_data < threshold & ~isnan(temp_data); + FEC_not_crossed = temp_data >= threshold & ~isnan(temp_data); + + %sum over channels for overall picture + sum_FEC_not_crossed(i,:) = sum(FEC_not_crossed); + sum_FEC_crossed(i,:) = sum(FEC_crossed); + + failure_rate_channelwise(i,:) = sum_FEC_not_crossed(i,:)./ ( sum_FEC_crossed(i,:) + sum_FEC_not_crossed(i,:)); + + end + + failure_rate_total = sum(sum_FEC_not_crossed,1) ./ ( sum(sum_FEC_crossed,1) + sum(sum_FEC_not_crossed,1) ); + % plot failure rate (nbetween 0 and 1) + + plot(wavelengths,failure_rate_total,'Color',plotJob.color,'LineWidth',1,'LineStyle',plotJob.plotTypeArg,'Marker','x','MarkerSize',5,'MarkerFaceColor',plotJob.color,'DisplayName',plotJob.displayname); + + %plot max overall + %scatter(wavelengths,failure_rate_channelwise ,35,plotJob.color,'Marker','.'); + + ylabel('Failure Rate of Link'); + xlabel('Wavelength in nm'); + + xlim([min(wavelengths),max(wavelengths) ]); + ylim([0,1]); + + grid minor; + set(gca, 'color', 'none'); + legend = []; + +% fontsize(AxesMain,8,"points") + + fig.Position = plotJob.Position; + fig.Units = "centimeters"; + fig.Position = [0 0 12 5 7]; + + try + set(AxesMain,'TickLabelInterpreter','latex') + + set(AxesMain.Legend,'Interpreter','latex') + end + +end + +function vec = removeZeros(vec) + % Find rows that contain only zeros + rows_to_remove = all(vec == 0, 2); + + % Remove rows with only zeros + vec(rows_to_remove, :) = []; end \ No newline at end of file diff --git a/Classes/Warehouse_class/functions/fwm_plots/plotChannelSpacingAna.m b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plotChannelSpacingAna.m similarity index 96% rename from Classes/Warehouse_class/functions/fwm_plots/plotChannelSpacingAna.m rename to Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plotChannelSpacingAna.m index 44febc6..b64a827 100644 --- a/Classes/Warehouse_class/functions/fwm_plots/plotChannelSpacingAna.m +++ b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plotChannelSpacingAna.m @@ -1,51 +1,51 @@ -function plotChannelSpacingAna(wh,plotJob) - -xAxis = wh.parameter.p_out.values; - - -realization = wh.parameter.realization.values(1:end); - -channelsp = wh.parameter.channelspacing.values(1:end); -channelsp = [200 400].*1e9; -for ch = 1:2 - channspacing = channelsp(ch); - for xl = 1:numel(xAxis) - p_out = xAxis(xl); - - curber = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.numchannels,channspacing); - curzdw = wh.getStoValue('zdw',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.numchannels,channspacing); - - ber(1:size(curber,1),1:size(curber,2),xl) = curber; - zdw(1:size(curber,1),1,xl) = curzdw; - - end - - ber = squeeze(mean(ber,1)); - zdw = squeeze(mean(zdw,1)); - - hdfec = 3.8e-3.*ones(size(xAxis)); - S = []; - wavelength={}; - - zdw_ = []; - zdw_chann = []; - zdw_tot = []; - S = []; - S_chann = []; - wl = round([1302.03471732576,1304.30061112288,1306.57440520904,1308.85614097425,1311.14586009814,1313.44360455251,1315.74941660391,1318.06333881618],2); - wl = 1:16; - wl = [1.2930 1.2953 1.2975 1.2998 1.3020 1.3043 1.3066 1.3089 1.3111 1.3134 1.3157 1.3181 1.3204 1.3227 1.3251 1.3274]; - - - a = InterX([hdfec(:)';xAxis],[mean(ber,1);xAxis]); - if ~isempty(a) - s(ch) = a(2); - else - s(ch) = NaN; - end -end - -figure(2224) -hold on -plot(channelsp,s,'LineWidth',1,'Color',plotJob.color,'Marker','o'); - +function plotChannelSpacingAna(wh,plotJob) + +xAxis = wh.parameter.p_out.values; + + +realization = wh.parameter.realization.values(1:end); + +channelsp = wh.parameter.channelspacing.values(1:end); +channelsp = [200 400].*1e9; +for ch = 1:2 + channspacing = channelsp(ch); + for xl = 1:numel(xAxis) + p_out = xAxis(xl); + + curber = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.numchannels,channspacing); + curzdw = wh.getStoValue('zdw',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.numchannels,channspacing); + + ber(1:size(curber,1),1:size(curber,2),xl) = curber; + zdw(1:size(curber,1),1,xl) = curzdw; + + end + + ber = squeeze(mean(ber,1)); + zdw = squeeze(mean(zdw,1)); + + hdfec = 3.8e-3.*ones(size(xAxis)); + S = []; + wavelength={}; + + zdw_ = []; + zdw_chann = []; + zdw_tot = []; + S = []; + S_chann = []; + wl = round([1302.03471732576,1304.30061112288,1306.57440520904,1308.85614097425,1311.14586009814,1313.44360455251,1315.74941660391,1318.06333881618],2); + wl = 1:16; + wl = [1.2930 1.2953 1.2975 1.2998 1.3020 1.3043 1.3066 1.3089 1.3111 1.3134 1.3157 1.3181 1.3204 1.3227 1.3251 1.3274]; + + + a = InterX([hdfec(:)';xAxis],[mean(ber,1);xAxis]); + if ~isempty(a) + s(ch) = a(2); + else + s(ch) = NaN; + end +end + +figure(2224) +hold on +plot(channelsp,s,'LineWidth',1,'Color',plotJob.color,'Marker','o'); + diff --git a/Classes/Warehouse_class/functions/fwm_plots/plotCurve.m b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plotCurve.m similarity index 97% rename from Classes/Warehouse_class/functions/fwm_plots/plotCurve.m rename to Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plotCurve.m index e06e7e5..be3813e 100644 --- a/Classes/Warehouse_class/functions/fwm_plots/plotCurve.m +++ b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plotCurve.m @@ -1,294 +1,294 @@ -function plotCurve(wh,plotJob) -%PLOTCURVE Summary of this function goes here -% Detailed explanation goes here - -fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName); - -if isvalid(fig) - figure(fig) - % fig = get(fig); - AxesMain = fig.CurrentAxes; - hold on -else - fig = figure('name',char(plotJob.figName)); - AxesMain = gca; - hold on -end - -col = plotJob.color; - -% we want to fetch all realizations -if plotJob.pmd == 0 - realization = 499; - % realization = 0:7; -else - realization = wh.parameter.realization.values(1:end); -end -realization = wh.parameter.realization.values(1:end); -% get all xAxis values -xAxis = wh.parameter.p_out.values; - -markerstyle = 'o'; -linestyle = '-'; - -% Fetch Data from Warehouse -for xl = 1:numel(xAxis) - p_out = xAxis(xl); - if string(plotJob.dataStatArg) == "Worst" - temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); - temp = removeZeros(temp); - ber(xl) = quantile(temp,0.9,"all"); - % ber(xl) = max(temp,[],'all'); - linew = 1.0; - markersz = plotJob.markersize; - markerstyle = plotJob.markerstyle; - linestyle = plotJob.linestyle; - - elseif string(plotJob.dataStatArg) == "AVG" - temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); - temp = removeZeros(temp); - ber(xl) = mean(temp,'all'); - linew = 1.0; - markersz = plotJob.markersize; - markerstyle = plotJob.markerstyle; - linestyle = plotJob.linestyle; - - elseif string(plotJob.dataStatArg) == "Best" - temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); - temp = removeZeros(temp); - ber(xl) = min(temp,[],'all'); - linew = 1.0; - markersz = plotJob.markersize; - markerstyle = plotJob.markerstyle; - linestyle = plotJob.linestyle; - - elseif string(plotJob.dataStatArg) == "All Channels; mean(PMD Realizations)" - temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); - temp = removeZeros(temp); - - ber(:,xl) = mean(temp,1,"omitnan").'; - - linew = 1; - markersz = 1; - markerstyle = plotJob.markerstyle; - linestyle = plotJob.linestyle; - - elseif string(plotJob.dataStatArg) == "Lineplot with quartiles" - - temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); - temp = removeZeros(temp); - ber(xl) = mean(temp,"all","omitnan").'; - - - upperq(xl) = quantile(temp,0.99,"all"); - lowerq(xl) = quantile(temp,0.04,"all"); - - - % upperq(xl) = 0.5*std(tmp,1,'all','omitnan'); - % lowerq(xl) = 0.5*std(tmp,1,'all','omitnan'); - - upperq(xl) = max(temp(:)); - lowerq(xl) = min(temp(:)); - - if lowerq(xl) == 0 - lowerq(xl) = 1e-8; - end - - % upperq(xl) = mean(tmp,"all","omitnan") + 1.96 * (std(tmp,1,'all','omitnan')/sqrt(numel(tmp))); - % lowerq(xl) = mean(tmp,"all","omitnan") - 1.96 * (std(tmp,1,'all','omitnan')/sqrt(numel(tmp))); - - linew = 1; - markersz = 1; - linestyle = '-'; - - elseif string(plotJob.dataStatArg) == "All Channels ;All PMD Realizations" - - raw_fetch = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw).'; - tmp = reshape(raw_fetch,[],1); - ber(1:size(tmp,1),xl) = tmp; - - ber_per_chann(:,:,xl) = raw_fetch; - - linew = 0.3; - markersz = 2; - linestyle = ':'; - - end -end - - -%routine to remove total outliers (here those wehere the rop curve has a mean BER greater than 0.1) -% ber_per_chann_clean = NaN(size(ber_per_chann)); -% for ch = 1:size(ber_per_chann,1) -% bla = squeeze(ber_per_chann(ch,:,:)); -% ber_per_chann(ch,find(mean(bla,2)>0.25),:) = NaN; -% cleaned = rmoutliers(bla,"mean",'ThresholdFactor',2); -% -% ber_per_chann_clean(ch,1:size(cleaned,1),1:size(cleaned,2)) = cleaned; -% -% end -% -% ber = []; -% for rop = 1:size(ber_per_chann,3) -% temp = squeeze(ber_per_chann_clean(:,:,rop)); -% ber(rop) = mean(temp,"all","omitnan").'; -% upperq(rop) = quantile(temp,0.9,"all"); -% lowerq(rop) = quantile(temp,0.1,"all"); -% end - - - - -xAxis = xAxis; - -% Plot Data -if string(plotJob.plotTypeArg) == "Scatter" - for rlz = 1:size(ber,1) - - if rlz < size(ber,1) - scatter(xAxis,ber(rlz,:),markersz,'MarkerEdgeColor',col,'MarkerFaceColor',col,'Parent', AxesMain(1),'HandleVisibility','off'); - else - scatter(xAxis,ber(rlz,:),markersz,'MarkerEdgeColor',col,'MarkerFaceColor',col,'Parent', AxesMain(1),'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]); - end - - end - -elseif string(plotJob.plotTypeArg) == "Lines" - - % if ~anynan(ber) - % [xAxis,ber] = interpCurve(xAxis, ber); - % end - - cols = cbrewer2('RdBu',size(ber,1)); - for rlz = 1:size(ber,1) -% - if (string(plotJob.dataStatArg) == "All Channels ;All PMD Realizations")||(string(plotJob.dataStatArg) == "All Channels; mean(PMD Realizations)") - ch = mod(rlz,plotJob.ch); - if ch == 0; ch = plotJob.ch; end - else - ch = plotJob.dataStatArg; - end - - if rlz < size(ber,1) - - col = cols(rlz,:); - - s = plot(xAxis,ber(rlz,:),linestyle,'Marker',"none",'MarkerSize',markersz,'LineWidth',linew,'Color',col,'Parent', AxesMain,'HandleVisibility','off'); - - s.DataTipTemplate.Interpreter = "latex"; - s.DataTipTemplate.DataTipRows(1).Label = "Ch: "; - s.DataTipTemplate.DataTipRows(1).Value = repmat(ch,size(ber)); - s.DataTipTemplate.DataTipRows(1); - s.DataTipTemplate.DataTipRows(2) = []; - - else - - if string(plotJob.dataStatArg) == "Lineplot with quartiles" - - [hl,hp] = boundedline(xAxis,ber(rlz,:),([(ber(rlz,:)-lowerq(rlz,:));upperq(rlz,:)-ber(rlz,:)]'),'-o','alpha','Color',col,'transparency', 0.06,'linewidth',0.7); - hl.MarkerFaceColor = col; - hl.MarkerSize = 2; - set(hp,'HandleVisibility','off'); - %hp.LineWidth = 1.2; - - ho = outlinebounds(hl,hp); - set(ho, 'linestyle', ':', 'color', col,'Linewidth',0.6); - set(ho,'HandleVisibility','off'); - - % errorbar(xAxis,ber(rlz,:),ber(rlz,:)-lowerq(rlz,:),upperq(rlz,:)-ber(rlz,:),'-o','Color',col,'linewidth',0.7); - - else - - s = plot(xAxis,ber(rlz,:),linestyle,'Marker',markerstyle,'MarkerFaceColor',col,'MarkerSize',markersz,'LineWidth',linew,'Color',col,'Parent', AxesMain,'DisplayName',[plotJob.displayname]); - - s.DataTipTemplate.Interpreter = "latex"; - s.DataTipTemplate.DataTipRows(1).Label = "Ch: "; - s.DataTipTemplate.DataTipRows(1).Value = repmat(string(ch),size(ber)); - s.DataTipTemplate.DataTipRows(1) - s.DataTipTemplate.DataTipRows(2) = []; - end - - end - - end -end - -% Draw FEC Threshold Line -%get x data of first children: -%get all linear Values -if 0 - linear = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,wh.parameter.p_out.values,0,0,499,"symmetric"); - linear = mean(linear,2); - lincurve = findall(AxesMain, 'Type', 'line','DisplayName','Linear Baseline'); - % - if isempty(lincurve) - xdata = AxesMain.Children(1).XData; - hdfec = 3.8e-3.*ones(size(xdata)); - plot(xdata,linear,'-','Marker',"o",'MarkerSize',3,'LineWidth',4,'Color',[0.6400 0.6400 0.6400],'MarkerFaceColor',[0.6400 0.6400 0.6400],'Parent', AxesMain,'DisplayName','Linear Baseline'); - %h = get(gca,'Children'); - %set(gca,'Children',[h(2) h(1)]) - end -end - -feccurve = findall(AxesMain, 'Type', 'line','DisplayName','FEC $3.8*10^{-3}$'); -% -if isempty(feccurve) - xdata = AxesMain.Children(1).XData; - hdfec = 3.8e-3.*ones(size(xdata)); - plot(xdata,hdfec,'--','MarkerSize',4,'Color','black','MarkerFaceColor','black','LineWidth',1,'Parent', AxesMain,'DisplayName','FEC $3.8*10^{-3}$','HandleVisibility','off'); - %h = get(gca,'Children'); - %set(gca,'Children',[h(2) h(1)]) -end - -% Figure Settings -%title(AxesMain,plotJob.title,"Interpreter","none"); - -xlabel(AxesMain,plotJob.xAxisLabel,"Interpreter","latex"); - -ylabel(AxesMain,plotJob.yAxisLabel,"Interpreter","latex"); - -set(AxesMain,'yscale','log'); - -grid(AxesMain,'on'); - -grid(AxesMain,'minor'); - -grid minor - -%legend(AxesMain); - -fontsize(AxesMain,8,"points") -% fontname(AxesMain,"Arial") - - -% fig.Position = plotJob.Position; -% fig.Units = "centimeters"; -% fig.Position = [2 2 8.5 7]; - -set(AxesMain,'TickLabelInterpreter','latex') - -set(AxesMain.Legend,'Interpreter','latex') -% set(gcf,'Units','centimeters') -% set(gcf,'Position',[2 2 9 4.5]) - -ylim([1e-5,0.3]); - -xlim([-10,-4]); - - -% annotation('textbox', [0.125, 0.32, 0.1, 0.1], 'String', "FEC 3.8e-3","LineStyle","none","FontSize",8,"FontUnits","points") - - -hold off - - -end - - -function vec = removeZeros(vec) - % Find rows that contain only zeros - rows_to_remove = all(vec == 0, 2); - - % Remove rows with only zeros - vec(rows_to_remove, :) = []; -end +function plotCurve(wh,plotJob) +%PLOTCURVE Summary of this function goes here +% Detailed explanation goes here + +fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName); + +if isvalid(fig) + figure(fig) + % fig = get(fig); + AxesMain = fig.CurrentAxes; + hold on +else + fig = figure('name',char(plotJob.figName)); + AxesMain = gca; + hold on +end + +col = plotJob.color; + +% we want to fetch all realizations +if plotJob.pmd == 0 + realization = 499; + % realization = 0:7; +else + realization = wh.parameter.realization.values(1:end); +end +realization = wh.parameter.realization.values(1:end); +% get all xAxis values +xAxis = wh.parameter.p_out.values; + +markerstyle = 'o'; +linestyle = '-'; + +% Fetch Data from Warehouse +for xl = 1:numel(xAxis) + p_out = xAxis(xl); + if string(plotJob.dataStatArg) == "Worst" + temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); + temp = removeZeros(temp); + ber(xl) = quantile(temp,0.9,"all"); + % ber(xl) = max(temp,[],'all'); + linew = 1.0; + markersz = plotJob.markersize; + markerstyle = plotJob.markerstyle; + linestyle = plotJob.linestyle; + + elseif string(plotJob.dataStatArg) == "AVG" + temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); + temp = removeZeros(temp); + ber(xl) = mean(temp,'all'); + linew = 1.0; + markersz = plotJob.markersize; + markerstyle = plotJob.markerstyle; + linestyle = plotJob.linestyle; + + elseif string(plotJob.dataStatArg) == "Best" + temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); + temp = removeZeros(temp); + ber(xl) = min(temp,[],'all'); + linew = 1.0; + markersz = plotJob.markersize; + markerstyle = plotJob.markerstyle; + linestyle = plotJob.linestyle; + + elseif string(plotJob.dataStatArg) == "All Channels; mean(PMD Realizations)" + temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); + temp = removeZeros(temp); + + ber(:,xl) = mean(temp,1,"omitnan").'; + + linew = 1; + markersz = 1; + markerstyle = plotJob.markerstyle; + linestyle = plotJob.linestyle; + + elseif string(plotJob.dataStatArg) == "Lineplot with quartiles" + + temp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); + temp = removeZeros(temp); + ber(xl) = mean(temp,"all","omitnan").'; + + + upperq(xl) = quantile(temp,0.99,"all"); + lowerq(xl) = quantile(temp,0.04,"all"); + + + % upperq(xl) = 0.5*std(tmp,1,'all','omitnan'); + % lowerq(xl) = 0.5*std(tmp,1,'all','omitnan'); + + upperq(xl) = max(temp(:)); + lowerq(xl) = min(temp(:)); + + if lowerq(xl) == 0 + lowerq(xl) = 1e-8; + end + + % upperq(xl) = mean(tmp,"all","omitnan") + 1.96 * (std(tmp,1,'all','omitnan')/sqrt(numel(tmp))); + % lowerq(xl) = mean(tmp,"all","omitnan") - 1.96 * (std(tmp,1,'all','omitnan')/sqrt(numel(tmp))); + + linew = 1; + markersz = 1; + linestyle = '-'; + + elseif string(plotJob.dataStatArg) == "All Channels ;All PMD Realizations" + + raw_fetch = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw).'; + tmp = reshape(raw_fetch,[],1); + ber(1:size(tmp,1),xl) = tmp; + + ber_per_chann(:,:,xl) = raw_fetch; + + linew = 0.3; + markersz = 2; + linestyle = ':'; + + end +end + + +%routine to remove total outliers (here those wehere the rop curve has a mean BER greater than 0.1) +% ber_per_chann_clean = NaN(size(ber_per_chann)); +% for ch = 1:size(ber_per_chann,1) +% bla = squeeze(ber_per_chann(ch,:,:)); +% ber_per_chann(ch,find(mean(bla,2)>0.25),:) = NaN; +% cleaned = rmoutliers(bla,"mean",'ThresholdFactor',2); +% +% ber_per_chann_clean(ch,1:size(cleaned,1),1:size(cleaned,2)) = cleaned; +% +% end +% +% ber = []; +% for rop = 1:size(ber_per_chann,3) +% temp = squeeze(ber_per_chann_clean(:,:,rop)); +% ber(rop) = mean(temp,"all","omitnan").'; +% upperq(rop) = quantile(temp,0.9,"all"); +% lowerq(rop) = quantile(temp,0.1,"all"); +% end + + + + +xAxis = xAxis; + +% Plot Data +if string(plotJob.plotTypeArg) == "Scatter" + for rlz = 1:size(ber,1) + + if rlz < size(ber,1) + scatter(xAxis,ber(rlz,:),markersz,'MarkerEdgeColor',col,'MarkerFaceColor',col,'Parent', AxesMain(1),'HandleVisibility','off'); + else + scatter(xAxis,ber(rlz,:),markersz,'MarkerEdgeColor',col,'MarkerFaceColor',col,'Parent', AxesMain(1),'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]); + end + + end + +elseif string(plotJob.plotTypeArg) == "Lines" + + % if ~anynan(ber) + % [xAxis,ber] = interpCurve(xAxis, ber); + % end + + cols = cbrewer2('RdBu',size(ber,1)); + for rlz = 1:size(ber,1) +% + if (string(plotJob.dataStatArg) == "All Channels ;All PMD Realizations")||(string(plotJob.dataStatArg) == "All Channels; mean(PMD Realizations)") + ch = mod(rlz,plotJob.ch); + if ch == 0; ch = plotJob.ch; end + else + ch = plotJob.dataStatArg; + end + + if rlz < size(ber,1) + + col = cols(rlz,:); + + s = plot(xAxis,ber(rlz,:),linestyle,'Marker',"none",'MarkerSize',markersz,'LineWidth',linew,'Color',col,'Parent', AxesMain,'HandleVisibility','off'); + + s.DataTipTemplate.Interpreter = "latex"; + s.DataTipTemplate.DataTipRows(1).Label = "Ch: "; + s.DataTipTemplate.DataTipRows(1).Value = repmat(ch,size(ber)); + s.DataTipTemplate.DataTipRows(1); + s.DataTipTemplate.DataTipRows(2) = []; + + else + + if string(plotJob.dataStatArg) == "Lineplot with quartiles" + + [hl,hp] = boundedline(xAxis,ber(rlz,:),([(ber(rlz,:)-lowerq(rlz,:));upperq(rlz,:)-ber(rlz,:)]'),'-o','alpha','Color',col,'transparency', 0.06,'linewidth',0.7); + hl.MarkerFaceColor = col; + hl.MarkerSize = 2; + set(hp,'HandleVisibility','off'); + %hp.LineWidth = 1.2; + + ho = outlinebounds(hl,hp); + set(ho, 'linestyle', ':', 'color', col,'Linewidth',0.6); + set(ho,'HandleVisibility','off'); + + % errorbar(xAxis,ber(rlz,:),ber(rlz,:)-lowerq(rlz,:),upperq(rlz,:)-ber(rlz,:),'-o','Color',col,'linewidth',0.7); + + else + + s = plot(xAxis,ber(rlz,:),linestyle,'Marker',markerstyle,'MarkerFaceColor',col,'MarkerSize',markersz,'LineWidth',linew,'Color',col,'Parent', AxesMain,'DisplayName',[plotJob.displayname]); + + s.DataTipTemplate.Interpreter = "latex"; + s.DataTipTemplate.DataTipRows(1).Label = "Ch: "; + s.DataTipTemplate.DataTipRows(1).Value = repmat(string(ch),size(ber)); + s.DataTipTemplate.DataTipRows(1) + s.DataTipTemplate.DataTipRows(2) = []; + end + + end + + end +end + +% Draw FEC Threshold Line +%get x data of first children: +%get all linear Values +if 0 + linear = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,wh.parameter.p_out.values,0,0,499,"symmetric"); + linear = mean(linear,2); + lincurve = findall(AxesMain, 'Type', 'line','DisplayName','Linear Baseline'); + % + if isempty(lincurve) + xdata = AxesMain.Children(1).XData; + hdfec = 3.8e-3.*ones(size(xdata)); + plot(xdata,linear,'-','Marker',"o",'MarkerSize',3,'LineWidth',4,'Color',[0.6400 0.6400 0.6400],'MarkerFaceColor',[0.6400 0.6400 0.6400],'Parent', AxesMain,'DisplayName','Linear Baseline'); + %h = get(gca,'Children'); + %set(gca,'Children',[h(2) h(1)]) + end +end + +feccurve = findall(AxesMain, 'Type', 'line','DisplayName','FEC $3.8*10^{-3}$'); +% +if isempty(feccurve) + xdata = AxesMain.Children(1).XData; + hdfec = 3.8e-3.*ones(size(xdata)); + plot(xdata,hdfec,'--','MarkerSize',4,'Color','black','MarkerFaceColor','black','LineWidth',1,'Parent', AxesMain,'DisplayName','FEC $3.8*10^{-3}$','HandleVisibility','off'); + %h = get(gca,'Children'); + %set(gca,'Children',[h(2) h(1)]) +end + +% Figure Settings +%title(AxesMain,plotJob.title,"Interpreter","none"); + +xlabel(AxesMain,plotJob.xAxisLabel,"Interpreter","latex"); + +ylabel(AxesMain,plotJob.yAxisLabel,"Interpreter","latex"); + +set(AxesMain,'yscale','log'); + +grid(AxesMain,'on'); + +grid(AxesMain,'minor'); + +grid minor + +%legend(AxesMain); + +fontsize(AxesMain,8,"points") +% fontname(AxesMain,"Arial") + + +% fig.Position = plotJob.Position; +% fig.Units = "centimeters"; +% fig.Position = [2 2 8.5 7]; + +set(AxesMain,'TickLabelInterpreter','latex') + +set(AxesMain.Legend,'Interpreter','latex') +% set(gcf,'Units','centimeters') +% set(gcf,'Position',[2 2 9 4.5]) + +ylim([1e-5,0.3]); + +xlim([-10,-4]); + + +% annotation('textbox', [0.125, 0.32, 0.1, 0.1], 'String', "FEC 3.8e-3","LineStyle","none","FontSize",8,"FontUnits","points") + + +hold off + + +end + + +function vec = removeZeros(vec) + % Find rows that contain only zeros + rows_to_remove = all(vec == 0, 2); + + % Remove rows with only zeros + vec(rows_to_remove, :) = []; +end diff --git a/Classes/Warehouse_class/functions/fwm_plots/plotHistogram.m b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plotHistogram.m similarity index 96% rename from Classes/Warehouse_class/functions/fwm_plots/plotHistogram.m rename to Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plotHistogram.m index 023a3a1..408cded 100644 --- a/Classes/Warehouse_class/functions/fwm_plots/plotHistogram.m +++ b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plotHistogram.m @@ -1,151 +1,151 @@ -function plotHistogram(wh,plotJob) - - -fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName); - -if isvalid(fig) - figure(fig) - fig = get(fig); - AxesMain = fig.CurrentAxes; - hold on -else - fig = figure('name',char(plotJob.figName)); - AxesMain = gca; - hold on -end - -col = plotJob.color; - -% we want to fetch all realizations -realization = wh.parameter.realization.values(1:end); - -% get all xAxis values -xAxis = wh.parameter.p_out.values; - - -% Fetch Data from Warehouse -for xl = 1:numel(xAxis) - p_out = xAxis(xl); - if string(plotJob.dataStatArg) == "Worst" - ber(xl) = max(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,string(plotJob.channelplan),string(plotJob.dsp)),[],'all'); - linew = 2.0; - markersz = 3; - linestyle = '-'; - elseif string(plotJob.dataStatArg) == "AVG" - ber(xl) = mean(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,string(plotJob.channelplan),string(plotJob.dsp)),'all'); - linew = 2.0; - markersz = 3; - linestyle = ':'; - elseif string(plotJob.dataStatArg) == "Best" - ber(xl) = min(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,string(plotJob.channelplan),string(plotJob.dsp)),[],'all'); - linew = 2.0; - markersz = 3; - linestyle = ':'; - - elseif string(plotJob.dataStatArg) == "All Channels; mean(PMD Realizations)" - tmp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,string(plotJob.channelplan),string(plotJob.dsp)); - - if numel(tmp(tmp==0)) ~= 0 - disp('Removed all zero values!'); - tmp(tmp==0) = NaN; - end - ber(:,xl) = mean(tmp,1,"omitnan").'; - - linew = 0.7; - markersz = 2; - linestyle = '-'; - - elseif string(plotJob.dataStatArg) == "All Channels ;All PMD Realizations" - - - - tmp = reshape(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,string(plotJob.channelplan),string(plotJob.dsp)).',[],1); - ber(1:size(tmp,1),xl) = tmp; - - linew = 0.3; - markersz = 2; - linestyle = ':'; - end -end - -disp('Removed all zero values!'); -ber(ber==0) = NaN; -if ~anynan(ber) - [xAxis,ber] = interpCurve(xAxis, ber); -end - -% plot FEC Crossing as histogram - -hdfec = 3.8e-3.*ones(size(xAxis)); -S = []; -for i = 1:size(ber,1) - a = InterX([hdfec;xAxis],[ber(i,:);xAxis]); - if ~isempty(a) - S(:,i) = a; - end -end - - -%% SUB 1 -AxesMain = subplot(2,1,1); - -hold on - -if ~isempty(S) - histogram(S(end,:),300,'Normalization','probability','FaceColor',col,'EdgeColor',col,'Parent',AxesMain,'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname],'FaceAlpha',0.4,'EdgeAlpha',0.4); -end - -xlim([-3 ,9 ]); -ylim([0 .10]); - -% Figure Settings -title(AxesMain,['$P_{in}:$ ',num2str(plotJob.p_in-9), 'dBm; L : ', num2str(plotJob.l),'Km'],'Interpreter','latex'); - -xlabel(AxesMain,plotJob.xAxisLabel,'Interpreter','latex'); - -ylabel('PDF') - -grid(AxesMain,'on'); - -grid(AxesMain,'minor'); - -%legend(AxesMain,'Interpreter','latex'); - -fontsize(AxesMain,24,"pixels") - -hold off - - -%% SUB 2 -AxesMain = subplot(2,1,2); - -if ~isempty(S) -hold on - -[f1,x1]=ecdf(S(end,:)); - plot(x1,f1,'r','LineWidth',3, 'Color',col,'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]); -end -xlim([-3 ,9 ]); -ylim([0 1]); -% Figure Settings -title(AxesMain,['$P_{in}:$ ',num2str(plotJob.p_in-9), 'dBm; L : ', num2str(plotJob.l),'Km'],'Interpreter','latex'); - -xlabel(AxesMain,plotJob.xAxisLabel,'Interpreter','latex'); - -ylabel('CDF') - -grid(AxesMain,'on'); - -grid(AxesMain,'minor'); - -fontsize(AxesMain,24,"pixels") - -%legend(AxesMain,'Interpreter','latex'); - -fig.Position = plotJob.Position; - -hold off - - - +function plotHistogram(wh,plotJob) + + +fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName); + +if isvalid(fig) + figure(fig) + fig = get(fig); + AxesMain = fig.CurrentAxes; + hold on +else + fig = figure('name',char(plotJob.figName)); + AxesMain = gca; + hold on +end + +col = plotJob.color; + +% we want to fetch all realizations +realization = wh.parameter.realization.values(1:end); + +% get all xAxis values +xAxis = wh.parameter.p_out.values; + + +% Fetch Data from Warehouse +for xl = 1:numel(xAxis) + p_out = xAxis(xl); + if string(plotJob.dataStatArg) == "Worst" + ber(xl) = max(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,string(plotJob.channelplan),string(plotJob.dsp)),[],'all'); + linew = 2.0; + markersz = 3; + linestyle = '-'; + elseif string(plotJob.dataStatArg) == "AVG" + ber(xl) = mean(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,string(plotJob.channelplan),string(plotJob.dsp)),'all'); + linew = 2.0; + markersz = 3; + linestyle = ':'; + elseif string(plotJob.dataStatArg) == "Best" + ber(xl) = min(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,string(plotJob.channelplan),string(plotJob.dsp)),[],'all'); + linew = 2.0; + markersz = 3; + linestyle = ':'; + + elseif string(plotJob.dataStatArg) == "All Channels; mean(PMD Realizations)" + tmp = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,string(plotJob.channelplan),string(plotJob.dsp)); + + if numel(tmp(tmp==0)) ~= 0 + disp('Removed all zero values!'); + tmp(tmp==0) = NaN; + end + ber(:,xl) = mean(tmp,1,"omitnan").'; + + linew = 0.7; + markersz = 2; + linestyle = '-'; + + elseif string(plotJob.dataStatArg) == "All Channels ;All PMD Realizations" + + + + tmp = reshape(wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,string(plotJob.channelplan),string(plotJob.dsp)).',[],1); + ber(1:size(tmp,1),xl) = tmp; + + linew = 0.3; + markersz = 2; + linestyle = ':'; + end +end + +disp('Removed all zero values!'); +ber(ber==0) = NaN; +if ~anynan(ber) + [xAxis,ber] = interpCurve(xAxis, ber); +end + +% plot FEC Crossing as histogram + +hdfec = 3.8e-3.*ones(size(xAxis)); +S = []; +for i = 1:size(ber,1) + a = InterX([hdfec;xAxis],[ber(i,:);xAxis]); + if ~isempty(a) + S(:,i) = a; + end +end + + +%% SUB 1 +AxesMain = subplot(2,1,1); + +hold on + +if ~isempty(S) + histogram(S(end,:),300,'Normalization','probability','FaceColor',col,'EdgeColor',col,'Parent',AxesMain,'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname],'FaceAlpha',0.4,'EdgeAlpha',0.4); +end + +xlim([-3 ,9 ]); +ylim([0 .10]); + +% Figure Settings +title(AxesMain,['$P_{in}:$ ',num2str(plotJob.p_in-9), 'dBm; L : ', num2str(plotJob.l),'Km'],'Interpreter','latex'); + +xlabel(AxesMain,plotJob.xAxisLabel,'Interpreter','latex'); + +ylabel('PDF') + +grid(AxesMain,'on'); + +grid(AxesMain,'minor'); + +%legend(AxesMain,'Interpreter','latex'); + +fontsize(AxesMain,24,"pixels") + +hold off + + +%% SUB 2 +AxesMain = subplot(2,1,2); + +if ~isempty(S) +hold on + +[f1,x1]=ecdf(S(end,:)); + plot(x1,f1,'r','LineWidth',3, 'Color',col,'DisplayName',[plotJob.dataStatArg,' Ch.: ', plotJob.displayname]); +end +xlim([-3 ,9 ]); +ylim([0 1]); +% Figure Settings +title(AxesMain,['$P_{in}:$ ',num2str(plotJob.p_in-9), 'dBm; L : ', num2str(plotJob.l),'Km'],'Interpreter','latex'); + +xlabel(AxesMain,plotJob.xAxisLabel,'Interpreter','latex'); + +ylabel('CDF') + +grid(AxesMain,'on'); + +grid(AxesMain,'minor'); + +fontsize(AxesMain,24,"pixels") + +%legend(AxesMain,'Interpreter','latex'); + +fig.Position = plotJob.Position; + +hold off + + + end \ No newline at end of file diff --git a/Classes/Warehouse_class/functions/fwm_plots/plotViolin.m b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plotViolin.m similarity index 96% rename from Classes/Warehouse_class/functions/fwm_plots/plotViolin.m rename to Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plotViolin.m index 93cfc10..ebe24ad 100644 --- a/Classes/Warehouse_class/functions/fwm_plots/plotViolin.m +++ b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plotViolin.m @@ -1,206 +1,206 @@ -function plotViolin(wh,plotJob) - -fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName); - -if isvalid(fig) - figure(fig) - fig = get(fig); - AxesMain = fig.CurrentAxes; - hold on -else - fig = figure('name',char(plotJob.figName)); - AxesMain = gca; - hold on -end - -%% Violin -col = plotJob.color; - -% we want to fetch all realizations -if plotJob.pmd == 0 - realization = 1; -else - realization = wh.parameter.realization.values(1:end); -end - -%realization = 0:8; - -% get all xAxis values -xAxis = wh.parameter.p_out.values; - -% ber = NaN(500,16,10); -% zdw = NaN(500,1,10); - -%get BER values for query -for xl = 1:numel(xAxis) - p_out = xAxis(xl); - - curber = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); - curber= removeZeros(curber); - ber(1:size(curber,1),1:size(curber,2),xl) = curber; - -end - -% to remove outliers set the percentile range -% a = squeeze(mean(ber,2)); -% out = isoutlier(mean(a,2),"percentiles",[0 100]); -% ber = ber(~out,:,:); -% disp(sum(out)); - -hdfec = 3.8e-3.*ones(size(xAxis)); -S = []; -wavelength={}; - - -S = []; -S_chann = []; - -wl = calcWavelengthPlan(plotJob.ch,plotJob.channelspacing,1310); -%get fec thresholds -% [C,ia,ib] =intersect(linx,xAxis); -% linear = squeeze(linear); - -%ber(ber==0) = NaN; -S_chann_no_crossing = zeros(1,plotJob.ch); -for chann = 1:size(ber,2) - - for realiz = 1:size(ber,1) - - ber_series = squeeze(ber(realiz,chann,:)).'; - if mean(ber_series) > 0.1 - continue - end - - a = InterX([hdfec(:)';xAxis],[ber_series;xAxis]); - - if ~isempty(a) - S_chann(realiz,chann) = a(2); -% if a(2) > -7 && string(plotJob.pol) == "copolarized" -% continue -% end - S(end+1) = a(2); - wavelength{end+1} = num2str(wl(chann)); - else - S(end+1) = 0; - wavelength{end+1} = num2str(wl(chann)); - S_chann_no_crossing(realiz,chann) = 1; - S_chann(realiz,chann) = -1; - end - - end -end - -threshold = -6; -FEC_crossed = sum(S_chann < threshold & ~isnan(S_chann),1); -FEC_not_crossed = sum(S_chann >= threshold & ~isnan(S_chann),1); -failure_rate = FEC_not_crossed ./ (FEC_crossed + FEC_not_crossed) ; - - -S_chann(S_chann==0) = NaN; - -total_avg = mean(S_chann,"all","omitnan"); - -%figure(2024) -%C = flip(cbrewer2('Spectral',8)); -if numel(S) <= numel(wl) - vs = scatter(1:numel(S),S,50,'o','MarkerEdgeColor','black','MarkerFaceColor',plotJob.color,'LineWidth',1,'HandleVisibility','off'); - %vs = scatter(1,mean(S),50,'o','MarkerEdgeColor','black','MarkerFaceColor',plotJob.color,'LineWidth',1); - -else - - vs = violinplot(S,wavelength,... - 'ViolinColor',plotJob.color,... - 'ViolinAlpha',0.1,... - 'MarkerSize',1,... - 'ShowMedian',false,... - 'EdgeColor',plotJob.color,... - 'ShowWhiskers',false,... - 'ShowData',false,... - 'ShowBox',false,... - 'Bandwidth',0.051 ... - ); - - - hold on - - partly_failed = boolean(ceil(failure_rate)); - - avg = mean(S_chann,1,"omitnan"); - - notfailed = ~partly_failed .* avg; - notfailed(notfailed==0) = NaN; - scatter(1:size(S_chann,2),notfailed,10,'Marker','x','MarkerEdgeColor','black','MarkerFaceColor',plotJob.color,'LineWidth',0.5,'HandleVisibility','off'); - - - hold on - partly_failed = partly_failed.*avg; - partly_failed(partly_failed==0) = NaN; - s=scatter(1:numel(failure_rate),partly_failed,10,'Marker','x','LineWidth',0.5,'HandleVisibility','off','MarkerEdgeColor','red'); - s.DataTipTemplate.Interpreter = "latex"; - s.DataTipTemplate.DataTipRows(1).Label = "Fail Rate: "; - s.DataTipTemplate.DataTipRows(1).Value = failure_rate; - s.DataTipTemplate.DataTipRows(2) = []; - hold off -end - -% ax = gca; -% ax.XTicks - -hold on -yline(total_avg,'LineWidth',1,'LineStyle','--','DisplayName','System Avg.') -fig.Position = plotJob.Position; - -xticklabels(1:16); -ylabel('Penalty in dB'); -xlabel('Channel Number'); -ylim([-9.3,-3]); -xlim([0,plotJob.ch+1]); -% grid minor; -set(gca, 'color', 'none'); -legend = []; - -fontsize(AxesMain,8,"points") - -fig.Position = plotJob.Position; -fig.Units = "centimeters"; -fig.Position = [2 2 8.5 7]; - -set(AxesMain,'TickLabelInterpreter','latex') - -set(AxesMain.Legend,'Interpreter','latex') - - - -if 0 -ber_sorted = sort(S); - -z1 = []; -penalty = mean(ber_sorted):0.01:mean(ber_sorted)+2; - -for i = 1:length(penalty) - l = penalty(i); - if i == 1 - z1 = [z1 sum(ber_sorted(1,:)l-0.01) / length(ber_sorted) ]; - end - -end - -penalty_higherthan = 0.5; -probability = sum(z1(find(penalty>mean(ber_sorted)+penalty_higherthan))); -disp(['A penalty of more than 0.5 dB has a probability of: ', num2str(probability)]); -end - -end - - -function vec = removeZeros(vec) - % Find rows that contain only zeros - rows_to_remove = all(vec == 0, 2); - - % Remove rows with only zeros - vec(rows_to_remove, :) = []; - - +function plotViolin(wh,plotJob) + +fig = findall(groot, 'Type', 'figure', 'Name', plotJob.figName); + +if isvalid(fig) + figure(fig) + fig = get(fig); + AxesMain = fig.CurrentAxes; + hold on +else + fig = figure('name',char(plotJob.figName)); + AxesMain = gca; + hold on +end + +%% Violin +col = plotJob.color; + +% we want to fetch all realizations +if plotJob.pmd == 0 + realization = 1; +else + realization = wh.parameter.realization.values(1:end); +end + +%realization = 0:8; + +% get all xAxis values +xAxis = wh.parameter.p_out.values; + +% ber = NaN(500,16,10); +% zdw = NaN(500,1,10); + +%get BER values for query +for xl = 1:numel(xAxis) + p_out = xAxis(xl); + + curber = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw); + curber= removeZeros(curber); + ber(1:size(curber,1),1:size(curber,2),xl) = curber; + +end + +% to remove outliers set the percentile range +% a = squeeze(mean(ber,2)); +% out = isoutlier(mean(a,2),"percentiles",[0 100]); +% ber = ber(~out,:,:); +% disp(sum(out)); + +hdfec = 3.8e-3.*ones(size(xAxis)); +S = []; +wavelength={}; + + +S = []; +S_chann = []; + +wl = calcWavelengthPlan(plotJob.ch,plotJob.channelspacing,1310); +%get fec thresholds +% [C,ia,ib] =intersect(linx,xAxis); +% linear = squeeze(linear); + +%ber(ber==0) = NaN; +S_chann_no_crossing = zeros(1,plotJob.ch); +for chann = 1:size(ber,2) + + for realiz = 1:size(ber,1) + + ber_series = squeeze(ber(realiz,chann,:)).'; + if mean(ber_series) > 0.1 + continue + end + + a = InterX([hdfec(:)';xAxis],[ber_series;xAxis]); + + if ~isempty(a) + S_chann(realiz,chann) = a(2); +% if a(2) > -7 && string(plotJob.pol) == "copolarized" +% continue +% end + S(end+1) = a(2); + wavelength{end+1} = num2str(wl(chann)); + else + S(end+1) = 0; + wavelength{end+1} = num2str(wl(chann)); + S_chann_no_crossing(realiz,chann) = 1; + S_chann(realiz,chann) = -1; + end + + end +end + +threshold = -6; +FEC_crossed = sum(S_chann < threshold & ~isnan(S_chann),1); +FEC_not_crossed = sum(S_chann >= threshold & ~isnan(S_chann),1); +failure_rate = FEC_not_crossed ./ (FEC_crossed + FEC_not_crossed) ; + + +S_chann(S_chann==0) = NaN; + +total_avg = mean(S_chann,"all","omitnan"); + +%figure(2024) +%C = flip(cbrewer2('Spectral',8)); +if numel(S) <= numel(wl) + vs = scatter(1:numel(S),S,50,'o','MarkerEdgeColor','black','MarkerFaceColor',plotJob.color,'LineWidth',1,'HandleVisibility','off'); + %vs = scatter(1,mean(S),50,'o','MarkerEdgeColor','black','MarkerFaceColor',plotJob.color,'LineWidth',1); + +else + + vs = violinplot(S,wavelength,... + 'ViolinColor',plotJob.color,... + 'ViolinAlpha',0.1,... + 'MarkerSize',1,... + 'ShowMedian',false,... + 'EdgeColor',plotJob.color,... + 'ShowWhiskers',false,... + 'ShowData',false,... + 'ShowBox',false,... + 'Bandwidth',0.051 ... + ); + + + hold on + + partly_failed = boolean(ceil(failure_rate)); + + avg = mean(S_chann,1,"omitnan"); + + notfailed = ~partly_failed .* avg; + notfailed(notfailed==0) = NaN; + scatter(1:size(S_chann,2),notfailed,10,'Marker','x','MarkerEdgeColor','black','MarkerFaceColor',plotJob.color,'LineWidth',0.5,'HandleVisibility','off'); + + + hold on + partly_failed = partly_failed.*avg; + partly_failed(partly_failed==0) = NaN; + s=scatter(1:numel(failure_rate),partly_failed,10,'Marker','x','LineWidth',0.5,'HandleVisibility','off','MarkerEdgeColor','red'); + s.DataTipTemplate.Interpreter = "latex"; + s.DataTipTemplate.DataTipRows(1).Label = "Fail Rate: "; + s.DataTipTemplate.DataTipRows(1).Value = failure_rate; + s.DataTipTemplate.DataTipRows(2) = []; + hold off +end + +% ax = gca; +% ax.XTicks + +hold on +yline(total_avg,'LineWidth',1,'LineStyle','--','DisplayName','System Avg.') +fig.Position = plotJob.Position; + +xticklabels(1:16); +ylabel('Penalty in dB'); +xlabel('Channel Number'); +ylim([-9.3,-3]); +xlim([0,plotJob.ch+1]); +% grid minor; +set(gca, 'color', 'none'); +legend = []; + +fontsize(AxesMain,8,"points") + +fig.Position = plotJob.Position; +fig.Units = "centimeters"; +fig.Position = [2 2 8.5 7]; + +set(AxesMain,'TickLabelInterpreter','latex') + +set(AxesMain.Legend,'Interpreter','latex') + + + +if 0 +ber_sorted = sort(S); + +z1 = []; +penalty = mean(ber_sorted):0.01:mean(ber_sorted)+2; + +for i = 1:length(penalty) + l = penalty(i); + if i == 1 + z1 = [z1 sum(ber_sorted(1,:)l-0.01) / length(ber_sorted) ]; + end + +end + +penalty_higherthan = 0.5; +probability = sum(z1(find(penalty>mean(ber_sorted)+penalty_higherthan))); +disp(['A penalty of more than 0.5 dB has a probability of: ', num2str(probability)]); +end + +end + + +function vec = removeZeros(vec) + % Find rows that contain only zeros + rows_to_remove = all(vec == 0, 2); + + % Remove rows with only zeros + vec(rows_to_remove, :) = []; + + end \ No newline at end of file diff --git a/Classes/Warehouse_class/functions/fwm_plots/plot_ber_distribution.m b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plot_ber_distribution.m similarity index 96% rename from Classes/Warehouse_class/functions/fwm_plots/plot_ber_distribution.m rename to Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plot_ber_distribution.m index 1d43674..8abf21b 100644 --- a/Classes/Warehouse_class/functions/fwm_plots/plot_ber_distribution.m +++ b/Classes/Warehouse_class/functions/phase_predist_plots/fwm_plots/plot_ber_distribution.m @@ -1,58 +1,58 @@ - -%automate plots -% [file, path] = uigetfile("C:\Users\Silas\Documents\MATLAB\Raw_Cluster_Simulations\session_januar24\wh_complete_at_1310.mat"); -% wh = load([path filesep file]); -% wh = wh.wh; - -plotJob = struct(); - -plotJob.l = 10; -plotJob.ch = 16; -plotJob.d = 3; -plotJob.sgm = 1; -plotJob.pol = "copolarized"; -plotJob.p_in = 3; -plotJob.gamma = 0.0023; -plotJob.pmd = 0.1; -plotJob.channelspacing = 400e9; -plotJob.randzdw = 0; - -ber_per_chann = []; -% get all xAxis values -xAxis = wh.parameter.p_out.values; -realization = wh.parameter.realization.values(1:end); -% Fetch Data from Warehouse -for xl = 1:numel(xAxis) - p_out = xAxis(xl); - raw_fetch = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw).'; - - ber_per_chann(:,:,xl) = raw_fetch; -end -%% - -figure(2023); - -for ch = [1,floor(plotJob.ch/2),ceil(plotJob.ch/2)+1,plotJob.ch] %1:15:size(ber_per_chann,1) - - for p = 5%1:size(ber_per_chann,3) - - % Extract data for the current row - row_data = squeeze(ber_per_chann(ch,:,p)); - [f, xi] = ksdensity(row_data); - % Identify the peak point - [max_density, max_index] = max(f); - peak_x = xi(max_index); - - end - % Create a histogram plot for the current row with a unique color - plot(xi, f, 'LineWidth', 2, 'DisplayName', ['Ch. ', num2str(ch)],'LineStyle','--'); - %histogram(row_data,100, 'DisplayName', ['Channel ', num2str(ch)], 'EdgeColor', 'none'); - - hold on; % Hold the plot for the next iteration - text(peak_x, max_density, ['Ch ', num2str(ch)], 'VerticalAlignment', 'bottom', 'HorizontalAlignment', 'left'); -end - - -legend show - + +%automate plots +% [file, path] = uigetfile("C:\Users\Silas\Documents\MATLAB\Raw_Cluster_Simulations\session_januar24\wh_complete_at_1310.mat"); +% wh = load([path filesep file]); +% wh = wh.wh; + +plotJob = struct(); + +plotJob.l = 10; +plotJob.ch = 16; +plotJob.d = 3; +plotJob.sgm = 1; +plotJob.pol = "copolarized"; +plotJob.p_in = 3; +plotJob.gamma = 0.0023; +plotJob.pmd = 0.1; +plotJob.channelspacing = 400e9; +plotJob.randzdw = 0; + +ber_per_chann = []; +% get all xAxis values +xAxis = wh.parameter.p_out.values; +realization = wh.parameter.realization.values(1:end); +% Fetch Data from Warehouse +for xl = 1:numel(xAxis) + p_out = xAxis(xl); + raw_fetch = wh.getStoValue('ber',plotJob.l,plotJob.d,plotJob.sgm,string(plotJob.pol),plotJob.p_in,p_out,plotJob.pmd,plotJob.gamma,realization,plotJob.ch,1310,plotJob.channelspacing,plotJob.randzdw).'; + + ber_per_chann(:,:,xl) = raw_fetch; +end +%% + +figure(2023); + +for ch = [1,floor(plotJob.ch/2),ceil(plotJob.ch/2)+1,plotJob.ch] %1:15:size(ber_per_chann,1) + + for p = 5%1:size(ber_per_chann,3) + + % Extract data for the current row + row_data = squeeze(ber_per_chann(ch,:,p)); + [f, xi] = ksdensity(row_data); + % Identify the peak point + [max_density, max_index] = max(f); + peak_x = xi(max_index); + + end + % Create a histogram plot for the current row with a unique color + plot(xi, f, 'LineWidth', 2, 'DisplayName', ['Ch. ', num2str(ch)],'LineStyle','--'); + %histogram(row_data,100, 'DisplayName', ['Channel ', num2str(ch)], 'EdgeColor', 'none'); + + hold on; % Hold the plot for the next iteration + text(peak_x, max_density, ['Ch ', num2str(ch)], 'VerticalAlignment', 'bottom', 'HorizontalAlignment', 'left'); +end + + +legend show + %% \ No newline at end of file diff --git a/Datatypes/equalizer_structure.m b/Datatypes/equalizer_structure.m index c8250a6..b94e0c0 100644 --- a/Datatypes/equalizer_structure.m +++ b/Datatypes/equalizer_structure.m @@ -8,6 +8,7 @@ classdef equalizer_structure < int32 % db_precoded (3) vnle_db_mlse (4) db_encoded (5) + ml_mlse (6) end end \ No newline at end of file diff --git a/Functions/EQ_structures/dsp_runid.m b/Functions/EQ_structures/dsp_runid.m index 1a20686..976bcfa 100644 --- a/Functions/EQ_structures/dsp_runid.m +++ b/Functions/EQ_structures/dsp_runid.m @@ -13,14 +13,13 @@ arguments end try - - % Initialize output structures output.ffe_package = {}; output.mlse_package = {}; output.vnle_package = {}; output.dbtgt_package = {}; output.dbenc_package = {}; + output.mlmlse_package = {}; if options.mode == "load_run_id" || options.append_to_db % Initialize database connection @@ -98,9 +97,10 @@ try use_ffe = 0; use_dfe = 0; - use_vnle_mlse = 1; + use_vnle_mlse = 0; use_dbtgt = 0; use_dbenc = 0; + use_ml_mlse = 1; addProcessingResultToDatabase = 0; @@ -130,7 +130,7 @@ try mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels); eq_post = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",2001,"sps",1,"decide",0,"adaption_technique","lms"); - eq_post =FFE("epochs_tr",5,"epochs_dd",2,"len_tr",2^13,"mu_dd",mu_dd,"mu_tr",mu_tr,"order",25,"sps",2,"decide",0, "adaption",adaption_method(adaption),"dd_mode",use_dd_mode); + eq_post = FFE("epochs_tr",5,"epochs_dd",2,"len_tr",2^13,"mu_dd",mu_dd,"mu_tr",mu_tr,"order",25,"sps",2,"decide",0, "adaption",adaption_method(adaption),"dd_mode",use_dd_mode); % Duobinary signaling (db encoded) mlse_db_enc = MLSE("DIR", [1,1], "duobinary_output", 0, "M", M, "trellis_states", PAMmapper(M,0).levels); eq_db_enc = EQ("Ne", ffe_order, "Nb", dfe_order, "training_length", len_tr, ... @@ -233,30 +233,25 @@ try database.addProcessingResult(run_id, ffe_results.metrics, ffe_results.config); end - % pf_ncoeffs = 2; - % eq_ = EQ("Ne",ffe_order,"Nb",dfe_order,"training_length",len_tr,"training_loops",5,"dd_loops",5,"K",2,"DCmu",mu_dc,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); - % pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1); - % % mlse_ = MLSE_viterbi("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels); - % mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels); - % - % [ffe_results, mlse_results] = vnle_postfilter_mlse(eq_, pf_, mlse_, M, Scpe_sig, Symbols, Tx_bits, ... - % "precode_mode", duob_mode,... - % 'showAnalysis', 0, ... - % "postFFE", [],... - % "eth_style_symbol_mapping", 0); - % - % ffe_results.metrics.print; - % mlse_results.metrics.print; - % - % output.mlse_package{r} = mlse_results; - % output.vnle_package{r} = ffe_results; - % - % if options.append_to_db - % database.addProcessingResult(run_id, mlse_results.metrics, mlse_results.config); - % database.addProcessingResult(run_id, ffe_results.metrics, ffe_results.config); - % end + end + + if use_ml_mlse + + %ML-based MLSE (L=2) + mu_ml = 0.01; training_epochs = 250; + ml_mlse_equalizer = ML_MLSE("epochs_tr",training_epochs,"epochs_dd",1, ... + "len_tr",length(Scpe_sig),"mu_dd",mu_ml,"mu_tr",mu_ml,"order",11,"sps",2, ... + "traceback_depth",128,"L",2,"delta",4,"adaptive_mu",0); + + [ml_mlse_results] = ml_mlse(ml_mlse_equalizer, M, Scpe_sig, Symbols, Tx_bits,"precode_mode",duob_mode); + output.mlmlse_package{r} = ml_mlse_results; + + if options.append_to_db + database.addProcessingResult(run_id, ml_mlse_results.metrics, ml_mlse_results.config); + end end + if use_dbtgt @@ -292,6 +287,7 @@ try if duob_mode == db_mode.db_encoded + mlse_db_enc = MLSE_viterbi("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels); db_results = duobinary_signaling(eq_db_enc, mlse_db_enc, M, Scpe_sig, Symbols, Tx_bits, "precode_mode",duob_mode, "showAnalysis",0,"postFFE",[]); output.dbenc_package{r} = db_results; if options.append_to_db diff --git a/Functions/EQ_structures/duobinary_signaling.m b/Functions/EQ_structures/duobinary_signaling.m index e47bc19..c484918 100644 --- a/Functions/EQ_structures/duobinary_signaling.m +++ b/Functions/EQ_structures/duobinary_signaling.m @@ -36,8 +36,9 @@ if ~isempty(options.postFFE) end % Process through MLSE -% [mlse_signal] = mlse_.process(eq_signal); -[mlse_signal,~,GMI_MLSE] = mlse_.process(eq_signal,tx_symbols); +[mlse_signal] = mlse_.process(eq_signal); +% tx_symbols_ = Duobinary().decode(tx_symbols); +% [mlse_signal,~,GMI_MLSE] = mlse_.process(eq_signal,tx_symbols); % Apply duobinary encoding and decoding mlse_signal = Duobinary().encode(mlse_signal); diff --git a/Functions/EQ_structures/ml_mlse.m b/Functions/EQ_structures/ml_mlse.m new file mode 100644 index 0000000..abd3aa0 --- /dev/null +++ b/Functions/EQ_structures/ml_mlse.m @@ -0,0 +1,113 @@ +function [ml_mlse_results] = ml_mlse(eq_, M, rx_signal, tx_symbols, tx_bits, options) +% +% +% Inputs: +% eq_ - Equalizer object +% M - Modulation order +% rx_signal - Received signal +% tx_symbols - Transmitted symbols +% tx_bits - Transmitted bits +% options - Optional parameters +% +% Outputs: +% ffe_results - Results from FFE processing + +arguments + eq_ + M + rx_signal + tx_symbols + tx_bits + options.precode_mode db_mode + options.eth_style_symbol_mapping = 0; + options.postFFE = []; + +end + +%% Process signals through equalizer + +[eq_signal_hd,y_ref] = eq_.process(rx_signal,tx_symbols); + +%% Calculate BER based on precoding mode +[bits, errors, ber, error_pos, errors_precoded, ber_precoded] = calculateBER(eq_signal_hd, tx_symbols, tx_bits, options.precode_mode, M, options.eth_style_symbol_mapping); + + +% Create FFE results structure +ml_mlse_results = struct(); +try + eq_.e = []; + eq_.e2 = []; + eq_.e3 = []; + eq_.b = []; + eq_.b2 = []; + eq_.b3 = []; +end + +ml_mlse_results.config = Equalizerstruct(); +ml_mlse_results.config.eq = jsonencode(eq_); +ml_mlse_results.config.equalizer_structure = int32(equalizer_structure.ml_mlse); +ml_mlse_results.config.comment = 'function: ML-based MLSE'; + +ml_mlse_results.metrics = Metricstruct; +ml_mlse_results.metrics.result_id = NaN; +ml_mlse_results.metrics.run_id = NaN; +ml_mlse_results.metrics.eqParam_id = NaN; +ml_mlse_results.metrics.date_of_processing = datetime('now'); +ml_mlse_results.metrics.BER = ber; +ml_mlse_results.metrics.numBits = bits; +ml_mlse_results.metrics.numBitErr = errors; +ml_mlse_results.metrics.BER_precoded = ber_precoded; +ml_mlse_results.metrics.numBitErr_precoded = errors_precoded; +ml_mlse_results.metrics.SNR = NaN; +ml_mlse_results.metrics.SNR_level = NaN; +ml_mlse_results.metrics.STD = NaN; +ml_mlse_results.metrics.STD_level = NaN; +ml_mlse_results.metrics.STDrx = NaN; +ml_mlse_results.metrics.STDrx_level = NaN; +ml_mlse_results.metrics.GMI = NaN; +ml_mlse_results.metrics.AIR = NaN; +ml_mlse_results.metrics.EVM = NaN; +ml_mlse_results.metrics.EVM_level = NaN; +ml_mlse_results.metrics.Alpha = NaN; + + +end + +%% Helper Functions +function [bits, errors, ber, error_pos, errors_precoded, ber_precoded] = calculateBER(eq_signal_hd, tx_symbols, tx_bits, precode_mode, M, eth_style) +% Calculate BER based on precoding mode +mapper = PAMmapper(M, 0, "eth_style", eth_style); + +switch precode_mode + case db_mode.no_db + % TX Data is not precoded + % A) Emulate diff precoding + eq_signal_hd_precoded = Duobinary().encode(eq_signal_hd, "M", M); + eq_signal_hd_precoded = Duobinary().decode(eq_signal_hd_precoded, "M", M); + + tx_symbols_precoded = Duobinary().encode(tx_symbols); + tx_symbols_precoded = Duobinary().decode(tx_symbols_precoded); + + tx_bits_precoded = mapper.demap(tx_symbols_precoded); + + rx_bits = mapper.demap(eq_signal_hd_precoded); + [~, errors_precoded, ber_precoded, ~] = calc_ber(rx_bits.signal, tx_bits_precoded.signal, "skip_front", 30000, "skip_end", 150, "returnErrorLocation", 1); + + % B) Just determine BER + rx_bits = mapper.demap(eq_signal_hd); + [bits, errors, ber, error_pos] = calc_ber(rx_bits.signal, tx_bits.signal, "skip_front", 30000, "skip_end", 150, "returnErrorLocation", 1); + + case db_mode.db_precoded + % Data is precoded on TX side + % A) Decode at Rx if no DB targeting was applied + eq_signal_hd_decoded = Duobinary().encode(eq_signal_hd, "M", M); + eq_signal_hd_decoded = Duobinary().decode(eq_signal_hd_decoded, "M", M); + rx_bits_decoded = mapper.demap(eq_signal_hd_decoded); + [~, errors_precoded, ber_precoded, ~] = calc_ber(rx_bits_decoded.signal, tx_bits.signal, "skip_front", 30000, "skip_end", 150, "returnErrorLocation", 1); + + % B) Omit the Coding by comparing with demapped TX symbol sequence + tx_bits_demapped = mapper.demap(tx_symbols); + rx_bits = mapper.demap(eq_signal_hd); + [bits, errors, ber, error_pos] = calc_ber(rx_bits.signal, tx_bits_demapped.signal, "skip_front", 30000, "skip_end", 150, "returnErrorLocation", 1); +end +end diff --git a/Functions/Job_Processing/configureEqualizers_remove.m b/Functions/Job_Processing/configureEqualizers_remove.m deleted file mode 100644 index f207088..0000000 --- a/Functions/Job_Processing/configureEqualizers_remove.m +++ /dev/null @@ -1,40 +0,0 @@ -function [eq_, pf_, mlse_, mlse_db_, eq_post] = configureEqualizers(M, len_tr, vnle_order, dfe_order, mu_dc, mu_ffe, mu_dfe, pf_ncoeffs) - % CONFIGUREEQUALIZERS Creates and configures equalizer objects - % - % Inputs: - % M - PAM level - % len_tr - Training length - % vnle_order - Array with orders for VNLE [order1, order2, order3] - % dfe_order - Array with orders for DFE - % mu_dc - DC adaptation rate - % mu_ffe - Array with adaptation rates for FFE [mu1, mu2, mu3] - % mu_dfe - Adaptation rate for DFE - % pf_ncoeffs - Number of coefficients for postfilter - % - % Outputs: - % eq_ - Configured EQ object - % pf_ - Configured Postfilter object - % mlse_ - Configured MLSE_viterbi object - % mlse_db_ - Configured MLSE_viterbi object for duobinary - % eq_post - Configured FFE object for post-processing - - % Configure main equalizer - eq_ = EQ("Ne", vnle_order, "Nb", dfe_order, ... - "training_length", len_tr, "training_loops", 5, "dd_loops", 5, ... - "K", 2, "DCmu", mu_dc, "DDmu", [mu_ffe mu_dfe], ... - "DFEmu", 0.005, "FFEmu", 0, "plotfinal", 0, "ideal_dfe", 1); - - % Configure postfilter - pf_ = Postfilter("ncoeff", pf_ncoeffs, "useBurg", 1); - - % Configure MLSE objects - mlse_ = MLSE_viterbi("duobinary_output", 0, 'M', M, ... - 'trellis_states', PAMmapper(M,0).levels); - mlse_db_ = MLSE_viterbi("DIR", [1,1], "duobinary_output", 0, ... - "M", M, "trellis_states", PAMmapper(M,0).levels); - - % Configure post-FFE - eq_post = FFE("epochs_tr", 5, "epochs_dd", 5, "len_tr", 4096*2, ... - "mu_dd", 1e-4, "mu_tr", 0, "order", 2001, ... - "sps", 1, "decide", 0); - end \ No newline at end of file diff --git a/Functions/Job_Processing/preprocessSignal.m b/Functions/Job_Processing/preprocessSignal.m index 8725ed3..4828bba 100644 --- a/Functions/Job_Processing/preprocessSignal.m +++ b/Functions/Job_Processing/preprocessSignal.m @@ -16,9 +16,9 @@ Scpe_sig = Scpe_sig.resample("fs_out", 2*fsym); [Scpe_sig, ~] = Scpe_sig.tsynch("reference", Symbols, "fs_ref", fsym, "debug_plots", 0); % Apply Gaussian filter -% Scpe_sig = Filter('filtdegree', 4, "f_cutoff", Symbols.fs.*0.6, ... -% "fs", Scpe_sig.fs, "filterType", filtertypes.gaussian, ... -% "active", true).process(Scpe_sig); +Scpe_sig = Filter('filtdegree', 4, "f_cutoff", Symbols.fs.*0.6, ... + "fs", Scpe_sig.fs, "filterType", filtertypes.gaussian, ... + "active", true).process(Scpe_sig); % Remove DC offset Scpe_sig = Scpe_sig - mean(Scpe_sig.signal); diff --git a/Functions/Job_Processing/submitJobs.m b/Functions/Job_Processing/submitJobs.m index 321032a..5826814 100644 --- a/Functions/Job_Processing/submitJobs.m +++ b/Functions/Job_Processing/submitJobs.m @@ -209,6 +209,7 @@ wh = submit_options.wh; wh.addValueToStorageByLinIdx(val.vnle_package, 'vnle_package', jobIndex); wh.addValueToStorageByLinIdx(val.dbtgt_package,'dbtgt_package',jobIndex); wh.addValueToStorageByLinIdx(val.dbenc_package,'dbenc_package',jobIndex); + wh.addValueToStorageByLinIdx(val.mlmlse_package,'mlmlse_package',jobIndex); end end function p = setupParallelPool(numWorkers, idleTimeout) diff --git a/Functions/beautifyBERplot.m b/Functions/beautifyBERplot.m index 1a4f953..2d70cee 100644 --- a/Functions/beautifyBERplot.m +++ b/Functions/beautifyBERplot.m @@ -1,43 +1,97 @@ function beautifyBERplot(options) +% BEAUTIFYBERPLOT Enhances BER-style plots for publication-quality figures. +% Supports automatic smoothing and trend-line overlay. +% +% Usage examples: +% beautifyBERplot; % default +% beautifyBERplot("polyfit",1); % add polynomial fit +% beautifyBERplot("polyfit",1,"fitmethod","pchip") % piecewise cubic fit +% +% Supported fitmethod options: 'polyfit', 'smoothingspline', 'loess', 'pchip' + arguments - options.logscale = 1 + options.logscale (1,1) logical = 1 + options.polyfit (1,1) logical = 0 + options.polyorder (1,1) double = 2 + options.fitmethod (1,1) string = "polyfit" % choose fit type end - % BEAUTIFYBERPLOT Enhances a BER plot for publication-quality figures. - % Set line properties for all current plot lines - lines = findall(gca, 'Type', 'Line'); - markers = {'o', 's', 'd', '^', 'v', '>', '<', 'p', 'h'}; % Define marker styles - num_markers = length(markers); - +% --- find all line objects in current axes +lines = findall(gca, 'Type', 'Line'); +markers = {'o', 's', 'd', '^', 'v', '>', '<', 'p', 'h'}; +num_markers = length(markers); + +% --- style all lines consistently +for i = 1:length(lines) + lines(i).LineWidth = 1.1; + lines(i).LineStyle = '-'; + if string(lines(i).Marker) == "none" + lines(i).Marker = markers{mod(i-1, num_markers) + 1}; + end + lines(i).MarkerSize = 4; + lines(i).MarkerFaceColor = lines(i).Color; +end + +% --- optional smoothing/fitting overlay +if options.polyfit + hold on for i = 1:length(lines) - lines(i).LineWidth = 1.3; % Thicker line width - lines(i).LineStyle = '-'; % Solid lines for simplicity - if string(lines(i).Marker) == "none" - lines(i).Marker = markers{mod(i-1, num_markers) + 1}; % Assign markers cyclically + x = lines(i).XData; + y = lines(i).YData; + valid = isfinite(x) & isfinite(y); + if sum(valid) < options.polyorder + 1 + continue; end - lines(i).MarkerSize = 7; % Marker size - lines(i).MarkerFaceColor = lines(i).Color; % Use line color for marker face - lines(i).MarkerEdgeColor = 'white'; + + xf = linspace(min(x(valid)), max(x(valid)), 200); + + % ----- choose fitting method ----- + switch lower(options.fitmethod) + case "polyfit" + p = polyfit(x(valid), y(valid), options.polyorder); + yf = polyval(p, xf); + + case "smoothingspline" + try + f = fit(x(valid)', y(valid)', 'smoothingspline'); + yf = feval(f, xf); + catch + yf = interp1(x(valid), y(valid), xf, 'pchip'); + end + + case "loess" + yf = smooth(x(valid), y(valid), 0.2, 'loess'); + yf = interp1(x(valid), yf, xf, 'linear', 'extrap'); + + case "pchip" + yf = interp1(x(valid), y(valid), xf, 'pchip'); + + otherwise + warning('Unknown fitmethod "%s". Using polyfit.', options.fitmethod); + p = polyfit(x(valid), y(valid), options.polyorder); + yf = polyval(p, xf); + end + + % --- lightened color for fit overlay + lightcol = lines(i).Color + 0.4 * (1 - lines(i).Color); + lightcol(lightcol > 1) = 1; + + plot(xf, yf, '-', 'Color', lightcol, ... + 'LineWidth', 0.7, 'Marker', 'none', ... + 'HandleVisibility','off'); end - - % Change all text interpreters to LaTeX - set(findall(gca, '-property', 'Interpreter'), 'Interpreter', 'latex'); - - % Set figure background to white - set(gcf, 'Color', 'w'); - - - % Set logarithmic scale for y-axis, but only if it makes sense. - % If this is not always desired, you could condition this on the presence of lines or data. - if options.logscale - set(gca, 'YScale', 'log'); - end - - % Customize grid and box appearance - set(gca, 'Box', 'on', 'LineWidth', 0.8); % Thicker border - grid on; - % grid minor; - - % Adjust font size and style for better readability - set(gca, 'FontSize', 10, 'FontName', 'Times New Roman'); + hold off +end + +% --- axis scaling and cosmetics +if options.logscale + set(gca, 'YScale', 'log'); +end + +set(findall(gca, '-property', 'Interpreter'), 'Interpreter', 'latex'); +set(gcf, 'Color', 'w'); +set(gca, 'Box', 'on', 'LineWidth', 0.8); +grid on; +set(gca, 'FontSize', 10, 'FontName', 'Times New Roman'); + end diff --git a/projects/HighSpeedExperiment_2024/Auswertung_JLT/ber_vs_dispersion.m b/projects/HighSpeedExperiment_2024/Auswertung_JLT/ber_vs_dispersion.m index 447daac..9c0d120 100644 --- a/projects/HighSpeedExperiment_2024/Auswertung_JLT/ber_vs_dispersion.m +++ b/projects/HighSpeedExperiment_2024/Auswertung_JLT/ber_vs_dispersion.m @@ -20,7 +20,7 @@ fp.where('Runs', 'rop_attenuation','EQUALS', 0); fields = db.getTableFieldNames('power_state_info'); -fields = [fields; db.getTableFieldNames('dashboard_ungrouped')]; +fields = [fields; db.getTableFieldNames('dashboard_ungrouped_new')]; [dataTable,~] = db.queryDB(fp, fields); eqstructures = unique(dataTable.equalizer_structure); diff --git a/projects/HighSpeedExperiment_2024/Auswertung_JLT/plot_measurements_gpt.m b/projects/HighSpeedExperiment_2024/Auswertung_JLT/plot_measurements_gpt.m index 0b5cefd..d0b95a1 100644 --- a/projects/HighSpeedExperiment_2024/Auswertung_JLT/plot_measurements_gpt.m +++ b/projects/HighSpeedExperiment_2024/Auswertung_JLT/plot_measurements_gpt.m @@ -41,7 +41,9 @@ plotdefs = struct( ... 'legendLocation' , 'best', ... 'fecLineWidth' , 2.2, ... % thicker FEC limits 'fecColor' , [0.25 0.25 0.25], ... - 'capSize' , 6 ... + 'capSize' , 6, ... + 'lineStyle_default' , '-', ... + 'use_pre_emph_styling' , true ... ); cfg.plot = filldefaults(cfg.plot, plotdefs); @@ -131,8 +133,23 @@ for gi = 1:nG yu = yu(ord); ylo = ylo(ord); yhi = yhi(ord); % Styles - pre = logical(grpTbl.pre_emph(gi)); - ls = tern(pre, cfg.plot.lineStyle_pre_emph_on, cfg.plot.lineStyle_pre_emph_off); + % Decide if we style by pre_emph + canStyleByPre = cfg.plot.use_pre_emph_styling && ismember('pre_emph', T.Properties.VariableNames); + + if canStyleByPre + if any(strcmp(group_by,'pre_emph')) + % pre_emph is an explicit grouping key -> take it from the group table + pre = logical(grpTbl.pre_emph(gi)); + else + % pre_emph not grouped, but available in the rows -> infer from the members of this group + pre = logical(mode(T.pre_emph(G==gi))); + end + ls = tern(pre, cfg.plot.lineStyle_pre_emph_on, cfg.plot.lineStyle_pre_emph_off); + else + % no pre-emph styling → use a single default style + ls = cfg.plot.lineStyle_default; + end + lbl = buildLabel(grpTbl(gi,:), group_by); % Main line (dark) diff --git a/projects/HighSpeedExperiment_2024/Auswertung_JLT/run_dsp_from_db.m b/projects/HighSpeedExperiment_2024/Auswertung_JLT/run_dsp_from_db.m index ff9eac0..212a72f 100644 --- a/projects/HighSpeedExperiment_2024/Auswertung_JLT/run_dsp_from_db.m +++ b/projects/HighSpeedExperiment_2024/Auswertung_JLT/run_dsp_from_db.m @@ -1,6 +1,6 @@ % === SETTINGS === dsp_options.append_to_db = 1; -dsp_options.max_occurences = 15; +dsp_options.max_occurences = 2; experiment = "highspeed_2024"; dsp_options.mode = "load_run_id"; % 'simulate' & 'load_files' @@ -42,16 +42,16 @@ fp = QueryFilter(); % fp.where('Runs', 'run_id','EQUALS', 987); M = 4; fp.where('Runs', 'pam_level','EQUALS', M); -fp.where('Runs', 'bitrate','EQUALS', 420e9);%360,390 -% fp.where('Runs', 'symbolrate','EQUALS', 162e9); -fp.where('Runs', 'fiber_length','EQUALS', 2); +fp.where('Runs', 'bitrate','EQUALS', 300e9);%360,390 +% fp.where('Runs', 'symbolrate','EQUALS', 195e9); +% fp.where('Runs', 'fiber_length','EQUALS', 1); fp.where('Runs', 'is_mpi','EQUALS', 0); % fp.where('Runs', 'interference_path_length','EQUALS', 1000); % fp.where('Runs', 'loop_id','GREATER_THAN', 11); % fp.where('Runs', 'sir','EQUALS',18); fp.where('Runs', 'wavelength','EQUAL', 1310); -fp.where('Runs', 'db_mode','EQUALS', 0); -fp.where('Runs', 'rop_attenuation','EQUAL', 0); +fp.where('Runs', 'db_mode','EQUALS', 1); +% fp.where('Runs', 'rop_attenuation','EQUAL', 0); % fp.where('Runs', 'power_pd_in','GREATER_THAN', 7); [dataTable,~] = db.queryDB(fp, db.getTableFieldNames('Runs')); @@ -66,15 +66,41 @@ wh.addStorage("mlse_package"); wh.addStorage("vnle_package"); wh.addStorage("dbtgt_package"); wh.addStorage("dbenc_package"); +wh.addStorage("mlmlse_package"); -% === RUN IT === +%% === RUN IT === [results,wh] = submitJobs(dataTable.run_id(:), dsp_options, "serial", 'wh', wh, 'waitbar', true); +%% results_db = results(dataTable.db_mode==1); results_nodb = results(dataTable.db_mode==0); -for i = 1:numel(results_db) +%BER for ML based MLSE +for i = 1:length(results_db) + ber_m = cellfun(@(c) c.metrics.BER_precoded, results_db{1,i}.mlmlse_package); + [BER_MLMLSE_pre_emph(i), ~] = min(ber_m); + + ber_m = cellfun(@(c) c.metrics.BER_precoded, results_nodb{1,i}.mlmlse_package); + [BER_MLMLSE(i), ~] = min(ber_m); + + ber_m = cellfun(@(c) c.metrics.BER_precoded, results_nodb{1,i}.mlmlse_package); + [BER_MLMLSE(i), ~] = min(ber_m); + + baudrate(i) = dataTable.symbolrate(i); + rop_db(i) = dataTable.power_rop((2*i)-1); +end + +figure(11);hold on +plot(sort(rop_db),sort(BER_MLMLSE_pre_emph)) +plot(sort(rop_db),sort(BER_MLMLSE)) +beautifyBERplot + +%% +results_db = results(dataTable.db_mode==1); +results_nodb = results(dataTable.db_mode==0); + +for i = 1:numel(results_nodb) % VNLE (from results_nodb) gmi_v = cellfun(@(c) c.metrics.GMI, results_nodb{1,i}.vnle_package); @@ -89,9 +115,9 @@ for i = 1:numel(results_db) idx_air_max_vnle(i) = find(air_v == max(air_v), 1); % MLSE (from results_db) - gmi_m = cellfun(@(c) c.metrics.GMI, results_nodb{1,i}.mlse_package); + gmi_m = cellfun(@(c) c.metrics.GMI, results_db{1,i}.mlse_package); ber_m = cellfun(@(c) c.metrics.BER, results_nodb{1,i}.mlse_package); - air_m = cellfun(@(c) c.metrics.AIR, results_nodb{1,i}.mlse_package); + air_m = cellfun(@(c) c.metrics.AIR, results_db{1,i}.mlse_package); [BER_MLSE(i), idx_ber] = min(ber_m); GMI_MLSE(i) = gmi_m(idx_ber); AIR_MLSE(i) = air_m(idx_ber); @@ -111,11 +137,22 @@ for i = 1:numel(results_db) idx_gmi_min_db(i) = find(gmi_db == min(gmi_db), 1); idx_air_max_db(i) = find(air_db == max(air_db), 1); + %BER for ML based MLSE + ber_m = cellfun(@(c) c.metrics.BER, results_nodb{1,i}.mlmlse_package); + [BER_MLMLSE(i), idx_ber] = min(ber_m); + ber_m = cellfun(@(c) c.metrics.BER_precoded, results_db{1,i}.mlmlse_package); + [BER_MLMLSE_PREC(i), idx_ber] = min(ber_m); + % metadata bitrate(i) = dataTable.bitrate(i); baudrate(i) = dataTable.symbolrate(i); + rop_atten(i) = dataTable.rop_attenuation(2*i); + rop_pre(i) = dataTable.power_rop((2*i)-1); + rop(i) = dataTable.power_rop((2*i)); end + +%% STYLE_BASE = 2; % adjust this single number to scale markers & lines MARKER_SIZE = STYLE_BASE; % marker size (MATLAB MarkerSize) LINE_WIDTH = max(2, STYLE_BASE/3); % line width (keeps lines reasonable when STYLE_BASE large) @@ -128,6 +165,7 @@ cm.VNLE = cols(1 + d, :); cm.MLSE = cols(2 + d, :); cm.DB_precode = cols(3 + d, :); cm.DB = cols(4 + d, :); % duobinary +cm.ML_MLSE = cols(6 + d, :); % prepare x values in GBd xGHz = baudrate .* 1e-9; @@ -139,7 +177,7 @@ mk.VNLE = {'Marker','o','MarkerFaceColor',cm.VNLE,'MarkerEdgeColor',cm.VNLE,' mk.MLSE = {'Marker','*','MarkerFaceColor',cm.MLSE,'MarkerEdgeColor',cm.MLSE,'MarkerSize',MARKER_SIZE}; mk.DB_precode = {'Marker','^','MarkerFaceColor',cm.DB_precode,'MarkerEdgeColor',cm.DB_precode,'MarkerSize',MARKER_SIZE}; mk.DB = {'Marker','d','MarkerFaceColor',cm.DB,'MarkerEdgeColor',cm.DB,'MarkerSize',MARKER_SIZE}; - +mk.ML_MLSE = {'Marker','^','MarkerFaceColor',cm.ML_MLSE,'MarkerEdgeColor',cm.ML_MLSE,'MarkerSize',MARKER_SIZE}; % ---------------- FIGURE : BER ---------------- figure(112+M); clf; hold on; @@ -149,20 +187,100 @@ plot(xGHz, BER_VNLE, ... plot(xGHz, BER_MLSE, ... 'DisplayName','MLSE', ... mk.MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE); -plot(xGHz, BER_DB, ... - 'DisplayName','DB tgt.', ... - mk.DB{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.DB); plot(xGHz, BER_DB_PREC, ... 'DisplayName','Diff. Precode + DB tgt.', ... - mk.DB{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.DB); + mk.DB{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.DB); +plot(xGHz, BER_MLMLSE_PREC, ... + 'DisplayName','ML-based MLSE (L=2)', ... + mk.ML_MLSE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.ML_MLSE); + +yline(2e-2,'LineWidth',1,'HandleVisibility','off'); yline(4.85e-3,'LineWidth',1,'HandleVisibility','off'); yline(2.2e-4,'LineWidth',1,'HandleVisibility','off'); xlabel('Baudrate in GBd'); ylabel('BER'); set(gca, 'yscale', 'log'); -set(gca, 'XTick', xticks_vals(1:2:end), 'XTickLabel', xtick_labels(1:2:end)); +set(gca, 'XTick', xticks_vals(1:end), 'XTickLabel', xtick_labels(1:end)); grid on; legend('Location','best'); +beautifyBERplot + + + +%% +%% +STYLE_BASE = 2; % adjust this single number to scale markers & lines +MARKER_SIZE = STYLE_BASE; % marker size (MATLAB MarkerSize) +LINE_WIDTH = max(2, STYLE_BASE/3); % line width (keeps lines reasonable when STYLE_BASE large) + +% --- color map / method -> color assignment (keeps colors consistent) --- +cols = cbrewer2('Paired',8); +cols = linspecer(6); +d = 0; +cm.VNLE = cols(1 + d, :); +cm.MLSE = cols(2 + d, :); +cm.DB_precode = cols(3 + d, :); +cm.DB = cols(4 + d, :); % duobinary +cm.ML_MLSE = cols(6 + d, :); + +% prepare x values in GBd +xdbm = flip(sort(rop)); +xticks_vals = xdbm; +xtick_labels = arrayfun(@(v) sprintf('%d', round(v)), xticks_vals, 'UniformOutput', false); + +% common marker settings (filled, same face+edge color) +mk.VNLE = {'Marker','o','MarkerFaceColor',cm.VNLE,'MarkerEdgeColor',cm.VNLE,'MarkerSize',MARKER_SIZE}; +mk.MLSE = {'Marker','*','MarkerFaceColor',cm.MLSE,'MarkerEdgeColor',cm.MLSE,'MarkerSize',MARKER_SIZE}; +mk.DB_precode = {'Marker','^','MarkerFaceColor',cm.DB_precode,'MarkerEdgeColor',cm.DB_precode,'MarkerSize',MARKER_SIZE}; +mk.DB = {'Marker','d','MarkerFaceColor',cm.DB,'MarkerEdgeColor',cm.DB,'MarkerSize',MARKER_SIZE}; +mk.ML_MLSE = {'Marker','^','MarkerFaceColor',cm.ML_MLSE,'MarkerEdgeColor',cm.ML_MLSE,'MarkerSize',MARKER_SIZE}; + +% ---------------- FIGURE : BER ---------------- +figure(112+M); clf; hold on; +plot(flip(sort(rop)), sort(BER_VNLE), ... + 'DisplayName','VNLE', ... + mk.VNLE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.VNLE); +plot(flip(sort(rop)), sort(BER_MLSE), ... + 'DisplayName','MLSE', ... + mk.MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE); +plot(flip(sort(rop)), sort(BER_MLSE), ... + 'DisplayName','MLSE', ... + mk.MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE); +plot(flip(sort(rop_pre)), sort(BER_DB_PREC), ... + 'DisplayName','Diff. Precode + DB tgt.', ... + mk.DB{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.DB); +plot(flip(sort(rop_pre)), sort(BER_MLMLSE_PREC), ... + 'DisplayName','ML-based MLSE Diff. Prec. (L=2)', ... + mk.ML_MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.ML_MLSE); +plot(flip(sort(rop_pre)), sort(BER_MLMLSE), ... + 'DisplayName','ML-based MLSE (L=2)', ... + mk.ML_MLSE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.DB_precode); + +yline(2e-2,'LineWidth',1,'HandleVisibility','off'); +yline(4.85e-3,'LineWidth',1,'HandleVisibility','off'); +yline(2.2e-4,'LineWidth',1,'HandleVisibility','off'); +xlabel('ROP in dBm'); +ylabel('BER'); +set(gca, 'yscale', 'log'); +% set(gca, 'XTick', xticks_vals(1:end), 'XTickLabel', xtick_labels(1:end)); +grid on; +legend('Location','best'); +beautifyBERplot + + +%% + + + + + + + + + + + + % ---------------- FIGURE 15 : GMI ---------------- diff --git a/projects/HighSpeedExperiment_2024/Auswertung_JLT/run_plot_measurements.m b/projects/HighSpeedExperiment_2024/Auswertung_JLT/run_plot_measurements.m index 73bd3e6..4e1fa0c 100644 --- a/projects/HighSpeedExperiment_2024/Auswertung_JLT/run_plot_measurements.m +++ b/projects/HighSpeedExperiment_2024/Auswertung_JLT/run_plot_measurements.m @@ -6,31 +6,32 @@ M = 4; fp = QueryFilter(); % fp.where('Runs', 'run_id','EQUALS', 987); % fp.where('Runs', 'pam_level','EQUALS', M); -% fp.where('Runs', 'symbolrate','EQUALS', 150e9); +% fp.where('Runs', 'symbolrate','EQUALS', 165e9); %150, 165, 180, 195, 210, 225, 240 % fp.where('Runs', 'fiber_length','EQUALS', 10); -fp.where('Runs', 'is_mpi','EQUALS', 0); +% fp.where('Runs', 'is_mpi','EQUALS', 0); +% fp.where('Runs', 'power_pd_in','GREATER_THAN', 7); % fp.where('Runs', 'interference_path_length','EQUALS', 1000); % fp.where('Runs', 'loop_id','GREATER_THAN', 11); % fp.where('Runs', 'sir','EQUALS',18); % fp.where('Runs', 'wavelength','EQUALS', 1310); -fp.where('Runs', 'db_mode','EQUALS', 1); % 0 == high preemphasis // 1 == low preemphasis -fp.where('Runs', 'rop_attenuation','EQUALS', 0); +fp.where('Runs', 'db_mode','EQUALS', 2); % 0 == high preemphasis // 1 == low preemphasis +% fp.where('Runs', 'rop_attenuation','EQUALS', 0); -fields = db.getTableFieldNames('power_state_info'); +fields = db.getTableFieldNames('power_state_info'); fields = [fields; db.getTableFieldNames('dashboard_ungrouped_new')]; [dataTable,~] = db.queryDB(fp, fields); %% cfg = struct; -cfg.x_axis = 'wavelength'; % 'symbolrate' | 'baudrate' | 'bitrate' | 'wavelength' -cfg.y_axis = 'power_mzm'; % 'BER' | 'GMI' | 'AIR' | ... -cfg.group_by = {}; -cfg.filters = struct('is_mpi',0,'pam_level',M,'equalizer_structure',[equalizer_structure.vnle,equalizer_structure.ffe,equalizer_structure.vnle_pf_mlse,equalizer_structure.vnle_db_mlse,equalizer_structure.dfe]); +cfg.x_axis = 'symbolrate'; % 'symbolrate' | 'bitrate' | 'wavelength' +cfg.y_axis = 'BER'; % 'BER' | 'GMI' | 'AIR' | ... +cfg.group_by = {'wavelength'}; +cfg.filters = struct('is_mpi',0,'pam_level',M,'equalizer_structure',[equalizer_structure.vnle_db_mlse]);%,equalizer_structure.ffe,equalizer_structure.vnle_pf_mlse,equalizer_structure.vnle_db_mlse,equalizer_structure.dfe]); cfg.y_scale = 'auto'; % auto -> log for BER*, linear otherwise cfg.outlier = 'mad'; % simple, robust; 'none' or 'pctl' also available cfg.show_raw = true; -cfg.show_spread = 'none'; % 'none' or 'iqr' +cfg.show_spread = 'iqr'; % 'none' or 'iqr' cfg.agg = 'mean'; % or 'median' cfg.show_precoded = 0; cfg.fec_lines = [2.2e-4 4.85e-3 2e-2]; % optional @@ -45,5 +46,4 @@ cfg.plot.scatterAlpha = 0.35; cfg.plot.legendLocation = 'best'; cfg.plot.fecLineWidth = 2.4; % thicker FEC limits - plot_measurements_gpt(dataTable, cfg); \ No newline at end of file diff --git a/projects/ML_based_MLSE/analyze_filter_length.m b/projects/ML_based_MLSE/analyze_filter_length.m new file mode 100644 index 0000000..616b715 --- /dev/null +++ b/projects/ML_based_MLSE/analyze_filter_length.m @@ -0,0 +1,164 @@ +%% analyze_filter_length.m +clear; clc; + +M = 4; +randkey = 1; + +% --- Parameter sweep +order_range = 2:3:11; % FFE order +delta_range = 0:2:4; % delta +SNR_dB = 20; + +% --- Prepare bit sequence +order_bits = 19; +s = RandStream('twister','Seed',randkey); +for i = 1:log2(M) + N = 2^(order_bits-1); + bitpattern(:,i) = randi(s,[0 1], N, 1); +end +Bits = Informationsignal(bitpattern); +Symbols = PAMmapper(M,0).map(Bits); +Symbols.fs = 200e9; + +% --- Channel (minimal ISI + AWGN) +h = [0.3 0.9 0.3]; h = h/norm(h); +symbols_filt = Symbols.filter(h,1); +symbols_noi = symbols_filt; +symbols_noi.signal = awgn(symbols_filt.signal,SNR_dB,'measured'); + +% --- Generate all parameter pairs +[O,D] = ndgrid(order_range, delta_range); +pairs = [O(:), D(:)]; + +training_len = 100; + +ber_vec = nan(size(pairs,1),1); % initialize with NaN +ber_training = nan(size(pairs,1),training_len); +ce_vec = nan(size(pairs,1),1); +ce_training = nan(size(pairs,1),training_len); + +% --- Parallel loop over parameter pairs +parfor k = 1:size(pairs,1) + order_k = pairs(k,1); + delta_k = pairs(k,2); + + % Skip invalid combinations (delay cannot exceed filter length) + if abs(delta_k) >= order_k + fprintf('Skip: order=%d, delta=%d (invalid)\n', order_k, delta_k); + continue; + end + + try + ml = ML_MLSE("epochs_tr",training_len,"epochs_dd",1,"len_tr",2^15, ... + "mu_dd",0.1,"mu_tr",0.1,"order",order_k,"sps",1, ... + "traceback_depth",128,"L",3,"delta",delta_k,"adaptive_mu",0); + + [y_ml,y_ref] = ml.process(symbols_noi,Symbols); + ref_bits = PAMmapper(M,0).demap(y_ref); + eq_bits = PAMmapper(M,0).demap(y_ml); + + ber_training(k,:) = ml.ber; + ce_training(k,:) = ml.ce; + + [~,~,ber_vec(k)] = calc_ber(eq_bits.signal, ref_bits.signal, ... + "skip_front",10,"skip_end",10); + L = min(length(ml.ce),30); + ce_vec(k) = mean(ml.ce(end-L+1:end)); + + fprintf('order=%d, delta=%d → BER=%.2e, CE=%.3f\n', ... + order_k, delta_k, ber_vec(k), ce_vec(k)); + catch ME + fprintf('Error at order=%d, delta=%d: %s\n', ... + order_k, delta_k, ME.message); + ber_vec(k) = NaN; + ce_vec(k) = NaN; + end +end + +% --- reshape to 2D matrices +ber_mat = reshape(ber_vec, numel(order_range), numel(delta_range)); +ce_mat = reshape(ce_vec, numel(order_range), numel(delta_range)); + + +%% --- Plot BER +figure; hold on +cols = cbrewer2('Set1',10); +for i = 1:numel(delta_range) + plot(order_range,ber_mat(:,i),'DisplayName',sprintf('delta: %d',delta_range(i)),'Color',cols(i,:)) +end +beautifyBERplot +ylabel('BER'); xlabel('Filter Order [N]'); +title('BER vs. Filter order'); +ylim([1e-4, 0.1]); +yline(3.8e-3,'HandleVisibility','off'); +yline(2.2e-4,'HandleVisibility','off'); + +%% --- Plot Cross-Entropy +figure; hold on +for i = 1:numel(delta_range) + plot(order_range,ce_mat(:,i),'DisplayName',sprintf('delta: %d',delta_range(i))) +end +% beautifyBERplot +ylabel('BER'); xlabel('Filter Order [N]'); +title('BER vs. Filter order'); + +%% --- Training Curves: BER and CE per combination +figure('Name','Training Convergence'); hold on +cols = cbrewer2('Set1', 10); % one color per delta + +[O, D] = ndgrid(order_range, delta_range); + +for i = 1:size(ber_training,1) + ord = O(i); + del = D(i); + + if ord <= del + continue; + end + % --- show only order 2 and 10 + if ord == 2 + lnst = '-'; + elseif ord == 5 + lnst = ':'; + elseif ord == 8 + lnst = '--'; + elseif ord == 11 + lnst = '-.'; + end + + + b = ber_training(i,:); + + + plot_label = sprintf('order=%d, delta=%d', ord, del); + plot(1:length(b), b, 'Color', cols(del+1, :), ... + 'DisplayName', plot_label,'LineStyle',lnst); +end + +set(gca,'YScale','log'); +xlabel('Epoch'); +ylabel('BER'); +title('Training Convergence (BER)'); +legend('show'); +grid on; + + +%% --- Cross-Entropy curves +figure('Name','Cross-Entropy'); hold on +cols = cbrewer2('Set1',size(ce_training,1)); +for i = 1:size(ce_training,1) + + [O, D] = ndgrid(order_range, delta_range); + plot_label = sprintf('order=%d, delta=%d', O(i), D(i)); + c = ce_training(i,:); + c(~isfinite(c) | c==0) = NaN; + if all(isnan(c)), continue; end + plot(1:length(c), c, 'Color', cols(D(i)+1,:), ... + 'DisplayName', plot_label); +end +set(gca,'YScale','log'); +xlabel('Epoch'); +ylabel('Cross-Entropy'); +title('Training Convergence (CE)'); +legend('show'); +grid on; diff --git a/projects/ML_based_MLSE/analyze_mu.m b/projects/ML_based_MLSE/analyze_mu.m new file mode 100644 index 0000000..044b71a --- /dev/null +++ b/projects/ML_based_MLSE/analyze_mu.m @@ -0,0 +1,113 @@ + +M = 4; +order = 19; +randkey = 1; + +bitpattern = []; +s = RandStream('twister','Seed',randkey); +for i = 1:log2(M) + N = 2^(order-1); %length of prbs + bitpattern(:,i) = randi(s,[0 1], N, 1); +end + +if M == 6 + bitpattern = reshape(bitpattern',[],1); + bitpattern = bitpattern(1:end-mod(length(bitpattern),5)); +end + +Bits = Informationsignal(bitpattern); + +Symbols = PAMmapper(M,0).map(Bits); +Symbols.fs = 200e9; + +Bits_ = PAMmapper(M, 0, "eth_style", 0).demap(Symbols); + +% --- Channel: minimal ISI response + AWGN --- +h = [0.3 0.9 0.3]; % impulse response (normalized later if desired) +h = h / norm(h); % optional normalization for unit energy + +symbols_filt = Symbols.filter(h,1); + + +%% SHOW Loss during training + +mu = logspace(-3,-0.8,12); +ber_ml_mlse = zeros(size(mu)); +ber_training = []; +ce_training = []; + +parfor i = 1:numel(mu) + + symbols_noi = symbols_filt; + SNR_dB = 20; + symbols_noi.signal = awgn(symbols_filt.signal, SNR_dB, 'measured'); % AWGN with given SNR + + ml_mlse_equalizer = ML_MLSE("epochs_tr",200,"epochs_dd",1,"len_tr",2^15,... + "mu_dd",mu(i),"mu_tr",mu(i),"order",5,"sps",1,... + "traceback_depth",128,"L",3,"delta",0,'adaptive_mu',0); + + [y_ml_mlse,y_ref] = ml_mlse_equalizer.process(symbols_noi,Symbols); + ref_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ref); + ml_mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ml_mlse); + [~, errors, ber_ml_mlse(i), errpos] = calc_ber(ml_mlse_bits.signal, ref_bits.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1); + fprintf('ML MLSE BER: %.2e \n',ber_ml_mlse(i)); + ber_training(i,:) = ml_mlse_equalizer.ber; + ce_training(i,:) = ml_mlse_equalizer.ce; +end + +%% +symbols_noi = symbols_filt; +SNR_dB = 20; +symbols_noi.signal = awgn(symbols_filt.signal, SNR_dB, 'measured'); % AWGN with given SNR +ml_mlse_equalizer_adap = ML_MLSE("epochs_tr",200,"epochs_dd",1,"len_tr",2^16,... + "mu_dd",1,"mu_tr",1,"order",5,"sps",1,... + "traceback_depth",128,"L",3,"delta",0,"adaptive_mu",1); + +[y_ml_mlse,y_ref] = ml_mlse_equalizer_adap.process(symbols_noi,Symbols); +ref_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ref); +ml_mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ml_mlse); +[~, errors, ber_ml_mlse_, errpos] = calc_ber(ml_mlse_bits.signal, ref_bits.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1); +fprintf('ML MLSE BER: %.2e \n',ber_ml_mlse_); + +%% +figure();hold on + +plot(mu,ber_ml_mlse,'DisplayName','ML-based MLSE'); + +beautifyBERplot; +xlim([mu(1), mu(end)]); +xlabel('mu'); +ylabel('BER'); +title('PAM-4; M=3; AWGN Channel'); +ylim([1e-5 0.1]); + +%% +figure() +hold on; +cols = cbrewer2('Spectral',12); +for i = 1:12 + plot(1:200,ber_training(i,:),'DisplayName', sprintf('mu=%.3f ',mu(i)),'Color',cols(i,:)); +end +set(gca,'YScale','log'); +xlabel('Epoch'); +ylabel('BER'); +title('PAM-4; L=3; SNR=20; AWGN Channel'); +plot(1:200,ml_mlse_equalizer_adap.ber,'DisplayName','Adaptive mu'); + +%% +figure() +hold on; +cols = cbrewer2('Spectral',12); +for i = 1:12 + plot(1:200,ce_training(i,:),'DisplayName', sprintf('mu=%.3f ',mu(i)),'Color',cols(i,:)); +end +set(gca,'YScale','log'); +xlabel('Epoch'); +ylabel('Cross-Entropy'); +title('PAM-4; L=3; SNR=20; AWGN Channel'); +plot(1:200,ml_mlse_equalizer_adap.ce,'DisplayName','Adaptive mu'); + + +%% SUPER LONG EPOCHS + + diff --git a/projects/ML_based_MLSE/experimental_data.m b/projects/ML_based_MLSE/experimental_data.m new file mode 100644 index 0000000..6543e9f --- /dev/null +++ b/projects/ML_based_MLSE/experimental_data.m @@ -0,0 +1,162 @@ + + +dsp_options.storage_path = 'Z:\2024\sioe_labor\'; +dsp_options.max_occurences = 1; +database = DBHandler("dataBase", 'labor_highspeed', "type", 'mysql' ); +run_id = 2776; +dataTable = queryRunid(run_id, database); +fsym = dataTable.symbolrate; +M = double(dataTable.pam_level); +duob_mode = db_mode(strrep(dataTable.db_mode,'"','')); + +% if database.checkIfRunExists('Results','run_id',run_id) +% disp(['Already got at least one reulst for run id: ',num2str(run_id),' ']) +% return +% end + +% Load and Sync signal data from DB +[Tx_bits, Symbols, Scpe_cell, ~] = loadAndSyncSignalDataFromDb(dataTable, dsp_options); + +% Preprocess signal +Scpe_sig = preprocessSignal(Scpe_cell{1}, Symbols, fsym); + +Scpe_sig.spectrum("fignum",1,"displayname",'Rx') + +%% + +ffe_order = [50, 5, 5]; +mu_ffe = [0.0001, 0.0008, 0.001]; +mu_dfe = 0.0004; +eq_ = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",2^14,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.005,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); +mlse_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,"trellis_states",PAMmapper(M,0).levels,'scale_mode',2,'trellis_exclusion',0,'trellis_state_mode',3); + + +%Duobinary Targeting +db_ref_sequence = Duobinary().encode(Symbols); +db_ref_constellation = unique(db_ref_sequence.signal); +[eq_signal, eq_noise] = eq_.process(Scpe_sig,db_ref_sequence); +%% +if 0 + [mlse_sig_sd,LLR,GMI_MLSE] = mlse_.process(eq_signal,Symbols); +else + % Ml MLSE + ml_mlse_equalizer = ML_MLSE("epochs_tr",20,"epochs_dd",1,"len_tr",length(eq_signal),... + "mu_dd",0.01,"mu_tr",0.01,"order",11,"sps",2,... + "traceback_depth",128,"L",1,"delta",4,'adaptive_mu',0); + [mlse_sig_sd,ref_sig] = ml_mlse_equalizer.process(Scpe_sig,db_ref_sequence); +end + +%% +mlse_sig_sd_decoded = Duobinary().decode(mlse_sig_sd,"M",M); +ref_sig_decoded = Duobinary().decode(db_ref_sequence,"M",M); + +mlse_sig_bits = PAMmapper(M,0,"eth_style",0).demap(mlse_sig_sd_decoded); +ref_sig_bits = PAMmapper(M,0,"eth_style",0).demap(ref_sig_decoded); + +err = sum(ref_sig_decoded.signal ~= mlse_sig_sd_decoded.signal); + +[bits_db,errors_db,ber_db,a] = calc_ber(mlse_sig_bits.signal,ref_sig_bits.signal,"skip_front",0,"skip_end",0,"returnErrorLocation",1); + +%% +switch duob_mode + + case db_mode.no_db + % TX Data is not precoded: + + % A) Emulate diff precoding + mlse_sig_hd_precoded = Duobinary().encode(mlse_sig_hd,"M",M); + mlse_sig_hd_precoded = Duobinary().decode(mlse_sig_hd_precoded,"M",M); + + tx_symbols_precoded = Duobinary().encode(Symbols); + tx_symbols_precoded = Duobinary().decode(tx_symbols_precoded); + + tx_bits_precoded = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(tx_symbols_precoded); + rx_bits_mlse = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(mlse_sig_hd_precoded); + + [~,errors_db_diff_precoded,ber_db_diff_precoded,~] = calc_ber(rx_bits_mlse.signal,tx_bits_precoded.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + + %B) Just determine BER + rx_bits_mlse = PAMmapper(M,0,"eth_style",options.eth_style_symbol_mapping).demap(mlse_sig_hd); + [bits_mlse,errors_mlse,ber_db,~] = calc_ber(rx_bits_mlse.signal,Tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + + case db_mode.db_precoded + + % Daten SIND TATSÄCHLICH precoded auf TX Seite: + + % A) Decode at Rx if no DB targeting was applied (we are in VNLE or MLSE EQ structure here! + mlse_sig_hd_decoded = Duobinary().encode(mlse_sig_hd,"M",M); + mlse_sig_hd_decoded = Duobinary().decode(mlse_sig_hd_decoded,"M",M); + rx_bits_mlse_decoded = PAMmapper(M,0,"eth_style",0).demap(mlse_sig_hd_decoded); + [~,errors_db_diff_precoded,ber_db_diff_precoded,a] = calc_ber(rx_bits_mlse_decoded.signal,Tx_bits.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + burst_db_precoded = count_error_bursts(a, 40); + % B) Omit the Coding by comparing with demapped TX symbol sequence + + Tx_bits_ = PAMmapper(M,0,"eth_style",0).demap(Symbols); + rx_bits_mlse = PAMmapper(M,0,"eth_style",0).demap(mlse_sig_hd); + [bits_db,errors_db,ber_db,a] = calc_ber(rx_bits_mlse.signal,Tx_bits_.signal,"skip_front",100,"skip_end",150,"returnErrorLocation",1); + burst_db = count_error_bursts(a, 40); + + cols = linspecer(8); + figure();hold on; + stem(1:40,burst_db,'LineWidth',1,'Color',cols(4,:),'Marker','_','DisplayName','w/o diff. precoder'); + stem(1:40,burst_db_precoded,'LineWidth',1,'Color',cols(3,:),'Marker','.','LineStyle','-','DisplayName','w diff. precoder'); + xlabel('Bit Error Burst Length') + ylabel('Occurence') + set(gca, 'yscale', 'log'); +end + + + + + + +%% SHOW Loss during training + +mu = logspace(-3,-0.8,12); +ber_ml_mlse = zeros(size(mu)); +ber_training = []; +ce_training = []; + +parfor i = 1:numel(mu) + + + + ml_mlse_equalizer = ML_MLSE("epochs_tr",200,"epochs_dd",1,"len_tr",length(Scpe_sig),... + "mu_dd",mu(i),"mu_tr",mu(i),"order",11,"sps",2,... + "traceback_depth",128,"L",2,"delta",4,'adaptive_mu',0); + + [y_ml_mlse,y_ref] = ml_mlse_equalizer.process(Scpe_sig,Symbols); + ref_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ref); + ml_mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ml_mlse); + [~, errors, ber_ml_mlse(i), errpos] = calc_ber(ml_mlse_bits.signal, ref_bits.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1); + fprintf('ML MLSE BER: %.2e \n',ber_ml_mlse(i)); + + ber_training(i,:) = ml_mlse_equalizer.ber; + ce_training(i,:) = ml_mlse_equalizer.ce; +end + +%% +figure();hold on + +plot(mu,ber_ml_mlse,'DisplayName','ML-based MLSE'); + +beautifyBERplot; +xlim([mu(1), mu(end)]); +xlabel('mu'); +ylabel('BER'); +title('PAM-4; M=3; AWGN Channel'); +ylim([1e-5 0.1]); + + +%% +figure() +hold on; +cols = cbrewer2('Spectral',12); +for i = 1:12 + plot(1:200,ber_training(i,:),'DisplayName', sprintf('mu=%.3f ',mu(i)),'Color',cols(i,:)); +end +set(gca,'YScale','log'); +xlabel('Epoch'); +ylabel('BER'); +title('PAM-4; L=3; SNR=20; AWGN Channel'); +plot(1:200,ml_mlse_equalizer_adap.ber,'DisplayName','Adaptive mu'); \ No newline at end of file diff --git a/projects/ML_based_MLSE/interp_fec_cross.m b/projects/ML_based_MLSE/interp_fec_cross.m new file mode 100644 index 0000000..18eac3f --- /dev/null +++ b/projects/ML_based_MLSE/interp_fec_cross.m @@ -0,0 +1,13 @@ +function rop_fec = interp_fec_cross(rops, ber, fec_thr) + if all(~isfinite(ber)) + rop_fec = NaN; return; + end + idx = find(ber < fec_thr, 1, 'first'); + if isempty(idx) || idx == 1 + rop_fec = NaN; return; % no crossing + end + % linear interpolation between the two nearest points + x1 = rops(idx-1); x2 = rops(idx); + y1 = ber(idx-1); y2 = ber(idx); + rop_fec = interp1([y1 y2], [x1 x2], fec_thr, 'linear', NaN); +end diff --git a/projects/ML_based_MLSE/minimal_example_huawei.zip b/projects/ML_based_MLSE/minimal_example_huawei.zip new file mode 100644 index 0000000000000000000000000000000000000000..cab08ae6305313b7f3a13116d0d032471f430465 GIT binary patch literal 14741 zcmaKzb8u$ey6t1zwr#$#la8H^?GE19wr$%sI<}LJZ9D0pbNf4WZ{595oqgu2HP>2I ztH!7~|9a~A&7mX*4uJvk&-i9w^ZmbG{_lhhLIPrEWp8C?WNTpNZe-_RYi3~SV&rCK z#q8n^4+0AD&wu|lsjDG^K+j{LTW$Wm5y6qHl>SQ;1_TC#+}q;cL`na%sIiH)lYxVg z9h2SvBv1BNmLC({iu~{M3UKALF_!S9n&Ou3oFXa=MH~2bs}tKQ+jkJ(Z$b@P4@t zqvthgXRr&Gw0Ax{e>A=+n*t&S zyc4m*{al2!N)}n}8sB9)=|D{Gf~f=W_>PCk5S>ZYQd-=ONd3HyQ#T;hr3m1KRqZClD$n$~6Q*?jiDb~#jb?51R zZoEE)MbV$^?>h}}=Nj-B#LNnTqLHwT)nVlyL+J0x4~TnPcpqbAjdL(KLI3$?{G$UQ ziPsT`Ug58(={#+#xLV(Y!hb1S?cOV`soZZ|cZ*$21-C1Plqn3LLOSs$?8C2bs>^VB zc44;IDOPQL7OpAIhY7@#2IJb-hN@ya8qRzWuRxoV<*cufuy)v?PynxGA?mR{;1BMq zB2bpO82|~EHMWfLb91S=UQqJQG~3ivwX8cqVtIm70HxV<%vqf=BZY-?=LH_UBk|;*2Pvn^LfY?Nsx^QM8574^@73^{o9w-6> z8qU@8Pd7NW^Qo#`0tRH%!%&i>-vBVjSz3=>H#z9kZ|JaW}YKi zj(tpPU71(D67`A*)16ovZc#cQso@)^8y$LS>Lqdm?Z8k5@CWmxCWA548 zj;&y$;OgY*xP|aaF{b?VO8$IEu;1=dAI$J^(j#bRrSo8ol;6mal345?h_vQlrHPQF zj%i?(Sd)xCiI%Lsm-z#hJ+*45drfOcY~fH+y*6#P+~yIsni*?Gv<8HYV(CxK;7DV( zRLjAp3f}HucKH#FWpySb(#@=@Qx>eNwK16FiiJf7L5b`CII!?}Izk}sS-aov!(SdC zh2EYa`7vr9R~|i9IO@zy!0vb4rf!}K0(DQ0lgu+XuudSBzmU8Pv>{MtFQ}686C9K; z*QN257dHtm3sUAuY}`I6v>?e_$y<{KWdn$)51M!3Jm``q2xL!Ta&;$fDaz~!Ov?*Q>H3SdFWBp_+=DL!1S*vI>p@HdS15Ca_zxUH&6pKLxN{~BrJFiJi>xwIraqRTo)UHZk!s`j*etu3(> zzV^LtS~#{WK$wU0B1d|wQ=pb=Sf3{h3SBUxe?@}6$W3eS3~!tax56;RSevfbi#xn} zQr^fS|8*1w_$qWSENkbZ@vUPd7fb!rT&r}GcfaQ<`wi)&2tvN{-Adg%VZR+13fIIa6_ykmhd2mG22}JHhYsCPTMVPv^rb>DMdxrP|o-wh5Qc2V0)2DLowIZ zy)YIMLI=($%+dPS?pPjjP$Oh4{Q(Ljc&WP(>HViTX`pK|o1)Q#*gr& ze3P{Y6#~oBXM0@dv#loU&W5xtw7iecx-W^%bMT~4(3u4^s@O()(2h966T<-i9CXVZ zsPyRlN!R1{KUQqJNu_q27CdIs z@J@&ep}3Y5y_gzpRWr<&U0o7>l6V4A*RTmFMO*xNGJhI3(^%Nt>>=}t{WUmhsf4PY zJ?;XQ*_!p62d{FVi@`O}ZE~8p9`Gk{&(1$=8X8pTph(pO48|gT^9IYcf$^m$|7C6B zK{DH$P+>^n=opx`n`{4#arykSVkH4xr*jwnawyIi<`!jS~JTz`JX5Cy~y3$jPB(H*c zCf^I?@aG$0L?n49frzoTlVD*FtN5I-WWQlcL=u{iAGXx1kctA*Zbwl&FTk8?!d!mW zUCJIRzg>P@t(}E@SZzELOVt!RIB`$#2X%R^SZeMrKjApMBfRKvZu{~Wm~A?RiSD0BIKr z7HK#&YMl-q8@#{$?N+neg`DQc)8h?~da;bzbhsjTktaDB@@vx0e07LV(H~;DH*k{- zGow~xn^t2=s!MmPy?Mx`bCWto!^2AKcWQc=^YRXX`Kg?!^|WI(L#%3pOg!vq(F_*!B{yJ z0mqB^m@s&;3|0$V#d~#E?ClcVIRuQc&}+X$EH_+!?!0VeYGfSEj3Kzyd`*@1B;I1m z0FBjHl*PFZz08^(2E#N0b~9<@i>>AK9+`m35GK+(Iz7qJ8qDR8COcUbt$bw+yTbEl zM$>kB6>dY5AvfBk4wxWRf#{%jgH$7y&|EdAxe&NabZ=>TP-_!e<8XQ9tmwO6sDI9r z*>IvAZ8^oPDcrvR83Mj-hVT!&Wv2N<{lYS70d)Jnqc|Y1WbhE59ahhYNGtrp)n=Tq7jdc>|imu+w)4EU) zPB^laz#Ej01r>h(3=U>4aK(Zddd!_xol3=yV$hq$j+rj5IN4dCYfheiQ6NOD66iL@ zXd$^eDLrr1;FooBq20paJCoa5+*>tg-#82YzOF~qR40~{v3rfGpO23O7gjqz4=Iqp z5rOe1;ZwF#B9lsOxeR{8X^&j{+Hv0!fHMBTZJngr#Q0fp(#~SHAwsO2&zyMldB|HL zzNh@-(yWcZC%O4757_)k?qD6?%{#N_poMRB;>vumT zu=eREd;B49hLAI&jPsp)3^()HC#_iY;jm+ac6-he-r0u|rI67?ZIqmQ1`mFbXbho6 z1FoT@If?75)iRfOP}|4n?YQl*MyJl>Zq`MS_$qIpfBhM6Ym=aCL05G_S1|-6)#44= zbL0@c2sIyXs&NRawmXm!(9lO6effQBi2(kh4)fIOKhdsMBdxrgoBn`#EX?1pr{?b--_XG+Te`=)g3`-&9 zdpk=|;KZOB*ndAY;hP4W)B6jb5tfQs#9zdcwb z1f?y{>)2Q~yVHhV^fYwI;Z1SqLkkXkvE%ZHYQwi@H{Y&)2rvZXA==Ay27D~9VJqxg zf+d3%?(PUCK-IFeW!9DEZ}`-E?s*4TN3l&(fC*DD$O^mh7l|R~i;C~hSf#Xi&98Tj zny6IJ&`EY}lI@$*qWHth6)v`36k1|Xsx=QH1qn3wrM^m(;NK>3v8c{LYv_nEch;f! zhh;V)2~rxhGf=#}`~9)YFkX{LH*YjWmqI`5Mj~++792O26S-C6&&Zwm zBJ5KXKR9t8Ohj)O!rKMkFtQ)*2`D8FVbYuonX|?M*-B#>U|WSsl{7{p;&FiOVAI}@ zR*_kXMFYRm(6-K*1O0t=iH6{4=|F>5qU$0xP{@PhUG_;1Z60JF1~bL$CAkbU3*0sR zx%{ilq*cfmdATz+C5!u0OoPbNB&^fqha9tD<$+rv9RZ`Z9!*gi(Y;Yw1Ck~IhTx}| zof`D1t;gv^SmBh|L3ucwaGu)P{pVrhm1Dpusm*!D%S-JNP~ZIOW)0m&XuSg9b16A5@j8^_~31&6GraLdvL zVS&o+;k+ew_1?<*S%PKDbZCd@bHFxQz11QbUW|@i3&tQa9XNz;MQGTbNmW8`+|RK7 zStNIBRB2B1Sp0Ew->DImqH#WT>__9Plkl^En86?7LcbC(B@pbQwu{!~ov#)W4N*XK zgrT~OV+mPGGn5|>e#4i9A>mdCMWaPfzQZtC%)zzSAYYb3i$iI!Vp%Eq@P8y11~VzS zh+`<_tW#4{nX3vkg!NjytXeu(iVg`o1iRS2&K&y=bz5HepK3&O#*Ac5p$@P5M*}ls z3_}@NIFJwE4$9QvR~WCe^5U02Pm!Jl_g$|PLcPO(@3>=P?y-TD733>9<0BrD5&a-; zQDd++1tP^e+dvq$K6X#M8%usuE2cY47Bfc(oOW^NV-J+VpanyFR?k)F-hNCtBDs9t zw`cYsz(t-WmN%7TD5o4fe8_bU533);>$SjlT@8TZV%JN6}t8qet3lUVBw5rLey1|W4Lgt-QT*KzqYLnq!AgI2f-&R+f9w;aSvT~R7uU%4M`FGTu&?STw{UM@E-QP*D zBgIfVAKX1dZhHYVRWquFf+4o6Ttn8rf~bA2bEVEa@kknOBT4 zx6m1OeTLl=pP@Wnv8+g2{jgyzf7T(A768vW`?n=eXL&k>8_L!N;TbLojo+nlXElRQ zF$k&!@_sQXiXaOP_aJA~Y^TT<(}d5lt>Q@}k0J-v4GKZQyi*xG4W#xF{7~A;krt~i zG!S&6H+aAWEVts7jjh6*+WzSQRkX3-PbnS>ep>{n53(E+3B6Q%QQDv?T^&(cZJd%K zX4y4lbQ*7FgcqqsmNK%GFTv-7!(bjSi}PJ640g1ttMJ4C{X?- z);qov1+XpmR(;m(1o3?QxR2-+$ETMyKR9~=Ob_MUIfm|(w(GmFIKx29JH=QgpiNTy z?4uVaIm!@sBqP>9sLE_~=%mw}O1j~iXIMl3q#|Kl>t#A3c5z?RT?q_)eZG9U=`|*1 z7SwHudf3U;%l8T&~-Drxf>9=@Z? zC#D#1cm{Ydt}4M0@j(jPC0LFG=JEb!gHJLxe^MBJhn;%?y@0$%drv>Mr9O?QRby}p zVN#zxqpVN9eVTdbDED;<1;09jvZKJe>oBUgpuqdIq_EcBxiZBo!UvfdP?Rmxn9<`N zE}2RbEYvj%X6`)*jki*Flh{;kiy+&Dv++$GvdeX+raonSZ63I_s^U@amH70SzN zl?Gik`;Bpj-?L*up`VT<<`b$~rytR=`nx+N9R4o0??%vb&mp};BJRR5miChVjfS%?yn20d#6X(*1_1&Vf*K|{hV0#;^2blCtTO4S$9O*>caCUFxz z&i{6*FDRs5Rbmw&1@-oB`=yFLABrt6bUOP5rX&XqgQqyipN9hif~W@q^8aawj{LtP z7MlM|L;f3i`JbT(;tQJ9$Y16{@)wFMYia*DXvOkHj{g$IVWAjKHXe7xTXhJ?P|*2i zWC5ieso!2f`aQZvawFWSb}Q`T*$WBV&h;2ekBE+hO(OTikUL4#vfDEG^ikFIQ|k z9DI5YBOdF@LO%TScKrwBp)la+36%y`K~X``KX@oyC{nADiL3Ou@sX+3E@{^HdbHY* zcT^ElafzMQjm^X+njvpzS~?S&ftt#B1&OkJAw{%%?_KMz!3N5IZJbj=E_H!M!R^#VvfO?gqt2qnUX~amfHQ2{SxOXqW_yEckD_m^5Zv zGg;rDN`pz9pctevdWv|s;K>0~MoL7S3AmBXS6ue*(NHdDAMI#Ct&Br)uYL3@k$JW)ADYj~3(;-5Zt8d^zD=OT__lqoF~UeW^tI zK6g0sDXI^nj*bF|!iF_63V(tmqr zHRX$KSts!+5Ue$wZMn4ULi=h2Guxv60Btge%5v`tH^!*FX&-#^ZVnfDhkS2@eE68D zS32drEm||u?pzmsJtpM4RQ<%wS84|LjKnOt+2(sGKj6Ux2okR1pOwI12qj4QMMi>J zf{e1q)`!6?B0X7B8!GR)<(C4jJzXuYimXaKDhQZG%T=R$1y`2n)m<9_daN_k0s^@} z4}r?{{2|_|VGTyoSF#;Wl`8RyMvy$~$3Jga_0#E2@Hk0_ZhCxU7vkhPhuLEsN;WR# zWej0~kEVG35HNb9CWmQ5`7WkbMT3SqwZ4-!h2AgZWV^-DLCC~E_<`UGtEH1HcMqRr zTUcwYr%K_G+F>)6WnO3)N?}Cfi<#9AX($U;xEk9T3O~+}o8m-effy4GOWbOj zOO=<+=oE%k9EK1ih}-vYQ=mM(eVDWhrr>}=ip5dXJrp_y?FMeL!kV$X*zit@Q;~ix z&LZ&EHyw9>6+eJrF<~Za;a%3kt}MpUmztsV>Bu~Z{uWa+-5y?KzEupj6-GSA@2_b& zuJOX={&P9{*93_eWYSqOKR=J^tMvLVV`9)a*1*1-1)6EZOkQKdGbTIY-*WX-nN$7aId8pP0XK_DWDI0fh;IXg zWaa^pO#`}h-ly`uy+N-50^y(uW8SL)$tlaPiY@82`1CJ(=N^&#KHvJ8v|~T>@`J{< zIcfS7llGC|Xufrx2frmDEsmtDeYKhyeYU6RP=R;Wr6VZ+$s9+*{z_cVZ5@Z(U~p=7 z30`;b3=GoYkIWmZdY4voQK1wvPPT3K^q`A+5PLd+CR+3z@2f^UKX^CuMGp;1*wnVfT;8=BlHLkNpKE-iHtcc&i(>(U%EFI8u9#Dm%l;I1T~WUEAalJOx9cZcm7NvN?=O?%nAkY3&ei z%b_*75=3l%Ey@#vH4Aa?2m2$pvHEmmEHrteaS~60v zB*&Bq`~v-_G?)X=!H=KtaVs%?zMJJ7ATkmD!Fb97)4`U z`fA%}*w*N0)@S6O#ObNZ0SS=gk!LajHdxamb!}}Aj8mxC4U(PMy{QN?QkDLnx7;6e zSo?yQTp!PIUwm$xCB(4ZC&dZGTe155D(<&Tm_$RALWg8dklABX$T?GS!{d* zk^nL2d*Tj9JCX|ixVlsSCGOcgLv*gtsm&5iO=@I`9Vz;ulv%$^1I{FzCkNPDqq+2}w@ATEr~ zEQ~pVX`V|!nqvXqv?h^#Lv`7e5+l8YX3XlL6s5VJPRjq5@^w6dIq$m=ZH|#9qWA+m zM={{qK-VH zqeNA>#=3OQJ0iIz4O*|YacZQPY$B4MUP}dg1_uFC9ja_aG+?BFX7?p*2k4aiE{GAUnGgK4{b=*^K=HnEAP&vssfgbe`UnR# z@4#gf*LjBW3lnIysj>?ZJjCI_sX@Oa978YAm$1b02$t^P#?yV^EGKdC#c4K4FJq{0 zQOew4T;w*`tthK6b1WQzQHM$wmReow11LtosOO622=O3j3r1y5TtRUgBLeHGJyT;P z0TL;36J28=tbnG_kb`|Dm{jV(DcnSgDY&z^<>BztR`f9(`89b+NMe&$EbIu85`QEk zwgzQ;Nr|YdTlV8So;3?|hFb{ly?^HXLp{Tjs@FvK1mvR~niuBlNXxfM)Z2Q`Xc_%-2MGRq53Z}hy z#xa=x9^k1L8Goouj%J-5==RJa(4Y$R-*R~RiHmUkw15ox_Rzu=iZ?@|&3E+cU~zIi zZH??U>0Tj~jL=|a&YqpL%H6@E-T1oQja`w#1x@p4G)m%k#!1fyo}N|qa7>#e-yZ;q zy3C*lr14%ETh_RXR)%ny#|aU*e%+l*>M;Axcg`Co2gYAFLTam|H@=Ju^`x#$F!=Pv zf*M=*-rPa!63QaU1?)f7`2^h(X*VNUC|#-r2zh9fR>TxuE+cf*8-09=eXl6IJ5a zlxg+DuFkwdt9#TjVj?vn8gXaMp}PTvMctu9{v|+ZTvWnNxtTR zk@KrKwDzAkFs9kM^SC}SqF(%)!o{XueEX?Gklvqjk|VTNKu+iZ_B~}9EaSQ0pA}Kc z#)%}(S$vhq08?)bqTi<@)dvMV2h!jCx^uXm8m0IlIM?voxp1GcJ)y;|T%XDgNIyKs zR_EeubtZ%0Mym<+`sVhMvEea?7`+wD9eUMh57wZH7`Zt72a!87S9c%xAKxBNFCTYe zYZd!?Uss1RUnPrByV)CBH?vc#dU;u;neOA+t6g~Fz+tnrnEswb3;Fd6UO)`mMdMtg z_UMoY`|?*ZGmc(Q*8sp`)tryO-V#l7XK|+q&uK{EEYCKW5)uqO*AfGd^ufbLiKKo; zUm>)fr9LY_wPL{rQ`e;~+4C_3$SSGN7qP0=B+&3#L8S~&B67Dbm;9?bV0~k)%8L)!w(>kJ-9AF$TEaNNHm0_eGAMA~>xM|u!$ONF9bFom-(5=WtNuUR(nzW8UOL*l;AS-;YxaGdl%jus^|6EvD8 zCh^fVmQ1+Q02cb4i&n}jLvjI4u7A`Hk6lgiIcnCjWOsfad<7{$dX0g*Pv+iqYaoB9 zoii>J*k5s}`qs!Xv0!)(D<#Q}qh@+x4BoM(v5()=4=Xi4k4XNSa!2O3n0csV58F9s ze+j?zw5yZX&{N89_B8WyP2YfP@=-4QY+m&7E#0`UQ^6+Ek^57?WK-Vpy=>8t_BGJoe()NJ^kqzC-huRN5~G&kw>E`IA8KFrFca-GH<* zf)$&=HjlD0Np<|fCE#Z}b2@Ea$ULYdRA)_zjvSYHppA8Zivp*D;qghORWw~bl6HbR zz%bh1J{ZBGk$au{v!4rqS0$1n$q7E)q2C;FTA8|pZB4g7xgyE3wJ zi!VK9vjqDOjc_<(8C!?Gs3i0fwDa0Tu3Yro>G_a13#iF&lUssiIK!^UzXyro^w-f7 z=Cr5Pg!SD&mQkpu!Kxa3SwY!Suz7)!3^ zibU#!x^2}d_1qwppg{zSzqK9?88$zbp*CYkPI0n8Q!e2x%NYrD@#oJJHc5_h8E|Js zFHh#(0`X!l5)b5ZG2RBm__bbM=uO&!W}Pd|Y8hHoKE@sJ-V)TS#W!}UeKY7CyV-k2 zo-bi}*H?Pvg7mTS$M(u~FZ9G#+$ct4*4x7|uA+x(IfuWZHqzYRdm0C$hOHN(Y<%4M zhkGT>XK*@C?rBIhKT_HE!DT^tH>|Quu?Yo|!~`$BwtxtA%I_0onqH!lnykJG72IiOL~ALe2ujFXNa zq|yO;E|c1z`n37!B#8kb+_6Lfae{$@?=Zku)L!LL9GyZr9~X@iDwflob_}!1V7}7C z5K`6iO}OwVRbj$0mn9i}EN&PXQp4}0K~d{@`ra!YQ%F>UpWVN;5A80dWV?N$$WG z!fQkRw1J^Hecj}=4f8y2W_Q%0HmyO55e;=5fO+nZUalZ@2J2*JIyCzMEsyH^qs(7jePK2p=kR2E|!&K$4;*8!PD> z^E5y79YGn}A7j&!6uxWv!$m-(HqOSvnJ)^5nUuai=p}N3dW;{2xqe2o`4JOGkBrRa z5507cfR0iHaR9cNH|@d6B(gc$zA{87C!vM1Z6;yZ_yU3z+bFn$Pvpz=Of8T|zAB(j zkE+wO$W0mn))RKeM5W{*t#(bjfNp2j(aG||8oIEHbSL|iqQ;n~h@`j0A&Sfd0LWIO zaWz`Q8ZNhcVC|y1Lmy!+<)IYvI_MdXl9x2t4`S|hpC`C0D3C{0utn_Zd_CGusDGUU zK`WC?qEMf((I!9y*Fw&$)80iRBj7| zIlvZoiE7u>jaH?eD1pC7JRUl_Axfai}ojYe8RA+ zePcqSwsM`%N;`Y2`jQHzWkX@ZNtyYM9hH`}S9$dMfzC@f=UoYfN;Nk!ef5HvZ?m^! zJY;n@(t)UP{6G=Te!=dwK&(f1TjIb{DqUU7&81R*Dh+OQ)h&0>v3d3cA}{$&JPT7h zDdk)^L7`}Jw2ZDr3jbO>^;lcX$6o3FjOuabwPG?N5XW-8%9yW|n`vw1mcN)G2?oaeB5TaPe9n+-HQz$Dd2C8Z?xy4s%FWefyj5Q6d0YJq=8e zua9jg&&oh>080*q8&C~unWT(Jj^$L2Z7)rVgCv^l=5EqZAAX+4JthEmfs2oG^9)3) zPO`{*SaIQ3j4t(%)lT?-1zkQ+f%nMcL;R*2=|IxBgh!r~X`}v37)RmPRc0oU1fY zd>fiOt~A;;ynbUFfC*jW$zcL^z88Sc;E7Rd(xUm?8j(T2FuWA6iAvmy z0KTW8Dpo;F%Vkd&z*}8OeimN+iYI(TlL0(vzHkYsG?rb8n^Tx?@sT3!@3_|3iNhIQ zOkTk^k<<0#K|C#WaW5DkuEdFZAFxP*OWFL{<|{50zW2xK(nk=WweU{m_z1xiMHXxR zNQ;Ig5ikm;eWCdBv(95)$f#cyc@Fv^x3pcz__jyg8T<{m3}J=b;%L&UXnC7_Jad<{ zzaehE+I3{Y3eoPWXQ{M>-0gN2EXZ^3b8+GV{Wj6>wO=~?+Oimy(~>AbH#?bxvd0hArI#4I-KP zQOAJ*<*t{6R5<&IYn0MSq!O_riV^5txeRz-`+X5C(kZi%K2z1bCeX3-xjpo??msm! zC8@_*C&SQx9{m1kG9Ps*8a`lxfFvvY(_{t(!vOzJA-}(n`u~nEk$+zP8+iVYkv~Wf z(0?L-|4;n?h5h~&e3OFwfAQ7;_5UpXzeNB3+WZs!`&XNPDEhxP(P{q8#sv32uHnBe z?SEkEf8G9J>i_EYPhAw5 literal 0 HcmV?d00001 diff --git a/projects/ML_based_MLSE/minimal_example_huawei/bcjr_pam.m b/projects/ML_based_MLSE/minimal_example_huawei/bcjr_pam.m new file mode 100644 index 0000000..674b55f --- /dev/null +++ b/projects/ML_based_MLSE/minimal_example_huawei/bcjr_pam.m @@ -0,0 +1,555 @@ +classdef bcjr_pam < handle + %MLSE calculates the most probable sequence for an input signal with given/ known channel impulse response of any length + + properties(Access=public) + M %PAM-M + DIR + trellis_states + duobinary_output + end + + methods (Access=public) + + function obj = bcjr_pam(options) + %NAME Construct an instance of this class + % Detailed explanation goes here + + arguments + options.M double = 4; + options.DIR double = [1]; + options.trellis_states double = [-3 -1 1 3]; + options.duobinary_output logical = false; + + end + + % + fn = fieldnames(options); + for n = 1:numel(fn) + try + obj.(fn{n}) = options.(fn{n}); + end + end + end + + function [VITERBI_ESTIMATION_SYMBOLS,LLR_exact,GMI] = process(obj,data_in,data_ref,tx_bits,bit_mapping) + + + debug = 0; + + % States should match the target states of the prev. EQ (EQ's job was to reduce the error between signal and the target) + trellis_state_mode = 2; + % 0 = use provided states (MUST provide the correct states); + % 1 = normalize to = 1 rms; + % 2 = use target symbols; + % 3 = use statistical levels + % 3 analyzes avg of rx signal levels - can help with nonlinear impairments + + trellis_exclusion = 1; % PAM-6 only (only if data is NOT precoded!) + + % Additional scaling between states, expected output (noiseless_received) and the noisy, filtered input signal + scale_mode = 2; % scale_mode: + % 0 = no scaling, + % 1 = use RMS to scale MODEL, + % 2 = use MMSE/time-corr to scale MODEL, -> This best to get the GMI right -> sometimes the LLP's are not centered around zero... + % 3 = use RMS to scale DATA, + % 4 = use MMSE/time-corr to scale DATA + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%%% PREPARATIONS %%%%%%%% + + % remove unnecessary zeros at start of impulse response to keep + % number of trellis states minimal + DIR_nonzero = find(obj.DIR ~= 0); + if DIR_nonzero(1) > 1 + obj.DIR(1:DIR_nonzero(1)-1) = []; + end + + if isscalar(obj.DIR) + obj.DIR = [0 obj.DIR]; + end + + % impulse respnse to remove from signal + obj.DIR = flip(obj.DIR); %i.e. -0.2676 -0.0478 1.0000 + + % Trellis States + obj.trellis_states = reshape(obj.trellis_states,1,[]); + if trellis_state_mode == 1 % Normalize the Trellis states to =1 RMS + + obj.trellis_states = obj.trellis_states ./ rms(obj.trellis_states); + + elseif trellis_state_mode == 2 %simply use the states from the ref signal (should be a robust option) + + obj.trellis_states = reshape(unique(data_ref),size(obj.trellis_states)); + + elseif trellis_state_mode == 3 %use_statistical_levels + + %%%% Separate the equalized signal into the respective levels based on the actually transmitted level + constellation = unique(data_ref); + + % find actual levels from rx signal + symbols_for_lvl = NaN(numel(constellation),length(data_ref)); + for l = 1:numel(constellation) + level_amplitude = constellation(l); + symbols_for_lvl(l,data_ref==level_amplitude) = data_in(data_ref==level_amplitude); + end + + %replace the trellis states + avg_levels = mean(symbols_for_lvl,2,'omitnan'); + obj.trellis_states = sort(avg_levels)'; + + %also replace the whole ref signal (PAM-M) levels + [~, idx] = ismember(data_ref, unique(data_ref)); + data_ref = avg_levels(idx); + + end + + + % seems to be the only way to use combvec for a flexible amount + % of vectors. 'combs' contains all trellis states + pre_comb_mat = repmat(obj.trellis_states,length(obj.DIR)-1,1); + pre_comb_cell = mat2cell(pre_comb_mat,ones(1,size(pre_comb_mat,1)),size(pre_comb_mat,2)); + combs = fliplr(combvec(pre_comb_cell{:}).'); + first_sym = combs(:,1); % das ist das älteste/ trailing Symbol aus der sequenz + last_sym = combs(:,end); %hiermit wird entschieden/ das ist das cursor symbol am ende der sequenz + nStates = length(last_sym); + + % % Calculate all possible input symbols for the desired impulse + % % response. Row number is the index of the previous state, + % % column number is the index of the next state + % % noise free received == branch metrics + % assumes: last_sym = combs(:,end); % already defined earlier + levels = sort(unique(obj.trellis_states(:)).'); + edges = [levels(1) levels(end)]; % edge levels (0 and 5 in PAM6) + + noise_free_received = inf(nStates,nStates); % rows: to, cols: from + edge_edge_mask = false(nStates,nStates); % rows: to, cols: from + + for from = 1:nStates + for to = 1:nStates + % valid transition if shift-register overlap holds + if all(combs(to,2:end) == combs(from,1:end-1)) + % noiseless sample for the 'to' state reached from 'from' + noise_free_received(to,from) = ... + dot(combs(to,:), obj.DIR(end:-1:2)) + last_sym(from)*obj.DIR(1); + + % mark edge→edge candidate (to be excluded only on even→odd steps) + edge_edge_mask(to,from) = ... + (last_sym(from)==edges(1) || last_sym(from)==edges(2)) && ... + (last_sym(to) ==edges(1) || last_sym(to) ==edges(2)); + end + end + end + + h = flip(obj.DIR(:)).'; + data_in = data_in(:); + y_ideal = conv(data_ref(:), h, "same"); + + switch scale_mode + case 0 + g = 1; b = 0; + case 1 % RMS: scale model to data + g = rms(data_in)/rms(y_ideal); b = mean(data_in) - g*mean(y_ideal); + case 2 % MMSE/time-corr: scale states to data + [c,lags] = xcorr(data_in(:), y_ideal, 64); + [~,ix] = max(abs(c)); + lag = lags(ix); + y_ideal = circshift(y_ideal, lag); + mu_y = mean(data_in(:)); + mu_i = mean(y_ideal); + y_c = data_in(:)-mu_y; + yi_c = y_ideal-mu_i; + g = (yi_c'*y_c)/(yi_c'*yi_c); + b = mu_y - g*mu_i; + case 3 % RMS flipped: scale data to model + gd = rms(y_ideal)/rms(data_in); bd = mean(y_ideal) - gd*mean(data_in); + data_in = gd*data_in + bd; + g = 1; b = 0; + case 4 % MMSE/time-corr flipped: scale data to states + [c,lags] = xcorr(data_in(:), y_ideal(:), 64); + [~,ix] = max(abs(c)); + lag = lags(ix); + y_ideal = circshift(y_ideal(:), lag); + mu_y = mean(data_in(:)); + mu_i = mean(y_ideal); + y_c = data_in(:) - mu_y; % data_in centered + yi_c = y_ideal - mu_i; % ideal centered + g = (y_c' * yi_c) / (y_c' * y_c); + b = mu_i - g * mu_y; + data_in = g * data_in(:) + b; + g = 1; b = 0; + end + + % apply (g,b) to states/ expected values + noise_free_received = g*noise_free_received + b; + last_sym = g*last_sym + b; + + % calculate noise power + sigma2 = mean(abs(data_in - (g*y_ideal + b)).^2); %noise = mean(abs((RX Signal - IDEAL Signal)))^2 + inv2s2 = 1/(2*sigma2); + + if debug + figure(100); clf; hold on + obj.showLevelScatter_(data_in, data_ref); + yline(noise_free_received(:), 'DisplayName','Transition States','Color','red','HandleVisibility','off'); + yline(obj.trellis_states(:), 'DisplayName','Transition States','Color','green','LineWidth',2,'HandleVisibility','off') + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%% FORWARD PASS (VITERBI -Alpha's) %%%%% + + % Initialize the output vector + pm = zeros(nStates,nStates); + bm_fw = zeros(nStates,nStates,length(data_in)); + + % first start is evaluated without ISI/ wihout the full Impulse response + % so simply use the constellation here + bm = -(data_in(1) - last_sym).^2 * inv2s2; + pm = pm + bm; + [alpha(:,1),pm_survivor_fw_idx(:,1)] = max(pm,[],2); + pm = repmat(alpha(:,1).',nStates,1); + bm_fw(:,:,1) = pm; + + % Forward Recursion (FSM Computation) + for n = 2:length(data_in) + + bm = -(data_in(n) - noise_free_received).^2 * inv2s2; + + % exclude edge to edge transitions only for even->odd steps && PAM-6 + if mod(n,2) == 0 && obj.M == 6 && trellis_exclusion + bm(edge_edge_mask) = -Inf; + end + + pm = pm + bm; + [alpha(:,n),pm_survivor_fw_idx(:,n)] = max(pm,[],2); % choose lowest path metric as new state (get min distance for all state transitions towards a new state) + pm = repmat(alpha(:,n).',nStates,1); % update pm (chosen state to 2nd dimension -> FROM state) + + bm_fw(:,:,n) = bm; + + end + + % we can now get the best path as min + viterbi_path = NaN(1,length(data_in)); + + % find ideal trellis path by going through the trellis backwards + [~,viterbi_path(length(data_in))] = max(alpha(:,length(data_in))); + for n = length(data_in):-1:2 + viterbi_path(n-1) = pm_survivor_fw_idx(viterbi_path(n),n); + end + + + if debug + alpha_ = alpha - min(alpha) + eps; + figure();hold on; + n = 10; + scatter(1:n,obj.trellis_states(repmat([1:numel(obj.trellis_states)]',1,n)),abs(alpha_(:,end-n+1:end)),'Marker','o','LineWidth',1); + scatter(1:n,obj.trellis_states(viterbi_path(end-n+1:end)),500,'Marker','x','LineWidth',1,'MarkerEdgeColor','green'); + % scatter(1:n,data_ref(end-n+1:end),500,'Marker','x','LineWidth',1,'MarkerEdgeColor','red'); + yticks(obj.trellis_states); + ylim([min(obj.trellis_states)-1 max(obj.trellis_states)+1]); + end + + VITERBI_ESTIMATION_SYMBOLS(1:length(data_in)) = first_sym(viterbi_path); + VITERBI_ESTIMATION_SYMBOLS = reshape(VITERBI_ESTIMATION_SYMBOLS,size(data_in)); + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%% BACKWARD (Beta's) %%%%% + + % Initialize the output vector + pm = zeros(nStates,nStates); + beta = zeros(nStates,length(data_in)); + pm_survivor_bw_idx = zeros(nStates,length(data_in)); + bm_bw = zeros(nStates,nStates,length(data_in)); + + % starting with the state that has the lowest sum path + % metric, follow the stored information about the + % predecessor + for h = length(data_in)-1:-1:1 + + bm = -(data_in(h+1) - noise_free_received).^2 * inv2s2; + + % exclude edge to edge transitions for even->odd steps && PAM-6 + if mod(h+1, 2) == 0 && obj.M == 6 && trellis_exclusion + bm(edge_edge_mask) = -Inf; + end + + pm = pm + bm.'; + [beta(:,h),pm_survivor_bw_idx(:,h)] = max(pm,[],2); % choose lowest path metric as new state + pm = repmat(beta(:,h).',nStates,1); % update pm (chosen state to 2nd dimension -> FROM state) + + bm_bw(:,:,h) = bm; + + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%% FORWARD (Combine Alpha and Beta to yield LLP's) %%%%% + + %calc the log probabilities (llp's) + + for k = 1:length(data_in) + + if k == 1 + + alpha_ = repmat(alpha(:,k)',[nStates,1])'; + beta_ = beta(:,k); + + LLP(:,k) = max(alpha_ + beta_,[],2); + + else + + alpha_ = repmat(alpha(:,k-1)',[nStates,1])'; + gamma_ = bm_fw(:,:,k)'; + beta_ = beta(:,k); + + LLP(:,k) = max(alpha_ + gamma_,[],1) + beta_'; + end + + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%% Calc LLR's %%%%% + + % These are interchangeable... + nml_LLP = LLP - max(LLP); %subtract highest value for better numerical stability, LLP's are not always close to zero + expLLP = exp(nml_LLP); + state_prob = expLLP ./ sum(expLLP); % sums to one (or numerically close to one) + + % compute symbol‐posteriors from LLP in the log‐domain: + amax = max(LLP,[],1); + logZ = amax + log(sum(exp(LLP - amax), 1)); + logPstate = LLP - logZ; % still in log‐domain + state_prob = exp(logPstate); % exact, sums to 1 + + if obj.M == 6 + + num_bits = 5; + + % all possible transitions (for now 36, including the "edges" + % of the QAM 32 constellation) + states = [-5 -3 -1 1 3 5]; + pam6transitions = combvec(states,states)'; % pam6transitions = + % [-5 -5; + % -3 -5; + % -1 -5; ... + + [~, idx_sym_1] = ismember(pam6transitions(:,1), states); + [~, idx_sym_2] = ismember(pam6transitions(:,2), states); + pam6ind = [idx_sym_1, idx_sym_2]; + + numPairs = floor(size(LLP,2)/2); + LLR_exact = zeros(numPairs,5); + LLR_maxlogmap = zeros(numPairs,5); + + for k = 1:numPairs + symbol1 = 2*k-1; + symbol2 = 2*k; + + LLP1 = LLP(:,symbol1); + LLP2 = LLP(:,symbol2); + prob1 = state_prob(:,symbol1); + prob2 = state_prob(:,symbol2); + + % All 36 Combinations: M = LLP Symbol 1 + LLP Symbol 2 + Mij = LLP1(pam6ind(:,1)) + LLP2(pam6ind(:,2)); + pij = prob1(pam6ind(:,1)) .* prob2(pam6ind(:,2)); + + % for each of the 5 bits sum exact-probs or max-log + for b = 1:num_bits + idx_sym_1 = bit_mapping(:,b)==1; + idx_bit_1 = bit_mapping(:,b)==0; + + % exact LLR from probabilities + P1 = sum(pij(idx_sym_1)); %prob that bit == 1 + P0 = sum(pij(idx_bit_1)); + LLR_exact(k,b) = log(P1./P0); %ratio by multiplication + + % max-log: + LLR_maxlogmap(k,b) = max( Mij(idx_sym_1) ) - max( Mij(idx_bit_1) ); % ratio by subtraction + end + end + + % GMI calc includes the Tx-bitstream + tx_bits_pam6_reshaped = reshape(tx_bits',5,[])'; % N x 5 + MI = zeros(1, num_bits); + for k = 1:num_bits + + idx_bit_1 = (tx_bits_pam6_reshaped(:,k) == 0); %wo sind die 1en + idx_sym_1 = (tx_bits_pam6_reshaped(:,k) == 1); %wo sind die 0en + + %LLR's for all actually transmitted ones or zeros + llr0 = LLR_exact(idx_bit_1,k); + llr1 = LLR_exact(idx_sym_1,k); + + % Calculate mutual information for bit position k + I0 = mean(log2(1 + exp(llr0))); % exp(--LLR) = exp(positive) > 1 + I1 = mean(log2(1 + exp(-llr1))); % exp(-+LLR) = exp(negative) < 1 + MI(k) = 1 - 0.5 * (I0 + I1); + end + + GMI = sum(MI); % Total mutual information per symbol + GMI = GMI/2; % GMI per single symbol not per two symbols + + else + + % Number of symbols and bits per symbol + num_bits = log2(length(obj.trellis_states)); % 2 bits per symbol + + % bit_mapping = PAMmapper(length(obj.trellis_states),0,"eth_style",0).showBitMapping; + + % Initialize LLR storage + LLR_maxlogmap = zeros(length(data_in),num_bits); + LLR_exact = zeros(length(data_in),num_bits); + + % Compute bit-wise LLRs + for bit_idx = 1:num_bits + + % Find indices where bit is 0 and where it is 1 + idx_bit_0 = bit_mapping(:,bit_idx) == 0; + idx_bit_1 = bit_mapping(:,bit_idx) == 1; + + % Sum over log-probabilities + % Max-Log approximation uses the single max LLP value + % instead of sum over all LLP's + LLR_maxlogmap(:,bit_idx) = max(LLP(idx_bit_1,:), [], 1) - max(LLP(idx_bit_0,:), [], 1); + + % Sum probabilities over states for which the bit is 1 and 0, respectively. + P0 = sum(state_prob(idx_bit_0, :),1); + P1 = sum(state_prob(idx_bit_1, :),1); + LLR_exact(:,bit_idx) = log(P1./P0); % N x num_bits + + + end + + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + %%%%% CALC NGMI %%%%% + + MI = zeros(1, num_bits); + for k = 1:num_bits + + idx_bit_0 = (tx_bits(:,k) == 0); %wo sind die 1en + idx_bit_1 = (tx_bits(:,k) == 1); %wo sind die 0en + + %LLR's for all actually transmitted ones or zeros + llr0 = LLR_exact(idx_bit_0,k); + llr1 = LLR_exact(idx_bit_1,k); + + % mutual information for bit position k + I0 = mean(log2(1 + exp(llr0))); % exp(--LLR) = exp(positive) > 1 + I1 = mean(log2(1 + exp(-llr1))); % exp(-+LLR) = exp(negative) < 1 + MI(k) = 1 - 0.5 * (I0 + I1); % assumes equally distributed ones and zeros + end + + GMI = sum(MI); % Total bitwise mutual information + + end + + + if debug + %%% DEBUG PLOT LIKELIHOOD RATIOS %%% + figure(115);clf + subplot(2,1,1) + for bit = 1:num_bits + hold on; + histogram(LLR_exact(:,bit),1000,"DisplayName",sprintf('Actual LLR of Bit Pos %d',bit),'LineStyle','none','FaceAlpha',0.4); + end + legend + + subplot(2,1,2) + for bit = 1:num_bits + hold on; + histogram(LLR_maxlogmap(:,bit),1000,"DisplayName",sprintf('Max Log LLR of Bit Pos %d',bit),'LineStyle','none','FaceAlpha',0.4); + end + legend + + if obj.M == 6 + pairs = reshape(VITERBI_ESTIMATION_SYMBOLS,2,[]).'; + levels = sort(unique(VITERBI_ESTIMATION_SYMBOLS)); + isedge = ismember(pairs, [levels(1) levels(end)]); + isforbidden = sum(isedge,2)==2; + fprintf('Found %d forbidden transitions (even -> odd ; edge -> edge).\n', nnz(isforbidden)); + end + + end + + + end + + function [symbols_for_lvl,avg_for_lvl] = showLevelScatter_(~,eq_signal,ref_symbols) + + figure() + + rx_symbols = eq_signal; %./ rms(eq_signal); + correct_symbols = ref_symbols; + + % col = cbrewer2('Paired',numel(unique(correct_symbols))*2); + col = ... + [0.6510 0.8078 0.8902; ... + 0.1216 0.4706 0.7059; ... + 0.6980 0.8745 0.5412; ... + 0.2000 0.6275 0.1725; ... + 0.9843 0.6039 0.6000; ... + 0.8902 0.1020 0.1098; ... + 0.9922 0.7490 0.4353; ... + 1.0000 0.4980 0; ... + 0.7922 0.6980 0.8392; ... + 0.4157 0.2392 0.6039; ... + 1.0000 1.0000 0.6000; ... + 0.6941 0.3490 0.1569; ... + 0.6510 0.8078 0.8902; ... + 0.1216 0.4706 0.7059; ... + 0.6980 0.8745 0.5412; ... + 0.2000 0.6275 0.1725]; + ccnt = -1; + + levels = unique(correct_symbols); + symbols_for_lvl = NaN(numel(levels),length(correct_symbols)); + start = 1; + ende = length(correct_symbols); + + for l = 1:numel(levels) + ccnt = ccnt+2; + + level_amplitude = levels(l); + + symbols_for_lvl(l,correct_symbols==level_amplitude) = rx_symbols(correct_symbols==level_amplitude); + std_lvl(l) = std(symbols_for_lvl(l,:),'omitnan'); + xax = 1:length(correct_symbols); + + scatter(xax(start:ende),symbols_for_lvl(l,start:ende),10,'.','MarkerFaceAlpha',0.5,'MarkerEdgeAlpha',0.5,'MarkerEdgeColor',col(ccnt,:)); + hold on; + + + end + + std_lvl = round(std_lvl,2); + + ccnt = 0; + avg_for_lvl = NaN(numel(levels),length(correct_symbols)); + % Add the windowed/ smoothed curves + for l = 1:numel(levels) + ccnt = ccnt+2; + level_amplitude = levels(l); + + L = 500; + movmean = 1/L .* movsum(rx_symbols(correct_symbols==level_amplitude),[L/2,L/2], 'Endpoints', 'fill'); + + avg_for_lvl(l,correct_symbols==level_amplitude) = movmean; + + nanx = isnan(avg_for_lvl(l,:)); + t = 1:numel(avg_for_lvl(l,:)); + avg_for_lvl(l,nanx) = interp1(t(~nanx), avg_for_lvl(l,~nanx), t(nanx)); + + plot(xax(start:ende),avg_for_lvl(l,start:ende),'Color',col(ccnt,:)); + + hold on + end + + % yline(levels); + xlabel('Samples'); + ylabel('Amplitude'); + ylim([-3 3]); + + end + + + end +end diff --git a/projects/ML_based_MLSE/minimal_example_huawei/minimal_example.m b/projects/ML_based_MLSE/minimal_example_huawei/minimal_example.m new file mode 100644 index 0000000..504a1b2 --- /dev/null +++ b/projects/ML_based_MLSE/minimal_example_huawei/minimal_example.m @@ -0,0 +1,193 @@ + +if 0 + % A) RUN FULL LOOP + M_format = [2,4,6,8]; + snr = 10:25; +else + % B) RUN FOR DEBUG AND TEST + M_format = 4; + snr = 20; +end + +for m = 1:length(M_format) + % --- Parameters --- + M = M_format(m); % PAM order (e.g., 2,4,8) + Nsym = 1e5; % number of symbols + h = [1, 0.5, 0.2]; % Impulse response to remove + + b = log2(M); + if M == 6 b = 5; end + rng(1); + bits_tx = logical(randi([0 1], Nsym, b, 'uint8')); + + tx_symbols = pammap(bits_tx,M); + + if M == 6 + states = unique(tx_symbols); + pam6transitions = combvec(states',states')'; % pam6transitions = + bitmapping = pamdemap(reshape(pam6transitions',1,[])',M); + else + bitmapping = pamdemap(unique(tx_symbols),M); + end + + scaling = sqrt(sum(unique(tx_symbols).^2)/numel(unique(tx_symbols))); + tx_symbols = tx_symbols ./ scaling; + + % apply impulse response to signal + y_filt = filter(h, 1, tx_symbols); + + for s = 1:length(snr) + + % apply noise + y = awgn(y_filt,snr(s),"measured",1); + + % apply ml-MLSE + adaptive_mu = 0; + mu_lms = 0.15; + ml_mlse_equalizer = ml_mlse_pam("epochs_tr",50,"epochs_dd",1,"len_tr",length(y)/2,... + "mu_dd",mu_lms,"mu_tr",mu_lms,"order",11,"sps",1,... + "L",2,"delta",4,"adaptive_mu",adaptive_mu); + + [ml_mlse_estimate,~] = ml_mlse_equalizer.process(y,tx_symbols); + rx_symbols = ml_mlse_estimate .* scaling; + bits_rx = pamdemap(rx_symbols,M); + + BER_ml(m,s) = nnz(bits_tx ~= bits_rx) / numel(bits_tx); + fprintf('BER = %.2e \n', BER_ml(m,s)); + + + % apply bcjr + BCJR = bcjr_pam("DIR",h,"duobinary_output",0,"M",M,"trellis_states",unique(tx_symbols)); + [viterbi_estimate,LLR,GMI(m,s)] = BCJR.process(y,tx_symbols,bits_tx,bitmapping); + + % decode LLR's + bits_LLR = LLR > 0; + + % demap viterbi symbols sequence + rx_symbols = viterbi_estimate .* scaling; + bits_rx = pamdemap(rx_symbols,M); + + % BER calc + BER_vit(m,s) = nnz(bits_tx ~= bits_LLR) / numel(bits_tx); + fprintf('BER LLR = %.2e \n', BER_vit(m,s)); + + BER_llr(m,s) = nnz(bits_tx ~= bits_rx) / numel(bits_tx); + fprintf('BER = %.2e \n', BER_llr(m,s)); + end +end +%% +figure();hold on +for m = 1:length(M_format) + p=plot(snr,BER_llr(m,:),'DisplayName',sprintf('Viterbi: PAM %d',M_format(m))); + plot(snr,BER_ml(m,:),'DisplayName',sprintf('ML-Based: PAM %d',M_format(m)),'LineStyle',':','Color',p.Color); +end +ylabel('BER'); +xlabel('SNR') +title('BER vs. SNR'); +set(gca, 'XScale', 'linear', ... + 'YScale', 'log', ... + 'TickLabelInterpreter', 'latex', ... + 'FontSize', 11); + +%% +figure();hold on +for m = 1:length(M_format) + plot(snr,GMI(m,:),'DisplayName',sprintf('GMI PAM %d',M_format(m))) +end +ylabel('GMI'); +xlabel('SNR') +title('GMI vs. SNR'); +set(gca, 'XScale', 'linear', ... + 'YScale', 'linear', ... + 'TickLabelInterpreter', 'latex', ... + 'FontSize', 11); + +function symbols = pammap(bits,M) +bits = logical(bits); +if M == 2 + symbols = bits; +elseif M == 4 + symbols= 2*bits(:,1) + (bits(:,1)==bits(:,2)); + symbols=2*symbols-3; + +elseif M == 6 + + m = 1; + + if size(bits,2)>size(bits,1) + bits = bits'; %vector aufrecht stellen + end + bits = reshape(bits',1,[])'; + thres = [-3 5;-1 5;-3 -5;-1 -5;-5 3;-5 1;-5 -3;-5 -1;-1 3;-1 1;-1 -3;-1 -1;-3 3;-3 1;-3 -3;-3 -1;3 5;1 5;3 -5;1 -5;5 3;5 1;5 -3;5 -1;1 3;1 1;1 -3;1 -1;3 3;3 1;3 -3;3 -1]; + % LUT based mapping + for k = 1:5:fix(length(bits)/5)*5 + symbols(m:m+1,1) = thres(bin2dec(int2str(bits(k:k+4)'))+1,:); + m = m+2; + end + +elseif M == 8 + x1 = bits(:,1); + x2 = (bits(:,1)==bits(:,3)); + x3 = x2~=bits(:,2); + + symbols = 4*x1 + 2*x2 + x3; + symbols=2*symbols-7; +end +end + +function bits = pamdemap(symbols,M) + +if M == 2 + thres=0; +elseif M == 4 + thres=[-2,0,2]; +elseif M == 6 + thres = [-3 5;-1 5;-3 -5;-1 -5;-5 3;-5 1;-5 -3;-5 -1;-1 3;-1 1;-1 -3;-1 -1;-3 3;-3 1;-3 -3;-3 -1;3 5;1 5;3 -5;1 -5;5 3;5 1;5 -3;5 -1;1 3;1 1;1 -3;1 -1;3 3;3 1;3 -3;3 -1]; +elseif M == 8 + thres=-6:2:6; +end + +if M ~= 6 + symbols = symbols'; + a = squeeze(repmat(real(symbols),[1 1 length(thres)])); %Eingangssignal in 3 spalten + b = squeeze(repmat(reshape(thres(:).',[1 1 length(thres)]),[1 length(symbols) 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(symbols),[1 1 length(thres)]) > repmat(reshape(thres(:).',[1 1 length(thres)]),[1 length(symbols) 1]); + s1=size(comp_real,1); + s2=size(comp_real,2); +end + +if M == 2 + data_out=abs(comp_real(:,:,1)); +elseif M == 4 + data_out=[comp_real(:,:,2); ones(s1,s2) - comp_real(:,:,1) + comp_real(:,:,3)]; +elseif M == 6 + + if size(symbols,2) > 1 + symbols = symbols.'; + end + + if length(symbols)/2 ~= round(length(symbols)/2) + symbols = [symbols;0]; + end + + m = 1; + for n = 1:2:length(symbols) + dist = sqrt((symbols(n)-thres(:,1)).^2+(symbols(n+1)-thres(:,2)).^2); + [~,dd_idx] = min(dist); + % dec_out(n:n+1) = LUT(dd_idx,:); + data_out(m:m+4) = bitget(dd_idx-1,5:-1:1); + m = m+5; + end + + data_out = reshape(data_out',5,[]); + +elseif M == 8 + data_out=[comp_real(:,:,4); + comp_real(:,:,1)-comp_real(:,:,3)+comp_real(:,:,5)-comp_real(:,:,7); + 1-comp_real(:,:,2)+comp_real(:,:,6)]; +end + +bits = data_out'; + +end \ No newline at end of file diff --git a/projects/ML_based_MLSE/minimal_example_huawei/ml_mlse_pam.m b/projects/ML_based_MLSE/minimal_example_huawei/ml_mlse_pam.m new file mode 100644 index 0000000..84ebfb4 --- /dev/null +++ b/projects/ML_based_MLSE/minimal_example_huawei/ml_mlse_pam.m @@ -0,0 +1,473 @@ +classdef ml_mlse_pam < handle + + % ALGORITHM DESCRIBED IN: + % W. Lanneer and Y. Lefevre, “Machine Learning-Based Pre-Equalizers for + % Maximum Likelihood Sequence Estimation in High-Speed PONs,” + % in 2023 31st European Signal Processing Conference + + % Further ML Refs: + % https://machinelearningmastery.com/cross-entropy-for-machine-learning/ + % https://docs.pytorch.org/docs/stable/generated/torch.nn.CrossEntropyLoss.html + + % The central idea is to overcome the (white-) noise assumption within the previously described + % Viterbi algorithm, more precisely a closed-loop optimization is proposed that finds a suitable + % filter-set to directly compute the branch metrics c_k (s,s^' ). These can directly be used to + % carry out the conventional Viterbi algorithm. The system consists of S^L S=F linear FIR filters, + % combined with one bias coefficient respectively. These filters take the received input samples to + % compute the branch metrics estimates (c_k ) ̂(s,s^' ) according toThe central idea is to overcome + % the (white-) noise assumption within the previously described Viterbi algorithm, more precisely + % a closed-loop optimization is proposed that finds a suitable filter-set to directly compute the + % branch metrics c_k (s,s^' ). These can directly be used to carry out the conventional Viterbi + % algorithm. The system consists of S^L S=F linear FIR filters, combined with one bias coefficient + % respectively. These filters take the received input samples to compute the branch metrics + % estimates. Finally, the usual Viterbi is carried out... + + % Recommended Settings and some findings: + + % Requires many training epochs. According to ML people, 100,200 or + % even up to 1000 epochs are normal for ML-convergence + + % The mu parameter _can_ be adaptive - using the cross entropy and when + % analyzing the isolated training it looks very promisig. However, is + % later use I found this is not as stable as a fixed learning rate. + % mu = 0.1 worked good for me + + % Longer orders/ filter length are not always better. For me order=11 + % was good. + + % Delay factor (delta) is good when the order is also increased. With + % order = 11, a delta of =4 shows good results + + properties + sps % usually 2 + order + e + e_tr + error + + len_tr + mu_tr + epochs_tr + + % dd_mode -> not implemented here! + mu_dd %weight update in dd mode + epochs_dd + + adaptive_mu + + constellation + + L %viterbi memory length + + alpha + DIR + DIR_flip + trellis_states + + traceback_depth + + S + Nf + delta + nStates + nFeasible + combs + first_sym + last_sym + valid + valid_to_idx + valid_from_idx + w + nbiasTerms + + true_to_state_idx + state_dict % containers.Map: key(sequence)->state index + key_fmt = '%.8g_'; % key format for sequence strings + nSym % |constellation| + + ber = [] + ce = ones(1,1); + end + + methods + function obj = ml_mlse_pam(options) + arguments(Input) + + options.sps = 2; + options.order = 15; + + options.len_tr = 4096; + options.mu_tr = 0; + options.epochs_tr = 5; + + % options.dd_mode = 1; + options.mu_dd = 1e-5; + options.epochs_dd = 5; + + options.adaptive_mu = 1; + + options.delta = 0; + options.traceback_depth = 1024; + + options.L = 1 + + end + + fn = fieldnames(options); + for n = 1:numel(fn) + obj.(fn{n}) = options.(fn{n}); + end + + obj.e = zeros(obj.order,1); + obj.error = 0; + end + + function [x_viterbi,x_ref] = process(obj, X, D) + + % actual processing of the signal (steps 1. - 3.) + % 1 normalize RMS + X = X./rms(X); + + % Use sorted constellation for deterministic mapping + obj.constellation = sort(unique(D),'ascend'); + obj.nSym = numel(obj.constellation); + + if length(X)/length(D) ~= obj.sps + warning('Signal length does not fit to reference!'); + end + + % ============================================================== + % INITIALIZATION + % ============================================================== + + % --- Parameters + obj.S = numel(obj.constellation); % Num of Symbols + obj.Nf = obj.order*obj.sps; % filter length (auto adapt for n-SPS...) + obj.nStates = obj.S^obj.L; % S^L states + obj.nFeasible = obj.nStates*obj.S; % S^(L+1) feasible states + + % --- Trellis mapping + obj.trellis_states = reshape(obj.constellation,1,[]); % make row vector + pre_comb_mat = repmat(obj.trellis_states, obj.L, 1); + pre_comb_cell = mat2cell(pre_comb_mat, ones(1,obj.L), size(pre_comb_mat,2)); + obj.combs = fliplr(combvec(pre_comb_cell{:}).'); % rows: states, columns: [x_k, x_{k-1}, ...] + obj.first_sym = obj.combs(:,1); + obj.last_sym = obj.combs(:,end); + obj.nStates = size(obj.combs,1); + + % --- Valid transitions; adapted from the old Viterbi in + % Move-It where the "noise free received" states are calculated + % using the same loop and clause + obj.valid = false(obj.nStates); + for from = 1:obj.nStates + for to = 1:obj.nStates + if all(obj.combs(to,2:end) == obj.combs(from,1:end-1)) + obj.valid(to,from) = true; + end + end + end + [obj.valid_to_idx, obj.valid_from_idx] = find(obj.valid); + + % Allocate vectors and weights + % !! IF SHAPE FIT, then we already have smth there an we want + % to start with the existing filter-set (saves comp. time/ or to test fixed filter on new data) + obj.nbiasTerms = 1; + if isempty(obj.w) || any(size(obj.w) ~= [obj.Nf+obj.nbiasTerms,obj.nFeasible]) + obj.w = zeros(obj.Nf+obj.nbiasTerms,obj.nFeasible); % filter weights per transition + bias tap + % obj.w = randn(obj.Nf+obj.nbiasTerms,obj.nFeasible); + end + + % This is a weird workaround - but it works and is much faster + % than findig the state indices every time: + % Precompute dictionary for fast state lookup (sequence -> state) + keys = cell(obj.nStates,1); + for i = 1:obj.nStates + keys{i} = obj.seq_key(obj.combs(i,:)); % combs row is already [x_k, x_{k-1}, ...] + end + obj.state_dict = containers.Map(keys, 1:obj.nStates); + + % ============================================================== + % TRAINING + % ============================================================== + + n = obj.len_tr; + training = 1; + obj.equalize(X, D,obj.mu_tr,obj.epochs_tr,n,training); + obj.e_tr = obj.e; + + % ============================================================== + % Testing; Fixed Mode + % ============================================================== + + n = length(X); + training = 0; + obj.mu_dd = obj.mu_tr; %For now no DD mode is implemented... + [x_viterbi,x_ref]=obj.equalize(X, D,obj.mu_dd,obj.epochs_dd,n,training); + + end + + function [y,y_ref] = equalize(obj,x,d,mu,epochs,N,training) + % ============================================================== + % ML-Based Branch Metric Estimation + Viterbi + % ============================================================== + debug = 1; + showPlots = 1; + + nSymbols = ceil(N/obj.sps); + + for epoch = 1:epochs + + % state metrics (log-domain costs): keep as column [nStatesx1] + pm = zeros(obj.nStates,1); + v_tilde = zeros(1,obj.nFeasible); + pred = zeros(nSymbols, obj.nStates); + pm_sto = nan(obj.nStates, nSymbols); + CE_accum = 0; + + % START IDX can be randomized during training, but this + % requires some testing - it is not better, maybe a + % solutiuon is to use the same window for 10-20 epochs + % and then switch to another window + % for now: simply use the first parts of the signal for + % training and also for testing... not "the + randomize_training_window = 0; + if randomize_training_window && training + max_start = length(x) - ( (ceil(N/obj.sps)-1)*obj.sps + 1 ); + max_start = max(1, max_start); % safety + start_sample = randi([1, max_start], 1); %rnd training; not really good + else + start_sample = 1; + end + + end_sample = start_sample + (ceil(N/obj.sps)-1)*obj.sps; + start_symbol = 1 + floor((start_sample - 1)/obj.sps); % ABSOLUTE symbol index + + symbol = 0; + for sample = start_sample:obj.sps:end_sample + symbol = symbol + 1; + k = symbol; + sym_idx = start_symbol + (symbol - 1); + + % input signal window y_k; delayed by delta + i1 = sample - obj.Nf + 1 + obj.delta; + i2 = sample + obj.delta; + buf = x(max(1,i1):min(length(x),i2)); + padL = max(0,1 - i1); + padR = max(0,i2 - length(x)); + yk = [zeros(padL,1); buf(:); zeros(padR,1)]; % Nfx1 + yk = [yk;ones( obj.nbiasTerms,1)]; + + % Apply Filter; Predict branch metrics for all feasible transitions: c_hat + % Formula (8) + c_hat = (yk.' * obj.w); % [1xnFeasible] + c_hat = c_hat.'; % [nFeasiblex1] + + % Extended path metrics: v_tilde = pm(from) + c_hat + v_tilde = pm(obj.valid_from_idx) + c_hat; % [nFeasiblex1] + + % ===== Cross Entropy Loss Update ===== + + if 1 %training + % --- allocate storage once + if epoch == 1 && symbol == 1 + obj.true_to_state_idx = ones(ceil(N/obj.sps),1,'uint32'); + end + + % --- previous "to" becomes current "from" + if symbol > 1 + true_from_state_idx = obj.true_to_state_idx(symbol-1); + else + true_from_state_idx = 1; + end + + % --- compute or reuse "to" state + if epoch == 1 + % only compute in first epoch + if sym_idx >= obj.L + key_to = obj.seq_key(flip(d(sym_idx-obj.L+1 : sym_idx))); + if isKey(obj.state_dict, key_to) + obj.true_to_state_idx(symbol) = obj.state_dict(key_to); + else + obj.true_to_state_idx(symbol) = true_from_state_idx; + end + else + obj.true_to_state_idx(symbol) = true_from_state_idx; + end + end + + % --- ensure valid (from,to) + dirac = zeros(obj.nFeasible,1); + mask = obj.valid_from_idx==true_from_state_idx & ... + obj.valid_to_idx == obj.true_to_state_idx(symbol); + if any(mask) + dirac(mask) = 1; + else + idx = find(obj.valid_from_idx==true_from_state_idx,1,'first'); + dirac(idx) = 1; + obj.true_to_state_idx(symbol) = obj.valid_to_idx(idx); + end + + % softmax over -v_tilde (numerically safe shift) + v_shift = -(v_tilde - min(v_tilde)); % shift to small positive numbers + v_shift = min(v_shift, 100); % clamp exponent argument to avoid extreme numbers/ overflow (exp(50)=5e21) + expv = exp(v_shift); + p = expv ./ (sum(expv) + eps); + + % Cross entropy + CE_symbol(symbol) = -log(p(dirac==1) + eps); + + if sym_idx > obj.L + CE_smooth(symbol) = 0.01*CE_symbol(symbol) + 0.99*CE_smooth(symbol-1); + else + if epoch > 1 + CE_smooth(symbol) = obj.ce(end); %stitch together ce from last epoch? or =1 for very first round?! + else + CE_smooth(symbol) = CE_symbol(symbol); + end + end + + CE_accum = CE_symbol(symbol) + CE_accum; + + % Formula (10) + % gradient term (t - p) + dmp = (dirac - p)'; % 1xnFeasible + + % Formula (10) + dL_Dw = (yk) .* dmp; + + % Start updates only when the symbol index has ≥ L history + if sym_idx >= obj.L + if obj.adaptive_mu + mu_eff = CE_smooth(sym_idx); + mu_eff = max(min(mu_eff, 0.2), 1e-4); + else + mu_eff = mu; + end + + % see Algorithm 1 in paper + obj.w = obj.w - mu_eff .* dL_Dw; % (Nf+1)xnFeasible + end + + % if debug && epoch > 2 + % figure(100); + % subplot(4,1,1); + % heatmap(p'); + % title('Probs') + % subplot(4,1,2); + % heatmap(dmp); + % title('Update') + % subplot(4,1,3); + % heatmap(dL_Dw); + % title('Update') + % subplot(4,1,4); + % heatmap(bj.w); + % title('Update') + % + % end + + end + + % Compare-Select + v_tilde_mat = inf(obj.nStates, obj.nStates); + v_tilde_mat(obj.valid) = v_tilde; %reshapes to usual (from x to) matrix + [pm_next, pred(k,:)] = min(v_tilde_mat, [], 2); %here, calc min for each column + + % re-center, otherwise it will overflow + pm_next = pm_next - min(pm_next); + + pm = pm_next; + pm_sto(:,symbol) = pm; + end + + % Traceback + [~, s_end] = min(pm); + viterbi_path = zeros(symbol,1); + viterbi_path(symbol) = s_end; + for n = symbol:-1:2 + viterbi_path(n-1) = pred(n, viterbi_path(n)); + end + + % cut here to have the same indices when shuffling/ + % starting the start_symbol indx != 1 + y_ref = d(start_symbol:end); + y = obj.first_sym(viterbi_path); + + % Debug and Plots + if debug && training + sym_start = start_symbol; + sym_end = start_symbol + symbol - 1; + ref_slice = d(sym_start : sym_end); + err = sum(y ~= ref_slice(1:numel(y))); + + try %works with demapper, not provided in Deliverable + ref_bits = PAMmapper(obj.S,0).demap(ref_slice); + eq_bits = PAMmapper(obj.S,0).demap(y); + [~, ~, ber, ~] = calc_ber(ref_bits, eq_bits, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1); + fprintf('Epoch: %d - BER: %.1e \n',epoch, ber); + obj.ber(epoch) = ber; + berlabel = 'BER'; + catch %fallback ser + ser = err./length(y); + fprintf('Epoch: %d - SER: %.1e \n',epoch, ser); + obj.ber(epoch) = ser; + berlabel = 'BER'; + end + + obj.ce(epoch) = CE_accum./symbol; + + if showPlots + figure(10);clf + subplot(3,2,1:2); + heatmap(obj.w); + title('Filter') + + subplot(3,2,3); + v_tildemat = NaN(obj.nStates, obj.nStates); + v_tildemat(obj.valid) = v_tilde; % log-domain scores + heatmap(v_tildemat); + title('Extended Path Metrics v-tilde') + + subplot(3,2,4); + scatter(1:symbol,pm_sto,1,'.') + title('Path Metric Winners v') + + subplot(3,2,5);hold on + scatter(1:symbol,CE_symbol,1,'.'); + scatter(1:symbol,CE_smooth,1,'.') + title('Cross Entropy') + ylabel('Cross Entropy') + xlabel('Symbols') + + subplot(3,2,6); hold on + % Left y-axis: Cross Entropy + yyaxis left + scatter(1:length(obj.ce), obj.ce, 10, 's', 'filled') + ylabel('Cross Entropy') + + % Right y-axis: BER + yyaxis right + scatter(1:length(obj.ber), obj.ber, 10, 'd', 'filled') + set(gca, 'YScale', 'log') + ylabel(berlabel) + + xlim([1, epochs]) + xlabel('Epoch') + title('Cross Entropy // BER') + grid on + + drawnow + end + end + end + end + end + + methods (Access=private) + function k = seq_key(obj, seq) + % Build a stable key string for a sequence row vector in the *same order as combs rows* ([x_k, x_{k-1}, ...]) + % Use rounding via sprintf to avoid floating-point issues. + % seq must be a row vector. + k = sprintf(obj.key_fmt, seq); + end + end +end diff --git a/projects/ML_based_MLSE/rate_evaluation.m b/projects/ML_based_MLSE/rate_evaluation.m index 07e4057..00494b7 100644 --- a/projects/ML_based_MLSE/rate_evaluation.m +++ b/projects/ML_based_MLSE/rate_evaluation.m @@ -5,14 +5,14 @@ ber_dbtgt = []; ber_ml = []; mlse = 1; -dbtgt = 1; - +dbtgt = 0; +duob_mode = db_mode.no_db; baudrates = [136:8:224].*1e9; -parfor i = 1:length(baudrates) +for i = 1:length(baudrates) rop = -8; M = 4; - [Rx_sig_2sps_v1, Symbols_v1, Tx_bits_v1] = standard_link_model("M",M,"fsym",baudrates(i),"rop",rop,"laser_linewidth",1300,"link_length_m",0,"random_key",1,"apply_pulsef",0); + [Rx_sig_2sps_v1, Symbols_v1, Tx_bits_v1] = standard_link_model("M",M,"fsym",baudrates(i),"rop",rop,"laser_linewidth",1310,"link_length_m",0,"random_key",1,"apply_pulsef",1); % [Rx_sig_2sps_v2, Symbols_v2, Tx_bits_v2] = standard_link_model("M",M,"fsym",200e9,"rop",rop,"laser_linewidth",1300,"link_length_m",0,"random_key",2); % [Rx_sig_2sps_v3, Symbols_v3, Tx_bits_v3] = standard_link_model("M",M,"fsym",200e9,"rop",rop,"laser_linewidth",1300,"link_length_m",0,"random_key",3); @@ -25,6 +25,7 @@ parfor i = 1:length(baudrates) eq_ = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",2^13,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.005,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1); mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels,'scale_mode',2,'trellis_exclusion',0,'trellis_state_mode',2,'debug',0,'DIR',pf_.coefficients); + [ffe_results, mlse_results] = vnle_postfilter_mlse(eq_, pf_, mlse_, M, Rx_sig_2sps_v1, Symbols_v1, Tx_bits_v1, ... "precode_mode", duob_mode,... 'showAnalysis', 0, ... @@ -33,6 +34,9 @@ parfor i = 1:length(baudrates) ber_ffe(i) = ffe_results.metrics.BER; ber_mlse(i) = mlse_results.metrics.BER; + + fprintf('BER FFE: %.2e \n',ber_ffe(i)); + fprintf('BER MLSE: %.2e \n',ber_mlse(i)); end @@ -69,11 +73,14 @@ parfor i = 1:length(baudrates) %% RUN ML-Based MLSE mu_lms = 0.15; - ml_mlse_equalizer = ML_MLSE("epochs_tr",30,"epochs_dd",1,"len_tr",2^15,... - "mu_dd",mu_lms,"mu_tr",mu_lms,"order",5,"sps",1,... - "traceback_depth",128,"L",3,"delta",0); + ml_mlse_equalizer = ML_MLSE("epochs_tr",50,"epochs_dd",1,"len_tr",2^16,... + "mu_dd",mu_lms,"mu_tr",mu_lms,"order",4,"sps",2,... + "traceback_depth",128,"L",2,"delta",0); - [y_ml_mlse,~] = ml_mlse_equalizer.process(y_white,Symbols_v1); + ml_mlse_equalizer.mu_tr = 0.005; + ml_mlse_equalizer.epochs_tr = 2; + ml_mlse_equalizer.epochs_dd = 1; + [y_ml_mlse,~] = ml_mlse_equalizer.process(Rx_sig_2sps_v1,Symbols_v1); ml_mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ml_mlse); [~, errors, ber_ml(i), errpos] = calc_ber(ml_mlse_bits.signal, Tx_bits_v1.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1); fprintf('ML MLSE BER: %.2e \n',ber_ml(i)); diff --git a/projects/ML_based_MLSE/read_csv.m b/projects/ML_based_MLSE/read_csv.m new file mode 100644 index 0000000..fbed164 --- /dev/null +++ b/projects/ML_based_MLSE/read_csv.m @@ -0,0 +1,30 @@ +%% read_wpd_csv.m +% Minimal importer for WebPlotDigitizer multi-curve CSV + +filename = 'wpd_datasets.csv'; % <-- set your file path here +T = readtable(filename); + +% Read header row manually +fid = fopen(filename); +hdr1 = strsplit(strrep(fgetl(fid), '"', ''), ','); % curve names +hdr2 = strsplit(strrep(fgetl(fid), '"', ''), ','); % X/Y header row +fclose(fid); + +% Extract unique curve names +names = hdr1(~cellfun('isempty',hdr1)); + +% Create struct for each curve +mii = struct(); +for i = 1:numel(names) + base = matlab.lang.makeValidName(strrep(names{i},' ','_')); + xi = 2*(i-1)+1; % X column + yi = xi+1; % Y column + mii.(base).X = T{:,xi}; + mii.(base).Y = T{:,yi}; + + % also create workspace variable "name_wpd" + assignin('base',[base '_wpd'], mii.(base)); +end + +disp('Imported datasets:'); +disp(fieldnames(mii)); diff --git a/projects/ML_based_MLSE/rop_evaluation.m b/projects/ML_based_MLSE/rop_evaluation.m index 68ed3eb..eb77a3f 100644 --- a/projects/ML_based_MLSE/rop_evaluation.m +++ b/projects/ML_based_MLSE/rop_evaluation.m @@ -1,95 +1,139 @@ +clear; clc; -ber_ffe = []; -ber_mlse = []; -ber_dbtgt = []; -ber_ml = []; +M = 4; +randkey = 1; +duob_mode = db_mode.no_db; mlse = 1; dbtgt = 1; -rops = linspace(-15,-5,12); -parfor i = 1:length(rops) - - rop = rops(i); - M = 4; - [Rx_sig_2sps_v1, Symbols_v1, Tx_bits_v1] = standard_link_model("M",M,"fsym",224e9,"rop",rop,"laser_linewidth",1300,"link_length_m",0,"random_key",1); - % [Rx_sig_2sps_v2, Symbols_v2, Tx_bits_v2] = standard_link_model("M",M,"fsym",200e9,"rop",rop,"laser_linewidth",1300,"link_length_m",0,"random_key",2); - % [Rx_sig_2sps_v3, Symbols_v3, Tx_bits_v3] = standard_link_model("M",M,"fsym",200e9,"rop",rop,"laser_linewidth",1300,"link_length_m",0,"random_key",3); - - %% FFE + MLSE - if mlse - pf_ncoeffs = 1; - ffe_order = [50, 0, 0]; - mu_ffe = [0.0001, 0.0008, 0.001]; - mu_dfe = 0.0004; - eq_ = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",2^13,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.005,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); - pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1); - mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels,'scale_mode',2,'trellis_exclusion',0,'trellis_state_mode',2,'debug',0,'DIR',pf_.coefficients); - [ffe_results, mlse_results] = vnle_postfilter_mlse(eq_, pf_, mlse_, M, Rx_sig_2sps_v1, Symbols_v1, Tx_bits_v1, ... - "precode_mode", duob_mode,... - 'showAnalysis', 0, ... - "postFFE", [],... - "eth_style_symbol_mapping", 0); - - ber_ffe(i) = ffe_results.metrics.BER; - ber_mlse(i) = mlse_results.metrics.BER; - end +baudrates = 180e9:2e9:220e9; % outer loop +rops = linspace(-10,0,12); % inner sweep +FEC_thr = 3.8e-3; % BER target + +% --- allocate results +reqROP_FFE = nan(size(baudrates)); +reqROP_MLSE = nan(size(baudrates)); +reqROP_DBTGT = nan(size(baudrates)); +reqROP_ML_MLSE2 = nan(size(baudrates)); +reqROP_ML_MLSE3 = nan(size(baudrates)); + +%% ====================== OUTER LOOP ====================== +for b = 1:numel(baudrates) + baudrate = baudrates(b); + fprintf('\n=== %.0f GBd ===\n', baudrate/1e9); + + ber_ffe = nan(size(rops)); + ber_mlse = nan(size(rops)); + ber_dbtgt = nan(size(rops)); + ber_ml2 = nan(size(rops)); + ber_ml3 = nan(size(rops)); + + %% -------- inner ROP loop -------- + for i = 1:length(rops) + rop = rops(i); + + [Rx_sig_2sps_v1, Symbols_v1, Tx_bits_v1] = standard_link_model( ... + "M",M,"fsym",baudrate,"rop",rop,"laser_linewidth",1310, ... + "link_length_m",0,"random_key",1); - - %% FFE DB tgt. + MLSE - if dbtgt - mlse_db_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,"trellis_states",PAMmapper(M,0).levels,'scale_mode',2,'trellis_exclusion',0,'trellis_state_mode',3); - ffe_order = [50, 0, 0]; - mu_ffe = [0.0001, 0.0008, 0.001]; - mu_dfe = 0.0004; - eq_ = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",2^13,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.005,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",1); - dbt_results = duobinary_target(eq_, mlse_db_, M, Rx_sig_2sps_v1, Symbols_v1, Tx_bits_v1, ... - "precode_mode", duob_mode, ... - 'showAnalysis', 0,... - "postFFE", []); - - ber_dbtgt(i) = dbt_results.metrics.BER; - end - - %% RUN ML-Based MLSE - - mu_lms = 0.15; - ml_mlse_equalizer = ML_MLSE("epochs_tr",30,"epochs_dd",1,"len_tr",2^14,... - "mu_dd",mu_lms,"mu_tr",mu_lms,"order",4,"sps",2,... - "traceback_depth",128,"L",2,"delta",0); - [y_ml_mlse,~] = ml_mlse_equalizer.process(Rx_sig_2sps_v1,Symbols_v1); - ml_mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ml_mlse); - [~, errors, ber_ml(i), errpos] = calc_ber(ml_mlse_bits.signal, Tx_bits_v1.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1); - fprintf('ML MLSE BER: %.2e \n',ber_ml(i)); - - % figure(11);hold on - % plot(1:numel(ml_mlse_equalizer.ber),ml_mlse_equalizer.ber); - % beautifyBERplot; - % xlim([1,numel(ml_mlse_equalizer.ber)]) + %% FFE + MLSE + if mlse + pf_ncoeffs = 1; + ffe_order = [50, 0, 0]; + mu_ffe = [0.0001, 0.0008, 0.001]; + mu_dfe = 0.0004; + eq_ = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",2^13, ... + "training_loops",5,"dd_loops",5,"K",2,"DCmu",0.005, ... + "DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0, ... + "plotfinal",0,"ideal_dfe",1); + pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1); + mlse_ = MLSE("duobinary_output",0,'M',M, ... + 'trellis_states',PAMmapper(M,0).levels,'scale_mode',2, ... + 'trellis_exclusion',0,'trellis_state_mode',2,'debug',0, ... + 'DIR',pf_.coefficients); + [ffe_results, mlse_results] = vnle_postfilter_mlse(eq_, pf_, mlse_, M, ... + Rx_sig_2sps_v1, Symbols_v1, Tx_bits_v1, ... + "precode_mode", duob_mode,'showAnalysis', 0, "postFFE", [], ... + "eth_style_symbol_mapping", 0); + + ber_ffe(i) = ffe_results.metrics.BER; + ber_mlse(i) = mlse_results.metrics.BER; + end + + %% FFE + duobinary target MLSE + if dbtgt + mlse_db_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M, ... + "trellis_states",PAMmapper(M,0).levels,'scale_mode',2, ... + 'trellis_exclusion',0,'trellis_state_mode',3); + ffe_order = [50, 0, 0]; + mu_ffe = [0.0001, 0.0008, 0.001]; + mu_dfe = 0.0004; + eq_ = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",2^13, ... + "training_loops",5,"dd_loops",5,"K",2,"DCmu",0.005, ... + "DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0, ... + "plotfinal",0,"ideal_dfe",1); + + dbt_results = duobinary_target(eq_, mlse_db_, M, Rx_sig_2sps_v1, ... + Symbols_v1, Tx_bits_v1, "precode_mode", duob_mode, ... + 'showAnalysis', 0, "postFFE", []); + ber_dbtgt(i) = dbt_results.metrics.BER; + end + + %% ML-based MLSE (L=2) + mu_ml = 0.1; training_epochs = 100; + ml_mlse_equalizer = ML_MLSE("epochs_tr",training_epochs,"epochs_dd",1, ... + "len_tr",2^16,"mu_dd",mu_ml,"mu_tr",mu_ml,"order",11,"sps",2, ... + "traceback_depth",128,"L",2,"delta",4,"adaptive_mu",0); + [y_ml_mlse,y_ref] = ml_mlse_equalizer.process(Rx_sig_2sps_v1,Symbols_v1); + ref_bits = PAMmapper(M,0).demap(y_ref); + ml_bits = PAMmapper(M,0).demap(y_ml_mlse); + [~,~,ber_ml2(i)] = calc_ber(ml_bits.signal, ref_bits.signal, ... + "skip_front",10,"skip_end",10); + + %% ML-based MLSE (L=3) + ml_mlse_equalizer = ML_MLSE("epochs_tr",training_epochs,"epochs_dd",1, ... + "len_tr",2^16,"mu_dd",mu_ml,"mu_tr",mu_ml,"order",11,"sps",2, ... + "traceback_depth",128,"L",3,"delta",4,"adaptive_mu",0); + [y_ml_mlse,y_ref] = ml_mlse_equalizer.process(Rx_sig_2sps_v1,Symbols_v1); + ref_bits = PAMmapper(M,0).demap(y_ref); + ml_bits = PAMmapper(M,0).demap(y_ml_mlse); + [~,~,ber_ml3(i)] = calc_ber(ml_bits.signal, ref_bits.signal, ... + "skip_front",10,"skip_end",10); + end % ROP loop + + %% --- find required ROP (FEC crossing) + reqROP_FFE(b) = interp_fec_cross(rops, ber_ffe, FEC_thr); + reqROP_MLSE(b) = interp_fec_cross(rops, ber_mlse, FEC_thr); + reqROP_DBTGT(b) = interp_fec_cross(rops, ber_dbtgt, FEC_thr); + reqROP_ML_MLSE2(b) = interp_fec_cross(rops, ber_ml2, FEC_thr); + reqROP_ML_MLSE3(b) = interp_fec_cross(rops, ber_ml3, FEC_thr); + + % --- diagnostic + fprintf('Baud %.0f GBd: FFE %.1f, MLSE %.1f, DB %.1f, ML2 %.1f, ML3 %.1f\n', ... + baudrate/1e9, reqROP_FFE(b), reqROP_MLSE(b), reqROP_DBTGT(b), ... + reqROP_ML_MLSE2(b), reqROP_ML_MLSE3(b)); end -%% - -figure(3); hold on; -if mlse -plot(rops,ber_ffe,'DisplayName','FFE'); -plot(rops,ber_mlse,'DisplayName','MLSE'); -end -if dbtgt -plot(rops,ber_dbtgt,'DisplayName','DB tgt'); -end -plot(rops,ber_ml,'DisplayName','ML-MLSE'); -beautifyBERplot; -legend - - - - - - - +%% ====================== PLOT REQUIRED ROP ====================== +cols = cbrewer2('Set1',8); +colFFE = cols(1,:); +colMLSE = cols(2,:); +colDBTGT = cols(4,:); +colML_MLSE = cols(3,:); +figure(); hold on +plot(baudrates/1e9, reqROP_FFE, '-o','Color',colFFE, 'DisplayName','FFE'); +plot(baudrates/1e9, reqROP_MLSE, '-s','Color',colMLSE, 'DisplayName','FFE+PF+MLSE'); +plot(baudrates/1e9, reqROP_DBTGT, '--^','Color',colDBTGT, 'DisplayName','DB tgt. MLSE'); +plot(baudrates/1e9, reqROP_ML_MLSE2, '-v','Color',colML_MLSE, 'DisplayName','ML-based MLSE (L=2)'); +plot(baudrates/1e9, reqROP_ML_MLSE3, '-d','Color',colML_MLSE*0.8,'DisplayName','ML-based MLSE (L=3)'); +xlabel('Baud rate [GBd]'); +ylabel('Required ROP [dBm]'); +title('ROP required for FEC threshold'); +grid on; legend('Location','northwest'); +beautifyBERplot("logscale",0,"polyfit",1,"polyorder",4,"fitmethod",'polyfit'); diff --git a/projects/ML_based_MLSE/rrop_vs_length_evaluation.m b/projects/ML_based_MLSE/rrop_vs_length_evaluation.m new file mode 100644 index 0000000..9d2ea2b --- /dev/null +++ b/projects/ML_based_MLSE/rrop_vs_length_evaluation.m @@ -0,0 +1,140 @@ +clear; clc; + +M = 4; +randkey = 1; +duob_mode = db_mode.no_db; + +mlse = 1; +dbtgt = 1; + +link_lengths = 0:1:8; % [m] --- outer loop +rops = linspace(-10, 0, 12); % [dBm] --- inner sweep +FEC_thr = 3.8e-3; % BER target +baudrate = 200e9; + +% --- allocate results +reqROP_FFE = nan(size(link_lengths)); +reqROP_MLSE = nan(size(link_lengths)); +reqROP_DBTGT = nan(size(link_lengths)); +reqROP_ML_MLSE2 = nan(size(link_lengths)); +reqROP_ML_MLSE3 = nan(size(link_lengths)); + +%% ====================== OUTER LOOP ====================== +for L = 1:numel(link_lengths) + link_length_m = link_lengths(L); + fprintf('\n=== %.0f m fiber length ===\n', link_length_m); + + ber_ffe = nan(size(rops)); + ber_mlse = nan(size(rops)); + ber_dbtgt = nan(size(rops)); + ber_ml2 = nan(size(rops)); + ber_ml3 = nan(size(rops)); + + %% -------- inner ROP loop -------- + parfor i = 1:length(rops) + rop = rops(i); + + [Rx_sig_2sps_v1, Symbols_v1, Tx_bits_v1] = standard_link_model( ... + "M",M,"fsym",baudrate,"rop",rop,"laser_wavelength",1290, ... + "link_length_km",link_length_m,"random_key",1); + + Rx_sig_2sps_v1.spectrum("displayname",'Rx Sig','normalizeTo0dB',1); + + %% FFE + MLSE + if mlse + pf_ncoeffs = 1; + ffe_order = [50, 0, 0]; + mu_ffe = [0.0001, 0.0008, 0.001]; + mu_dfe = 0.0004; + eq_ = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",2^13, ... + "training_loops",5,"dd_loops",5,"K",2,"DCmu",0.005, ... + "DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0, ... + "plotfinal",0,"ideal_dfe",1); + pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1); + mlse_ = MLSE("duobinary_output",0,'M',M, ... + 'trellis_states',PAMmapper(M,0).levels,'scale_mode',2, ... + 'trellis_exclusion',0,'trellis_state_mode',2,'debug',0, ... + 'DIR',pf_.coefficients); + + [ffe_results, mlse_results] = vnle_postfilter_mlse(eq_, pf_, mlse_, M, ... + Rx_sig_2sps_v1, Symbols_v1, Tx_bits_v1, ... + "precode_mode", duob_mode,'showAnalysis', 0, "postFFE", [], ... + "eth_style_symbol_mapping", 0); + + ber_ffe(i) = ffe_results.metrics.BER; + ber_mlse(i) = mlse_results.metrics.BER; + end + + %% FFE + duobinary target MLSE + if dbtgt + mlse_db_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M, ... + "trellis_states",PAMmapper(M,0).levels,'scale_mode',2, ... + 'trellis_exclusion',0,'trellis_state_mode',3); + ffe_order = [50, 0, 0]; + mu_ffe = [0.0001, 0.0008, 0.001]; + mu_dfe = 0.0004; + eq_ = EQ("Ne",ffe_order,"Nb",[0,0,0],"training_length",2^13, ... + "training_loops",5,"dd_loops",5,"K",2,"DCmu",0.005, ... + "DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0, ... + "plotfinal",0,"ideal_dfe",1); + + dbt_results = duobinary_target(eq_, mlse_db_, M, Rx_sig_2sps_v1, ... + Symbols_v1, Tx_bits_v1, "precode_mode", duob_mode, ... + 'showAnalysis', 0, "postFFE", []); + ber_dbtgt(i) = dbt_results.metrics.BER; + end + + %% ML-based MLSE (L=2) + mu_ml = 0.1; training_epochs = 100; + ml_mlse_equalizer = ML_MLSE("epochs_tr",training_epochs,"epochs_dd",1, ... + "len_tr",2^16,"mu_dd",mu_ml,"mu_tr",mu_ml,"order",11,"sps",2, ... + "traceback_depth",128,"L",2,"delta",4,"adaptive_mu",0); + [y_ml_mlse,y_ref] = ml_mlse_equalizer.process(Rx_sig_2sps_v1,Symbols_v1); + ref_bits = PAMmapper(M,0).demap(y_ref); + ml_bits = PAMmapper(M,0).demap(y_ml_mlse); + [~,~,ber_ml2(i)] = calc_ber(ml_bits.signal, ref_bits.signal, ... + "skip_front",10,"skip_end",10); + + %% ML-based MLSE (L=3) + ml_mlse_equalizer = ML_MLSE("epochs_tr",training_epochs,"epochs_dd",1, ... + "len_tr",2^16,"mu_dd",mu_ml,"mu_tr",mu_ml,"order",11,"sps",2, ... + "traceback_depth",128,"L",3,"delta",4,"adaptive_mu",0); + [y_ml_mlse,y_ref] = ml_mlse_equalizer.process(Rx_sig_2sps_v1,Symbols_v1); + ref_bits = PAMmapper(M,0).demap(y_ref); + ml_bits = PAMmapper(M,0).demap(y_ml_mlse); + [~,~,ber_ml3(i)] = calc_ber(ml_bits.signal, ref_bits.signal, ... + "skip_front",10,"skip_end",10); + end % ROP loop + + %% --- find required ROP (FEC crossing) + reqROP_FFE(L) = interp_fec_cross(rops, ber_ffe, FEC_thr); + reqROP_MLSE(L) = interp_fec_cross(rops, ber_mlse, FEC_thr); + reqROP_DBTGT(L) = interp_fec_cross(rops, ber_dbtgt, FEC_thr); + reqROP_ML_MLSE2(L) = interp_fec_cross(rops, ber_ml2, FEC_thr); + reqROP_ML_MLSE3(L) = interp_fec_cross(rops, ber_ml3, FEC_thr); + + fprintf('Length %.0f m: FFE %.1f, MLSE %.1f, DB %.1f, ML2 %.1f, ML3 %.1f\n', ... + link_length_m, reqROP_FFE(L), reqROP_MLSE(L), reqROP_DBTGT(L), ... + reqROP_ML_MLSE2(L), reqROP_ML_MLSE3(L)); +end + +%% ====================== PLOT REQUIRED ROP ====================== +cols = cbrewer2('Set1',8); +colFFE = cols(1,:); +colMLSE = cols(2,:); +colDBTGT = cols(4,:); +colML_MLSE = cols(3,:); + +figure(); hold on +plot(link_lengths, reqROP_FFE, '-o','Color',colFFE, 'DisplayName','FFE'); +plot(link_lengths, reqROP_MLSE, '-s','Color',colMLSE, 'DisplayName','FFE+PF+MLSE'); +plot(link_lengths, reqROP_DBTGT, '--^','Color',colDBTGT, 'DisplayName','DB tgt. MLSE'); +plot(link_lengths, reqROP_ML_MLSE2, '-v','Color',colML_MLSE, 'DisplayName','ML-based MLSE (L=2)'); +plot(link_lengths, reqROP_ML_MLSE3, '-d','Color',colML_MLSE*0.8,'DisplayName','ML-based MLSE (L=3)'); + +xlabel('Link length [km]'); +ylabel('Required ROP [dBm]'); +title(sprintf('Required ROP the reach FEC threshold (3.8e-3); %.0f GBd PAM-%d', baudrate.*1e-9, M)); +legend('Location','northwest'); +grid on; +beautifyBERplot("logscale",0,"polyfit",1,"polyorder",3,"fitmethod",'smoothingspline'); diff --git a/projects/ML_based_MLSE/standard_link_model.m b/projects/ML_based_MLSE/standard_link_model.m index 2412af1..004c249 100644 --- a/projects/ML_based_MLSE/standard_link_model.m +++ b/projects/ML_based_MLSE/standard_link_model.m @@ -22,7 +22,7 @@ function [Rx_sig_2sps,Symbols,Tx_bits] = standard_link_model(options) options.laser_linewidth (1,1) double = 1e6 % --- Channel parameters --- - options.link_length_m (1,1) double = 0 + options.link_length_km (1,1) double = 0 options.rop (1,:) double = -5 options.fsym (1,:) double = (212:16:256)*1e9 options.doub_mode (1,1) db_mode = db_mode.no_db @@ -57,7 +57,7 @@ function [Rx_sig_2sps,Symbols,Tx_bits] = standard_link_model(options) "randomkey",options.random_key+1).process(El_sig); % --- Fiber --- - Opt_sig = Fiber("fsimu",Opt_sig.fs,"fiber_length",options.link_length_m, ... + Opt_sig = Fiber("fsimu",Opt_sig.fs,"fiber_length",options.link_length_km, ... "alpha",0.3,"D",0,"lambda0",1310,"gamma",0,"Dslope",0.07).process(Opt_sig); % --- Amplifier (ROP set) --- @@ -90,6 +90,10 @@ function [Rx_sig_2sps,Symbols,Tx_bits] = standard_link_model(options) [~,Scpe_cell,~,found_sync] = Scpe_sig_2sps.tsynch( ... "reference",Symbols,"fs_ref",options.fsym,"debug_plots",0); - Rx_sig_2sps = Scpe_cell{1}.normalize("mode","rms"); + try + Rx_sig_2sps = Scpe_cell{1}.normalize("mode","rms"); + catch + Rx_sig_2sps = Scpe_sig_2sps.normalize("mode","rms"); + end end diff --git a/projects/ML_based_MLSE/theoretic_channel_evaluation.m b/projects/ML_based_MLSE/theoretic_channel_evaluation.m new file mode 100644 index 0000000..3eb6f09 --- /dev/null +++ b/projects/ML_based_MLSE/theoretic_channel_evaluation.m @@ -0,0 +1,157 @@ + +M = 4; +order = 18; +randkey = 1; + +bitpattern = []; +s = RandStream('twister','Seed',randkey); +for i = 1:log2(M) + N = 2^(order-1); %length of prbs + bitpattern(:,i) = randi(s,[0 1], N, 1); +end + +if M == 6 + bitpattern = reshape(bitpattern',[],1); + bitpattern = bitpattern(1:end-mod(length(bitpattern),5)); +end + +Bits = Informationsignal(bitpattern); + +Symbols = PAMmapper(M,0).map(Bits); +Symbols.fs = 200e9; + +Bits_ = PAMmapper(M, 0, "eth_style", 0).demap(Symbols); + +% --- Channel: minimal ISI response + AWGN --- +h = [0.3 0.9 0.3,0.1]; % impulse response (normalized later if desired) +h = h / norm(h); % optional normalization for unit energy + +symbols_filt = Symbols.filter(h,1); + + +%% SHOW FIG 3 in Paper: "ML Base Pre-Eq" + +SNR_dB = [20:1:25]; +SNR_db = linspace(12,25,12); + +ber_ffe = zeros(size(SNR_dB)); +ber_mlse_l5 = zeros(size(SNR_dB)); +ber_nwf_mlse_l2 = zeros(size(SNR_dB)); +ber_ml_mlse_l2 = zeros(size(SNR_dB)); +ber_ml_mlse_l3 = zeros(size(SNR_dB)); +ber_ml_mlse_l4 = zeros(size(SNR_dB)); + +epochs_training = 100; + +for i = 1:numel(SNR_dB) + + symbols_noi = symbols_filt; + symbols_noi.signal = awgn(symbols_filt.signal, SNR_dB(i), 'measured'); % AWGN with given SNR + + % Sequence Est L=5 + mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels,'scale_mode',0,'trellis_exclusion',0,'trellis_state_mode',2,'debug',0,'DIR',h); + mlse_.DIR = h; + [y_mlse] = mlse_.process(symbols_noi,Symbols); + mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_mlse); + [~, ~, ber_mlse_l5(i), ~] = calc_ber(mlse_bits.signal, Bits.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1); + fprintf('MLSE L5: %.2e \n',ber_mlse_l5(i)); + + % 2nd Approach + mu_lms = 0.0005; + pf_ncoeffs = 1; + eq_ = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",2^13,"mu_dd",mu_lms,"mu_tr",mu_lms,"order",16,"sps",1,"dd_mode",1,"adaption_technique","lms"); + pf_ = Postfilter("ncoeff",pf_ncoeffs,"useBurg",1); + + % FFE + [y_ffe, ffe_noise] = eq_.process(symbols_noi, Symbols); + + Eq_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ffe); + [~, ~, ber_ffe(i), ~] = calc_ber(Eq_bits.signal, Bits.signal, "skip_front", 0, "skip_end", 0, "returnErrorLocation", 1); + fprintf('FFE: %.2e \n',ber_ffe(i)); + + % Postfilter + [y_white,~] = pf_.process(y_ffe, ffe_noise); + + % Sequence Est + mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels,'scale_mode',0,'trellis_exclusion',0,'trellis_state_mode',2,'debug',0,'DIR',pf_.coefficients); + [y_mlse] = mlse_.process(y_white,Symbols); + mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_mlse); + [~, errors, ber_nwf_mlse_l2(i), errpos] = calc_ber(mlse_bits.signal, Bits.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1); + fprintf('MLSE: %.2e \n',ber_nwf_mlse_l2(i)); + + % ML-base MLSE L=2 + adaptive_mu = 0; + mu_lms = 0.15; + ml_mlse_equalizer = ML_MLSE("epochs_tr",epochs_training,"epochs_dd",1,"len_tr",2^15,... + "mu_dd",mu_lms,"mu_tr",mu_lms,"order",11,"sps",1,... + "traceback_depth",128,"L",2,"delta",4,"adaptive_mu",adaptive_mu); + [y_ml_mlse,~] = ml_mlse_equalizer.process(symbols_noi,Symbols); + ml_mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ml_mlse); + [~, errors, ber_ml_mlse_l2(i), errpos] = calc_ber(ml_mlse_bits.signal, Bits.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1); + fprintf('ML MLSE BER: %.2e \n',ber_ml_mlse_l2(i)); + + % ML-base MLSE L=3 + mu_lms = 0.15; + ml_mlse_equalizer = ML_MLSE("epochs_tr",epochs_training,"epochs_dd",1,"len_tr",2^16,... + "mu_dd",mu_lms,"mu_tr",mu_lms,"order",11,"sps",1,... + "traceback_depth",128,"L",3,"delta",4,"adaptive_mu",adaptive_mu); + [y_ml_mlse,~] = ml_mlse_equalizer.process(symbols_noi,Symbols); + ml_mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ml_mlse); + [~, errors, ber_ml_mlse_l3(i), errpos] = calc_ber(ml_mlse_bits.signal, Bits.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1); + fprintf('ML MLSE BER: %.2e \n',ber_ml_mlse_l3(i)); + + % % ML-base MLSE L=5 + % mu_lms = 0.15; + % ml_mlse_equalizer = ML_MLSE("epochs_tr",epochs_training,"epochs_dd",1,"len_tr",2^15,... + % "mu_dd",mu_lms,"mu_tr",mu_lms,"order",11,"sps",1,... + % "traceback_depth",128,"L",5,"delta",4); + % [y_ml_mlse,~] = ml_mlse_equalizer.process(symbols_noi,Symbols); + % ml_mlse_bits = PAMmapper(M, 0, "eth_style", 0).demap(y_ml_mlse); + % [~, errors, ber_ml_mlse_l5(i), errpos] = calc_ber(ml_mlse_bits.signal, Bits.signal, "skip_front", 10, "skip_end", 10, "returnErrorLocation", 1); + % fprintf('ML MLSE BER: %.2e \n',ber_ml_mlse_l5(i)); + + +end + +%% +figure(); hold on; + +% --- define scheme colors (consistent palette) +cols = cbrewer2('SET1',8); +colFFE = cols(1,:); % blue +colMLSE = cols(2,:); % orange +colML_MLSE = cols(3,:); % green +colNWF_MLSE = cols(4,:); % purple + +% --- local simulation results +plot(SNR_dB, ber_ffe, '-o', 'Color', colFFE, 'DisplayName','FFE (N=16)'); +if M==2, plot(FFE_wpd.X, FFE_wpd.Y, ':', 'LineWidth',1.5, 'Color', colFFE, 'DisplayName','Paper FFE'); end + + +plot(SNR_dB, ber_mlse_l5, '-s', 'Color', colMLSE, 'DisplayName','MLSE (L=5)'); +if M==2, plot(MLSE_wpd.X, MLSE_wpd.Y, ':', 'LineWidth',1.5, 'Color', colMLSE, 'DisplayName','Paper MLSE L=5'); end + +plot(SNR_dB, ber_nwf_mlse_l2,'--^','Color', colNWF_MLSE, 'DisplayName','FFE+PF+MLSE (L=2)'); +plot(SNR_dB, ber_ml_mlse_l2, '-v', 'Color', colML_MLSE, 'DisplayName','ML-based MLSE (L=2)'); +if M==2, plot(ML_MLSE_L_2_wpd.X,ML_MLSE_L_2_wpd.Y,':', 'LineWidth',1.5, 'Color', colML_MLSE, 'DisplayName','Paper ML-based MLSE L=2'); end + + +plot(SNR_dB, ber_ml_mlse_l3, '-d', 'Color', colML_MLSE, 'DisplayName','ML-based MLSE (L=3)'); + +if M==2, plot(SNR_dB, ber_ml_mlse_l5, '-p', 'Color', colML_MLSE, 'DisplayName','ML-based MLSE (L=5)'); end +if M==2, plot(ML_MLSE_L_5_wpd.X,ML_MLSE_L_5_wpd.Y,':', 'LineWidth',1.5, 'Color', colML_MLSE, 'DisplayName','Paper ML-based MLSE L=5'); end +% --- imported WebPlotDigitizer data (dotted) + +yline(3.8e-3,'HandleVisibility','off'); +yline(2.2e-4,'HandleVisibility','off'); + +% --- formatting +beautifyBERplot; +xlim([SNR_dB(1), SNR_dB(end)]); +ylim([1e-5 0.1]); +xlabel('Input SNR [dB]'); +ylabel('Bit Error Rate (BER)'); +title('PAM-4; M=4; AWGN Channel'); +legend('Location','southwest'); +grid on; +