Main Content

通过开发和使用代码替换库来优化生成的代码 - MATLAB

开发和使用代码替换库来替换生成的代码中的函数和运算符。代码替换是指更改代码生成器为函数和运算符生成的代码以满足应用程序代码要求的一种方法。例如,您可以替换生成的代码以满足以下要求:

  • 针对特定运行时环境的优化,包括(但不限于)特定目标硬件。

  • 与现有应用程序代码集成。

  • 符合某种标准,例如 AUTOSAR。

  • 修改代码行为,例如启用或禁用非有限或内联支持。

  • 应用程序或工程特定的代码要求,例如使用 BLAS 或去除 math.h 和系统头文件,或调用 memcpymemset

您可以将代码生成器配置为使用 MathWorks® 提供的代码替换库。如果您有 Embedded Coder® 许可证,则可以使用代码替换工具以交互方式开发您自己的代码替换库,或者以编程方式开发。

此示例提供的 MATLAB® 代码说明了可定义代码替换映射的各种方法。对于每个示例 MATLAB 函数,此示例都提供了 MATLAB 文件,说明如何以编程方式来开发函数和运算符的代码替换。

有关详细信息,请参阅What Is Code Replacement Customization?开发代码替换库

创建注册文件

创建并保存注册文件。由于路径中可能已存在 rtwTargetInfo.m 文件,此示例从具有不同名称的文件创建一个新文件。

copyfile myRtwTargetInfoCRL.txt rtwTargetInfo.m 

开发代码替换库的步骤

  1. 根据函数或运算映射、编译版本信息和注册信息来确定代码替换要求。

  2. 为代码替换库开发做好准备(例如,确定或开发模型以测试您的库)。

  3. 定义代码替换映射。

  4. 指定替换代码的编译信息。

  5. 注册代码替换映射。

  6. 验证代码替换。

  7. 部署库。

有关详细信息,请参阅开发代码替换库

数学函数替换

此示例定义和注册数学函数的代码替换映射。您可以为各种函数定义代码替换映射。有关详细信息,请参阅Code You Can Replace from MATLAB Code

1.replace_math_fcns.m 文件包含以下代码:

function [y1, y2] = replace_math_fcns(u1, u2) %#codegen

%   Copyright 2008-2010 The MathWorks, Inc.

y1 = single(atan2(u1,u2));
y2 = double(cos(double(u1)) + sin(double(u2)));

2.配置代码生成器以使用代码替换库函数替换示例

RTW.TargetRegistry.getInstance('reset');
cfg = coder.config('lib','ecoder',true);
cfg.CodeReplacementLibrary = 'Function Replacement Examples';
cfg.GenerateReport = false;
cfg.LaunchReport = false;

3.设置配置参数,以编译和定义函数输入类型。

t = single(2); 

4.打开并浏览代码替换表定义文件 crl_table_functions.m

5.通过使用指向代码替换库的配置参数和在步骤 3 中定义的示例输入类作为 codegen 命令的输入参数,将 MATLAB 程序编译为 C 源文件。

codegen('replace_math_fcns', '-config', cfg, '-args', {t, t});
Code generation successful.

6.replace_math_fcns.c 文件包含以下生成代码:

file = fullfile('codegen','lib','replace_math_fcns','replace_math_fcns.c');
coder.example.extractLines(file,'#include "replace_math_fcns.h','* File trailer for replace_math_fcns.c',1,0)
#include "replace_math_fcns.h"
#include "MyMath.h"

/* Function Definitions */
/*
 * Copyright 2008 The MathWorks, Inc.
 *
 * Arguments    : float u1
 *                float u2
 *                float *b_y1
 *                double *y2
 * Return Type  : void
 */
void replace_math_fcns(float u1, float u2, float *b_y1, double *y2)
{
  *b_y1 = atan2_single(u1, u2);
  *y2 = cos_double(u1) + sin_double(u2);
}

/*

有关数学函数替换的详细信息,请参阅Math Function Code Replacement

加法和减法运算符替换

此示例说明如何为加法 (+) 和减法 (-) 运算定义和注册代码替换映射。定义加法和减法运算的条目时,可以指定您的库函数实现以下哪种算法 (EntryInfoAlgorithm):

  • 运算前转换 (CBO) (RTW_CAST_BEFORE_OP),默认值

  • 运算后转换 (CAO) (RTW_CAST_AFTER_OP)

1.addsub_two_int16.m 文件包含以下代码:

function [y1, y2] = addsub_two_int16(u1, u2) %#codegen

%   Copyright 2008-2010 The MathWorks, Inc.

y1 = int16(u1 + u2);
y2 = int16(u1 - u2);

注意,代码使用默认算法 CBO。

2.配置代码生成器以使用代码替换库加法和减法示例

RTW.TargetRegistry.getInstance('reset');
cfg = coder.config('lib','ecoder',true);
cfg.CodeReplacementLibrary = 'Addition & Subtraction Examples';
cfg.GenerateReport = false;
cfg.LaunchReport = false;

3.设置配置参数,以编译和定义运算输入类型。

t = int16(2); 

4.打开并浏览代码替换表定义文件 addsub_two_int16(u1, u2).m

5.通过使用指向所需代码替换库的配置参数和在步骤 3 中定义的示例输入类作为 codegen 命令的输入参数,将 MATLAB 程序编译为 C 源文件。

codegen('addsub_two_int16','-config', cfg, '-args', {t, t});
Code generation successful.

6.addsub_two_int16.c 文件包含以下生成代码。

file = fullfile('codegen','lib','addsub_two_int16','addsub_two_int16.c');
coder.example.extractLines(file,'#include "addsub_two_int16.h','* File trailer for addsub_two_int16.c',1,0);
#include "addsub_two_int16.h"
#include "MyMath.h"

/* Function Definitions */
/*
 * Copyright 2008 The MathWorks, Inc.
 *
 * Arguments    : short u1
 *                short u2
 *                short *b_y1
 *                short *y2
 * Return Type  : void
 */
void addsub_two_int16(short u1, short u2, short *b_y1, short *y2)
{
  *b_y1 = s16_add_s16_s16(u1, u2);
  *y2 = s16_sub_s16_s16(u1, u2);
}

/*

有关加法和减法运算符替换的详细信息,请参阅Scalar Operator Code ReplacementAddition and Subtraction Operator Code Replacement

矩阵运算符替换

此示例为以下矩阵运算定义和注册代码替换映射:加法、减法、乘法、转置、共轭和埃尔米特。

支持的类型包括:

  • single, double

  • int8, uint8

  • int16, uint16

  • int32, uint32

  • csingle, cdouble

  • cint8, cuint8

  • cint16, cuint16

  • cint32, cuint32

  • 定点整数

  • 混合类型(每个输入中有不同的类型)

1.replace_matrix_ops.m 文件包含以下代码:

function [y1, y2, y3] = replace_matrix_ops(u1, u2) %#codegen
% This block supports the Embedded MATLAB subset.
% See the help menu for details. 

%   Copyright 2010 The MathWorks, Inc.

y1 = u1 + u2;
y2 = u1 - u2;
y3 = y2';

2.配置代码生成器以使用代码替换库矩阵 Op 替换示例

RTW.TargetRegistry.getInstance('reset');
cfg = coder.config('lib','ecoder',true);
cfg.CodeReplacementLibrary = 'Matrix Op Replacement Examples';
cfg.GenerateReport = false;
cfg.LaunchReport = false;

3.设置配置参数,以编译和定义运算输入类型。

t = [1.0 2.0; 3.0, 4.0]; 

4.打开并浏览代码替换表定义文件 crl_table_matops.m。

5.使用指向所需代码替换库的配置参数和在步骤 3 中定义的示例输入类作为 codegen 命令的输入参数,编译 MATLAB 程序。

codegen('replace_matrix_ops', '-config', cfg, '-args', {t, t});
Code generation successful.

6.replace_matrix_ops.c 文件包含以下生成代码:

file = fullfile('codegen','lib','replace_matrix_ops','replace_matrix_ops.c');
coder.example.extractLines(file,'#include "replace_matrix_ops.h','* File trailer for replace_matrix_ops.c',1,0);
#include "replace_matrix_ops.h"
#include "MatrixMath.h"

/* Function Definitions */
/*
 * This block supports the Embedded MATLAB subset.
 *  See the help menu for details.
 *
 * Arguments    : const double u1[4]
 *                const double u2[4]
 *                double b_y1[4]
 *                double y2[4]
 *                double y3[4]
 * Return Type  : void
 */
void replace_matrix_ops(const double u1[4], const double u2[4], double b_y1[4],
                        double y2[4], double y3[4])
{
  /*    Copyright 2015 The MathWorks, Inc. */
  matrix_sum_2x2_double((double *)&u1[0], (double *)&u2[0], &b_y1[0]);
  matrix_sub_2x2_double((double *)&u1[0], (double *)&u2[0], &y2[0]);
  y3[0] = y2[0];
  y3[1] = y2[1];
  y3[2] = y2[2];
  y3[3] = y2[3];
}

/*

有关矩阵运算符替换的详细信息,请参阅Small Matrix Operation to Processor Code Replacement

BLAS 的矩阵乘法替换

此示例为基本线性代数子例程 (BLAS) 中的子例程 xGEMMxGEMV 定义并注册代码替换映射。您可以将以下运算映射到 BLAS 子例程:

  • 矩阵乘法

  • 对一个或两个输入进行转置的矩阵乘法

  • 对一个或两个输入进行埃尔米特运算的矩阵乘法

1.replace_matrix_ops_blas.m 文件包含以下代码:

function [y1, y2] = replace_matrix_ops_blas(u1, u2) %#codegen
% This block supports the MATLAB Coder subset.
% See the help menu for details. 

%   Copyright 2010 The MathWorks, Inc.

y1 = u1 * u2;
y2 = u1 * u2;

2.配置代码生成器以使用代码替换库 BLAS 替换示例

RTW.TargetRegistry.getInstance('reset');
cfg = coder.config('lib','ecoder',true);
cfg.CodeReplacementLibrary = 'BLAS Replacement Examples';
cfg.GenerateReport = false;
cfg.LaunchReport = false;

3.设置配置参数,以编译和定义函数输入类型。

t = [1.0 2.0 3.0; 4.0 5.0 6.0; 7.0 8.0 9.0]; 

4.打开并浏览代码替换表定义文件 crl_table_blas.m

5.使用指向所需代码替换库的配置参数和在步骤 3 中定义的示例输入类作为 codegen 命令的输入参数,编译 MATLAB 程序。

codegen('replace_matrix_ops_blas', '-config', cfg, '-args', {t, t});
Code generation successful.

6.replace_matrix_ops_blas.c 文件包含以下生成代码。

file = fullfile('codegen','lib','replace_matrix_ops_blas','replace_matrix_ops_blas.c');
coder.example.extractLines(file,'#include "replace_matrix_ops_blas.h','* File trailer for replace_matrix_ops_blas.c',1,0);
#include "replace_matrix_ops_blas.h"
#include "blascompat32.h"
#include <string.h>

/* Function Definitions */
/*
 * This block supports the MATLAB Coder subset.
 *  See the help menu for details.
 *
 * Arguments    : const double u1[9]
 *                const double u2[9]
 *                double b_y1[9]
 *                double y2[9]
 * Return Type  : void
 */
void replace_matrix_ops_blas(const double u1[9], const double u2[9],
                             double b_y1[9], double y2[9])
{
  double ALPHA;
  double BETA;
  int K;
  int LDA;
  int LDB;
  int LDC;
  int M;
  int N;
  char TRANSA;
  char TRANSB;
  /*    Copyright 2015 The MathWorks, Inc. */
  TRANSA = 'N';
  TRANSB = 'N';
  M = 3;
  N = 3;
  K = 3;
  ALPHA = 1.0;
  LDA = 3;
  LDB = 3;
  BETA = 0.0;
  LDC = 3;
  dgemm32(&TRANSA, &TRANSB, &M, &N, &K, &ALPHA, &u1[0], &LDA, &u2[0], &LDB,
          &BETA, &b_y1[0], &LDC);
  memcpy(&y2[0], &b_y1[0], 9U * sizeof(double));
}

/*

有关 BLAS 矩阵乘法替换的详细信息,请参阅Matrix Multiplication Operation to MathWorks BLAS Code Replacement

行优先矩阵运算和列优先矩阵运算的替换

此示例定义并注册行优先矩阵运算和列优先矩阵运算的代码替换映射。

1.replace_mixed_row_column_ops.m 文件包含以下代码:

function [y1, y2 , y3, y4] = replace_mixed_row_column_ops( u1,u2, u3)
    coder.rowMajor;
    [y1,y2] = Child_Op(u1,u2,u3);
    y3 = u1*u2;
    y4 = u1+u3;
end

function [b1, b2] = Child_Op( a1,a2,a3)
    coder.columnMajor;
    coder.inline('never');
    b1 = a1*a2;
    b2 = a1+a3;
end

2.配置代码生成器以使用代码替换库行优先 CRL 示例

RTW.TargetRegistry.getInstance('reset');
cfg = coder.config('lib','ecoder',true);
cfg.CodeReplacementLibrary = 'Row Major CRL Examples';
cfg.GenerateReport = false;
cfg.LaunchReport = false;

3.设置配置参数,以编译和定义函数输入类型。

t = [1 2; 3 4]; 

4.打开并浏览代码替换表定义文件 crl_table_row_major_op.mcrl_table_column_major_op.m

5.使用指向所需代码替换库的配置参数和在步骤 3 中定义的示例输入类作为 codegen 命令的输入参数,编译 MATLAB 程序。

codegen('replace_mixed_row_column_ops.m', '-config', cfg, '-args', {t, t, t});
Code generation successful.

6.replace_matrix_row_column_ops.c 文件包含以下生成代码。

file = fullfile('codegen','lib','replace_mixed_row_column_ops','replace_mixed_row_column_ops.c');
coder.example.extractLines(file,'#include "replace_mixed_row_column_ops.h','* File trailer for replace_mixed_row_column_ops.c',1,0);
#include "replace_mixed_row_column_ops.h"
#include "CRL_Multiplication.h"

/* Function Declarations */
static void Child_Op(const double a1[4], const double a2[4], const double a3[4],
                     double b1[4], double b2[4]);

/* Function Definitions */
/*
 * Arguments    : const double a1[4]
 *                const double a2[4]
 *                const double a3[4]
 *                double b1[4]
 *                double b2[4]
 * Return Type  : void
 */
static void Child_Op(const double a1[4], const double a2[4], const double a3[4],
                     double b1[4], double b2[4])
{
  MyMul_CUSTOM_COL((double *)&a1[0], (double *)&a2[0], &b1[0], 2U, 2U, 2U, 2U);
  MyAdd_CUSTOM_COL((double *)&a1[0], (double *)&a3[0], &b2[0], 2U, 2U, 2U, 2U);
}

/*
 * Arguments    : const double u1[4]
 *                const double u2[4]
 *                const double u3[4]
 *                double b_y1[4]
 *                double y2[4]
 *                double y3[4]
 *                double y4[4]
 * Return Type  : void
 */
void replace_mixed_row_column_ops(const double u1[4], const double u2[4],
                                  const double u3[4], double b_y1[4],
                                  double y2[4], double y3[4], double y4[4])
{
  double b_u1[4];
  double b_u2[4];
  double b_u3[4];
  double dv[4];
  double dv1[4];
  b_u1[0] = u1[0];
  b_u2[0] = u2[0];
  b_u3[0] = u3[0];
  b_u1[1] = u1[2];
  b_u2[1] = u2[2];
  b_u3[1] = u3[2];
  b_u1[2] = u1[1];
  b_u2[2] = u2[1];
  b_u3[2] = u3[1];
  b_u1[3] = u1[3];
  b_u2[3] = u2[3];
  b_u3[3] = u3[3];
  Child_Op(b_u1, b_u2, b_u3, dv, dv1);
  y2[0] = dv1[0];
  b_y1[0] = dv[0];
  y2[1] = dv1[2];
  b_y1[1] = dv[2];
  y2[2] = dv1[1];
  b_y1[2] = dv[1];
  y2[3] = dv1[3];
  b_y1[3] = dv[3];
  MyMul_CUSTOM_ROW((double *)&u1[0], (double *)&u2[0], &y3[0], 2U, 2U, 2U, 2U);
  MyAdd_CUSTOM_ROW((double *)&u1[0], (double *)&u3[0], &y4[0], 2U, 2U, 2U, 2U);
}

/*

使用 Coder.Replace 替换 MATLAB 函数

对于内置数据类型、复数数据类型和定点数据类型,代码替换库支持替换以标量和矩阵作为输入输出的 MATLAB 函数。

1.coder_replace_fcn.m 文件包含以下代码:

function [y1, y2, y3] = coder_replace_fcn(u1, u2) %#codegen
%   Copyright 2012 The MathWorks, Inc.

y1 = myScalarFunction(u1(1),u1(2));
y2 = myMatrixFunction(u1, u2);
complexValue = u1 + 1i;
y3 = myComplexFunction(complexValue, u2(1));
end


%-----------------------------------------
% Lookup this function for CRL replacement
% Function: myScalarFunction
% Inputs:  u1: double scalar
%          u2: double scalar
% Outputs: y1: double scalar
%----------------------------------------
function y1 = myScalarFunction(u1, u2)

% Trigger CRL lookup 
coder.replace('-errorifnoreplacement');
y1 = sin(u1) + cos(u2);
end

%-----------------------------------------
% Lookup this function for CRL replacement
% Function: myMatrixFunction
% Inputs:  u1: 2x2 double matrix
%          u2: 2x2 double matrix
% Outputs: y1: 2x2 double matrix
%----------------------------------------
function y1 = myMatrixFunction(u1, u2)

% Trigger CRL lookup 
coder.replace('-errorifnoreplacement');
y1 = u1 + u2;
end


%-----------------------------------------
% Lookup this function for CRL replacement
% Function: myComplexFunction
% Inputs:  u1: 2x2 complex double matrix
%          u2: double scalar
% Outputs: y1: 2x2 complex double matrix
%-----------------------------------------
function y1 = myComplexFunction(u1, u2)

% Trigger CRL lookup 
coder.replace('-errorifnoreplacement');
y1 = u1 + u2;
end

2.配置代码生成器以使用代码替换库 Coder 替换示例

RTW.TargetRegistry.getInstance('reset');
cfg = coder.config('lib','ecoder',true);
cfg.CodeReplacementLibrary = 'Coder Replace Examples';
cfg.GenerateReport = false;
cfg.LaunchReport = false;

3.设置配置参数,以编译和定义函数输入类型。

t = [1 2; 3 4];

4.浏览代码替换表定义文件 crl_table_coder_replace.m

5.使用指向所需代码替换库的配置参数和在步骤 3 中定义的示例输入类作为 codegen 命令的输入参数,编译 MATLAB 程序。

codegen('coder_replace_fcn', '-config', cfg, '-args', {t, t});
Code generation successful.

6.coder_replace_fcn.c 文件包含以下生成代码。

file = fullfile('codegen','lib','coder_replace_fcn','coder_replace_fcn.c');
coder.example.extractLines(file,'#include "coder_replace_fcn.h','* File trailer for coder_replace_fcn.c',1,0)
#include "coder_replace_fcn.h"
#include "MyMath.h"

/* Function Definitions */
/*
 * Copyright 2012 The MathWorks, Inc.
 *
 * Arguments    : const double u1[4]
 *                const double u2[4]
 *                double *b_y1
 *                double y2[4]
 *                creal_T y3[4]
 * Return Type  : void
 */
void coder_replace_fcn(const double u1[4], const double u2[4], double *b_y1,
                       double y2[4], creal_T y3[4])
{
  creal_T dcv[4];
  *b_y1 = myScalarFunction_impl(u1[0], u1[1]);
  myMatrixFunction_impl(&y2[0], (double *)&u1[0], (double *)&u2[0]);
  dcv[0].re = u1[0];
  dcv[0].im = 1.0;
  dcv[1].re = u1[1];
  dcv[1].im = 1.0;
  dcv[2].re = u1[2];
  dcv[2].im = 1.0;
  dcv[3].re = u1[3];
  dcv[3].im = 1.0;
  myComplexFunction_impl(&y3[0], &dcv[0], u2[0]);
}

/*

有关详细信息,请参阅Replace MATLAB Functions with Custom Code by Using the coder.replace Function

编译信息

对于代码替换表中的每个条目,您可以为替换函数指定如下所示的编译信息:

  • 头文件依赖项

  • 源文件依赖项

  • 其他包含路径

  • 其他源文件路径

  • 其他链接标志

此外,在代码生成前,您可以指定 RTW.copyFileToBuildDir 将生成替换代码所需的头文件、源文件或目标文件复制到编译文件夹中。您可以将 RTW.copyFileToBuildDir 指定为:

  • setTflCFunctionEntryParameterssetTflCOperationEntryParameterssetTflCSemaphoreEntryParameters 调用中 GenCallback 属性的值。

  • registerCFunctionEntryregisterCOperationEntryregisterCSemaphoreEntry 调用中 genCallback 参量的值。

注意:此示例中的 .m 脚本配置仅用于代码生成,因为没有提供替换函数的实现。

有关如何指定替换代码编译信息的详细信息,请参阅开发代码替换库

清理

刷新当前 MATLAB 会话中的库注册信息。

RTW.TargetRegistry.getInstance('reset');