Mercurial > hg > ltpda
diff m-toolbox/m/gui/gltpda/ltpdasim.m @ 0:f0afece42f48
Import.
author | Daniele Nicolodi <nicolodi@science.unitn.it> |
---|---|
date | Wed, 23 Nov 2011 19:22:13 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/m-toolbox/m/gui/gltpda/ltpdasim.m Wed Nov 23 19:22:13 2011 +0100 @@ -0,0 +1,562 @@ +function ltpdasim(block) + +% This is the automatic function wrapper +% ======================================================================== +% ==================== level-2 M file S-function ========================= +% ======================================================================== +% This wrapper is the automatic function, called by every function block +% in Simulink, able to execute m-file functions retrieving from Simulink: +% (1) the pointer to the object(s) to be analyzed, coming in as input of +% the corresponding block (ie, the DATA), +% (2) the name of the function to be applied on those data, from the tag +% of the currently executed block (ie, the true FUNCTION), +% (3) the parameters for that particular block, retrieved from the global +% shared workspace by the handle of the block (ie, the PARAMETERS). +% +% The output is then generated as: +% OUTPUT = FUNCTION(DATA,PARAMETERS) +% +% This output in the end is saved into the global array containing all +% the AOs (ie, all the DATA go together with other data): thus this output +% will be freely accessible by all the other functions. +% +% The only real output to Simulink will be just the ordinal number of the +% so-generated AO into the global array of AOs. +% +% $Id: ltpdasim.m,v 1.37 2008/12/01 20:03:51 nicola Exp $ + + +setup(block); + + +%% Setup + +function setup(block) + + % Register dialog parameter: none, because they're retrieved directly + % from the memory. This will prevent the user to modify the parameters + % outside the proper parameters panel: + block.NumDialogPrms = 0; + + % Register number of input and output ports + block.NumInputPorts = 1; + block.NumOutputPorts = 1; + + % Setup functional port properties to dynamically inherited. + block.SetPreCompInpPortInfoToDynamic; + + block.InputPort(1).DirectFeedthrough = true; + block.InputPort(1).DatatypeID = 0; + block.InputPort(1).Complexity = 0; + block.OutputPort(1).DatatypeID = 0; + block.OutputPort(1).Complexity = 0; + block.SampleTimes = [0 0]; + block.SetAccelRunOnTLC(false); + + block.OutputPort(1).Dimensions = 1; + + % Register methods + block.RegBlockMethod('SetInputPortSamplingMode',@SetInpPortFrameData); + block.RegBlockMethod('SetInputPortDimensions', @SetInpPortDims); + block.RegBlockMethod('Outputs', @Outputs); + + function SetInpPortFrameData(block, idx, fd) %#ok<INUSL> + block.InputPort(1).SamplingMode = fd; + block.OutputPort(1).SamplingMode = fd; + + function SetInpPortDims(block, idx, di) + block.InputPort(idx).Dimensions = di; + + +%% Outputs +function Outputs(block) +global LTPDAinvar gl loop execModels %#ok<NUSED> + +% disp(['The name of the currently executed block is ',get_param(get_param(gcbh,'Parent'),'Name')]) +% disp(['The current size of LTPDAinvar is ',num2str(size(LTPDAinvar,1))]) + +currparent = get_param(gcbh,'Parent'); +subsyshandle = get_param(currparent, 'handle'); + +% Check if it's a partial execution: +if ismember('executionList',evalin('base','who')) + executionList = evalin('base','executionList'); + blockIndex = -1; + for i=1:size(executionList,1), if executionList(i)==gcbh, blockIndex = i; break; end; end + if blockIndex == -1 % this block is not included in the list of those to be executed. + disp([' . Partial execution: block ',get_param(subsyshandle,'Name'),' will be skipped.']) + block.OutputPort(1).Data = -1; + return + else + % Check if the block must receive data from Simulink or retrieve them from a previous calculation: + if block.InputPort(1).Data(1)==-1 + annotation = find_system(bdroot,'FindAll','on','Type','Annotation','Tag','ltpda model'); + execHistory = get_param(annotation,'UserData'); + blockIndex = -1; + for i=1:size(execHistory,1), if execHistory{i,2}==subsyshandle, blockIndex = i; end; end + if blockIndex == -1 % something's wrong: the selected block is not included in the previous execution history + warning(['*** Partial execution: impossible to retrieve inputs. The block ',get_param(subsyshandle,'Name'),' seems to have never been executed.']) + block.OutputPort(1).Data = -1; + return + end + j=3; + while ~isempty(execHistory{blockIndex,j}) + block.InputPort(1).Data(j-2) = execHistory{blockIndex,j}; + j = j+1; + end + disp([' . Partial execution: block ',get_param(subsyshandle,'Name'),' will now be executed with data retrieved from previous calculation.']) + else + disp([' . Partial execution: block ',get_param(subsyshandle,'Name'),' will now be executed.']) + end + end +end + +% Check if the user wants to stop the execution: +lastChar = get(findobj('Name','LTPDA Progress Bar'),'CurrentCharacter'); +if ~isempty(lastChar) && strcmp(lastChar,'x') + set_param(bdroot, 'SimulationCommand', 'stop') + return +end + +% Update the progress bar window: + progressBar = findobj('Tag','progressaxes'); + if ~isempty(progressBar) + blocksTotal = get(findobj('Tag','blockstotal'),'UserData'); + blocksDone = get(findobj('Tag','done'),'UserData'); + blocksToGo = get(findobj('Tag','togo'),'UserData'); + set(findobj('Tag','done'),'UserData',blocksDone+1); + set(findobj('Tag','togo'),'UserData',blocksToGo-1); + set(findobj('Tag','done'),'String',['Done: ',num2str(blocksDone+1)]); + set(findobj('Tag','togo'),'String',['To go: ',num2str(blocksToGo-1)]); + currblockname = get_param(get_param(gcbh,'Parent'),'Name'); + for i=1:numel(currblockname), if double(currblockname(i))==10, currblockname(i)=' '; end; end + set(findobj('Tag','currentexec'),'String',['Current block: ',currblockname]); + progressSize = get(progressBar,'UserData'); + progressPosition = get(progressBar,'Position'); + progressPosition(3) = 1+(progressSize(3)/blocksTotal)*(blocksDone+1); + set(progressBar,'Position',progressPosition) + progressBarLoop = findobj('Tag','progressaxes2'); + if ~isempty(progressBarLoop) + set(findobj('Tag','done'),'String',['Blocks done: ',num2str(blocksDone+1)]); + loopStatus = getappdata(0,'loopStatus'); + progressSize = get(progressBarLoop,'UserData'); + progressLoopPosition = get(progressBarLoop,'Position'); + progressLoopPosition(3) = 1+(progressSize(3)/loopStatus(1))*loopStatus(2); + set(progressBarLoop,'Position',progressLoopPosition) + end + drawnow + end + +% Retrieve the function name from the block tag: + blocktag = get_param(gcb, 'tag'); + if strcmp(blocktag,'generic') + paramcommand = get_param(get_param(get_param(gcbh,'Parent'), 'handle'),'Description'); + eval(paramcommand) + blocktag = functionName; + end + +% ======================================================================== +%% For arithmetic blocks +% ======================================================================== + + if strcmp(blocktag,'arithmetic') + eq = get_param(currparent,'MaskDescription'); + if strcmp(eq,'Arithmetic block: the user can type in the desidered equation.') + disp(sprintf('Error: in the ''%s'' arithmetic block no equation has been typed in.',get_param(currparent,'Name'))) + close(findobj('Name','LTPDA Progress Bar')) + error(['Error: in the ',get_param(currparent,'Name'),' arithmetic block no equation has been typed in.']) + end + equation = eq; + equation(strfind(equation,char(10))) = []; + + paramcommand = get_param(subsyshandle,'Description'); + if isempty(paramcommand), paramcommand = 'params=plist(''alpha'',''-->'',''beta'',''-->'');'; end + eval(paramcommand) + + for i=1:nparams(params) + inputBlock = find_system(currparent,'SearchDepth',1,'LookUnderMasks','all','Name',lower(params.params(i).key)); + if numel(inputBlock)>1, inputBlock(1)=[]; end % this can happen only when the currparent has the same name: then, ignore the 1st, ie. the currparent itself + inputNumb = get_param(inputBlock{1},'Tag'); + equation = strrep(equation,lower(params.params(i).key),['LTPDAinvar{block.InputPort(1).Data(',inputNumb,'),1}']); + end + + try + outdata = eval(equation); + + % Setting the output signal name: + ifsetName = get_param(currparent,'UserData'); + if ~isempty(ifsetName) && isa(ifsetName,'char') + % ifsetName = ifsetName; + else + ifsetName = get_param(currparent,'Name'); + end + if numel(outdata)==1 + outdata = setName(outdata,ifsetName); + else + for i=1:size(outdata,1) + for j=1:size(outdata,2) + outdata(i,j) = setName(outdata(i,j),[ifsetName,'_',num2str(i),'-',num2str(j)]); + end + end + end + + x = size(LTPDAinvar,1); + blockName = currparent; + for i=1:numel(blockName), if double(blockName(i))==10, blockName(i)=' '; end; end + LTPDAinvar = [LTPDAinvar;{outdata,0,blockName}]; + block.OutputPort(1).Data = x+1; + + probe = get_param(currparent,'MaskHelp'); + if ~isempty(probe) && isa(probe,'char') && strcmp(probe,'probe') + LTPDAinvar{size(LTPDAinvar,1),2} = 2; + end + + return + + catch err + disp(sprintf('Something''s wrong in the calculation of the results of the ''%s'' arithmetic block.',get_param(currparent,'Name'))) + disp('The inputs were:') + for i=1:nparams(params) + disp(['Input ',num2str(i),':']) + LTPDAinvar{block.InputPort(1).Data(i),1} %#ok<NOPRT> + end + disp('The equation was:') + disp(eq) + close(findobj('Name','LTPDA Progress Bar')) + + rethrow(err) + + end + end % for the arithmetic block + +% ======================================================================== +%% =================== RETRIEVE THE PARAMETERS LIST ====================== +% ======================================================================== + + % The command line to produce the proper parameters list for the block + % currently executed is retrieved from the description of this parent subsystem + paramcommand = get_param(subsyshandle,'Description'); + loopExecution = 0; + + if ~isempty(paramcommand) + eval(paramcommand); + + % Verify if a global variable or nested loop variable has been used: + for i=1:nparams(params) + currVal = params.params(i).val; + if ischar(currVal) && numel(currVal)>5 && strcmp(currVal(1:5),'loop.') + loopExecution = 1; + try %#ok<ALIGN> + setVal(params.params(i),eval(params.params(i).val)); + catch, end + end + if ischar(currVal) && numel(currVal)>3 && strcmp(currVal(1:3),'gl.') + try %#ok<ALIGN> + setVal(params.params(i),eval(params.params(i).val)); + catch, end + end + end + + if ~exist('paramEnabled','var'), paramEnabled = ones(1,nparams(params)); end + currparam = plist(); + for jj=1:nparams(params) + if paramEnabled(jj)==1 + if numel(params.params(jj).key)>6 && strcmpi(params.params(jj).key(1:7),'addPar_'), params.params(jj).setKey(params.params(jj).key(8:end)); end + currparam = append(currparam,params.params(jj)); + end + end + else + currparam = plist(); + end + + % Retrieve parameters from Simulink: + paramFromSimulink = 0; + for i=1:nparams(currparam) + paramKey2 = currparam.params(i).key; + if numel(paramKey2)>7 && strcmpi(paramKey2(1:7),'addPar_'), paramKey = paramKey2(8:end); else paramKey = paramKey2; end + paramVal = currparam.params(i).val; + if (isa(paramVal,'char') && strcmp(paramVal,'-->')) || (isa(paramVal,'cell') && numel(paramVal)==1 && isa(paramVal{1},'char') && strcmp(paramVal{1},'-->')) + paramFromSimulink = paramFromSimulink + 1; + mux = find_system(currparent,'SearchDepth',1,'LookUnderMasks','all','BlockType','Mux'); + muxWidths = get_param(mux{1},'CompiledPortWidths'); + muxWidths = muxWidths.Inport; + inputBlock = find_system(currparent,'SearchDepth',1,'LookUnderMasks','all','Name',lower(paramKey)); + if numel(inputBlock)>1, inputBlock(1)=[]; end % this can happen only when the currparent has the same name: then, ignore the 1st, ie. the currparent itself + inputNumb = str2double(get_param(inputBlock{1},'Tag')); + x = 0; + for j=1:inputNumb-1 + x=x+muxWidths(j); + end + paramVal = [LTPDAinvar{block.InputPort(1).Data(x+1)}]; + if muxWidths(inputNumb)>1 + for j=x+2:x+muxWidths(inputNumb) + paramVal = [paramVal,LTPDAinvar{block.InputPort(1).Data(j)}]; + end + end + currparam = pset(currparam,paramKey2,paramVal); + end + end + +% ======================================================================== +%% ======================== CALCULATE THE RESULTS ========================= +% ======================================================================== + + y = length(block.InputPort(1).Data) - paramFromSimulink; + + % Check to verify the type of function: + specFunc = {'display'}; + [meth,clas] = strtok(get(get_param(currparent,'Handle'),'Tag')); + category = ''; + if strcmp(meth,'method') + clas = strtrim(clas); + infoObj = eval([clas,'.getInfo(''',blocktag,''')']); + category = infoObj.mcategory; + end + + if ismember(blocktag,specFunc) + % Input, but no parameters and no output + type = 4; + % ====================================== + elseif strcmp(category,'Output') + % Input and parameters, but no output + type = 3; + % =================================== + elseif ~isempty(utils.prog.find_in_models(currparent,'SearchDepth',1,'LookUnderMasks','all','BlockType','Ground')) || block.InputPort(1).Data(1)==0 + % No input, but parameters and output + type = 2; + % =================================== + elseif nparams(currparam)==0 + % Input and output, but no parameters + type = 1; + % ============================ + else + % Input, parameters and output + type = 0; + % ============================ + end + + + switch type + % ==================================================================== + case 4 % Input, but no parameters and no output + command = 'feval(blocktag,'; + for i=1:y + dVal = block.InputPort(1).Data(i); + if dVal>0, command = [command sprintf('LTPDAinvar{%d},', dVal)]; end + end + command = [command(1:end-1) ');']; + try + eval(command) + catch err + disp('4') + disp(sprintf('Something''s wrong in the calculation of the results of the %s function.',blocktag)) + disp(sprintf('The name of the currently executed block is %s.',get_param(currparent,'Name'))) + disp(sprintf('The (first) input data ordinal number, in the list of objects, was %d.',block.InputPort(1).Data(1))) + close(findobj('Name','LTPDA Progress Bar')) + rethrow(err) + end + block.OutputPort(1).Data = 1; % this will be ignored: no output expected. + return; + + % ==================================================================== + case 3 % Input and parameters, but no output + try + command = 'feval(blocktag,'; + for i=1:y + dVal = block.InputPort(1).Data(i); + if dVal>0, command = [command sprintf('LTPDAinvar{%d},', dVal)]; end + end + command = [command 'currparam);']; + if strcmpi(blocktag,'plot'), figure; end; + eval(command); + catch err + disp('3') + disp(sprintf('Something''s wrong in the calculation of the results of the %s function.',blocktag)) + disp(sprintf('The name of the currently executed block is %s.',get_param(currparent,'Name'))) + disp(sprintf('The (first) input data ordinal number, in the list of objects, was %d.',block.InputPort(1).Data(1))) + disp('The plist passed was:') + currparam %#ok<NOPRT> + close(findobj('Name','LTPDA Progress Bar')) + rethrow(err) + end + block.OutputPort(1).Data = 1; % this will be ignored: no output expected. + return; + + % ==================================================================== + case 2 % No input, but parameters and output + try + outdata = feval(blocktag,currparam); + catch err + disp('2') + disp(sprintf('Something''s wrong in the calculation of the results of the %s function.',blocktag)) + disp(sprintf('The name of the currently executed block is %s.',get_param(currparent,'Name'))) + disp('The plist passed was:') + currparam %#ok<NOPRT> + close(findobj('Name','LTPDA Progress Bar')) + rethrow(err) + end + + % ==================================================================== + case 1 % Input and output, but no parameters + try + command = 'outdata = feval(blocktag,'; + for i=1:y + dVal = block.InputPort(1).Data(i); + if dVal>0, command = [command sprintf('LTPDAinvar{%d},', dVal)]; end + end + command = [command(1:end-1) ');']; + eval(command); + catch err + disp('1') + disp(sprintf('Something''s wrong in the calculation of the results of the %s function.',blocktag)) + disp(sprintf('The name of the currently executed block is %s.',get_param(currparent,'Name'))) + disp(sprintf('The (first) input data ordinal number, in the list of objects, was %d.',block.InputPort(1).Data(1))) + disp('The plist passed was:') + currparam %#ok<NOPRT> + close(findobj('Name','LTPDA Progress Bar')) + rethrow(err) + end + % ==================================================================== + case 0 % Input, parameters and output + try + command = 'outdata = feval(blocktag,'; + for i=1:y + dVal = block.InputPort(1).Data(i); + if dVal>0, command = [command sprintf('LTPDAinvar{%d},', dVal)]; end + end + command = [command 'currparam);']; + eval(command); + catch err + disp('1') + disp(sprintf('Something''s wrong in the calculation of the results of the %s function.',blocktag)) + disp(sprintf('The name of the currently executed block is %s.',get_param(currparent,'Name'))) + disp(sprintf('The (first) input data ordinal number, in the list of objects, was %d.',block.InputPort(1).Data(1))) + disp('The plist passed was:') + currparam %#ok<NOPRT> + close(findobj('Name','LTPDA Progress Bar')) + rethrow(err) + end + + end + +%========================================================================== +%% Cycle to remove objects from memory as soon as they're no longer necessary: +%========================================================================== + +if ~getappdata(0,'maintainresults'); + portConnectivity = get(subsyshandle,'PortConnectivity'); + for i = 1:numel(portConnectivity) + notUsedAnymore = 1; + if isempty(portConnectivity(i).DstBlock) + parentBlock = portConnectivity(i).SrcBlock; + childrenBlocks = utils.prog.findchildren(parentBlock); + for j = 1:numel(childrenBlocks) + if isempty(get_param(childrenBlocks(j),'MaskVariables')), notUsedAnymore = 0; end + end + % disp(sprintf('*** (Currently executing block %s)',get_param(currparent,'Name'))) + if notUsedAnymore && LTPDAinvar{block.InputPort(1).Data(i),2}==0 + % disp(['*** Removed object n°.',num2str(block.InputPort(1).Data(i)),', which was a ',class(LTPDAinvar{block.InputPort(1).Data(i),1}),'.']) + disp(sprintf('*** (Currently executing block %s)',get_param(currparent,'Name'))) + LTPDAinvar(block.InputPort(1).Data(i),:) = []; + + % Update the execution history: + ltpda_annotation = find_system(bdroot,'FindAll','on','Type','Annotation','Tag','ltpda model'); + execHistory = get_param(ltpda_annotation,'UserData'); + for xx=1:size(execHistory,1) + for yy=3:size(execHistory,2), + if execHistory{xx,yy} == block.InputPort(1).Data(i), execHistory{xx,yy} = -1; end + if execHistory{xx,yy} > block.InputPort(1).Data(i), execHistory{xx,yy} = execHistory{xx,yy}-1; end + end + if execHistory{xx,1} == block.InputPort(1).Data(i), execHistory{xx,1} = -1; end + if execHistory{xx,1} > block.InputPort(1).Data(i), execHistory{xx,1} = execHistory{xx,1}-1; end + end + set_param(ltpda_annotation,'UserData',execHistory); + + disp('*** LTPDA object cleared from memory, being now unused') + end + end + end +end + % ======================================================================== +%% =============================== OUTPUTS ================================ +% ======================================================================== + + % Set this block status to 'executed': + set(subsyshandle,'MaskVariables','1'); + set(gcbh,'MaskVariables','1'); + +signalName = get_param(currparent,'Name'); +ifsetName = get_param(currparent,'UserData'); +if ~isempty(ifsetName) && isa(ifsetName,'double') && ifsetName==1 + if numel(outdata)==1 + outdata = setName(outdata,signalName); + else + for i=1:size(outdata,1) + for j=1:size(outdata,2) + outdata(i,j) = set(outdata(i,j),'name',[signalName,'_',num2str(i),'-',num2str(j)]); + end + end + end +end + +try + % To prevent the result calculated here from being canceled at the + % end of the calculation: + probe = get_param(currparent,'MaskHelp'); + if ~isempty(probe) && isa(probe,'char') && strcmp(probe,'probe'), keepThis = 1; + else keepThis = 0; + end + + % Appending the results: + ltpda_annotation = find_system(bdroot,'FindAll','on','Type','Annotation','Tag','ltpda model'); + execHistory = get_param(ltpda_annotation,'UserData'); + % If there's a previous execution history, check if the current block belongs to it: + if ~isempty(execHistory) + member = 0; + for i=1:size(execHistory,1) + if execHistory{i,2}==subsyshandle, member = 1; index = i; break; end + end + end + if ~isempty(execHistory) && member && ~loopExecution + x = execHistory{index,1}; + if x==-1, x = size(LTPDAinvar,1)+1; end + for i=1:numel(currparent), if double(currparent(i))==10, currparent(i)=' '; end; end + LTPDAinvar(x,:) = {outdata,keepThis,currparent}; + block.OutputPort(1).Data = x; + execHistory{index,1} = x ; + execHistory{index,2} = subsyshandle ; + for i=1:y , execHistory{index,2+i} = block.InputPort(1).Data(i); end + else + if isempty(execHistory), execHistory = {}; end + x = size(LTPDAinvar,1); + LTPDAinvar = [LTPDAinvar;{outdata,keepThis,currparent}]; + block.OutputPort(1).Data = x+1; + execHistory{end+1,1} = x+1 ; + execHistory{end,2} = subsyshandle ; + for i=1:y , execHistory{end,2+i} = block.InputPort(1).Data(i); end + end + + % Update the execution history: + % Are stored the the output obj pointer, the handle of the current subsytem and the input obj pointers: + set_param(ltpda_annotation,'UserData',execHistory); + + +catch + disp('------------------============================================------------------') + disp('------------------============================================------------------') + disp('------------------============================================------------------') + disp(sprintf('Something''s wrong in appending to the global variable LTPDAinvar the results of the %s function.',blocktag)) + disp(sprintf('The name of the currently executed block is %s.',get_param(currparent,'Name'))) + disp('The data to be saved, calculated into this block, are:') + outdata %#ok<NOPRT> + disp('------------------============================================------------------') + disp('------------------============================================------------------') + disp('------------------============================================------------------') +end + +%========================================================================== + + % The output to Simulink is just the ordinal number (ONE AND ONLY ONE + % NUMBER) of the object appended to the global array LTPDAinvar. + +% endfunction