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

MathWorks的Christophe Pouillot著

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

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

如果无法在目标平台上安装MATLAB Runtime,请考虑使用MATLAB Coder从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 Coder项目或运行命令行函数codegen.这两种方法都允许指定输出目录和生成的dll的名称—这是一个很好的实践,因为它避免了将MATLAB当前文件夹与生成的文件混在一起。

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

codegen -o MATLAB_CODER_DLL -d ..\ autogen_matlabcoder kalmanfilter。m参数{0 (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类型 描述
void * 系统。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.Text.StringBuilder 装饰与ANSI
donst char * 系统。字符串或System.Text.StringBuilder 装饰与ANSI
wchar_t * 系统。字符串或System.Text.StringBuilder 装饰与Unicode
Const wchar_t * 系统。字符串或System.Text.StringBuilder 装饰与Unicode
浮动 系统。单 32位
系统。双 64位

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

该表表明,“double”C类型将被简单地转换为a系统。双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)]Public static extern voidkalmanfilter(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 ([]);

我们可以将调用添加到我们的函数中,但是在工作流的这一点上,我们只需要函数声明。我们将在步骤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)-> releasedoubllearrayelements (env, a, ac, 0);返回结果;}

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

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

Java类型 原生类型 描述
布尔 jboolean unsigned 8位
字节 Jbyte 签署了8位
字符 jchar 无符号16位
jshort 签署了16位
Int jint 签署了32位
jlong 签署了64位
浮动 jfloat 32位
jdouble 64位
无效 无效 N/A

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

  1. 构建JNI C DLL。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 ([]);公共静态无效main(String[] args) {example myM =例();myM.initialize ();//初始化卡尔曼滤波器[] ak = {1,2};[] bk = myM.kalmanfilter(ak);//调用本机方法} }

注意一个的存在初始化函数。该函数由MATLAB Coder编写。这是卡尔曼滤波器所要求的kalmanfilterMATLAB函数使用持久变量。因此,我们需要声明和包装“initialize”函数。

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

这种方法的好处

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

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

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

关于作者

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

发布于2015 - 92946v00


查看相关功能的文章