restructure and organize

This commit is contained in:
Silas Oettinghaus
2026-06-22 22:58:58 +02:00
parent c4f75b7ec4
commit 33ec5b3116
36 changed files with 1914 additions and 674 deletions

View File

@@ -815,11 +815,18 @@ classdef Signal
pkpos = sort(pkpos);
% if mean(w) > 15 || mean(p) > 15
% return
% else
% sequenceFound = 1;
% end
if isempty(pks)
warning(['Error in findpeaks, ususally the seuqnece is too short. No Peaks detected']);
return
end
if max(p) < 0.3 || median(w) > 15
%median(w) > 15 part means reject if the detected correlation peaks are too broad. That can be sensible: a true sync peak should often be sharp.
warning(['Error in findpeaks, ususally the seuqnece is too short. max(p) = ',num2str(max(p)),'; median(w)=',num2str(median(w)),'']);
return
end
sequenceFound = 1;
if options.debug_plots
figure(121212);clf

View File

@@ -462,6 +462,44 @@ classdef PAMmapper
end
function [out, levels] = splitByReferenceLevels(obj, data_in, reference_in, options)
% Split received samples by the transmitted/reference PAM level.
% Unlike separate_pamlevels, this does not decide the RX level.
arguments
obj
data_in
reference_in
options.levels = []
options.tolerance (1,1) double {mustBeNonnegative} = 0
end
data = obj.toNumericVector(data_in);
reference = obj.toNumericVector(reference_in);
if numel(data) ~= numel(reference)
error("PAMmapper:LengthMismatch", ...
"data_in and reference_in must have the same number of samples.");
end
if isempty(options.levels)
levels = unique(reference);
else
levels = options.levels(:).';
end
out = NaN(numel(levels), numel(reference));
for levelIdx = 1:numel(levels)
if options.tolerance == 0
levelMask = reference == levels(levelIdx);
else
levelMask = abs(reference - levels(levelIdx)) <= options.tolerance;
end
out(levelIdx, levelMask) = data(levelMask);
end
end
function [Signal_out] = quantize(obj,Signal_in,options)
arguments
obj
@@ -621,5 +659,19 @@ classdef PAMmapper
end
methods (Access = private)
function values = toNumericVector(~, signalLike)
if isa(signalLike, "Signal")
values = signalLike.signal;
else
values = signalLike;
end
values = values(:).';
end
end
end

View File

@@ -1,12 +1,10 @@
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);
% FFE variant for MPI/DC-removal experiments.
% With dc_buffer_len <= 1, ffe_buffer_len <= 1 and no smoothing, this
% follows FFE.m semantics so MPI-reduction changes can be isolated.
properties
sps % usually 2
sps
order
e
e_tr
@@ -16,28 +14,37 @@ classdef FFE_DCremoval_adaptive_mu < handle
mu_tr
epochs_tr
adaption_technique
dd_mode
mu_dd
epochs_dd
dd_len_fraction
mu_dc
e_dc
P
dc_buffer_len
adaptive_mu_mode
ffe_buffer_len
smoothing_buffer_length
smoothing_buffer_update
constellation
decide
save_debug = 0;
debug_struct
optmize_mus = 0;
mu_optimization
mu_optimization_iter = 0;
end
methods
function obj = FFE_DCremoval_adaptive_mu(options)
arguments(Input)
options.sps = 2;
options.order = 15;
@@ -45,23 +52,31 @@ classdef FFE_DCremoval_adaptive_mu < handle
options.mu_tr = 0;
options.epochs_tr = 5;
options.adaption_technique adaption_method = adaption_method.lms;
options.dd_mode = 1;
options.mu_dd = 1e-5;
options.epochs_dd = 5;
options.dd_len_fraction = 0.25;
options.mu_dc = 0.05;
options.dc_buffer_len = 1;
options.ffe_buffer_len = 1;
options.adaptive_mu_mode = 1;
options.ffe_buffer_len = 1;
options.smoothing_buffer_length = 0;
options.smoothing_buffer_update = 0;
options.decide = false;
options.save_debug = 0;
options.optmize_mus = 0;
end
assert(options.dc_buffer_len>0);
assert(options.dc_buffer_len >= 0);
assert(options.ffe_buffer_len >= 0);
assert(options.smoothing_buffer_length >= 0);
if options.smoothing_buffer_length > 0
assert(options.smoothing_buffer_update > 0);
end
fn = fieldnames(options);
for n = 1:numel(fn)
@@ -69,283 +84,328 @@ classdef FFE_DCremoval_adaptive_mu < handle
end
obj.e = zeros(obj.order,1);
obj.e_dc = 0;
obj.error = 0;
obj.dc_buffer_len = floor(obj.dc_buffer_len);
obj.ffe_buffer_len = floor(obj.ffe_buffer_len);
obj.smoothing_buffer_length = floor(obj.smoothing_buffer_length);
obj.smoothing_buffer_update = floor(obj.smoothing_buffer_update);
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);
obj.e_dc = 0;
% 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
delta = 0.05;
obj.P = (1/delta) * eye(obj.order);
if obj.optmize_mus
obj.optimizeMus(X.signal,D.signal);
obj.e = zeros(obj.order,1);
obj.e_dc = 0;
obj.P = (1/delta) * eye(obj.order);
end
% Training Mode
training = 1;
obj.equalize(X.signal, D.signal,obj.mu_tr,obj.epochs_tr,obj.len_tr,training);
showviz = 0;
obj.equalize(X.signal,D.signal,obj.mu_tr,obj.epochs_tr,obj.len_tr,training,showviz);
obj.e_tr = obj.e;
% Decision Directed Mode
N = X.length;
n = X.length;
training = 0;
[signal,decision]=obj.equalize(X.signal, D.signal,obj.mu_dd,obj.epochs_dd,N,training);
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);
end
[signal,decision] = obj.applyCurrentTaps(X.signal,n);
% 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
X.fs = D.fs;
lbdesc = [num2str(obj.order),' tap FFE'];
X = X.logbookentry(lbdesc); % append to logbook
X = X.logbookentry(lbdesc);
Noi = X;
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
function [y,d_hat] = equalize(obj,x,d,mu,epochs,N,training,showviz)
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
mu
epochs
N
training
showviz = 0 %#ok<INUSD>
end
if isempty(obj.e)
obj.e = zeros(obj.order,1);
end
% Zero-padding for filter memory
x = [zeros(floor(obj.order/2),1); x; zeros(obj.order,1)];
lambda = mu;
% 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 = 3e-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);
if training
mask = ones(obj.order,1);
else
mask = zeros(obj.order,1);
mask(900:end) = 1;
mask(ceil(length(obj.e)/2)) = 1;
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;
mask = ones(obj.order,1);
always_ideal_decision = 0;
grad = 0;
weight = 0;
update = 0;
if mu == 0 || (~obj.dd_mode && ~training)
epochs = 1;
end
dc_buffer_enabled = obj.mu_dc ~= 0 && obj.dc_buffer_len > 1;
adaptive_dc_enabled = dc_buffer_enabled && obj.adaptive_mu_mode;
if dc_buffer_enabled
e_dc_buffer = NaN(obj.dc_buffer_len,1);
end
ffe_buffer_enabled = ~training && obj.ffe_buffer_len > 1 && ...
obj.adaption_technique ~= adaption_method.rls;
if ffe_buffer_enabled
grad_buffer = NaN(obj.order,obj.ffe_buffer_len);
end
if obj.smoothing_buffer_length > 0
smoothing_buffer = zeros(1,obj.smoothing_buffer_length);
smoothing_mean = 0;
end
P_err = 0;
alpha = 0.98;
err_prev = 0;
gamma_dc = 1e-6;
mu_min = 1e-6;
mu_max = 3e-1;
for epoch = 1 : epochs
symbol = 0;
for sample = 1 : obj.sps : N
symbol = symbol + 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);
smoothing_buffer = circshift(smoothing_buffer,1,2);
smoothing_buffer(1) = x(sample);
if mod(symbol,obj.smoothing_buffer_update) == 0
smoothing_mean = mean(smoothing_buffer);
end
x(sample:sample+obj.sps-1) = x(sample:sample+obj.sps-1)-smth_mean;
x(sample:sample+obj.sps-1) = x(sample:sample+obj.sps-1) - smoothing_mean;
end
U = x(obj.order+sample-1:-1:sample);
%-- 1) filter output with DC correction
y(s) = e_dc_est + obj.e.'*U;
y(symbol,1) = obj.e_dc + (obj.e.*mask).' * U;
%-- 2) decision
if training
[~, idx] = min(abs(d(s) - obj.constellation));
d_hat(symbol,1) = d(symbol);
else
[~, idx] = min(abs(y(s) - obj.constellation));
end
d_hat(s) = obj.constellation(idx);
%-- 3) error
e_val = y(s) - d_hat(s);
if epoch == epochs
err(s,idx) = e_val;
true_err(s,idx) = y(s) - d(s);
end
%-- 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;
if ~always_ideal_decision
[~,symbol_idx] = min(abs(y(symbol) - obj.constellation));
d_hat(symbol,1) = obj.constellation(symbol_idx);
else
normU = (U.'*U) + eps;
obj.e = obj.e - e_val * U / normU;
d_hat(symbol,1) = d(symbol);
end
else
if 0
% buffer gradient
if mu_lms ~= 0
grad = e_val * U;
else
end
err(symbol) = d_hat(symbol) - y(symbol); %#ok<AGROW>
true_err(symbol) = y(symbol) - d(symbol); %#ok<AGROW,NASGU>
if training || obj.dd_mode
switch obj.adaption_technique
case adaption_method.lms
weight = mu;
grad = err(symbol) * U;
update = grad * weight;
case adaption_method.nlms
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
weight = mu / normU;
grad = err(symbol) * U;
update = grad * weight;
case adaption_method.rls
denom = lambda + U.' * obj.P * U;
k = (obj.P * U) / denom;
update = k * err(symbol);
end
end
%-- 5) DC adaptation
if obj.mu_dc ~= 0
if obj.adaptive_mu_mode
% 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 -- new "P_err" is "e_val^2"
P_err = alpha*P_err + (1-alpha)*e_val^2;
mu_dc_norm = obj.mu_dc / (P_err + eps);
if ffe_buffer_enabled
grad_buffer = circshift(grad_buffer,1,2);
grad_buffer(:,1) = update;
if mod(symbol,obj.ffe_buffer_len) == 0
obj.e = obj.e + mean(grad_buffer,2,"omitnan");
end
else
% DC buffer update & periodic estimate
% P_err = alpha*P_err + (1-alpha)*e_val^2;
% mu_dc_norm = obj.mu_dc / (P_err + eps);
mu_dc_norm = obj.mu_dc;
obj.e = obj.e + update;
end
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');
if obj.adaption_technique == adaption_method.rls
obj.P = (1/lambda) * (obj.P - k * (U.' * obj.P));
end
P_err_save(s) = P_err;
% Pcorr_save(s) = e_val * err_prev;
Ucorr_save(s) = (U.'*U);
mu_dc_save(s) = mu_dc_norm;
e_dc_save(s) = e_dc_est;
if obj.mu_dc ~= 0
if adaptive_dc_enabled
delta_mu = gamma_dc * err(symbol) * err_prev * (U.'*U);
obj.mu_dc = min(max(obj.mu_dc + delta_mu,mu_min),mu_max);
err_prev = err(symbol);
P_err = alpha*P_err + (1-alpha)*err(symbol)^2;
mu_dc_eff = obj.mu_dc / (P_err + eps);
else
mu_dc_eff = obj.mu_dc;
end
if dc_buffer_enabled
e_dc_buffer = circshift(e_dc_buffer,1);
e_dc_buffer(1) = obj.e_dc + mu_dc_eff * err(symbol);
if mod(symbol,obj.dc_buffer_len) == 0
obj.e_dc = median(e_dc_buffer,"omitnan");
end
else
obj.e_dc = obj.e_dc + mu_dc_eff * err(symbol);
end
end
end
% store instantaneous squared error
obj.error(epoch, s) = e_val^2;
if obj.save_debug
obj.debug_struct.error(epoch,symbol) = err(symbol) * err(symbol)';
if training
obj.debug_struct.error_tr(epoch,symbol) = err(symbol) * err(symbol)';
obj.debug_struct.update_tr(epoch,symbol) = update.'*update ./ rms(obj.e);
end
end
% obj.error(epoch,symbol) = err(symbol) * err(symbol)';
end
end
% Optional plotting in DD mode (uncomment if needed)
if 0%~training
constellation = unique(d);
lvlcol = cbrewer2('Paired', numel(constellation)*2);
lvlcol = lvlcol(2:2:end, :);
true_err(true_err==0) = NaN;
true_errmoverr = movsum(true_err, 4096, 'omitnan');
true_errmoverr = true_errmoverr./rms(true_errmoverr);
moverr = movsum(err, [100,100], 'omitnan');
moverr = moverr./rms(moverr);
figure(500); clf
hold on
% 1st subplot: true_errmoverr
% subplot(2,2,1); hold on
% for k = 1:4
% scatter(1:numSymbols, true_errmoverr(:,k), 1, lvlcol(k,:), '.');
% end
% scatter(1:numSymbols, Ucorr_save./rms(Ucorr_save), 1, lvlcol(1,:), '.','DisplayName','Ucorr_save');
% scatter(1:numSymbols, Pcorr_save./rms(Pcorr_save), 1, lvlcol(1,:), '.','DisplayName','P_corr');
% scatter(1:numSymbols, P_err_save, 1, lvlcol(1,:), '.','DisplayName','P_err');
% scatter(1:numSymbols, mu_dc_save, 1, lvlcol(2,:), '.','DisplayName','adapted value of $\mu_{DC}$');
% scatter(1:numSymbols, sum(moverr,2,'omitnan'), 1, lvlcol(1,:), '.','DisplayName','Mov Error $\hat{d}$ - x over all levels');
scatter(1:numSymbols, sum(e_dc_save,2,'omitnan'), 1, lvlcol(2,:), '.','DisplayName','Est. Error that is subtracted');
title('Moving Sum Error');
hold off
legend
% 2nd subplot: moverr
subplot(2,2,2); hold on
for k = 1:4
scatter(1:numSymbols, moverr(:,k), 1, lvlcol(k,:), '.');
end
title('Moving Sum Error');
hold off
legend
% 3rd subplot: err
subplot(2,2,3); hold on
for k = 1:4
scatter(1:numSymbols, err(:,k), 1, lvlcol(k,:), '.');
end
title('Error');
hold off
legend
% 4th subplot: err + obj.constellation'
subplot(2,2,4); hold on
for k = 1:4
scatter(1:numSymbols, err(:,k) + obj.constellation(k), 1, lvlcol(k,:), '.');
end
yline(obj.constellation, '--k');
title('Error + Constellation');
hold off
legend
sgtitle('Error Analysis Subplots');
end
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;
return
end
N_dd = floor(N * obj.dd_len_fraction);
N_dd = max(obj.sps,N_dd);
N_dd = min(N,N_dd);
end
function optimizeMus(obj,x,d)
switch obj.adaption_technique
case adaption_method.lms
mu_range = [1e-5, 1e-2];
case adaption_method.nlms
mu_range = [1e-3, 5e-1];
case adaption_method.rls
mu_range = [0.98, 0.99999];
end
mu_dc_range = [1e-5, 1e-1];
mu_tr_var = optimizableVariable("mu_tr",mu_range,"Transform","log");
vars = mu_tr_var;
if obj.dd_mode
vars = [vars, optimizableVariable("mu_dd",mu_range,"Transform","log")];
end
optimize_mu_dc = obj.mu_dc ~= 0;
if optimize_mu_dc
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, ...
"MaxObjectiveEvaluations",10, ...
"AcquisitionFunctionName","expected-improvement-plus", ...
"IsObjectiveDeterministic",false, ...
"Verbose",0, ...
"PlotFcn",[]);
obj.mu_tr = obj.mu_optimization.XAtMinObjective.mu_tr;
if obj.dd_mode
obj.mu_dd = obj.mu_optimization.XAtMinObjective.mu_dd;
end
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_DCremoval_adaptive_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);
elseif obj.dd_mode
fprintf("\nFFE_DCremoval_adaptive_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);
elseif optimize_mu_dc
fprintf("\nFFE_DCremoval_adaptive_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);
else
fprintf("\nFFE_DCremoval_adaptive_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);
end
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.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);
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");
end
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_DCremoval_adaptive_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);
elseif obj.dd_mode
fprintf("\rFFE_DCremoval_adaptive_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_DCremoval_adaptive_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);
else
fprintf("\rFFE_DCremoval_adaptive_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);
end
obj.save_debug = old_debug;
obj.mu_dc = old_mu_dc;
end
end
end

View File

@@ -95,14 +95,14 @@ classdef DataStorage < handle
end
function addStorage(obj,varName)
% add a storage
storage = cell(obj.dim);
obj.sto.(string(varName)) = storage;
end
function addStorage(obj,varName)
% add a storage
storage = cell(obj.getStorageSize());
obj.sto.(string(varName)) = storage;
end
function addValueToStorage(obj, valueToStore ,storageVarName, varargin)
@@ -273,14 +273,18 @@ classdef DataStorage < handle
end
%append to index list :-)
fn_=fieldnames(obj.sto);
n_ = fn_{1};
lin_idx(c,:) = sub2ind(size(obj.sto.(n_)),indices{:});
% lin_idx(c,:) = eval(['sub2ind(size(obj.sto.',n_,')',str,');']);
end
if isscalar(indices)
lin_idx(c,:) = indices{1};
else
fn_=fieldnames(obj.sto);
n_ = fn_{1};
lin_idx(c,:) = sub2ind(size(obj.sto.(n_)),indices{:});
% lin_idx(c,:) = eval(['sub2ind(size(obj.sto.',n_,')',str,');']);
end
end
end
% Mapping for single Index
@@ -291,24 +295,33 @@ classdef DataStorage < handle
function [phys_indices,param_name] = getPhysIndicesByLinIndex(obj, lin_idx)
% Converts a linear index into the corresponding physical parameter values
% Inputs:
% - lin_idx: The linear index within the storage array
function [phys_indices,param_name] = getPhysIndicesByLinIndex(obj, lin_idx)
% Converts a linear index into the corresponding physical parameter values
% Inputs:
% - lin_idx: The linear index within the storage array
% Output:
% - phys_indices: A cell array containing the physical parameter values for each dimension
% Initialize output cell array
phys_indices = cell(1, numel(obj.fn));
% Convert linear index to subscript indices
[subscripts{1:numel(obj.dim)}] = ind2sub(obj.dim, lin_idx);
% Map subscripts to physical values for each parameter
for i = 1:numel(obj.fn)
param_name{i} = obj.fn(i);
phys_indices{i} = obj.parameter.(param_name{i}).getPhysForIndex(subscripts{i});
end
% Initialize output cell array
phys_indices = cell(1, numel(obj.fn));
param_name = cell(1, numel(obj.fn));
if isempty(obj.fn)
return
end
% Convert linear index to subscript indices
if isscalar(obj.dim)
subscripts = {lin_idx};
else
[subscripts{1:numel(obj.dim)}] = ind2sub(obj.dim, lin_idx);
end
% Map subscripts to physical values for each parameter
for i = 1:numel(obj.fn)
param_name{i} = obj.fn(i);
phys_indices{i} = obj.parameter.(param_name{i}).getPhysForIndex(subscripts{i});
end
end
function [physStruct, stored_value] = getPhysAndValueByLinIndex(obj, storageVarName, lin_idx)
@@ -327,8 +340,14 @@ classdef DataStorage < handle
% Initialize an empty structure
physStruct = struct();
% Convert linear index to subscript indices
[subscripts{1:numel(obj.dim)}] = ind2sub(obj.dim, lin_idx);
% Convert linear index to subscript indices
if isempty(obj.fn)
subscripts = {};
elseif isscalar(obj.dim)
subscripts = {lin_idx};
else
[subscripts{1:numel(obj.dim)}] = ind2sub(obj.dim, lin_idx);
end
% Map subscripts to physical values and parameter names for each dimension
for i = 1:numel(obj.fn)
@@ -343,17 +362,31 @@ classdef DataStorage < handle
stored_value = obj.sto.(storageVarName){lin_idx};
end
function num_elements = getLastLinIndice(obj)
% Returns all possible linear indices for the data structure
% Output:
% - lin_indices: A column vector containing all linear indices for the storage array
% Calculate the total number of elements in the storage array
num_elements = prod(obj.dim);
end
end
function num_elements = getLastLinIndice(obj)
% Returns all possible linear indices for the data structure
% Output:
% - lin_indices: A column vector containing all linear indices for the storage array
% Calculate the total number of elements in the storage array
if isempty(obj.dim)
num_elements = 1;
else
num_elements = prod(obj.dim);
end
end
function storageSize = getStorageSize(obj)
if isempty(obj.dim)
storageSize = [1, 1];
elseif isscalar(obj.dim)
storageSize = [obj.dim, 1];
else
storageSize = obj.dim;
end
end
end
end