Files
imdd_silas/projects/Diss/400G_revisit/PLOT_EYES_400G_REVISIT.m

385 lines
12 KiB
Matlab

%% 400G revisit: eye comparison for PAM-4/6/8
% The native Signal.eye() method is used for the eye display. Optional TikZ
% export is configured below and uses mat2tikz_improved().
%
% db_mode_setting:
% 0 - no duobinary processing; use the copied FFE configuration
% 1 - DB-targeted VNLE; the VNLE target is Duobinary().encode(Symbols)
% 2 - DB-encoded data; equalize the stored DB-encoded Symbols with a VNLE
clc;
%% Configuration
M_values = [4];
selectedBitrate = 360e9;
selectedFiberLengthKm = 10;
selectedWavelengthNm = 1310;
selectedRopAttenuation = 0;
selectedIsMpi = 0;
db_mode_setting = 2; % Set to 0, 1, or 2.
average_signals = 1;
show_histograms = true;
export_tikz = 0;
max_occurences = 10;
histogram_figure_base = 600;
eye_figure_base = 500;
psd_figure_base = 700;
% PSD colors follow the established DSP algorithm styles. The target is
% black and the received waveform is grey.
dsp_styles = defaultAlgorithmStyles();
psd_color_target = [0, 0, 0];
psd_color_received = [0.3500, 0.3500, 0.3500];
psd_color_equalized = dsp_styles.color(dsp_styles.algorithm_key == "vnle", :);
tikz_root = 'C:\Users\Silas\Documents\6971e0b65b380ca6d71c837f\04_Experimental_Evaluation\tikz\400g';
tikz_eye_folder = fullfile(tikz_root, 'eyes');
tikz_histogram_folder = fullfile(tikz_root, 'histograms');
tikz_psd_folder = fullfile(tikz_root, 'psd');
% The averaging/gain/normalization follows FIGURE_EYES.m.
average_gain = 1.25;
% Common equalizer parameters copied from FIGURE_EYES.m.
len_tr = 4096*2;
training_loops = 5;
dd_loops = 5;
eq_K = 2;
mu_dc = 0.005;
mu_ffe = [0.0001, 0.0008, 0.001];
mu_dfe = 0.0004;
if ~ismember(db_mode_setting, [0, 1, 2])
error('PLOT_EYES_400G_REVISIT:InvalidDbMode', ...
'db_mode_setting must be 0, 1, or 2.');
end
if export_tikz
if ~exist(tikz_eye_folder, 'dir')
mkdir(tikz_eye_folder);
end
if ~exist(tikz_histogram_folder, 'dir')
mkdir(tikz_histogram_folder);
end
if ~exist(tikz_psd_folder, 'dir')
mkdir(tikz_psd_folder);
end
end
%% Database setup
dsp_options = struct();
dsp_options.storage_path = 'W:\labdata\sioe_labor\';
dsp_options.start_occurence = 1;
dsp_options.max_occurences = max_occurences;
database = DBHandler( ...
"dataBase", "labor_highspeed", ...
"type", "mysql", ...
"server", "192.168.178.192", ...
"user", "silas", ...
"password", "silas");
%% DSP phase: query, synchronize, equalize, and collect all signals
selectedRuns = [];
eyeSignals = cell(size(M_values));
rawSignals = cell(size(M_values));
eyeReferences = cell(size(M_values));
symbolRates = NaN(size(M_values));
for mIdx = 1:numel(M_values)
M = M_values(mIdx);
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);
fp.where('Runs', 'pam_level', 'EQUALS', M);
fp.where('Runs', 'db_mode', 'EQUALS', db_mode_setting);
if ~isempty(selectedBitrate)
fp.where('Runs', 'bitrate', 'EQUALS', selectedBitrate);
end
[dataTable, ~] = database.queryDB(fp, database.getTableFieldNames('Runs'));
if isempty(dataTable)
error('PLOT_EYES_400G_REVISIT:MissingRun', ...
'No run found for PAM-%d with the selected filters.', M);
end
dataTable = sortrows(dataTable, {'bitrate', 'run_id'});
dataTable = dataTable(1, :);
if isempty(selectedRuns)
selectedRuns = dataTable;
else
selectedRuns = [selectedRuns; dataTable]; %#ok<AGROW>
end
fsym = double(dataTable.symbolrate(1));
symbolRates(mIdx) = fsym;
[~, Symbols, Scpe_cell, found_sync] = ...
loadAndSyncRunSignals(dataTable, dsp_options);
if ~found_sync || isempty(Scpe_cell)
error('PLOT_EYES_400G_REVISIT:SynchronizationFailed', ...
'Could not synchronize the selected PAM-%d run.', M);
end
Scpe_sig = averageScopeSignals(Scpe_cell, average_signals, average_gain);
Scpe_sig = preprocessSignal(Scpe_sig, Symbols, fsym);
Scpe_sig = Scpe_sig.normalize("mode", "rms");
switch db_mode_setting
case 0
% Simply FFE, copied from FIGURE_EYES.m.
eq_ = EQ("Ne", [50, 0, 0], ...
"Nb", [0, 0, 0], ...
"training_length", len_tr, ...
"training_loops", training_loops, ...
"dd_loops", dd_loops, ...
"K", eq_K, ...
"DCmu", mu_dc, ...
"DDmu", [mu_ffe, mu_dfe], ...
"DFEmu", 0.005, ...
"FFEmu", 0, ...
"plotfinal", 0, ...
"ideal_dfe", false);
referenceForEye = Symbols;
case 1
% DB-targeted VNLE: train against the DB waveform generated
% from the stored (precoded but not DB-encoded) symbols.
eq_ = makeVnle(len_tr, training_loops, dd_loops, eq_K, ...
mu_dc, mu_ffe, mu_dfe);
referenceForEye = Duobinary().encode(Symbols, "M", M);
case 2
% DB-encoded data: the stored Symbols already contain the DB
% encoded reference waveform used by the VNLE.
eq_ = makeVnle(len_tr, training_loops, dd_loops, eq_K, ...
mu_dc, mu_ffe, mu_dfe);
referenceForEye = Symbols;
end
[equalized_signal, ~] = eq_.process(Scpe_sig, referenceForEye);
eyeSignals{mIdx} = equalized_signal;
rawSignals{mIdx} = Scpe_sig;
eyeReferences{mIdx} = referenceForEye;
fprintf('PAM-%d: run %d, %.3f GBd, db_mode %d\n', ...
M, dataTable.run_id(1), fsym*1e-9, db_mode_setting);
end
%% Plotting and export phase
show_histograms = 1;
showEye = 1;
showPSD = 1;
for mIdx = 1:numel(M_values)
M = M_values(mIdx);
fsym = symbolRates(mIdx);
rawSignal = rawSignals{mIdx};
equalized_signal = eyeSignals{mIdx};
referenceForEye = eyeReferences{mIdx};
if showPSD
psdFigure = psd_figure_base + mIdx + db_mode_setting;
figure(psdFigure); clf;
switch db_mode_setting
case 0
referencePsdName = sprintf('PAM-%d reference', M);
equalizedPsdName = 'FFE output';
psd_color_equalized = dsp_styles.color( ...
dsp_styles.algorithm_key == "vnle", :);
case 1
referencePsdName = 'DB-target reference';
equalizedPsdName = 'DB-targeted VNLE output';
psd_color_equalized = dsp_styles.color( ...
dsp_styles.algorithm_key == "vnle_db_mlse", :);
case 2
referencePsdName = 'DB-encoded reference';
equalizedPsdName = 'DB-encoded VNLE output';
psd_color_equalized = dsp_styles.color( ...
dsp_styles.algorithm_key == "db_encoded", :);
end
referenceForEye.spectrum( ...
"fignum", psdFigure, ...
"show_onesided", 1, ...
"fft_length", 4096, ...
"displayname", referencePsdName, ...
"color", psd_color_target);
rawSignal.spectrum( ...
"fignum", psdFigure, ...
"show_onesided", 1, ...
"fft_length", 4096, ...
"displayname", 'Received signal', ...
"color", psd_color_received);
equalized_signal.spectrum( ...
"fignum", psdFigure, ...
"show_onesided", 1, ...
"fft_length", 4096, ...
"displayname", equalizedPsdName, ...
"color", psd_color_equalized);
eq_noise = equalized_signal - referenceForEye;
showEQNoisePSD(eq_noise, ...
"fignum", 800, ...
"displayname", sprintf('%.0f Gbps: VNLE Noise', selectedBitrate), ...
"colormode", "diverging");
% PSDs are line-only, irrespective of the marker styles used by
% algorithm comparison plots.
set(findall(gca, 'Type', 'Line'), 'Marker', 'none');
figure(psdFigure);
title(sprintf('PSD comparison: %.0f GBd PAM-%d', fsym*1e-9, M), ...
'Interpreter', 'none');
legend('Location', 'best', 'Interpreter', 'none');
grid on;
box on;
if export_tikz
baudrateLabel = sprintf('%.0fGBd', fsym*1e-9);
psdFilename = fullfile(tikz_psd_folder, ...
sprintf('psd_pam_%d_%s_db_mode_%d.tikz', ...
M, baudrateLabel, db_mode_setting));
mat2tikz_improved(psdFilename);
end
end
if showEye
% Use the native Signal eye implementation for the displayed eye.
eyeFigure = eye_figure_base + mIdx+ db_mode_setting;
equalized_signal.eye(fsym, M, ...
"fignum", eyeFigure, ...
"displayname", sprintf('PAM-%d, db_mode = %d', M, db_mode_setting));
figure(eyeFigure);
set(gcf, "Position", [100 + 430*(mIdx - 1), 100, 400, 360]);
stripEyeAxes(gca);
if export_tikz
baudrateLabel = sprintf('%.0fGBd', fsym*1e-9);
eyeFilename = fullfile(tikz_eye_folder, ...
sprintf('eye_pam_%d_%s_db_mode_%d.tikz', ...
M, baudrateLabel, db_mode_setting));
mat2tikz_improved(eyeFilename);
end
end
if show_histograms || export_tikz
histogramFigure = histogram_figure_base + M + db_mode_setting;
plotHistogram(equalized_signal, referenceForEye, ...
M, histogramFigure, db_mode_setting, histogramLegendLabels(M));
if export_tikz
figure(histogramFigure);
histogramFilename = fullfile(tikz_histogram_folder, ...
sprintf('histogram_pam_%d_%s_db_mode_%d.tikz', ...
M, baudrateLabel, db_mode_setting));
mat2tikz_improved(histogramFilename,"cleanfigure",1);
end
end
end
%% Local functions
function signalOut = averageScopeSignals(scopeCell, averageSignals, gain)
signalOut = scopeCell{1};
if ~averageSignals
return
end
commonLength = min(cellfun(@(s) numel(s.signal), scopeCell));
scopeMean = zeros(commonLength, 1);
for idx = 1:numel(scopeCell)
scopeMean = scopeMean + scopeCell{idx}.signal(1:commonLength);
end
scopeMean = scopeMean ./ numel(scopeCell);
signalOut.signal = gain .* scopeMean;
end
function eq_ = makeVnle(lenTr, trainingLoops, ddLoops, eqK, muDc, muFfe, muDfe)
eq_ = EQ("Ne", [50, 5, 5], ...
"Nb", [0, 0, 0], ...
"training_length", lenTr, ...
"training_loops", trainingLoops, ...
"dd_loops", ddLoops, ...
"K", eqK, ...
"DCmu", muDc, ...
"DDmu", [muFfe, muDfe], ...
"DFEmu", 0.005, ...
"FFEmu", 0, ...
"plotfinal", 0, ...
"ideal_dfe", true);
end
function plotHistogram(equalizedSignal, referenceForEye, M, figureNumber, ...
dbModeSetting, legendLabels)
figure(figureNumber); clf;
if dbModeSetting ~= 0
uncodedReference = Duobinary().decode(referenceForEye, "M", M);
showLevelHistogram(equalizedSignal, referenceForEye, ...
"fignum", figureNumber, ...
"ref_symbol_uncoded", uncodedReference, ...
"legendLabels", legendLabels);
else
showLevelHistogram(equalizedSignal, referenceForEye, ...
"fignum", figureNumber, ...
"legendLabels", legendLabels);
end
title(sprintf('PAM-%d histogram, db\_mode = %d', M, dbModeSetting));
end
function labels = histogramLegendLabels(M)
labels = arrayfun(@(idx) sprintf('$p(z|d=d_{%d})$', idx), ...
1:M, 'UniformOutput', false);
end
function stripEyeAxes(ax)
title(ax, '');
xlabel(ax, '');
ylabel(ax, '');
set(ax, ...
'XTick', [], ...
'YTick', [], ...
'XTickLabel', [], ...
'YTickLabel', [], ...
'XMinorTick', 'off', ...
'YMinorTick', 'off');
grid(ax, 'off');
end
function styles = defaultAlgorithmStyles()
styles = table( ...
["vnle"; ...
"vnle_pf_mlse"; ...
"vnle_db_mlse"; ...
"ml_mlse"; ...
"db_encoded"], ...
[equalizer_structure.vnle; ...
equalizer_structure.vnle_pf_mlse; ...
equalizer_structure.vnle_db_mlse; ...
equalizer_structure.ml_mlse; ...
equalizer_structure.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", "eq", "name", "marker", ...
"lineStyle", "markerFaceColor", "color"]);
end