385 lines
12 KiB
Matlab
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
|