auswertungsfiles und algos for ECOC 2025 rush...
This commit is contained in:
@@ -141,7 +141,7 @@ classdef Signal
|
||||
|
||||
arguments
|
||||
obj
|
||||
options.fignum
|
||||
options.fignum = []
|
||||
options.displayname = [];
|
||||
options.timeframe = 0;
|
||||
options.clear = 0;
|
||||
|
||||
@@ -57,6 +57,8 @@ classdef FFE_DCremoval < handle
|
||||
obj.e = zeros(obj.order,1);
|
||||
obj.error = 0;
|
||||
|
||||
obj.dc_buffer_len = floor(obj.dc_buffer_len);
|
||||
|
||||
end
|
||||
|
||||
function [X,Noi] = process(obj, X, D)
|
||||
@@ -155,16 +157,15 @@ classdef FFE_DCremoval < handle
|
||||
end
|
||||
end
|
||||
|
||||
if ~training
|
||||
figure(1122)
|
||||
hold on
|
||||
scatter(1:numel(e_dc_save),e_dc_save,1,'.');
|
||||
scatter(1:numel(y),y,1,'.');
|
||||
|
||||
end
|
||||
% if ~training
|
||||
% figure(1122)
|
||||
% hold on
|
||||
% scatter(1:numel(e_dc_save),e_dc_save,1,'.');
|
||||
% % scatter(1:numel(y),y,1,'.');
|
||||
%
|
||||
% end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
272
Classes/04_DSP/Equalizer/FFE_DCremoval_adaptive_mu.m
Normal file
272
Classes/04_DSP/Equalizer/FFE_DCremoval_adaptive_mu.m
Normal file
@@ -0,0 +1,272 @@
|
||||
classdef FFE_DCremoval_adaptive_mu < handle
|
||||
% Implementation of plain and simple FFE.
|
||||
% 1) Training mode (stable performance when you use NLMS)
|
||||
% 2) Decision directed mode
|
||||
|
||||
% Eq = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",25,"sps",2,"decide",0);
|
||||
|
||||
properties
|
||||
sps % usually 2
|
||||
order
|
||||
e
|
||||
error
|
||||
|
||||
len_tr
|
||||
mu_tr
|
||||
epochs_tr
|
||||
|
||||
mu_dd
|
||||
epochs_dd
|
||||
|
||||
mu_dc
|
||||
dc_buffer_len
|
||||
|
||||
ffe_buffer_len
|
||||
|
||||
smoothing_buffer_length
|
||||
smoothing_buffer_update
|
||||
|
||||
constellation
|
||||
|
||||
decide
|
||||
end
|
||||
|
||||
methods
|
||||
function obj = FFE_DCremoval_adaptive_mu(options)
|
||||
arguments(Input)
|
||||
|
||||
options.sps = 2;
|
||||
options.order = 15;
|
||||
|
||||
options.len_tr = 4096;
|
||||
options.mu_tr = 0;
|
||||
options.epochs_tr = 5;
|
||||
|
||||
options.mu_dd = 1e-5;
|
||||
options.epochs_dd = 5;
|
||||
|
||||
options.mu_dc = 0.05;
|
||||
options.dc_buffer_len = 1;
|
||||
|
||||
options.ffe_buffer_len = 1;
|
||||
|
||||
options.smoothing_buffer_length = 0;
|
||||
options.smoothing_buffer_update = 0;
|
||||
options.decide = false;
|
||||
|
||||
end
|
||||
|
||||
assert(options.dc_buffer_len>0);
|
||||
|
||||
fn = fieldnames(options);
|
||||
for n = 1:numel(fn)
|
||||
obj.(fn{n}) = options.(fn{n});
|
||||
end
|
||||
|
||||
obj.e = zeros(obj.order,1);
|
||||
obj.error = 0;
|
||||
|
||||
obj.dc_buffer_len = floor(obj.dc_buffer_len);
|
||||
|
||||
end
|
||||
|
||||
function [X,Noi] = process(obj, X, D)
|
||||
|
||||
% actual processing of the signal (steps 1. - 3.)
|
||||
% 1 normalize RMS
|
||||
X = X.normalize("mode","rms");
|
||||
|
||||
obj.constellation = unique(D.signal);
|
||||
|
||||
% if obj.smoothing_buffer_length > 0
|
||||
% % Apply A1 filter smoothing
|
||||
% % Calculate the moving sum with the window size N1
|
||||
% moving_sum = movsum(X.signal, [obj.smoothing_buffer_length,0]);
|
||||
%
|
||||
% % Initialize the output smoothed signal
|
||||
% X.signal = X.signal - (1 / obj.smoothing_buffer_length) * moving_sum;
|
||||
% end
|
||||
|
||||
% Training Mode
|
||||
training = 1;
|
||||
obj.equalize(X.signal, D.signal,obj.mu_tr,obj.epochs_tr,obj.len_tr,training);
|
||||
|
||||
% Decision Directed Mode
|
||||
N = X.length;
|
||||
training = 0;
|
||||
[signal,decision]=obj.equalize(X.signal, D.signal,obj.mu_dd,obj.epochs_dd,N,training);
|
||||
|
||||
% Output Signal
|
||||
if obj.decide
|
||||
X.signal = decision;
|
||||
else
|
||||
X.signal = signal;
|
||||
end
|
||||
X.fs = D.fs; %change sampling frequency of outgoing signal from fdac e.g. 2 sps to symbol spaced = fsym
|
||||
lbdesc = [num2str(obj.order),' tap FFE'];
|
||||
X = X.logbookentry(lbdesc); % append to logbook
|
||||
|
||||
Noi = X - D;
|
||||
|
||||
end
|
||||
|
||||
function [y,d_hat] = equalize(obj, x, d, mu_lms, epochs, N, training)
|
||||
% Equalize with adaptive DC-removal, VSS, and parallel-buffered DC updates
|
||||
% Added: FFE gradient buffering in DD mode (error buffer) with update every obj.dc_buffer_len symbols
|
||||
|
||||
arguments
|
||||
obj
|
||||
x
|
||||
d
|
||||
mu_lms % LMS step-size (or 0 for NLMS)
|
||||
epochs % number of training/DD epochs
|
||||
N % number of samples to process
|
||||
training % boolean flag: true->training mode, false->DD mode
|
||||
end
|
||||
|
||||
% Zero-padding for filter memory
|
||||
x = [zeros(floor(obj.order/2),1); x; zeros(obj.order,1)];
|
||||
|
||||
% Initialize storage
|
||||
numSymbols = ceil(N/obj.sps);
|
||||
y = zeros(numSymbols,1);
|
||||
d_hat = zeros(numSymbols,1);
|
||||
err = NaN(numSymbols,numel(obj.constellation));
|
||||
e_dc_save= zeros(numSymbols,1);
|
||||
|
||||
% DC-adaptation parameters
|
||||
P_err = 0; % running error power
|
||||
alpha = 0.98; % forgetting factor for error power
|
||||
err_prev = 0; % previous error sample for VSS correlation
|
||||
gamma_dc = 1e-6; % meta step-size for DC VSS
|
||||
mu_min = 1e-6; % lower bound for mu_dc
|
||||
mu_max = 1e-1; % upper bound for mu_dc
|
||||
|
||||
% DC removal buffer
|
||||
L = obj.dc_buffer_len; % buffer length
|
||||
e_dc_buf = NaN(L,1);
|
||||
e_dc_est = 0;
|
||||
|
||||
% FFE gradient buffer (DD mode only)
|
||||
L_grad = obj.ffe_buffer_len; % buffer length
|
||||
if ~training
|
||||
% each column holds one past gradient of length obj.order
|
||||
grad_buf = NaN(obj.order, L_grad);
|
||||
|
||||
end
|
||||
|
||||
smth_buffer = zeros(1, obj.smoothing_buffer_length);
|
||||
smth_mean = 0;
|
||||
% Main loop
|
||||
for epoch = 1:epochs
|
||||
s = 0;
|
||||
for sample = 1:obj.sps:N
|
||||
s = s + 1;
|
||||
|
||||
if obj.smoothing_buffer_length > 0
|
||||
smth_buffer = circshift(smth_buffer,1,2);
|
||||
smth_buffer(1) = x(sample);
|
||||
if mod(s, obj.smoothing_buffer_update) == 0
|
||||
smth_mean = mean(smth_buffer);
|
||||
end
|
||||
x(sample:sample+obj.sps-1) = x(sample:sample+obj.sps-1)-smth_mean;
|
||||
end
|
||||
|
||||
U = x(obj.order+sample-1:-1:sample);
|
||||
|
||||
%-- 1) filter output with DC correction
|
||||
y(s) = e_dc_est + obj.e.'*U;
|
||||
|
||||
%-- 2) decision
|
||||
if training
|
||||
[~, idx] = min(abs(d(s) - obj.constellation));
|
||||
else
|
||||
[~, idx] = min(abs(y(s) - obj.constellation));
|
||||
end
|
||||
d_hat(s) = obj.constellation(idx);
|
||||
|
||||
%-- 3) error
|
||||
e_val = y(s) - d_hat(s);
|
||||
err(s,idx) = e_val;
|
||||
|
||||
%-- 4) tap-weight update: training immediate, DD buffered
|
||||
if training
|
||||
% immediate update (LMS or NLMS)
|
||||
if mu_lms ~= 0
|
||||
obj.e = obj.e - mu_lms * e_val * U;
|
||||
else
|
||||
normU = (U.'*U) + eps;
|
||||
obj.e = obj.e - e_val * U / normU;
|
||||
end
|
||||
else
|
||||
if 1
|
||||
% buffer gradient
|
||||
if mu_lms ~= 0
|
||||
grad = e_val * U;
|
||||
else
|
||||
normU = (U.'*U) + eps;
|
||||
grad = e_val * U / normU;
|
||||
end
|
||||
% shift and insert
|
||||
grad_buf = circshift(grad_buf, 1, 2);
|
||||
grad_buf(:,1) = grad;
|
||||
% update once every L symbols
|
||||
if mod(s, L_grad) == 0
|
||||
avg_grad = mean(grad_buf, 2, 'omitnan');
|
||||
if mu_lms ~= 0
|
||||
obj.e = obj.e - mu_lms * avg_grad;
|
||||
else
|
||||
obj.e = obj.e - avg_grad;
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
%-- 5) DC adaptation
|
||||
if obj.mu_dc ~= 0
|
||||
|
||||
% VSS for mu_dc
|
||||
delta_mu = gamma_dc * e_val * err_prev * (U.'*U);
|
||||
obj.mu_dc = min(max(obj.mu_dc + delta_mu, mu_min), mu_max);
|
||||
err_prev = e_val;
|
||||
|
||||
% DC buffer update & periodic estimate
|
||||
P_err = alpha*P_err + (1-alpha)*e_val^2;
|
||||
mu_dc_norm = obj.mu_dc / (P_err + eps);
|
||||
e_dc_buf = circshift(e_dc_buf, 1);
|
||||
e_dc_buf(1) = e_dc_est - mu_dc_norm * e_val;
|
||||
|
||||
if mod(s, L) == 0
|
||||
e_dc_est = median(e_dc_buf, 'omitnan');
|
||||
end
|
||||
|
||||
e_dc_save(s) = e_dc_est;
|
||||
end
|
||||
|
||||
% store instantaneous squared error
|
||||
obj.error(epoch, s) = e_val^2;
|
||||
end
|
||||
end
|
||||
|
||||
% Optional plotting in DD mode (uncomment if needed)
|
||||
if ~training
|
||||
figure(342);clf
|
||||
hold on
|
||||
scatter(1:numSymbols, err + obj.constellation', '.', 'SizeData', 1);
|
||||
|
||||
yline(obj.constellation);
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function mu = update_mu()
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
240
Classes/04_DSP/Equalizer/FFE_DCremoval_level.m
Normal file
240
Classes/04_DSP/Equalizer/FFE_DCremoval_level.m
Normal file
@@ -0,0 +1,240 @@
|
||||
classdef FFE_DCremoval_level < handle
|
||||
% Implementation of plain and simple FFE.
|
||||
% 1) Training mode (stable performance when you use NLMS)
|
||||
% 2) Decision directed mode
|
||||
|
||||
% Eq = FFE("epochs_tr",5,"epochs_dd",5,"len_tr",4096*2,"mu_dd",1e-4,"mu_tr",0,"order",25,"sps",2,"decide",0);
|
||||
|
||||
properties
|
||||
sps % usually 2
|
||||
order
|
||||
e
|
||||
error
|
||||
|
||||
len_tr
|
||||
mu_tr
|
||||
epochs_tr
|
||||
|
||||
mu_dd
|
||||
epochs_dd
|
||||
|
||||
mu_dc
|
||||
dc_buffer_len
|
||||
|
||||
constellation
|
||||
|
||||
decide
|
||||
|
||||
KF_meas_noise = 0;
|
||||
KF_process_noise = 0;
|
||||
KF_state_cov = 0;
|
||||
end
|
||||
|
||||
methods
|
||||
function obj = FFE_DCremoval_level(options)
|
||||
arguments(Input)
|
||||
|
||||
options.sps = 2;
|
||||
options.order = 15;
|
||||
|
||||
options.len_tr = 4096;
|
||||
options.mu_tr = 0;
|
||||
options.epochs_tr = 5;
|
||||
|
||||
options.mu_dd = 1e-5;
|
||||
options.epochs_dd = 5;
|
||||
|
||||
options.mu_dc = 0.05;
|
||||
options.dc_buffer_len = 1;
|
||||
|
||||
options.decide = false;
|
||||
|
||||
end
|
||||
|
||||
assert(options.dc_buffer_len>0);
|
||||
|
||||
fn = fieldnames(options);
|
||||
for n = 1:numel(fn)
|
||||
obj.(fn{n}) = options.(fn{n});
|
||||
end
|
||||
|
||||
obj.e = zeros(obj.order,1);
|
||||
obj.error = 0;
|
||||
|
||||
obj.dc_buffer_len = floor(obj.dc_buffer_len);
|
||||
|
||||
end
|
||||
|
||||
function [X,Noi] = process(obj, X, D)
|
||||
|
||||
% actual processing of the signal (steps 1. - 3.)
|
||||
% 1 normalize RMS
|
||||
X = X.normalize("mode","rms");
|
||||
|
||||
obj.constellation = unique(D.signal);
|
||||
|
||||
% Training Mode
|
||||
training = 1;
|
||||
obj.equalize(X.signal, D.signal,obj.mu_tr,obj.epochs_tr,obj.len_tr,training);
|
||||
|
||||
% Decision Directed Mode
|
||||
N = X.length;
|
||||
training = 0;
|
||||
[signal,decision]=obj.equalize(X.signal, D.signal,obj.mu_dd,obj.epochs_dd,N,training);
|
||||
|
||||
% Output Signal
|
||||
if obj.decide
|
||||
X.signal = decision;
|
||||
else
|
||||
X.signal = signal;
|
||||
end
|
||||
X.fs = D.fs; %change sampling frequency of outgoing signal from fdac e.g. 2 sps to symbol spaced = fsym
|
||||
lbdesc = [num2str(obj.order),' tap FFE'];
|
||||
X = X.logbookentry(lbdesc); % append to logbook
|
||||
|
||||
Noi = X - D;
|
||||
|
||||
end
|
||||
function [y, d_hat, logs] = equalize(obj, x, d, mu_lms, epochs, N, training)
|
||||
% Equalize with Kalman-based DC removal; training epochs estimate KF noise parameters
|
||||
|
||||
arguments
|
||||
obj
|
||||
x
|
||||
d
|
||||
mu_lms % LMS step-size (or 0 for NLMS)
|
||||
epochs % number of training or DD epochs
|
||||
N % number of samples to process
|
||||
training % true => training mode (tap-training + noise estimation)
|
||||
end
|
||||
|
||||
% Zero-pad for filter memory
|
||||
x = [zeros(floor(obj.order/2),1); x; zeros(obj.order,1)];
|
||||
numSym = ceil(N/obj.sps);
|
||||
|
||||
% Pre-allocate outputs
|
||||
y = zeros(numSym,1);
|
||||
d_hat = zeros(numSym,1);
|
||||
|
||||
% --- Training: estimate noise stats and train taps ---
|
||||
if training
|
||||
% Pre-allocate error accumulator
|
||||
totalTrain = epochs * numSym;
|
||||
trainErrs = zeros(totalTrain,1);
|
||||
te_idx = 0;
|
||||
|
||||
for ep = 1:epochs
|
||||
s = 0;
|
||||
for n = 1:obj.sps:N
|
||||
s = s + 1;
|
||||
U = x(obj.order + n - 1 : -1 : n);
|
||||
|
||||
% Equalizer output (no DC correction yet)
|
||||
y(s) = obj.e.' * U;
|
||||
|
||||
% Decision based on known symbol
|
||||
[~, idx] = min(abs(d(s) - obj.constellation));
|
||||
d_hat(s) = obj.constellation(idx);
|
||||
|
||||
% Instantaneous error
|
||||
e_n = y(s) - d_hat(s);
|
||||
|
||||
% Collect error for noise estimation
|
||||
te_idx = te_idx + 1;
|
||||
trainErrs(te_idx) = e_n;
|
||||
|
||||
% Tap-weight update (LMS or NLMS)
|
||||
if mu_lms ~= 0
|
||||
obj.e = obj.e - mu_lms * e_n * U;
|
||||
else
|
||||
normU = (U.'*U) + eps;
|
||||
obj.e = obj.e - e_n * U / normU;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
% Estimate measurement noise R and process noise Q
|
||||
R_est = var(trainErrs(1:te_idx));
|
||||
Q_est = 1e-3 * R_est; % Q/R ratio = 1e-3 (tune as needed)
|
||||
|
||||
% Store into object for DD pass
|
||||
obj.KF_meas_noise = R_est;
|
||||
obj.KF_process_noise = Q_est;
|
||||
obj.KF_state_cov = 5*R_est; % or 5*R_est for a more “eager” start
|
||||
|
||||
% No Kalman in training; return
|
||||
logs = struct();
|
||||
return;
|
||||
end
|
||||
|
||||
% --- Decision-Directed with Kalman DC tracking ---
|
||||
% Initialize Kalman state
|
||||
x_est = 0;
|
||||
P = obj.KF_state_cov; % initial P (tune in obj; e.g. 1)
|
||||
|
||||
% Logging containers
|
||||
logs.y_raw = zeros(numSym,1);
|
||||
logs.y_corr = zeros(numSym,1);
|
||||
logs.err = zeros(numSym,1);
|
||||
logs.K_gain = zeros(numSym,1);
|
||||
logs.x_est = zeros(numSym,1);
|
||||
logs.P = zeros(numSym,1);
|
||||
logs.normU = zeros(numSym,1);
|
||||
logs.tap_norm = zeros(numSym,1);
|
||||
|
||||
for ep = 1:epochs
|
||||
s = 0;
|
||||
for n = 1:obj.sps:N
|
||||
s = s + 1;
|
||||
U = x(obj.order + n - 1 : -1 : n);
|
||||
|
||||
% 1) Kalman prediction
|
||||
P = P + obj.KF_process_noise;
|
||||
x_prior = x_est;
|
||||
|
||||
% 2) raw equalizer output
|
||||
y_raw = obj.e.' * U;
|
||||
logs.y_raw(s) = y_raw;
|
||||
|
||||
% 3) DC-corrected output
|
||||
y_corr = y_raw + x_prior;
|
||||
y(s) = y_corr;
|
||||
logs.y_corr(s) = y_corr;
|
||||
|
||||
% 4) decision-directed symbol
|
||||
[~, idx] = min(abs(y_corr - obj.constellation));
|
||||
d_hat(s) = obj.constellation(idx);
|
||||
|
||||
% 5) error
|
||||
e_n = y_corr - d_hat(s);
|
||||
logs.err(s) = e_n;
|
||||
|
||||
% 6) tap-weight update (LMS/NLMS)
|
||||
if mu_lms ~= 0
|
||||
obj.e = obj.e - mu_lms * e_n * U;
|
||||
else
|
||||
normU = U.' * U + eps;
|
||||
logs.normU(s) = normU;
|
||||
obj.e = obj.e - e_n * U / normU;
|
||||
end
|
||||
|
||||
logs.tap_norm(s) = norm(obj.e);
|
||||
|
||||
% 7) Kalman update
|
||||
K_gain = P / (P + obj.KF_meas_noise);
|
||||
x_est = x_prior + K_gain * (e_n - x_prior);
|
||||
P = (1 - K_gain) * P;
|
||||
|
||||
% 8) log Kalman state
|
||||
logs.K_gain(s) = K_gain;
|
||||
logs.x_est(s) = x_est;
|
||||
logs.P(s) = P;
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@@ -70,7 +70,7 @@ classdef DBHandler < handle
|
||||
% Get table names and the first rows of each table to understand the structure
|
||||
obj.getTableNames();
|
||||
obj.getTables();
|
||||
obj.getDistinctValues();
|
||||
% obj.getDistinctValues();
|
||||
end
|
||||
|
||||
function obj = getTableNames(obj)
|
||||
|
||||
Reference in New Issue
Block a user