Example: Creating a Custom Signal Processing Filter Block Library

Properties You Can Specialize Across Instances of Library Blocks

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.

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 by selecting

**File**>**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 fieldComplexity Select **Inherited**from the Complexity menuType 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.

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**Evaluate: Checked

Tunable: Cleared

Read only: Cleared

Hidden: Cleared

Never save: Cleared

**Dialog**Enable: Checked

Visible: Checked

Callback: no entry

**Layout**Item location: Grayed out

Prompt location: Left

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 options**Select

**Fixed-Step**for**Type**Select

**discrete (no continuous states)**for**Solver**Enter

**1**for**Fixed-step size**

**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' */ }

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. |

Was this topic helpful?