Simulin金宝appk上的Guy

金宝appSimulink &基于模型的设计

在c++应用程序中利用MATLAB生成的代码

今天我很高兴欢迎客座博主 艾琳McGarrity .我很高兴欢迎Erin作为客座博客的主要原因是,他将讨论如何从MATLAB代码和Simulink模型中生成C/ c++代码金宝app MATLAB编码器 金宝app仿真软件编码器 而且 嵌入式编码器 .虽然我以前在这个博客中更多地关注与模拟相关的主题,但我意识到代码生成对这个博客的许多读者来说是一个重要的主题。我们希望在下面的评论中听到您对今天的主题的看法,以及您希望在这个博客中看到其他与代码生成相关的主题。

简介

假设我们有一个奇特的数值例程,我们一直在MATLAB中工作,我们想在外部c++应用程序中使用。在这篇文章中,我们将展示如何从MATLAB代码中生成动态库,我们可以从c++程序中调用它。这将允许我们在外部程序中利用MATLAB的一些功能。

MATLAB代码

为了演示工作流,让我们创建一个执行适合某些数据的行的例程。这个函数有两个输入, x 而且 y ,它们都是要拟合的数据向量。这些向量的长度应该相等 N .这个函数的输出是 而且 b 为最拟合数据的直线的斜率和截距。我们将通过最小化点到直线垂直距离的平方来进行拟合,其形式是这个方程给出的点斜式 [1] :
ϕ(m,b)=i=1N(y(i)-(mx(i)+b))2" style="vertical-align:-17px"> ϕ b 1 N y - x + b 2
的最小值 ϕ(m,b)" style="vertical-align:-5px"> ϕ b 可以用通常的方法求它对的导数吗 而且 b 把这些设为0。这样我们就得到了以下两个方程组:
mϕ(m,b)=0=i=1N-2(y(i)-(mx(i)+b))x(i)" style="vertical-align:-17px"> ϕ b 0 1 N - 2 y - x + b x
而且
bϕ(m,b)=0=i=1N-2(y(i)-(mx(i)+b))1" style="vertical-align:-17px"> b ϕ b 0 1 N - 2 y - x + b 1
这里我们用到了导数算子和和交换。方程两边都除以-2后,我们可以把这个方程组重新排列成一个矩阵方程
[i=1Nx(i)2i=1Nx(i)i=1Nx(i)N][mb]=[i=1Nx(i)y(i)i=1Ny(i)]." style="vertical-align:-45px"> 1 N x 2 1 N x 1 N x N b 1 N x y 1 N y
这个方程组可以用紧凑符号表示为
Hp=f." style="vertical-align:-5px"> H p f
来解 $ p=[m,b]^T $ 我们可以两边同时乘以的倒数 H
H-1Hp=H-1f," style="vertical-align:-5px"> H - 1 H p H - 1 f
或者简单地
p=H-1f." style="vertical-align:-5px"> p H - 1 f
说明:MATLAB代码求解。- 而且 b 看起来是这样的:
函数[m, b] = lineFitter(x,y)
确保x和y有相同数量的元素。
断言(元素个数(x) = =元素个数(y));
形成左边的矩阵
H = [x(:)'*x(:) sum(x(:),1);
总和(x(:), 1)元素个数(x)];
%形成残差
F = [x(:)'*y(:)
总和(y (:), 1)];
%解方程组
p = H\f;
%分配斜率
M = p(1);
B = p(2);
结束

在MATLAB中测试拟合程序

为了检查我们的代码,让我们加载一些数据,拟合直线并绘制所有内容。
D = readmatrix(“myData.csv”);
X = d(:,1);
Y = d(:,2);
拟合数据
[m,b] = lineFitter(x,y)
M = 4.0493
B = -0.0247
根据拟合参数创建直线
Xgrid = 0:0.1:1;
Ygrid = m*xgrid + b;
绘制所有内容
图;clf
散射(x, y);
持有所有
情节(xgrid ygrid,“线宽”2);

为拟合例程生成代码

现在,我们可以生成代码和创建动态库所需的一切 lineFitter 例行公事。我们将使用 coder.config 而且 coder.typeof
为动态库设置编码器对象
CFG = code .config(“dll”);
cfg。冗长=“详细”
cfg。GenCodeOnly = true;
为输入创建样例变量。我们想要做这些输入
%动态大小,因为我们可能有任意大小的数据文件。
Xarg = code .typeof(1.0, [10000, 1], [1,0]);
Yarg = code .typeof(1.0, [10000, 1], [1,0]);
生成代码和报告
codegen-config cfg lineFitter。米-args {xarg,yarg} -nargout 2 -report
编译lineFitter函数…------------------------------------------------------------------------ 编译抑制:生成代码。------------------------------------------------------------------------ ### 生成编译报告……代码生成成功:查看报告
MATLAB R2022b中的代码生成报告有一个整洁的功能,称为“ 跟踪代码 ,它显示了MATLAB代码对应于C代码:
我们稍后需要的相关代码是接口 lineFitter .关键代码在里面 lineFitter.h :
/*函数声明*/
(const emxArray_real_T *x, const emxArray_real_T *y,
双*m,双*b);
输入是常量数组指针,输出是指向double类型的指针。这将指导我们的客户端实现,如下所示。

打包代码

现在我们有了代码,我们可以使用 codebuild 而且 packNgo 生成和打包构建工件,我们可以接管我们的客户端应用程序。在本例中,我们将使用 CMake 而且 SHARED_LIBRARY 选项来进行代码构建,以便我们能够使用 CMake程序 在我们的客户端建立一切。CMake是一个允许我们执行平台独立编译代码的工具。简而言之,我们可以为CMake提供一个要构建的东西的列表,它将为我们执行所有的检查和编译。
codebuild (”。/ codegen / dll / lineFitter”“BuildMethod”“CMake”“BuildVariant”“SHARED_LIBRARY”);
packNGo (”。/ codegen / dll / lineFitter”“PackType”“分层”“文件名”“lineFitter”);
这会生成一个存档文件 lineFitter.zip ,我们可以复制到我们的客户端代码库。

创建动态库

现在我们有了代码,就可以构建它并创建一个例程来链接到客户端机器上。之后,我们可以在客户端代码中添加调用行拟合例程所需的代码。假设我们把新生成的 lineFitter.zip 这里,把所有东西都解压。解 lineFitter.zip 会产生两个文件, mlrFiles.zip 而且 sDirFiles.zip .解压缩这些文件将创建两个目录,R2022b和codegen。
C:\work\lineFitExample> dir /w
[codegen] linefiter .zip mlrFiles.zip [R2022b] sDirFiles.zip
它们分别包含所需的MATLAB头文件和我们生成的代码。为了构建这些文件,我们将创建一个名为build_lib的目录,然后使用以下命令调用cmake [2] (结果也显示出来了):
C:\work\lineFitExample> mkdir build_lib
C:\work\LineFitExample> cmake -G "NMake Makefiles" -B ./build_lib -DCMAKE_BUILD_TYPE=Release -DMATLAB_ROOT=。/ R2022b s / codegen / dll / lineFitter
C编译器标识为MSVC 19.29.30137.0
<剪>
构建文件已经写到:C:/work/LineFitExample/build_lib
C:\work\LineFitExample> cmake—build build_lib
[8/8]链接CXX共享库codegen\dll\lineFitter\lineFitter_win64.dll
\#\#\#已创建库:C:/work/LineFitExample/build_lib/codegen/dll/lineFitter/lineFitter_win64.dll

使用动态库

现在我们已经生成了动态库 lineFitter_win64.dll 时,就可以创建将使用 lineFitter 例行公事。我们的客户端应用程序读取csv文件,并将列放入两个列表中:
为了使这段代码与我们新创建的动态库连接,我们需要分配数组。这些数组是有类型的 emx_Array_real_T 如上所示。我们将编写一个函数来进行分配,但首先我们将包括两个我们需要的头文件:
# include“lineFitter.h”
# include“lineFitter_emxAPI.h”
现在我们准备编写数组分配函数,我们将把它放在主例程之上。此函数接受一个double类型的列表,并将其复制到 emxArray_real_T 它已经被分配到合适的大小。此代码的示例可以在该目录中找到 。\ codegen \ dll \ lineFitter \ \ c例子
ArrayHelperFunc.png
最后,我们将添加调用来分配我们的向量,并在主例程的读取代码下面,但在最终的return语句之前求解系统:
LineFitCode.png
我们客户端的CMakeLists.txt文件如下所示:
CMakeFile.png
现在,我们准备编译客户端应用程序。你可以在这里下载结果文件: CMakeLists.txt 而且 myFit.cpp .您还需要数据文件,它在 myData.csv
这个过程类似于编译上面的库,这是CMake的吸引力的一部分。命令如下:
C:\work\LineFitExample> mkdir build
C:只\work\LineFitExample> cmake -G "NMake Makefiles" -B build -S。-DCMAKE_BUILD_TYPE =释放
C编译器标识为MSVC 19.29.30137.0
<剪>
构建文件已经被写入:C:/work/LineFitExample/ Build
C:\work\LineFitExample> cmake—build build
[2/2]链接CXX可执行文件myFit.exe
现在我们在构建目录中有了可执行文件myFit.exe。测试代码的最后步骤是:
C:\work\LineFitExample\build_lib\codegen\dll\lineFitter\;%PATH%
C:\work\LineFitExample> .\build\myFit.exe myData.csv
M,b = 4.04926, -0.0246821
我们可以看到,斜率和截距和我们在MATLAB中得到的是一样的。

笔记

此方法仅用于演示目的。在生产中,您应该使用 polyfit 来解决这个问题。
在这个例子中,我们使用Visual Studio工具来编译代码。为了在命令行中设置,我运行了脚本:
C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\辅助\Build\vcvars64.bat

现在轮到你了

我们希望你喜欢这个例子。很快,我们将在此基础上构建一个更复杂的示例。如果你想在博客上看到其他与Coder相关的话题,请在下面的评论中告诉我们。
|

댓글

댓글을남기려면링크를클릭하여MathWorks계정에로그하거나계정을새로만드십시오。