BCJR implementation

WDM code added (Pol Cont., Opt MUX/DEMUX, Opt Atten, DP_Fiber) -> the codebase is not optimized to always work with dp signals!
This commit is contained in:
Silas Oettinghaus
2025-09-17 13:58:58 +02:00
parent f4a22d23a2
commit 4099f6820f
37 changed files with 3643 additions and 593 deletions

View File

@@ -4,30 +4,39 @@ dataBase = 'labor_highspeed';%'C:\Users\Silas\Documents\MATLAB\Datensätze\sio
db = DBHandler("dataBase", [dataBase], "type", database_type);
fp = QueryFilter();
% fp.where('Runs', 'run_id','EQUALS', 987);
% fp.where('Runs', 'run_id','EQUALS', 987);
M = 8;
fp.where('Runs', 'pam_level','EQUALS', M);
% fp.where('Runs', 'bitrate','LESS_THAN', 310e9);
fp.where('Runs', 'fiber_length','EQUALS', 2);
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','EQUALS', 1310);
% fp.where('Runs', 'db_mode','EQUALS', 1);
fp.where('Runs', 'rop_attenuation','EQUALS', 0);
fp.where('Runs', 'pam_level','EQUALS', M);
% fp.where('Runs', 'bitrate','LESS_THAN', 310e9);
fp.where('Runs', 'fiber_length','EQUALS', 2);
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','EQUALS', 1293);
% fp.where('Runs', 'db_mode','EQUALS', 0);
fp.where('Runs', 'rop_attenuation','EQUALS', 0);
% [dataTable,~] = db.queryDB(fp, db.getTableFieldNames('dashboard'));
fields = db.getTableFieldNames('power_state_info');
fields = [fields; db.getTableFieldNames('dashboard_ungrouped_new')];
[dataTable,~] = db.queryDB(fp, fields);
eqstructures = unique(dataTable.equalizer_structure);
% Create the figure
figure(10);
showFiltered = true;
showPrecoded = false;
show_bitrate = true;
figure(5);
hold on
for pre_emph = [1]
dbmode_filtered = dataTable(dataTable.db_mode == ~pre_emph,:);
for eqs = [equalizer_structure.vnle, equalizer_structure.vnle_pf_mlse , equalizer_structure.vnle_db_mlse]
for eqs = [equalizer_structure.vnle, equalizer_structure.vnle_pf_mlse]
% figure('Name',string([char(eqs),'']));
% hold on
for pre_emph = [0,1]
dbmode_filtered = dataTable(dataTable.db_mode == ~pre_emph,:);
eq_choice = equalizer_structure(eqs);
@@ -37,50 +46,238 @@ for pre_emph = [1]
end
eq_filtered = dbmode_filtered(dbmode_filtered.equalizer_structure == eq_choice,:);
symbolrate_sorted = sortrows(eq_filtered,{'symbolrate','min_BER_precoded'}, 'ascend');
[~, ia] = unique(symbolrate_sorted.symbolrate, 'first');
% ===== NEW: compute averages + per-row keep masks (robust filtering) =====
[Tav, keepMask, keepMaskP] = avgBerBySymbolrate(eq_filtered); % <= NEW
% x-values (bitrate) for raw points (same mapping as your lines)
M = unique(eq_filtered.pam_level); % (assumes single PAM per curve)
if show_bitrate
x_raw = eq_filtered.symbolrate.*1e-9 .* floor(log2(M)*10)/10;
else
x_raw = eq_filtered.symbolrate.*1e-9;
end
% ===== NEW: scatter kept raw BER points (hidden from legend) =====
cols = cbrewer2('Paired',12);
thisColor = cols((2*eqs)+1+pre_emph,:);
scatter(x_raw(keepMask), ... % kept points
eq_filtered.BER(keepMask), ...
14, thisColor, 'filled', ...
'MarkerFaceAlpha', 0.35, ...
'MarkerEdgeAlpha', 0.35, ...
'HandleVisibility','off');
if showPrecoded
scatter(x_raw(keepMaskP), ... % kept precoded points
eq_filtered.BER_precoded(keepMaskP), ...
14, thisColor, 'filled', ...
'Marker', 'square', ...
'MarkerFaceAlpha', 0.35, ...
'MarkerEdgeAlpha', 0.35, ...
'HandleVisibility','off');
end
% ===== NEW: optionally show filtered-out points in red =====
if showFiltered
bad = ~keepMask;
if any(bad)
scatter(x_raw(bad), eq_filtered.BER(bad), ...
18, 'r', 'x', 'LineWidth', 1.2, ...
'HandleVisibility','off');
end
badp = ~keepMaskP;
if any(badp)
scatter(x_raw(badp), eq_filtered.BER_precoded(badp), ...
18, 'r', '+', 'LineWidth', 1.2, ...
'HandleVisibility','off');
end
end
% Keep your sorting and one-per-symbolrate behavior (using Tav)
symbolrate_sorted = sortrows(Tav,{'symbolrate','avg_BER_calc'}, 'ascend');
[~, ia] = unique(symbolrate_sorted.symbolrate, 'first');
symbolrate_sorted = symbolrate_sorted(ia, :);
% Example data (replace these with your real vectors)
symbolrate = symbolrate_sorted.symbolrate.*1e-9; % in baud
bitrate = symbolrate * floor(log2(M)*10)/10;
ber = symbolrate_sorted.min_BER; % BER
ber_precoded = symbolrate_sorted.min_BER_precoded; % BER
cols = cbrewer2('Paired',12);
cols = [0.4660 0.6740 0.1880 ; 0.9290 0.6940 0.1250 ; 0 0.4470 0.7410; 0.4940 0.1840 0.5560]; %VNLE; PF ; DFE ; DB tgt
dname = [char(eq_choice)];
if pre_emph
if show_bitrate
% Bitrate for the averaged curves (unchanged)
xraw = symbolrate_sorted.symbolrate.*1e-9 .* floor(log2(M)*10)/10;
else
xraw = symbolrate_sorted.symbolrate.*1e-9;
end
% Use the MATLAB-averaged BERs
ber = symbolrate_sorted.avg_BER_calc;
ber_precoded = symbolrate_sorted.avg_BER_precoded_calc;
dname = strrep([char(eq_choice)],'_',' ');
if pre_emph
dname = [dname,' with pre-emph.'];
else
dname = [dname,' w/o pre-emph.'];
end
plot(bitrate, ber, 'LineWidth', 1.5, 'MarkerSize', 5,'Marker','o','LineStyle','-','Color',cols((2*eqs)+1+pre_emph,:),'MarkerEdgeColor',cols((2*eqs)+1+pre_emph,:),'MarkerFaceColor',[1,1,1],'DisplayName',[dname]);
plot(bitrate, ber_precoded, 'LineWidth', 1.5, 'MarkerSize', 5,'Marker','square','LineStyle',':','Color',cols((2*eqs)+1+pre_emph,:),'MarkerEdgeColor',cols((2*eqs)+1+pre_emph,:),'MarkerFaceColor',[1,1,1],'DisplayName',[dname,'; pre-coded']);
grid on;
% Axis labels and title
xlabel('Baud Rate GBaud', 'FontSize', 12);
ylabel('BER', 'FontSize', 12);
title('BER vs. Baud Rate', 'FontSize', 14, 'FontWeight', 'bold');
% Improve tick formatting
set(gca, 'XScale', 'linear', ...
'YScale', 'log', ...
'TickLabelInterpreter', 'latex', ...
'FontSize', 11);
legend
plot(xraw, ber, ...
'LineWidth', 1.5, 'MarkerSize', 5, ...
'Marker','o','LineStyle','-', ...
'Color',thisColor,'MarkerEdgeColor',thisColor,'MarkerFaceColor',[1,1,1], ...
'DisplayName', dname);
xticks(bitrate);
if showPrecoded
plot(xraw, ber_precoded, ...
'LineWidth', 1.5, 'MarkerSize', 5, ...
'Marker','square','LineStyle',':', ...
'Color',thisColor,'MarkerEdgeColor',thisColor,'MarkerFaceColor',[1,1,1], ...
'DisplayName', [dname,'; pre-coded']);
end
grid on;
if show_bitrate
xlabel('Net bitrate [GBps]', 'FontSize', 12);
else
xlabel('Symbol rate [GBd]', 'FontSize', 12);
end
ylabel('BER', 'FontSize', 12);
title('BER vs. Baud Rate','FontSize', 14, 'FontWeight', 'bold');
set(gca, 'XScale', 'linear', ...
'YScale', 'log', ...
'TickLabelInterpreter', 'latex', ...
'FontSize', 11);
% Optional: tighten axis limits
xlim([min(bitrate), max(bitrate)]);
ylim([5e-5, 0.5]);
xticks(xraw);
if show_bitrate
xticks(200:25:500);
xlim([350 500]);
else
xlim([min(xraw), max(xraw)]);
end
ylim([5e-4, 0.3]);
end
yline([2.2e-4, 4.85e-3, 2e-2],'LineWidth',1,'LineStyle','--','HandleVisibility','off');
end
function [Tav, keepAll, keepAllP] = avgBerBySymbolrate(T, ZT, MIN_G)
% Minimal robust averaging of BER per symbolrate (+ masks for kept points).
% Usage: [Tav, keepAll, keepAllP] = avgBerBySymbolrate(T, ZT, MIN_G)
% Defaults: ZT=3 (MAD z-thresh in log10), MIN_G=2 (min points to filter)
if nargin < 2, ZT = 5; end
if nargin < 5, MIN_G = 0; end
hasP = ismember('BER_precoded', T.Properties.VariableNames);
hasNB = ismember('numBits', T.Properties.VariableNames);
[G,~,idx] = unique(T.symbolrate);
nG = numel(G);
avgBER = nan(nG,1);
avgBERp = nan(nG,1);
keepAll = false(height(T),1);
keepAllP = false(height(T),1);
for gi = 1:nG
r = idx==gi;
x = T.BER(r);
nb = hasNB * T.numBits(r) + ~hasNB; % if missing, nb==1 (scalar expansion ok)
[avgBER(gi), keepAll(r)] = rmeanBer(x, nb, ZT, MIN_G);
if hasP
xp = T.BER_precoded(r);
[avgBERp(gi), keepAllP(r)] = rmeanBer(xp, nb, ZT, MIN_G);
end
end
Tav = table(G, avgBER, avgBERp, ...
'VariableNames', {'symbolrate','avg_BER_calc','avg_BER_precoded_calc'});
end
function [mu, keep] = rmeanBer(x, nb, ZT, MIN_G, onlyHighOutliers, minKeepThreshold)
% Robust arithmetic mean of BER with log-domain MAD filtering (returns keep mask)
%
% Params:
% x : BER values
% nb : numBits (for floor)
% ZT : MAD z-threshold
% MIN_G : min group size before filtering
% onlyHighOutliers : (bool) if true, only discard values above mean
% minKeepThreshold : values below this BER are always kept
%
% Returns:
% mu : robust mean
% keep : logical mask of kept samples
if nargin < 5, onlyHighOutliers = false; end
if nargin < 6, minKeepThreshold = 0; end
x(~isfinite(x)) = NaN;
if ~isscalar(nb), nb(~isfinite(nb)) = NaN; end
if isscalar(nb) && ~isfinite(nb), nb = 1; end
floorVal = realmin;
if ~isscalar(nb) || (isscalar(nb) && isfinite(nb) && nb~=1)
fv = 0.5 ./ max(nb, eps); % rule-of-three style floor
if isscalar(fv), floorVal = fv; else, floorVal = fv; end
end
xAdj = x;
bad = ~isfinite(xAdj) | xAdj <= 0;
if isscalar(floorVal)
xAdj(bad) = floorVal;
else
xAdj(bad) = floorVal(bad);
end
valid = isfinite(xAdj) & xAdj > 0;
keep = false(size(xAdj));
if nnz(valid)==0
mu = NaN; return
end
if nnz(valid) < MIN_G
mu = mean(xAdj(valid),'omitnan'); keep(valid)=true; return
end
lx = log10(xAdj(valid));
med = median(lx,'omitnan');
mad = median(abs(lx-med),'omitnan');
if mad<=0 || ~isfinite(mad)
keep(valid) = true;
mu = mean(xAdj(valid),'omitnan');
return
end
sigma = 1.4826*mad;
ksel = abs(lx-med) <= ZT*sigma;
% convert to linear indices
vIdx = find(valid);
% === Extension A: only drop high outliers ===
if onlyHighOutliers
logMean = mean(lx,'omitnan');
highIdx = lx > logMean;
ksel = ksel | ~highIdx; % always keep values below/equal to mean
end
% === Extension B: always keep values below minKeepThreshold ===
belowThr = xAdj(valid) < minKeepThreshold;
ksel = ksel | belowThr;
keep(vIdx(ksel)) = true;
if any(keep)
mu = mean(xAdj(keep),'omitnan');
else
mu = mean(xAdj(valid),'omitnan');
keep(valid) = true;
end
end
yline([4.85e-3, 2e-2],'LineWidth',1,'LineStyle','--','HandleVisibility','off'); beautifyBERplot();

View File

@@ -1,6 +1,6 @@
% === SETTINGS ===
dsp_options.append_to_db = 0;
dsp_options.max_occurences = 1;
dsp_options.append_to_db = 1;
dsp_options.max_occurences = 15;
experiment = "highspeed_2024";
dsp_options.mode = "load_run_id"; % 'simulate' & 'load_files'
@@ -39,29 +39,23 @@ end
% === Get Run ID's ===
fp = QueryFilter();
% fp.where('Runs', 'run_id','EQUALS', 987);
fp.where('Runs', 'pam_level','EQUALS', 4);
fp.where('Runs', 'bitrate','EQUALS', 360e9);
fp.where('Runs', 'fiber_length','EQUALS', 2);
% fp.where('Runs', 'run_id','EQUALS', 987);
M = 6;
% fp.where('Runs', 'pam_level','EQUALS', M);
% fp.where('Runs', 'bitrate','EQUALS', 480e9);
% fp.where('Runs', 'symbolrate','EQUALS', 162e9);
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','EQUALS', 1310);
fp.where('Runs', 'db_mode','EQUALS', 0);
fp.where('Runs', 'rop_attenuation','EQUALS', 0);
fp.where('Runs', 'wavelength','LESS_THAN', 1311);
% fp.where('Runs', 'db_mode','EQUALS', 0);
% fp.where('Runs', 'rop_attenuation','NOT_EQUAL', 0);
% fp.where('Runs', 'power_pd_in','GREATER_THAN', 7);
[dataTable,~] = db.queryDB(fp, db.getTableFieldNames('Runs'));
% Keep only the rows corresponding to the first occurrence of each 'sir' value
% [~, unique_indices] = unique(dataTable.sir, 'first');
% dataTable = dataTable(unique_indices, :);
% dataTable = dataTable(1,:);
% === Set LOOPS & Initialize DataStorage ===
dsp_options.parameters = struct();
% dsp_options.parameters.pf_ncoeffs = [1,2];%[0,logspace(-4,0,10)];
@@ -75,150 +69,281 @@ wh.addStorage("dbenc_package");
% === RUN IT ===
[results,wh] = submitJobs(dataTable.run_id(:), dsp_options, "serial", 'wh', wh, 'waitbar', true);
[results,wh] = submitJobs(dataTable.run_id(:), dsp_options, "parallel", 'wh', wh, 'waitbar', true);
results_db = results(dataTable.db_mode==1);
results_nodb = results(dataTable.db_mode==0);
for i = 1:numel(results_db)
% VNLE (from results_nodb)
gmi_v = cellfun(@(c) c.metrics.GMI, results_nodb{1,i}.vnle_package);
ber_v = cellfun(@(c) c.metrics.BER, results_nodb{1,i}.vnle_package);
air_v = cellfun(@(c) c.metrics.AIR, results_nodb{1,i}.vnle_package);
snr_v = cellfun(@(c) c.metrics.SNR, results_nodb{1,i}.vnle_package);
[BER_VNLE(i), idx_ber] = min(ber_v);
GMI_VNLE(i) = gmi_v(idx_ber);
AIR_VNLE(i) = air_v(idx_ber);
SNR_VNLE(i) = max(snr_v);
idx_gmi_min_vnle(i) = find(gmi_v == min(gmi_v), 1);
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);
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);
[BER_MLSE(i), idx_ber] = min(ber_m);
GMI_MLSE(i) = gmi_m(idx_ber);
AIR_MLSE(i) = air_m(idx_ber);
idx_gmi_min_mlse(i) = find(gmi_m == min(gmi_m), 1);
idx_air_max_mlse(i) = find(air_m == max(air_m), 1);
% DB (from results_db, BER_precoded)
gmi_db = cellfun(@(c) c.metrics.GMI, results_db{1,i}.dbtgt_package);
ber_db = cellfun(@(c) c.metrics.BER, results_db{1,i}.dbtgt_package);
ber_db_prec = cellfun(@(c) c.metrics.BER_precoded, results_db{1,i}.dbtgt_package);
air_db = cellfun(@(c) c.metrics.AIR, results_db{1,i}.dbtgt_package);
[BER_DB(i), idx_ber] = min(ber_db);
[BER_DB_PREC(i), idx_ber] = min(ber_db_prec);
GMI_DB(i) = gmi_db(idx_ber);
AIR_DB(i) = air_db(idx_ber);
idx_gmi_min_db(i) = find(gmi_db == min(gmi_db), 1);
idx_air_max_db(i) = find(air_db == max(air_db), 1);
% metadata
bitrate(i) = dataTable.bitrate(i);
baudrate(i) = dataTable.symbolrate(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)
% --- 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
% prepare x values in GBd
xGHz = baudrate .* 1e-9;
xticks_vals = xGHz;
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};
% wh.getStoValue('ffe_package',0.005);
% wh.getStoValue('mlse_package',0.005);
% ---------------- FIGURE : BER ----------------
figure(112+M); clf; hold on;
plot(xGHz, BER_VNLE, ...
'DisplayName','VNLE', ...
mk.VNLE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.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);
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));
grid on;
legend('Location','best');
% [dataTable,~] = db.queryDB(fp, [db.getTableFieldNames('Runs');db.getTableFieldNames('Results');db.getTableFieldNames('Equalizer')]);
% ---------------- FIGURE 15 : GMI ----------------
figure(113+M); clf; hold on;
plot(xGHz, GMI_VNLE, ...
'DisplayName','VNLE', ...
mk.VNLE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
plot(xGHz, GMI_MLSE, ...
'DisplayName','MLSE', ...
mk.MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
plot(xGHz, GMI_DB, ...
'DisplayName','DB tgt.', ...
mk.DB{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.DB);
ylim([log2(M)-1, log2(M)]);
xlabel('Baudrate in GBd');
ylabel('GMI');
set(gca, 'XTick', xticks_vals(1:2:end), 'XTickLabel', xtick_labels(1:2:end));
grid on;
legend('Location','best');
% ---------------- FIGURE 15 : AIR ----------------
m = floor(log2(M)*10)/10;
figure(114+M); clf; hold on;
plot(xGHz, GMI_VNLE.*xGHz, ...
'DisplayName','AIR VNLE', ...
mk.VNLE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
% duobinary has only one GMI curve (DB output)
plot(xGHz, GMI_MLSE.*xGHz, ...
'DisplayName','AIR MLSE', ...
mk.MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
% MLSE symbol-wise (if present)
plot(xGHz, GMI_DB.*xGHz, ...
'DisplayName','AIR DB tgt.', ...
mk.DB{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.DB);
% ylim([log2(M)-1, log2(M)]);
xlabel('Baudrate in GBd');
ylabel('AIR in Gbps');
set(gca, 'XTick', xticks_vals(1:2:end), 'XTickLabel', xtick_labels(1:2:end));
grid on;
legend('Location','best');
% ---------------- FIGURE 15 : Information Rates ----------------
tp = TransmissionPerformance;
m = floor(log2(M)*10)/10;
figure(213+M); clf; hold on;
netrates_vnle = tp.calculateNetRate(baudrate.* m, ...
'NGMI', GMI_VNLE./m, ...
'BER', BER_VNLE);
%
% dataTable = cleanUpTable(dataTable);
% wh_analyze = wh_adap;
% % wh_analyze = wh_dcremoval_old2;
% % wh_analyze = wh_dcremoval_old2;
% plot(xGHz, GMI_VNLE.*xGHz, ...
% 'DisplayName','GMI*R VNLE', ...
% mk.VNLE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
%
% res = cell(wh_analyze.parameter.mu_dc.length,wh_analyze.parameter.dc_buffer_len.length);
% ber_mean = zeros(wh_analyze.parameter.mu_dc.length,wh_analyze.parameter.dc_buffer_len.length);
% for m = 1:wh_analyze.parameter.mu_dc.length
% for b = 1:wh_analyze.parameter.dc_buffer_len.length
% res{m,b}=wh_analyze.getStoValue("ffe_package",wh_analyze.parameter.mu_dc.values(m),wh_analyze.parameter.dc_buffer_len.values(b));
% try
% cells = res{m,b}{1};
% idx = cellfun(@(c) ~isempty(c), cells);
% ber = cellfun(@(c) c.metrics.BER, cells(idx));
% ber_mean(m,b) = mean(ber);
% catch
% ber_mean(m,b) = NaN;
% end
% end
% end
%
% figure()
% hold on
% ber_fix = cellfun(@(c) c.ffe_package{1}.metrics.BER, results_fix);
% ber_adap_m2 = cellfun(@(c) c.ffe_package{1}.metrics.BER, results_adap);
% ber_adap_method1 = cellfun(@(c) c.ffe_package{1}.metrics.BER, results);
% plot(dataTable.sir,ber_fix,'LineWidth',1,'DisplayName',sprintf('DCt; fix mu = 0.5; p=1024'),'Marker','.','MarkerSize',10);
% plot(dataTable.sir,ber_adap_method1,'LineWidth',1,'DisplayName',sprintf('DCt; adap mu 1; p=1024'),'Marker','.','MarkerSize',10);
% plot(dataTable.sir,ber_adap_m2,'LineWidth',1,'DisplayName',sprintf('DCt; adap mu 2; p=1024'),'Marker','.','MarkerSize',10);
% xlabel('BER');
% xlabel('SIR');
% yline([4.85e-3,2e-2],'HandleVisibility', 'off','LineWidth',1,'LineStyle','--');
% % ylim([9e-4, 0.5]);
% set(gca, 'YScale', 'log'); % BER is usually plotted log-scale
% legend('show', 'Location', 'best');
% grid on;
% plot(xGHz, netrates_vnle.SDHD.NetRate.*1e-9, ...
% 'DisplayName','SD+HD VNLE', ...
% mk.VNLE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
% plot(xGHz, netrates_vnle.HD.NetRate.*1e-9, ...
% 'DisplayName','Staircase VNLE', ...
% mk.VNLE{:}, 'LineStyle','-.','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
%
%
% %
% % MLSE symbol-wise (if present)
% plot(xGHz, GMI_MLSE.*xGHz, ...
% 'DisplayName','GMI*R MLSE', ...
% mk.MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
%
%
% figure; clf
%
% % Create meshgrid for contourf
% [X, Y] = meshgrid(dsp_options.parameters.mu_dc, dsp_options.parameters.dc_buffer_len);
%
% % Create contour plot
% contourf(X, Y, ber_mean', 20); % 20 contour levels, adjust as needed
%
% % Set axes to logarithmic scale
% set(gca, 'XScale', 'log', 'YScale', 'log');
%
% colormap("parula");
% c = colorbar;
% c.Label.String = 'BER';
%
% xlabel('\mu_{dc}');
% ylabel('dc\_buffer\_len');
% title('BER Optimization over \mu_{dc} and dc\_buffer\_len');
%
% % Make plot prettier
% grid on
% set(gca, 'Layer', 'top'); % Put grid lines on top of contours
%
%
% % === Look at it ===
% y_var = 'BER_precoded';
% x_var = 'bitrate';
% fixedVars = {'equalizer_structure', x_var};
%
% [dataTableClean, outliersTable] = removeGroupOutliers(dataTable, fixedVars, y_var);
%
% % --- Group and aggregate ---
% dataTableGrpd_mean = groupIt(fixedVars, dataTableClean, @mean);
% dataTableGrpd_min = groupIt(fixedVars, dataTableClean, @min);
% dataTableGrpd_max = groupIt(fixedVars, dataTableClean, @max);
%
% % Choose a color map
% cols = linspecer(numel(unique(dataTableGrpd_mean.equalizer_structure)));
%
% figure;
% hold on;
%
% % Get unique equalizer structures for grouping
% unique_eq = unique(dataTableGrpd_mean.equalizer_structure);
%
% for i = 1:numel(unique_eq)
% eq_val = unique_eq(i);
%
% % Filter grouped data for this equalizer structure
% filt = dataTableGrpd_mean.equalizer_structure == eq_val;
%
% x = dataTableGrpd_mean.(x_var)(filt);
% y_mean = dataTableGrpd_mean.(y_var)(filt);
% y_min = dataTableGrpd_min.(y_var)(filt);
% y_max = dataTableGrpd_max.(y_var)(filt);
%
% % Bounds for boundedline (distance from mean)
% y_lower = y_mean - y_min;
% y_upper = y_max - y_mean;
% y_bounds = [y_lower, y_upper];
%
% % --- Bounded line (mean ± min/max) ---
% if exist('boundedline', 'file')
% [hl, hp] = boundedline(x, y_mean, y_bounds, ...
% 'alpha', 'transparency', 0.1, ...
% 'cmap', cols(i,:), ...
% 'nan', 'fill', ...
% 'orientation', 'vert');
% set(hl, 'LineWidth', 1.2, 'DisplayName', sprintf('Eq %s', eq_val));
% set(hp, 'HandleVisibility', 'off');
% else
% % If boundedline is not available, use errorbar
% errorbar(x, y_mean, y_lower, y_upper, ...
% 'o-', 'Color', cols(i,:), 'LineWidth', 1.2, ...
% 'DisplayName', sprintf('Eq %d', eq_val),'HandleVisibility', 'off');
% end
%
% % --- Normal line (mean only) ---
% plot(x, y_mean, '-', 'Color', cols(i,:), 'LineWidth', 1.5, ...
% 'DisplayName', sprintf('Mean Eq %s', eq_val),'HandleVisibility', 'off');
%
% % --- Scatter plot for individual points (from original data) ---
% % Filter original data for this group
% orig_filt = dataTableClean.equalizer_structure == eq_val;
% x_scatter = dataTableClean.(x_var)(orig_filt);
% y_scatter = dataTableClean.(y_var)(orig_filt);
%
% scatter(x_scatter, y_scatter, 10,cols(i,:), 'filled', ...
% 'MarkerFaceAlpha', 0.5, 'DisplayName', sprintf('Scatter Eq %s', eq_val),'HandleVisibility', 'off');
% end
%
% yline([2.2e-4,4.85e-3,2e-2],'HandleVisibility', 'off','LineWidth',1,'LineStyle','--');
% set(gca, 'YScale', 'log'); % BER is usually plotted log-scale
% xlabel(x_var, 'Interpreter', 'none');
% ylabel(y_var, 'Interpreter', 'none');
% legend('show', 'Location', 'best');
% grid on;
% title(sprintf('%s vs. %s', y_var, x_var), 'Interpreter', 'none');
% hold off;
% netrates_mlse = tp.calculateNetRate(baudrate.* m, ...
% 'NGMI', GMI_MLSE./m, ...
% 'BER', BER_MLSE);
% plot(xGHz, netrates_mlse.SDHD.NetRate.*1e-9, ...
% 'DisplayName','SD+HD MLSE', ...
% mk.MLSE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
% plot(xGHz, netrates_mlse.HD.NetRate.*1e-9, ...
% 'DisplayName','Staircase MLSE', ...
% mk.MLSE{:}, 'LineStyle','-.','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
% duobinary has only one GMI curve (DB output)
figure(1111); clf; hold on;
plot(xGHz, GMI_DB.*xGHz, ...
'DisplayName','GMI*R DB tgt.', ...
mk.DB{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.DB);
netrates_db = tp.calculateNetRate(baudrate.* m, ...
'NGMI', GMI_DB./m, ...
'BER', BER_DB_PREC);
plot(xGHz, netrates_db.SDHD.NetRate.*1e-9, ...
'DisplayName','SD+HD DB', ...
mk.DB{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.DB);
plot(xGHz, netrates_db.STAIR.NetRate.*1e-9, ...
'DisplayName','Staircase DB', ...
mk.DB_precode{:}, 'LineStyle','-.','LineWidth',LINE_WIDTH,'Color',cm.DB_precode);
plot(xGHz, netrates_db.O_FEC.NetRate.*1e-9, ...
'DisplayName','O-FEC DB', ...
mk.DB_precode{:}, 'LineStyle','--','LineWidth',LINE_WIDTH,'Color',cm.DB_precode);
plot(xGHz, netrates_db.KP4_hamming.NetRate.*1e-9, ...
'DisplayName','KP4 Hamming DB', ...
mk.DB_precode{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.DB_precode);
% ylim([log2(M)-1, log2(M)]);
xlabel('Baudrate in GBd');
ylabel('AIR in Gbps');
set(gca, 'XTick', xticks_vals(1:2:end), 'XTickLabel', xtick_labels(1:2:end));
grid on;
legend('Location','best');
% xlim([1, 256])
figure(2222); clf; hold on;
plot(xGHz, GMI_MLSE.*xGHz, ...
'DisplayName','GMI*R DB tgt.', ...
mk.MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
netrates_mlse = tp.calculateNetRate(baudrate.* m, ...
'NGMI', GMI_MLSE./m, ...
'BER', BER_MLSE);
plot(xGHz, netrates_mlse.SDHD.NetRate.*1e-9, ...
'DisplayName','SD+HD DB', ...
mk.MLSE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
plot(xGHz, netrates_mlse.STAIR.NetRate.*1e-9, ...
'DisplayName','Staircase DB', ...
mk.VNLE{:}, 'LineStyle','-.','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
plot(xGHz, netrates_mlse.O_FEC.NetRate.*1e-9, ...
'DisplayName','O-FEC DB', ...
mk.VNLE{:}, 'LineStyle','--','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
plot(xGHz, netrates_mlse.KP4_hamming.NetRate.*1e-9, ...
'DisplayName','KP4 Hamming DB', ...
mk.VNLE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
% ylim([log2(M)-1, log2(M)]);
xlabel('Baudrate in GBd');
ylabel('AIR in Gbps');
set(gca, 'XTick', xticks_vals(1:2:end), 'XTickLabel', xtick_labels(1:2:end));
grid on;
legend('Location','best');
% xlim([1, 256])
figure(3333); clf; hold on;
plot(xGHz, GMI_VNLE.*xGHz, ...
'DisplayName','GMI*R DB tgt.', ...
mk.MLSE{:}, 'LineStyle','-','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
netrates_vnle = tp.calculateNetRate(baudrate.* m, ...
'NGMI', GMI_VNLE./m, ...
'BER', BER_VNLE);
plot(xGHz, netrates_vnle.SDHD.NetRate.*1e-9, ...
'DisplayName','SD+HD DB', ...
mk.MLSE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.MLSE);
plot(xGHz, netrates_vnle.STAIR.NetRate.*1e-9, ...
'DisplayName','Staircase DB', ...
mk.VNLE{:}, 'LineStyle','-.','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
plot(xGHz, netrates_vnle.O_FEC.NetRate.*1e-9, ...
'DisplayName','O-FEC DB', ...
mk.VNLE{:}, 'LineStyle','--','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
plot(xGHz, netrates_vnle.KP4_hamming.NetRate.*1e-9, ...
'DisplayName','KP4 Hamming DB', ...
mk.VNLE{:}, 'LineStyle',':','LineWidth',LINE_WIDTH,'Color',cm.VNLE);
% ylim([log2(M)-1, log2(M)]);
xlabel('Baudrate in GBd');
ylabel('AIR in Gbps');
set(gca, 'XTick', xticks_vals(1:2:end), 'XTickLabel', xtick_labels(1:2:end));
grid on;
legend('Location','best');
% xlim([1, 256])