397 lines
13 KiB
Matlab
397 lines
13 KiB
Matlab
function output = mpi_recipe_dev(Scpe_sig_raw, Symbols, Tx_bits, options)
|
|
%mpi_recipe_dev Minimal MPI equalizer comparison recipe.
|
|
|
|
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
|
|
|
|
%% Execution toggles
|
|
|
|
run_conventional_ffe = 1;
|
|
run_ma = 0;
|
|
run_hpf = 0;
|
|
run_a2_tracked_levels = 1;
|
|
run_a2_residual = 1;
|
|
run_a1 = 1;
|
|
run_tracking_adaptive = 1;
|
|
plot_output_signals = 0;
|
|
|
|
%% Shared fixed EQ settings
|
|
eq_sps = 2;
|
|
eq_order = 50;
|
|
eq_adaption = "nlms";
|
|
eq_len_tr = 4096;
|
|
eq_epochs_tr = 5;
|
|
eq_mu_tr = 0.04;
|
|
eq_epochs_dd = 3;
|
|
eq_save_debug = false;
|
|
|
|
block_update = 1;
|
|
if isfield(options.userParameters,"block_update")
|
|
block_update = options.userParameters.block_update;
|
|
end
|
|
|
|
Scpe_sig = preprocessSignal(Scpe_sig_raw, Symbols, options.fsym, ...
|
|
"mode", "auto", ...
|
|
"debug_plots", options.debug_plots);
|
|
output = struct();
|
|
|
|
%%
|
|
if plot_output_signals
|
|
showLevelScatter(Scpe_sig, Symbols, ...
|
|
"fsym", options.fsym, ...
|
|
"fignum", 400, ...
|
|
"normalize", true);
|
|
end
|
|
|
|
%% Conventional FFE
|
|
if run_conventional_ffe
|
|
eq_ffe = FFE_plain( ...
|
|
"sps", eq_sps, ...
|
|
"order", eq_order, ...
|
|
"decide", false, ...
|
|
"adaption_technique", eq_adaption, ...
|
|
"len_tr", eq_len_tr, ...
|
|
"epochs_tr", eq_epochs_tr, ...
|
|
"mu_tr", eq_mu_tr, ...
|
|
"dd_mode", true, ...
|
|
"epochs_dd", eq_epochs_dd, ...
|
|
"mu_dd", 0.0012, ...
|
|
"optmize_mus", false, ...
|
|
"plot_mu_optimization", options.debug_plots, ...
|
|
"save_debug", eq_save_debug);
|
|
|
|
storageName = "conventional_ffe";
|
|
[ffe_results,equalized_signal] = runFfe(eq_ffe, "Conventional FFE", ...
|
|
Scpe_sig, Symbols, Tx_bits, options);
|
|
ffe_results = attachMpiReductionConfig(ffe_results, eq_ffe, storageName, ...
|
|
"plain_ffe", "baseline", block_update);
|
|
output.(char(storageName)) = ffe_results;
|
|
|
|
eq_noise_ffe = equalized_signal - Symbols;
|
|
|
|
|
|
if plot_output_signals
|
|
plotEqSignals(equalized_signal,Symbols,options,400,-1);
|
|
end
|
|
end
|
|
|
|
|
|
%% Moving Average Filter -> Conventional FFE
|
|
if run_ma
|
|
eq_ffe = FFE_plain( ...
|
|
"sps", eq_sps, ...
|
|
"order", eq_order, ...
|
|
"decide", false, ...
|
|
"adaption_technique", eq_adaption, ...
|
|
"len_tr", eq_len_tr, ...
|
|
"epochs_tr", eq_epochs_tr, ...
|
|
"mu_tr", eq_mu_tr, ...
|
|
"dd_mode", true, ...
|
|
"epochs_dd", eq_epochs_dd, ...
|
|
"mu_dd", 0.0012, ...
|
|
"optmize_mus", false, ...
|
|
"plot_mu_optimization", options.debug_plots, ...
|
|
"save_debug", eq_save_debug);
|
|
|
|
%%% APPLY MA filter
|
|
movavg_window_length = options.userParameters.bufferlen;
|
|
movavg_window_symmetry = "causal"; % "causal" or "noncausal"
|
|
|
|
switch movavg_window_symmetry
|
|
case "causal"
|
|
dc_estimate = movmean(Scpe_sig.signal, ...
|
|
[movavg_window_length-1,0],"Endpoints","shrink");
|
|
case "noncausal"
|
|
dc_estimate = movmean(Scpe_sig.signal, ...
|
|
movavg_window_length,"Endpoints","shrink");
|
|
otherwise
|
|
error("mpi_recipe_dev:InvalidMovAvgSymmetry", ...
|
|
"movavg_window_symmetry must be 'causal' or 'noncausal'.");
|
|
end
|
|
|
|
Scpe_sig_filt = Scpe_sig;
|
|
Scpe_sig_filt.signal = Scpe_sig.signal - dc_estimate;
|
|
clear dc_estimate;
|
|
|
|
storageName = "MovAvg_plus_conventional_FFE";
|
|
[ffe_results,equalized_signal] = runFfe(eq_ffe, "Moving-average + conventional FFE", ...
|
|
Scpe_sig_filt, Symbols, Tx_bits, options);
|
|
clear Scpe_sig_filt;
|
|
ffe_results = attachMpiReductionConfig(ffe_results, eq_ffe, storageName, ...
|
|
"MovAvg_plus_conventional_FFE", char(movavg_window_symmetry), block_update);
|
|
output.(char(storageName)) = ffe_results;
|
|
|
|
if plot_output_signals
|
|
plotEqSignals(equalized_signal,Symbols,options,400,-1);
|
|
end
|
|
end
|
|
|
|
|
|
|
|
%% High Pass Filter -> Conventional FFE
|
|
if run_hpf
|
|
eq_ffe = FFE_plain( ...
|
|
"sps", eq_sps, ...
|
|
"order", eq_order, ...
|
|
"decide", false, ...
|
|
"adaption_technique", eq_adaption, ...
|
|
"len_tr", eq_len_tr, ...
|
|
"epochs_tr", eq_epochs_tr, ...
|
|
"mu_tr", eq_mu_tr, ...
|
|
"dd_mode", true, ...
|
|
"epochs_dd", eq_epochs_dd, ...
|
|
"mu_dd", 0.0012, ...
|
|
"optmize_mus", false, ...
|
|
"plot_mu_optimization", options.debug_plots, ...
|
|
"save_debug", eq_save_debug);
|
|
|
|
%%% APPLY HPF in MHZ order
|
|
f = Filter("f_cutoff",options.userParameters.hpf,"filterType","butterworth","lowpass",0,"filtdegree",4,"fs",options.fsym*2);
|
|
Scpe_sig_filt = f.process(Scpe_sig);
|
|
|
|
storageName = "HPF_plus_conventional_FFE";
|
|
[ffe_results,equalized_signal] = runFfe(eq_ffe, "Conventional FFE", ...
|
|
Scpe_sig_filt, Symbols, Tx_bits, options);
|
|
clear Scpe_sig_filt;
|
|
ffe_results = attachMpiReductionConfig(ffe_results, eq_ffe, storageName, ...
|
|
"HPF_plus_conventional_FFE", "hpf", block_update);
|
|
output.(char(storageName)) = ffe_results;
|
|
|
|
if plot_output_signals
|
|
plotEqSignals(equalized_signal,Symbols,options,400,-1);
|
|
end
|
|
end
|
|
|
|
|
|
|
|
%% A2 tracked-level decision
|
|
if run_a2_tracked_levels
|
|
eq_ffe = FFE_A2TrackedLevels( ...
|
|
"sps", eq_sps, ...
|
|
"order", eq_order, ...
|
|
"decide", true, ...
|
|
"adaption_technique", eq_adaption, ...
|
|
"len_tr", eq_len_tr, ...
|
|
"epochs_tr", eq_epochs_tr, ...
|
|
"mu_tr", eq_mu_tr, ...
|
|
"dd_mode", true, ...
|
|
"epochs_dd", eq_epochs_dd, ...
|
|
"mu_dd", 0.012, ...
|
|
"dc_smoothing_a2", 1, ...
|
|
"dc_level_avg_bufferlength_a2", 112, ... %war 112
|
|
"dc_level_update_blocklength_a2", block_update, ... % war block_update
|
|
"dc_level_weights_a2", [1], ...
|
|
"save_debug", eq_save_debug);
|
|
|
|
storageName = "a2_adaptive_levels";
|
|
[ffe_results,equalized_signal] = runFfe(eq_ffe, "A2 tracked levels", ...
|
|
Scpe_sig, Symbols, Tx_bits, options);
|
|
ffe_results = attachMpiReductionConfig(ffe_results, eq_ffe, storageName, ...
|
|
"a2_tracked_levels", "tracked_levels", block_update);
|
|
output.(char(storageName)) = ffe_results;
|
|
|
|
if plot_output_signals
|
|
plotEqSignals(equalized_signal,Symbols,options,410,-1);
|
|
end
|
|
end
|
|
|
|
%% A2 residual correction
|
|
if run_a2_residual
|
|
eq_ffe = FFE_A2Residual( ...
|
|
"sps", eq_sps, ...
|
|
"order", eq_order, ...
|
|
"decide", false, ...
|
|
"adaption_technique", eq_adaption, ...
|
|
"len_tr", eq_len_tr, ...
|
|
"epochs_tr", eq_epochs_tr, ...
|
|
"mu_tr", eq_mu_tr, ...
|
|
"dd_mode", true, ...
|
|
"epochs_dd", eq_epochs_dd, ...
|
|
"mu_dd", 0.012, ...
|
|
"dc_smoothing_a2", 1, ...
|
|
"dc_level_avg_bufferlength_a2", 112, ...
|
|
"dc_level_update_blocklength_a2", block_update, ...
|
|
"dc_level_weights_a2", [0.6], ...
|
|
"save_debug", eq_save_debug, "optmize_mus",0);
|
|
|
|
storageName = "a2_residual";
|
|
[ffe_results,equalized_signal] = runFfe(eq_ffe, "A2 residual", ...
|
|
Scpe_sig, Symbols, Tx_bits, options);
|
|
ffe_results = attachMpiReductionConfig(ffe_results, eq_ffe, storageName, ...
|
|
"a2_residual", "residual_correction", block_update);
|
|
output.(char(storageName)) = ffe_results;
|
|
|
|
if plot_output_signals
|
|
plotEqSignals(equalized_signal,Symbols,options,420,-1);
|
|
end
|
|
end
|
|
|
|
%% A1 moving-average input suppression
|
|
if run_a1
|
|
eq_ffe = FFE_A1( ...
|
|
"sps", eq_sps, ...
|
|
"order", eq_order, ...
|
|
"decide", false, ...
|
|
"adaption_technique", eq_adaption, ...
|
|
"len_tr", eq_len_tr, ...
|
|
"epochs_tr", eq_epochs_tr, ...
|
|
"mu_tr", eq_mu_tr, ...
|
|
"dd_mode", false, ...
|
|
"epochs_dd", eq_epochs_dd, ...
|
|
"mu_dd", 0.012, ...
|
|
"dc_smoothing_a1", 1, ...
|
|
"dc_avg_bufferlength_a1", 2048, ... %was 2048
|
|
"dc_avg_update_blocklength_a1", block_update, ...
|
|
"save_debug", eq_save_debug);
|
|
|
|
storageName = "a1_ff_dc_avg";
|
|
[ffe_results,equalized_signal] = runFfe(eq_ffe, "A1", ...
|
|
Scpe_sig, Symbols, Tx_bits, options);
|
|
ffe_results = attachMpiReductionConfig(ffe_results, eq_ffe, storageName, ...
|
|
"a1_moving_average", "ff_dc_avg", block_update);
|
|
output.(char(storageName)) = ffe_results;
|
|
|
|
if plot_output_signals
|
|
plotEqSignals(equalized_signal,Symbols,options,430,-1);
|
|
end
|
|
end
|
|
|
|
%% DC tracking, adaptive/persistence path
|
|
if run_tracking_adaptive
|
|
eq_ffe = FFE_DCTracking( ...
|
|
"sps", eq_sps, ...
|
|
"order", eq_order, ...
|
|
"decide", false, ...
|
|
"adaption_technique", eq_adaption, ...
|
|
"len_tr", eq_len_tr, ...
|
|
"epochs_tr", eq_epochs_tr, ...
|
|
"mu_tr", eq_mu_tr, ...
|
|
"dd_mode", true, ...
|
|
"epochs_dd", eq_epochs_dd, ...
|
|
"mu_dd", 0.012, ...
|
|
"dc_tracking_mu", 0.002, ...
|
|
"dc_tracking_adaptive_enabled", true, ...
|
|
"dc_tracking_persistence_gain", 0, ...
|
|
"dc_tracking_buffer_len", block_update, ...
|
|
"optmize_mus", false, ...
|
|
"optimize_dc_tracking_params", true, ...
|
|
"dc_tracking_optimization_len", 2^15, ...
|
|
"dc_tracking_optimization_max_evals", 30, ...
|
|
"plot_mu_optimization", options.debug_plots, ...
|
|
"save_debug", eq_save_debug);
|
|
|
|
storageName = "dc_tracking";
|
|
[ffe_results,equalized_signal] = runFfe(eq_ffe, "DC tracking adaptive", ...
|
|
Scpe_sig, Symbols, Tx_bits, options);
|
|
ffe_results = attachMpiReductionConfig(ffe_results, eq_ffe, storageName, ...
|
|
"dc_tracking", "adaptive", block_update);
|
|
output.(char(storageName)) = ffe_results;
|
|
|
|
% fignum = 106;
|
|
%
|
|
% eq_noise = equalized_signal - Symbols;
|
|
% dn = sprintf("FFE DCT; SIR: %d dB",options.dataTable.sir);
|
|
% showEQNoisePSD(eq_noise, "fignum", fignum, "displayname", dn,"colormode","diverging");
|
|
% ylim([-70 -30]);
|
|
%
|
|
% dn = sprintf("FFE only; SIR: %d dB",options.dataTable.sir);
|
|
% showEQNoisePSD(eq_noise_ffe, "fignum", fignum+1, "displayname", dn,"colormode","diverging");
|
|
% ylim([-70 -30]);
|
|
|
|
if plot_output_signals
|
|
|
|
plotEqSignals(equalized_signal,Symbols,options,450,-1);
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
function [ffe_results,equalized_signal] = runFfe(eq_ffe,description,Scpe_sig,Symbols,Tx_bits,options)
|
|
[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",resultDescription(description,options));
|
|
end
|
|
|
|
function ffe_results = attachMpiReductionConfig(ffe_results, eq_ffe, storageName, ...
|
|
algorithm, algorithmVariant, block_update)
|
|
ffe_results.mpi_reduction_config = struct( ...
|
|
"storage_name", char(storageName), ...
|
|
"algorithm", char(algorithm), ...
|
|
"algorithm_variant", char(algorithmVariant), ...
|
|
"eq_class", class(eq_ffe), ...
|
|
"params", collectMpiReductionParams(eq_ffe, block_update));
|
|
end
|
|
|
|
function params = collectMpiReductionParams(eq_ffe, block_update)
|
|
params = struct();
|
|
params.block_update = block_update;
|
|
|
|
whitelistedProps = [ ...
|
|
"sps", ...
|
|
"order", ...
|
|
"decide", ...
|
|
"adaption_technique", ...
|
|
"len_tr", ...
|
|
"epochs_tr", ...
|
|
"mu_tr", ...
|
|
"dd_mode", ...
|
|
"epochs_dd", ...
|
|
"mu_dd", ...
|
|
"optmize_mus", ...
|
|
"plot_mu_optimization", ...
|
|
"save_debug", ...
|
|
"dc_smoothing_a1", ...
|
|
"dc_avg_bufferlength_a1", ...
|
|
"dc_avg_update_blocklength_a1", ...
|
|
"dc_smoothing_a2", ...
|
|
"dc_level_avg_bufferlength_a2", ...
|
|
"dc_level_update_blocklength_a2", ...
|
|
"dc_level_weights_a2", ...
|
|
"dc_tracking_mu", ...
|
|
"dc_tracking_adaptive_enabled", ...
|
|
"dc_tracking_persistence_gain", ...
|
|
"dc_tracking_buffer_len", ...
|
|
"dc_tracking_mu_eff_max", ...
|
|
"optimize_dc_tracking_params", ...
|
|
"dc_tracking_optimization_len", ...
|
|
"dc_tracking_optimization_max_evals", ...
|
|
"dc_tracking_optimization_delay_weight", ...
|
|
"dc_tracking_optimization_smoothing_len"];
|
|
|
|
for propIdx = 1:numel(whitelistedProps)
|
|
propName = char(whitelistedProps(propIdx));
|
|
if isprop(eq_ffe, propName)
|
|
params.(propName) = eq_ffe.(propName);
|
|
end
|
|
end
|
|
end
|
|
|
|
function description = resultDescription(prefix,options)
|
|
sir = options.dataTable.sir;
|
|
if numel(sir) > 1
|
|
sir = sir(1);
|
|
end
|
|
description = sprintf('%s; SIR %g dB',prefix,sir);
|
|
end
|
|
|
|
function plotEqSignals(equalized_signal,Symbols,options,fignum,output_scale)
|
|
|
|
showLevelScatter(equalized_signal .* output_scale, Symbols, ...
|
|
"fsym", options.fsym, ...
|
|
"fignum", fignum + 1, ...
|
|
"normalize", true);
|
|
end
|