In Simulink®, you can create your own block libraries as a way to reuse the functionality of blocks or subsystems in one or more models. If you want to reuse a set of MATLAB® algorithms in Simulink models, you can encapsulate your MATLAB code in a MATLAB Function block library.
As with other Simulink block libraries, you can specialize each instance of MATLAB Function library blocks in your model to use different data types, sample times, and other properties. Library instances that inherit the same properties can reuse generated code
Here is a basic workflow for creating custom block libraries with MATLAB Function blocks. To work through these steps with an example, see Example: Creating a Custom Signal Processing Filter Block Library.
Add polymorphic MATLAB code to MATLAB Function blocks in a Simulink model.
Polymorphic code is code that can process data with different properties, such as type, size, and complexity.
Configure the blocks to inherit the properties you want to specialize.
For a list of properties you can specialize, see Properties You Can Specialize Across Instances of Library Blocks.
Optionally, customize your library code using masking.
Add instances of MATLAB Function library blocks to a Simulink model.
Note
If your MATLAB Function block library is masked, you cannot modify contents of the block with mask initialization code. The Allow library block to modify its contents option in the Mask dialog box is not supported for MATLAB Function block libraries.
Step 1: Add the Filter Algorithms to MATLAB Function Library Blocks
Step 2: Configure Blocks to Inherit Properties You Want to Specialize
Step 4: Add Instances of MATLAB Library Blocks to a Simulink Model
This simple example takes you through the workflow described in How to Create Custom MATLAB Function Block Libraries to show you how to:
Create a library of signal processing filter algorithms using MATLAB Function blocks
Customize one of the library blocks using mask parameters
Convert one of the filter algorithms to source-protected P-code that you can call from a MATLAB Function library block
The MATLAB filter algorithms are:
my_fft. Performs a discrete Fourier transform on an input signal. The input can be a vector, matrix, or multidimensional array whose length is a power of 2.
my_conv. Convolves two input vector signals. Outputs a subsection of
the convolution with a size specified by a mask parameter, Shape
.
my_sobel. Convolves a 2D input matrix with a Sobel edge detection filter.
In Simulink, create a library model. On the Simulation tab, select New > Library
Drag three MATLAB Function blocks into the model from the User-Defined Functions section of the Simulink Library Browser and name them:
my_fft_filter
my_conv_filter
my_sobel_filter
Save the library model as my_filter_lib
.
Open the MATLAB Function block named my_fft_filter
,
replace the template code with the following code, and save the block:
function y = my_fft(x) y = fft(x);
Replace the template code in my_conv_filter
block
with the following code and save the block:
function c = my_conv(a, b) c = conv(a, b);
Replace the template code in my_sobel_filter
block
with the following code and save the block:
function y = my_sobel(u) %% "my_sobel_filter" is a MATLAB function %% on the MATLAB path. y = my_sobel_filter(u);
The my_sobel
function acts as a wrapper that
calls a MATLAB function, my_sobel_filter
,
on the code generation path. my_sobel_filter
implements
the algorithm that convolves a 2D input matrix with a Sobel edge detection
filter. By calling the function rather than inlining the code directly
in the MATLAB Function block, you can reuse the algorithm
both as MATLAB code and in a Simulink model. You will create my_sobel_filter
next.
In the same folder where you created my_filter_lib
,
create a new MATLAB function my_sobel_filter
with
the following code:
function y = my_sobel_filter(u) % Sobel edge detection filter h = [1 2 1;... 0 0 0;... -1 -2 -1]; y = abs(conv2(u, h));
Save the file as my_sobel_filter.m
.
In this example, the data in the signal processing filter algorithms must inherit size, type, and complexity from the Simulink model. By default, data in MATLAB Function blocks inherit these properties. To explicitly configure data to inherit properties:
Open a MATLAB Function block and select Edit Data.
In the left pane of the Ports and Data Manager, select the data of interest.
In the right pane, configure the data to inherit properties from Simulink:
To Inherit | What to Specify |
---|---|
Size | Enter -1 in Size field |
Complexity | Select Inherited from the Complexity menu |
Type | Select Inherit: Same as Simulink from the Type menu |
For example, if you open the MATLAB Function block my_fft_filter and
look at the properties of input x
in the Ports
and Data Manager, you see that size, type, and complexity are inherited
by default.
Note
If your design has specific requirements or constraints, you can enter values for any of these properties, rather than inherit them from Simulink. For example, if your algorithm is not supposed to work with complex inputs, set Complexity to Off.
In this exercise you will modify the convolution filter my_conv
to
use a custom parameter shape
that specifies what
subsection of the convolution to output. To customize this algorithm
for your library, place the my_conv_filter
block
under a masked subsystem and define shape
as a
mask parameter.
Convert the block to a masked subsystem:
Right-click the my_conv_filter block and select Subsystem & Model Reference > Create Subsystem from Selection.
The my_conv_filter block changes to a subsystem block.
Change the name of the subsystem to my_conv_filter.
Right-click the my_conv_filter subsystem and select Mask > Create Mask from the context menu.
The Mask Editor appears with the Icon & Ports tab open.
Enter in the Icon drawing commands text box:
disp('my_conv'); port_label('output', 1, 'c'); port_label('input', 1, 'a'); port_label('input', 2, 'b');
Select the Parameters & Dialog tab.
Highlight the Parameters line item in the Dialog box pane.
Add a popup-type parameter by clicking Popup under the Parameter list in the Controls pane.
A new parameter will appear in the Dialog box pane.
In the Property editor pane, set the Properties:
Property | Value |
---|---|
Name | shape |
Value | full |
Prompt | shape |
Type | popup |
Type options | Open the Type Options Editor and enter:full same valid |
Set the Attributes, Dialog, and Layout properties in the Property editor pane:
Attributes, Dialog, and Layout Items | Value |
---|---|
Attributes |
|
Dialog |
|
Layout |
|
Click OK.
Your subsystem should now look like this:
Set subsystem properties for code reuse:
Right-click the my_conv_filter subsystem and select Block Parameters (Subsystem) from the context menu.
In the subsystem parameters dialog box, select the Treat as atomic unit check box.
The dialog box expands to display new fields.
To generate a reusable function, select the Code Generation
tab and in the Function packaging field, select Reusable
function
from the drop-down menu.
Note
This is an optional step, required for this example. If you leave the default setting of Auto, the code generation software uses an internal rule to determine whether to inline the function or not.
Click OK.
Define the shape
parameter in the MATLAB Function my_conv
:
Right-click the my_conv_filter subsystem and select Mask > Look Under Mask from the context menu.
The block diagram under the masked subsystem opens, containing the my_conv_filter block:
Change the names of the port blocks to match the data names as follows:
Change: | To: |
---|---|
In1 | a |
In2 | b |
Out1 | c |
Double-click the my_conv_filter block to open the MATLAB Function Block Editor.
In the MATLAB Function Block Editor, select Edit Data.
In the Ports and Data Manager, select Add > Data.
A new data element appears selected, along with its properties dialog.
Enter the following properties:
Property | What To Specify |
---|---|
Name | Enter shape . |
Scope | Select Parameter. |
Tunable | Clear the box. |
Leave Size, Complexity, and Type as inherited (the defaults), as described in Step 2: Configure Blocks to Inherit Properties You Want to Specialize.
Click Apply, close the Ports and Data Manager, and return to the MATLAB Function Block Editor.
Use the shape
parameter to determine
the size of the convolution to output:
In the MATLAB Function Block Editor, modify the my_conv
function
to call conv
with the right shape:
function c = my_conv(a, b, shape) if shape == 1 c = conv(a, b, 'full'); elseif shape == 2 c = conv(a, b, 'same'); else c = conv(a, b, 'valid'); end
Save your changes and close the MATLAB Function Block Editor.
In this exercise, you will add specialized instances of the my_conv_filter library block to a simple test model.
Open a new Simulink model.
For purposes of this exercise, set the following configuration parameters for simulation:
Pane | Section | What to Specify |
---|---|---|
Solver | Solver selection |
|
Data Import/Export | Save options | Structure for Format |
Drag two instances of the my_conv_filter block
from the my_filter_lib
library into the model.
Add Constant, Outport, and Display blocks. Your model should look something like this:
Both library instances share the same size, type,
and complexity for inputs a
and b
respectively.
Double-click each library instance.
The shape
parameter defaults to full for
both instances.
Simulate the model.
Each library instance outputs the same result, the full 2D convolution:
Specialize the second instance, my_conv_filter1 by
setting the value of its shape
parameter to same.
Now simulate the model again.
This time, the outputs have different sizes: my_conv_filter3 outputs
the full 2D convolution, while my_conv_filter1 displays
the central part of the convolution as a 1-by-2 vector, the same size
as a
:
Now, add a third instance by copying my_conv_filter1. Specialize the new instance, my_conv_filter2, so that it does not inherit the same size inputs as the first two instances:
Simulate the model again.
This time, my_conv_filter1 and my_conv_filter2 each
display the central part of the convolution, but the output sizes
are different because each matches a different sized input a
.
When instances of MATLAB Function library blocks inherit the same properties, they can reuse generated code, as illustrated by an example based on Step 4: Add Instances of MATLAB Library Blocks to a Simulink Model:
In this model, the library instances my_conv_filter and my_conv_filter1 inherit
the same size, type, and complexity for each respective input. For
each instance, input a
is a 1-by-2 vector and input b
is
a 1-by-5 vector. By comparison, the inputs of my_conv_filter2 inherit
different respective sizes; both are 1-by-3 vectors.
In addition, each library instance has a mask parameter called shape that determines what subsection of the convolution to output. Assume that the value of shape is the same for each instance.
To generate code for this example, follow these steps:
Enable code reuse for the library block:
In the library, right-click the MATLAB Function block my_conv_filter and select Block Parameters (Subsystem) from the context menu.
In the Function Block Parameters dialog box, set these parameters:
Select the Treat as atomic unit check box.
In the Function packaging field,
select Reusable function
from the drop-down
menu.
Configure the model for code generation.
For purposes of this exercise, set the following configuration parameters:
Pane | Section | What to Specify |
---|---|---|
Code Generation | Target selection | Enter ert.tlc for System
target file |
Code Generation > Report | Select Create code generation report check box. |
Build the model.
If you build this model, the generated C code reuses logic for
the my_conv_filter
and my_conv_filter1
library
instances because they inherit the same input properties:
/* * Output and update for atomic system: * '<Root>/my_conv_filter' * '<Root>/my_conv_filter1' */ void sp_algorithm_tes_my_conv_filter(const real32_T rtu_a[2], const real32_T rtu_b[5], rtB_my_conv_filter_sp_algorithm *localB) { int32_T jA; int32_T jA_0; real32_T s; int32_T jC; /* MATLAB Function Block: '<S1>/my_conv_filter' */ /* MATLAB Function 'my_conv_filter/my_conv_filter': '<S4>:1' */ /* '<S4>:1:4' */ for (jC = 0; jC < 6; jC++) { if (5 < jC + 2) { jA = jC - 4; } else { jA = 0; } if (2 < jC + 1) { jA_0 = 2; } else { jA_0 = jC + 1; } s = 0.0F; while (jA + 1 <= jA_0) { s += rtu_b[jC - jA] * rtu_a[jA]; jA++; } localB->c[jC] = s; } /* end of MATLAB Function Block: '<S1>/my_conv_filter' */ } |
However, a separate function is generated for my_conv_filter2:
/* Output and update for atomic system: '<Root>/my_conv_filter2' */ void sp_algorithm_te_my_conv_filter2(const real_T rtu_a[3], const real_T rtu_b[3], rtB_my_conv_filter_sp_algorit_h *localB) { int32_T jA; int32_T jA_0; real_T s; int32_T jC; /* MATLAB Function Block: '<S3>/my_conv_filter' */ /* MATLAB Function 'my_conv_filter/my_conv_filter': '<S6>:1' */ /* '<S6>:1:4' */ for (jC = 0; jC < 5; jC++) { if (3 < jC + 2) { jA = jC - 2; } else { jA = 0; } if (3 < jC + 1) { jA_0 = 3; } else { jA_0 = jC + 1; } s = 0.0; while (jA + 1 <= jA_0) { s += rtu_b[jC - jA] * rtu_a[jA]; jA++; } localB->c[jC] = s; } /* end of MATLAB Function Block: '<S3>/my_conv_filter' */ } |
Note
Generating C code for this model requires a Simulink Coder™ or Embedded Coder® license.
You debug MATLAB Function library blocks the same way you debug any MATLAB Function block. However, when you add a breakpoint in a library block, the breakpoint is shared by all instances. As you continue execution, the debugger stops at the breakpoint in each instance.
You can specialize instances of MATLAB Function library blocks by allowing them to inherit any of the following properties from Simulink:
Property | Inherits by Default? | How to Specify Inheritance |
---|---|---|
Type | Yes | Set data type property to Inherit: Same as Simulink. |
Size | Yes | Set data size property to -1. |
Complexity | Yes | Set data complexity property to Inherited. |
Limit range | No | Specify minimum and maximum values as Simulink parameters. For example, if minimum value = aParam and
maximum value = aParam + 3, different instances
of a MATLAB Function library block can resolve to different aParam parameters
defined in their parent mask subsystems. |
Sampling mode (input) | Yes | MATLAB Function block input ports always inherit sampling mode |
Data type override mode for fixed-point data | Yes | Set data type override property to Inherit. |
Sample time (block) | Yes | Set block sample time property to -1. |