分享使用 MATLAB 生成 C 代码的方法和研究

描述

一直以来,工程师都手工编写 C 语言实现算法再通过编译器编译为机器代码。能否使用编码器将 MATLAB 这样的高级语言翻译成 C 语言?大多数工程师认为这是可行的——理论来说。

但实际上是否可行?

生成的代码是可读性如何?效率如何?执行速度如何?

面向工业流程或只是处于研发阶段?

MATLAB Coder 的使用技巧和最佳实践可以直接回答以上问题,这里还将分享行业将 MATLAB 生成 C 代码的成功经验和应用案例(包括 Delphi、Baker Hughes、iSonea、dorsaVi 等)。

- 对比 MATLAB 和 C 代码 -

以下面这个简单的 MATLAB 乘法函数为例。

function c = myMult (a, b)

% Multiply two inputs

c = a * b;

给定标量输入,MATLAB Coder 可以生成下面的 C 代码:

#include "myMult.h"

doublemyMult (doublea,doubleb)

{

return a *b;

}

正如所见,生成的代码清楚地与 MATLAB 代码相映射。

同样的 MATLAB 代码,当给定两个矩阵输入时,在生成的 C 代码中会包含三层嵌套的 for 循环:

#include "myMult.h"

void myMult (const doublea[12], const doubleb[20],doublec[15],)

{

inti0;

inti1;

inti2;

for(i0 = 0; i0 < 3; i0++)  {

for(i1 = 0; i1 < 5; i1++)  {

c[i0 + 3 * i1] = 0.0;

for(i2 = 0; i2 < 4; i2++)  {

c[i0 + 3 * i1] += a[i0 + 3 * i2] * b[i2 + (i1 << 2 )];

}

}

}

}

推荐!

- 三步迭代工作流程 -

上述简单的函数可以在一个步骤中实现。但是对于更多的实际项目来说,我们推荐使用三步迭代工作流程的结构化方法:

C代码

准备好需要生成代码的算法。检验并修改 MATLAB 代码来引入生成 C 代码的要素,使用支持代码生成的 MATLAB 语言和函数。

使用默认设置测试 MATLAB 代码生成时的可读性。通过生成并执行 MEX 文件来检查运行中的错误。如果运行成功,则进行下一步。如果不成功,则重复第一步直到能生成一个 MEX 函数。

生成 C 代码或保留第二步的 MEX 函数。你可以通过迭代 MATLAB 代码来优化生成的 C 代码(外观、内存和速度)或 MEX 函数(性能)。

MATLAB Coder app 会引导你在MATLAB环境中完成这一迭代过程:

分析你的 MATLAB 代码,提供输入数据的类型和大小

生成一个 MEX 函数,测试你的 MATLAB 代码是否准备好

执行 MEX 函数,检查运行错误

等效的命令行函数提供同样的功能,因此你可以生成代码作为脚本或函数的一部分。

C代码

左:自动检测不支持代码生成的特征和函数。

右:自动分析和建议输入数据的类型和大小。

- 实际生成代码的限制 -

当你准备好代码生成的 MATLAB 算法时,你需要考虑到 MATLAB 和 C 代码的差别导致的限制,包括:

内存分配。在 MATLAB 中,内存分配是自动的。在 C 代码中,内存分配则是手动的——可以是静态(static),动态(malloc),或者堆栈(局部变量)。

数组语言。MATLAB 提供丰富的数组运算集,可以简化数值算法的代码。C 代码则需要用明确的 for 循环表达同样的算法。

动态类型。MATLAB 可以在运行时自动地确定数据类型和大小。C 语言要求对所有变量和函数进行明确的类型声明。

多态性。MATLAB 函数可以支持多种不同输入类型,而 C 语言要求固定的类型声明。在顶层,你必须明确预期的 C 函数声明。

这里详细说明多态性。多态性可以根据你的输入给一行 MATLAB 代码赋予不同的意义。例如,图中的函数可以表示标量乘法,向量点积,或者矩阵乘法。另外,你的输入可以是不同的数据类型(逻辑值,整形,浮点数,定点数),也可以是实数或复数。

C代码

MATLAB 强大的算法开发环境体现于当你创建算法时,不需要考虑实现的具体细节。但是,对于等效的 C 代码,你不得不明确操作的含义。例如上述案例,MATLAB 代码可以被翻译成一行返回 B*C 的值的 C 代码:

doublefoo (doubleb,doublec)

{

return b * c;

}

或者,它可以被翻译成 11 行由 3 层 for 循环组成的将两个矩阵相乘的 C 代码:

void myMult (const doublea[12], const doubleb[20],doublec[15],)

{

inti0;

inti1;

inti2;

for(i0 = 0; i0 < 3; i0++)  {

for(i1 = 0; i1 < 5; i1++)  {

c[i0 + 3 * i1] = 0.0;

for(i2 = 0; i2 < 4; i2++)  {

c[i0 + 3 * i1] += a[i0 + 3 * i2] * b[i2 + (i1 << 2 )];

}

}

}

}

- 多核代码生成和其他优化方法 -

在 MATLAB 中,迭代过程互相独立的 for 循环可以简单地通过将 for 替换为 parfor 实现并行运行。MATLAB Coder 使用 Open Multiprocessing (OpenMP)应用程序接口来支持 parfor 循环中的共享内存和多核代码生成。OpenMP 被很多 C 编译器(例如 Microsoft Visual Studio Professional)支持 。

你可以使用有 Embedded Coder 的 MATLAB Coder 来进一步优化代码效率并定制生成的代码。Embedded Coder 提供对生成的代码的函数、文件和数据的细粒度控制的优化。

例如你可以使用存储类来控制生成的代码中全局变量的声明和定义,并使用代码生成模板来自定义生成的代码中的横幅和注释。Embedded Coder 还可以通过使用代码替换库来提高代码效率,代码替换库可以使用为 ARM Cortex-A 和 ARM Cortex-M 等流行的处理器而优化过的实现来替换某些运算符和函数。

- 测试生成的代码 -

在开发 MATLAB 算法时,你可以创建单元测试来验证算法是否能产生你预期的结果。使用 MATLAB 单元测试框架编写的测试可以被用于验证生成的代码的运行情况是否与 MATLAB 算法一致。使用 Embedded Coder 你可以结合 SIL 和 PIL 在测试生成的独立代码或库时实现单元测试的重用。

- 自动化工作流程 -

MATLAB Coder  保证了将 MATLAB 算法转换为 C 代码的自动化工作流程。这个工作流程可以花费更少的时间编写和调试低C代码,而有更多的时间用于开发、测试和调优设计。

通过 MATLAB 中的黄金参考,包括算法和测试平台,你可以更快地将算法移植到 C 代码中。MATLAB 单元测试以及 Embedded Coder 的 SIL 和 PIL 测试框架等自动化工具,可以让你全面而系统地测试MATLAB 代码和 C 代码。无论你是在传统 的PC端,Web 服务器,移动设备,还是嵌入式处理器上实现设计,MATLAB Coder 将帮助您更快地从 MATLAB 生成 C 代码,并减少手工错误。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分