Auswertung Experiment
Database tüddelei DBHanlder läuft gut für DIESE Datanbank struktur... App begonnen aber weit entfernt von gutem Stand
This commit is contained in:
@@ -254,7 +254,12 @@ classdef Signal
|
||||
CallingModifier = evalin('caller','obj');
|
||||
end
|
||||
|
||||
CallingModifierStruct = obj.objToStructFilteredRecursive(CallingModifier);
|
||||
if isa(CallingModifier,"Signal")
|
||||
CallingModifierStruct = obj.objToStructFilteredRecursive(CallingModifier);
|
||||
ModifierCopy = {CallingModifierStruct};
|
||||
end
|
||||
|
||||
ModifierCopy = {CallingModifier};
|
||||
|
||||
SignalType = [string(class(obj))];
|
||||
TimeStamp = [(datetime('now','TimeZone','local','Format','HH:mm:ss'))];
|
||||
@@ -263,7 +268,7 @@ classdef Signal
|
||||
Nase = [0];
|
||||
SignalCopy = obj.signal;
|
||||
ModifierName = class(CallingModifier);
|
||||
ModifierCopy = {CallingModifierStruct};
|
||||
|
||||
|
||||
cell = {SignalType , TimeStamp , Length , SignalPower(1) , Nase, SignalCopy, ModifierName, ModifierCopy, Description};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
classdef EQ %< handle
|
||||
classdef EQ < handle
|
||||
%EQ Summary of this class goes here
|
||||
% Detailed explanation goes here
|
||||
|
||||
@@ -289,9 +289,9 @@ classdef EQ %< handle
|
||||
|
||||
e_dc = e_dc - obj.DCmu*error;
|
||||
|
||||
obj.error_log.e_ffe(cnt,trainloops) = e_ffe;
|
||||
obj.error_log.e_dfe(cnt,trainloops) = e_dfe;
|
||||
obj.error_log.e_(cnt,trainloops) = error;
|
||||
% obj.error_log.e_ffe(cnt,trainloops) = e_ffe;
|
||||
% obj.error_log.e_dfe(cnt,trainloops) = e_dfe;
|
||||
% obj.error_log.e_(cnt,trainloops) = error;
|
||||
|
||||
cnt = cnt+1;
|
||||
if obj.Nb(1) > 0
|
||||
@@ -460,7 +460,7 @@ classdef EQ %< handle
|
||||
|
||||
if 1%mu_mat ~= 0
|
||||
e_dc = e_dc - obj.DCmu*error;
|
||||
error_log(cnt,dd_loop) = e_dc;
|
||||
% error_log(cnt,dd_loop) = e_dc;
|
||||
cnt = cnt+1;
|
||||
end
|
||||
|
||||
|
||||
60
Classes/04_DSP/Equalizer/Postfilter.m
Normal file
60
Classes/04_DSP/Equalizer/Postfilter.m
Normal file
@@ -0,0 +1,60 @@
|
||||
classdef Postfilter < handle
|
||||
%NAME Summary of this class goes here
|
||||
% Detailed explanation goes here
|
||||
|
||||
properties(Access=public)
|
||||
ncoeff = 2;
|
||||
burg_coeff = [];
|
||||
|
||||
end
|
||||
|
||||
methods (Access=public)
|
||||
function obj = Postfilter(options)
|
||||
%NAME Construct an instance of this class
|
||||
% Detailed explanation goes here
|
||||
|
||||
arguments
|
||||
options.ncoeff double = 2
|
||||
end
|
||||
|
||||
%
|
||||
fn = fieldnames(options);
|
||||
for n = 1:numel(fn)
|
||||
try
|
||||
obj.(fn{n}) = options.(fn{n});
|
||||
end
|
||||
end
|
||||
|
||||
% do more stuff
|
||||
|
||||
end
|
||||
|
||||
function signalclass_out = process(obj,signalclass_in,noiseclass_in)
|
||||
|
||||
obj.burg_coeff = arburg(noiseclass_in.signal,obj.ncoeff);
|
||||
signalclass_in = signalclass_in.filter(obj.burg_coeff,1);
|
||||
|
||||
% append to logbook
|
||||
lbdesc = ['Postfilter'];
|
||||
signalclass_in = signalclass_in.logbookentry(lbdesc);
|
||||
|
||||
% write to output
|
||||
signalclass_out = signalclass_in;
|
||||
|
||||
end
|
||||
|
||||
function showFilter(obj,noiseclass_in)
|
||||
|
||||
noiseclass_in.spectrum('displayname','Noise PSD shifted to 0dBm','fignum',123,'normalizeTo0dB',1);
|
||||
|
||||
[h,w] = freqz(1,obj.burg_coeff,length(noiseclass_in),"whole",noiseclass_in.fs);
|
||||
h = h/max(abs(h));
|
||||
hold on
|
||||
w_ = (w - noiseclass_in.fs/2);
|
||||
plot(w_.*1e-9,20*log10(fftshift(h)),'DisplayName',['Burg Coeffs: ', num2str(obj.burg_coeff), ' ']);
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
classdef MLSE
|
||||
classdef MLSE < handle
|
||||
%MLSE calculates the most probable sequence for an input signal with given/ known channel impulse response of any length
|
||||
|
||||
properties(Access=public)
|
||||
|
||||
@@ -38,10 +38,22 @@ classdef DBHandler < handle
|
||||
error('Failed to connect to the database: %s', e.message);
|
||||
end
|
||||
|
||||
% Get table names and the first rows of each table to understand the structure
|
||||
obj.getTableNames();
|
||||
obj.getTables();
|
||||
obj.getDistinctValues();
|
||||
if obj.dbIsHealthy
|
||||
|
||||
obj.refresh();
|
||||
|
||||
else
|
||||
error('DB seems to be corrupt')
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
function obj = refresh(obj)
|
||||
% Get table names and the first rows of each table to understand the structure
|
||||
obj.getTableNames();
|
||||
obj.getTables();
|
||||
obj.getDistinctValues();
|
||||
end
|
||||
|
||||
function obj = getTableNames(obj)
|
||||
@@ -86,10 +98,10 @@ classdef DBHandler < handle
|
||||
obj.distinctValues = struct();
|
||||
|
||||
% Iterate over each table in obj.tables
|
||||
tableNames = fieldnames(obj.tables);
|
||||
tableNames_ = fieldnames(obj.tables);
|
||||
|
||||
for i = 1:numel(tableNames)
|
||||
tableName = tableNames{i};
|
||||
for i = 1:numel(tableNames_)
|
||||
tableName = tableNames_{i};
|
||||
|
||||
% Initialize a sub-struct to store distinct values for each field in the table
|
||||
obj.distinctValues.(tableName) = struct();
|
||||
@@ -101,10 +113,10 @@ classdef DBHandler < handle
|
||||
for j = 1:numel(fieldNames)
|
||||
fieldName = fieldNames{j};
|
||||
|
||||
% Skip fields ending with '_id' as they don't contain useful distinct values
|
||||
if endsWith(fieldName, '_id')
|
||||
continue;
|
||||
end
|
||||
% % Skip fields ending with '_id' as they don't contain useful distinct values
|
||||
% if endsWith(fieldName, '_id')
|
||||
% continue;
|
||||
% end
|
||||
|
||||
% Construct SQL to get distinct values for the current field
|
||||
query = sprintf('SELECT DISTINCT %s FROM %s', fieldName, tableName);
|
||||
@@ -123,17 +135,38 @@ classdef DBHandler < handle
|
||||
obj.distinctValues.(tableName).(fieldName) = distinctValues;
|
||||
|
||||
catch e
|
||||
warning('Failed to retrieve distinct values for %s.%s: %s', tableName, fieldName, e.message);
|
||||
% warning('Failed to retrieve distinct values for %s.%s: %s', tableName, fieldName, e.message);
|
||||
obj.distinctValues.(tableName).(fieldName) = [];
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
% Display the distinct values (optional, for debugging purposes)
|
||||
disp('Distinct values for each field:');
|
||||
disp(obj.distinctValues);
|
||||
end
|
||||
|
||||
function healthyDB = dbIsHealthy(obj)
|
||||
healthyDB = false;
|
||||
|
||||
num_runs = obj.fetch('SELECT COUNT(*) AS total_runs FROM Runs');
|
||||
|
||||
num_configs = obj.fetch('SELECT COUNT(*) AS total_configurations FROM Configurations');
|
||||
|
||||
num_meas = obj.fetch('SELECT COUNT(*) AS total_measurements FROM Measurements');
|
||||
|
||||
assert((num_runs{1,1}==num_configs{1,1})&&(num_configs{1,1}==num_meas{1,1}),'Different num of entries per table');
|
||||
|
||||
%Check for any duplicate paths
|
||||
duplictae_raw = obj.fetch("SELECT COALESCE(Runs.rx_raw_path,'NaN') AS rx_raw_path, COUNT(*) AS occurrences FROM Runs GROUP BY rx_raw_path HAVING COUNT(*) > 1");
|
||||
duplictae_sync = obj.fetch("SELECT COALESCE(Runs.rx_sync_path,'NaN') AS rx_sync_path, COUNT(*) AS occurrences FROM Runs GROUP BY rx_sync_path HAVING COUNT(*) > 1");
|
||||
|
||||
if size(duplictae_raw,2) > 1
|
||||
for i = 1:size(duplictae_raw,2)-1
|
||||
fprintf('Raw Rx Paths: Found %d duplictaes of %s \n',duplictae_raw.occurrences(i),duplictae_raw.rx_raw_path(i));
|
||||
end
|
||||
end
|
||||
healthyDB = true;
|
||||
end
|
||||
|
||||
|
||||
|
||||
function lastID = appendToTable(obj, tableName, newRow)
|
||||
% appendToTable Appends a new row to the specified table
|
||||
@@ -241,11 +274,87 @@ classdef DBHandler < handle
|
||||
end
|
||||
end
|
||||
|
||||
function addBEREntry(obj, berValue, occurrence, runID, ffe, dfe, mlse, pf, eqType, ffe_order, dfe_order, len_tr, mu_ffe, mu_dfe, mu_dc, comment)
|
||||
% addBEREntry Adds a BER entry linked to an existing or new Equalizer entry.
|
||||
% Usage:
|
||||
% addBEREntry(runID, eq, ffe, dfe, mlse, pf, eqType, ffe_order, dfe_order, len_tr, mu_ffe, mu_dfe, mu_dc, berValue, comment)
|
||||
|
||||
if isempty(pf)
|
||||
postfilter_taps = [];
|
||||
else
|
||||
postfilter_taps = pf.burg_coeff;
|
||||
end
|
||||
|
||||
% Create equalizer data struct for searching and adding if necessary
|
||||
equalizerData = struct( ...
|
||||
'ffe', jsonencode(ffe), ...
|
||||
'dfe', jsonencode(dfe), ...
|
||||
'mlse', jsonencode(mlse), ...
|
||||
'pf', jsonencode(pf), ...
|
||||
'eq_type', string(eqType), ...
|
||||
'ffe_order', jsonencode(ffe_order), ...
|
||||
'dfe_order', jsonencode(dfe_order), ...
|
||||
'postfilter_taps',jsonencode(postfilter_taps),...
|
||||
'len_tr', len_tr, ...
|
||||
'mu_ffe', jsonencode(mu_ffe), ...
|
||||
'mu_dfe', mu_dfe, ...
|
||||
'mu_dc', mu_dc, ...
|
||||
'comment', comment ...
|
||||
);
|
||||
|
||||
% Check if exact Equalizer and BER entries already exist in the DB ...
|
||||
selectedFields = {'Runs.run_id','BERs.ber_id','Equalizer.eq_id','BERs.ber',['BERs.occurrence' ...
|
||||
'']};
|
||||
filterParams = obj.tables;
|
||||
filterParams.Equalizer = equalizerData;
|
||||
[dataTable,sql_query] = obj.queryDB(filterParams, selectedFields);
|
||||
|
||||
% get or insert Equalizer
|
||||
if ~isempty(dataTable)
|
||||
% Equalizer entry already exists, use the existing eq_id
|
||||
cur_eq_id = dataTable.eq_id;
|
||||
else
|
||||
% Insert the new Equalizer entry
|
||||
cur_eq_id = obj.appendToTable('Equalizer', equalizerData);
|
||||
end
|
||||
|
||||
% skip if already here or insert BER entry
|
||||
if ~isempty(dataTable)
|
||||
|
||||
% A BER entry with the same eq_id, run_id, and occurrence already exists
|
||||
existingBERValue = dataTable.ber;
|
||||
|
||||
% Compare the existing BER value with the new BER value
|
||||
if existingBERValue == berValue
|
||||
fprintf('The BER entry %.2e || -- eq_id: %d -- run_id: %d -- occurrence: %d already exists. \n',berValue, cur_eq_id, runID, occurrence);
|
||||
else
|
||||
fprintf('Already found BER for EQ: %.2e ~= %.2e || -- eq_id: %d -- run_id: %d -- occurrence: %d already exists.\n', berValue, existingBERValue, cur_eq_id, runID, occurrence);
|
||||
end
|
||||
|
||||
else
|
||||
|
||||
% No such BER entry exists, insert the new BER entry
|
||||
berData = struct( ...
|
||||
'run_id', runID, ...
|
||||
'eq_id', cur_eq_id, ...
|
||||
'ber', berValue, ...
|
||||
'occurrence', occurrence ...
|
||||
);
|
||||
|
||||
obj.appendToTable('BERs', berData);
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
function answer = fetch(obj,query)
|
||||
answer = fetch(obj.conn,query);
|
||||
end
|
||||
|
||||
function result = getPathsWithFlexibleFilter(obj, filterParams, selectedFields)
|
||||
function [result,query] = queryDB(obj, filterParams, selectedFields)
|
||||
% getPathsWithFlexibleFilter Retrieves values from Runs table with flexible filtering
|
||||
% and lets the user select which fields to include in the SELECT statement.
|
||||
%
|
||||
@@ -257,8 +366,9 @@ classdef DBHandler < handle
|
||||
% If left empty, two popup windows will prompt the user for input.
|
||||
%
|
||||
% Outputs:
|
||||
% rxRawPaths: Cell array of values from the Runs table matching the criteria.
|
||||
% filteredValues: Table of distinct values for parameters included in filterParams.
|
||||
% result: table with sql return
|
||||
% query: this was send to SQL DB
|
||||
|
||||
arguments
|
||||
obj
|
||||
filterParams = [];
|
||||
@@ -299,7 +409,7 @@ classdef DBHandler < handle
|
||||
fieldName = fieldParts{2};
|
||||
|
||||
if isnumeric(obj.tables.(tableName).(fieldName))
|
||||
selectClause = [selectClause, 'COALESCE(', selectedFields{i}, ', -1) AS ', fieldName];
|
||||
selectClause = [selectClause, 'COALESCE(', selectedFields{i}, ', ''NaN'') AS ', fieldName];
|
||||
else
|
||||
selectClause = [selectClause, 'COALESCE(', selectedFields{i}, ', '''') AS ', fieldName];
|
||||
end
|
||||
@@ -321,10 +431,10 @@ classdef DBHandler < handle
|
||||
|
||||
% Loop through each table in filterParams
|
||||
filterClauses = [];
|
||||
tableNames = fieldnames(filterParams);
|
||||
tableNames_ = fieldnames(filterParams);
|
||||
|
||||
for t = 1:numel(tableNames)
|
||||
tableName = tableNames{t};
|
||||
for t = 1:numel(tableNames_)
|
||||
tableName = tableNames_{t};
|
||||
tableParams = filterParams.(tableName);
|
||||
|
||||
% Loop through each parameter in the table
|
||||
@@ -343,12 +453,14 @@ classdef DBHandler < handle
|
||||
elseif isnumeric(value) && isnan(value)
|
||||
% If value is NaN, use IS NULL in SQL
|
||||
filterClause = sprintf('%s IS NULL', fullName);
|
||||
elseif isnumeric(value)
|
||||
elseif isnumeric(value) && ~isEnumeration(value)
|
||||
filterClause = sprintf('%s = %f', fullName, value);
|
||||
elseif islogical(value) || (isnumeric(value) && ismember(value, [0, 1]))
|
||||
elseif islogical(value) || (isnumeric(value) && ismember(value, [0, 1])) && ~isEnumeration(value)
|
||||
filterClause = sprintf('%s = %d', fullName, value);
|
||||
elseif ischar(value) || isstring(value)
|
||||
filterClause = sprintf('%s = "%s"', fullName, value);
|
||||
filterClause = sprintf('%s = ''%s''', fullName, char(value)); %nicht nach string suchen sondern nach chararray -> 'bla' statt "bla"
|
||||
elseif isEnumeration(value)
|
||||
filterClause = sprintf('%s = ''%s''', fullName, value);
|
||||
else
|
||||
error('Unsupported data type for field "%s".', fullName);
|
||||
end
|
||||
@@ -376,6 +488,7 @@ classdef DBHandler < handle
|
||||
end
|
||||
|
||||
|
||||
|
||||
function selectedFields = promptSelectFields(obj)
|
||||
% promptSelectFields Prompts the user to select fields from multiple tables to include in the SELECT statement using settingsdlg.
|
||||
|
||||
@@ -436,41 +549,67 @@ classdef DBHandler < handle
|
||||
% promptFilterParameters Prompts the user to enter filter parameters using the settingsdlg framework.
|
||||
|
||||
% Get all possible parameters from all tables (excluding sqlite_sequence)
|
||||
tableNames = fieldnames(obj.tables);
|
||||
tableNames = setdiff(tableNames, {'sqlite_sequence'}); % Remove sqlite_sequence
|
||||
tableNames_ = fieldnames(obj.tables);
|
||||
tableNames_ = setdiff(tableNames_, {'sqlite_sequence'}); % Remove sqlite_sequence
|
||||
|
||||
% Prepare the inputs for settingsdlg with sections and separators
|
||||
promptSettings = {};
|
||||
allFieldsFullName = {};
|
||||
convertedFieldNames = {};
|
||||
|
||||
for i = 1:numel(tableNames)
|
||||
for i = 1:numel(tableNames_)
|
||||
% Add a separator for each table section
|
||||
promptSettings{end + 1} = 'separator';
|
||||
promptSettings{end + 1} = tableNames{i};
|
||||
promptSettings{end + 1} = tableNames_{i};
|
||||
|
||||
% Get all fields from the current table
|
||||
tableFields = fieldnames(obj.tables.(tableNames{i}));
|
||||
tableFields = fieldnames(obj.tables.(tableNames_{i}));
|
||||
|
||||
% Prepare each field to be added to the dialog
|
||||
for j = 1:numel(tableFields)
|
||||
fieldName = tableFields{j};
|
||||
fullName = sprintf('%s.%s', tableNames{i}, fieldName);
|
||||
fullName = sprintf('%s.%s', tableNames_{i}, fieldName);
|
||||
convertedName = strrep(fullName, '.', '_'); % Replace '.' with '_'
|
||||
|
||||
% Skip fields that do not have distinct values stored
|
||||
if ~isfield(obj.distinctValues.(tableNames_{i}), fieldName)
|
||||
continue;
|
||||
end
|
||||
|
||||
% Get the distinct values for the field
|
||||
distinctValues_ = obj.distinctValues.(tableNames_{i}).(fieldName);
|
||||
|
||||
% Prepare distinct values for dropdown
|
||||
if isempty(distinctValues_)
|
||||
% If there are no distinct values, use only an "All" entry
|
||||
distinctValues_ = {'All'};
|
||||
else
|
||||
% Ensure distinctValues is a cell array of strings
|
||||
if isnumeric(distinctValues_)
|
||||
distinctValues_ = arrayfun(@(x) num2str(x), distinctValues_, 'UniformOutput', false);
|
||||
elseif isstring(distinctValues_)
|
||||
distinctValues_ = cellstr(distinctValues_);
|
||||
elseif iscell(distinctValues_) && ~iscellstr(distinctValues_)
|
||||
distinctValues_ = cellfun(@num2str, distinctValues_, 'UniformOutput', false);
|
||||
end
|
||||
|
||||
% Add an "All" option at the beginning of the distinct values list
|
||||
distinctValues_ = [{'All'}; distinctValues_];
|
||||
end
|
||||
|
||||
allFieldsFullName{end + 1} = fullName; % Add full name to the list
|
||||
convertedFieldNames{end + 1} = convertedName; % Store the converted name
|
||||
|
||||
% Add the field name and value setting to the prompt
|
||||
promptSettings{end + 1} = {sprintf('%s', fullName), convertedName};
|
||||
promptSettings{end + 1} = [];
|
||||
promptSettings{end + 1} = distinctValues_; % Add distinct values as dropdown options
|
||||
end
|
||||
end
|
||||
|
||||
% Create the settings dialog
|
||||
[settings, button] = settingsdlg(...
|
||||
'title', 'Input Parameters for Filtering', ...
|
||||
'description', 'Enter the values for each field to filter. Leave empty to include all values. Type NaN for NULL.', ...
|
||||
'description', 'Enter the values for each field to filter. Select "All" to include all values.', ...
|
||||
promptSettings{:} ...
|
||||
);
|
||||
|
||||
@@ -497,7 +636,7 @@ classdef DBHandler < handle
|
||||
end
|
||||
|
||||
% Assign values to the respective fields under each table
|
||||
if isempty(value)
|
||||
if strcmp(value, 'All')
|
||||
filterParams.(tableName).(fieldName) = []; % Set to empty to include all values
|
||||
elseif isnumeric(value) && isnan(value)
|
||||
filterParams.(tableName).(fieldName) = NaN; % Use NaN to handle as NULL
|
||||
@@ -510,5 +649,6 @@ classdef DBHandler < handle
|
||||
|
||||
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user