MLSE has some more class settings
DSP auswertung weiter geschrieben
This commit is contained in:
@@ -6,6 +6,10 @@ classdef MLSE < handle
|
|||||||
DIR
|
DIR
|
||||||
trellis_states
|
trellis_states
|
||||||
duobinary_output
|
duobinary_output
|
||||||
|
trellis_state_mode
|
||||||
|
trellis_exclusion
|
||||||
|
debug
|
||||||
|
scale_mode
|
||||||
end
|
end
|
||||||
|
|
||||||
methods (Access=public)
|
methods (Access=public)
|
||||||
@@ -19,7 +23,10 @@ classdef MLSE < handle
|
|||||||
options.DIR double = [1];
|
options.DIR double = [1];
|
||||||
options.trellis_states double = [-3 -1 1 3];
|
options.trellis_states double = [-3 -1 1 3];
|
||||||
options.duobinary_output logical = false;
|
options.duobinary_output logical = false;
|
||||||
|
options.trellis_state_mode = 2;
|
||||||
|
options.trellis_exclusion = 0;
|
||||||
|
options.scale_mode = 2;
|
||||||
|
options.debug = 0;
|
||||||
end
|
end
|
||||||
|
|
||||||
%
|
%
|
||||||
@@ -33,6 +40,12 @@ classdef MLSE < handle
|
|||||||
|
|
||||||
function [signalclass_hd,LLR,GMI] = process(obj,signalclass,ref_symbolclass)
|
function [signalclass_hd,LLR,GMI] = process(obj,signalclass,ref_symbolclass)
|
||||||
|
|
||||||
|
arguments
|
||||||
|
obj
|
||||||
|
signalclass
|
||||||
|
ref_symbolclass
|
||||||
|
end
|
||||||
|
|
||||||
data_in = signalclass.signal;
|
data_in = signalclass.signal;
|
||||||
shape_in = size(data_in);
|
shape_in = size(data_in);
|
||||||
data_ref = ref_symbolclass.signal;
|
data_ref = ref_symbolclass.signal;
|
||||||
@@ -54,18 +67,25 @@ classdef MLSE < handle
|
|||||||
|
|
||||||
function [VITERBI_ESTIMATION_SYMBOLS,LLR_maxlogmap,GMI] = process_(obj,data_in,data_ref)
|
function [VITERBI_ESTIMATION_SYMBOLS,LLR_maxlogmap,GMI] = process_(obj,data_in,data_ref)
|
||||||
|
|
||||||
debug = 1;
|
|
||||||
|
|
||||||
trellis_state_mode = 0; % General: States should match the target states of the prev. EQ (EQ's job was to reduce the error between signal and the target)
|
arguments
|
||||||
|
obj
|
||||||
|
data_in
|
||||||
|
data_ref
|
||||||
|
end
|
||||||
|
|
||||||
|
debug = obj.debug;
|
||||||
|
|
||||||
|
trellis_state_mode = obj.trellis_state_mode; % General: States should match the target states of the prev. EQ (EQ's job was to reduce the error between signal and the target)
|
||||||
% 0 = use provided states (MUST provide the correct states);
|
% 0 = use provided states (MUST provide the correct states);
|
||||||
% 1 = normalize to = 1 rms;
|
% 1 = normalize to = 1 rms;
|
||||||
% 2 = use target symbols;
|
% 2 = use target symbols;
|
||||||
% 3 = use statistical levels
|
% 3 = use statistical levels
|
||||||
% 3 analyzes avg of rx signal levels - can help with nonlinear impairments
|
% 3 analyzes avg of rx signal levels - can help with nonlinear impairments
|
||||||
|
|
||||||
trellis_exclusion = 0; % PAM-6 only (only if data is NOT precoded!)
|
trellis_exclusion = obj.trellis_exclusion; % PAM-6 only (only if data is NOT precoded!)
|
||||||
|
|
||||||
scale_mode = 0; % scale_mode:
|
scale_mode = obj.scale_mode; % scale_mode:
|
||||||
% 0 = no scaling,
|
% 0 = no scaling,
|
||||||
% 1 = RMS→scale MODEL,
|
% 1 = RMS→scale MODEL,
|
||||||
% 2 = MMSE/time-corr→scale MODEL,
|
% 2 = MMSE/time-corr→scale MODEL,
|
||||||
|
|||||||
@@ -201,7 +201,18 @@ try
|
|||||||
if useviterbi
|
if useviterbi
|
||||||
mlse_ = MLSE_viterbi("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels);
|
mlse_ = MLSE_viterbi("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels);
|
||||||
else
|
else
|
||||||
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels);
|
|
||||||
|
if duob_mode == db_mode.no_db && M == 6 %only for PAM-6 and no duobinary precoding, otherwise leads to false sequence estimation
|
||||||
|
trellexlusion = 1;
|
||||||
|
else
|
||||||
|
trellexlusion = 0;
|
||||||
|
end
|
||||||
|
|
||||||
|
%state_mode 3 -> stat lvl; state_mode 2 -> use target lvls
|
||||||
|
%scale_mode 2 -> mmse adaption
|
||||||
|
|
||||||
|
mlse_ = MLSE("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels,'scale_mode',2,'trellis_exclusion',trellexlusion,'trellis_state_mode',2);
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
[ffe_results, mlse_results] = vnle_postfilter_mlse(eq_, pf_, mlse_, M, Scpe_sig, Symbols, Tx_bits, ...
|
[ffe_results, mlse_results] = vnle_postfilter_mlse(eq_, pf_, mlse_, M, Scpe_sig, Symbols, Tx_bits, ...
|
||||||
@@ -253,7 +264,12 @@ try
|
|||||||
if useviterbi
|
if useviterbi
|
||||||
mlse_db_ = MLSE_viterbi("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels);
|
mlse_db_ = MLSE_viterbi("duobinary_output",0,'M',M,'trellis_states',PAMmapper(M,0).levels);
|
||||||
else
|
else
|
||||||
mlse_db_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,"trellis_states",PAMmapper(M,0).levels);
|
if duob_mode == db_mode.no_db && M == 6 %only for PAM-6 and no duobinary precoding, otherwise leads to false sequence estimation
|
||||||
|
trellexlusion = 1;
|
||||||
|
else
|
||||||
|
trellexlusion = 0;
|
||||||
|
end
|
||||||
|
mlse_db_ = MLSE("DIR",[1,1],"duobinary_output",0,"M",M,"trellis_states",PAMmapper(M,0).levels,'scale_mode',2,'trellis_exclusion',trellexlusion,'trellis_state_mode',3);
|
||||||
end
|
end
|
||||||
ffe_order = [50, 5, 5];
|
ffe_order = [50, 5, 5];
|
||||||
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);
|
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);
|
||||||
|
|||||||
@@ -17,7 +17,9 @@ fp.where('Runs', 'wavelength','EQUALS', 1310);
|
|||||||
% fp.where('Runs', 'db_mode','EQUALS', 1); % 0 == high preemphasis // 1 == low preemphasis
|
% fp.where('Runs', 'db_mode','EQUALS', 1); % 0 == high preemphasis // 1 == low preemphasis
|
||||||
fp.where('Runs', 'rop_attenuation','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);
|
eqstructures = unique(dataTable.equalizer_structure);
|
||||||
|
|
||||||
@@ -43,11 +45,12 @@ for pre_emph = [0,1]
|
|||||||
end
|
end
|
||||||
symbolrate_sorted = sortrows(eq_filtered,{'symbolrate'}, 'ascend');
|
symbolrate_sorted = sortrows(eq_filtered,{'symbolrate'}, 'ascend');
|
||||||
|
|
||||||
|
|
||||||
% Example data (replace these with your real vectors)
|
% Example data (replace these with your real vectors)
|
||||||
symbolrate = symbolrate_sorted.symbolrate.*1e-9; % in baud
|
symbolrate = symbolrate_sorted.symbolrate.*1e-9; % in baud
|
||||||
bitrate = symbolrate * 2;
|
bitrate = symbolrate * 2;
|
||||||
gmi = symbolrate_sorted.max_GMI; % BER
|
gmi = symbolrate_sorted.GMI; % BER
|
||||||
snr = symbolrate_sorted.max_SNR; % BER
|
snr = symbolrate_sorted.SNR; % BER
|
||||||
cols = cbrewer2('Paired',12);
|
cols = cbrewer2('Paired',12);
|
||||||
|
|
||||||
dname = [char(eq_choice)];
|
dname = [char(eq_choice)];
|
||||||
|
|||||||
@@ -0,0 +1,340 @@
|
|||||||
|
function h = plot_measurements_gpt(T, cfg)
|
||||||
|
% Versatile plotting from your DB table (with cbrewer2 'Paired' palette).
|
||||||
|
%
|
||||||
|
% Usage:
|
||||||
|
% h = plot_measurements_flex(dataTable, cfg)
|
||||||
|
|
||||||
|
%% ---- Defaults
|
||||||
|
if nargin < 2, cfg = struct; end
|
||||||
|
defaults = struct( ...
|
||||||
|
'x_axis' , 'symbolrate', ...
|
||||||
|
'y_axis' , 'BER', ...
|
||||||
|
'y_scale' , 'auto', ...
|
||||||
|
'group_by' , {{'equalizer_structure','pre_emph'}}, ...
|
||||||
|
'filters' , struct, ...
|
||||||
|
'agg' , 'mean', ...
|
||||||
|
'outlier' , 'auto', ...
|
||||||
|
'mad_z' , 3, ...
|
||||||
|
'pct_limits' , [2.5 97.5], ...
|
||||||
|
'min_pts_x' , 3, ...
|
||||||
|
'show_raw' , true, ...
|
||||||
|
'show_precoded', [], ...
|
||||||
|
'show_spread' , 'none', ...
|
||||||
|
'fec_lines' , [2.2e-4 4.85e-3 2e-2], ...
|
||||||
|
'plot', struct() ...
|
||||||
|
);
|
||||||
|
cfg = filldefaults(cfg, defaults);
|
||||||
|
|
||||||
|
% ---- Plot defaults (new)
|
||||||
|
plotdefs = struct( ...
|
||||||
|
'use_cbrewer2' , true, ...
|
||||||
|
'colormap' , 'Paired', ... % ColorBrewer 'Paired'
|
||||||
|
'paired_dark_first' , true, ... % dark for lines, light for scatter
|
||||||
|
'lineWidth' , 1.8, ...
|
||||||
|
'errWidth' , 1.0, ...
|
||||||
|
'scatterSize' , 14, ...
|
||||||
|
'scatterAlpha' , 0.35, ...
|
||||||
|
'marker' , 'o', ...
|
||||||
|
'marker_precoded' , 's', ...
|
||||||
|
'lineStyle_pre_emph_on' , '--', ...
|
||||||
|
'lineStyle_pre_emph_off', '-', ...
|
||||||
|
'legendLocation' , 'best', ...
|
||||||
|
'fecLineWidth' , 2.2, ... % thicker FEC limits
|
||||||
|
'fecColor' , [0.25 0.25 0.25], ...
|
||||||
|
'capSize' , 6 ...
|
||||||
|
);
|
||||||
|
cfg.plot = filldefaults(cfg.plot, plotdefs);
|
||||||
|
|
||||||
|
%% ---- Derived/prep columns
|
||||||
|
if ~ismember('pre_emph', T.Properties.VariableNames)
|
||||||
|
if ~ismember('db_mode', T.Properties.VariableNames)
|
||||||
|
error('Missing column "db_mode" for pre_emph derivation.');
|
||||||
|
end
|
||||||
|
T.pre_emph = T.db_mode == 0;
|
||||||
|
end
|
||||||
|
if ~ismember(cfg.y_axis, T.Properties.VariableNames)
|
||||||
|
error('y_axis "%s" not found in table.', cfg.y_axis);
|
||||||
|
end
|
||||||
|
|
||||||
|
isBER = startsWith(cfg.y_axis, "BER", 'IgnoreCase', true);
|
||||||
|
if strcmpi(cfg.y_scale,'auto'), cfg.y_scale = tern(isBER, 'log', 'linear'); end
|
||||||
|
if strcmpi(cfg.outlier,'auto'), cfg.outlier = tern(isBER, 'mad', 'none'); end
|
||||||
|
if isempty(cfg.show_precoded)
|
||||||
|
cfg.show_precoded = isBER && ismember('BER_precoded', T.Properties.VariableNames);
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ---- Filters
|
||||||
|
T = applyFilters(T, cfg.filters);
|
||||||
|
[x_raw, x_label] = computeX(T, cfg.x_axis);
|
||||||
|
y_raw = T.(cfg.y_axis);
|
||||||
|
|
||||||
|
validXY = isfinite(x_raw) & isfinite(y_raw);
|
||||||
|
T = T(validXY, :);
|
||||||
|
x_raw = x_raw(validXY);
|
||||||
|
y_raw = y_raw(validXY);
|
||||||
|
|
||||||
|
if cfg.show_precoded && ismember('BER_precoded', T.Properties.VariableNames)
|
||||||
|
y_raw_p = T.BER_precoded(validXY);
|
||||||
|
else
|
||||||
|
y_raw_p = [];
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ---- Grouping
|
||||||
|
group_by = cfg.group_by;
|
||||||
|
if ~all(ismember(group_by, T.Properties.VariableNames))
|
||||||
|
error('Some group_by columns are missing in table.');
|
||||||
|
end
|
||||||
|
[G, grpTbl] = findgroups(T(:, group_by));
|
||||||
|
nG = max(G);
|
||||||
|
|
||||||
|
% ==== Colors (cbrewer2 'Paired' with dark/ light pairs) ====
|
||||||
|
[cols_line, cols_scatter] = buildGroupColors(nG, cfg.plot);
|
||||||
|
|
||||||
|
%% ---- Plotting
|
||||||
|
figure; hold on; grid on;
|
||||||
|
h.lines = gobjects(nG,1);
|
||||||
|
h.err = gobjects(nG,1);
|
||||||
|
h.scat = gobjects(nG,1);
|
||||||
|
h.lines_p = gobjects(nG,1);
|
||||||
|
|
||||||
|
for gi = 1:nG
|
||||||
|
idx = (G==gi);
|
||||||
|
Ti = T(idx,:);
|
||||||
|
xi = x_raw(idx);
|
||||||
|
yi = y_raw(idx);
|
||||||
|
|
||||||
|
% Aggregate per unique x
|
||||||
|
[xu, ia, iu] = unique(xi);
|
||||||
|
yu = nan(size(xu));
|
||||||
|
ylo = nan(size(xu));
|
||||||
|
yhi = nan(size(xu));
|
||||||
|
|
||||||
|
for k = 1:numel(xu)
|
||||||
|
bin = (iu==k);
|
||||||
|
yy = yi(bin);
|
||||||
|
yy = yy(isfinite(yy));
|
||||||
|
if isempty(yy), continue; end
|
||||||
|
km = outlierMask(yy, cfg, strcmpi(cfg.y_scale,'log'));
|
||||||
|
if nnz(km) < cfg.min_pts_x, km = true(size(yy)); end
|
||||||
|
yy = yy(km);
|
||||||
|
|
||||||
|
if strcmpi(cfg.agg,'median'), yu(k)=median(yy,'omitnan'); elseif strcmpi(cfg.agg,'mean'), yu(k)=mean(yy,'omitnan'); elseif strcmpi(cfg.agg,'min'), yu(k)=min(yy); end
|
||||||
|
if strcmpi(cfg.show_spread,'iqr')
|
||||||
|
q = prctile(yy,[25 75]);
|
||||||
|
ylo(k) = max(yu(k)-q(1), eps);
|
||||||
|
yhi(k) = max(q(2)-yu(k), eps);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
% sort
|
||||||
|
[xu, ord] = sort(xu);
|
||||||
|
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);
|
||||||
|
lbl = buildLabel(grpTbl(gi,:), group_by);
|
||||||
|
|
||||||
|
% Main line (dark)
|
||||||
|
colL = cols_line(gi,:);
|
||||||
|
h.lines(gi) = plot(xu, yu, ...
|
||||||
|
'LineWidth', cfg.plot.lineWidth, ...
|
||||||
|
'Marker', cfg.plot.marker, 'MarkerSize', 5, ...
|
||||||
|
'Color', colL, 'LineStyle', ls, ...
|
||||||
|
'DisplayName', char(lbl));
|
||||||
|
|
||||||
|
% Spread (IQR) in line color
|
||||||
|
if strcmpi(cfg.show_spread,'iqr') && any(isfinite(ylo)) && any(isfinite(yhi))
|
||||||
|
h.err(gi) = errorbar(xu, yu, ylo, yhi, 'LineStyle','none', ...
|
||||||
|
'Color', colL, 'CapSize', cfg.plot.capSize, 'HandleVisibility','off');
|
||||||
|
h.err(gi).LineWidth = cfg.plot.errWidth;
|
||||||
|
end
|
||||||
|
|
||||||
|
% Raw kept scatter (light)
|
||||||
|
if cfg.show_raw
|
||||||
|
keep_all = false(size(yi));
|
||||||
|
for k = 1:numel(xu)
|
||||||
|
bin = (iu==k);
|
||||||
|
yy = yi(bin);
|
||||||
|
km = outlierMask(yy, cfg, strcmpi(cfg.y_scale,'log'));
|
||||||
|
if nnz(km) < cfg.min_pts_x, km = true(size(yy)); end
|
||||||
|
keep_all(bin) = km;
|
||||||
|
end
|
||||||
|
colS = cols_scatter(gi,:);
|
||||||
|
scatter(xi(keep_all), yi(keep_all), cfg.plot.scatterSize, colS, 'filled', ...
|
||||||
|
'MarkerFaceAlpha', cfg.plot.scatterAlpha, 'MarkerEdgeAlpha', cfg.plot.scatterAlpha, ...
|
||||||
|
'HandleVisibility','off');
|
||||||
|
end
|
||||||
|
|
||||||
|
% Precoded overlay (dotted, squares), in line color
|
||||||
|
if cfg.show_precoded && ~isempty(y_raw_p) && strcmpi(cfg.y_axis,'BER')
|
||||||
|
ypi = y_raw_p(idx);
|
||||||
|
ypu = nan(size(xu));
|
||||||
|
for k = 1:numel(xu)
|
||||||
|
bin = (iu==k);
|
||||||
|
yy = ypi(bin);
|
||||||
|
yy = yy(isfinite(yy));
|
||||||
|
if isempty(yy), continue; end
|
||||||
|
km = outlierMask(yy, cfg, true);
|
||||||
|
if nnz(km) < cfg.min_pts_x, km = true(size(yy)); end
|
||||||
|
yy = yy(km);
|
||||||
|
if strcmpi(cfg.agg,'median'), ypu(k)=median(yy,'omitnan'); elseif strcmpi(cfg.agg,'mean'), ypu(k)=mean(yy,'omitnan'); elseif strcmpi(cfg.agg,'min'), ypu(k)=min(yy); end
|
||||||
|
end
|
||||||
|
h.lines_p(gi) = plot(xu, ypu, ...
|
||||||
|
'LineWidth', max(1.2, cfg.plot.lineWidth-0.2), ...
|
||||||
|
'Marker', cfg.plot.marker_precoded, 'MarkerSize', 5, ...
|
||||||
|
'Color', colL, 'LineStyle', ':', ...
|
||||||
|
'DisplayName', [char(lbl) ' (precoded)']);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
%% ---- Axes / Labels / FEC
|
||||||
|
ylabel(cfg.y_axis, 'Interpreter','none');
|
||||||
|
xlabel(x_label, 'Interpreter','none');
|
||||||
|
set(gca, 'YScale', cfg.y_scale, 'FontSize', 11);
|
||||||
|
legend('Location', cfg.plot.legendLocation); box on;
|
||||||
|
|
||||||
|
if startsWith(cfg.y_axis,"BER",'IgnoreCase',true)
|
||||||
|
for v = cfg.fec_lines
|
||||||
|
yline(v, '--', 'Color', cfg.plot.fecColor, ...
|
||||||
|
'LineWidth', cfg.plot.fecLineWidth, 'HandleVisibility','off');
|
||||||
|
end
|
||||||
|
ylim([1e-4, 0.3]);
|
||||||
|
end
|
||||||
|
|
||||||
|
end % ===== main =====
|
||||||
|
|
||||||
|
|
||||||
|
%% ===================== Helpers =====================
|
||||||
|
|
||||||
|
function cfg = filldefaults(cfg, defs)
|
||||||
|
fn = fieldnames(defs);
|
||||||
|
for i = 1:numel(fn)
|
||||||
|
f = fn{i};
|
||||||
|
if ~isfield(cfg, f) || isempty(cfg.(f))
|
||||||
|
cfg.(f) = defs.(f);
|
||||||
|
elseif isstruct(defs.(f)) && isstruct(cfg.(f))
|
||||||
|
cfg.(f) = filldefaults(cfg.(f), defs.(f)); % recursive for structs
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function out = tern(cond, a, b)
|
||||||
|
if cond, out = a; else, out = b; end
|
||||||
|
end
|
||||||
|
|
||||||
|
function T2 = applyFilters(T, filters)
|
||||||
|
if isempty(filters), T2 = T; return; end
|
||||||
|
keep = true(height(T),1);
|
||||||
|
fns = fieldnames(filters);
|
||||||
|
for i = 1:numel(fns)
|
||||||
|
name = fns{i};
|
||||||
|
if ~ismember(name, T.Properties.VariableNames)
|
||||||
|
warning('Filter column "%s" not found. Ignored.', name); %#ok<*WNTAG>
|
||||||
|
continue
|
||||||
|
end
|
||||||
|
val = filters.(name);
|
||||||
|
col = T.(name);
|
||||||
|
if isa(val,'function_handle')
|
||||||
|
m = val(col);
|
||||||
|
if ~islogical(m) || ~isequal(size(m), size(col))
|
||||||
|
error('Filter for %s must return logical mask of same size.', name);
|
||||||
|
end
|
||||||
|
keep = keep & m;
|
||||||
|
else
|
||||||
|
keep = keep & ismember(col, val);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
T2 = T(keep,:);
|
||||||
|
end
|
||||||
|
|
||||||
|
function [x, label] = computeX(T, whichX)
|
||||||
|
switch lower(whichX)
|
||||||
|
case {'symbolrate','baudrate'}
|
||||||
|
x = T.symbolrate * 1e-9;
|
||||||
|
label = 'Symbol rate [GBd]';
|
||||||
|
case 'bitrate'
|
||||||
|
if ~ismember('pam_level', T.Properties.VariableNames)
|
||||||
|
error('bitrate requires "pam_level" column.');
|
||||||
|
end
|
||||||
|
bits = log2(double(T.pam_level));
|
||||||
|
x = (T.symbolrate .* bits) * 1e-9;
|
||||||
|
label = 'Bitrate [Gb/s]';
|
||||||
|
otherwise
|
||||||
|
if ~ismember(whichX, T.Properties.VariableNames)
|
||||||
|
error('x_axis "%s" not found in table.', whichX);
|
||||||
|
end
|
||||||
|
x = T.(whichX);
|
||||||
|
label = whichX;
|
||||||
|
end
|
||||||
|
x = double(x(:));
|
||||||
|
end
|
||||||
|
|
||||||
|
function keep = outlierMask(y, cfg, useLog)
|
||||||
|
if isempty(y), keep = false(size(y)); return; end
|
||||||
|
y = y(:);
|
||||||
|
switch lower(cfg.outlier)
|
||||||
|
case 'none'
|
||||||
|
keep = true(size(y)); return
|
||||||
|
case 'mad'
|
||||||
|
z = tern(useLog, log10(y), y);
|
||||||
|
med = median(z,'omitnan');
|
||||||
|
madv = median(abs(z-med),'omitnan');
|
||||||
|
if ~(isfinite(madv) && madv>0)
|
||||||
|
keep = true(size(y)); return
|
||||||
|
end
|
||||||
|
sigma = 1.4826*madv;
|
||||||
|
zz = tern(useLog, log10(y), y);
|
||||||
|
keep = abs(zz - med) <= cfg.mad_z*sigma;
|
||||||
|
case 'pctl'
|
||||||
|
pr = prctile(y, cfg.pct_limits);
|
||||||
|
keep = (y >= pr(1)) & (y <= pr(2));
|
||||||
|
otherwise
|
||||||
|
error('Unknown outlier mode "%s".', cfg.outlier);
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function s = buildLabel(grpRow, group_by)
|
||||||
|
parts = strings(1, numel(group_by));
|
||||||
|
for i = 1:numel(group_by)
|
||||||
|
key = group_by{i};
|
||||||
|
val = grpRow.(key);
|
||||||
|
if iscell(val), val = val{1}; end
|
||||||
|
if islogical(val), val = tern(val,'pre-emph on','pre-emph off'); end
|
||||||
|
parts(i) = sprintf('%s=%s', key, string(val));
|
||||||
|
end
|
||||||
|
s = strjoin(parts, ', ');
|
||||||
|
end
|
||||||
|
|
||||||
|
function [cols_line, cols_scatter] = buildGroupColors(nG, plotcfg)
|
||||||
|
% Build paired colors (dark for lines, light for scatter) using cbrewer2('Paired')
|
||||||
|
useBrewer = plotcfg.use_cbrewer2 && exist('cbrewer2','file')==2;
|
||||||
|
if useBrewer
|
||||||
|
N = max(2*nG, 12); % ensure pairs available
|
||||||
|
C = cbrewer2(plotcfg.colormap, N);
|
||||||
|
cols_line = zeros(nG,3);
|
||||||
|
cols_scatter = zeros(nG,3);
|
||||||
|
for i = 1:nG
|
||||||
|
if plotcfg.paired_dark_first
|
||||||
|
dark = C(2*i-1, :); light = C(2*i, :);
|
||||||
|
else
|
||||||
|
light = C(2*i-1, :); dark = C(2*i, :);
|
||||||
|
end
|
||||||
|
cols_line(i,:) = dark;
|
||||||
|
cols_scatter(i,:) = light;
|
||||||
|
end
|
||||||
|
else
|
||||||
|
% Fallback: lines() + lightened scatter
|
||||||
|
C = lines(max(nG,7));
|
||||||
|
cols_line = C(1:nG,:);
|
||||||
|
cols_scatter = zeros(nG,3);
|
||||||
|
for i = 1:nG
|
||||||
|
cols_scatter(i,:) = lightenColor(cols_line(i,:), 0.5); % 50% toward white
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function c2 = lightenColor(c, fracTowardWhite)
|
||||||
|
c = c(:).';
|
||||||
|
c2 = (1-fracTowardWhite)*c + fracTowardWhite*1;
|
||||||
|
end
|
||||||
@@ -44,7 +44,7 @@ M = 6;
|
|||||||
% fp.where('Runs', 'pam_level','EQUALS', M);
|
% fp.where('Runs', 'pam_level','EQUALS', M);
|
||||||
% fp.where('Runs', 'bitrate','EQUALS', 480e9);
|
% fp.where('Runs', 'bitrate','EQUALS', 480e9);
|
||||||
% fp.where('Runs', 'symbolrate','EQUALS', 162e9);
|
% fp.where('Runs', 'symbolrate','EQUALS', 162e9);
|
||||||
fp.where('Runs', 'fiber_length','EQUALS', 1);
|
% fp.where('Runs', 'fiber_length','EQUALS', 1);
|
||||||
fp.where('Runs', 'is_mpi','EQUALS', 0);
|
fp.where('Runs', 'is_mpi','EQUALS', 0);
|
||||||
% fp.where('Runs', 'interference_path_length','EQUALS', 1000);
|
% fp.where('Runs', 'interference_path_length','EQUALS', 1000);
|
||||||
% fp.where('Runs', 'loop_id','GREATER_THAN', 11);
|
% fp.where('Runs', 'loop_id','GREATER_THAN', 11);
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
database_type = 'mysql';
|
||||||
|
dataBase = 'labor_highspeed';%'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\silas_labor_newdsp_newstructure.db';
|
||||||
|
db = DBHandler("dataBase", [dataBase], "type", database_type);
|
||||||
|
|
||||||
|
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', 'fiber_length','EQUALS', 10);
|
||||||
|
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); % 0 == high preemphasis // 1 == low preemphasis
|
||||||
|
fp.where('Runs', 'rop_attenuation','EQUALS', 0);
|
||||||
|
|
||||||
|
fields = db.getTableFieldNames('power_state_info');
|
||||||
|
fields = [fields; db.getTableFieldNames('dashboard_ungrouped_new')];
|
||||||
|
[dataTable,~] = db.queryDB(fp, fields);
|
||||||
|
|
||||||
|
cfg = struct;
|
||||||
|
cfg.x_axis = 'accumulated_dispersion'; % 'symbolrate' | 'baudrate' | 'bitrate' | 'wavelength'
|
||||||
|
cfg.y_axis = 'BER'; % 'BER' | 'GMI' | 'AIR' | ...
|
||||||
|
cfg.group_by = {'equalizer_structure','pre_emph'};
|
||||||
|
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.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.agg = 'mean'; % or 'median'
|
||||||
|
cfg.show_precoded = 0;
|
||||||
|
cfg.fec_lines = [2.2e-4 4.85e-3 2e-2]; % optional
|
||||||
|
|
||||||
|
% New styling knobs
|
||||||
|
cfg.plot.use_cbrewer2 = true;
|
||||||
|
cfg.plot.colormap = 'Paired';
|
||||||
|
cfg.plot.paired_dark_first = false; % dark for lines, light for scatter
|
||||||
|
cfg.plot.lineWidth = 2.0;
|
||||||
|
cfg.plot.errWidth = 1.2;
|
||||||
|
cfg.plot.scatterAlpha = 0.35;
|
||||||
|
cfg.plot.legendLocation = 'best';
|
||||||
|
cfg.plot.fecLineWidth = 2.4; % thicker FEC limits
|
||||||
|
|
||||||
|
|
||||||
|
plot_measurements_gpt(dataTable, cfg);
|
||||||
Reference in New Issue
Block a user