während Diss, 400G plots

This commit is contained in:
Silas Oettinghaus
2026-08-13 10:22:01 +02:00
parent 7a9deaeb0c
commit c77327d39f
27 changed files with 1769 additions and 248 deletions

View File

@@ -0,0 +1,241 @@
%% Best pre-emphasis and precoding settings at 2 km / 1310 nm
% The four requested technique labels map to the stored equalizer classes:
% VNLE -> vnle
% MLSE -> VNLE + PF + MLSE (vnle_pf_mlse)
% DB tgt. -> VNLE DBt. + MLSE (vnle_db_mlse)
% ML based -> ML pre-EQ + Viterbi (ml_mlse)
%
% For every technique and PAM format, the globally lowest valid BER is
% selected across the available gross rates, db_mode 0/1 variants, and
% BER/BER_precoded variants. The resulting table reports binary settings:
% preemph = 0/1 and precode = 0/1.
clear; clc;
%% 1) Query the 2 km / 1310 nm normal-link data
selectedFiberLengthKm = 2;
selectedWavelengthNm = 1310;
selectedRopAttenuation = 0;
selectedIsMpi = 0;
selectedPamLevels = [4 6 8];
normalDbModes = [double(db_mode.no_db), double(db_mode.db_precoded)];
techniques = table( ...
["VNLE"; "MLSE"; "DB tgt."; "ML based"], ...
["vnle"; "vnle_pf_mlse"; "vnle_db_mlse"; "ml_mlse"], ...
'VariableNames', ["technique", "algorithm_key"]);
db = DBHandler( ...
"dataBase", "labor_highspeed", ...
"type", "mysql", ...
"server", "192.168.178.192", ...
"user", "silas", ...
"password", "silas");
db.refresh();
fp = QueryFilter();
fp.where("Runs", "fiber_length", "EQUALS", selectedFiberLengthKm);
fp.where("Runs", "wavelength", "EQUALS", selectedWavelengthNm);
fp.where("Runs", "rop_attenuation", "EQUALS", selectedRopAttenuation);
fp.where("Runs", "is_mpi", "EQUALS", selectedIsMpi);
fields = db.getTableFieldNames('dashboard_ungrouped_alltime');
fields = appendMissingFields(fields, {'Runs.precomp_amp'; 'Runs.is_mpi'});
[rawData, query] = db.queryDB(fp, fields);
disp(query);
data = cleanRows(rawData);
data = data(ismember(data.db_mode, normalDbModes) & ...
ismember(data.pam_level, selectedPamLevels), :);
if ~ismember("precomp_amp", string(data.Properties.VariableNames))
warning("check_best_settings:NoPrecompAmp", ...
"Runs.precomp_amp was not returned; using db_mode == 0 as preemph = 1.");
data.pre_emphasis = data.db_mode == double(db_mode.no_db);
else
data.pre_emphasis = derivePreEmphasis(data.precomp_amp, data.db_mode);
end
%% 2) Build BER and BER_precoded candidates
baseRows = data(isfinite(data.BER) & data.BER > 0, :);
baseRows.precode = zeros(height(baseRows), 1);
baseRows.BER_plot = baseRows.BER;
baseRows.algorithm_key = algorithmKeyFromEqualizer(baseRows.equalizer_structure);
baseRows = baseRows(baseRows.algorithm_key ~= "", :);
if ismember("BER_precoded", string(data.Properties.VariableNames))
precodedRows = data(isfinite(data.BER_precoded) & data.BER_precoded > 0, :);
precodedRows.precode = ones(height(precodedRows), 1);
precodedRows.BER_plot = precodedRows.BER_precoded;
precodedRows.algorithm_key = algorithmKeyFromEqualizer( ...
precodedRows.equalizer_structure);
precodedRows = precodedRows(precodedRows.algorithm_key ~= "", :);
metricRows = [baseRows; precodedRows];
else
warning("check_best_settings:NoPrecodedBer", ...
"BER_precoded was not returned; only precode = 0 is available.");
metricRows = baseRows;
end
fprintf("Candidate rows: %d\n", height(metricRows));
%% 3) Find the lowest BER and its binary settings
numResults = height(techniques) * numel(selectedPamLevels);
best = repmat(struct( ...
"technique", "", ...
"algorithm_key", "", ...
"pam", NaN, ...
"BER", NaN, ...
"preemph", NaN, ...
"precode", NaN, ...
"db_mode", NaN, ...
"grossrate_Gbps", NaN, ...
"symbolrate_GBd", NaN), numResults, 1);
resultIdx = 0;
for techniqueIdx = 1:height(techniques)
for pamIdx = 1:numel(selectedPamLevels)
resultIdx = resultIdx + 1;
algorithmKey = techniques.algorithm_key(techniqueIdx);
pamLevel = selectedPamLevels(pamIdx);
candidates = metricRows( ...
metricRows.algorithm_key == algorithmKey & ...
metricRows.pam_level == pamLevel, :);
best(resultIdx).technique = techniques.technique(techniqueIdx);
best(resultIdx).algorithm_key = algorithmKey;
best(resultIdx).pam = pamLevel;
if isempty(candidates)
continue
end
[~, bestRowIdx] = min(candidates.BER_plot);
row = candidates(bestRowIdx, :);
best(resultIdx).BER = row.BER_plot;
best(resultIdx).preemph = double(row.pre_emphasis);
best(resultIdx).precode = double(row.precode);
best(resultIdx).db_mode = double(row.db_mode);
best(resultIdx).grossrate_Gbps = double(row.grossrate) .* 1e-9;
best(resultIdx).symbolrate_GBd = double(row.symbolrate) .* 1e-9;
end
end
bestRows = struct2table(best);
disp(bestRows);
%% 4) Compact tables for direct use in the thesis configuration
binaryTable = table(techniques.technique, ...
NaN(height(techniques), 1), NaN(height(techniques), 1), ...
NaN(height(techniques), 1), NaN(height(techniques), 1), ...
NaN(height(techniques), 1), NaN(height(techniques), 1), ...
'VariableNames', ["technique", ...
"PAM4_preemph", "PAM4_precode", ...
"PAM6_preemph", "PAM6_precode", ...
"PAM8_preemph", "PAM8_precode"]);
labelTable = table(techniques.technique, strings(height(techniques), 1), ...
strings(height(techniques), 1), strings(height(techniques), 1), ...
'VariableNames', ["technique", "PAM4", "PAM6", "PAM8"]);
for rowIdx = 1:height(bestRows)
techniqueIdx = find(techniques.algorithm_key == bestRows.algorithm_key(rowIdx), 1);
pamField = sprintf("PAM%d", bestRows.pam(rowIdx));
binaryTable.(sprintf("%s_preemph", pamField))(techniqueIdx) = ...
bestRows.preemph(rowIdx);
binaryTable.(sprintf("%s_precode", pamField))(techniqueIdx) = ...
bestRows.precode(rowIdx);
if isfinite(bestRows.BER(rowIdx))
labelTable.(pamField)(techniqueIdx) = sprintf( ...
"preemph=%d, precode=%d (BER=%.3g)", ...
bestRows.preemph(rowIdx), bestRows.precode(rowIdx), ...
bestRows.BER(rowIdx));
else
labelTable.(pamField)(techniqueIdx) = "no valid BER";
end
end
disp("Binary setting table:");
disp(binaryTable);
disp("Settings with winning BER:");
disp(labelTable);
%% Local helpers
function fields = appendMissingFields(fields, extraFields)
fields = cellstr(fields);
extraFields = cellstr(extraFields);
for idx = 1:numel(extraFields)
if ~any(strcmp(fields, extraFields{idx}))
fields{end+1, 1} = extraFields{idx}; %#ok<AGROW>
end
end
end
function T = cleanRows(T)
numericFields = ["result_id", "run_id", "eq_id", "bitrate", ...
"grossrate", "symbolrate", "pam_level", "wavelength", ...
"fiber_length", "db_mode", "rop_attenuation", "precomp_amp", ...
"numBits", "numBitErr", "BER", "numBitErr_precoded", ...
"BER_precoded", "GMI", "AIR", "NGMI"];
for fieldIdx = 1:numel(numericFields)
fieldName = numericFields(fieldIdx);
if ismember(fieldName, string(T.Properties.VariableNames))
T.(char(fieldName)) = numericColumn(T.(char(fieldName)));
end
end
end
function preEmphasis = derivePreEmphasis(precompAmp, dbMode)
preEmphasis = false(size(dbMode));
validPrecomp = isfinite(precompAmp);
preEmphasis(validPrecomp) = precompAmp(validPrecomp) > -45;
missingPrecomp = ~validPrecomp;
preEmphasis(missingPrecomp) = ...
dbMode(missingPrecomp) == double(db_mode.no_db);
end
function algorithmKey = algorithmKeyFromEqualizer(equalizerColumn)
eqNumeric = equalizerNumeric(equalizerColumn);
algorithmKey = strings(size(eqNumeric));
algorithmKey(eqNumeric == double(equalizer_structure.vnle)) = "vnle";
algorithmKey(eqNumeric == double(equalizer_structure.vnle_pf_mlse)) = ...
"vnle_pf_mlse";
algorithmKey(eqNumeric == double(equalizer_structure.vnle_db_mlse)) = ...
"vnle_db_mlse";
algorithmKey(eqNumeric == double(equalizer_structure.ml_mlse)) = "ml_mlse";
end
function eqNumeric = equalizerNumeric(equalizerColumn)
if isa(equalizerColumn, "equalizer_structure") || isnumeric(equalizerColumn)
eqNumeric = double(equalizerColumn);
return
end
equalizerString = string(equalizerColumn);
eqNumeric = str2double(equalizerString);
enumNames = ["vnle", "vnle_pf_mlse", "vnle_db_mlse", "ml_mlse"];
enumValues = [double(equalizer_structure.vnle), ...
double(equalizer_structure.vnle_pf_mlse), ...
double(equalizer_structure.vnle_db_mlse), ...
double(equalizer_structure.ml_mlse)];
for idx = 1:numel(enumNames)
missingNumeric = isnan(eqNumeric);
eqNumeric(missingNumeric & equalizerString == enumNames(idx)) = ...
enumValues(idx);
end
end
function values = numericColumn(values)
if iscell(values)
values = string(values);
end
if isstring(values) || ischar(values)
values = str2double(values);
end
values = double(values);
end

View File

@@ -35,10 +35,6 @@ fp.where('Runs', 'wavelength', SqlOperator.EQUALS, wavelength);
fp.where('Runs', 'is_mpi', SqlOperator.EQUALS, is_mpi);
fp.where('Runs', 'db_mode', 'LESS_THAN', 2);
fp.where('Runs', 'rop_attenuation', SqlOperator.EQUALS, rop_attenuation);
% fp.where('Runs', 'symbolrate','EQUALS', 180e9);
% if ~isempty(baudrate_GBd)
% fp.where('Runs', 'symbolrate', SqlOperator.IN, baudrate_GBd*1e9);
% end
fields = [db.getTableFieldNames('dashboard_ungrouped_alltime')];
fields = unique(fields, 'stable');
@@ -65,6 +61,12 @@ for runIndex = 1:numel(run_ids)
runData = queryRunid(run_ids(runIndex), db);
fsym = double(runData.symbolrate(1));
bitrate = double(runData.bitrate(1));
symbolrate = double(runData.symbolrate(1));
if double(runData.db_mode) == 0 || double(runData.db_mode) == 2
ispreemph = 1;
elseif double(runData.db_mode) == 1
ispreemph = 0;
end
dsp_options.max_occurences = 20;
dsp_options.start_occurence = 2;
@@ -94,53 +96,54 @@ for runIndex = 1:numel(run_ids)
"plotfinal", 0, ...
"ideal_dfe", 1);
% eq_ = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",len_tr, ...
% "mu_dd",1e-1,"mu_tr",0.4,"order",50, ...
% "sps",2,"decide",0,"optmize_mus",1,"dd_mode",1, ...
% "adaption_technique","nlms","dc_tracking_mu",1.021e-05);
[equalized_signal, eq_noise] = eq_vnle.process(Scpe_sig, Symbols);
postfilter_order = 3;
pf = Postfilter("ncoeff", postfilter_order, "useBurg", 1);
[mlse_sig_sd,whitened_noise] = pf.process(equalized_signal, eq_noise);
% mlse = MLSE( ...
% "DIR", [0 0], ...
% "duobinary_output", 0, ...
% "M", M, ...
% "trellis_states", PAMmapper(M, 0).levels);
%
% [results, ~] = vnle_postfilter_mlse( ...
% eq_vnle, pf, mlse, M, Scpe_sig, Symbols, Tx_bits, ...
% "precode_mode", db_mode.no_db, ...
% "showAnalysis", 0, ...
% "postFFE", [], ...
% "eth_style_symbol_mapping", 0);
%
dbt = 1;
if dbt
Symbols_ = Duobinary().encode(Symbols);
else
Symbols_ = Symbols;
end
[equalized_signal, eq_noise] = eq_vnle.process(Scpe_sig, Symbols_);
eq_noise = eq_noise - mean(eq_noise.signal);
fig = figure(220+runIndex);
showEQNoisePSD(eq_noise, ...
"fignum", fig.Number, ...
"displayname", sprintf('%.0f Gbps: VNLE Noise', bitrate*1e-9), ...
"postfilter_taps", pf.coefficients, ...
"colormode", "qualitative");
whitened_noise = whitened_noise - mean(whitened_noise.signal);
whitened_noise.spectrum("displayname", 'Whitened Noise', "fignum", fig.Number, "normalizeTo0dB", 0,"fft_length",4096,"normalizeToDC",0);
if ~dbt
postfilter_order = 3;
pf = Postfilter("ncoeff", postfilter_order, "useBurg", 1);
[mlse_sig_sd,whitened_noise] = pf.process(equalized_signal, eq_noise);
end
fig = figure(220);
if ~dbt
showEQNoisePSD(eq_noise, ...
"fignum", fig.Number, ...
"displayname", sprintf('EEN: %.0f GBd; preemph: %d', symbolrate*1e-9,ispreemph), ...
"postfilter_taps", pf.coefficients, ...
"colormode", "qualitative","color",clr.Paired.lblue);
whitened_noise = whitened_noise - mean(whitened_noise.signal);
whitened_noise.spectrum("displayname", 'Whitened Noise', "fignum", fig.Number, "normalizeTo0dB", 0,"fft_length",4096,"normalizeToDC",0,"color",clr.Paired.dblue);
else
showEQNoisePSD(eq_noise, ...
"fignum", fig.Number, ...
"displayname", sprintf('EEN: %.0f GBd; preemph: %d', symbolrate*1e-9,ispreemph), ...
"colormode", "qualitative","color",clr.Paired.lblue);
end
xlabel('Frequency in GHz');
ylabel('normalized to 0 dB');
% title('Noise of soft decision signal (not MLSE)');
grid on;
grid minor;
legend('show', 'Interpreter', 'none', 'Location', 'best');
% ylim([-70 -50]);
max_fs = max(max_fs, eq_noise.fs);
xlim([-max_fs/2 max_fs/2]*1e-9);
end
xlabel('Frequency in GHz');
ylabel('normalized to 0 dB');
title('Noise of soft decision signal (not MLSE)');
grid on;
grid minor;
legend('show', 'Interpreter', 'none', 'Location', 'best');
xlim([-max_fs/2 max_fs/2]*1e-9);
ylim([-20 0]);
function signalOut = averageScopeSignals(scopeCell, averageSignals, gain)
signalOut = scopeCell{1};

View File

@@ -0,0 +1,407 @@
%% Maximum AIR over wavelength at 10 km
% One curve is shown for each selected EQ/PAM contender. For every
% wavelength, the row with the maximum AIR is retained across the available
% symbol rates and normal db_mode 0/1 variants.
% DBS uses db_mode = 2, equalizer_structure = db_encoded, and only results
% processed after 2026-01-01.
clear; clc;
%% 1) Configuration
normalFiberLengthKm = 2;
duobinaryFiberLengthKm = 10;
selectedRopAttenuation = 0;
selectedIsMpi = 0;
duobinaryDateCutoff = datetime("2026-01-01 00:00:00");
% Thesis colors and curve/PAM mapping.
curves = struct;
curves(1).name = "DBS + VNLE + MLSE (PAM-4)";
curves(1).algorithm_key = "db_encoded";
curves(1).pam = 4;
curves(1).color = clr.Paired.orange;
curves(1).marker = "square";
curves(1).source = "duobinary";
curves(1).usePrecodedBer = false;
curves(2).name = "VNLE DBt. + MLSE";
curves(2).algorithm_key = "vnle_db_mlse";
curves(2).pam = 4;
curves(2).color = clr.Paired.blue;
curves(2).marker = "square";
curves(2).source = "normal";
curves(2).usePrecodedBer = true;
% curves(3).name = "ML pre-EQ + Viterbi";
% curves(3).algorithm_key = "ml_mlse";
% curves(3).pam = 4;
% curves(3).color = clr.Paired.purple;
% curves(3).marker = "square";
% curves(3).source = "normal";
% curves(3).usePrecodedBer = true;
curves(3).name = "VNLE + PF + MLSE";
curves(3).algorithm_key = "vnle_pf_mlse";
curves(3).pam = 6;
curves(3).color = clr.Paired.green;
curves(3).marker = "v";
curves(3).source = "normal";
curves(3).usePrecodedBer = false;
% curves(5).name = "ML pre-EQ + Viterbi";
% curves(5).algorithm_key = "ml_mlse";
% curves(5).pam = 6;
% curves(5).color = clr.Paired.purple;
% curves(5).marker = "v";
% curves(5).source = "normal";
% curves(5).usePrecodedBer = true;
curves(4).name = "DBS + VNLE + MLSE (PAM-6)";
curves(4).algorithm_key = "db_encoded";
curves(4).pam = 6;
curves(4).color = clr.Paired.orange;
curves(4).marker = "v";
curves(4).source = "duobinary";
curves(4).usePrecodedBer = false;
curves(5).name = "VNLE + PF + MLSE";
curves(5).algorithm_key = "vnle_pf_mlse";
curves(5).pam = 8;
curves(5).color = clr.Paired.red;
curves(5).marker = "o";
curves(5).source = "normal";
curves(5).usePrecodedBer = false;
%% 2) Query normal and DBS rows over all wavelengths
db = DBHandler( ...
"dataBase", "labor_highspeed", ...
"type", "mysql", ...
"server", "192.168.178.192", ...
"user", "silas", ...
"password", "silas");
db.refresh();
selectedFields = db.getTableFieldNames('dashboard_ungrouped_alltime');
normalRows = queryRows(db, selectedFields, normalFiberLengthKm, ...
selectedRopAttenuation, selectedIsMpi);
normalRows = cleanRows(normalRows);
normalRows = normalRows(ismember(normalRows.db_mode, ...
[double(db_mode.no_db), double(db_mode.db_precoded)]), :);
normalRows.algorithm_key = lower(string(normalRows.equalizer_structure));
duobinaryRows = queryRows(db, selectedFields, duobinaryFiberLengthKm, ...
selectedRopAttenuation, selectedIsMpi);
duobinaryRows = cleanRows(duobinaryRows);
duobinaryRows = duobinaryRows( ...
duobinaryRows.db_mode == double(db_mode.db_encoded), :);
duobinaryRows = duobinaryRows( ...
equalizerMask(duobinaryRows.equalizer_structure, ...
equalizer_structure.db_encoded), :);
if ismember("date_of_processing", string(duobinaryRows.Properties.VariableNames))
duobinaryRows.date_of_processing = ...
datetime(string(duobinaryRows.date_of_processing));
duobinaryRows = duobinaryRows( ...
datetime(duobinaryRows.date_of_processing) > duobinaryDateCutoff, :);
else
warning("plot_air_wavelength:NoProcessingDate", ...
"date_of_processing was not returned; no DBS date filter was applied.");
end
duobinaryRows.algorithm_key = repmat("db_encoded", height(duobinaryRows), 1);
normalRows = addAirMetric(normalRows);
duobinaryRows = addAirMetric(duobinaryRows);
fprintf("Normal %g km rows: %d\n", normalFiberLengthKm, height(normalRows));
fprintf("DBS %g km rows after date filter: %d\n", ...
duobinaryFiberLengthKm, height(duobinaryRows));
%% 3) Select maximum AIR per wavelength for every configured curve
tp = TransmissionPerformance;
results = repmat(emptyResult(), numel(curves), 1);
for curveIdx = 1:numel(curves)
curve = curves(curveIdx);
if curve.source == "normal"
sourceRows = normalRows;
else
sourceRows = duobinaryRows;
end
curveRows = sourceRows(sourceRows.pam_level == curve.pam & ...
sourceRows.algorithm_key == curve.algorithm_key, :);
curveRows.BER_plot = curveRows.BER;
if curve.usePrecodedBer && ismember("BER_precoded", ...
string(curveRows.Properties.VariableNames))
usePrecoded = isfinite(curveRows.BER_precoded);
curveRows.BER_plot(usePrecoded) = curveRows.BER_precoded(usePrecoded);
end
measuredNgmi = numericOrNaN(curveRows, "NGMI");
measuredBer = numericOrNaN(curveRows, "BER_plot");
grossRate = numericOrNaN(curveRows, "grossrate");
measuredNgmi(~isfinite(measuredNgmi) | measuredNgmi < 0 | ...
measuredNgmi > 1.05) = NaN;
measuredBer(~isfinite(measuredBer) | measuredBer <= 0 | ...
measuredBer > 0.5) = NaN;
ndr = tp.calculateNetRate(grossRate, ...
"NGMI", measuredNgmi, ...
"BER", measuredBer);
curveRows.NDR_O_FEC = columnVector(ndr.O_FEC.NetRate) .* 1e-9;
bestRows = bestMetricByWavelength(curveRows, "AIR_Gbps");
bestOfecRows = bestMetricByWavelength(curveRows, "NDR_O_FEC");
results(curveIdx).name = curve.name;
results(curveIdx).color = curve.color;
results(curveIdx).marker = curve.marker;
results(curveIdx).pam = curve.pam;
results(curveIdx).air = makeMetricSeries( ...
bestRows, "AIR_Gbps", curve.usePrecodedBer);
results(curveIdx).ofec = makeMetricSeries( ...
bestOfecRows, "NDR_O_FEC", curve.usePrecodedBer);
fprintf("%s, PAM-%d: AIR=%d, O-FEC=%d wavelength points\n", ...
curve.name, curve.pam, ...
numel(results(curveIdx).air.x), ...
numel(results(curveIdx).ofec.x));
end
%% 4) Plot maximum AIR and O-FEC NDR over wavelength
fig = figure(435); clf;
t = tiledlayout(fig, 1, 2, ...
"TileSpacing", "compact", ...
"Padding", "compact");
axAir = nexttile(t, 1);
airHandles = plotMetricPanel(axAir, results, "air", ...
"AIR [Gb/s]", "a) Maximum AIR");
axOfec = nexttile(t, 2);
ofecHandles = plotMetricPanel(axOfec, results, "ofec", ...
"O-FEC NDR [Gb/s]", "b) O-FEC");
allWavelengthCells = cell(numel(results), 1);
for curveIdx = 1:numel(results)
allWavelengthCells{curveIdx} = [ ...
results(curveIdx).air.x(:); ...
results(curveIdx).ofec.x(:)];
end
allWavelengths = vertcat(allWavelengthCells{:});
allWavelengths = allWavelengths(isfinite(allWavelengths));
if ~isempty(allWavelengths)
xLimits = [min(allWavelengths) - 1, max(allWavelengths) + 1];
for ax = [axAir, axOfec]
xlim(ax, xLimits);
xticks(ax, unique(allWavelengths));
end
end
validOfecMask = isgraphics(ofecHandles);
if any(validOfecMask)
legend(axOfec, ofecHandles(validOfecMask), ...
makeLegendNames(results(validOfecMask)), ...
"Location", "southoutside", ...
"NumColumns", min(3, nnz(validOfecMask)), ...
"Interpreter", "none");
elseif any(isgraphics(airHandles))
validAirMask = isgraphics(airHandles);
legend(axAir, airHandles(validAirMask), ...
makeLegendNames(results(validAirMask)), ...
"Location", "southoutside", ...
"NumColumns", min(3, nnz(validAirMask)), ...
"Interpreter", "none");
end
sgtitle(t, sprintf("Best AIR and O-FEC results over wavelength, %.0f km", ...
normalFiberLengthKm));
set(fig, "Position", 1e3 .* [0.08 0.42 1.75 0.48]);
%% Local helpers
function T = queryRows(db, fields, fiberLengthKm, ropAttenuation, isMpi)
fp = QueryFilter();
fp.where("Runs", "fiber_length", "EQUALS", fiberLengthKm);
fp.where("Runs", "rop_attenuation", "EQUALS", ropAttenuation);
fp.where("Runs", "is_mpi", "EQUALS", isMpi);
[T, query] = db.queryDB(fp, fields);
disp(query);
end
function T = cleanRows(T)
numericFields = ["result_id", "run_id", "eq_id", "bitrate", ...
"grossrate", "symbolrate", "pam_level", "wavelength", ...
"fiber_length", "db_mode", "rop_attenuation", "numBits", ...
"numBitErr", "BER", "numBitErr_precoded", "BER_precoded", ...
"GMI", "AIR", "NGMI"];
for fieldIdx = 1:numel(numericFields)
fieldName = numericFields(fieldIdx);
if ismember(fieldName, string(T.Properties.VariableNames))
T.(char(fieldName)) = numericColumn(T.(char(fieldName)));
end
end
T.equalizer_structure = lower(string(T.equalizer_structure));
end
function T = addAirMetric(T)
T.AIR_Gbps = numericOrNaN(T, "AIR") .* 1e-9;
gmi = numericOrNaN(T, "GMI");
symbolrate = numericOrNaN(T, "symbolrate");
grossrate = numericOrNaN(T, "grossrate");
fallbackAir = gmi .* symbolrate .* 1e-9;
useFallback = ~isfinite(T.AIR_Gbps) | T.AIR_Gbps < 0 | ...
(isfinite(grossrate) & T.AIR_Gbps > grossrate .* 1.05e-9);
T.AIR_Gbps(useFallback) = fallbackAir(useFallback);
end
function bestRows = bestMetricByWavelength(T, metricField)
if isempty(T)
bestRows = T;
return
end
values = numericOrNaN(T, metricField);
valid = isfinite(T.wavelength) & isfinite(values) & values >= 0;
candidate = T(valid, :);
values = values(valid);
if isempty(candidate)
bestRows = candidate;
return
end
[groupId, ~] = findgroups(candidate.wavelength);
keepIdx = zeros(max(groupId), 1);
for groupIdx = 1:max(groupId)
rowIdx = find(groupId == groupIdx);
[~, localIdx] = max(values(rowIdx));
keepIdx(groupIdx) = rowIdx(localIdx(1));
end
bestRows = sortrows(candidate(keepIdx, :), "wavelength");
end
function series = makeMetricSeries(T, metricField, usePrecodedBer)
series = emptyMetricSeries();
if isempty(T)
return
end
series.x = numericOrNaN(T, "wavelength");
series.y = numericOrNaN(T, metricField);
series.air = numericOrNaN(T, "AIR_Gbps");
series.ngmi = numericOrNaN(T, "NGMI");
series.ber = numericOrNaN(T, "BER_plot");
series.symbolrate = numericOrNaN(T, "symbolrate") .* 1e-9;
series.grossrate = numericOrNaN(T, "grossrate") .* 1e-9;
series.precoding = repmat(double(usePrecodedBer), height(T), 1);
series.dbMode = numericOrNaN(T, "db_mode");
end
function series = emptyMetricSeries()
series = struct( ...
"x", [], ...
"y", [], ...
"air", [], ...
"ngmi", [], ...
"ber", [], ...
"symbolrate", [], ...
"grossrate", [], ...
"precoding", [], ...
"dbMode", []);
end
function handles = plotMetricPanel(ax, results, seriesField, yLabel, panelTitle)
hold(ax, "on");
handles = gobjects(numel(results), 1);
for curveIdx = 1:numel(results)
result = results(curveIdx);
series = result.(seriesField);
if isempty(series.x)
continue
end
handles(curveIdx) = plot(ax, series.x, series.y, ...
"LineStyle", "-", ...
"Marker", result.marker, ...
"MarkerSize", 5, ...
"LineWidth", 1.35, ...
"Color", result.color, ...
"MarkerFaceColor", result.color, ...
"MarkerEdgeColor", result.color, ...
"DisplayName", result.name);
handles(curveIdx).DataTipTemplate.DataTipRows = [ ...
dataTipTextRow(yLabel, series.y); ...
dataTipTextRow("AIR [Gb/s]", series.air); ...
dataTipTextRow("NGMI", series.ngmi); ...
dataTipTextRow("BER", series.ber); ...
dataTipTextRow("Symbol rate [GBd]", series.symbolrate); ...
dataTipTextRow("Gross rate [Gb/s]", series.grossrate); ...
dataTipTextRow("precoding", series.precoding); ...
dataTipTextRow("db_mode", series.dbMode)];
end
set(ax, "FontSize", 9, "TickLabelInterpreter", "none");
xlabel(ax, "Wavelength [nm]");
ylabel(ax, yLabel);
title(ax, panelTitle);
grid(ax, "on");
grid(ax, "minor");
box(ax, "on");
end
function names = makeLegendNames(results)
names = strings(numel(results), 1);
for idx = 1:numel(results)
if contains(results(idx).name, "PAM-")
names(idx) = results(idx).name;
else
names(idx) = results(idx).name + ...
" (PAM-" + string(results(idx).pam) + ")";
end
end
end
function result = emptyResult()
result = struct( ...
"name", "", ...
"color", [0 0 0], ...
"marker", "o", ...
"pam", NaN, ...
"air", emptyMetricSeries(), ...
"ofec", emptyMetricSeries());
end
function values = numericColumn(values)
if iscell(values)
values = string(values);
end
if isstring(values) || ischar(values)
values = str2double(values);
end
values = double(values);
end
function values = numericOrNaN(T, fieldName)
if ismember(fieldName, string(T.Properties.VariableNames))
values = numericColumn(T.(char(fieldName)));
else
values = NaN(height(T), 1);
end
values = values(:);
end
function values = columnVector(values)
values = double(values(:));
end
function mask = equalizerMask(equalizerColumn, eqValue)
mask = lower(string(equalizerColumn)) == lower(string(eqValue));
end

View File

@@ -33,7 +33,7 @@ db.refresh();
fp = QueryFilter();
fp.where('Runs', 'fiber_length', 'EQUALS', selectedFiberLengthKm);
fp.where('Runs', 'wavelength', 'EQUALS', selectedWavelengthNm);
% fp.where('Runs', 'wavelength', 'EQUALS', selectedWavelengthNm);
if ~isempty(selectedRopAttenuation)
fp.where('Runs', 'rop_attenuation', 'EQUALS', selectedRopAttenuation);
end
@@ -141,7 +141,7 @@ for pamIdx = 1:numel(selectedPamLevels)
algoData = sortrows(bestPlotData(rowMask, :), "grossrate_Gbps");
if showRawEntries
scatter(ax, algoData.grossrate_Gbps, algoData.BER_plot, ...
rawHandle = scatter(ax, algoData.grossrate_Gbps, algoData.BER_plot, ...
9, ...
"Marker", ".", ...
"MarkerEdgeColor", style.color, ...
@@ -149,10 +149,14 @@ for pamIdx = 1:numel(selectedPamLevels)
"MarkerEdgeAlpha", 0.25, ...
"MarkerFaceAlpha", 0.25, ...
"HandleVisibility", "off");
rawHandle.DataTipTemplate.DataTipRows = [ ...
dataTipTextRow("Gross rate [Gb/s]", algoData.grossrate_Gbps); ...
dataTipTextRow("BER", algoData.BER_plot); ...
dataTipTextRow("db_mode", algoData.db_mode)];
end
if showBestLine
plot(ax, algoData.grossrate_Gbps, algoData.BER_plot, ...
bestHandle = plot(ax, algoData.grossrate_Gbps, algoData.BER_plot, ...
"LineStyle", style.lineStyle, ...
"Marker", style.marker, ...
"MarkerSize", 5, ...
@@ -161,6 +165,10 @@ for pamIdx = 1:numel(selectedPamLevels)
"MarkerFaceColor", style.markerFaceColor, ...
"MarkerEdgeColor", style.color, ...
"DisplayName", style.name);
bestHandle.DataTipTemplate.DataTipRows = [ ...
dataTipTextRow("Gross rate [Gb/s]", algoData.grossrate_Gbps); ...
dataTipTextRow("BER", algoData.BER_plot); ...
dataTipTextRow("db_mode", algoData.db_mode)];
end
end

View File

@@ -81,7 +81,7 @@ if isempty(plotData)
return
end
plotData.bitrate_Gbps = plotData.bitrate .* 1e-9;
plotData.bitrate_Gbps = plotData.grossrate .* 1e-9;
plotData = sortrows(plotData, ...
["pam_level", "wavelength", "detection_type", "bitrate_Gbps", "run_id"]);

View File

@@ -4,7 +4,7 @@
% algorithm and is restricted to the post-2026 processing results.
%
% The figure has one column per PAM format and one row per metric:
% BER, NGMI, GMI, AIR, NGMI-based SD+HD NDR, and the best BER-based NDR.
% BER, NGMI, GMI, AIR, and all requested FEC NDR curves.
% NDR values are calculated from the measured BER/NGMI using
% TransmissionPerformance.
@@ -13,7 +13,7 @@ clear; clc;
%% 1) Query data
selectedPamLevels = [4, 6, 8];
selectedFiberLengthKm = 10;
selectedFiberLengthKm = 2;
selectedWavelengthNm = 1310;
selectedRopAttenuation = 0;
selectedIsMpi = 0;
@@ -21,7 +21,7 @@ selectedIsMpi = 0;
normalDbModes = [double(db_mode.no_db), double(db_mode.db_precoded)];
duobinaryDbMode = double(db_mode.db_encoded);
showRawEntries = false;
showRawEntries = true; % set true to overlay all candidate rows
maxBerForPlot = 0.5;
algoStyles = defaultAlgorithmStyles();
@@ -76,6 +76,9 @@ end
if ismember("date_of_processing", string(duobinaryRows.Properties.VariableNames))
duobinaryRows.date_of_processing = datetime(string(duobinaryRows.date_of_processing));
duobinaryRows = duobinaryRows(datetime(duobinaryRows.date_of_processing)>datetime("2026-01-01 00:00:00"),:);
% Keep the table variable type compatible with the normal rows before
% concatenating both result sets.
duobinaryRows.date_of_processing = string(duobinaryRows.date_of_processing);
else
warning("plot_best_metrics:NoProcessingDate", ...
"date_of_processing was not returned; no duobinary date filtering was applied.");
@@ -94,7 +97,8 @@ plotData = plotData(plotData.symbolrate_GBd > 0 & ...
isfinite(plotData.symbolrate_GBd), :);
fprintf("Remaining metric rows: %d\n", height(plotData));
disp(groupcounts(plotData, ["algorithm_key", "pam_level", "precode"]));
disp(groupcounts(plotData, ...
["algorithm_key", "pam_level", "pre_emphasis", "precode"]));
%% 3) Calculate BER-/NGMI-dependent net rates
@@ -108,30 +112,48 @@ ber(~isfinite(ber) | ber <= 0 | ber > maxBerForPlot) = NaN;
ndr = tp.calculateNetRate(grossRate, "NGMI", ngmi, "BER", ber);
plotData.NDR_SDHD = columnVector(ndr.SDHD.NetRate) .* 1e-9;
berBasedRates = [ ...
columnVector(ndr.STAIR.NetRate); ...
columnVector(ndr.HD.NetRate); ...
columnVector(ndr.KP4.NetRate); ...
columnVector(ndr.KP4_hamming.NetRate); ...
columnVector(ndr.O_FEC.NetRate)];
plotData.NDR_BER_BEST = max(reshape(berBasedRates, height(plotData), []), [], 2, "omitnan") .* 1e-9;
plotData.NDR_STAIR = columnVector(ndr.STAIR.NetRate) .* 1e-9;
plotData.NDR_HD = columnVector(ndr.HD.NetRate) .* 1e-9;
plotData.NDR_KP4 = columnVector(ndr.KP4.NetRate) .* 1e-9;
plotData.NDR_KP4_HAMMING = columnVector(ndr.KP4_hamming.NetRate) .* 1e-9;
plotData.NDR_O_FEC = columnVector(ndr.O_FEC.NetRate) .* 1e-9;
%% 4) Keep the best row for every plotted metric and group
metricDefinitions = struct( ...
"field", {"BER_plot", "NGMI", "GMI", "AIR_Gbps", "NDR_SDHD", "NDR_BER_BEST"}, ...
"label", {"BER", "NGMI", "GMI [bit/sym]", "AIR [Gb/s]", ...
"SD+HD NDR [Gb/s]", "Best BER-FEC NDR [Gb/s]"}, ...
"scale", {"log", "linear", "linear", "linear", "linear", "linear"});
metricDefinitions = struct;
metricDefinitions(1).fields = "BER_plot";
metricDefinitions(1).label = "BER";
metricDefinitions(1).seriesLabels = "BER";
metricDefinitions(1).seriesLineStyles = "-";
metricDefinitions(2).fields = "NGMI";
metricDefinitions(2).label = "NGMI";
metricDefinitions(2).seriesLabels = "NGMI";
metricDefinitions(2).seriesLineStyles = "-";
metricDefinitions(3).fields = "GMI";
metricDefinitions(3).label = "GMI [bit/sym]";
metricDefinitions(3).seriesLabels = "GMI";
metricDefinitions(3).seriesLineStyles = "-";
metricDefinitions(4).fields = "AIR_Gbps";
metricDefinitions(4).label = "AIR [Gb/s]";
metricDefinitions(4).seriesLabels = "AIR";
metricDefinitions(4).seriesLineStyles = "-";
metricDefinitions(5).fields = ["NDR_SDHD", "NDR_STAIR", "NDR_HD", ...
"NDR_KP4", "NDR_KP4_HAMMING", "NDR_O_FEC"];
metricDefinitions(5).label = "NDR [Gb/s]";
metricDefinitions(5).seriesLabels = ["SD+HD", "Staircase", "HD-FEC", ...
"KP4", "KP4 + Hamming", "O-FEC"];
metricDefinitions(5).seriesLineStyles = ["-"; "--"; ":"; "-."; "-"; "--"];
bestMetricData = cell(numel(metricDefinitions), 1);
for metricIdx = 1:numel(metricDefinitions)
bestMetricData{metricIdx} = bestMetricRows(plotData, ...
metricDefinitions(metricIdx).field);
bestMetricData{metricIdx} = cell(numel(metricDefinitions(metricIdx).fields), 1);
for seriesIdx = 1:numel(metricDefinitions(metricIdx).fields)
bestMetricData{metricIdx}{seriesIdx} = bestMetricRows(plotData, ...
metricDefinitions(metricIdx).fields(seriesIdx));
end
end
availableStyles = algoStyles(hasAlgorithmRows(plotData, algoStyles), :);
availableStyles = algoStyles(hasPlotStyleRows(plotData, algoStyles), :);
if isempty(availableStyles)
warning("plot_best_metrics:NoSelectedAlgorithms", ...
"None of the configured algorithm styles match the queried rows.");
@@ -147,53 +169,60 @@ t = tiledlayout(fig, numel(metricDefinitions), numel(selectedPamLevels), ...
for metricIdx = 1:numel(metricDefinitions)
metric = metricDefinitions(metricIdx);
metricData = bestMetricData{metricIdx};
for pamIdx = 1:numel(selectedPamLevels)
selectedPamLevel = selectedPamLevels(pamIdx);
ax = nexttile(t); hold(ax, "on");
pamMask = metricData.pam_level == selectedPamLevel;
for seriesIdx = 1:numel(metric.fields)
metricData = bestMetricData{metricIdx}{seriesIdx};
metricField = metric.fields(seriesIdx);
pamMask = metricData.pam_level == selectedPamLevel;
for styleIdx = 1:height(availableStyles)
style = availableStyles(styleIdx, :);
rowMask = pamMask & metricData.algorithm_key == style.algorithm_key;
if ~any(rowMask)
continue
end
for styleIdx = 1:height(availableStyles)
style = availableStyles(styleIdx, :);
rowMask = pamMask & ...
metricData.algorithm_key == style.algorithm_key & ...
metricData.pre_emphasis == style.pre_emphasis;
if ~any(rowMask)
continue
end
algoData = sortrows(metricData(rowMask, :), "symbolrate_GBd");
y = algoData.(metric.field);
valid = isfinite(y);
if ~any(valid)
continue
end
algoData = sortrows(metricData(rowMask, :), "symbolrate_GBd");
y = algoData.(char(metricField));
valid = isfinite(y);
if ~any(valid)
continue
end
if showRawEntries
scatter(ax, algoData.symbolrate_GBd(valid), y(valid), ...
9, ...
"Marker", ".", ...
if isequal(showRawEntries, true)
scatter(ax, algoData.symbolrate_GBd(valid), y(valid), ...
9, ...
"Marker", ".", ...
"MarkerEdgeColor", style.color, ...
"MarkerFaceColor", style.color, ...
"MarkerEdgeAlpha", 0.25, ...
"MarkerFaceAlpha", 0.25, ...
"HandleVisibility", "off");
end
plot(ax, algoData.symbolrate_GBd(valid), y(valid), ...
"LineStyle", metric.seriesLineStyles(seriesIdx), ...
"Marker", style.marker, ...
"MarkerSize", 4, ...
"LineWidth", 1.35, ...
"Color", style.color, ...
"MarkerFaceColor", style.markerFaceColor, ...
"MarkerEdgeColor", style.color, ...
"MarkerFaceColor", style.color, ...
"MarkerEdgeAlpha", 0.25, ...
"MarkerFaceAlpha", 0.25, ...
"HandleVisibility", "off");
"DisplayName", style.displayName);
end
plot(ax, algoData.symbolrate_GBd(valid), y(valid), ...
"LineStyle", style.lineStyle, ...
"Marker", style.marker, ...
"MarkerSize", 4, ...
"LineWidth", 1.35, ...
"Color", style.color, ...
"MarkerFaceColor", style.markerFaceColor, ...
"MarkerEdgeColor", style.color, ...
"DisplayName", style.name);
end
formatMetricAxis(ax, metric, selectedPamLevel);
if metricIdx == 1 && pamIdx == 1
legend(ax, "Location", "southwest", "Interpreter", "none");
elseif metricIdx == numel(metricDefinitions) && pamIdx == 1
addNdrLegend(ax, metric.seriesLabels, metric.seriesLineStyles);
end
end
end
@@ -229,17 +258,27 @@ values = double(values(:));
end
function styles = defaultAlgorithmStyles()
styles = table( ...
["vnle"; "vnle_pf_mlse"; "vnle_db_mlse"; "ml_mlse"; "db_encoded"], ...
["VNLE"; "VNLE + PF + MLSE"; "VNLE DBt. + MLSE"; ...
"ML pre-EQ + Viterbi"; "DBS + VNLE + MLSE"], ...
["o"; "square"; "diamond"; "^"; "v"], ...
["-"; "-"; "-"; "-"; "-"], ...
["w"; "w"; "w"; "w"; "w"], ...
[clr.Paired.red; clr.Paired.green; clr.Paired.blue; ...
clr.Paired.purple; clr.Paired.orange], ...
'VariableNames', ["algorithm_key", "name", "marker", ...
"lineStyle", "markerFaceColor", "color"]);
algorithmKey = repelem(["vnle"; "vnle_pf_mlse"; "vnle_db_mlse"; ...
"ml_mlse"; "db_encoded"], 2, 1);
name = repelem(["VNLE"; "VNLE + PF + MLSE"; "VNLE DBt. + MLSE"; ...
"ML pre-EQ + Viterbi"; "DBS + VNLE + MLSE"], 2, 1);
preEmphasis = repmat([false; true], 5, 1);
preEmphasisLabel = repmat(["w/o pre-emph."; "w/ pre-emph."], 5, 1);
preEmphasisLabel(algorithmKey == "db_encoded") = "duobinary";
styles = table(algorithmKey, name, preEmphasis, preEmphasisLabel, ...
repelem(["o"; "square"; "diamond"; "^"; "v"], 2, 1), ...
repmat("-", 10, 1), ...
repmat("w", 10, 1), ...
[clr.Paired.lred; clr.Paired.dred; ...
clr.Paired.lgreen; clr.Paired.dgreen; ...
clr.Paired.lblue; clr.Paired.dblue; ...
clr.Paired.llila; clr.Paired.dlila; ...
clr.Paired.lorange; clr.Paired.dorange], ...
'VariableNames', ["algorithm_key", "name", "pre_emphasis", ...
"preEmphasisLabel", "marker", "lineStyle", ...
"markerFaceColor", "color"]);
styles.displayName = styles.name + "; " + styles.preEmphasisLabel;
end
function plotData = buildNormalMetricRows(data)
@@ -247,6 +286,7 @@ baseRows = data(isfinite(data.BER), :);
baseRows.precode = false(height(baseRows), 1);
baseRows.BER_plot = baseRows.BER;
baseRows.algorithm_key = algorithmKeyFromEqualizer(baseRows.equalizer_structure);
baseRows.pre_emphasis = baseRows.db_mode == double(db_mode.db_precoded);
baseRows = baseRows(baseRows.algorithm_key ~= "", :);
if ismember("BER_precoded", string(data.Properties.VariableNames))
@@ -255,6 +295,7 @@ if ismember("BER_precoded", string(data.Properties.VariableNames))
precodedRows.BER_plot = precodedRows.BER_precoded;
precodedRows.algorithm_key = algorithmKeyFromEqualizer( ...
precodedRows.equalizer_structure);
precodedRows.pre_emphasis = precodedRows.db_mode == double(db_mode.db_precoded);
precodedRows = precodedRows(precodedRows.algorithm_key ~= "", :);
plotData = [baseRows; precodedRows];
else
@@ -269,6 +310,7 @@ plotData = data(isfinite(data.BER), :);
plotData.precode = false(height(plotData), 1);
plotData.BER_plot = plotData.BER;
plotData.algorithm_key = repmat("db_encoded", height(plotData), 1);
plotData.pre_emphasis = false(height(plotData), 1);
end
function plotData = addDerivedMetrics(plotData)
@@ -343,7 +385,7 @@ if isempty(candidateData)
return
end
groupVars = ["pam_level", "algorithm_key", "symbolrate_GBd"];
groupVars = ["pam_level", "algorithm_key", "pre_emphasis", "symbolrate_GBd"];
groupId = findgroups(candidateData(:, groupVars));
keepIdx = zeros(max(groupId), 1);
for curGroup = 1:max(groupId)
@@ -359,10 +401,11 @@ end
bestData = sortrows(candidateData(keepIdx, :), groupVars);
end
function keep = hasAlgorithmRows(data, algoStyles)
function keep = hasPlotStyleRows(data, algoStyles)
keep = false(height(algoStyles), 1);
for idx = 1:height(algoStyles)
keep(idx) = any(data.algorithm_key == algoStyles.algorithm_key(idx));
keep(idx) = any(data.algorithm_key == algoStyles.algorithm_key(idx) & ...
data.pre_emphasis == algoStyles.pre_emphasis(idx));
end
end
@@ -376,7 +419,7 @@ grid(ax, "on");
grid(ax, "minor");
box(ax, "on");
switch metric.field
switch metric.fields(1)
case "BER_plot"
set(ax, "YScale", "log");
ylim(ax, [1e-5 0.2]);
@@ -405,3 +448,15 @@ else
title(ax, sprintf("PAM-%d", pamLevel));
end
end
function addNdrLegend(ax, seriesLabels, seriesLineStyles)
legendHandles = gobjects(numel(seriesLabels), 1);
for idx = 1:numel(seriesLabels)
legendHandles(idx) = plot(ax, NaN, NaN, ...
"Color", [0.2 0.2 0.2], ...
"LineStyle", seriesLineStyles(idx), ...
"LineWidth", 1.35, ...
"DisplayName", seriesLabels(idx));
end
legend(ax, legendHandles, "Location", "southwest", "Interpreter", "none");
end

View File

@@ -9,9 +9,9 @@ clear; clc;
%% 1) Query data
selectedPamLevels = [4, 6, 8];
selectedFiberLengthKm = 1;
selectedFiberLengthKm = 10;
selectedWavelengthNm = 1310;
selectedBitrateGbps = 360;
selectedBitrateGbps = 420;
selectedIsMpi = 0; % set [] to use all entries
maxPowerPdIn = []; % set a numeric limit to enable

View File

@@ -9,7 +9,7 @@ clear; clc;
%% 1) Query data
selectedPamLevels = [4, 6, 8];
selectedFiberLengthKm = 5;
selectedFiberLengthKm = 10;
selectedBitratesGbps = 300:30:480; % set [] to use all available bitrates
selectedRopAttenuation = 0; % set [] to use all ROP attenuation values
selectedIsMpi = 0; % set [] to use all entries

View File

@@ -8,7 +8,7 @@ dsp_options.recipe = @dsp_400g_recipe;
dsp_options.append_to_db = false;
% dsp_options.append_mpi_reduction_db = false;
dsp_options.start_occurence = 1;
dsp_options.max_occurences = 3;
dsp_options.max_occurences = 16;
dsp_options.debug_plots = false;
@@ -33,65 +33,148 @@ db = DBHandler("dataBase", [dsp_options.dataBase], ...
"password", dsp_options.password);
%% Load normal Signal w/o preemphasis
fp = QueryFilter();
fp.where('Runs','fiber_length','EQUALS', 10);
fp.where('Runs','wavelength','EQUALS', 1310);
fp.where('Runs','bitrate','EQUALS', 420e9);
fp.where('Runs','pam_level','EQUALS', 4);
fp.where('Runs','rop_attenuation','EQUALS', 0);
fp.where('Runs','is_mpi','EQUALS', 0);
fp.where('Runs', 'db_mode','EQUALS', 0);
fields = db.getTableFieldNames('Runs');
[dataTable, query] = db.queryDB(fp, fields);
cols = cbrewer2('Spectral',6);
cols = linspecer(2);
len = [1 2 3 5 6 8 10];
idx = 1;
for lambda = 1302%[1297.5]
fp = QueryFilter();
len = 10;
fp.where('Runs','fiber_length','EQUALS', 10); % 1 2 3 5 6 8 10
fp.where('Runs','wavelength','EQUALS', lambda); %
fp.where('Runs','bitrate','EQUALS', 450e9);
fp.where('Runs','pam_level','EQUALS', 4);
fp.where('Runs','rop_attenuation','EQUALS', 0);
fp.where('Runs','is_mpi','EQUALS', 0);
fp.where('Runs', 'db_mode','EQUALS', 0);
fields = db.getTableFieldNames('Runs');
[dataTable, query] = db.queryDB(fp, fields);
[~, Symbols_preemph, S, ~] = loadAndSyncRunSignals(dataTable(1,:), dsp_options);
average_signals = 1;
if average_signals
Scpe_sig_avg = S{1};
scope_mean = zeros(size(S{1}.signal));
for n=1:numel(S)
scope_mean = scope_mean + S{n}.signal;
end
scope_mean = scope_mean ./ n;
Scpe_sig_avg.signal = scope_mean;
ScopeSignal_preemph = preprocessSignal(Scpe_sig_avg, Symbols_preemph, Symbols_preemph.fs,"gaussian_cutoff_factor",0.8);
else
ScopeSignal = S{1};
ScopeSignal_preemph = preprocessSignal(ScopeSignal, Symbols_preemph, Symbols_preemph.fs);
end
fignum = 2;
dn = sprintf("Rx Spectrum; %d nm",floor(lambda));
ScopeSignal_preemph.spectrum("displayname",dn,'fignum',fignum,'normalizeTo0dB',1,'fft_length',2^15,'show_onesided',1,'color',cols(idx,:));
[~, Symbols_preemph, Scpe_cell_preemph, ~] = loadAndSyncRunSignals(dataTable(1,:), dsp_options);
ScopeSignal = Scpe_cell_preemph{1};
ScopeSignal_preemph = preprocessSignal(ScopeSignal, Symbols_preemph, Symbols_preemph.fs);
if len == 10
fp.where('Runs', 'db_mode','EQUALS', 2);
fields = db.getTableFieldNames('Runs');
[dataTable, query] = db.queryDB(fp, fields);
[~, Symbols_db, S, found_sync] = loadAndSyncRunSignals(dataTable(1,:), dsp_options);
ScopeSignal = S{1};
average_signals = 1;
if average_signals
Scpe_sig_avg = S{1};
scope_mean = zeros(size(S{1}.signal));
for n=1:numel(S)
scope_mean = scope_mean + S{n}.signal;
end
scope_mean = scope_mean ./ n;
Scpe_sig_avg.signal = scope_mean;
ScopeSignal = preprocessSignal(Scpe_sig_avg, Symbols_preemph, Symbols_preemph.fs,"gaussian_cutoff_factor",0.8);
else
ScopeSignal = S{1};
ScopeSignal = preprocessSignal(ScopeSignal, Symbols_preemph, Symbols_preemph.fs);
end
ScopeSignal_DB = preprocessSignal(ScopeSignal, Symbols_db, Symbols_db.fs);
end
if len == 10
fignum = 2;
dn = sprintf("DBS Rx Spectrum; %d nm",floor(lambda));
ScopeSignal_DB.spectrum("displayname",dn,'fignum',fignum,'normalizeTo0dB',1,'fft_length',2^15,'show_onesided',1,'color',cols(idx+1,:));
% Symbols_db.spectrum("displayname",dn,'fignum',fignum,'normalizeTo0dB',1,'fft_length',1024,'show_onesided',1,'color',cols(idx+1,:));
end
% Fiber and system parameters
lambda0 = 1314e-9; % zero-dispersion wavelength [m]
lambda = lambda*1e-9; % operating wavelength [m]
S0 = 0.092; % dispersion slope [ps/(nm²·km)]
L = 10e3; % fiber length [m]
c = physconst('lightspeed');
% Derived quantities
S0_si = S0 * 1e3; % → s/m³
D_lambda = (S0/4) * (lambda*1e9 - (lambda0*1e9)^4/(lambda*1e9)^3); % ps/(nm·km)
D_si = D_lambda * 1e-6; % → s/m²
b2 = -D_si * lambda^2 / (2*pi*c); % s²/m
Dacc = D_lambda * L;
fprintf('Accumulated Dispersion: %.2f ps/nm \n', Dacc / 1e3);
% Frequency grid
f_max = 200e9;
f = linspace(0, f_max, 5000); % [Hz]
% IM/DD transfer function (power fading)
phi = 2*pi^2 * b2 * f.^2 * L;
H = abs(cos(phi));
% Plot
plot(f/1e9, 10*log10(H), 'LineWidth', 1,'Color','black','DisplayName','CD Transfer function','HandleVisibility','on');
grid on; box on;
xlabel('Frequency [GHz]');
ylabel('Magnitude [dB]');
% title(sprintf('IM/DD Power Fading: 10 km; 1275nm', lambda*1e9, L/1000),"Interpreter","latex");
% ylim([-20 0]);
idx = idx +1;
end
%% Load normal Signal w/o preemphasis
fp = QueryFilter();
fp.where('Runs','fiber_length','EQUALS', 10);
fp.where('Runs','wavelength','EQUALS', 1310);
fp.where('Runs','bitrate','EQUALS', 420e9);
fp.where('Runs','pam_level','EQUALS', 4);
fp.where('Runs','rop_attenuation','EQUALS', 0);
fp.where('Runs','is_mpi','EQUALS', 0);
fp.where('Runs', 'db_mode','EQUALS', 1);
fp.where('Runs', 'db_mode','EQUALS', 0);
fields = db.getTableFieldNames('Runs');
[dataTable, query] = db.queryDB(fp, fields);
[~, Symbols, Scpe_cell, ~] = loadAndSyncRunSignals(dataTable(1,:), dsp_options);
ScopeSignal = Scpe_cell{1};
ScopeSignal_no_preemph = preprocessSignal(ScopeSignal, Symbols, Symbols.fs);
fignum = len;
ScopeSignal_preemph.spectrum("displayname",'Full Response w/ preemphasis','fignum',fignum,'normalizeTo0dB',0,'color',clr.Paired.dgreen,'fft_length',4096*6);
%% Duobinary
fp = QueryFilter();
fp.where('Runs','fiber_length','EQUALS', 10);
fp.where('Runs','wavelength','EQUALS', 1310);
fp.where('Runs','bitrate','EQUALS', 420e9);
fp.where('Runs','pam_level','EQUALS', 4);
fp.where('Runs','rop_attenuation','EQUALS', 0);
fp.where('Runs','is_mpi','EQUALS', 0);
fp.where('Runs', 'db_mode','EQUALS', 2);
if len == 10
fp.where('Runs', 'db_mode','EQUALS', 2);
fields = db.getTableFieldNames('Runs');
[dataTable, query] = db.queryDB(fp, fields);
[~, Symbols_db, Scpe_cell_db, found_sync] = loadAndSyncRunSignals(dataTable(1,:), dsp_options);
ScopeSignal = Scpe_cell_db{1};
ScopeSignal_DB = preprocessSignal(ScopeSignal, Symbols_db, Symbols_db.fs);
end
fields = db.getTableFieldNames('Runs');
[dataTable, query] = db.queryDB(fp, fields);
if len == 10
fignum = 2;
dn = sprintf("DBS Rx Spectrum; %d nm",floor(lambda));
ScopeSignal_DB.spectrum("displayname",dn,'fignum',fignum,'normalizeTo0dB',1,'fft_length',2^15,'show_onesided',1,'color',cols(idx,:));
end
[~, Symbols_db, Scpe_cell_db, found_sync] = loadAndSyncRunSignals(dataTable(1,:), dsp_options);
ScopeSignal = Scpe_cell_db{1};
ScopeSignal_DB = preprocessSignal(ScopeSignal, Symbols_db, Symbols_db.fs);
%%
ScopeSignal_no_preemph.spectrum("displayname",'Full Response w/o preemphasis','fignum',2,'normalizeTo0dB',0,'color',clr.Paired.dblue);
ScopeSignal_preemph.spectrum("displayname",'Full Response w/ preemphasis','fignum',2,'normalizeTo0dB',0,'color',clr.Paired.dgreen);
ScopeSignal_DB.spectrum("displayname",'DB Response w/ preemphasis','fignum',2,'normalizeTo0dB',0,'color',clr.Paired.dorange);
%%

View File

@@ -0,0 +1,261 @@
%% Best AIR and FEC data rates over all wavelengths for 2 km and 10 km
% The table follows the contender mapping used in the thesis figures:
% PAM-4: DB target + MLSE, with DBS + VNLE + MLSE at 10 km
% PAM-6: VNLE + PF + MLSE, with DBS + VNLE + MLSE at 10 km
% PAM-8: VNLE + PF + MLSE
%
% For every configured contender, the maximum valid rate is selected across
% the available gross rates and symbol rates. BER_precoded is used for the
% DB-target curve, as in FIGURE_NGMI_THESIS_FINAL.m.
clear;
%% Configuration
normalFiberLengthsKm = [2 10];
duobinaryFiberLengthKm = 10;
selectedRopAttenuation = 0;
selectedIsMpi = 0;
duobinaryDateCutoff = datetime("2026-01-01 00:00:00");
curves = struct( ...
"name", {"DBt. + MLSE"; "DBS + VNLE + MLSE"; ...
"VNLE + PF + MLSE"; "DBS + VNLE + MLSE"; ...
"VNLE + PF + MLSE"}, ...
"algorithm_key", {"vnle_db_mlse"; "db_encoded"; ...
"vnle_pf_mlse"; "db_encoded"; ...
"vnle_pf_mlse"}, ...
"pam", {4; 4; 6; 6; 8}, ...
"source", {"normal"; "duobinary"; "normal"; "duobinary"; "normal"}, ...
"usePrecodedBer", {true; false; false; false; false});
%% Query the normal and DBS data
db = DBHandler( ...
"dataBase", "labor_highspeed", ...
"type", "mysql", ...
"server", "192.168.178.192", ...
"user", "silas", ...
"password", "silas");
db.refresh();
selectedFields = db.getTableFieldNames('dashboard_ungrouped_alltime');
normalRows = cell(size(normalFiberLengthsKm));
for lengthIdx = 1:numel(normalFiberLengthsKm)
normalRows{lengthIdx} = queryRows(db, selectedFields, ...
normalFiberLengthsKm(lengthIdx), ...
selectedRopAttenuation, selectedIsMpi);
normalRows{lengthIdx} = cleanRows(normalRows{lengthIdx});
normalRows{lengthIdx} = normalRows{lengthIdx}(ismember( ...
normalRows{lengthIdx}.db_mode, ...
[double(db_mode.no_db), double(db_mode.db_precoded)]), :);
normalRows{lengthIdx}.algorithm_key = ...
lower(string(normalRows{lengthIdx}.equalizer_structure));
fprintf("Normal %g km rows: %d\n", normalFiberLengthsKm(lengthIdx), ...
height(normalRows{lengthIdx}));
end
duobinaryRows = queryRows(db, selectedFields, duobinaryFiberLengthKm, ...
selectedRopAttenuation, selectedIsMpi);
duobinaryRows = cleanRows(duobinaryRows);
duobinaryRows = duobinaryRows(duobinaryRows.db_mode == ...
double(db_mode.db_encoded), :);
duobinaryRows = duobinaryRows( ...
duobinaryRows.equalizer_structure == "db_encoded", :);
if ismember("date_of_processing", string(duobinaryRows.Properties.VariableNames))
processedDate = datetime(string(duobinaryRows.date_of_processing));
duobinaryRows = duobinaryRows(processedDate > duobinaryDateCutoff, :);
else
warning("table_best_rates:NoProcessingDate", ...
"date_of_processing was not returned; no DBS date filter was applied.");
end
duobinaryRows.algorithm_key = repmat("db_encoded", height(duobinaryRows), 1);
fprintf("DBS %g km rows after date filter: %d\n", ...
duobinaryFiberLengthKm, height(duobinaryRows));
%% Calculate maximum rates
tp = TransmissionPerformance;
resultRows = repmat(emptyResultRow(), 0, 1);
for lengthIdx = 1:numel(normalFiberLengthsKm)
for curveIdx = 1:numel(curves)
curve = curves(curveIdx);
if curve.source ~= "normal"
continue
end
resultRows(end+1) = evaluateCurve(normalRows{lengthIdx}, curve, ...
normalFiberLengthsKm(lengthIdx), tp); %#ok<SAGROW>
end
end
for curveIdx = 1:numel(curves)
curve = curves(curveIdx);
if curve.source ~= "duobinary"
continue
end
resultRows(end+1) = evaluateCurve(duobinaryRows, curve, ...
duobinaryFiberLengthKm, tp); %#ok<SAGROW>
end
ratesTable = struct2table(resultRows);
ratesTable = ratesTable(:, ...
["pam", "fiber_length_km", "technique", "AIR_Gbps", ...
"SDHD_Gbps", "HD_Gbps", "AIR_grossrate_Gbps", ...
"SDHD_grossrate_Gbps", "HD_grossrate_Gbps", ...
"AIR_symbolrate_GBd", "SDHD_symbolrate_GBd", ...
"HD_symbolrate_GBd"]);
disp("Best rates (Gb/s):");
disp(ratesTable(:, ["pam", "fiber_length_km", "technique", ...
"AIR_Gbps", "SDHD_Gbps", "HD_Gbps"]));
displayTable = table( ...
ratesTable.pam(:), ...
ratesTable.fiber_length_km(:), ...
string(ratesTable.technique(:)), ...
formatRateWithSymbol(ratesTable.AIR_Gbps(:), ratesTable.AIR_symbolrate_GBd(:)), ...
formatRateWithSymbol(ratesTable.SDHD_Gbps(:), ratesTable.SDHD_symbolrate_GBd(:)), ...
formatRateWithSymbol(ratesTable.HD_Gbps(:), ratesTable.HD_symbolrate_GBd(:)), ...
'VariableNames', {'PAM', 'Distance_km', 'EQ_contender', ...
'AIR', 'SDHD_FEC', 'HD_FEC'});
disp("Best rates with the symbol rate used for each metric:");
disp(displayTable);
%% Local functions
function T = queryRows(db, fields, fiberLengthKm, ropAttenuation, isMpi)
fp = QueryFilter();
fp.where("Runs", "fiber_length", "EQUALS", fiberLengthKm);
fp.where("Runs", "rop_attenuation", "EQUALS", ropAttenuation);
fp.where("Runs", "is_mpi", "EQUALS", isMpi);
[T, query] = db.queryDB(fp, fields);
disp(query);
end
function T = cleanRows(T)
numericFields = ["result_id", "run_id", "eq_id", "bitrate", "grossrate", ...
"symbolrate", "pam_level", "wavelength", "fiber_length", "db_mode", ...
"rop_attenuation", "numBits", "numBitErr", "BER", ...
"numBitErr_precoded", "BER_precoded", "GMI", "AIR", "NGMI"];
for fieldIdx = 1:numel(numericFields)
fieldName = numericFields(fieldIdx);
if ismember(fieldName, string(T.Properties.VariableNames))
T.(char(fieldName)) = numericColumn(T.(char(fieldName)));
end
end
T.equalizer_structure = lower(string(T.equalizer_structure));
end
function result = evaluateCurve(sourceRows, curve, fiberLengthKm, tp)
result = emptyResultRow();
result.pam = curve.pam;
result.fiber_length_km = fiberLengthKm;
result.technique = curve.name;
curveRows = sourceRows(sourceRows.pam_level == curve.pam & ...
sourceRows.algorithm_key == curve.algorithm_key, :);
if isempty(curveRows)
warning("table_best_rates:NoRows", ...
"No rows found for %s, PAM-%d, %g km.", ...
curve.name, curve.pam, fiberLengthKm);
return
end
curveRows.BER_plot = numericOrNaN(curveRows, "BER");
if curve.usePrecodedBer && ismember("BER_precoded", ...
string(curveRows.Properties.VariableNames))
precodedBer = numericOrNaN(curveRows, "BER_precoded");
usePrecoded = isfinite(precodedBer);
curveRows.BER_plot(usePrecoded) = precodedBer(usePrecoded);
end
curveRows = addAirMetric(curveRows);
grossRate = numericOrNaN(curveRows, "grossrate");
ngmi = numericOrNaN(curveRows, "NGMI");
ber = numericOrNaN(curveRows, "BER_plot");
ngmi(~isfinite(ngmi) | ngmi < 0 | ngmi > 1.05) = NaN;
ber(~isfinite(ber) | ber <= 0 | ber > 0.5) = NaN;
ndr = tp.calculateNetRate(grossRate, "NGMI", ngmi, "BER", ber);
curveRows.SDHD_Gbps = columnVector(ndr.SDHD.NetRate) .* 1e-9;
curveRows.HD_Gbps = columnVector(ndr.O_FEC.NetRate) .* 1e-9;
result = assignMaximum(result, curveRows, "AIR_Gbps");
result = assignMaximum(result, curveRows, "SDHD_Gbps");
result = assignMaximum(result, curveRows, "HD_Gbps");
end
function result = assignMaximum(result, T, fieldName)
values = numericOrNaN(T, fieldName);
valid = isfinite(values) & values >= 0;
if ~any(valid)
return
end
[maximum, localIndex] = max(values(valid));
validRows = find(valid);
rowIndex = validRows(localIndex);
prefix = erase(fieldName, "_Gbps");
result.(fieldName) = maximum;
result.(char(prefix + "_grossrate_Gbps")) = ...
numericOrNaN(T(rowIndex, :), "grossrate") .* 1e-9;
result.(char(prefix + "_symbolrate_GBd")) = ...
numericOrNaN(T(rowIndex, :), "symbolrate") .* 1e-9;
end
function T = addAirMetric(T)
T.AIR_Gbps = numericOrNaN(T, "AIR") .* 1e-9;
gmi = numericOrNaN(T, "GMI");
fallbackAir = gmi .* numericOrNaN(T, "symbolrate") .* 1e-9;
grossRate = numericOrNaN(T, "grossrate");
useFallback = ~isfinite(T.AIR_Gbps) | T.AIR_Gbps < 0 | ...
(isfinite(grossRate) & T.AIR_Gbps > grossRate .* 1.05e-9);
T.AIR_Gbps(useFallback) = fallbackAir(useFallback);
end
function result = emptyResultRow()
result = struct( ...
"pam", NaN, ...
"fiber_length_km", NaN, ...
"technique", "", ...
"AIR_Gbps", NaN, ...
"SDHD_Gbps", NaN, ...
"HD_Gbps", NaN, ...
"AIR_grossrate_Gbps", NaN, ...
"SDHD_grossrate_Gbps", NaN, ...
"HD_grossrate_Gbps", NaN, ...
"AIR_symbolrate_GBd", NaN, ...
"SDHD_symbolrate_GBd", NaN, ...
"HD_symbolrate_GBd", NaN);
end
function values = numericColumn(values)
if iscell(values)
values = string(values);
end
if isstring(values) || ischar(values)
values = str2double(values);
end
values = double(values);
end
function values = numericOrNaN(T, fieldName)
if ismember(fieldName, string(T.Properties.VariableNames))
values = numericColumn(T.(char(fieldName)));
else
values = NaN(height(T), 1);
end
values = values(:);
end
function values = columnVector(values)
values = double(values(:));
end
function text = formatRateWithSymbol(rateGbps, symbolrateGBd)
text = strings(size(rateGbps));
valid = isfinite(rateGbps) & isfinite(symbolrateGBd);
text(valid) = compose("%.0f (%.0f GBd)", ...
rateGbps(valid), symbolrateGBd(valid));
text(~valid) = "--";
end

View File

@@ -1,5 +1,5 @@
rates = [420e9];
rates = [400e9];
rcalpha = 0.05;
fsym = rates/2;
apply_pulsef = 1;
@@ -56,8 +56,6 @@ Digi_sig_rx.spectrum(...
Digi_sig_pre_rx.spectrum(...
"displayname",'Rx w/ pre-emphasis',...
"fignum",2,"normalizeTo0dB",0,"color",clr.Paired.dblue);
@@ -80,6 +78,9 @@ Pform = Pulseformer("fsym",fsym,"fdac",4*fsym,"pulse","rrc","pulselength",16,"al
"mrds_code",0,"mrds_blocklength",512).process();
Digi_sig_DB= Digi_sig_DB.normalize("mode","oneone");
Digi_sig_DB_rx = precomp_est.apply(...
Digi_sig_DB,'maxampdb',0,'loadPath',precomp_path,'fileName',precomp_fn);
maxamp = -38; %optimized for DB!
precomp_est = ChannelFreqResp("Nacq",2048,"Navg",100,"Ncp",63,'f_ref',Digi_sig_DB.fs);
precomp_path = "W:\labdata\sioe_labor\precomp";
@@ -89,27 +90,33 @@ Digi_sig_DB_pre.signal = reshape(Digi_sig_DB_pre.signal,[],1);
Digi_sig_DB_pre = Digi_sig_DB_pre.resample("fs_out",256e9);
Digi_sig_DB_pre = Digi_sig_DB_pre.normalize("mode","oneone");
Digi_sig_DB_pre_rx = precomp_est.apply(...
Digi_sig_DB_pre,'maxampdb',0,'loadPath',precomp_path,'fileName',precomp_fn);
%%
AWG_ = M8199B("kover",4);
% AWG_ = AWG("fdac",256e9,"f_cutoff",fsym,"lpf_active",0,"kover",4,"bit_resolution",12,"upsampling_method","samplehold","precomp_sinc_rolloff",1);
El_sig = AWG_.process(Digi_sig);
El_sig_preemph = AWG_.process(Digi_sig_pre);
El_sig_channel = AWG_.process(Digi_sig_channel);
% El_sig_channel = AWG_.process(Digi_sig_channel);
El_sig.spectrum("displayname",'Full Response w/o preemphasis','fignum',1,'normalizeTo0dB',0,'color',clr.Paired.lblue);
El_sig_preemph.spectrum("displayname",'Full Response w/ preemphasis','fignum',1,'normalizeTo0dB',0,'color',clr.Paired.dblue);
El_sig_channel.spectrum("displayname",'Full Response w/ measured channel','fignum',1,'normalizeTo0dB',0,'color',clr.Paired.blue);
% El_sig_channel.spectrum("displayname",'Full Response w/ measured channel','fignum',1,'normalizeTo0dB',0,'color',clr.Paired.blue);
%%
El_sig_DB_preemph = AWG_.process(Digi_sig_DB_pre);
El_sig_DB = AWG_.process(Digi_sig_DB);
El_sig_DB_rx = AWG_.process(Digi_sig_DB_pre_rx);
Digi_sig_DB.spectrum("displayname",'DB Response w/o preemphasis','fignum',1,'normalizeTo0dB',1,'color',clr.Paired.lorange);
Digi_sig_DB_pre.spectrum("displayname",'DB Response w/ preemphasis','fignum',1,'normalizeTo0dB',1,'color',clr.Paired.dorange);
El_sig_DB.spectrum("displayname",'DB Response w/o preemphasis','fignum',1,'normalizeTo0dB',0,'color',clr.Paired.lorange);
El_sig_DB_preemph.spectrum("displayname",'DB Response w/ preemphasis','fignum',1,'normalizeTo0dB',0,'color',clr.Paired.dorange);
Digi_sig_DB_rx.spectrum("displayname",'DB Response w/o preemphasis at Rx','fignum',1,'normalizeTo0dB',1,'color',clr.Paired.lred);
Digi_sig_DB_pre_rx.spectrum("displayname",'DB Response w/ preemphasis at Rx','fignum',1,'normalizeTo0dB',1,'color',clr.Paired.dred);

View File

@@ -5,7 +5,7 @@ dsp_options.recipe = @dsp_400g_recipe;
dsp_options.append_to_db = false;
% dsp_options.append_mpi_reduction_db = false;
dsp_options.start_occurence = 1;
dsp_options.max_occurences = 3;
dsp_options.max_occurences = 1;
dsp_options.debug_plots = false;
@@ -36,11 +36,12 @@ maxRunIds = 1; % keep small until the recipe settings are sett
fp = QueryFilter();
fp.where('Runs','fiber_length','EQUALS', 10);
fp.where('Runs','wavelength','EQUALS', 1310);
% fp.where('Runs','bitrate','LESS_THAN', 480e9);
% fp.where('Runs','pam_level','EQUALS', 4);
% fp.where('Runs','bitrate','LESS_THAN', 330e9);
fp.where('Runs','symbolrate','EQUALS', 174e9);
fp.where('Runs','pam_level','EQUALS', 6);
fp.where('Runs','rop_attenuation','EQUALS', 0);
fp.where('Runs','is_mpi','EQUALS', 0);
% fp.where('Runs', 'db_mode','EQUALS', 2);
fp.where('Runs', 'db_mode','EQUALS', 1);
fields = db.getTableFieldNames('Runs');
[dataTable, query] = db.queryDB(fp, fields);
@@ -67,7 +68,7 @@ dsp_options.userParameters = struct();
% dsp_options.userParameters.len_tr = 4096*2;
% dsp_options.userParameters.pf_ncoeffs = [1,2,3];
dsp_options.userParameters.decoding_mode = [db_decoder.sequencedetection];
% dsp_options.userParameters.decoding_mode = [db_decoder.sequencedetection];
% dsp_options.userParameters.pf_ncoeffs = [1, 2, 3];
% dsp_options.userParameters.mu_dc = [0, 1e-5, 1e-4];
% dsp_options.userParameters.run_ml_mlse_db = [false, true];
@@ -86,7 +87,7 @@ fprintf("-> [ %d run_id(s) x %d userParam combination(s) = %d job(s) ] x %d real
%% Run
[results, wh] = submitJobs(run_ids, dsp_options, processingMode.parallel, ...
[results, wh] = submitJobs(run_ids, dsp_options, processingMode.serial, ...
"wh", wh, ...
"waitbar", true);