Main Content

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 calculation of the data for the implementation function to use.

Derived Parameters for Block Replacement

In block replacement, you describe a derived parameter by using a MATLAB expression or multiple expressions that produce the value when evaluated in the workspace. The string expression must have 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

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 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 or reinterpretcast 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:

Discrete FIR Filter block with one input and one output.

The block is configured with these settings:

  • Coefficient sourceDialog parameters

  • Filter structureDirect form

  • Input processingColumns 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
    )

Some arguments that the implementation functions use are derived from block data. In the block replacement workflow, these are called derived parameters. Note the arguments that are derived from block data in this example:

  • coefsSize - The number of coefficients

  • blockSize - 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 general 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 function 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);

 Code Replacement Table File

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 pre-calculations on an input data buffer, create a temporary buffer argument by using a derived parameter.

  1. Add the derived parameter expression to the block 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>';

  2. Create an argument object from the derived parameter by using getTflArgFromString. Specify the data type for the parameter.

    bufferArg = getTflArgFromString(hTable, 'tempBuffer', 'single*');

  3. Create an RTW.CImplementation object and add the argument to the object by using the addArgument 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:

  1. Add the derived parameter expression to the block entry object. For this example, add the parameter coeffs that stores the pre-processed coefficient vector derived from the block parameters BiQuadCoeffs and ScaleValues.

    blockEntry.DerivedBlockParams{end+1} = 'coeffs = preprocess(<%BiQuadCoeffs>,<%ScaleValues>)';

  2. Create an argument object from the derived parameter by using getTflArgFromString. Specify the data type for the parameter.

    globalArg = getTflArgFromString(hTable, 'coeffs', 'single*');

  3. For the argument object, set PersistData to true.

    globalArg.PersistData = true;

  4. Create an RTW.CImplementation object for the implementation function and add the argument to the object by using the addArgument function.

    implementationFunc = RTW.CImplementation;
    addArgument(implementationFunc, globalArg);

The code generator generates the global variable coeffs as a DWork vector.

See Also

| |

Related Topics