目录
通过命令行生成 C 代码
在本教程中,将使用 MATLAB® Coder™codegen命令为 MATLAB 函数生成静态C库。首先生成只能接受具有固定预分配大小的输入的 C 代码。然后生成可以接受许多不同大小的输入的 C 代码。
还可以使用 MATLAB Coder App 生成代码。
教程文件
将教程文件从文件夹 matlabroot\help\toolbox\coder\examples\euclidean 复制到本地工作文件夹。此处,matlabroot 是 MATLAB 安装文件夹,例如 C:\Program Files\MATLAB\R2019a。要将这些文件复制到您的当前文件夹,请运行以下 MATLAB 命令:
copyfile(fullfile(matlabroot,'help','toolbox','coder','examples','euclidean'))
本地工作文件夹不能为私有文件夹或 @ 文件夹。本教程使用 euclidean_data.mat、euclidean.m、test.m、build_lib_fixed.m 和 build_lib_variable.m 文件。
-
MATLAB 数据文件 euclidean_data.mat 包含两段数据:三维欧几里德空间中的一个点以及三维欧几里德空间中的一组其他点。更具体地说:
-
x 是一个 3×1 列向量,表示三维欧几里德空间中的一个点。
-
cb 是一个 3×216 数组。cb 中的每列都表示三维欧几里德空间中的一个点。
-
-
MATLAB 文件 euclidean.m 包含 euclidean 函数,该函数在本示例中实现核心算法。该函数接受 x 和 cb 作为输入。它计算 x 和 cb 中每个点之间的欧几里德距离,并返回以下量:
-
列向量 y_min,它等于 cb 中表示与 x 距离最近的点的列。
-
列向量 y_max,它等于 cb 中表示与 x 距离最远的点的列。
-
二维向量 idx,它包含 cb 中向量 y_min 和 y_max 的列索引。
-
二维向量 distance,它包含计算出的到 x 的最小和最大距离。
-
function [y_min,y_max,idx,distance] = euclidean(x,cb)
% Initialize minimum distance as distance to first element of cb
% Initialize maximum distance as distance to first element of cb
idx(1)=1;
idx(2)=1;
distance(1)=norm(x-cb(:,1));
distance(2)=norm(x-cb(:,1));
% Find the vector in cb with minimum distance to x
% Find the vector in cb with maximum distance to x
for index=2:size(cb,2)
d=norm(x-cb(:,index));
if d < distance(1)
distance(1)=d;
idx(1)=index;
end
if d > distance(2)
distance(2)=d;
idx(2)=index;
end
end
% Output the minimum and maximum distance vectors
y_min=cb(:,idx(1));
y_max=cb(:,idx(2));
end
- MATLAB 脚本 test.m 将数据文件 euclidean_data.mat 加载到工作区中。接着,它调用函数 euclidean 来计算 y_min、y_max、idx 和 distance。然后,脚本在命令行中显示计算出的量。加载 euclidean_data.mat 是在调用核心算法之前执行的预处理步骤。显示结果是后处理步骤。
% Load test data
load euclidean_data.mat
% Determine closest and farthest points and corresponding distances
[y_min,y_max,idx,distance] = euclidean(x,cb);
% Display output for the closest point
disp('Coordinates of the closest point are: ');
disp(num2str(y_min'));
disp(['Index of the closest point is ', num2str(idx(1))]);
disp(['Distance to the closest point is ', num2str(distance(1))]);
disp(newline);
% Display output for the farthest point
disp('Coordinates of the farthest point are: ');
disp(num2str(y_max'));
disp(['Index of the farthest point is ', num2str(idx(2))]);
disp(['Distance to the farthest point is ', num2str(distance(2))]);
-
编译脚本 build_lib_fixed.m 和 build_lib_variable.m 包含的命令可从MATLAB 代码生成静态C 库,这两个库分别接受固定大小和可变大小输入。这些脚本的内容显示在本教程后面有关生成 C代码的部分中。
提示:可以使用MATLAB Coder 从MATLAB函数生成代码。不支持从MATLAB脚本生成代码。
请使用测试脚本将预处理和后处理步骤与实现核心算法的函数分隔开。这种做法能够轻松地重用算法。需要为实现核心算法的 MATLAB 函数生成代码。不需要为测试脚本生成代码。
为 MATLAB 函数生成 C 代码
运行原始 MATLAB 代码
在 MATLAB 中运行测试脚本 test.m。输出显示 y、idx 和 distance。
Coordinates of the closest point are:
0.8 0.8 0.4
Index of the closest point is 171
Distance to the closest point is 0.080374
Coordinates of the farthest point are:
0 0 1
Index of the farthest point is 6
Distance to the farthest point is 1.2923
使 MATLAB 代码适用于代码生成
为了使MATLAB 代码适用于代码生成,可以使用代码分析器和代码生成就绪工具。MATLAB 编辑器中的代码分析器会在输入代码时持续检查代码。它会报告问题,并提出修改建议,以最大程度地提高性能和可维护性。代码生成就绪工具会筛查 MATLAB 代码中是否存在代码生成不支持的功能和函数。
C/C++ 代码生成支持的某些 MATLAB 内置函数和工具箱函数、类以及 System object 有特定的代码生成限制。这些限制和相关使用说明列在其对应参考页的扩展功能部分。
-
在 MATLAB 编辑器中打开 euclidean.m。MATLAB 编辑器右上角的代码分析器消息指示标记为绿色。分析器未在代码中检测到错误、警告或改进机会。
-
在函数声明后面添加 %#codegen 指令:
%#codegen 指令提示代码分析器识别特定于代码生成的警告和错误。function [y,idx,distance] = euclidean(x,cb) %#codegen
代码分析器消息指示标记变为红色,表示它检测到代码生成问题。 -
要查看警告消息,请将光标移到带下划线的代码片段上。警告指示,代码生成要求先对变量 idx 和 distance 进行完全定义,然后才可以对它们进行下标索引。出现这些警告是因为代码生成器必须在这些变量在代码中首次出现时确定其大小。要解决此问题,请使用 ones 函数同时分配和初始化这些数组。
% Initialize minimum distance as distance to first element of cb % Initialize maximum distance as distance to first element of cb idx = ones(1,2); distance = ones(1,2)*norm(x-cb(:,1));
代码分析器消息指示标记再次变为绿色,表示它没有再检测到任何代码生成问题。
-
保存文件。
-
要运行代码生成就绪工具,请从 MATLAB 命令行调用 coder.screener 函数。
coder.screener('euclidean')
该工具不会检测 euclidean 的任何代码生成问题。
MATLAB Online™ 不支持代码生成就绪工具。
注意:代码分析器和代码生成就绪工具可能无法检测到所有代码生成问题。消除这两个工具检测到的错误或警告后,使用 MATLAB Coder 生成代码以确定MATLAB 代码是否还存在其他合规性问题。
现在即可使用 MATLAB Coder App 编译代码。此处,编译指从MATLAB 代码生成 C/C++ 代码。
注意:编译 MATLAB 代码指从 MATLAB 代码生成 C/C++ 代码。在其他情况下,“编译”可能指 C/C++ 编译器的操作。
定义输入类型
由于 C 使用静态类型,因此在代码生成时(也称为编译时),代码生成器必须确定 MATLAB 文件中所有变量的类、大小和复/实性。因此,在为文件生成代码时,必须指定入口函数的所有输入参数的属性。入口函数是顶层 MATLAB 函数,可以从中生成代码。
当使用 codegen 命令生成代码时,请使用 -args 选项指定入口函数的示例输入参数。代码生成器使用这些信息来确定输入参数的属性。在下一步中,将使用 codegen 命令从入口函数 euclidean 生成 MEX 文件。
检查运行时问题
从入口函数生成 MEX 函数。MEX 函数是可从 MATLAB 内部调用的生成的代码。运行该 MEX 函数,检查生成的 MEX 函数和原始的 MATLAB 函数是否具有相同的功能。
执行此步骤是一个很好的做法,因为可以检测并解决在生成的 C 代码中更难诊断出来的运行时错误。默认情况下,MEX 函数包括内存完整性检查。这些检查执行数组边界和维度检查,还检测为 MATLAB 函数生成的代码中是否存在内存完整性冲突问题。
为了将 MATLAB 代码转换为高效的 C/C++ 源代码,代码生成器引入了优化,在某些情况下,这会导致生成的代码与原始源代码在行为上有所不同。
-
使用 codegen 命令为 euclidean.m 生成 MEX 文件。要验证 MEX 函数,请运行测试脚本 test,并将调用 MATLAB 函数 euclidean 替换为调用生成的 MEX 函数。
codegen euclidean.m -args {x,cb} -test test
输出为:
此输出与原始 MATLAB 函数生成的输出相匹配,并验证 MEX 函数。现在,可以为 euclidean 生成独立的 C 代码。Running test file: 'test' with MEX function 'euclidean_mex'. Coordinates of the closest point are: 0.8 0.8 0.4 Index of the closest point is 171 Distance to the closest point is 0.080374 Coordinates of the farthest point are: 0 0 1 Index of the farthest point is 6 Distance to the farthest point is 1.2923
- 默认情况下,codegen 在当前文件夹中生成名为 euclidean_mex 的 MEX 函数。
- 可以使用 -args 选项指定入口函数 euclidean 的示例输入参数。代码生成器使用这些信息来确定输入参数的属性。
- 使用 -test 选项运行测试文件 test.m。此选项将测试文件中对 euclidean 的调用替换为对 euclidean_mex 的调用。
注意:在从MATLAB 代码生成独立的 C/C++ 代码之前,请生成 MEX 函数。运行生成的 MEX 函数,并确保它具有与MATLAB 函数相同的运行时行为。如果生成的 MEX 函数的执行结果不同于 MATLAB 的结果,或者出错,必须先修复这些问题,然后生成独立的代码。否则,生成的独立代码可能不可靠并且具有未定义的行为。
生成 C 代码
编译脚本 build_lib_fixed.m 包含用于为 euclidean.m 生成代码的命令。
% Load the test data
load euclidean_data.mat
% Generate code for euclidean.m with codegen. Use the test data as example input.
codegen -report -config:lib euclidean.m -args {x, cb}
请注意:
-
codegen 读取文件 euclidean.m,并将 MATLAB 代码转换为 C 代码。
-
-report 选项指示 codegen 生成代码生成报告,可使用该报告调试代码生成问题,并验证 MATLAB 代码是否适用于代码生成。
-
-config:lib 选项指示 codegen 生成静态C库,而不是生成默认MEX函数。
-
-args 选项指示codegen使用示例输入参数x和cb的类、大小和复/实性为euclidean.m生成代码。
可以通过使用适当的选项和codegen命令,选择生成 MEX 函数或其他C/C++编译类型,而不是生成C静态库。
-
运行编译脚本。
MATLAB会处理编译文件,并输出以下消息:
代码生成器在work\codegen\lib\euclidean 中生成独立的C静态库euclidean。此处,work是包含教程文件的文件夹。Code generation successful: View report.
-
要在 Report Viewer 中查看代码生成报告,请点击 View report。
如果代码生成器在代码生成过程中检测到错误或警告,报告将说明问题并提供有问题的 MATLAB 代码的链接。
提示:在命令行使用编译脚本生成代码。编译脚本自动执行命令行重复执行的一系列 MATLAB 命令,可帮助节省时间和消除输入错误。
将生成的 C 代码与原始 MATLAB 代码进行比较
要将生成的 C 代码与原始 MATLAB 代码进行比较,请在 MATLAB 编辑器中打开 C 文件 euclidean.c 和 euclidean.m 文件。
关于生成的C代码的重要信息:
-
函数签名为:
void euclidean(const double x[3], const double cb[648], double y_min[3], double y_max[3], double idx[2], double distance[2])
const double x[3] 对应于您的 MATLAB 代码中的输入 x。x 的大小是 3,它对应于MATLAB 生成代码时使用的示例输入的总大小 (3×1)。
const double cb[648] 对应于MATLAB 代码中的输入 cb。cb 的大小是 648,它对应于MATLAB 生成代码时使用的示例输入的总大小 (3×216)。在本例中,生成的代码使用一维数组来表示 MATLAB 代码中的二维数组。
生成的代码有四个额外的输入参数:数组 y_min、y_max、idx 和 distance。这些数组用于返回输出值。它们对应于原始 MATLAB 代码中的输出参数 y_min、y_max、idx 和 distance。
-
代码生成器将保留函数名称和注释。如果可能,代码生成器会保留变量名称。
注意:如果MATLAB 代码中的某个变量设置为常量值,它在生成的C代码中将不会显示为变量。在这种情况下,生成的C代码将包含该变量的实际值。
使用 Embedded Coder®,可以在 MATLAB 代码和生成的 C/C++ 代码之间进行交互式追溯。
为可变大小输入生成 C 代码
为 euclidean.m 生成的 C 函数只能接受与在代码生成期间指定的样本输入具有相同大小的输入。但是,对应的 MATLAB 函数的输入数组可以具有任意大小。在本教程的此部分,您将从 euclidean.m 中生成接受可变大小输入的 C 代码。
假设希望生成的 C 代码中的 x 和 cb 的维度具有以下属性:
-
x 和 cb 的第一个维度的大小为可变大小,但不超过 3。
-
x 的第二个维度具有固定大小,其值为 1。
-
cb 的第二个维度的大小为可变大小,但不超过 216。
要指定这些输入属性,请使用 coder.typeof 函数。coder.typeof(A,B,1) 指定一个可变大小的输入,其类和复/实性与 A 相同,其上限由大小向量 B 的对应元素给出。
使用编译脚本 build_lib_variable.m,该脚本使用 coder.typeof 在生成的C库中指定可变大小输入的属性。
% Load the test data
load euclidean_data.mat
% Use coder.typeof to specify variable-size inputs
eg_x=coder.typeof(x,[3 1],1);
eg_cb=coder.typeof(cb,[3 216],1);
% Generate code for euclidean.m using coder.typeof to specify
% upper bounds for the example inputs
codegen -report -config:lib euclidean.m -args {eg_x,eg_cb}
现在,可以按照与以前相同的步骤生成代码。euclidean.c 中生成的 C 代码的函数签名现在为:
void euclidean(const double x_data[], const int x_size[1], const double cb_data[],
const int cb_size[2], double y_min_data[], int y_min_size[1],
double y_max_data[], int y_max_size[1], double idx[2], double
distance[2])
参数 x_data、cb_data、y_min_data 和 y_max_data 对应于原始 MATLAB 函数中的输入参数 x 和 cb 以及输出参数 y_min 和 y_max。现在,C 函数接受四个额外的输入参数,即 x_size、cb_size、y_min_size 和 y_max_size,它们在运行时指定 x_data、cb_data、y_min_data 和 y_max_data 的大小。