Many changes in DBHandler

new general processing structure
just before splitting off the projects folder from this repo
This commit is contained in:
Silas Oettinghaus
2025-05-13 10:24:09 +02:00
parent 727c3d9364
commit 9ce23c4a10
38 changed files with 2440 additions and 1103 deletions

View File

@@ -0,0 +1,40 @@
function [eq_, pf_, mlse_, mlse_db_, eq_post] = configureEqualizers(M, len_tr, vnle_order, dfe_order, mu_dc, mu_ffe, mu_dfe, pf_ncoeffs)
% CONFIGUREEQUALIZERS Creates and configures equalizer objects
%
% Inputs:
% M - PAM level
% len_tr - Training length
% vnle_order - Array with orders for VNLE [order1, order2, order3]
% dfe_order - Array with orders for DFE
% mu_dc - DC adaptation rate
% mu_ffe - Array with adaptation rates for FFE [mu1, mu2, mu3]
% mu_dfe - Adaptation rate for DFE
% pf_ncoeffs - Number of coefficients for postfilter
%
% Outputs:
% eq_ - Configured EQ object
% pf_ - Configured Postfilter object
% mlse_ - Configured MLSE_viterbi object
% mlse_db_ - Configured MLSE_viterbi object for duobinary
% eq_post - Configured FFE object for post-processing
% Configure main equalizer
eq_ = EQ("Ne", vnle_order, "Nb", dfe_order, ...
"training_length", len_tr, "training_loops", 5, "dd_loops", 5, ...
"K", 2, "DCmu", mu_dc, "DDmu", [mu_ffe mu_dfe], ...
"DFEmu", 0.005, "FFEmu", 0, "plotfinal", 0, "ideal_dfe", 1);
% Configure postfilter
pf_ = Postfilter("ncoeff", pf_ncoeffs, "useBurg", 1);
% Configure MLSE objects
mlse_ = MLSE_viterbi("duobinary_output", 0, 'M', M, ...
'trellis_states', PAMmapper(M,0).levels);
mlse_db_ = MLSE_viterbi("DIR", [1,1], "duobinary_output", 0, ...
"M", M, "trellis_states", PAMmapper(M,0).levels);
% Configure post-FFE
eq_post = FFE("epochs_tr", 5, "epochs_dd", 5, "len_tr", 4096*2, ...
"mu_dd", 1e-4, "mu_tr", 0, "order", 2001, ...
"sps", 1, "decide", 0);
end

View File

@@ -0,0 +1,106 @@
function [Bits, Symbols, Scpe_cell, found_sync] = loadSignalData(dataTable, options)
% LOADSIGNALDATA Loads and synchronizes signal data from storage
%
% Inputs:
% dataTable - Table with file paths and configuration
% options - Struct with storage_path and max_occurences
%
% Outputs:
% Symbols_mapped - Mapped symbols from bits
% Symbols - Original symbols
% Scpe_cell - Cell array of synchronized signals
% found_sync - Boolean indicating if synchronization was successful
found_sync = 0;
tempLocalStorage = 1;
% Part A: Check and load from local storage if available
if tempLocalStorage == 1
local_filename = sprintf('sync_data_run_%s.mat', num2str(dataTable.run_id));
if exist(local_filename, 'file')
% Load from local storage and return
load(local_filename, 'Bits', 'Symbols', 'Scpe_cell');
found_sync = 1;
end
end
% If not locally saved, load from storage
if ~found_sync
% Load transmitted bits
Bits = load([options.storage_path, char(dataTable.tx_bits_path)]);
Bits = Bits.Bits;
% Map bits to symbols
M = double(dataTable.pam_level);
fsym = dataTable.symbolrate;
Symbols_mapped = PAMmapper(M,0).map(Bits);
Symbols_mapped.fs = fsym;
% Load original symbols
Symbols = load([options.storage_path, char(dataTable.tx_symbols_path)]);
Symbols = Symbols.Symbols;
found_sync = 0;
Scpe_cell = {};
% Try to load pre-synchronized data
try
Scpe_load = load([options.storage_path, char(dataTable.rx_sync_path)]);
Scpe_cell = Scpe_load.S;
[~,~,~,found_sync] = Scpe_cell{2}.tsynch("reference", Symbols, "fs_ref", fsym, "debug_plots", 1);
catch
% Continue to next method if this fails
end
end
% If not found, try with raw data
if ~found_sync
try
Scpe_sig_raw = load([options.storage_path, char(dataTable.rx_raw_path(1))]);
Scpe_sig_raw = Scpe_sig_raw.Scpe_sig_raw;
Scpe_sig_resampled = Scpe_sig_raw.resample("fs_in", Scpe_sig_raw.fs, "fs_out", 2*fsym);
[~, Scpe_cell, ~, found_sync] = Scpe_sig_resampled.tsynch("reference", Symbols, "fs_ref", fsym, "debug_plots", 1);
catch
% Continue to next method if this fails
end
end
% Last attempt with mapped symbols
if ~found_sync && exist('Scpe_sig_raw', 'var')
if length(Symbols_mapped.signal) ~= sum(Symbols_mapped.signal == Symbols.signal)
[~, Scpe_cell, ~, found_sync] = Scpe_sig_raw.tsynch("reference", Symbols_mapped, "fs_ref", fsym, "debug_plots", 0);
end
end
% Part B: Save to local storage if data was loaded and synced
if tempLocalStorage == 1 && found_sync
local_filename = sprintf('sync_data_run_%s.mat', num2str(dataTable.run_id));
% Create directory if it doesn't exist
if ~exist('temp_sync_data', 'dir')
mkdir('temp_sync_data');
end
% List existing files and remove oldest if more than N
max_local_files = 10; % Store up to N files
files = dir('sync_data_run_*.mat');
if length(files) >= max_local_files
% Sort by date
[~, idx] = sort([files.datenum]);
% Delete oldest file
delete(files(idx(1)).name);
end
% Save current data
save(local_filename, 'Bits', 'Symbols', 'Scpe_cell');
end
% Limit number of occurrences
if found_sync
record_realizations = min(options.max_occurences, length(Scpe_cell));
Scpe_cell = Scpe_cell(1:record_realizations);
else
warning('Could not synchronize the received signal with the stored symbols!');
end
end

View File

@@ -0,0 +1,26 @@
function Scpe_sig = preprocessSignal(Scpe_sig, Symbols, fsym)
% PREPROCESSSIGNAL Performs standard preprocessing on a signal
%
% Inputs:
% Scpe_sig - Input signal
% Symbols - Reference symbols for synchronization
% fsym - Symbol frequency
%
% Outputs:
% Scpe_sig - Preprocessed signal
% Resample to 2x symbol rate
Scpe_sig = Scpe_sig.resample("fs_out", 2*fsym);
% Synchronize with reference
[Scpe_sig, ~] = Scpe_sig.tsynch("reference", Symbols, "fs_ref", fsym, "debug_plots", 0);
% Apply Gaussian filter
Scpe_sig = Filter('filtdegree', 4, "f_cutoff", Symbols.fs.*0.6, ...
"fs", Scpe_sig.fs, "filterType", filtertypes.gaussian, ...
"active", true).process(Scpe_sig);
% Remove DC offset
Scpe_sig = Scpe_sig - mean(Scpe_sig.signal);
end

View File

@@ -0,0 +1,47 @@
function printResults(run_id, M, Symbols, vnle_pf_package, dbtgt_package, occ)
% PRINTRESULTS Prints formatted results from equalization
%
% Inputs:
% run_id - Run identifier
% M - PAM level
% Symbols - Symbol data with fs property
% vnle_pf_package - VNLE+PF results package
% dbtgt_package - DB target results package (optional)
% occ - Occurrence index
% Print header
fprintf("==== EQUALIZATION RUN-ID %d | PAM-%d | %.2f GBd ====\n\n", run_id, M, Symbols.fs.*1e-9);
% VNLE Results
if ~isempty(vnle_pf_package)
vnle_result = vnle_pf_package{occ}.resultsVNLE;
mlse_result = vnle_pf_package{occ}.resultsMLSE;
fprintf(">> VNLE Results:\n");
fprintf(" BER: %.2e\n", vnle_result.BER);
fprintf(" BER (pre-code): %.2e\n", vnle_result.BER_precoded);
fprintf(" SNR: %.2f dB\n", vnle_result.SNR);
fprintf(" GMI: %.4f\n", vnle_result.GMI);
fprintf(" Linerate: %.2f Gbps\n", Symbols.fs .* floor(log2(M)*10)/10 .*1e-9);
fprintf(" AIR: %.2f Gbps\n", vnle_result.AIR.*1e-9);
fprintf("\n");
% MLSE Results
fprintf(">> MLSE Results:\n");
fprintf(" BER: %.2e\n", mlse_result.BER);
fprintf(" BER (pre-code): %.2e\n", mlse_result.BER_precoded);
fprintf(" Channel Alpha: %.2f\n", mlse_result.Alpha);
fprintf("\n");
end
% DB Target Results
if ~isempty(dbtgt_package)
dbtgt = dbtgt_package{occ}.resultsDBtgt;
fprintf(">> DB Target Results:\n");
fprintf(" BER: %.2e\n", dbtgt.BER);
fprintf(" BER (pre-code): %.2e\n", dbtgt.BER_precoded);
fprintf("\n");
end
fprintf("- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \n\n");
end

View File

@@ -0,0 +1,11 @@
function dataTable = queryRunid(run_id, database)
% Query database for run configuration
filterParams = database.tables;
filterParams.Runs = struct('run_id', run_id);
[dataTable, ~] = database.queryDB(filterParams, database.getTableFieldNames('Runs'));
[~, uniqueIdx] = unique(dataTable.run_id); % Get unique run_id indices
dataTable = dataTable(uniqueIdx, :); % Extract unique configurations for each run_id
end

View File

@@ -0,0 +1,213 @@
function [results,wh] = submitJobs(run_ids, dsp_options, submit_mode, submit_options)
% SUBMITJOBS Submits dsp_runid jobs for processing
%
% Inputs:
% run_ids - Single run ID or array of Run IDs for processing
% dsp_options - Options for dsp_runid function
% submit_mode - Execution mode: 'parallel' or 'linear'
% options - Optional parameters
%
% Outputs:
% results - Cell array of results from each job
% wh - Updated DataStorage object
% USAGE:
% % === SETTINGS ===
%
% dsp_options.append_to_db = 1;
% dsp_options.max_occurences = 15;
% dsp_options.database_path = 'C:\Users\Silas\Documents\MATLAB\Datensätze\sioe_labor\';
% dsp_options.database_name = 'silas_labor_newdsp_newstructure.db';
% dsp_options.storage_path = 'Z:\2024\sioe_labor\';
% dsp_options.parameters = struct();
% dsp_options.parameters.mu_dc = [0.005];
%
% % === Get Run ID's ===
% db = DBHandler("pathToDB", [dsp_options.database_path, dsp_options.database_name], "type", "sqlite");
% fp = QueryFilter();
% % fp.where('Runs', 'run_id','EQUALS', 5108);
% fp.where('Runs', 'is_mpi','EQUALS', 0);
% fp.where('Runs', 'fiber_length','EQUALS', 1);
% fp.where('Runs', 'wavelength','EQUALS', 1310);
% fp.where('Runs', 'db_mode','EQUALS', 0);
% fp.where('Runs', 'rop_attenuation','EQUALS', 0);
% fp.where('Runs', 'pam_level','EQUALS', 4);
% fp.where('Runs', 'bitrate','EQUALS', 360e9);
% fp.where('Runs', 'power_pd_in','GREATER_THAN', 7);
% [dataTable,~] = db.queryDB(fp, db.getTableFieldNames('Runs'));
% % === Initialize DataStorage ===
% wh = DataStorage(dsp_options.parameters);
% wh.addStorage("ffe_package");
% wh.addStorage("mlse_package");
% wh.addStorage("vnle_package");
% wh.addStorage("dbtgt_package");
% wh.addStorage("dbenc_package");
%
% % === RUN IT ===
% [results,wh] = submitJobs(dataTable.run_id(:), dsp_options, "parallel", 'wh', wh, 'waitbar', true);
% wh.getStoValue('ffe_package',0.005);
% wh.getStoValue('mlse_package',0.005);
arguments
run_ids int32 = 0
dsp_options struct = struct();
submit_mode processingMode = processingMode.serial
submit_options.waitbar (1,1) logical = true
submit_options.wh = DataStorage(struct()); % Optional DataStorage object
end
% Ensure run_ids is a row vector
run_ids = run_ids(:)';
% Get number of jobs per run_id
nJobsPerRunId = submit_options.wh.getLastLinIndice;
nRunIds = length(run_ids);
totalJobs = nJobsPerRunId * nRunIds;
% Initialize results array for all jobs
results = cell(nJobsPerRunId, nRunIds);
futures = cell(totalJobs, 1);
% Initialize waitbar if requested
if submit_options.waitbar
h = waitbar(0, 'Processing Jobs...');
cleanupObj = onCleanup(@() delete(h));
end
% Process jobs based on mode
if submit_mode == processingMode.parallel
setupParallelPool();
% Submit jobs to parallel pool
jobCounter = 0;
for r = 1:nRunIds
for k = 1:nJobsPerRunId
jobCounter = jobCounter + 1;
optionalVars = buildOptionalVars(k, submit_options.wh);
% Submit job with proper arguments
futures{jobCounter} = parfeval(@dsp_runid, 1, run_ids(r), ...
"database_name", dsp_options.database_name, ...
"append_to_db", dsp_options.append_to_db, ...
"database_path", dsp_options.database_path, ...
"max_occurences", dsp_options.max_occurences, ...
"storage_path", dsp_options.storage_path, ...
"parameters", optionalVars);
fprintf('[RunID %d, Job %d] Submitted to pool.\n', run_ids(r), k);
end
end
if submit_options.waitbar
setupParallelWaitbar(futures, totalJobs, h);
end
% Fetch results
jobCounter = 0;
for r = 1:nRunIds
for k = 1:nJobsPerRunId
jobCounter = jobCounter + 1;
try
results{k,r} = fetchOutputs(futures{jobCounter});
fprintf('[RunID %d, Job %d] Completed successfully.\n', run_ids(r), k);
storeResult(results{k,r}, k, submit_options.wh);
catch ME
handleError(ME, k, run_ids(r));
results{k,r} = ME;
end
end
end
elseif submit_mode == processingMode.serial
% Process jobs sequentially
jobCounter = 0;
for r = 1:nRunIds
for k = 1:nJobsPerRunId
jobCounter = jobCounter + 1;
optionalVars = buildOptionalVars(k, submit_options.wh);
try
fprintf('[RunID %d, Job %d] Running in linear mode...\n', run_ids(r), k);
results{k,r} = dsp_runid(run_ids(r),...
"database_name", dsp_options.database_name,...
"append_to_db", dsp_options.append_to_db,...
"database_path", dsp_options.database_path,...
"max_occurences", dsp_options.max_occurences,...
"storage_path", dsp_options.storage_path,...
"parameters", optionalVars);
fprintf('[RunID %d, Job %d] Completed successfully.\n', run_ids(r), k);
storeResult(results{k,r}, k, submit_options.wh);
catch ME
handleError(ME, k, run_ids(r));
results{k,r} = ME;
end
% Update waitbar if requested
if submit_options.waitbar
waitbar(jobCounter/totalJobs, h, sprintf('Completed %d/%d jobs', jobCounter, totalJobs));
end
end
end
else
error('')
end
wh = submit_options.wh;
% Helper functions remain the same except for handleError
% Modified handleError function to include run_id
function handleError(ME, jobIndex, run_id)
fprintf('[RunID %d, Job %d] ERROR [%s]: %s\n', run_id, jobIndex, ME.identifier, ME.message);
for st = ME.stack'
fprintf(' %s:%d (%s)\n', st.file, st.line, st.name);
end
fprintf('Full report:\n%s\n', getReport(ME,'extended'));
end
% Other helper functions remain unchanged
function setupParallelPool()
curpool = gcp('nocreate');
if isempty(curpool)
parpool;
else
if ~isempty(curpool.FevalQueue.QueuedFutures) || ~isempty(curpool.FevalQueue.RunningFutures)
oldq = length(curpool.FevalQueue.QueuedFutures) + length(curpool.FevalQueue.RunningFutures);
curpool.FevalQueue.cancelAll;
fprintf('Canceled %d unfetched jobs from old queue.\n', oldq);
end
end
end
function optionalVars = buildOptionalVars(jobIndex, wh)
optionalVars = struct();
if ~isempty(wh.getDimension)
[parametervalues, parameternames] = wh.getPhysIndicesByLinIndex(jobIndex);
for pidx = 1:numel(parameternames)
optionalVars.(parameternames{pidx}) = parametervalues{pidx};
end
end
end
function setupParallelWaitbar(futures, totalJobs, h)
updateWaitbar = @(~) waitbar(sum(cellfun(@(f) strcmp(f.State, 'finished'), futures))/totalJobs, h, ...
sprintf('Completed %d/%d jobs', sum(cellfun(@(f) strcmp(f.State, 'finished'), futures)), totalJobs));
futureArray = [futures{:}];
afterEach(futureArray, updateWaitbar, 0);
end
function storeResult(result, jobIndex, wh)
if ~isempty(wh)
wh.addValueToStorageByLinIdx(result.ffe_package, 'ffe_package', jobIndex);
wh.addValueToStorageByLinIdx(result.mlse_package, 'mlse_package', jobIndex);
wh.addValueToStorageByLinIdx(result.vnle_package, 'vnle_package', jobIndex);
wh.addValueToStorageByLinIdx(result.dbtgt_package, 'dbtgt_package', jobIndex);
wh.addValueToStorageByLinIdx(result.dbenc_package, 'dbenc_package', jobIndex);
end
end
end