Atom Tab for Programmable Super Block

Define the Atom tab of the Block Builder for a programmable super block.

For programmable super blocks, you do not need to define simulation functions. You only need to define the SetParameters function in the Atom tab. What is being defined is essentially a subsystem, and OML code is used to construct the diagram inside the block. This code includes the following:
_block = vssAddNewObject('SubSystem', _diagram);
_diagr = vssCreateObject('Diagram');

The code continues to populate _diagr with blocks and links, constructing a diagram.

To define a block in the diagram requires the following steps:

  1. Define the block parameters using an OML struct.
  2. Load the block from the corresponding library.
  3. Instantiate the block.
As an example, consider the block DiscreteDelay, which has parameters init_cond, typ, and externalActivation. The block can be instantiated in the diagram _diagr as follows:
_params = struct();
_params.init_cond = z0;
_params.typ = 'double';
_params.externalActivation = 0;
vssLoadBlock('system', 'Dynamical', 'DiscreteDelay');
_vss._palettes.('_system').('Dynamical').('DiscreteDelay').setparams(_diagr, 'DiscreteDelay', _params);

In this example, the initial condition is set to z0, which must be a parameter of the programmable super block. Links between blocks are established using the OML function vssAdd_Link. For instance, the following instruction connects the first output of the Input block to the first output of the DiscreteDelay block via a regular link:

vssAdd_Link(_diagram, 'Input', 'DiscreteDelay', 1, 1, 0, 1, 1);

When the Block Builder is invoked with a masked super block, the SetParameters function of the block is automatically generated. This function contains the code responsible for constructing the diagram in the Super Block. In this case, the diagram is fixed.

A fixed-diagram programmable super block might not be useful because it can also be implemented with a standard masked super block. However, it can serve as a useful starting point for defining the SetParameters function of a more general programmable super block. This approach is illustrated through the following example.

Example

In this example, the problem is to create a shift register block where each register value is exposed through a separate output. The number of registers and outputs is variable and equal to nout, given as a block parameter. In the case of three registers and outputs (nout=3), the diagram is as follows:
The super block is used as a starting point for construction of the programmable super block. Prepare the super block to be masked by defining the undefined variables z0 and nout in the Initialization script of the model. You can then apply auto-masking:
The result is:

After the super block is masked, click Block Builder with the super block selected. The Block Builder interface now contains a good starting point for defining a new block.

You must change some properties, in particular, the number ports in the Ports tab. Initially, the ports are fixed:
Reduce the Number of Ports to 2, and change the output to be variable and equal to nout.
In the Parameters tab, click the ... to edit the properties of the nout parameter and change its Type to Number with a Value of 4.
In the Atom tab, the initial SetParameters code constructs the diagram by instantiating blocks and connecting them for the case of nout=3. No graphical properties are used at this point. The code generated by Block Builder for the fixed diagram is as follows:
function _setdiagram_1 (_diagram, _label, __fenv__)
_curdiagram=_diagram;
_curlabel=_label;
importenv(__fenv__);
_diagram=_curdiagram;
_label=_curlabel;
clear _curdiagram;
clear _curlabel;
global _vss;
global __OBJ_ERR_;
_parent = __OBJ_ERR_.('block');
__OBJ_ERR_.('type')='context';
if isscalar(z0) z0=z0*ones(nout,1);end
__OBJ_ERR_.('block')=vssConstructBlockFullName(_parent,'Output_2');
__OBJ_ERR_.('type')='parameters';
_params=struct();
_params.portNumber=3;
_params.insize=[-1;-2];
_params.intyp='inherit';
vssLoadBlock('system','Ports','Output');
_vss._palettes.('_system').('Ports').('Output').setparams(_diagram,'Output_2',_params);
__OBJ_ERR_.('block')=vssConstructBlockFullName(_parent,'DiscreteDelay_2');
__OBJ_ERR_.('type')='parameters';
_params=struct();
_params.init_cond=z0(3);
_params.typ='double';
_params.externalActivation=0;
vssLoadBlock('system','Dynamical','DiscreteDelay');
_vss._palettes.('_system').('Dynamical').('DiscreteDelay').setparams(_diagram,'DiscreteDelay_2',_params);
__OBJ_ERR_.('block')=vssConstructBlockFullName(_parent,'Output_1');
__OBJ_ERR_.('type')='parameters';
_params=struct();
_params.portNumber=2;
_params.insize=[-1;-2];
_params.intyp='inherit';
vssLoadBlock('system','Ports','Output');
_vss._palettes.('_system').('Ports').('Output').setparams(_diagram,'Output_1',_params);
__OBJ_ERR_.('block')=vssConstructBlockFullName(_parent,'Output');
__OBJ_ERR_.('type')='parameters';
_params=struct();
_params.portNumber=1;
_params.insize=[-1;-2];
_params.intyp='inherit';
vssLoadBlock('system','Ports','Output');
_vss._palettes.('_system').('Ports').('Output').setparams(_diagram,'Output',_params);
__OBJ_ERR_.('block')=vssConstructBlockFullName(_parent,'Input');
__OBJ_ERR_.('type')='parameters';
_params=struct();
_params.portNumber=1;
_params.outsize=[-1;-2];
_params.outtyp='inherit';
_params.dept=0;
vssLoadBlock('system','Ports','Input');
_vss._palettes.('_system').('Ports').('Input').setparams(_diagram,'Input',_params);
__OBJ_ERR_.('block')=vssConstructBlockFullName(_parent,'Block');
__OBJ_ERR_.('type')='parameters';
_params=struct();
vssLoadBlock('system','Links','Split');
_vss._palettes.('_system').('Links').('Split').setparams(_diagram,'Block',_params);
__OBJ_ERR_.('block')=vssConstructBlockFullName(_parent,'DiscreteDelay_1');
__OBJ_ERR_.('type')='parameters';
_params=struct();
_params.init_cond=z0(2);
_params.typ='double';
_params.externalActivation=0;
vssLoadBlock('system','Dynamical','DiscreteDelay');
_vss._palettes.('_system').('Dynamical').('DiscreteDelay').setparams(_diagram,'DiscreteDelay_1',_params);
__OBJ_ERR_.('block')=vssConstructBlockFullName(_parent,'Split');
__OBJ_ERR_.('type')='parameters';
_params=struct();
vssLoadBlock('system','Links','Split');
_vss._palettes.('_system').('Links').('Split').setparams(_diagram,'Split',_params);
__OBJ_ERR_.('block')=vssConstructBlockFullName(_parent,'DiscreteDelay');
__OBJ_ERR_.('type')='parameters';
_params=struct();
_params.init_cond=z0(1);
_params.typ='double';
_params.externalActivation=0;
vssLoadBlock('system','Dynamical','DiscreteDelay');
_vss._palettes.('_system').('Dynamical').('DiscreteDelay').setparams(_diagram,'DiscreteDelay',_params);
vssAdd_Link(_diagram,'Output_2','DiscreteDelay_2',1,1,1,0,1);
vssAdd_Link(_diagram,'DiscreteDelay_1','Block',1,1,0,1,1);
vssAdd_Link(_diagram,'Block','Output_1',1,1,0,1,1);
vssAdd_Link(_diagram,'DiscreteDelay_2','Block',1,2,1,0,1);
vssAdd_Link(_diagram,'Input','DiscreteDelay',1,1,0,1,1);
vssAdd_Link(_diagram,'DiscreteDelay','Split',1,1,0,1,1);
vssAdd_Link(_diagram,'Split','DiscreteDelay_1',1,1,0,1,1);
vssAdd_Link(_diagram,'Split','Output',2,1,0,1,1);
end
_block = vssAddNewObject('SubSystem',_diagram);
_diagr= vssCreateObject('Diagram');
_setdiagram_1(_diagr,_label,getcurrentenv());
vssSet_SubSystem(_block,1,3,0,0,0,_label,_diagr);

The variable __OBJ_ERR_ is used to anchor the error locations for generating precise error messages. In the case of programmable super blocks, this is not very useful and it is better to reference all error message to the parent block, the programmable super block. In general, users do not know about the content of this block.

You can extend the above code so that it can work for arbitrary nout number of delays and outputs. Note that the individual error tags are removed so that all errors are referred to the parent. The new script below used in the context of the super block is also extended to produce better error messages:
function shiftreg_setdiagram_1 (_diagram, _label, __fenv__)
_curdiagram=_diagram;
_curlabel=_label;
importenv(__fenv__);
_diagram=_curdiagram;
_label=_curlabel;
clear _curdiagram;
clear _curlabel;
global _vss;
global __OBJ_ERR_;
_parent = __OBJ_ERR_.('block');
__OBJ_ERR_.('type')='context';
if isscalar(z0) z0=z0*ones(nout,1); elseif length(z0)~=nout error('size of z0 must match nb of outputs.');end
__OBJ_ERR_.('block')=vssConstructBlockFullName(_parent,'DiscreteDelay');
_params=struct();
_params.init_cond=z0(1);
_params.typ='double';
_params.externalActivation=0;
vssLoadBlock('system','Dynamical','DiscreteDelay');
_vss._palettes.('_system').('Dynamical').('DiscreteDelay').setparams(_diagram,'DiscreteDelay',_params);
_params=struct();
vssLoadBlock('system','Links','Split');
_vss._palettes.('_system').('Links').('Split').setparams(_diagram,'Split_1',_params);
_params=struct();
_params.portNumber=1;
_params.outsize=[-1;-2];
_params.outtyp='inherit';
_params.dept=0;
vssLoadBlock('system','Ports','Input');
_vss._palettes.('_system').('Ports').('Input').setparams(_diagram,'Input',_params);
_params=struct();
_params.portNumber=1;
_params.insize=[-1;-2];
_params.intyp='inherit';
vssLoadBlock('system','Ports','Output');
_vss._palettes.('_system').('Ports').('Output').setparams(_diagram,'Output',_params);
vssAdd_Link(_diagram,'Input','DiscreteDelay',1,1,0,1,1);
vssAdd_Link(_diagram,'DiscreteDelay','Split_1',1,1,0,1,1);
vssAdd_Link(_diagram,'Split_1','Output',2,1,0,1,1);
for i=2:nout-1
	_params=struct();
	_params.init_cond=z0(i);
	_params.typ='double';
	_params.externalActivation=0;
	vssLoadBlock('system','Dynamical','DiscreteDelay');
	_vss._palettes.('_system').('Dynamical').('DiscreteDelay').setparams(_diagram,['DiscreteDelay_',...
	num2str(i-1)],_params);
	_params=struct();
	_params.portNumber=i;
	_params.insize=[-1;-2];
	_params.intyp='inherit';
	vssLoadBlock('system','Ports','Output');
	_vss._palettes.('_system').('Ports').('Output').setparams(_diagram,['Output_',num2str(i-1)],_params);
	_params=struct();
	vssLoadBlock('system','Links','Split');
	_vss._palettes.('_system').('Links').('Split').setparams(_diagram,['Split_',num2str(i)],_params);
	vssAdd_Link(_diagram,['Split_',num2str(i-1)],['DiscreteDelay_',num2str(i-1)],1,1,0,1,1);
	vssAdd_Link(_diagram,['DiscreteDelay_',num2str(i-1)],['Split_',num2str(i)],1,1,0,1,1);
	vssAdd_Link(_diagram,['Split_',num2str(i)],['Output_',num2str(i-1)],2,1,0,1,1);
end
_params=struct();
_params.init_cond=z0(nout);
_params.typ='double';
_params.externalActivation=0;
vssLoadBlock('system','Dynamical','DiscreteDelay');
_vss._palettes.('_system').('Dynamical').('DiscreteDelay').setparams(_diagram,['DiscreteDelay_',...
	num2str(nout-1)],_params);
_params=struct();
_params.portNumber=nout;
_params.insize=[-1;-2];
_params.intyp='inherit';
vssLoadBlock('system','Ports','Output');
_vss._palettes.('_system').('Ports').('Output').setparams(_diagram,['Output_',num2str(nout-1)],_params);
vssAdd_Link(_diagram,['DiscreteDelay_',num2str(nout-1)],['Output_',num2str(nout-1)],1,1,0,1,1);
vssAdd_Link(_diagram,['Split_',num2str(nout-1)],['DiscreteDelay_',num2str(nout-1)],1,1,0,1,1);
end
_block = vssAddNewObject('SubSystem',_diagram);
_diagr= vssCreateObject('Diagram');
shiftreg_setdiagram_1(_diagr,_label,getcurrentenv());
vssSet_SubSystem(_block,1,nout,0,0,0,_label,_diagr);

Examining the new script, the new repeated blocks are named by extensions _2, _3, up to nout. This is not needed for links, which are not named.

After creating the first layer of blocks, the repeated structure is created within the following for loop:

for i=2:nout-1
    ....
end

The final layer is created after the for loop. Another change needs to be made in the code to change the number of outputs of the new block:

vssSet_SubSystem(_block,1,3,0,0,0,_label,_diagr);

is replaced by:

vssSet_SubSystem(_block,1,nout,0,0,0,_label,_diagr);

indicating that the block has nout outputs instead of 3.

You can move the new block to another model and set its paramters to the desired values and test it.