classdef DataStorage < handle %DATASTORAGE Summary of this class goes here % Detailed explanation goes here properties inputParams = struct; parameter = struct; fn = []; dim = []; sto = {}; % getPhysForIndex = struct; % getIndexForPhys = struct; end methods function obj = DataStorage(inputParams) %DATASTORAGE Construct an instance of this class % Detailed explanation goes here % scheiß Variablenname obj.inputParams = inputParams; % Field Names obj.fn = string(fieldnames(inputParams)); % _______________ % Two dicts that map between physical and array index :-) % Dictionary: 10 km -> 3 % obj.getIndexForPhys = obj.buildIndexDict(); % Dictionary: 3 -> 10Km % obj.getPhysForIndex = obj.buildPhysDict(); % _______________ % This is the 2nd Idea -> ecery given Param will be a class % instance of "Parameter", therin user can access the dicts and % informations... Have not decided which way is best.. obj = obj.buildParameter(); % get dimension of dataStorage % e.g. if we have L = [1,2,10,80] and D=[8, 17, 21], we would % need an array with dimesion [4,3]. obj.dim = obj.getDimension(); % finally, create the main storage as cell array obj.sto = struct; end function save(obj,path) try save(path,"obj"); catch e disp(e.message) disp('Provide save path') end end function showInfo(obj) disp("Data Structure with fields:"); fprintf('%-12s', 'Name'); fprintf('%1s', '| '); fprintf('%0s ', 'Dimension'); fprintf('%4s', '| '); fprintf('%0s ', 'Physical Values'); fprintf('\n'); disp('----------------------------------------------------------------'); for i = 1:numel(obj.fn) fprintf('%-12s', char(obj.fn(i))); fprintf('%1s', '| '); fprintf('%8.1i ', obj.dim(i)); fprintf('%5s', '| '); fprintf('%-7s ', string(obj.parameter.(obj.fn(i)).values) ); fprintf('\n'); end disp('----------------------------------------------------------------'); stofn = string(fieldnames(obj.sto)); for s = 1:numel(stofn) nonempty = numel(find(~cellfun(@isempty,obj.sto.(stofn(s))))); overall = numel(obj.sto.(stofn(s))); fprintf('%-8s', 'Storage '); fprintf('%-10s', char(stofn(s))); fprintf('%4s', 'filled with '); fprintf('%-5s', num2str(nonempty)); fprintf('%-1s', ' entries -> '); fprintf('%-5s', num2str(nonempty/overall*100)); fprintf('%-1s', '% filled'); fprintf('\n'); end end function dim = getDimension(obj) dim = zeros(1,numel(obj.fn)); for p = 1:numel(obj.fn) %loop all parameter names and add their length :-) dim(p)=obj.parameter.(obj.fn(p)).length; end end function obj = buildParameter(obj) for p = 1:numel(obj.fn) name = obj.fn(p); values = obj.inputParams.(name); obj.parameter.(name) = StorageParameter(name,values); end end function addStorage(obj,varName) % add a storage storage = cell(obj.dim); obj.sto.(string(varName)) = storage; end function addValueToStorage(obj, valueToStore ,storageVarName, varargin) if nargin-3 == numel(obj.fn) lin_idx = obj.getIndicesByPhys(varargin); obj.sto.(storageVarName){lin_idx} = valueToStore; else error('Specify all the indices to access the right place in storage!') end end function addValueToStorageByLinIdx(obj, valueToStore ,storageVarName, lin_idx) obj.sto.(storageVarName){lin_idx} = valueToStore; end % Access Value(s) function value = getStoValue(obj,storageVarName, varargin) if nargin-2 == numel(obj.fn) %es wurden aausreichend argumente übergeben :-) %es gibt jedoch erstmal keinen Check ob die Reihenfolge %richtig ist value = []; lin_idx = obj.getIndicesByPhys(varargin); errcnt = 0; for i=1:numel(lin_idx) tmp = obj.sto.(storageVarName){lin_idx(i)}; if ~isempty(tmp) if isa(tmp,'double') value(i) = tmp ; elseif isa(tmp,'Signal') || isa(tmp,'struct') || isa(tmp,'Exfo_laser') || isa(tmp,'DC_supply') if i == 1 value = {}; end value{i} = tmp ; elseif isa(tmp,'cell') if isa(tmp{1},'Signal') if i == 1 value = {}; end value{i} = tmp{1} ; else value{i} = tmp ; end else try if i == 1 value = {}; end value{i} = tmp ; catch % value(i,:) = tmp(1:size(value,2)) ; if size(value,2) < size(tmp,2) diff = size(tmp,2) - size(value,2); value(:,end+1:end+diff) = NaN(size(value,1),diff); value(i,:) = tmp ; elseif size(value,2) > size(tmp,2) diff = size(value,2) - size(tmp,2); tmp(:,end+1:end+diff) = NaN(1,diff); value(i,:) = tmp ; end end end else errcnt = errcnt+1; if errcnt < 3 %get back the n-dimensional subiondices... [sub{1:length(size(obj.sto.(storageVarName)))}] = ind2sub(size(obj.sto.(storageVarName)),lin_idx(i)); %get back the physical representaion word = []; for phys_idx = 1:numel(obj.fn) parametername = obj.fn(phys_idx); word = [word,char(parametername),': ', num2str(obj.parameter.(parametername).getPhysForIndex(sub{phys_idx})),' ;']; end % warning(['Requested Data is not in Warehouse ', word]); elseif errcnt == 3 % warning(['... ', word]); end end if errcnt > 2 % warning([num2str(errcnt),' requested datapoint(s) not in warehouse.']); end end else error('Wrong Request using ExampleWarehouse.getStoValue(*parameter set*). Give me all the Parameters! Please!') end end % Mapping for several Indices (calls the mapping for single index) function lin_idx = getIndicesByPhys(obj,varargin) %map _all_ phys. to indices - several calls of single mapping inputsz = cellfun(@size,varargin{1},'UniformOutput',false); inputmax = cell2mat(cellfun(@max,inputsz,'UniformOutput',false)); % I wrote this method for a single query, then refined it for vectorial % inputs (which work fine), but lastly recognized that I % destroyed single query... however, this if / else will fix it! if sum(inputmax)==length(inputmax) vecQuery = 1; %set any value to one else vecQuery = find(inputmax~=1); %position of vectorial queries end q={}; for i = 1:numel(vecQuery) q{i} = varargin{1,1}{vecQuery(i)}; %the two vectors end combination = combvec(q{:}); %combine all possible combinations for c = 1:length(combination) %loop over all possible combinations indices = {}; str = []; for r = 1:numel(vecQuery) %replace varargin with current query (could have been renamed... however it works) varargin{1}{vecQuery(r)} = combination(r,c); end for p = 1:numel(obj.fn) curPhysQuery = varargin{1}{p}; %can be: a) single value // b) range curParameterName = obj.fn(p); indices{end+1} = obj.getIndexByPhys(curParameterName,curPhysQuery); % str = [str, ',indices{', num2str(p), '}']; 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 end % Mapping for single Index function idx = getIndexByPhys(obj,fieldname,phys) %map single phys to index idx = obj.parameter.(fieldname).getIndexForPhys(phys); end 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 end function [physStruct, stored_value] = getPhysAndValueByLinIndex(obj, storageVarName, lin_idx) % Retrieves a structure with physical parameter values as fieldnames, % their corresponding parameter names as values, and the stored value % for a given linear index. % Inputs: % - storageVarName: Name of the storage variable in obj.sto % - lin_idx: The linear index within the storage array % Outputs: % - physStruct: A structure with physical parameter values as fieldnames % and parameter names as values % - stored_value: The value stored at the given linear index in the % specified storage variable % Initialize an empty structure physStruct = struct(); % Convert linear index to subscript indices [subscripts{1:numel(obj.dim)}] = ind2sub(obj.dim, lin_idx); % Map subscripts to physical values and parameter names for each dimension for i = 1:numel(obj.fn) param_name = obj.fn(i); phys_value = obj.parameter.(param_name).getPhysForIndex(subscripts{i}); % Add to the structure with phys_value as the fieldname and param_name as the value physStruct.(param_name) = phys_value; end % Retrieve the stored value at the given linear index 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 end