work on MPI

This commit is contained in:
Silas Oettinghaus
2026-07-13 15:25:45 +02:00
parent a6cf742121
commit ef0a74cb7f
16 changed files with 2894 additions and 705 deletions

View File

@@ -0,0 +1,404 @@
function output = mpi_recipe_dev(Scpe_sig_raw, Symbols, Tx_bits, options)
%mpi_recipe_dev Minimal example recipe for the DSP job framework.
% This recipe intentionally performs only light preprocessing and records
% summary values. It demonstrates the recipe interface without running a
% full equalizer chain.
arguments
Scpe_sig_raw
Symbols
Tx_bits
options.fsym
options.M
options.duob_mode
options.dataTable table
options.userParameters struct = struct()
options.debug_plots (1,1) logical = false
end
Scpe_sig = preprocessSignal(Scpe_sig_raw, Symbols, options.fsym, ...
"mode", "auto", ...
"debug_plots", options.debug_plots);
output = struct();
%% conventional FFE
eq_core_settings = { ...
"sps", 2, ...
"order", 25, ...
"decide", 0, ...
"adaption_technique", "nlms"};
eq_training_settings = { ...
"len_tr", 4096, ...
"epochs_tr", 5, ...
"mu_tr", 0.04};
eq_dd_settings = { ...
"dd_mode", 1, ...
"epochs_dd", 3, ...
"mu_dd", 0.012};
eq_a1_settings = { ...
"dc_smoothing_a1", 0, ...
"dc_avg_bufferlength_a1", 0, ...
"dc_avg_update_blocklength_a1", 1};
eq_a2_settings = { ...
"dc_smoothing_a2", 0, ...
"dc_level_avg_bufferlength_a2", 0, ...
"dc_level_update_blocklength_a2", 0, ...
"dc_level_weights_a2", [0.6 0.6 0.6 0.6]};
eq_dc_tracking_settings = { ...
"dc_tracking_mu", 0, ...
"dc_tracking_adaptive_enabled", 0, ...
"dc_tracking_persistence_gain", 0, ...
"dc_tracking_buffer_len", 0};
eq_ffe_update_settings = { ...
"ffe_update_buffer_len", 1};
eq_optimizer_settings = { ...
"optmize_mus", 0, ...
"plot_mu_optimization", options.debug_plots, ...
"optimize_dc_tracking_params", 0, ...
"optimize_a2_level_weights", 0, ...
"a2_level_weight_optimization_len", 2^15, ...
"a2_level_weight_optimization_max_evals", 30, ...
"a2_level_weight_max", 1};
eq_debug_settings = { ...
"save_debug", false};
eq_settings = [ ...
eq_core_settings, ...
eq_training_settings, ...
eq_dd_settings, ...
eq_a1_settings, ...
eq_a2_settings, ...
eq_dc_tracking_settings, ...
eq_ffe_update_settings, ...
eq_optimizer_settings, ...
eq_debug_settings];
eq_ffe = FFE(eq_settings{:});
if 1
[ffe_results,equalized_signal] = ffe(eq_ffe, options.M, Scpe_sig, Symbols, Tx_bits, ...
"precode_mode", options.duob_mode, ...
'showAnalysis', options.debug_plots, ...
"postFFE", [], ...
"eth_style_symbol_mapping", 0);
ffe_results.metrics.print("description",sprintf('Immediate A2; SIR %d dB',options.dataTable.sir));
output.conventional_ffe = ffe_results;
end
if options.debug_plots
showLevelScatter(Scpe_sig_raw, Symbols, ...
"fsym", options.fsym, ...
"fignum", 400, ...
"normalize", true);
[~, avg_for_lvl] = showLevelScatter(equalized_signal, Symbols, ...
"fsym", options.fsym, ...
"fignum", 401, ...
"normalize", true);
end
%% A2
eq_core_settings = { ...
"sps", 2, ...
"order", 25, ...
"decide", 0, ...
"adaption_technique", "nlms"};
eq_training_settings = { ...
"len_tr", 4096, ...
"epochs_tr", 5, ...
"mu_tr", 0.04};
eq_dd_settings = { ...
"dd_mode", 1, ...
"epochs_dd", 3, ...
"mu_dd", 0.012};
eq_a1_settings = { ...
"dc_smoothing_a1", 0, ...
"dc_avg_bufferlength_a1", 0, ...
"dc_avg_update_blocklength_a1", 1};
eq_a2_settings = { ...
"dc_smoothing_a2", 1, ...
"dc_level_avg_bufferlength_a2", 256, ...
"dc_level_update_blocklength_a2", options.userParameters.block_update, ...
"dc_level_weights_a2", [0.6 0.6 0.6 0.6]};
eq_dc_tracking_settings = { ...
"dc_tracking_mu", 0, ...
"dc_tracking_adaptive_enabled", 0, ...
"dc_tracking_persistence_gain", 0, ...
"dc_tracking_buffer_len", 0};
eq_ffe_update_settings = { ...
"ffe_update_buffer_len", 1};
eq_optimizer_settings = { ...
"optmize_mus", 0, ...
"plot_mu_optimization", options.debug_plots, ...
"optimize_dc_tracking_params", 0, ...
"optimize_a2_level_weights", 1, ...
"a2_level_weight_optimization_len", 2^15, ...
"a2_level_weight_optimization_max_evals", 30, ...
"a2_level_weight_max", 1};
eq_debug_settings = { ...
"save_debug", false};
eq_settings = [ ...
eq_core_settings, ...
eq_training_settings, ...
eq_dd_settings, ...
eq_a1_settings, ...
eq_a2_settings, ...
eq_dc_tracking_settings, ...
eq_ffe_update_settings, ...
eq_optimizer_settings, ...
eq_debug_settings];
eq_ffe = FFE(eq_settings{:});
if 1
[ffe_results,equalized_signal] = ffe(eq_ffe, options.M, Scpe_sig, Symbols, Tx_bits, ...
"precode_mode", options.duob_mode, ...
'showAnalysis', options.debug_plots, ...
"postFFE", [], ...
"eth_style_symbol_mapping", 0);
ffe_results.metrics.print("description",sprintf('Immediate A2; SIR %d dB',options.dataTable.sir));
output.a2_immediate_updates = ffe_results;
end
if options.debug_plots
showLevelScatter(Scpe_sig_raw, Symbols, ...
"fsym", options.fsym, ...
"fignum", 400, ...
"normalize", true);
[~, avg_for_lvl] = showLevelScatter(equalized_signal, Symbols, ...
"fsym", options.fsym, ...
"fignum", 401, ...
"normalize", true);
end
%% A1
eq_a1_settings = { ...
"dc_smoothing_a1", 1 ...
"dc_avg_bufferlength_a1", 2048, ...
"dc_avg_update_blocklength_a1", options.userParameters.block_update};
eq_a2_settings = { ...
"dc_smoothing_a2", 0, ...
"dc_level_avg_bufferlength_a2", 0, ...
"dc_level_update_blocklength_a2", 0, ...
"dc_level_weights_a2", [0.6 0.6 0.6 0.6]};
eq_optimizer_settings = { ...
"optmize_mus", 0, ...
"plot_mu_optimization", options.debug_plots, ...
"optimize_dc_tracking_params", 0, ...
"optimize_a2_level_weights", 0, ...
"a2_level_weight_optimization_len", 2^15, ...
"a2_level_weight_optimization_max_evals", 30, ...
"a2_level_weight_max", 1};
eq_debug_settings = { ...
"save_debug", false};
eq_settings = [ ...
eq_core_settings, ...
eq_training_settings, ...
eq_dd_settings, ...
eq_a1_settings, ...
eq_a2_settings, ...
eq_dc_tracking_settings, ...
eq_ffe_update_settings, ...
eq_optimizer_settings, ...
eq_debug_settings];
eq_ffe = FFE(eq_settings{:});
if 1
[ffe_results,equalized_signal] = ffe(eq_ffe, options.M, Scpe_sig, Symbols, Tx_bits, ...
"precode_mode", options.duob_mode, ...
'showAnalysis', options.debug_plots, ...
"postFFE", [], ...
"eth_style_symbol_mapping", 0);
ffe_results.metrics.print("description",sprintf('Immediate A1; SIR %d dB',options.dataTable.sir));
output.a1_immediate_updates = ffe_results;
end
%% Tracking
eq_core_settings = { ...
"sps", 2, ...
"order", 25, ...
"decide", 0, ...
"adaption_technique", "nlms"};
eq_training_settings = { ...
"len_tr", 4096, ...
"epochs_tr", 5, ...
"mu_tr", 0.04};
eq_dd_settings = { ...
"dd_mode", 1, ...
"epochs_dd", 3, ...
"mu_dd", 0.012};
eq_a1_settings = { ...
"dc_smoothing_a1", 0, ...
"dc_avg_bufferlength_a1", 0, ...
"dc_avg_update_blocklength_a1", 1};
eq_a2_settings = { ...
"dc_smoothing_a2", 0, ...
"dc_level_avg_bufferlength_a2", 0, ...
"dc_level_update_blocklength_a2", 0, ...
"dc_level_weights_a2", [0.6 0.6 0.6 0.6]};
eq_dc_tracking_settings = { ...
"dc_tracking_mu", 0.002, ...
"dc_tracking_adaptive_enabled", 0, ...
"dc_tracking_persistence_gain", 0, ...
"dc_tracking_buffer_len", options.userParameters.block_update};
eq_ffe_update_settings = { ...
"ffe_update_buffer_len", 1};
eq_optimizer_settings = { ...
"optmize_mus", 0, ...
"plot_mu_optimization", options.debug_plots, ...
"optimize_dc_tracking_params", 1, ...
"optimize_a2_level_weights", 0, ...
"a2_level_weight_optimization_len", 2^15, ...
"a2_level_weight_optimization_max_evals", 30, ...
"a2_level_weight_max", 1};
eq_debug_settings = { ...
"save_debug", false};
eq_settings = [ ...
eq_core_settings, ...
eq_training_settings, ...
eq_dd_settings, ...
eq_a1_settings, ...
eq_a2_settings, ...
eq_dc_tracking_settings, ...
eq_ffe_update_settings, ...
eq_optimizer_settings, ...
eq_debug_settings];
eq_ffe = FFE(eq_settings{:});
if 1
[ffe_results,equalized_signal] = ffe(eq_ffe, options.M, Scpe_sig, Symbols, Tx_bits, ...
"precode_mode", options.duob_mode, ...
'showAnalysis', options.debug_plots, ...
"postFFE", [], ...
"eth_style_symbol_mapping", 0);
ffe_results.metrics.print("description",sprintf('Immediate A2; SIR %d dB',options.dataTable.sir));
output.tracking_fixmu_immediate_updates = ffe_results;
end
%% Tracking Adaptive
eq_core_settings = { ...
"sps", 2, ...
"order", 25, ...
"decide", 0, ...
"adaption_technique", "nlms"};
eq_training_settings = { ...
"len_tr", 4096, ...
"epochs_tr", 5, ...
"mu_tr", 0.04};
eq_dd_settings = { ...
"dd_mode", 1, ...
"epochs_dd", 3, ...
"mu_dd", 0.012};
eq_a1_settings = { ...
"dc_smoothing_a1", 0, ...
"dc_avg_bufferlength_a1", 0, ...
"dc_avg_update_blocklength_a1", 1};
eq_a2_settings = { ...
"dc_smoothing_a2", 0, ...
"dc_level_avg_bufferlength_a2", 0, ...
"dc_level_update_blocklength_a2", 0, ...
"dc_level_weights_a2", [0.6 0.6 0.6 0.6]};
eq_dc_tracking_settings = { ...
"dc_tracking_mu", 0.002, ...
"dc_tracking_adaptive_enabled", 1, ...
"dc_tracking_persistence_gain", 0, ...
"dc_tracking_buffer_len", options.userParameters.block_update};
eq_ffe_update_settings = { ...
"ffe_update_buffer_len", 1};
eq_optimizer_settings = { ...
"optmize_mus", 0, ...
"plot_mu_optimization", options.debug_plots, ...
"optimize_dc_tracking_params", 1, ...
"optimize_a2_level_weights", 0, ...
"a2_level_weight_optimization_len", 2^15, ...
"a2_level_weight_optimization_max_evals", 30, ...
"a2_level_weight_max", 1};
eq_debug_settings = { ...
"save_debug", false};
eq_settings = [ ...
eq_core_settings, ...
eq_training_settings, ...
eq_dd_settings, ...
eq_a1_settings, ...
eq_a2_settings, ...
eq_dc_tracking_settings, ...
eq_ffe_update_settings, ...
eq_optimizer_settings, ...
eq_debug_settings];
eq_ffe = FFE(eq_settings{:});
if 1
[ffe_results,equalized_signal] = ffe(eq_ffe, options.M, Scpe_sig, Symbols, Tx_bits, ...
"precode_mode", options.duob_mode, ...
'showAnalysis', options.debug_plots, ...
"postFFE", [], ...
"eth_style_symbol_mapping", 0);
ffe_results.metrics.print("description",sprintf('Immediate A2; SIR %d dB',options.dataTable.sir));
output.tracking_adaptive_immediate_updates = ffe_results;
end
end

View File

@@ -4,202 +4,469 @@ function output = mpi_recipe_dev(Scpe_sig_raw, Symbols, Tx_bits, options)
% summary values. It demonstrates the recipe interface without running a
% full equalizer chain.
arguments
Scpe_sig_raw
Symbols
Tx_bits
options.fsym
options.M
options.duob_mode
options.dataTable table
options.userParameters struct = struct()
options.debug_plots (1,1) logical = false
end
arguments
Scpe_sig_raw
Symbols
Tx_bits
options.fsym
options.M
options.duob_mode
options.dataTable table
options.userParameters struct = struct()
options.debug_plots (1,1) logical = false
end
Scpe_sig = preprocessSignal(Scpe_sig_raw, Symbols, options.fsym, ...
"mode", "auto", ...
"debug_plots", options.debug_plots);
output = struct();
Scpe_sig = preprocessSignal(Scpe_sig_raw, Symbols, options.fsym, ...
"mode", "auto", ...
"debug_plots", options.debug_plots);
output = struct();
%% conventional FFE
eq_core_settings = { ...
"sps", 2, ...
"order", 50, ...
"decide", 0, ...
"adaption_technique", "nlms"};
eq_training_settings = { ...
"len_tr", 4096, ...
"epochs_tr", 5, ...
"mu_tr", 0.04};
eq_dd_settings = { ...
"dd_mode", 1, ...
"epochs_dd", 3, ...
"mu_dd", 0.012};
eq_a1_settings = { ...
"dc_smoothing_a1", 0, ...
"dc_avg_bufferlength_a1", 0, ...
"dc_avg_update_blocklength_a1", 1};
eq_a2_settings = { ...
"dc_smoothing_a2", 0, ...
"dc_level_avg_bufferlength_a2", 0, ...
"dc_level_update_blocklength_a2", 0, ...
"dc_level_weights_a2", [0.6 0.6 0.6 0.6]};
eq_dc_tracking_settings = { ...
"dc_tracking_mu", 0, ...
"dc_tracking_adaptive_enabled", 0, ...
"dc_tracking_persistence_gain", 0, ...
"dc_tracking_buffer_len", 1};
eq_ffe_update_settings = { ...
"ffe_update_buffer_len", 0};
eq_optimizer_settings = { ...
"optmize_mus", 0, ...
"plot_mu_optimization", options.debug_plots, ...
"optimize_dc_tracking_params", 0, ...
"optimize_a2_level_weights", 0, ...
"a2_level_weight_optimization_len", 2^15, ...
"a2_level_weight_optimization_max_evals", 30, ...
"a2_level_weight_max", 1};
eq_debug_settings = { ...
"save_debug", false};
eq_settings = [ ...
eq_core_settings, ...
eq_training_settings, ...
eq_dd_settings, ...
eq_a1_settings, ...
eq_a2_settings, ...
eq_dc_tracking_settings, ...
eq_ffe_update_settings, ...
eq_optimizer_settings, ...
eq_debug_settings];
eq_ffe = FFE(eq_settings{:});
% ffe_order_ffe = [50, 0, 0];
% mu_ffe = [0.0001, 0.0008, 0.001];
% mu_dfe = 0.0004;
% mu_ffe = [0, 0,0];
% mu_dfe = 0.0004;
% mu_dc = 0.005;
% eq_ffe = EQ("Ne",ffe_order_ffe,"Nb",[0,0,0],"training_length",4096,"training_loops",5,"dd_loops",5,"K",2,"DCmu",0.00,"DDmu",[mu_ffe mu_dfe],"DFEmu",0.005,"FFEmu",0,"plotfinal",0,"ideal_dfe",0);
if 1
[ffe_results,equalized_signal] = ffe(eq_ffe, options.M, Scpe_sig, Symbols, Tx_bits, ...
"precode_mode", options.duob_mode, ...
'showAnalysis', options.debug_plots, ...
"postFFE", [], ...
"eth_style_symbol_mapping", 0);
ffe_results.metrics.print("description",sprintf('Immediate A2; SIR %d dB',options.dataTable.sir));
output.conventional_ffe = ffe_results;
end
if 1
eq_core_settings = { ...
"sps", 2, ...
"order", 25, ...
"decide", 0, ...
"adaption_technique", "nlms"};
showLevelScatter(Scpe_sig_raw, Symbols, ...
"fsym", options.fsym, ...
"fignum", 400, ...
"normalize", true, ...
"debug_plots", false, ...
"showPlot", true, ...
"showStdAnnotations", true, ...
"yLimits", [-2.5 2.5], ...
"xLimits",[0 2.3],...
"scatterAlpha", 0.25, ...
"scatterSize", 1, ...
"avgLineMaxPoints", 500, ...
"avgLineSmoothWindow", 5);
eq_training_settings = { ...
"len_tr", 4096, ...
"epochs_tr", 5, ...
"mu_tr", 0.04};
eq_dd_settings = { ...
"dd_mode", 1, ...
"epochs_dd", 5, ...
"mu_dd", 0.012};
exportName = "before_eq";
exportDir = "C:/Users/Silas/Documents/6971e0b65b380ca6d71c837f/04_Experimental_Evaluation/tikz/mpi";
pngFile = fullfile(exportDir, exportName + "_img.png"); % absolute filesystem output
tikzFile = fullfile(exportDir, exportName + ".tikz"); % absolute filesystem output
pngTikzPath = "04_Experimental_Evaluation/tikz/mpi/" + exportName + "_img.png"; % path written into TikZ
figure(400);
exportLevelScatterTikz(gca, pngFile, tikzFile, pngTikzPath, ...
"resolutionDpi", 150, ...
"generatedBy", "mpi_recipe_dev.m");
eq_a1_settings = { ...
"dc_smoothing_a1", 0, ...
"dc_avg_bufferlength_a1", 0};
showLevelScatter(equalized_signal.*-1, Symbols, ...
"fsym", options.fsym, ...
"fignum", 401, ...
"normalize", true, ...
"debug_plots", false, ...
"showPlot", true, ...
"showStdAnnotations", true, ...
"yLimits", [-2.5 2.5], ...
"xLimits",[0 2.3],...
"scatterAlpha", 0.25, ...
"scatterSize", 1, ...
"avgLineMaxPoints", 500, ...
"avgLineSmoothWindow", 5);
eq_a2_settings = { ...
"dc_smoothing_a2", 0, ...
"dc_level_avg_bufferlength_a2", 0, ...
"dc_level_weights_a2", [0.692 0.979 0.98 0.138]};
exportName = "after_ffe_eq";
pngFile = fullfile(exportDir, exportName + "_img.png"); % absolute filesystem output
tikzFile = fullfile(exportDir, exportName + ".tikz"); % absolute filesystem output
pngTikzPath = "04_Experimental_Evaluation/tikz/mpi/" + exportName + "_img.png"; % path written into TikZ
figure(401);
exportLevelScatterTikz(gca, pngFile, tikzFile, pngTikzPath, ...
"resolutionDpi", 150, ...
"generatedBy", "mpi_recipe_dev.m");
eq_dc_tracking_settings = { ...
"dc_tracking_mu", 0.05, ...
"dc_tracking_adaptive_enabled", 0, ...
"dc_tracking_buffer_len", 1024};
end
eq_ffe_update_settings = { ...
"ffe_update_buffer_len", 1};
eq_optimizer_settings = { ...
"optmize_mus", 0, ...
"plot_mu_optimization", options.debug_plots, ...
"optimize_dc_tracking_params", 1, ...
"optimize_a2_level_weights", 0, ...
"a2_level_weight_optimization_len", 2^15, ...
"a2_level_weight_optimization_max_evals", 30, ...
"a2_level_weight_max", 1};
%% A2
eq_core_settings = { ...
"sps", 2, ...
"order", 50, ...
"decide", 0, ...
"adaption_technique", "nlms"};
eq_debug_settings = { ...
"save_debug", true};
eq_training_settings = { ...
"len_tr", 4096, ...
"epochs_tr", 5, ...
"mu_tr", 0.04};
eq_settings = [ ...
eq_core_settings, ...
eq_training_settings, ...
eq_dd_settings, ...
eq_a1_settings, ...
eq_a2_settings, ...
eq_dc_tracking_settings, ...
eq_ffe_update_settings, ...
eq_optimizer_settings, ...
eq_debug_settings];
eq_dd_settings = { ...
"dd_mode", 1, ...
"epochs_dd", 3, ...
"mu_dd", 0.012};
eq_ffe = FFE(eq_settings{:});
eq_a1_settings = { ...
"dc_smoothing_a1", 0, ...
"dc_avg_bufferlength_a1", 0, ...
"dc_avg_update_blocklength_a1", 1};
eq_a2_settings = { ...
"dc_smoothing_a2", 1, ...
"dc_level_avg_bufferlength_a2", 256, ...
"dc_level_update_blocklength_a2", options.userParameters.block_update, ...
"dc_level_weights_a2", [0.6]};
eq_dc_tracking_settings = { ...
"dc_tracking_mu", 0, ...
"dc_tracking_adaptive_enabled", 0, ...
"dc_tracking_persistence_gain", 0, ...
"dc_tracking_buffer_len", 0};
eq_ffe_update_settings = { ...
"ffe_update_buffer_len", 1};
eq_optimizer_settings = { ...
"optmize_mus", 0, ...
"plot_mu_optimization", options.debug_plots, ...
"optimize_dc_tracking_params", 0, ...
"optimize_a2_level_weights", 1, ...
"a2_level_weight_optimization_len", 2^15, ...
"a2_level_weight_optimization_max_evals", 30, ...
"a2_level_weight_max", 1};
eq_debug_settings = { ...
"save_debug", false};
eq_settings = [ ...
eq_core_settings, ...
eq_training_settings, ...
eq_dd_settings, ...
eq_a1_settings, ...
eq_a2_settings, ...
eq_dc_tracking_settings, ...
eq_ffe_update_settings, ...
eq_optimizer_settings, ...
eq_debug_settings];
eq_ffe = FFE(eq_settings{:});
if 0
[ffe_results,equalized_signal] = ffe(eq_ffe, options.M, Scpe_sig, Symbols, Tx_bits, ...
"precode_mode", options.duob_mode, ...
'showAnalysis', options.debug_plots, ...
"postFFE", [], ...
"eth_style_symbol_mapping", 0);
ffe_results.metrics.print("description",sprintf('Immediate A2; SIR %d dB',options.dataTable.sir));
output.a2_immediate_updates = ffe_results;
end
if options.debug_plots
showLevelScatter(Scpe_sig_raw, Symbols, ...
"fsym", options.fsym, ...
"fignum", 400, ...
"normalize", true);
[~, avg_for_lvl] = showLevelScatter(equalized_signal, Symbols, ...
"fsym", options.fsym, ...
"fignum", 401, ...
"normalize", true);
end
%% A1
eq_a1_settings = { ...
"dc_smoothing_a1", 1 ...
"dc_avg_bufferlength_a1", 2048, ...
"dc_avg_update_blocklength_a1", options.userParameters.block_update};
eq_a2_settings = { ...
"dc_smoothing_a2", 0, ...
"dc_level_avg_bufferlength_a2", 0, ...
"dc_level_update_blocklength_a2", 0, ...
"dc_level_weights_a2", [0.6 0.6 0.6 0.6]};
eq_optimizer_settings = { ...
"optmize_mus", 0, ...
"plot_mu_optimization", options.debug_plots, ...
"optimize_dc_tracking_params", 0, ...
"optimize_a2_level_weights", 0, ...
"a2_level_weight_optimization_len", 2^15, ...
"a2_level_weight_optimization_max_evals", 30, ...
"a2_level_weight_max", 1};
eq_debug_settings = { ...
"save_debug", false};
eq_settings = [ ...
eq_core_settings, ...
eq_training_settings, ...
eq_dd_settings, ...
eq_a1_settings, ...
eq_a2_settings, ...
eq_dc_tracking_settings, ...
eq_ffe_update_settings, ...
eq_optimizer_settings, ...
eq_debug_settings];
eq_ffe = FFE(eq_settings{:});
if 0
[ffe_results,equalized_signal] = ffe(eq_ffe, options.M, Scpe_sig, Symbols, Tx_bits, ...
"precode_mode", options.duob_mode, ...
'showAnalysis', options.debug_plots, ...
"postFFE", [], ...
"eth_style_symbol_mapping", 0);
ffe_results.metrics.print("description",sprintf('Immediate A1; SIR %d dB',options.dataTable.sir));
output.a1_immediate_updates = ffe_results;
showLevelScatter(Scpe_sig_raw, Symbols, ...
"fsym", options.fsym, ...
"fignum", 400, ...
"normalize", true);
[~, avg_for_lvl] = showLevelScatter(equalized_signal, Symbols, ...
"fsym", options.fsym, ...
"fignum", 401, ...
"normalize", true);
end
%% Tracking fixed
eq_core_settings = { ...
"sps", 2, ...
"order", 50, ...
"decide", 0, ...
"adaption_technique", "nlms"};
eq_training_settings = { ...
"len_tr", 4096, ...
"epochs_tr", 5, ...
"mu_tr", 0.04};
eq_dd_settings = { ...
"dd_mode", 1, ...
"epochs_dd", 3, ...
"mu_dd", 0.012};
eq_a1_settings = { ...
"dc_smoothing_a1", 0, ...
"dc_avg_bufferlength_a1", 0, ...
"dc_avg_update_blocklength_a1", 1};
eq_a2_settings = { ...
"dc_smoothing_a2", 0, ...
"dc_level_avg_bufferlength_a2", 0, ...
"dc_level_update_blocklength_a2", 0, ...
"dc_level_weights_a2", [0.6 0.6 0.6 0.6]};
eq_dc_tracking_settings = { ...
"dc_tracking_mu", 0.002, ...
"dc_tracking_adaptive_enabled", 0, ...
"dc_tracking_persistence_gain", 0, ...
"dc_tracking_buffer_len", options.userParameters.block_update};
eq_ffe_update_settings = { ...
"ffe_update_buffer_len", 1};
eq_optimizer_settings = { ...
"optmize_mus", 0, ...
"plot_mu_optimization", options.debug_plots, ...
"optimize_dc_tracking_params", 1, ...
"optimize_a2_level_weights", 0, ...
"a2_level_weight_optimization_len", 2^15, ...
"a2_level_weight_optimization_max_evals", 30, ...
"a2_level_weight_max", 1};
eq_debug_settings = { ...
"save_debug", false};
eq_settings = [ ...
eq_core_settings, ...
eq_training_settings, ...
eq_dd_settings, ...
eq_a1_settings, ...
eq_a2_settings, ...
eq_dc_tracking_settings, ...
eq_ffe_update_settings, ...
eq_optimizer_settings, ...
eq_debug_settings];
eq_ffe = FFE(eq_settings{:});
if 1
[ffe_results,equalized_signal] = ffe(eq_ffe, options.M, Scpe_sig, Symbols, Tx_bits, ...
"precode_mode", options.duob_mode, ...
'showAnalysis', options.debug_plots, ...
"postFFE", [], ...
"eth_style_symbol_mapping", 0);
ffe_results.metrics.print("description",sprintf('Immediate A2; SIR %d dB',options.dataTable.sir));
output.tracking_fixmu_immediate_updates = ffe_results;
end
%% Tracking Adaptive
eq_core_settings = { ...
"sps", 2, ...
"order", 50, ...
"decide", 0, ...
"adaption_technique", "nlms"};
eq_training_settings = { ...
"len_tr", 4096, ...
"epochs_tr", 5, ...
"mu_tr", 0.04};
eq_dd_settings = { ...
"dd_mode", 1, ...
"epochs_dd", 3, ...
"mu_dd", 0.012};
eq_a1_settings = { ...
"dc_smoothing_a1", 0, ...
"dc_avg_bufferlength_a1", 0, ...
"dc_avg_update_blocklength_a1", 1};
eq_a2_settings = { ...
"dc_smoothing_a2", 0, ...
"dc_level_avg_bufferlength_a2", 0, ...
"dc_level_update_blocklength_a2", 0, ...
"dc_level_weights_a2", [0.6 0.6 0.6 0.6]};
eq_dc_tracking_settings = { ...
"dc_tracking_mu", 0.002, ...
"dc_tracking_adaptive_enabled", 1, ...
"dc_tracking_persistence_gain", 0, ...
"dc_tracking_buffer_len", options.userParameters.block_update};
eq_ffe_update_settings = { ...
"ffe_update_buffer_len", 1};
eq_optimizer_settings = { ...
"optmize_mus", 0, ...
"plot_mu_optimization", options.debug_plots, ...
"optimize_dc_tracking_params", 1, ...
"optimize_a2_level_weights", 0, ...
"a2_level_weight_optimization_len", 2^15, ...
"a2_level_weight_optimization_max_evals", 30, ...
"a2_level_weight_max", 1};
eq_debug_settings = { ...
"save_debug", false};
eq_settings = [ ...
eq_core_settings, ...
eq_training_settings, ...
eq_dd_settings, ...
eq_a1_settings, ...
eq_a2_settings, ...
eq_dc_tracking_settings, ...
eq_ffe_update_settings, ...
eq_optimizer_settings, ...
eq_debug_settings];
eq_ffe = FFE(eq_settings{:});
if 1
[ffe_results,equalized_signal] = ffe(eq_ffe, options.M, Scpe_sig, Symbols, Tx_bits, ...
"precode_mode", options.duob_mode, ...
'showAnalysis', options.debug_plots, ...
"postFFE", [], ...
"eth_style_symbol_mapping", 0);
ffe_results.metrics.print("description",sprintf('Immediate A2; SIR %d dB',options.dataTable.sir));
output.tracking_adaptive_immediate_updates = ffe_results;
showLevelScatter(Scpe_sig_raw, Symbols, ...
"fsym", options.fsym, ...
"fignum", 400, ...
"normalize", true);
[~, avg_for_lvl] = showLevelScatter(equalized_signal, Symbols, ...
"fsym", options.fsym, ...
"fignum", 401, ...
"normalize", true);
end
%% NORMAL FFE
if 1
[ffe_results,equalized_signal] = ffe(eq_ffe, options.M, Scpe_sig, Symbols, Tx_bits, ...
"precode_mode", options.duob_mode, ...
'showAnalysis', options.debug_plots, ...
"postFFE", [], ...
"eth_style_symbol_mapping", 0);
ffe_results.metrics.print("description",sprintf('Normal FFE; SIR %d dB',options.dataTable.sir));
output.ffe_package = ffe_results;
[~, avg_for_lvl] = showLevelScatter(equalized_signal, Symbols, ...
"fsym", options.fsym, ...
"fignum", 401, ...
"normalize", true);
output.ffe_debug = struct();
dbg = eq_ffe.debug_struct;
smooth_len = 501;
output.ffe_debug.smoothing_window = smooth_len;
error_first_s = movmean(dbg.error_first_epoch(:),smooth_len,"omitnan");
error_last_s = movmean(dbg.error(:),smooth_len,"omitnan");
dc_tracking_mu_eff_s = movmean(dbg.dc_tracking_mu_eff(:),smooth_len,"omitnan");
dc_tracking_est_s = movmean(dbg.dc_tracking_est(:),smooth_len,"omitnan");
figure(460); clf;
tiledlayout(2,1,"TileSpacing","compact","Padding","compact");
nexttile;
semilogy(error_first_s + eps,"DisplayName","first epoch");
hold on;
semilogy(error_last_s + eps,"DisplayName","last epoch");
grid on;
ylabel("error");
title("FFE debug error");
legend("Location","best");
nexttile;hold on
% plot(eq_sig_mov,"DisplayName","err dc eff");
plot(dc_tracking_mu_eff_s,"DisplayName","mu DC - either fixed or adaptive");
e_dc_scale = max(abs(dc_tracking_est_s),[],"omitnan") + eps;
plot(-1.*dc_tracking_est_s./e_dc_scale,"DisplayName","Inverted DC-tracking; Value that is subtracted during EQ");
avg_lvl_dc=mean(avg_for_lvl,1,"omitnan");
plot(avg_lvl_dc./0.01,"DisplayName","Smoothed EQ output signal; calc'd by showLevelScatter");
grid on;
xlabel("Symbol");
ylabel("mu dc eff");
title("Effective adaptive DC step");
legend
inv_dc_track = -dc_tracking_est_s(:);
avg_lvl_dc = avg_lvl_dc(:);
xcorr_len = min(numel(inv_dc_track),numel(avg_lvl_dc));
inv_dc_xcorr = inv_dc_track(1:xcorr_len);
avg_lvl_xcorr = avg_lvl_dc(1:xcorr_len);
inv_dc_xcorr = fillmissing(inv_dc_xcorr,"linear","EndValues","nearest");
avg_lvl_xcorr = fillmissing(avg_lvl_xcorr,"linear","EndValues","nearest");
inv_dc_xcorr = inv_dc_xcorr - mean(inv_dc_xcorr,"omitnan");
avg_lvl_xcorr = avg_lvl_xcorr - mean(avg_lvl_xcorr,"omitnan");
[dc_level_xcorr,dc_level_lags] = xcorr(inv_dc_xcorr,avg_lvl_xcorr,"coeff");
[dc_level_corr,dc_level_idx] = max(dc_level_xcorr);
dc_level_delay_symbols = dc_level_lags(dc_level_idx);
output.ffe_debug.dc_level_delay_symbols = dc_level_delay_symbols;
output.ffe_debug.dc_level_delay_corr = dc_level_corr;
output.ffe_debug.dc_level_lags = dc_level_lags;
output.ffe_debug.dc_level_xcorr = dc_level_xcorr;
fprintf("FFE debug: xcorr(inv DC tracking, avg level) delay=%d symbols, corr=%6.3f\n", ...
dc_level_delay_symbols,dc_level_corr);
figure(461); clf;
plot(dc_level_lags,dc_level_xcorr,"DisplayName","xcorr");
hold on;
plot(dc_level_delay_symbols,dc_level_corr,"ro","DisplayName","max");
grid on;
xlabel("Lag in symbols");
ylabel("Correlation coefficient");
title(sprintf("Delay estimate: %d symbols (corr %.3f)",dc_level_delay_symbols,dc_level_corr));
legend("Location","best");
end
%
%
% %% MPI Reduction
% if 1
%
% % dc_buffer_len = 0;
% % ffe_buffer_len = 0;
% % smoothing_buffer_length = options.userParameters.smoothing_length;
% % smoothing_buffer_update = 1;
%
% % eq_ffe_dcr = FFE_DCremoval_adaptive_mu(eq_settings{:}, ...
% % "dc_buffer_len",dc_buffer_len, ...
% % "ffe_buffer_len",ffe_buffer_len,...
% % "smoothing_buffer_length",smoothing_buffer_length,...
% % "smoothing_buffer_update",smoothing_buffer_update);
%
% eq_ = FFE_DCremoval("epochs_tr",5,"epochs_dd",3,"len_tr",4096*2,"mu_dd",...
% 0.0002,"mu_tr",0,"order",25,"sps",2,"decide",0,...
% "mu_dc",0.005,"dc_buffer_len",1);
%
% ffe_results_dcr = ffe(eq_, options.M, Scpe_sig, Symbols, Tx_bits, ...
% "precode_mode", options.duob_mode, ...
% 'showAnalysis', options.debug_plots, ...
% "postFFE", [], ...
% "eth_style_symbol_mapping", 0);
%
% ffe_results_dcr.metrics.print("description",'FFE DCR');
% output.ffe_dcr_package = ffe_results_dcr;
% end
end

View File

@@ -0,0 +1,320 @@
function exportLevelScatterTikz(sourceAx, pngFile, tikzFile, pngTikzPath, options)
%EXPORTLEVELSCATTERTIKZ Export showLevelScatter axes as PNG-backed TikZ.
% Rasterizes scatter objects into a PNG layer and writes average lines plus
% text annotations as PGFPlots objects.
arguments
sourceAx
pngFile (1,1) string
tikzFile (1,1) string
pngTikzPath (1,1) string
options.resolutionDpi (1,1) double {mustBePositive, mustBeInteger} = 150
options.xLabel (1,1) string = "Time in $\mu$s"
options.yLabel (1,1) string = "Normalized Amplitude"
options.generatedBy (1,1) string = "exportLevelScatterTikz.m"
end
outputDir = fileparts(pngFile);
if ~exist(outputDir, "dir")
mkdir(outputDir);
end
exportScatterLayerPng(sourceAx, pngFile, options.resolutionDpi);
linePlots = collectTikzLinePlots(sourceAx);
textAnnotations = collectTikzTextAnnotations(sourceAx);
writeTikzPngAxis(tikzFile, pngTikzPath, sourceAx, linePlots, textAnnotations, options);
end
function exportScatterLayerPng(sourceAx, pngFile, resolutionDpi)
sourceFig = ancestor(sourceAx, "figure");
xLimits = sourceAx.XLim;
yLimits = sourceAx.YLim;
scatterHandles = findGraphicsObjectsByType(sourceAx, "scatter");
exportFig = figure( ...
"Visible", "off", ...
"Color", "white", ...
"Units", sourceFig.Units, ...
"Position", sourceFig.Position);
cleanupFigure = onCleanup(@() close(exportFig));
exportAx = copyobj(sourceAx, exportFig);
exportAx.Units = "normalized";
exportAx.Position = [0 0 1 1];
exportAx.XLim = xLimits;
exportAx.YLim = yLimits;
exportAx.XLimMode = "manual";
exportAx.YLimMode = "manual";
stripAxesToScatterOnly(exportAx);
hideAxesInkForRasterExport(exportAx);
fprintf("Exporting scatter PNG with XLim=[%g %g], YLim=[%g %g], scatter objects=%d: %s\n", ...
xLimits(1), xLimits(2), yLimits(1), yLimits(2), numel(scatterHandles), pngFile);
drawnow;
exportFig.PaperPositionMode = "auto";
print(exportFig, char(pngFile), "-dpng", sprintf("-r%d", resolutionDpi));
end
function stripAxesToScatterOnly(ax)
plotObjects = findall(ax);
for objIdx = 1:numel(plotObjects)
obj = plotObjects(objIdx);
if obj == ax || ~isvalid(obj)
continue
end
objType = string(get(obj, "Type"));
if lower(objType) ~= "scatter"
delete(obj);
end
end
end
function hideAxesInkForRasterExport(ax)
ax.Visible = "on";
ax.Color = "white";
ax.Box = "off";
ax.XGrid = "off";
ax.YGrid = "off";
ax.XMinorGrid = "off";
ax.YMinorGrid = "off";
ax.XTick = [];
ax.YTick = [];
ax.XColor = "white";
ax.YColor = "white";
ax.Title.String = "";
ax.XLabel.String = "";
ax.YLabel.String = "";
end
function handles = findGraphicsObjectsByType(parentHandle, objectType)
allHandles = findall(parentHandle);
matches = false(size(allHandles));
for handleIdx = 1:numel(allHandles)
currentHandle = allHandles(handleIdx);
if ~isvalid(currentHandle)
continue
end
matches(handleIdx) = lower(string(get(currentHandle, "Type"))) == lower(string(objectType));
end
handles = allHandles(matches);
end
function linePlots = collectTikzLinePlots(sourceAx)
lineHandles = findGraphicsObjectsByType(sourceAx, "line");
lineHandles = flipud(lineHandles(:));
linePlots = repmat(struct( ...
"xData", [], ...
"yData", [], ...
"color", [], ...
"lineWidth", []), numel(lineHandles), 1);
validLineCount = 0;
for lineIdx = 1:numel(lineHandles)
lineHandle = lineHandles(lineIdx);
xData = lineHandle.XData(:);
yData = lineHandle.YData(:);
validSamples = isfinite(xData) & isfinite(yData);
if ~any(validSamples)
continue
end
validLineCount = validLineCount + 1;
linePlots(validLineCount).xData = xData(validSamples);
linePlots(validLineCount).yData = yData(validSamples);
linePlots(validLineCount).color = lineHandle.Color;
linePlots(validLineCount).lineWidth = lineHandle.LineWidth;
end
linePlots = linePlots(1:validLineCount);
end
function textAnnotations = collectTikzTextAnnotations(sourceAx)
textHandles = findGraphicsObjectsByType(sourceAx, "text");
textHandles = flipud(textHandles(:));
xLimits = sourceAx.XLim;
yLimits = sourceAx.YLim;
textAnnotations = repmat(struct( ...
"x", [], ...
"y", [], ...
"text", "", ...
"anchor", "center"), numel(textHandles), 1);
validTextCount = 0;
for textIdx = 1:numel(textHandles)
textHandle = textHandles(textIdx);
labelText = string(textHandle.String);
if strlength(strtrim(labelText)) == 0
continue
end
textPosition = textHandle.Position;
if textPosition(1) < xLimits(1) || textPosition(1) > xLimits(2) || ...
textPosition(2) < yLimits(1) || textPosition(2) > yLimits(2)
continue
end
validTextCount = validTextCount + 1;
textAnnotations(validTextCount).x = textPosition(1);
textAnnotations(validTextCount).y = textPosition(2);
textAnnotations(validTextCount).text = labelText;
textAnnotations(validTextCount).anchor = matlabTextAlignmentToTikzAnchor( ...
textHandle.HorizontalAlignment, textHandle.VerticalAlignment);
end
textAnnotations = textAnnotations(1:validTextCount);
end
function writeTikzPngAxis(tikzFile, pngTikzPath, sourceAx, linePlots, textAnnotations, options)
outputDir = fileparts(tikzFile);
if ~exist(outputDir, "dir")
mkdir(outputDir);
end
xLimits = sourceAx.XLim;
yLimits = sourceAx.YLim;
fid = fopen(tikzFile, "w");
if fid < 0
error("exportLevelScatterTikz:TikzOpenFailed", ...
"Could not open TikZ export file: %s", tikzFile);
end
cleanupFile = onCleanup(@() fclose(fid));
axisOptions = {
" every axis/.append style={font=\scriptsize},"
"width=\fwidth,"
"height=\fheight,"
"at={(0\fwidth,0\fheight)},"
"scale only axis,"
"axis on top,"
"xmin=" + formatPgfNumber(xLimits(1)) + ","
"xmax=" + formatPgfNumber(xLimits(2)) + ","
"xlabel style={font=\color{white!15!black}\small},"
"xlabel={" + options.xLabel + "},"
"ymin=" + formatPgfNumber(yLimits(1)) + ","
"ymax=" + formatPgfNumber(yLimits(2)) + ","
"ylabel style={font=\color{white!15!black}\small},"
"ylabel={" + options.yLabel + "},"
"axis background/.style={fill=white},"
"xmajorgrids,"
"ymajorgrids,"
"grid style={line width=0.4pt, dotted, color=black!20},"
"scaled ticks=false,"
"tick label style={/pgf/number format/fixed, /pgf/number format/1000 sep={}},"
"legend columns=1"
};
fprintf(fid, "%% This file was generated by %s.\n", options.generatedBy);
fprintf(fid, "%%\n");
for lineIdx = 1:numel(linePlots)
fprintf(fid, "%s\n", formatTikzColorDefinition(lineIdx, linePlots(lineIdx).color));
end
if ~isempty(linePlots)
fprintf(fid, "%%\n");
end
fprintf(fid, "%s\n\n", "\begin{tikzpicture}");
fprintf(fid, "%s\n", "\begin{axis}[%");
for optionIdx = 1:numel(axisOptions)
fprintf(fid, "%s\n", axisOptions{optionIdx});
end
fprintf(fid, "%s\n", "]");
graphicsLine = sprintf( ...
"\\addplot [forget plot] graphics [xmin=%s, xmax=%s, ymin=%s, ymax=%s] {%s};", ...
formatPgfNumber(xLimits(1)), ...
formatPgfNumber(xLimits(2)), ...
formatPgfNumber(yLimits(1)), ...
formatPgfNumber(yLimits(2)), ...
char(strrep(pngTikzPath, "\", "/")));
fprintf(fid, "%s\n\n", graphicsLine);
writeTikzLinePlots(fid, linePlots);
writeTikzTextAnnotations(fid, textAnnotations);
fprintf(fid, "%s\n\n", "\end{axis}");
fprintf(fid, "%s", "\end{tikzpicture}%");
end
function valueText = formatPgfNumber(value)
valueText = string(sprintf("%.15g", value));
end
function colorDefinition = formatTikzColorDefinition(colorIdx, rgbColor)
colorDefinition = sprintf( ...
"\\definecolor{mycolor%d}{rgb}{%.5f,%.5f,%.5f}%%", ...
colorIdx, rgbColor(1), rgbColor(2), rgbColor(3));
end
function writeTikzLinePlots(fid, linePlots)
for lineIdx = 1:numel(linePlots)
fprintf(fid, "\\addplot [color=mycolor%d, line width=%.1fpt, forget plot]\n", ...
lineIdx, linePlots(lineIdx).lineWidth);
fprintf(fid, " table[row sep=crcr]{%%\n");
for sampleIdx = 1:numel(linePlots(lineIdx).xData)
fprintf(fid, "%s\t%s\\\\\n", ...
formatPgfNumber(linePlots(lineIdx).xData(sampleIdx)), ...
formatPgfNumber(linePlots(lineIdx).yData(sampleIdx)));
end
fprintf(fid, "};\n\n");
end
end
function writeTikzTextAnnotations(fid, textAnnotations)
for textIdx = 1:numel(textAnnotations)
fprintf(fid, "\\node[font=\\scriptsize, anchor=%s, fill=white, draw=black!40, rounded corners=2pt, inner sep=2pt]\n", ...
textAnnotations(textIdx).anchor);
fprintf(fid, " at (axis cs:%s,%s) {%s};\n\n", ...
formatPgfNumber(textAnnotations(textIdx).x), ...
formatPgfNumber(textAnnotations(textIdx).y), ...
escapeTikzText(textAnnotations(textIdx).text));
end
end
function anchor = matlabTextAlignmentToTikzAnchor(horizontalAlignment, verticalAlignment)
horizontalAlignment = string(horizontalAlignment);
verticalAlignment = string(verticalAlignment);
if horizontalAlignment == "left"
horizontalAnchor = "west";
elseif horizontalAlignment == "right"
horizontalAnchor = "east";
else
horizontalAnchor = "";
end
if verticalAlignment == "top"
verticalAnchor = "north";
elseif verticalAlignment == "bottom"
verticalAnchor = "south";
else
verticalAnchor = "";
end
if strlength(horizontalAnchor) > 0 && strlength(verticalAnchor) > 0
anchor = verticalAnchor + " " + horizontalAnchor;
elseif strlength(horizontalAnchor) > 0
anchor = horizontalAnchor;
elseif strlength(verticalAnchor) > 0
anchor = verticalAnchor;
else
anchor = "center";
end
end
function textOut = escapeTikzText(textIn)
textOut = char(textIn);
% textOut = strrep(textOut, "\", "\textbackslash{}");
textOut = strrep(textOut, "{", "\{");
textOut = strrep(textOut, "}", "\}");
textOut = strrep(textOut, "%", "\%");
textOut = strrep(textOut, "&", "\&");
textOut = strrep(textOut, "#", "\#");
textOut = strrep(textOut, "_", "\_");
% textOut = strrep(textOut, "$", "\$");
end