摘要: 有两种方法能够实现C#语言调用matlab编写的函数:一种是利用matlab应用 类 型库直接调用matlab函数;另一种是将matlab函数编译成库函数,调用库函数。本文通过计算机器人质量质心的项目实例叙述了这两种方法的实现步骤,并对所用到的两种语言之间常用的变量转换方法进行了讲解,最后总结了这两种方法的优缺点。
关键词: C#, matlab, 混合编程, 动态链接库
matlab语言是解释型语言,它封装了C/C++语言,易学易用,而且非常适合与做矩阵运算,解微分方程、常微分方程,图像处理等科学计算。 但matlab程序运行时边解释边执行,因此执行效率较低。 C#语言是面向对象的编译执行语言,程序执行时需要先编译成目标代码,然后执行整个目标代码,因此执行效率较高;C#语言基于微软的.NET 框架,已被广泛地应用于编写计算机通讯和网络应用程序中。
软件项目开发中经常会遇到这样一种情况:项目用C#语言编写应用程序,在应用程序中需要利用一些复杂的算法,这些算法用matlab语言编写和验证比较方便快捷。 因此,需要将matlab语言编写的算法集成在C#语言编写的应用程序中,利用C#语言调用matlab函数模块。
有两种方法可将matlab语言应用在C#程序中,一种是在C#项目中引用matlab应用类型库Matlab Application Type Library, 通过MLApp.MLApp类对象的方法 Excute() 调用matlab的函数;
另一种方法是通过matlab的部署工具deploytool将matlab编译成动态链接库*.dll, 在C#项目中引用库,若库中还用到了matlab的其他组件,还要在运行C#的计算机上安装matlab编译运行时组件MCR.
本文通过项目实例介绍这两种方法的具体实施及优缺点。首先介绍matalb实现机器人质量质心的算法,算法中用到了通过矩阵的QR分解获得矩阵的特征值,解线性方程组最优解,获得工具测质量、质心的X,Y,Z坐标值;接着通过例程讲解了如何实现C#代码直接调用matlab语言和C#间接调用matlab语言编译的动态链接库的两种方法,并分析了这两种方法的优缺点。
项目实例的界面效果如下:
工具质量质心计算部分采用matlab编写的.m文件,文件位于./calibration/目录,如下图所示:
其中, test_mass_calibration.m为测试文件,用于随机输入一些数据测试质量质心;而realtime_mass_calibration.m为实际部署到项目中的文件,用于将实际测试到的关节位置下的工具的力和力矩值输入到计算模块中。
在C#项目中引用matlab应用类型库MLApp,通过MLApp.MLApp类对象的方法Excute直接调用matlab函数. 这种方法的优点是在C#项目中直接调用**.m**文件的函数,直观易用,开发效率高。缺点是要求在运行调试C#项目的计算机上必须同时安装有Visual Studio和matlab,显然这种方法只能用于科学研究,对于最终产品是不适合的,你总不能在用户购买你的软件产品的同时,还要再购买matlab软件吧。
1. 在matlab工具上编译.m函数文件成库文件。
我所用的matlab版本号为matlab1014A, 首先在matlab上检查需要编译的.m函数文件没有语法错误和运算错误,之后在命令行窗口输入deploytool,
选择Library Compiler, 进入编译界面
2. Library Compiler窗口各个变量的设置
在TYPE窗口,选择.NET Assembly; 在EXPORTED FUNCTIONS窗口,添加.m函数文件,注意只能添加函数文件,不能添加脚本文件;在PACKAGING OPTIONS区域,若选择Runtime downloaded from web ,生成的库文件只包含所添加的函数文件编译成的库文件,若选择Runtime included in package, 则除了所添加的函数文件编译成的库文件外,还需要在用户的计算机上安装MCR(参考文献1)。输入库名(Library Name)命名空间(Namespace)及类名(MassCali),点击Package,生成相应的库文件;
3. 在VS项目中,引用库文件
引用所生成的库文件目录中的for_redistribution_files_only/ToolPara.dll库文件及MWArray库文件;
4. 在界面的右边“运行”按钮的成员函数中添加如下代码:
#region 测试质量质心计算模块,该模块采用matlab算法,
// 实例化质量质心计算类的对象: massCali
ToolPara.MassCali massCali = new ToolPara.MassCali();
//计算结果
//随机测试,用于测试算法, 输入的数据来自随机产生
MWStructArray result = (MWStructArray)massCali.test_mass_calibration();
//输出结果
this.MassByLib = ((MWNumericArray)result["mass"])[1, 1].ToScalarDouble();
this.BaryCenterByLibX = ((MWNumericArray)result["p_ee_cm"])[1, 1].ToScalarDouble();
this.BaryCenterByLibY = ((MWNumericArray)result["p_ee_cm"])[2, 1].ToScalarDouble();
this.BaryCenterByLibZ = ((MWNumericArray)result["p_ee_cm"])[3, 1].ToScalarDouble();
// 若输入的数据的维度不够,计算失败并报警
double ErrorStatus = ((MWNumericArray)result["error_status"])[1, 1].ToScalarDouble();
if (ErrorStatus == 1)
MessageBox.Show("计算失败! 输入的数据不足以支持计算,请将工具置于不同的姿态并重新计算");
#endregion
同时,需要在文件的开头,添加以下库文件:
using MathWorks.MATLAB.NET.Utility;
using MathWorks.MATLAB.NET.Arrays;
1. matlab生成的库函数的输入和输出变量类型为MWArray类型
以matlab函数
function [mass] = realtime_mass_calibration(gam, force, g, p_ee_fms, num)
为例,生成的C文件的头文件中相应的函数为:
public MWArray realtime_mass_calibration(MWArray gam, MWArray force, MWArray g, MWArray p_ee_fms);
public MWArray realtime_mass_calibration(MWArray gam, MWArray force, MWArray g);
public MWArray realtime_mass_calibration(MWArray gam, MWArray force);
public MWArray realtime_mass_calibration(MWArray gam);
public MWArray realtime_mass_calibration();
public MWArray realtime_mass_calibration(MWArray gam, MWArray force, MWArray g, MWArray p_ee_fms, MWArray num);
因此,在使用这些函数时,需要将C#变量转换为MWArray变量。
2. 由于函数的输入变量为二维数组,因此用MWArray类的间接子类MWNumericArray变量作为库函数的输入变量
首先应将需要输入和输出的变量设计成二维数组,如:
double[,] g = new double[3, 1];
然后,将变量g转换为MWNumericArray变量输入给库函数:
MWStructArray result = (MWStructArray)massCali.realtime_mass_calibration(
(MWNumericArray)gam,
(MWNumericArray)force,
(MWNumericArray)g,
(MWNumericArray)p_ee_fms,
6);
3. 由于库函数输出的变量为一结构体 mass, 因此用MWArray的子类MWStructArray类变量作为函数的输出//计算结果
//随机测试,用于测试算法, 输入的数据来自随机产生
//MWStructArray result = (MWStructArray)massCali.test_mass_calibration();
//实时工作,输入的数据gam, force来自力传感器
MWStructArray result = (MWStructArray)massCali.realtime_mass_calibration(
(MWNumericArray)gam,
(MWNumericArray)force,
(MWNumericArray)g,
(MWNumericArray)p_ee_fms,
6);
//输出结果
this.Mass = ((MWNumericArray)result["mass"])[1, 1].ToScalarDouble();
this.BaryCenterX = ((MWNumericArray)result["p_ee_cm"])[1, 1].ToScalarDouble();
this.BaryCenterY = ((MWNumericArray)result["p_ee_cm"])[2, 1].ToScalarDouble();
this.BaryCenterZ = ((MWNumericArray)result["p_ee_cm"])[3, 1].ToScalarDouble();
这种方法将无需在用户的计算机上安装matlab软件,只需要安装matlab相应版本的编译运行时工具MCR,不同版本的matlab, MCR也不同,可在matlab的命令行中输入mcrinstaller查看帮助. 本文所用的matlab版本为matlab2014a, MCR安装文件在**\Matlab\R2014a\Toolbox\Compiler\deploy\win32\MCRInstaller.exe**. 因此这种方法比较适合部署到用户的计算机上。 缺点时开发阶段,每次matlab的算法调整,都需要重新编译成新的.dll库文件,对于开发者来说没有直接调用matlab函数方便快捷。
VS项目运行界面如下图所示。左边部分为采用直接调用matlab函数的方法实现C#项目集成matlab代码,右边部分为调用matlab函数编译的库文件实现C#项目集成matlab代码。每次点击 运行 按钮时,程序随机产生一组数据参与计算,因此,每次运行的结果都稍有不同。当然,若随机生成的数据的秩太小而无法满足计算时,界面会做出提示并将所有结果输出为0.
本文详细描述了直接调用matlab语句和调用matlab编译的库函数两种方法实现C#与matlab混合编程。 这两种方法中,直接调用matlab语句比较方便开发,但不利于部署到用户的计算机上;而调用matlab库文件的方法部署到用户的计算机上比较方便,但在开发时多了一步编译的过程,每次matlab程序修改后,都要重新编译一次才能被VS项目使用。
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删