From 3cafb06c4f77adb2e469a0224e22995e05a7c086 Mon Sep 17 00:00:00 2001 From: Silas Oettinghaus Date: Thu, 9 Jul 2026 08:46:35 +0200 Subject: [PATCH] FFE / MPI algorithm --- Classes/04_DSP/Equalizer/FFE.m | 111 +++++++++++------- Functions/EQ_recipes/mpi_recipe_dev.m | 10 +- .../MPI_revisit/investigate_mpi_algorithms.m | 2 +- 3 files changed, 72 insertions(+), 51 deletions(-) diff --git a/Classes/04_DSP/Equalizer/FFE.m b/Classes/04_DSP/Equalizer/FFE.m index d38c425..f655098 100644 --- a/Classes/04_DSP/Equalizer/FFE.m +++ b/Classes/04_DSP/Equalizer/FFE.m @@ -47,6 +47,7 @@ classdef FFE < handle optmize_mus = 0; mu_optimization mu_optimization_iter = 0; + mu_optimization_len end methods @@ -64,13 +65,14 @@ classdef FFE < handle options.dd_mode = 1; options.mu_dd = 1e-5; options.epochs_dd = 5; - options.dd_len_fraction = 0.25; + options.dd_len_fraction = 1; options.mu_dc = 0; options.decide = false; options.save_debug = 0; options.optmize_mus = 0; + options.mu_optimization_len = 2^15; end @@ -116,10 +118,10 @@ classdef FFE < handle training = 0; showviz = 0; if obj.dd_mode - n_dd = obj.ddLength(n); - obj.equalize(X.signal, D.signal,obj.mu_dd,obj.epochs_dd,n_dd,training,showviz); + [signal,decision] = obj.equalize(X.signal, D.signal,obj.mu_dd,obj.epochs_dd,n,training,showviz); + else + [signal,decision] = obj.equalize(X.signal, D.signal,0,1,n,training,showviz); end - [signal,decision]=obj.applyCurrentTaps(X.signal,n); % Output Signal if obj.decide @@ -175,6 +177,7 @@ classdef FFE < handle for epoch = 1 : epochs symbol = 0; + % obj.e_dc = 0; for sample = 1 : obj.sps : N symbol = symbol+1; @@ -269,17 +272,6 @@ classdef FFE < handle end - function [y,d_hat] = applyCurrentTaps(obj,x,N) - x = [zeros(floor(obj.order/2),1); x; zeros(obj.order,1)]; - for sample = 1 : obj.sps : N - symbol = (sample - 1) / obj.sps + 1; - U = x(obj.order+sample-1:-1:sample); - y(symbol,1) = obj.e_dc + obj.e.' * U; - [~,symbol_idx] = min(abs(y(symbol) - obj.constellation)); - d_hat(symbol,1) = obj.constellation(symbol_idx); - end - end - function N_dd = ddLength(obj,N) if isempty(obj.dd_len_fraction) || obj.dd_len_fraction <= 0 || obj.dd_len_fraction >= 1 N_dd = N; @@ -292,6 +284,8 @@ classdef FFE < handle end function optimizeMus(obj,x,d) + [x_opt,d_opt,N_opt] = obj.optimizationSignals(x,d); + switch obj.adaption_technique case adaption_method.lms mu_range = [1e-5, 1e-2]; @@ -312,7 +306,8 @@ classdef FFE < handle vars = [vars, optimizableVariable("mu_dc",mu_dc_range,"Transform","log")]; end obj.mu_optimization_iter = 0; - obj.mu_optimization = bayesopt(@(p)obj.muObjective(p,x,d),vars, ... + fprintf("FFE mu opt uses %d samples / %d symbols\n",N_opt,numel(d_opt)); + obj.mu_optimization = bayesopt(@(p)obj.muObjective(p,x_opt,d_opt),vars, ... "MaxObjectiveEvaluations",20, ... "AcquisitionFunctionName","expected-improvement-plus", ... "IsObjectiveDeterministic",false, ... @@ -325,58 +320,84 @@ classdef FFE < handle if optimize_mu_dc obj.mu_dc = obj.mu_optimization.XAtMinObjective.mu_dc; end - objective_db = 10*log10(obj.mu_optimization.MinObjective); if obj.dd_mode && optimize_mu_dc - fprintf("\nFFE mu opt done: mu_tr=%9.3e, mu_dd=%9.3e, mu_dc=%9.3e, MSE=%9.3e, MSE_dB=%7.2f dB\n", ... - obj.mu_tr,obj.mu_dd,obj.mu_dc,obj.mu_optimization.MinObjective,objective_db); + fprintf("\nFFE mu opt done: mu_tr=%9.3e, mu_dd=%9.3e, mu_dc=%9.3e, BER=%9.3e\n", ... + obj.mu_tr,obj.mu_dd,obj.mu_dc,obj.mu_optimization.MinObjective); elseif obj.dd_mode - fprintf("\nFFE mu opt done: mu_tr=%9.3e, mu_dd=%9.3e, MSE=%9.3e, MSE_dB=%7.2f dB\n", ... - obj.mu_tr,obj.mu_dd,obj.mu_optimization.MinObjective,objective_db); + fprintf("\nFFE mu opt done: mu_tr=%9.3e, mu_dd=%9.3e, BER=%9.3e\n", ... + obj.mu_tr,obj.mu_dd,obj.mu_optimization.MinObjective); elseif optimize_mu_dc - fprintf("\nFFE mu opt done: mu_tr=%9.3e, mu_dc=%9.3e, MSE=%9.3e, MSE_dB=%7.2f dB\n", ... - obj.mu_tr,obj.mu_dc,obj.mu_optimization.MinObjective,objective_db); + fprintf("\nFFE mu opt done: mu_tr=%9.3e, mu_dc=%9.3e, BER=%9.3e\n", ... + obj.mu_tr,obj.mu_dc,obj.mu_optimization.MinObjective); else - fprintf("\nFFE mu opt done: mu_tr=%9.3e, MSE=%9.3e, MSE_dB=%7.2f dB\n", ... - obj.mu_tr,obj.mu_optimization.MinObjective,objective_db); + fprintf("\nFFE mu opt done: mu_tr=%9.3e, BER=%9.3e\n", ... + obj.mu_tr,obj.mu_optimization.MinObjective); end end - function objective_db = muObjective(obj,params,x,d) + function [x_opt,d_opt,N_opt] = optimizationSignals(obj,x,d) + N_available = min(numel(x),numel(d) * obj.sps); + + if isempty(obj.mu_optimization_len) || obj.mu_optimization_len <= 0 || isinf(obj.mu_optimization_len) + N_opt = N_available; + else + N_opt = min(N_available,max(obj.len_tr,obj.mu_optimization_len)); + end + + N_opt = obj.sps * floor(N_opt / obj.sps); + N_opt = max(obj.sps,N_opt); + + n_symbols = N_opt / obj.sps; + x_opt = x(1:N_opt); + d_opt = d(1:n_symbols); + end + + function objective = muObjective(obj,params,x,d) old_debug = obj.save_debug; old_mu_dc = obj.mu_dc; - obj.save_debug = 1; - if isprop(params,"mu_dc") + obj.save_debug = 0; + has_mu_dc = any(strcmp(params.Properties.VariableNames,"mu_dc")); + if has_mu_dc obj.mu_dc = params.mu_dc; end obj.e = zeros(obj.order,1); obj.e_dc = 0; obj.P = (1/0.05) * eye(obj.order); obj.debug_struct = struct(); - obj.equalize(x,d,params.mu_tr,obj.epochs_tr,obj.len_tr,1,0); + N_tr = min(obj.len_tr,numel(x)); + [signal,~] = obj.equalize(x,d,params.mu_tr,obj.epochs_tr,N_tr,1,0); if obj.dd_mode - obj.equalize(x,d,params.mu_dd,obj.epochs_dd,obj.ddLength(numel(x)),0,0); - objective = mean(obj.debug_struct.error(end,:),"omitnan"); - else - objective = mean(obj.debug_struct.error_tr(end,:),"omitnan"); + [signal,~] = obj.equalize(x,d,params.mu_dd,obj.epochs_dd,numel(x),0,0); end + + M = numel(unique(d)); + mapper = PAMmapper(M,0); + eq_signal_sd = Signal(signal); + eq_signal_hd = mapper.quantize(eq_signal_sd); + tx_symbols = Signal(d); + rx_bits = mapper.demap(eq_signal_hd); + tx_bits = mapper.demap(tx_symbols); + [~,errors,ber,~] = calc_ber(rx_bits.signal,tx_bits.signal, ... + "skip_front",10, ... + "skip_end",10, ... + "returnErrorLocation",1); + objective = ber; if ~isfinite(objective) objective = inf; end - objective_db = 10*log10(objective); obj.mu_optimization_iter = obj.mu_optimization_iter + 1; - optimize_mu_dc = isprop(params,"mu_dc"); - if obj.dd_mode && optimize_mu_dc - fprintf("\rFFE mu opt %02d: mu_tr=%9.3e, mu_dd=%9.3e, mu_dc=%9.3e, MSE=%9.3e, MSE_dB=%7.2f dB", ... - obj.mu_optimization_iter,params.mu_tr,params.mu_dd,params.mu_dc,objective,objective_db); + if obj.dd_mode && has_mu_dc + fprintf("\rFFE mu opt %02d: mu_tr=%9.3e, mu_dd=%9.3e, mu_dc=%9.3e, BER=%9.3e, errors=%d", ... + obj.mu_optimization_iter,params.mu_tr,params.mu_dd,params.mu_dc,ber,errors); elseif obj.dd_mode - fprintf("\rFFE mu opt %02d: mu_tr=%9.3e, mu_dd=%9.3e, MSE=%9.3e, MSE_dB=%7.2f dB", ... - obj.mu_optimization_iter,params.mu_tr,params.mu_dd,objective,objective_db); - elseif optimize_mu_dc - fprintf("\rFFE mu opt %02d: mu_tr=%9.3e, mu_dc=%9.3e, MSE=%9.3e, MSE_dB=%7.2f dB", ... - obj.mu_optimization_iter,params.mu_tr,params.mu_dc,objective,objective_db); + fprintf("\rFFE mu opt %02d: mu_tr=%9.3e, mu_dd=%9.3e, BER=%9.3e, errors=%d", ... + obj.mu_optimization_iter,params.mu_tr,params.mu_dd,ber,errors); + elseif has_mu_dc + fprintf("\rFFE mu opt %02d: mu_tr=%9.3e, mu_dc=%9.3e, BER=%9.3e, errors=%d", ... + obj.mu_optimization_iter,params.mu_tr,params.mu_dc,ber,errors); else - fprintf("\rFFE mu opt %02d: mu_tr=%9.3e, MSE=%9.3e, MSE_dB=%7.2f dB", ... - obj.mu_optimization_iter,params.mu_tr,objective,objective_db); + fprintf("\rFFE mu opt %02d: mu_tr=%9.3e, BER=%9.3e, errors=%d", ... + obj.mu_optimization_iter,params.mu_tr,ber,errors); end obj.save_debug = old_debug; obj.mu_dc = old_mu_dc; diff --git a/Functions/EQ_recipes/mpi_recipe_dev.m b/Functions/EQ_recipes/mpi_recipe_dev.m index 0321960..7babb83 100644 --- a/Functions/EQ_recipes/mpi_recipe_dev.m +++ b/Functions/EQ_recipes/mpi_recipe_dev.m @@ -21,18 +21,18 @@ function output = mpi_recipe_dev(Scpe_sig_raw, Symbols, Tx_bits, options) "debug_plots", options.debug_plots); - mu_dc = 0.005;%1e-5; + mu_dc = 0;%1e-5; eq_settings = { ... "epochs_tr", 5, ... - "epochs_dd", 3, ... + "epochs_dd", 5, ... "len_tr", 4096*2, ... - "mu_dd",3.005e-03, ... - "mu_tr",1.063e-01, ... + "mu_dd",0.02, ... + "mu_tr",0.2, ... "order", 25, ... "sps", 2, ... "decide", 0, ... - "optmize_mus", 0, ... + "optmize_mus", 1, ... "dd_mode", 1, ... "adaption_technique", "nlms", ... "mu_dc", mu_dc}; diff --git a/projects/Diss/MPI_revisit/investigate_mpi_algorithms.m b/projects/Diss/MPI_revisit/investigate_mpi_algorithms.m index ca17bf2..31f45e4 100644 --- a/projects/Diss/MPI_revisit/investigate_mpi_algorithms.m +++ b/projects/Diss/MPI_revisit/investigate_mpi_algorithms.m @@ -5,7 +5,7 @@ dsp_options.recipe = @mpi_recipe_dev; dsp_options.append_to_db = false; dsp_options.start_occurence = 1; dsp_options.max_occurences = 10; -dsp_options.debug_plots = false; +dsp_options.debug_plots = true; dsp_options.database_type = "mysql";