%% 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 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