Products & Services Solutions Academia Support User Community Company

Learn more about Simulink   

Tutorial: Creating a Custom Block

How to Design a Custom Block

In general, you use the following process to design a custom block:

  1. Define the behavior required by the custom block.

  2. Decide which custom block type to use.

  3. Determine if the block should reside in a library.

  4. Add a graphical user interface to the block.

Suppose you want to create a customized saturation block that limits the upper and lower bounds of a signal based on either a block parameter or the value of an input signal. In a second version of the block, you want the option to plot the saturation limits after the simulation is finished. The following tutorial steps you through designing these blocks. The library customsat_lib.mdl contains the two versions of the customized saturation block.

The example model sldemo_customsat.mdl uses the basic version of the block.

Defining Custom Block Behavior

Begin by defining the features and limitations of your custom block. In this example, the block supports the following features:

It also has the following restrictions:

Deciding on a Custom Block Type

Based on the custom block's features, the implementation needs to support the following:

Therefore, this tutorial implements the custom block using a Level-2 M-file S-function. M-file S-functions support multiple inputs and, because the algorithm is simple, do not have significant overhead when updating the diagram or simulating the model. See Comparison of Custom Block Functionality for a description of the different functionality provided by M-file S-functions as compared to other types of custom blocks.

Parameterizing the M-File S-Function

Begin by defining the S-function parameters. This example requires four parameters:

The first and third S-function parameters represent modes that must be translated into values the S-function can recognize. Therefore, define the following values for the upper and lower saturation limit modes:

Writing the M-File S-Function

Once the S-function parameters and functionality are defined, write the S-function. The template msfuntmpl.m provides a starting point for writing a Level-2 M-file S-function. You can find a completed version of the custom saturation block in the file custom_sat.m. Save this file to your working directory before continuing with this tutorial.

This S-function modifies the S-function template as follows:

Placing Custom Blocks in a Library

Libraries allow you to share your custom blocks with other users, easily update the functionality of copies of the custom block, and collect blocks for a particular project into a single location. This example places the custom saturation block into a library as follows:

  1. Open a new Simulink library (see Creating a Library).

  2. Add a new Level-2 M-file S-Function block from the Simulink User-Defined Functions library into your new library.

  3. Double-click the block to open its Block Parameters dialog box. Enter the name of the S-function custom_sat into the M-file name field.

  4. Enter the following default values into the Parameters field.

    2,-1,2,1
  5. Click OK on the Block Parameters dialog box.

  6. Save the library to your working directory as saturation_lib.mdl. The following figure shows the resulting custom saturation block library.

At this point, you have created a custom saturation block that can be shared with other users. You can make the block easier to use by adding a customized graphical user interface.

Adding a Graphical User Interface to a Custom Block

You can create a simple block dialog for the custom saturation block using the provided masking capabilities. Masking the block also allows you to add port labels to indicate which port corresponds to the input signal and the saturation limits.

To mask the block:

  1. Right-click the custom saturation block in saturation_lib.mdl and select Mask M-file S-Function from the context menu. The Mask Editor opens.

  2. On the Icon pane, enter the following into Drawing commands.

    port_label('input',1,'uSig')

    This command labels the default port as the input signal under saturation.

  3. On the Parameters pane, add four parameters corresponding to the four S-function parameters. From top to bottom, set up each parameter's properties as follows.

    PromptVariableTypeTunablePopupsAction for Dialog Callback
    Upper boundary:upModepopupNoNo limit | Enter limit as parameter | Limit using input signal'upperbound_callback'
    Upper limit:upValeditYesN/A'upperparam_callback'
    Lower boundary:lowModepopupNoNo limit | Enter limit as parameter | Limit using input signal'lowerbound_callback'
    Lower limit:lowValeditYesN/A'lowerparam_callback'

    The dialog callback is invoked using the action string in the following command:

    customsat_callback(action,gcb)

    The M-file customsat_callback.m contains the mask parameter callbacks. If you are stepping through this tutorial, open this file and save it to your working directory. This M-file, described in detail later, has two input arguments. The first input argument is a string indicating which mask parameter invoked the callback. The second input argument is the handle to the associated Level-2 M-file S-Function block.

    The following figure shows the final Parameters pane in the Mask Editor.

  4. On the Mask Editor's Initialization pane, select Allow library block to modify its contents. This setting allows the S-function to change the number of ports on the block.

  5. On the Documentation pane:

    • Enter Customized Saturation into the Mask type field.

    • Enter the following into the Mask description field.

    Limit the input signal to an upper and lower saturation value
    set either through a block parameter or input signal.
  6. Click OK on the Mask Editor to complete the mask parameters dialog.

  7. To map the S-function parameters to the mask parameters, right-click the Level-2 M-file S-Function block and select Look Under Mask. The Level-2 M-file S-Function Block Parameters dialog box opens.

  8. Change the entry in the Parameters field as follows.

    lowMode,lowVal,upMode,upVal

    The following figure shows the new Block Parameters dialog.

  9. Click OK on the Level-2 M-file S-Function Block Parameters dialog box. Double-clicking the new version of the customized saturation block opens the mask parameter dialog box shown in the following figure.

To create a more complicated graphical user interface, place a Handle Graphics user interface on top of the masked block. The block's OpenFcn would invoke the Handle Graphics user interface, which uses calls to set_param to modify the S-function block's parameters based on settings in the user interface.

Writing the Mask Callback

The function customsat_callback.m contains the mask callback code for the custom saturation block's mask parameter dialog box. This function invokes subfunctions corresponding to each mask parameter through a call to feval.

The following subfunction controls the visibility of the upper saturation limit's field based on the selection for the upper saturation limit's mode. The callback begins by obtaining values for all mask parameters using a call to get_param with the property name MaskValues. If the callback needed the value of only one mask parameter, it could call get_param with the specific mask parameter name, for example, get_param(block,'upMode'). Because this example needs two of the mask parameter values, it uses the MaskValues property to reduce the calls to get_param.

The callback then obtains the visibilities of the mask parameters using a call to get_param with the property name MaskVisbilities. This call returns a cell array of strings indicating the visibility of each mask parameter. The callback alters the values for the mask visibilities based on the selection for the upper saturation limit's mode and then updates the port label string.

The callback finally uses the set_param command to update the block's MaskDisplay property to label the block's input ports.

function customsat_callback(action,block)
% CUSTOMSAT_CALLBACK contains callbacks for custom saturation block

%   Copyright 2003-2007 The MathWorks, Inc.

%% Use function handle to call appropriate callback
feval(action,block)

%% Upper bound callback
function upperbound_callback(block)

vals = get_param(block,'MaskValues');
vis = get_param(block,'MaskVisibilities');
portStr = {'port_label(''input'',1,''uSig'')'};
switch vals{1}
    case 'No limit'
        set_param(block,'MaskVisibilities',[vis(1);{'off'};vis(3:4)]);
    case 'Enter limit as parameter'
        set_param(block,'MaskVisibilities',[vis(1);{'on'};vis(3:4)]);
    case 'Limit using input signal'
        set_param(block,'MaskVisibilities',[vis(1);{'off'};vis(3:4)]);
        portStr = [portStr;{'port_label(''input'',2,''up'')'}];
end
if strcmp(vals{3},'Limit using input signal'),
    portStr = [portStr;{['port_label(''input'',',num2str(length(portStr)+1), ...
        ',''low'')']}];
end
set_param(block,'MaskDisplay',char(portStr));

The final call to set_param invokes the setup function in the M-file S-function custom_sat.m. Therefore, the setup function can be modified to set the number of input ports based on the mask parameter values instead of on the S-function parameter values. This change to the setup function keeps the number of ports on the Level-2 M-File S-Function block consistent with the values shown in the mask parameter dialog box.

The modified M-file S-function custom_sat_final.m contains the following new setup function. If you are stepping through this tutorial, open the file and save it to your working directory.

%% Function: setup ===================================================
function setup(block)

% Register original number of ports based on settings in Mask Dialog
ud = getPortVisibility(block);
numInPorts = 1 + isequal(ud(1),3) + isequal(ud(2),3);

block.NumInputPorts = numInPorts;
block.NumOutputPorts = 1;

% Setup port properties to be inherited or dynamic
block.SetPreCompInpPortInfoToDynamic;
block.SetPreCompOutPortInfoToDynamic;

% Override input port properties
block.InputPort(1).DatatypeID  = 0;  % double
block.InputPort(1).Complexity  = 'Real';

% Override output port properties
block.OutputPort(1).DatatypeID  = 0; % double
block.OutputPort(1).Complexity  = 'Real';

% Register parameters. In order:
% -- If the upper bound is off (1) or on and set via a block parameter (2)
%    or input signal (3)
% -- The upper limit value. Should be empty if the upper limit is off or
%    set via an input signal
% -- If the lower bound is off (1) or on and set via a block parameter (2)
%    or input signal (3)
% -- The lower limit value. Should be empty if the lower limit is off or
%    set via an input signal
block.NumDialogPrms     = 4;
block.DialogPrmsTunable = {'Nontunable','Tunable','Nontunable','Tunable'};

% Register continuous sample times [0 offset]
block.SampleTimes = [0 0];

%% -----------------------------------------------------------------
%% Options
%% -----------------------------------------------------------------
% Specify if Accelerator should use TLC or call back into
% M-file
block.SetAccelRunOnTLC(false);

%% -----------------------------------------------------------------
%% Register methods called during update diagram/compilation
%% -----------------------------------------------------------------

block.RegBlockMethod('CheckParameters',      @CheckPrms);
block.RegBlockMethod('ProcessParameters',    @ProcessPrms);
block.RegBlockMethod('PostPropagationSetup', @DoPostPropSetup);
block.RegBlockMethod('Outputs',              @Outputs);
block.RegBlockMethod('Terminate',            @Terminate);
%endfunction

The getPortVisibility subfunction in custom_sat_final.m uses the saturation limit modes to construct a flag that is passed back to the setup function. The setup function uses this flag to determine the necessary number of input ports.

%% Function: Get Port Visibilities =======================================
function ud = getPortVisibility(block)

ud = [0 0];

vals = get_param(block.BlockHandle,'MaskValues');
switch vals{1}
    case 'No limit'
        ud(2) = 1;
    case 'Enter limit as parameter'
        ud(2) = 2;
    case 'Limit using input signal'
        ud(2) = 3;
end

switch vals{3}
    case 'No limit'
        ud(1) = 1;
    case 'Enter limit as parameter'
        ud(1) = 2;
    case 'Limit using input signal'
        ud(1) = 3;
end

Updating the Library

Update the library saturation_lib.mdl so that it calls custom_sat_final.m.

  1. Right-click the Level-2 M-file S-Function block in saturation_lib.mdl and select Look Under Mask. The Level-2 M-file S-Function Block Parameters dialog box opens.

  2. Enter custom_sat_final in the M-file name field, as shown in the following figure.

  3. Click OK on the Block Parameters dialog box.

Adding Block Functionality Using Block Callbacks

The User-Defined Saturation with Plotting block in customsat_lib.mdl uses block callbacks to add functionality to the original custom saturation block. This block provides an option to plot the saturation limits when the simulation ends. The following steps show how to modify the original custom saturation block to create this new block.

  1. Add a check box to the mask parameter dialog box to toggle the plotting option on and off, as shown in the following figure.

    To add this check box:

    1. Right-click the Level-2 M-file S-Function block in saturation_lib.mdl and select Edit Mask.

    2. On the Mask Editor's Parameters pane, add a fifth mask parameter with the following properties.

      PropertyValue
      PromptPlot saturation limits
      Variableplotcheck
      Typecheckbox
      TunableNo
      Dialog callbackcustomsat_callback('plotsaturation',gcb);

    3. Click OK on the Mask Editor.

  2. Write a callback for the new check box. The callback initializes a structure to store the saturation limit values during simulation in the Level-2 M-File S-Function block's UserData. The M-file customsat_plotcallback.m contains this new callback, as well as modified versions of the previous callbacks to handle the new mask parameter. If you are following through this example, open customsat_plotcallback.m and copy its subfunctions over the previous subfunctions in customsat_callback.m.

    %% Plotting checkbox callback
    function plotsaturation(block)
    
    % Reinitialize the block's userdata
    vals = get_param(block,'MaskValues');
    ud = struct('time',[],'upBound',[],'upVal',[],'lowBound',[],'lowVal',[]);
    
    if strcmp(vals{1},'No limit'),
        ud.upBound = 'off';
    else
        ud.upBound = 'on';
    end
    
    if strcmp(vals{3},'No limit'),
        ud.lowBound = 'off';
    else
        ud.lowBound = 'on';
    end
    
    set_param(gcb,'UserData',ud);
  3. Update the M-file S-function's Outputs method to store the saturation limits, if applicable, as done in the new M-file S-function custom_sat_plot.m. If you are following through this example, copy the Outputs method in custom_sat_plot.m over the original Outputs method in custom_sat_final.m

    %% Function: Outputs ===================================================
    function Outputs(block)
    
    lowMode    = block.DialogPrm(1).Data;
    upMode     = block.DialogPrm(3).Data;
    sigVal     = block.InputPort(1).Data;
    vals = get_param(block.BlockHandle,'MaskValues');
    plotFlag = vals{5};
    lowPortNum = 2;
    
    % Check upper saturation limit
    if isequal(upMode,2)
        upVal = block.RuntimePrm(2).Data;
    elseif isequal(upMode,3)
        upVal = block.InputPort(2).Data;
        lowPortNum = 3; % Move lower boundary down one port number
    else
        upVal = inf;
    end
    
    % Check lower saturation limit
    if isequal(lowMode,2),
        lowVal = block.RuntimePrm(1).Data;
    elseif isequal(lowMode,3)
        lowVal = block.InputPort(lowPortNum).Data;
    else
        lowVal = -inf;
    end
    
    % Use userdata to store limits, if plotFlag is on
    if strcmp(plotFlag,'on');    
        ud = get_param(block.BlockHandle,'UserData');
        ud.lowVal = [ud.lowVal;lowVal];
        ud.upVal = [ud.upVal;upVal];
        ud.time = [ud.time;block.CurrentTime];
        set_param(block.BlockHandle,'UserData',ud)
    end
    
    % Assign new value to signal
    if sigVal > upVal,
        sigVal = upVal;
    elseif sigVal < lowVal,
        sigVal=lowVal;
    end
    
    block.OutputPort(1).Data = sigVal;
    
    %endfunction
  4. Write the function plotsat.m to plot the saturation limits. This function takes the handle to the Level-2 M-File S-Function block and uses this handle to retrieve the block's UserData. If you are following through this tutorial, save plotsat.m to your working directory.

    function plotSat(block)
    
    % PLOTSAT contains the plotting routine for custom_sat_plot
    %   This routine is called by the S-function block's StopFcn.
    
    ud = get_param(block,'UserData');
    fig=[];
    if ~isempty(ud.time)
        if strcmp(ud.upBound,'on')
            fig = figure;
            plot(ud.time,ud.upVal,'r');
            hold on
        end
        if strcmp(ud.lowBound,'on')
            if isempty(fig),
                fig = figure;
            end
            plot(ud.time,ud.lowVal,'b');
        end
        if ~isempty(fig)
            title('Upper bound in red. Lower bound in blue.')
        end
        
        % Reinitialize userdata
        ud.upVal=[];
        ud.lowVal=[];
        ud.time = [];
        set_param(block,'UserData',ud);
    end
  5. Right-click the Level-2 M-file S-Function block and select Block Properties. The Block Properties dialog box opens. On the Callbacks pane, modify the StopFcn to call the plotting callback as shown in the following figure, then click OK.

  


Related Products & Applications

Learn more about Simulink through this collection of videos, articles, technical literature and the Getting Started with Simulink Guide.

 © 1984-2009- The MathWorks, Inc.    -   Site Help   -   Patents   -   Trademarks   -   Privacy Policy   -   Preventing Piracy   -   RSS