技术文章

从MATLAB生成C代码的乐趣

作者Bill Chou,MathWorks


几十年来,工程师们已经使用编译器将C等低级语言翻译成机器代码。但是,有可能翻译像MATLAB这样的高级语言吗®使用编码器转换成C?大多数工程师会同意这在理论上是可能的,但在实践中可行吗?生成的代码可读还是意大利面?高效还是臃肿?快还是慢?它支持工业工作流,还是仅仅支持研发?

本文正面解决了这些问题。它提供了使用MATLAB Coder™的技巧和最佳实践,以及Delphi、Baker Hughes、iSone和dorsaVi等公司成功应用生成代码的行业示例。

本文中的代码示例可用于下载。

MATLAB与C代码的比较:一个乘法示例

下面的简单MATLAB函数将两个输入相乘。

MATLABtoC-01a(材料实验室)

给定标量输入,MATLAB编码器生成以下C代码:

MATLABtoC-01b

如您所见,生成的代码清楚地映射回MATLAB代码。

当给定两个矩阵输入时,同一段MATLAB代码会生成三个嵌套的对于-C中的循环:

MATLABtoC-01c(数学实验室)

推荐的三步迭代工作流

上面显示的简单功能可以在一个步骤中实现。但对于更实质性的项目,我们建议采用结构化方法,使用三步迭代工作流(图1):

  1. 为代码生成准备算法。检查并修改MATLAB代码,以介绍低级C代码所需的实现注意事项,并使用MATLAB支持的语言和函数代码生成。
  2. 使用默认设置测试MATLAB代码是否可以生成代码。通过生成和执行MEX文件来检查运行时错误。如果成功,请转至下一步。如果没有,请重复步骤1,直到可以生成MEX函数。
  3. 生成C代码或保留步骤2中的MEX函数。您可以迭代MATLAB代码来优化生成的C代码(外观、内存和速度)或MEX函数(性能)。
图1。生成代码的三步迭代工作流。
图1。生成代码的三步迭代工作流。

MATLAB Coder应用程序引导您完成这个迭代过程,同时使您能够留在MATLAB环境中。它分析您的MATLAB代码,为您的输入建议数据类型和大小。它通过生成MEX函数来测试MATLAB代码是否已准备好进行代码生成,然后执行MEX函数检查运行时错误(图2)。等效的命令行函数提供了相同的功能,因此您可以将代码作为脚本或函数的一部分生成。

图2。左:自动检查代码生成不支持的特性和功能。右:输入数据类型和大小的自动分析和建议。
图2。左:自动检查代码生成不支持的特性和功能。右:输入数据类型和大小的自动分析和建议。

视频“从MATLAB代码生成C代码”(见下文)以生成卡尔曼滤波器预测弹跳球的轨迹为例说明了这些步骤。您将看到,三步迭代过程使我们能够生成与原始MATLAB结果密切匹配并满足其跟踪要求的代码。

实施限制

在为代码生成准备MATLAB算法时,需要考虑MATLAB和C代码之间的差异导致的实现约束。其中包括:

  • 内存分配。在MATLAB中,内存分配是自动的。在C代码中,内存分配是手动的,可以静态分配(使用静止的),动态(使用malloc公司),或在堆栈上(使用局部变量)。
  • 基于数组的语言。MATLAB提供了一组丰富的数组操作,可以对数值算法进行简明编码。C代码需要显式对于-循环来表示相同的算法。
  • 动态键入。MATLAB会在代码运行时自动确定数据类型和大小。C需要对所有变量和函数进行显式类型声明。
  • 多态性。MATLAB函数可以支持许多不同的输入类型,而C需要固定的类型声明。在顶层,您必须指定预期的C函数声明。

让我们仔细看看多态性。多态性可以根据您的输入为一行MATLAB代码赋予不同的含义。例如,图3中显示的函数可以表示标量乘法、点积或矩阵乘法。此外,输入可以是不同的数据类型(逻辑、整数、浮点、定点),也可以是实数或复数。

图3。多态性示例。
图3。多态性示例。

MATLAB是一个强大的算法开发环境,因为在创建算法时,您不需要担心实现细节。然而,对于等价的C代码,您必须指定操作的含义。例如,上面显示的一行MATLAB代码可以转换为返回B*C的这一行C代码:

MATLABtoC-04b型

或者,它可以被翻译成11行C代码,用3对于-将两个矩阵相乘的循环:

MATLABtoC-04c型

视频“使用MATLAB编码器解决实现约束”(见下文)使用Newton-Raphson算法来说明将实现约束考虑在内的概念。您将看到使用三步迭代工作流程生成的代码与原始MATLAB结果完全匹配。

使用生成的代码:四个用例

使用MATLAB编码器从MATLAB算法生成可读和可移植的C/C++代码后,您可以选择使用它。例如,您可以:

  • 将MATLAB算法作为源代码或库集成到大型软件项目中,例如在PC和服务器上运行的自定义模拟器或软件包(请参阅下面的视频“使用MATLAB编码器将代码集成到Visual Studio”)
  • 在ARM等嵌入式处理器上实现并验证MATLAB算法®处理器和移动设备(请参阅下面的视频,“使用MATLAB编码器部署到iPhone和iPad应用程序”)
  • 将MATLAB算法原型化为PC上的独立可执行文件(参见下面的视频“使用MATLAB生成原型的可执行文件”)
  • 通过生成调用编译的MEX函数来加速MATLAB代码的计算密集型部分(参见下面的视频“使用MATLAB编码器加速图像压缩算法”)

行业成功案例

  • 贝克休斯动力与遥测小组根据序列预测算法生成DLL,并将其集成到PC上运行的地面解码软件中,该软件使井下数据能够在钻井操作期间快速可靠地解码。
  • 多尔萨维从运动分析算法中生成C++代码并将其编译成DLL,然后将其集成到运行在PC上的C#应用程序中,该应用程序分析运动员的运动以诊断损伤。

  • VivaQuant公司根据心律监测算法生成定点C代码,并为ARM Cortex-M处理器编译。
  • 德尔福生成了汽车雷达传感器对准算法的C代码,并将其编译为ARM10处理器。
  • 呼吸根据声学呼吸监测算法生成C代码,并为iPhone应用程序、Android应用程序和基于云的服务器软件编译。

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

在MATLAB中,对于-迭代彼此独立的循环可以通过替换并行运行对于具有帕尔夫MATLAB编码器使用Open Multiprocessing(OpenMP)应用程序接口支持共享内存、多核代码生成帕福循环。许多C编译器(例如Microsoft)都支持OpenMP®Visual Studio®专业)。

多核能力代码生成

您可以将MATLAB编码器与嵌入式编码器一起使用®以进一步优化代码效率并定制生成的代码。嵌入式编码器为生成代码的函数、文件和数据的细粒度控制提供了优化。例如,您可以使用存储类控制生成代码中全局变量的声明和定义,并使用代码生成模板自定义生成代码中的横幅和注释。嵌入式编码器还通过使用代码替换库来提高代码效率,代码替换库用针对流行处理器(如ARM Cortex公司®-一个手臂皮质-M.

测试生成的代码

在开发MATLAB算法时,可以创建单元测试来验证算法是否产生预期的结果。使用编写的测试MATLAB单元测试框架可以重复使用,以验证生成的代码的行为是否与您的MATLAB算法相同。视频“使用MATLAB编码器对生成的代码进行单元测试”和“用MATLAB和MATLAB解码器对C代码进行单元检测”(见下文)展示了如何将嵌入式编码器中的单元测试与生成的独立代码或库上的软件互操作(SIL)和处理器互操作(PIL)测试结合使用。

自动化工作流

MATLAB编码器支持将MATLAB算法转换为C代码的自动化工作流。使用此工作流,您可以减少编写和调试低级C代码的时间,而花费更多的时间开发、测试和调整设计。通过在MATLAB中维护一个黄金参考,包括算法和测试台,您可以更快地将算法更改传播到C代码中。自动化工具,如MATLAB单元测试框架和嵌入式编码器SIL和PIL测试框架,可以让您彻底系统地测试MATLAB代码和C代码。您是否正在执行上运行的设计传统PC,web服务器,移动设备,或嵌入式处理器,MATLAB编码器将帮助您更快地从MATLAB转换到C代码,并且减少手动翻译错误。

2016年出版- 92987v00版