技术文章和通讯

从MATLAB生成C代码用于Java和。net应用程序

MathWorks的Christophe Pouillot著


您可以最大限度地利用在MATLAB中开发、测试和验证的算法®通过与未安装MATLAB的其他人共享该算法。为了避免用另一种语言重新编码该算法所带来的开发和测试成本,有两种方法可用:使用MATLAB编译器™ SDK或使用MATLAB编码器™.

MATLAB编译器SDK加密您的算法并将其打包到C/C++共享库中,Microsoft®Python。net程序集,®软件包和Java®类。使用这些组件构建的应用程序在MATLAB运行时上运行,该运行时提供了对MATLAB语言、图形和工具箱的访问,而不需要MATLAB接口。MATLAB Runtime可以安装在任何能够运行MATLAB的目标平台上,比如运行Windows、MacOS或Linux的桌面或服务器平台。

如果在目标平台上安装MATLAB运行时是不可能的,考虑使用MATLAB编码器从MATLAB算法的数值计算部分生成C或C++代码。生成的代码可以用作更大系统的组件。这种方法适用于Android和iOS等智能手机平台。

本文介绍了使用MATLAB Coder在C/ c++、. net或Java环境中部署MATLAB应用程序的工作流,而不需要安装MATLAB Runtime。使用卡尔曼滤波器的代码说明了工作流程。

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

C/C++、.NET和Java目标平台的工作流

部署到C/ c++、。net或Java目标平台的起点是使用MATLAB Coder从MATLAB代码生成C代码。下一步是有针对性的,具体如下:

  • 对于C/C++平台,可以直接使用生成的C代码。
  • 对于。net平台,您可以通过平台调用服务(P/Invoke),一种允许托管代码调用本机代码的技术。
  • 对于Java平台,您可以编写C包装代码以使生成的C代码能够与Java本地接口(JNI)一起使用1

MATLAB中卡尔曼滤波函数的原型为:

函数y = kalmanfilter (z)%%MATLAB代码

部署。净

要让应用程序在。net平台上运行,请遵循以下五个步骤(图1):

图1所示。将MATLAB部署到。net平台的步骤。
  1. 运行MATLAB Coder从MATLAB代码生成C代码和DLL。

您可以创建MATLAB编码器项目或运行命令行函数codegen.这两种方法都允许指定输出目录和生成的dll的名称—这是一个很好的实践,因为它避免了将MATLAB当前文件夹与生成的文件混在一起。

对于卡尔曼滤波器,生成C代码的MATLAB命令为:

codegen–o MATLAB_CODER_DLL–d..\autogen_matlabcoder kalmanfilter.m-args{zeros(2,1)}
  1. 打开由MATLAB Coder生成的头文件*.h,查看由MATLAB函数生成的C函数接口。

在我们的例子中,MATLAB卡尔曼滤波器将被转换成一个C函数,其原型是:

外面的空白Kalmanfilter(const双z [2],双重的y [2]);/*C代码*/

我们为双参数生成卡尔曼滤波器,因为双参数是MATLAB的默认类型。(注意,MATLAB Coder允许您更改生成代码的数据类型,而无需更改您的MATLAB代码。)

  1. 检查函数参数的C数据类型,并将它们转换为。net数据类型。

这一步很重要,因为您必须用。net语言编写函数声明。有关更多信息,请参见平台调用数据类型

表1显示了等价的C和。net类型。

C类型 net类型 描述
空虚* 系统。IntPtr 32位Windows操作系统上的32位
64位的Windows操作系统
无符号字符 系统。字节 8位
短的 系统。Int16 16位
无符号短 系统。UInt16 16位
int 系统。Int32 32位
无符号整型 系统。UInt32 32位
系统。Int32 32位
无符号长 系统。UInt32 32位
烧焦 系统。字符 用ANSI装饰
wchar_t 系统。字符 用Unicode装饰
char * System.String或System.Text.StringBuilder 用ANSI装饰
donst char * System.String或System.Text.StringBuilder 用ANSI装饰
wchar\t* System.String或System.Text.StringBuilder 用Unicode装饰
康斯特沃克哈特酒店* System.String或System.Text.StringBuilder 用Unicode装饰
浮动 系统。单 32位
双重的 系统。双 64位

表1。等价于C和。net数据类型。

该表表明“双”C类型将简单地翻译成一个系统。双net类型。这意味着C函数原型是这样的:

无效Kalmanfilter(const双z [2],双重的y [2]);/*C代码*/

可以翻译成以下.NET C#函数原型:

无效kalmanfilter(Double[] a, Double[] b);/* c#代码*/

请确保将.NET或Java类型与C类型正确匹配。不匹配不会在编译和运行时引发错误,但数值无效。

  1. 编写. net代码来声明和调用导入的函数。

在我们的示例中,我们编写了以下Visual Basic .NET代码:

Visual Basic.NET代码导入System.Runtime.InteropServices模块Module1 < DllImport (“MATLAB_CODER_DLL.dll”,CallingConvention:=CallingConvention.Cdecl)>公共子Kalmanfilter(按值传递一()作为双按值传递b ()作为双终止子Main ()昏暗的正义与发展党作为双() ak = {1,2}昏暗的汉堡王作为双() bk = {0,0}终止子终端模块

此外,我们用c#编写了以下代码。

/* c#代码*/使用System.Runtime.InteropServices;类程序{[DllImport (“MATLAB_CODER_DLL.dll”,CallingConvention=CallingConvention.Cdecl)]公共静态外部无效kalmanfilter(Double[] a, Double[] b);静态的空白主要(一串[] args) {Double[] ak = {1,2};双[]bk =双[2];kalmanfilter (ak, bk);} }

请注意这两种代码之间的相似性:Visual Basic.NET代码提供了一个包含“main”过程的模块,而C#有一个包含“main”方法的类。这两种代码语言都需要使用InteropServices函数,其中包含用于P/Invoke技术的方法。

生成.NET代码不需要DLL文件或C头文件。相反,构建将依赖于您自己在“DllImport”语句中对函数的.NET声明。这意味着,如果.NET声明与C声明不兼容,但与.NET调用兼容,则生成.NET代码不会引发错误。该错误仅在运行时出现。

  1. 运行.NET代码。确保将DLL文件和可执行文件存储在同一文件夹中。

部署到Java平台

要准备应用程序在.Java平台上运行,请遵循以下七个步骤(图2):

图2。将MATLAB部署到Java平台的步骤。
  1. 运行MATLAB编码器从您的MATLAB代码生成C代码。

生成卡尔曼滤波器的C代码的MATLAB命令如下

codegen -o MATLAB_CODER_DLL -d ..\ autogen_matlabcoder kalmanfilter。m参数{0 (2,1)}

当部署到JAVA时,我们使用选项“-c”,而不是DLL。来生成c代码。我们需要编写额外的c代码来获得JAVA的最终DLL。

  1. 编写包含函数的Java声明的Java代码。

Java声明不仅在语法和数据类型上不同于C声明,而且在参数上也不同。C函数接受数组指针作为输出参数,而Java则返回对象数组。相应地,您必须将您的C原型转换为Java原型。但是,请记住,您的C函数的包装器,而不是C本机函数,将在Java代码中直接调用。

对于卡尔曼过滤器,我们编写以下Java代码,并将其保存到名为example.java的文件中。

公共课范例{/*加载C DLL */静态{System.loadLibrary (“MATLAB_JNI”);}/*函数原型*/Public static native double[] kalmanfilter (双重的[]a);

我们可以将调用添加到我们的函数中,但是在工作流的这一点上,我们只需要函数声明。我们将在步骤5中添加调用。

注意,结果数组是Java函数的返回值,而它是C函数的输出参数。

  1. 从保存的Java文件生成一个C头文件。

在我们的例子中,我们使用javahJava开发工具包中的工具。这个工具从包含本地方法的给定Java类创建C头文件。

我们运行以下MATLAB命令:

!javah示例% MATLAB命令

与MATLAB系统中的所有可执行文件命令一样,该文件javah.exe必须由运行MATLAB的操作系统知道。在Windows上,这意味着环境变量PATH必须包含javah.exe

上面的命令将生成一个C头文件,其中包含以下JNI C函数声明:

JNIEXPORT jdoubleArray JNICALL Java_example_kalmanfilter(JNIEnv *, jclass, jdoubleArray);
  1. 为JNI C声明编写C实现代码。这个C包装器代码执行以下操作:

    • 将JAVA类型数据转换为C类型数据
    • 调用C函数
    • 将C类型数据转换为JAVA类型数据

卡尔曼滤波器的包装器C代码如下所示:

JNIEXPORT jdoubleArray Java_example_kalmanfilter (JNIEnv *env, jclass cls, jdoubleArray a)/*C代码*/{jdouble临时[2];/ * 1。复制JAVA数组到C数组*/jdouble* ac = (*env)->GetDoubleArrayElements(env,a,0);/*创建新的JAVA数组*/jdoubleArray结果= (*env)->NewDoubleArray(env, 3);如果(result != NULL) {/*2.调用C函数*/kalmanfilter (ac,临时);/ * 3。将C数组复制到Java数组*/(*env)->SetDoubleArrayRegion(env,result,0,3,temp);}/*删除临时C数组*/(*env)->释放双数组元素(env,a,ac,0);返回结果;}

注意,Java类型本身被转换为JNI类型。事实上,双[]Java数组类型显示为jdoubleArray,而double Java类型则显示为jdouble类型。

表2显示了Java和Java JNI类型之间的等价性(有关更多信息,请参阅JNI类型和数据结构).

Java类型 原生类型 描述
布尔值 jboolean 无符号8位
字节 Jbyte 签署了8位
烧焦 jchar 无符号16位
短的 jshort 签署了16位
Int 吉特 有符号32位
签署了64位
浮动 jfloat 32位
双重的 jdouble 64位
无效 无效 N/A

表2。Java和Java JNI数据类型。

  1. 构建jnicdll。DLL包括:

    • 由MATLAB Coder在步骤1中创建的C源文件
    • 控件创建的C JNI头文件javah步骤3中的工具
    • 第4步中为JNI接口编写的包装器C代码
  1. 向Java代码中添加函数调用并编译它。
/* JAVA代码*/公共课范例{/*加载C DLL */静态{System.loadLibrary (“MATLAB_JNI”);}Public static native void初始化();Public static native double[] kalmanfilter (双重的[]a);公共静态无效main(String[] args) {example myM =例();myM.initialize ();//初始化卡尔曼滤波器双重的[] ak = {1,2};双重的[] bk = myM.kalmanfilter(ak);//调用本机方法} }

注意一个的存在初始化函数。该函数由MATLAB编码器创建。由于kalmanfilterMATLAB函数使用持久变量。因此,我们需要声明和包装“initialize”函数。

  1. 运行Java代码。确保DLL文件位于与Java可执行文件相同的文件夹中。

这种方法的好处

我们已经概述了一个工作流,允许您将MATLAB算法部署到任何平台上,即使是不支持MATLAB的平台。万博1manbetx平台框架可以是C、c++或Java语言。

这种工作流程的好处是很多的。您不仅可以避免用另一种语言重写MATLAB代码的成本和测试翻译后的代码的成本,还可以节省开发时间并从MATLAB Coder获得生产质量的C代码。

1JNI技术不是在JAVA代码中调用本机C的唯一方法。您还可以使用称为JAVA本机访问(JNA)的技术。JNA需要使用额外的包。

关于作者

Christophe Pouillot是MathWorks的高级顾问。他的专业领域包括自动代码生成、模型验证和验证,以及开发、部署MATLAB和Simulink应用程序,并将其与其他技术语言连接。在加入MathWorks之前,Christophe设计并开发了多个行业的软件应用程序,包括能源、汽车和航空航天。克里斯托弗拥有法国南特中心大学机器人工程学士和硕士学位。万博1manbetx

发布于2015 - 92946v00

查看相关功能的文章