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 = 0; run_a2_residual = 0; run_a1 = 0; run_tracking_adaptive = 1; plot_output_signals = 1; %% 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", false, ... "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