Seth on Simulink
August 21st, 2008
Mask Initialization and Self-Modifying Blocks
In previous posts, I introduced advanced
masking concepts and discussed how to build a masked library block with a dynamic
mask dialog. In this post, I will show how the example Saturation block
adds/deletes ports and rewires itself depending on its configuration.
The Saturation Block Example

After configuring the block dialog, clicking Apply or OK
executes the mask initialization callback. The mask initialization callback is
where most of the work for a mask happens. Mask initialization commands should
take the parameter values set in the mask dialog and configure the block so it
is ready to run. In the Saturation block example, the block is switching
between two basic configurations, the Dynamic Saturation and the Fixed
Saturation.

The difference between the configurations is the type of
block used for up and lo. They are ports to provide dynamic limits, and
constants to provide fixed limits.
Key point: do the least amount of work that you can
in the mask initialization.
Mask initialization code should do the minimum amount of
work that it can because mask initialization runs many times in the life of a
model. In addition to running when you click OK or Apply, mask initialization runs
at the start of every simulation and update diagram, when you call set_param to
modify the block, and when you are building the model as you drop the block
into the system.
The mask parameters are the variable names set on the
parameters page of the mask editor. (See below)

Blocks in the system under the mask can access these variables
in the mask workspace. Initialization commands also run in the mask workspace,
so these variables are part of the mask initialization callback. (see below) If
a block will rewire itself, or add ports, you must check Allow library block
to modify its contents.

For the saturation block, I chose to call an M-function to
do the work of the initialization command. I find it is more convenient to
debug and the MATLAB editor is a more comfortable development for mask
initialization commands that are more than a few lines.
Use the state of the mask GUI to control the code
My function is saturation_init_cb. I pass into the function
all the variables it needs from the mask workspace. This is more efficient
than calling get_param on the block. I always pass in the result of gcb
(get pathname of current block). I will use this path
when I need to reference the blocks inside the saturation block subsystem.
In order to do the least amount of work, my mask
initialization checks the system to see if changes are needed. The check for
the upper limit source runs through the switch statement to handle the two
possible values, internal or external. The code then checks for the BlockType
of the saturation/up block. If it is not the right type, we call the
local replace function to replace the block. If we have added a constant, we
set the Value of that constant to use the uplim variable from the mask. A
similar action is repeated for the lower limit.
% saturation_init_cb Mask Initialization
function saturation_init_cb(blk,uplimsrc,uplim,...
lowlimsrc,lowlim)
% Check for upper limit source
switch uplimsrc
case 'external'
% Check for constant
if strcmp(get_param([blk '/up'],'BlockType'),...
'Constant')
replace([blk '/up'],'built-in/Inport');
end
case 'internal'
% Check for inport
if strcmp(get_param([blk '/up'],'BlockType'),...
'Inport')
replace([blk '/up'],'built-in/Constant')
set_param([blk '/up'],'Value','uplim')
end
end
% Check for lower limit source
switch lowlimsrc
case 'external'
% Check for constant
if strcmp(get_param([blk '/lo'],'BlockType'),...
'Constant')
replace([blk '/lo'],'built-in/Inport')
end
case 'internal'
% Check for inport
if strcmp(get_param([blk '/lo'],'BlockType'),...
'Inport')
replace([blk,'/lo'],'built-in/Constant')
set_param([blk '/lo'],'Value','lowlim')
end
end
The replace function gets the position and orientation from
the old block, deletes it and then adds the new block in its place.
% Local replace function
function replace(oldblock,newblock)
pos = get_param(oldblock,'Position');
orient = get_param(oldblock,'Orientation');
delete_block(oldblock);
add_block(newblock,oldblock,'Position',pos,...
'Orientation',orient);
Note, the replace_block function in Simulink could not be
used here because it is meant for model wide changes. While it is possible to
limit the affect of replace_block to a specific system, replace block doesn’t
work on library blocks. Self-modifiable masked blocks are library blocks, so this
is a common helper function used for this kind of mask.
Renumbering ports to control the order
The port number affects the order that the ports show up on
the outside of the block. Wires cross the boundary of the block and remain
connected through the inport that they are originally connected to. A port can
be inserted before or after existing ports on the block by changing the
numbering of all ports. The following code sets the port numbers by checking
the values of uplimsrc and lowlimsrc. When the upper limit source is external,
that will be the first port. If not, the first port is the u input. I can
keep track of the order and number of the ports by incrementing the numbering
variable each time I set a port number.
% Renumber ports
% when using external upper limit, % set blk/up port to 1
n = 1;
if strcmp(uplimsrc,'external')
set_param([blk '/up'],'Port',num2str(n))
n = 2; % increase n
end
% set u port to n
set_param([blk '/u'],'Port',num2str(n))
% when using external lower limit, % set blk/lo port to n+1
if strcmp(lowlimsrc,'external')
set_param([blk '/lo'],'Port',num2str(n+1))
end
Now it’s your turn
I have shared some of my best practices for programming
self-modifying blocks. What techniques have you used to program masks? Share
your comments here.
22:30 UTC |
Posted in Masking |
Permalink |
You can follow any responses to this entry through the RSS 2.0 feed.
You can skip to the end and leave a response. Pinging is currently not allowed.
Leave a Reply
|
 |
Seth Popinchalk is an Application Engineer for The MathWorks. He writes here about Simulink and other MathWorks tools used in Model-Based Design.
|
 |
|
I wonder how it is possible to define initial values for the parameters in the mask. for example your values “1″ and “-1″ for the upper and lower limit. how do you do this? when i define a parameter as ‘uplim = 1′ in the initialization window of the mask editor it still remains 0 when starting the model.
TIA,
Kai
@Kai - The initial value will be the last one you entered into the library block mask. When you work in the mask editor, all your parameters are initialized to 0, or the first option in a popup list. After you have completed designing the mask, close the mask editor, and while the library is still unlocked, set the value in the mask. Save the library, and this is now your default value. The next time you drag that block into your model, that initial value will be your parameter value.
Hi Seth,
Great graphics you got here. I especially like the first one, cool animated picture! I”m not a big simulink user, but I like the way you presented your information. Love the graphics.
Quan
I have used configurable subsystems in my library to provide a similar capability - one block provides multiple variations of basically the same functionality. The drawback with my approach is that the input ports are present whether they are used or not. It seems that this approach could provide similar functionality with a much cleaner finished model.
Can the two techniques be combined - i.e., can I update my configurable subsytems to remove unused inputs via self-modification without breaking all my existing models that use those blocks?
@Quan - Thanks for the compliment!
@Jim - The two methods can be combined. If you have large structural changes in your block algorithm, the configurable subsystem can be used to switch between them. It may be even easier to simply delete one block and replace it with the other, and then wire the ports appropriately.
Seth, I’m reading your post on self modifying blocks with great interest. I’d like to create a subsystem with a variable number of inputs, but am a novice at programming in simulinkese. My subsystem contains a mux to which the inputs will be connected. My mask for the subsystem will prompt for the number of inputs. So, since the new number of inputs may be more or less than the current number, I’m guessing I should start by removing all input ports and connectors from the input ports. I’m not sure how to find them however. Then I guess I would create new input ports, and sequentially connect them to the mux. I think I know how to do that. Any help you can provide would be great.
@Hans - I suggest that you aim to do the minimum work required to update the mask. Start by finding the existing inports:
s = find_system(gcb,’BlockType’,'Inport’)
Then delete some number of ports if you have too many, or add ports if you have too few. MaskInitialization code is called during many different operations. Every time you start the simulation, your block should merely check that the state of the blocks inside it match the values of the parameters in the mask. Update diagram can also happen DURING simulation (think, Pause and Restart). If your code just deletes all the ports, this will not be allowed. Good luck on making your mask.
I’ve created a simular subsystem. My problem is, that all connection lines are shifted, eyery time I open my modell or I want to simulate it. There are no connection to the Subsystem when I open it.
Any Idea?
@Jens - In situations where blocks end up disconnected I usually suspect that initialization code is deleting lines or blocks or both. Try to write conditional code to only delete the block if it needs to be replaced. If this doesn’t help, contact technical support and they may be able to help find the reason why.