Newer
Older
classdef SCDclass_algo
%SCD algorithm handling object
% The class holds all information and
% methods for handling a Simulink
% algorithm
modelname % Name of the model
mdscontainer % Container class for MDS+ interface objects
taskcontainer % Container class for init and term tasks
exportedtps % List of tunable parameters variable to be exported
datadictionary % Name of the used data dictionary
refdatadictionaries % Cell array of referenced data dictionaries
stdinits % Standard inits scripts for fixed parameters
timing % Timing info structure
exportedtpsdefaults % default tunable parameters defining functions
inBus % name of input bus
outBus % name of output bus
modelslx % slx model file name
folder % folder containing algorithm
% Empty algorithm constructor
obj.modelname=name;
obj.mdscontainer = SCDclass_mdsobjcontainer;
obj.taskcontainer = SCDclass_taskcontainer;
obj.exportedtps = {};

Cristian Galperti
committed
obj.exportedtpsdefaults = {};
obj.stdinits = {};
obj.datadictionary = '';
obj.refdatadictionaries = {};
obj.timing.t_start=0;
obj.timing.t_stop=1;
obj.timing.dt=1e-3;
% buses
obj.inBus = [obj.modelname,'_inBus' ];
obj.outBus = [obj.modelname,'_outBus'];
obj.modelslx = [obj.modelname,'.slx'];
% files
% algo path depending on .slx location
assert(~isempty(which(obj.modelslx)),'can''t find slx model %s',obj.modelslx);
obj.folder = fileparts(which(obj.modelslx));
% Standard data dictionary equal to algorithm name,
% overriddable by the setter method
obj=obj.setdatadictionary([name '.sldd']);
end
%% Print infos
function printinfo(obj)
fprintf('*****************************************************\n');
fprintf('* SCD algorithm: ''%s''\n',obj.modelname);
fprintf('*****************************************************\n');
if(~isempty(obj.datadictionary))
fprintf('* Data dictionary:\n %s\n',obj.datadictionary);
else
fprintf('* Data dictionary:\n base workspace\n');
end
if numel(obj.exportedtps)>0
fprintf('* Tunable params structs:\n');
for ii=1:numel(obj.exportedtps)
fprintf(' %s\n',obj.exportedtps{ii});
end
end
fprintf('* Tunable params objects:\n')
obj.printparameters;
fprintf('* Wavegen objects:\n');
obj.printwavegens;
fprintf('* Tasks objects:\n');
obj.printtasks;
fprintf('* Fixed parameters inits:\n');
obj.printinits;
fprintf('*****************************************************\n');
end
%% Setup
function setup(obj)
% setup()
%
% calls updatetemplatetp and
% buildworkspacetpstruct
%
% an algorithm block diagram
% should pass ctrl-d (instandalone opening)
% after this call

Cristian Galperti
committed
obj.updatetemplatetp;
obj.buildworkspacetpstruct;
end
%% General purpose getters
function out = getname(obj)
out=obj.modelname;
end
function out = getmdscontainer(obj)
out=obj.mdscontainer;
end
function out = gettaskcontainer(obj)
out=obj.taskcontainer;
end
function out = gettiming(obj)
out=obj.timing;
end
function out = getinits(obj)
out=obj.stdinits;
end
%% Data dictionary setter and getter
function obj = setdatadictionary(obj, datadict)
obj.datadictionary=datadict;
end
function out = getdatadictionary(obj)
out = obj.datadictionary;
end
function designDataObj = opendatadictionarydesigndata(obj)
dict = Simulink.data.dictionary.open(obj.getdatadictionary);
designDataObj = getSection(dict, 'Design Data');
function dictionaryObj = createdatadictionary(obj,varargin)
% create data dictionary in path obj.folder/obj.getdatadictionary
dd = obj.getdatadictionary;
ddpath = fullfile(obj.folder,dd);
% Create if not existing already
if isempty(ddpath)
fprintf('generating data dictionary %s\n',fullfile(obj.folder,obj.getdatadictionary));
dictionaryObj = Simulink.data.dictionary.create(ddpath);
else
dictionaryObj = Simulink.data.dictionary.open(ddpath);
fprintf('Data dictionary %s already exists, not created\n',ddpath);
end
function obj = setreferenceddatadictionaries(obj,refdd)
if ischar(refdd) && ~iscell(refdd); refdd={refdd}; end % to cell
assert(iscell(refdd) && isrow(refdd),'refdd must be a row cell array of data dictionary names')
obj.refdatadictionaries = refdd;
end
%% Tunable parameters structures handling functions
function out = getexportedtps(obj)
out = obj.exportedtps;
function obj = addtunparamstruct(obj, structname, default_function)
% obj = addtunparamstruct(structname, varargin)

Cristian Galperti
committed
%
% adds a tunable parameter to the algo object
% inputs:
% structname: name of the tunable param (string)
% varargin{1}: a function handle to get
% its default value, this function takes no arguments
% and must return either a struct or a Simulink.Parameter
%
% example: obj=obj.addtunparamstruct('SCDalgo_doublet_tp',
% @()SCDalgo_doublet_loadtp());
if(~ismember(structname, obj.exportedtps))
obj.exportedtps{end+1}=structname;
else
error('SCDclass_algo:addtunparamsstruct','Tunable parameter struct already present, cannot add!');

Cristian Galperti
committed
end
if nargin==3
assert(isa(default_function, 'function_handle'),'SCDclass_algo:addtunparamstruct', 'third argument, if present, must be a function handle');
obj.exportedtpsdefaults{end+1} = default_function; % add defaults to list

Cristian Galperti
committed
end
end
function obj = updatetemplatetp(obj)
% obj = updatetemplatetp()

Cristian Galperti
committed
%
% For every configured tunparams structure
% if a default value function is present it is

Cristian Galperti
committed
% updated in the template version of the tun params
% in the algo data dictionary.
% The default value function of a tunparams can be given

Cristian Galperti
committed
% as an optional third argument of addtunparamstruct
% method
DD = obj.opendatadictionarydesigndata;
for ii=1:numel(obj.exportedtps)
if ~isempty(obj.exportedtpsdefaults{ii})
% get current value of parameters from the function
% handle
fprintf(' %s: calling %s\n', obj.getname, char(obj.exportedtpsdefaults{ii}));

Cristian Galperti
committed
TP=obj.exportedtpsdefaults{ii}();
if ~isa(TP,'Simulink.Parameter')
assert(isstruct(TP),'default function must return either a Simulink.Parameter or a structure');
P = Simulink.Parameter;
P.Value = TP;
else
P = TP;
end
P.CoderInfo.StorageClass='ExportedGlobal';

Cristian Galperti
committed
% updates default tunable parameters structure in data dictionary
tmplname = sprintf('%s_tmpl',obj.exportedtps{ii});
if DD.exist(tmplname)
oldEntry = DD.getEntry(tmplname);
if isequal(oldEntry.getValue.Value,P.Value)
fprintf('%s: keep old template %s since not changed\n',obj.getname,tmplname);
continue;
else
% replace
DD.deleteEntry(tmplname); fprintf(' %s: deleted previous entry, ', obj.getname);
DD.addEntry(tmplname,P); fprintf('added new %s\n',tmplname);
end

Cristian Galperti
committed
else
fprintf(' %s: added new %s\n',obj.getname, tmplname);

Cristian Galperti
committed
DD.addEntry(tmplname,P);
end
end
function obj = buildworkspacetpstruct(obj)

Cristian Galperti
committed
% obj = buildworkspacetpstruct(obj)
%
% this funtion builds a workspace structures containing
% replicas of all tunable parameters structurea in the data
% dictionaries, this structure is the one actually used

Cristian Galperti
committed
% for loading simulation data from MDS
% It is better not to use directly data dictionaries structures
% to avoid flooding dds with big sim data sets (and

Cristian Galperti
committed
% consequently the SCD GIT itself
if(isempty(obj.datadictionary))
warning('SCDclass_algo:buildworkspacetpstruct','Methods ignored for this object, data dictionary isn''t configured');
return;
end
dd=SCDconf_getdatadict(obj.datadictionary);
for ii=1:numel(obj.exportedtps)
simstructnamedd=sprintf('%s_tmpl',char(obj.exportedtps(ii)));
simstructnamews=char(obj.exportedtps(ii));
simstruct = dd.getEntry(simstructnamedd).getValue;
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
assignstr=sprintf('%s=temp;',simstructnamews);
assignin('base','temp',simstruct);
evalin('base',assignstr);
end
evalin('base','clear temp;');
end
%% MDS container methods forwarders
function obj = addparameter(obj, param)
obj.mdscontainer=obj.mdscontainer.addparameter(param);
obj.mdscontainer=obj.mdscontainer.bindlastparameter(obj.modelname, obj.datadictionary, obj.exportedtps);
end
function obj = printparameters(obj)
obj.mdscontainer=obj.mdscontainer.printparameters;
end
function obj = actualizeparameters(obj, shot)
obj.mdscontainer=obj.mdscontainer.actualizeparameters(shot);
end
function obj = addwavegen(obj, wavegen)
obj.mdscontainer=obj.mdscontainer.addwavegen(wavegen);
obj.mdscontainer=obj.mdscontainer.bindlastwavegen(obj.modelname, obj.datadictionary, obj.timing);
end
function obj = printwavegens(obj)
obj.mdscontainer=obj.mdscontainer.printwavegens;
end
function obj = actualizewavegens(obj, shot)
obj.mdscontainer=obj.mdscontainer.actualizewavegens(shot);
end
function obj = cleanwavegens(obj)
obj.mdscontainer=obj.mdscontainer.cleanwavegens;
end
%% Task container methods forwarders
function obj = addtask(obj, task)
obj.taskcontainer=obj.taskcontainer.addtask(task);
obj.taskcontainer=obj.taskcontainer.bindlasttask(obj.modelname, obj.datadictionary);
end
function obj = printtasks(obj)
obj.taskcontainer=obj.taskcontainer.printtasks;
end
%% Timing information
function obj = settiming(obj, t_start, dt, t_stop)
obj.timing.t_start=t_start;
obj.timing.dt=dt;
obj.timing.t_stop=t_stop;
end
%% Fixed inits
function obj = addfpinitfcn(obj, fcnname, targetstruct,targetworkspace)
if nargin<3
targetstruct = '';
end
if nargin<4
targetworkspace = 'datadictionary'; % default: data dictionary workspace (assigninGlobal)
if ~iscell(targetstruct) && ~isempty(targetstruct)
targetstruct = {targetstruct};
end
if(~isempty(obj.stdinits))
for ii=1:numel(obj.stdinits)
if ~isempty(targetstruct) && contains(obj.stdinits{ii}{2},targetstruct)
warning('SCDclass_algo:addfpinitfcn','A function defining the structure %s has already been added, ignoring.\d',targetstruct)
return
end
end
end
% FF question to CG: why is this a cell and not a struct?
temp=cell(10,1);
temp{1}=fcnname;
temp{2}=targetstruct;
temp{3}=targetworkspace;
obj.stdinits{end+1}=temp;
end
function printinits(obj)
if(~isempty(obj.stdinits))
for ii=1:numel(obj.stdinits)
if isempty(obj.stdinits{ii}{2})
fprintf('%s : init function with no outputs\n',char(obj.stdinits{ii}{1}));
else
fprintf('%s -> %s in workspace %s \n',char(obj.stdinits{ii}{1}),char(obj.stdinits{ii}{2}{1}),char(obj.stdinits{ii}{3}));
function initdd(obj)
% generate/initialize data dictionary
dictionaryObj = obj.createdatadictionary;
designDataObj = opendatadictionarydesigndata(obj);
% link data dictionary to model and disable access to base
obj.load;
set_param(obj.getname,'DataDictionary',obj.getdatadictionary,'EnableAccessToBaseWorkspace','on');
% call initialization functions to populate dd with fixed parameters
% populate with template tunable parameters
obj.updatetemplatetp;
% add buses
if ~isempty(which(obj.inBus)) && ~isempty(which(obj.outBus))
fprintf('Add buses to data dictionary: %s, %s\n',obj.inBus,obj.outBus);
eval(obj.inBus); % eval buses in base workspace
eval(obj.outBus);
addEntry(designDataObj,obj.inBus ,evalin('base',obj.inBus ));
addEntry(designDataObj,obj.outBus,evalin('base',obj.outBus));
evalin('base',sprintf('clear %s %s',obj.inBus,obj.outBus));
else
fprintf('no buses imported in datadictionary - assuming they are already there\n')
% add configurations.sldd as referenced data dictionary, plus
% other optional data dictionaries (e.g. used by lower-level components of an algorithm)
for refdd = ['configurations.sldd',obj.refdatadictionaries]
fprintf('adding referenced data dictionary %s to %s \n',refdd{:},obj.getdatadictionary)
dictionaryObj.addDataSource(refdd{:});
end
end
function callinits(obj)
% call initialization functions that set fixed parameters
if ~isempty(obj.stdinits)
for ii=1:numel(obj.stdinits)
initfunction = obj.stdinits{ii}{1};
targetnames = obj.stdinits{ii}{2};
workspace = obj.stdinits{ii}{3};
nout = numel(targetnames);
fprintf('Calling init function ''%s'', assigning its output to ''%s'' in %s...\n',...
char(initfunction),cell2mat(targetnames),workspace);
else
fprintf('Calling init function ''%s''...\n',char(initfunction));
end
if ischar(initfunction)
initcmd=sprintf('%s(obj);', initfunction);
[value{1:nout}] = eval(initcmd);
elseif isa(initfunction,'function_handle')
if nargin(initfunction)==1
elseif nargin(initfunction)==0
else
error('unexpected number of input arguments for function %s',func2str(initfunction));
end
[value{1:nout}] = initfunction(argins{:}); % function has an input argument
else
error('initfunction must be a string or a function handle')
end
% assigns in base workspace or datadictionary depending
% on target workspace
for iout = 1:nout
% cycle over number of output arguments of the function
val = value{iout};
target = targetnames{iout};
if strcmp(workspace,'datadictionary')
% assign in associated data dictionary
Simulink.data.assigninGlobal(obj.modelname, target, val);
elseif strcmp(workspace,'base')
% assign in base workspace
assignin('base',target,val)
end
end
%% generic operation methods
function compile(obj)
try
eval(sprintf('%s([],[],[],''compile'')',obj.modelname));
catch ME
try
eval(sprintf('%s([],[],[],''term'')',obj.modelname)); % terminate if necessary
catch
rethrow(ME); % rethrow error so we can see it
end
eval(sprintf('%s([],[],[],''term'')',obj.modelname)); % terminate is successful
end
function sim(obj)
sim(obj.modelname);
end
function test_harness(obj)
harnessname = sprintf('%s_harness.slx',obj.getname);
if ~exist(harnessname,'file')
warning('no harness %s found, skipping test',harnessname);
return
else
fprintf('running test harness %s\n',harnessname);
sim(harnessname);
% add tests to check output result somehow (TBD)
end
end
function open(obj)
open(obj.modelname)
end
function load(obj)
load_system(obj.modelname);
end