FFE / MPI algorithm

This commit is contained in:
Silas Oettinghaus
2026-07-09 08:46:35 +02:00
parent 1879441999
commit 3cafb06c4f
3 changed files with 72 additions and 51 deletions

View File

@@ -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;

View File

@@ -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};

View File

@@ -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";