Use Derived Data in Replacement Code Implementations
Some custom implementations that you can use for block replacement require data that is derived from the inputs, outputs, and parameters of the block. For example, an implementation function could require the dimensions of the input data. Input dimensions are not stored as a block parameter but can be computed from the input data. For block replacement, you define this computed data as a derived parameter by specifying a MATLAB® expression or multiple expressions that produce the value. When the code generator uses the block replacement, the generated code includes the derived parameter for the implementation function to use.
Derived Parameters for Block Replacement
To define a derived parameter, use a character vector expression of this form:
'varName = expression'
The left side of the equation specifies the variable name that the implementation function uses for the derived parameter.
The right side of the equation specifies an expression that the code generator evaluates in the MATLAB workspace.
The expression on the right side can use block inputs, outputs, block parameters that you define as block parameter arguments, or other derived parameters that you have already defined. Enter the input, output, or parameter name between the tokens
<%
and>
. If you use a block parameter, you must specify the data type to match the parameter as a block parameter argument.The expression on the right side can use MATLAB functions that are on the path and support code generation.
For example, these expressions define derived parameters that are calculated by using block parameter values, block inputs, and previously defined derived parameters:
'DiscreteFir_Coefficients = <%Coefficients>' % Coefficients is a block parameter 'coeffDim = size(<%Coefficients>)' % Coefficients is a block parameter 'dim1 = <%coeffDim>(1)' % coeffDim is a derived parameter defined above 'dim2 = <%coeffDim>(2)' % coeffDim is a derived parameter defined above 'DiscreteFir_InitialStates = <%InitialStates>' % InitialStates is a block parameter 'InputDim = size(<%u1>)' % u1 is a block input
DerivedBlockParams
vector of the RTW.TflBlockEntry
object.The basic workflow to add a derived parameter to a block entry is:
By default, the code generator generates the derived parameters as local variables in the implementation functions that use them. You can also store a derived parameter as a global DWork variable. For an example, see Use a Global Variable for a Derived Parameter.
If your implementation function uses an input data buffer to calculate the outputs, create a temporary buffer argument by using a derived parameter. Store the buffer as a global variable. For an example, see Create a Temporary Data Buffer by Using a Derived Parameter.
Limitations
These limitations apply to derived parameters:
The expression must not use DWork arguments within the left or right side of the equation.
The expression must not call a MATLAB function that creates a persistent variable.
Do not reuse derived parameter names. You can use the name of a derived parameter within the right side of the equation for another parameter, but you cannot use the same parameter name on the left side of multiple derived parameter equations.
Derived parameters do not support structures.
If a derived parameter requires a data type conversion, use an explicit
cast
orreinterpretcast
conversion.
Create a Block Replacement Entry for Code That Uses Derived Parameters
Examine the Model and Implementation Code
Determine which derived parameter arguments to use by examining your implementation code and the block(s) for which you want to replace the default generated code. For this example, consider this Discrete FIR Filter block:
The block is configured with these settings:
Property | Setting |
---|---|
Coefficient source | Dialog parameters |
Filter structure | Direct form |
Input processing | Columns as channels (frame based) |
For this example, replace the code generated from this block with custom implementation functions that have these signatures:
Initialization function signature:
void my_fir_init ( uint16_6 coefsSize, uint32_t blockSize )
Output function signature:
void my_fir ( float32_t *pSrc, uint32_t blockSize )
The arguments that are derived from block data in this example are:
coefsSize
— The number of coefficientsblockSize
— The length of the block input data
Create a Basic Block Replacement Entry
In a code replacement table, create a block replacement entry object. Specify the conceptual criteria for the entry to match, including the block key, block parameter settings, and block inputs and outputs. In a later step, you specify additional conceptual criteria for the derived parameters. For an example that shows how to create a basic block replacement entry, see Replace Code Generated from Discrete FIR Filter Blocks.
function hTable = crl_table_derived_params % Create a function to call the code replacement library table %% Create a table object hTable = RTW.TflTable; %% Create an entry hEntry = RTW.TflBlockEntry; %% Specify block Key hEntry.Key = 'DiscreteFir'; %% Specify Block Parameter Values to Match prop1 = RTW.BlockProperty("CoefSource","Dialog parameters"); addBlockProperty(hEntry,prop1); prop2 = RTW.BlockProperty("FilterStructure","Direct form"); addBlockProperty(hEntry,prop2); prop3 = RTW.BlockProperty("InputProcessing","Columns as channels (frame based)"); addBlockProperty(hEntry,prop3); %% Add block inputs and outputs to match % Input signal port argInput1 = RTW.TflArgMatrix("u1","RTW_IO_INPUT","single"); argInput1.DimRange = [1 1; Inf 1]; hEntry.addConceptualArg(argInput1); % Output signal port argOutput = RTW.TflArgMatrix("u1","RTW_IO_OUTPUT","single"); argOutput.DimRange = [1 1; Inf 1]; hEntry.addConceptualArg(argOutput);
Create implementation objects that represent the implementation functions by calling
RTW.CImplementation
. Specify the basic properties of the implementation
functions, including the function name and header file. Add this code, and the code in
later steps, in the same code replacement table file that you created.
% Initialization function arm_fir_init_f32 initImpl = RTW.CImplementation(); initImpl.Name = 'my_fir_init'; initImpl.HeaderFile = 'my_fir.h'; % Output function arm_fir_f32 outImpl = RTW.CImplementation(); outImpl.Name = 'my_fir'; outImpl.HeaderFile = 'my_fir.h';
You use these implementation objects to specify the derived parameters that the implementation functions use.
Add Derived Parameter Expressions to the Entry
For each derived parameter, write the expression that produces the derived data,
following the requirements described in Derived Parameters for Block Replacement. Specify each
expression as one value in the DerivedBlockParams
vector of the RTW.TflBlockEntry
object.
For example, add the expression that produces the data for the
coefsSize
argument from the length of the block parameter
Coefficients
:
%% Add derived parameter arguments % coefsSize hEntry.DerivedBlockParams{end+1} = 'coefsSize = length(<%Coefficients>)';
Next, add the expression that produces the data for the blockSize
argument from the length of the input
data:
% blockSize hEntry.DerivedBlockParams{end+1} = 'blockSize = length(<%u1>)';
Add Derived Parameter Arguments to Implementation Function Specifications
Specify the data type of each argument by creating an argument handle and specifying
the derived parameter name and the data type. Then add the argument to the implementation
object that you created for the function by using the addArgument
function.
% Init function - coefsSize coefsSizeArg = getTflArgFromString(hTable,'coefsSize','uint16'); addArgument(initImpl,coefsSizeArg); % Init & Out functions - blockSize blockSizeArg = getTflArgFromString(hTable,'blockSize','uint32'); addArgument(initImpl,blockSizeArg); addArgument(outImpl,blockSizeArg);
Add Block Parameter Arguments to the Entry
For each block parameter value used by the derived parameter expressions, add the block parameter to the conceptual representation as a block parameter argument. Adding a block parameter argument to the conceptual representation enables the code generator to match only blocks that have parameter data types that match the data types required by the derived parameter expressions and implementation functions.
For this example, add a block parameter argument for the
Coefficients
parameter, which is used to calculate the derived
parameter coefsSize
. Specify that the argument should be a matrix with
type int16
.
blockParamArg = RTW.TflArgMatrix('Coefficients','RTW_IO_INPUT','int16'); addBlockParamArg(hEntry,blockParamArg);
Complete the Implementation Objects and Add Them to the Entry
Complete the implementation representation objects by adding the other arguments. For
this example, add the input argument for the output function by calling addArgument
.
arg = getTflArgFromString(hTable,'u1','single*'); addArgument(outImpl,arg);
Once you have specified the arguments, including regular arguments and derived
parameter arguments, for each implementation function, add the implementation objects to
the block replacement entry by calling addImplementation
.
%% Add implementation functions to entry object addImplementation(hEntry,'initialize',initImpl); addImplementation(hEntry,'output',outImpl);
Add the entry to the table.
addEntry(hTable,hEntry);
Register and apply the code replacement library as described in Validate and Register the Code Replacement Library.
Create a Temporary Data Buffer by Using a Derived Parameter
If your implementation function performs precalculations on an input data buffer, create a temporary buffer argument by using a derived parameter.
Add the derived parameter expression to the block replacement entry object. For this example, add the parameter
tempBuffer
that stores the value pre-calculated from the value of the first block input.precalculateFunc
is an example custom function that performs the precalculation.blockEntry.DerivedBlockParams{end+1} = 'tempBuffer = precalculateFunc<%u1>';
Create an argument object from the derived parameter by using
getTflArgFromString
. Specify the data type for the parameter.bufferArg = getTflArgFromString(hTable, 'tempBuffer', 'single*');
Create an
RTW.CImplementation
object and add the argument to the object by using theaddArgument
function.implementationFunc = RTW.CImplementation; addArgument(implementationFunc, bufferArg);
The code generator generates a temporary buffer tempBuffer
that is initialized with the first block input values. tempBuffer
has the
same dimensions as input u1
and will use a data type cast if the base
type of u1
is not single
.
Use a Global Variable for a Derived Parameter
By default, the code generator generates the derived parameters as local variables in the implementation functions that use them. To store a derived parameter as a global variable:
Add the derived parameter expression to the block replacement entry object. For this example, add the parameter
coeffs
that stores the preprocessed coefficient vector derived from the block parametersBiQuadCoeffs
andScaleValues
.blockEntry.DerivedBlockParams{end+1} = 'coeffs = preprocess(<%BiQuadCoeffs>,<%ScaleValues>)';
Create an argument object from the derived parameter by using
getTflArgFromString
. Specify the data type for the parameter.globalArg = getTflArgFromString(hTable, 'coeffs', 'single*');
For the argument object, set
PersistData
totrue
.globalArg.PersistData = true;
Create an
RTW.CImplementation
object for the implementation function and add the argument to the object by using theaddArgument
function.implementationFunc = RTW.CImplementation; addArgument(implementationFunc, globalArg);
The code generator generates the global variable coeffs
as
a DWork vector.
See Also
RTW.TflBlockEntry
| RTW.BlockProperty
| RTW.CImplementation