分享

【原创】简析MATLAB和.NET混合编程

 伊本经阁 2012-05-30

简析MATLAB和.NET混合编程  

0.背景

MATLAB作为一款功能强大、效率高、交互性好的可视化高级计算机语言,在数值计算、自动控制、数字信号处理、图形处理、仿真、神经网络、小波分析等各个领域有着广泛的应用。虽然MATLAB是一个完全独立的编程和数据运算的集成环境使用它可以很方便地做很多工作,但是,很多时候仅仅依靠MATLAB环境还是不能很好地完成工作,例如一个大的项目中需要使用到MATLAB中很容易实现而且很有些的功能时,如果这个时候使用特定语言开发,将会是一个费时费力的事情,而且稳定性、效率方面都不如MATLAB好;或者,其他语言编写的优秀程序,如果想在MATLAB中使用,就要重写M文件,造成了人力和物力的浪费,所以MATLAB和其他程序之间的数据交换就显得十分必要,MATLAB程序接口的出现,就解决了这些问题,通过接口与其他编程环境交互,各取所长,充分发挥MATLAB计算的优点,而避开MATLAB效率低的问题。

1.MATLAB的接口

       MATLAB提供了多种编程语言的接口,通过微软的组建对象模型(Component Object ModelCOM)完成外部程序、客户端和服务端之间的通讯和数据共享,这些功能的实现都是使用了MATLAB的应用程序接口(Application Program InterfaceAPI)来实现的。

下图是MATLAB提供的接口。

简析MATLAB和.NET混合编程 - Castor - 趁年轻,多折腾~~
 MATLAB使用自身强大的编译器可以将MATLAB的应用程序编译为一个独立的程序(.exe)或者组件(.dll),这些组件又能够被FortranCC++等高级语言调用,实现了和其他程序之间的交互;通过使用MATLAB Builder EX,将MATLAB的函数打包为组件,这样就能够能被Excel使用;通过使用MATLAB Builder JA,可以由MATLAB程序创建Java语言中的类,这些类完全可以在没有安装MATLAB的桌面计算机或者网络服务器上运行。通过使用MATLAB Builder NE,将MATLAB函数封装入.NET中类的方法,这些类就可以像其他托管代码一样被.NET环境下的所有语言调用,例如C#VB.NETJ#C++.NETF#等语言,甚至是网络程序也可以调用,例如ASP.NET

2.外部语言的选取

由上节可见MATLAB的编程接口是相当丰富的,这里就.NET方式讨论,使用.NET的接口有如下几个优点:

代码安全。作为托管代码,不会出现指针带来的问题,这就保证了程序的稳定性

容错机制。C#中具有异常处理方法,因此即使程序在运行中出现了错误,也能从故障中快速恢复,或者提供较好的摆脱异常的方法,而不是像其他程序那样造成程序崩溃。

面向对象。通过将函数打包为一个类的方法,实现了完整的面向对象编程,方便了代码的阅读和管理,并能够实现面向对象中的重载、继承、多态等功能。

2.1什么是.NET

       .NET的定义,根据微软官方的描述:

       .NET is a "revolutionary new platform built on open Internet protocols and standards with tools and services that meld computing and communications in new ways".NET 是微软公司的一组软件技术,用来连接信息、人、系统和各种设备。它通过使用 Web Services 技术来获得软件的高度集成。除了将小型的、分散的、构建模块应用互相连接起来,还将 Internet 上的更大应用连接起来。微软总裁兼首席执行官Steve Ballmer把它定义为:.NET代表一个集合,一个环境,一个可以作为平台支持下一代Internet的可编程结构。

       .NET的核心部分是.NET Framework,这是一组框架,是.NET的核心支持库,.NET Framework提供CLR(公共语言运行时)提供了对各种程序的支持,通常将在CLR的控制下运行的代码,称为托管代码(managed code)。使用.NET开发的程序需要在.NET Framework下才能运行,就像VB的程序需要VB运行库,java程序需要JVMJava虚拟机)一样。下图是.NET Framework的架构:

简析MATLAB和.NET混合编程 - Castor - 趁年轻,多折腾~~
        通过使用Visual Studio.NET开发工具,可以使用多种语言开发,采用CLS(公共语言规范)后,编译为中间语言,这种语言是专门针对公共语言的,和其他高级语言无关,因此,高级语言可以在这个层面上实现融合和互通,这也是.NET架构的一大优势,也是其成功的关键因素。最后,在CLR(公共语言运行时)提供的支持,从而在操作系统上运行。MATLAB Builder NE就是将M文件编译为位于Basic Class Library同一层,实现了程序的运行

2.2语言的选择

       首先需要明白的是,NET Framework只是一个平台,并不是一种具体的编程语言,实际开发过程中需要有一种具体的语言和对应的工具,根据微软的构想,在推出.NET架构的同时,还是推出了一款专门针对该平台的语言——C#,该语言是纯粹面向对象的,并能最大化地释放.NET平台的优势,实现了软件的安全、快速开发。另外,根据上图可知,使用的开发工具是Visual Studio.NET,微软旗舰级的开发工具Visual Studio也升级到了2010版,该开发工具是一套可视化的编程环境,其强大的功能,如自动代码、智能感知、错误高亮、代码重构等功能,使程序开发起来事半功倍。

3.如何实现混合编程

       如前面所说,混合编程有一个很显著的问题,就是最终的程序以何种方式实现。这涉及到了两种实现方。首先,可以将.NET程序在MATLAB中运行,这个时候MATLAB是宿主程序,而.NET程序以一种插件的方式存在,共享MATLAB的内存空间;另一种方式是将NATLAB程序编译为托管代码,然后在C#的程序中调用,这个时候就脱离了MATLAB的环境,可以形成独立的软件。

3.1使用MATLAB.NET接口

这种方式是以MATLAB为主程序,.NET程序以插件的方式为MATLAB调用,该方法对MATLAB的要求很简单,基本不需要做任何改动。事实上MATLAB天然的提供了对.NET程序的支持。

通过使用这种方式,可以实现:1..NET中类的实例。2.通过使用类成员操作.NET程序。当然,这种方法和一般的面向对象还是有一些局限性,例如不能访问子类,不能将.NET对象保存到MAT文件中,也不能使用控制台输入、输出等。

事实上,使用这种方式开发的人员,更多的是.NET程序员,他们无需关心MATLAB是如何实现的,也用不着和MATLAB打交道,只需要在编程中能够将自己的接口暴露给MATLAB即可,当然了电脑上必须安装.NET Framework才能实现。

下面是一个简单的例子:

例如在MATLAB的命令窗口中输入:

>> dt=System.DateTime(2011,5,11)

运行结果为:

dt =

  System.DateTime

  Package: System

  Properties:

           Date: [1x1 System.DateTime]

            Day: 11

      DayOfWeek: [1x1 System.DayOfWeek]

      DayOfYear: 131

           Hour: 0

           Kind: [1x1 System.DateTimeKind]

    Millisecond: 0

         Minute: 0

          Month: 5

            Now: [1x1 System.DateTime]

         UtcNow: [1x1 System.DateTime]

         Second: 0

          Ticks: 634406688000000000

      TimeOfDay: [1x1 System.TimeSpan]

          Today: [1x1 System.DateTime]

           Year: 2011

       MinValue: [1x1 System.DateTime]

       MaxValue: [1x1 System.DateTime]

  Methods, Superclasses

       为什么是这个结果?首先,MATLAB在启动的时候会自动加载程序集System.dll(另一个是mscorlib.dll),该程序集是.NET中非常重要的文件之一,提供了基本类型、数学计算等功能。而DateTime就是其中的一个结构体,该结构体主要用于描述时间。使用该结构体创建了一个实例dt,然后调用的构造函数是DateTime(year,month,day)MATLAB显示关于该实例的基本信息,并在最后还提供显示该结构体方法和超类的链接。

如果再输入:

>> dt.Year

则显示:

ans =

        2011

       这里就访问了.NET代码中的属性。事实上,MATLAB提供了专门的函数查看托管类的属性和方法。

例如输入:

>> properties System.DateTime

>> methods System.DateTime

       就可以查看一个结构体或者类支持的方法和属性。

3.2如何开发自定义类

       虽然.NET提供了大量的类和方法,但是并不能满足实际工作中的需要,有时需要自己开发一些自定义的类,使用Visual Studio.NET将会很轻松地实现开发。

       VS中新建一个类库的项目,在Class1.cs中输入如下内容:

using System;

using System.Collections.Generic;

using System.Text;

using System.Windows.Forms;

namespace ToMATLAB

{

    public class XDClass

    {

        //这是一个不带返回值的方法

        public void Message()

        {

            MessageBox.Show("Here is Dot Net~");

        }

       

        //这是一个属性

        public string Help

        {

            get

            {

                return "I am a Property of Class XDClass";

            }

        }

        //这是一个带返回值的方法,利用海伦公式计算三角形面积

        public double TriangleArea(double a,double b,double c)

        {

            double max = a;

            if (max < b) max = b;

            if (max < c) max = c;

            if (2 * max >= a + b + c)

                return -1;//不构成三角形

            else

            {

                double p = (a + b + c) / 2;

                return Math.Sqrt(p * (p - a) * (p - b) * (p - c));

            }

        }

    }

}

       然后按F6编译生成一个名为ToMATLAB.dll文件,该文件就是被MATLAB加载的.NET程序集。然后在MATLABCommand Window中输入:

>> asmInfo = NET.addAssembly('C:\Users\Castor\Desktop\ToMATLAB.dll')

效果如下:

asmInfo =

  NET.Assembly handle

  Package: NET

Properties for class NET.Assembly:

    AssemblyHandle

    Classes

    Structures

    Enums

    GenericTypes

    Interfaces

    Delegates

NET.addAssembly函数加载一个.NET的程序集,即编译生成的动态链接库文件,加载完成后可以通过Properties函数或者methods函数查看其属性和方法。运行如下:

>> properties ToMATLAB.XDClass

Properties for class ToMATLAB.XDClass:

    Help

>> methods ToMATLAB.XDClass

Methods for class ToMATLAB.XDClass:

Equals Message       XDClass       eq            ge            le            notify

GetHashCode   ToString      addlistener   findobj       gt            lt           

GetType       TriangleArea  delete        findprop      isvalid       ne

       可见MATLAB能够识别我们编写的方法和属性,下面测试一下属性和方法:

>> xd=ToMATLAB.XDClass()

xd =

  ToMATLAB.XDClass handle

  Package: ToMATLAB

  Properties:

    Help: [1x1 System.String]

  Methods, Events, Superclasses

>> xd.Help

ans =

I am a Property of Class XDClass

>> xd.Message

>> xd.Message

xd.Message

>> xd.TriangleArea(3,4,5)

ans =

     6

>> xd.TriangleArea(3,4,1)

ans =

-1

当运行到Message的时候,会出现一个对话框:

简析MATLAB和.NET混合编程 - Castor - 趁年轻,多折腾~~

这是使用了.NET中的MessageBox.Show方法的原因,另外要注意的是,该对话框是有模式的对话框,这个时候编译器会挂起,虽然在Command Window下可以输入命令,但是却不能被编译器解释,这是模式对话框的一个显著特点。最后调用了xd实例的方法,利用海伦公式计算一个三角形的面积,当提供的三个参数不能构成三角形的时候,计算结果为-1,其实这个时候应该理解为错误代码,显然面积应该是一个正数,通过检查该值可以判断方法是否正确运行。

4.外部程序调用MATLAB函数

相比前一种方式,这种方法实施起来显得有些复杂,但是可扩展更大,这种方式可以完全脱离MATLAB环境,实现软件的快速开发。

在实施这一混合编程之前,需要先介绍独立于MATLAB的程序一些基本问题的。

4.1 MCR简介

 MCR的全称是MATLAB Compiler Runtime,即MATLAB编译器运行时。根据MathWorks公司的定义:

The MATLAB Compiler Runtime (MCR) is an execution engine made up of the same shared libraries MATLAB uses to enable the execution of MATLAB files on systems without an installed version of MATLAB.

可见MCR是一个由MATLAB共享类库构成的执行引擎,他能够使MATLAB文件在没有MATLAB的机器上运行。这一点和.NET Framework相对于.NET程序一样,即为程序的运行提供了底层支持。当发布程序的时候,需要将MCR也打包进来,否则没有MATLAB的机器上程序不能执行,如同.NET程序不能在没有.NET Framework的机器上运行一样。MCRMATLAB软件一同发布,可以在MATLAB中输入命令“mcr”或者“mcrinstaller”获取其保存路径:

>> mcr

The WIN32 MCR Installer, version 7.14, is:

    D:\MATLAB\toolbox\compiler\deploy\win32\MCRInstaller.exe

MCR installers for other platforms are located in:

    D:\MATLAB\toolbox\compiler\deploy\<ARCH>

  <ARCH> is the value of COMPUTER('arch') on the target machine.

Full list of available MCR installers:

D:\MATLAB\toolbox\compiler\deploy\win32\MCRInstaller.exe

For more information, read your local MCR Installer help.

Or see the online documentation at The MathWorks' web site. (Page may load slowly.)

根据上面的运行结果,可知该文件的完整路径是:

D:\MATLAB\toolbox\compiler\deploy\win32\MCRInstaller.exe

4.2 MWArray API简介

 MCR包含了文件MWArray.dll,该文件中的API承担了用户程序和MCR之间数据交换的任务,因此,每一个独立文件都需要包含对该文件的引用,否则程序就不能使用MATLAB中的函数,为使用该文件,需要先安装MCR,该文件在安装完MCR后位于:installation_folder\toolbox\dotnetbuilder\bin\architecture\framework_version

另外,该文件中有两个重要的命名空间,MathWorks.MATLAB.NET.ArraysMathWorks.MATLAB.NET.UtilityArrays命名空间下的类提供从其他任何兼容CLSCommon Language Specification 语言访问MATLAB中数组的功能,这些类支持数组格式化、类型的特定索引和错误处理的功能。而Utility命名空间下的类提供了对MWArray类架构和MATLAB公共运行时的托管API的通用支持。

4.3.混合编程的实施

为了将MATLAB中的程序作为组件提供给其他.NET程序使用,需要做两方面的工作:

1.M文件打包为与.NET兼容的程序集

2.在外部程序中添加对程序集的引用

4.3.1 MATLAB端的工作

首先是将M文件打包为程序集。MATLAB将函数作为某个类中的方法,通过对类的操作实现对函数的调用。首先准备好函数,这些函数需要保存在M文件中,例如MATLAB中的函数SVD很强大,而我们不想自己重写,或者对幻方比较感兴趣,也不知道具体如何事实,但是在MATLAB下面只要一个函数就能解决,这些功能对外部程序就很有用,下面是这两个M文件:

%函数1.矩阵的SVD分解

function [u,s,v]=XDSVD(A)

    [u,s,v]=svd(A);

end

 

%函数2.生成幻方矩阵

function m=XDMagic(n)

    m=magic(n);

end

假设这两个文件分别保存为XDSVD.mXDMagic.m,下面将其打包为.NET兼容的组件。这就需要使用deploytool命令:

MATLAB的命令窗口中输入:

>> deploytool

将出现如下对话框,设置好项目名,并指定目标组件的形式是.NET Assembly,然后确定。
 简析MATLAB和.NET混合编程 - Castor - 趁年轻,多折腾~~
       Deployment Tool中添加一个名为Functions的类,并为该类添加我们事先准备好的两个M文件。

简析MATLAB和.NET混合编程 - Castor - 趁年轻,多折腾~~

  这个时候XDMagicXDSVD函数将作为Functions类的方法而存在,这个时候就可以点击开始编译了,不过在编译之前,还需要说说Package标签下的一些细节。

简析MATLAB和.NET混合编程 - Castor - 趁年轻,多折腾~~
        由上图可见,该标签页下会显示编译之后的文件,下方还有一个链接是Add MCR,该功能是将MCRInstaller.exe也作为程序的组件打包进去,如果使用这个方式,编译程序会变得很大(不添加才1KB,如果添加会变为173MB),会显著增加编译时间,实际上更好的方法是,不添加MCR,而是另外单独拷贝,这样部署起来更方便灵活。

       编译完成之后或生成一个和项目同名的文件夹,其中最重要的文件就是distrib文件夹下的Castor.dll,该文件就是提供给其他.NET程序调用的类库。通过反编译程序可以查看它的成员方法,如下图:

简析MATLAB和.NET混合编程 - Castor - 趁年轻,多折腾~~
 4.3.2 .NET主程序编程

接下来的工作就是如何在外部程序中使用该程序集。还是以C#为例,创建一个Windows窗口程序。添加必须的控件,然后添加对MWArray.dllCastor.dll的引用以及加入需要的命名空间。

程序界面如下:

简析MATLAB和.NET混合编程 - Castor - 趁年轻,多折腾~~简析MATLAB和.NET混合编程 - Castor - 趁年轻,多折腾~~

核心代码如下:

private void button1_Click(object sender, EventArgs e)

{

    Functions f = new Functions();

    MWNumericArray na = null;

    MWArray[] arr1 = null;

    MWArray[] arr2 = null;

    int i = Convert.ToInt16(textBox2.Text);

    arr1 = f.XDMagic(1, i);

    try

    {

        arr2 = f.XDSVD(3, arr1[0]);//返回三个数组

        MessageBox.Show(arr2[0].ToString(), "矩阵U");

        MessageBox.Show(arr2[1].ToString(), "矩阵S");

        MessageBox.Show(arr2[2].ToString(), "矩阵V");

    }

    catch (Exception exc)

    {

        MessageBox.Show("出现异常,原因是:" + exc.Message, "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);

    }

}

private void button2_Click(object sender, EventArgs e)

{

    Functions f = new Functions();

    MWNumericArray na = null;

    MWArray[] ansArray = null;

    int i = Convert.ToInt16(textBox2.Text);

    ansArray=f.XDMagic(1,i);

    na = (MWNumericArray)ansArray[0];//只有一个数组返回

    MessageBox.Show(na.ToString());

}

4.3 调试运行

程序运行效果如下(假设输入的参数是5):

幻方:

简析MATLAB和.NET混合编程 - Castor - 趁年轻,多折腾~~

  矩阵USV分别如下:

简析MATLAB和.NET混合编程 - Castor - 趁年轻,多折腾~~
简析MATLAB和.NET混合编程 - Castor - 趁年轻,多折腾~~ 
简析MATLAB和.NET混合编程 - Castor - 趁年轻,多折腾~~
        这个结果和MATLAB下运行的效果是一样的。最后提一下一个小问题,就是程序在初始化自定义类Functions时会花费较多时间,大约持续2~3秒钟,程序如同假死一般,但第二次点击按钮反应却很快,可以推断程序集是动态加载的。

5.总结

       通过对MATLAB混合编程环境的论述和实例讲解,阐述了.NETMATLAB交互使用的方法,缩短了项目开发的周期,提高了算法的准确度,具有很重要的实践意义。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多