手把手教你C#与MATLAB混合编程
来源: | 作者:JYTEK | 发布时间: 2023-12-15 | 1918 次浏览 | 分享到:

关键词:MATLAB、C#、混合编程


1.问题描述

本例中,将MATLAB中的积分算法cumtrapz封装生成dll,用C#调用MATLAB的积分算法,实现MATLAB和.NET的混合编程,通过使用此方法将MATLAB函数封装成.NET中类的方法,这些类就可以像其他托管代码一样被.NET环境下的所有语言调用。

总体来讲,C#和MATLAB混合编程有以下优点:

1. MATLAB拥有大量的科学计算函数库,可以提供给C#直接使用,省去了开发这个过程。

2. MATLAB拥有自己的编译器和开发平台,而且语法简单,更容易使普通科研人员掌握。编写的m函数可以直接给C#使用,这就避免了重复开发。

3. MATLAB拥有大量的行业工具箱,如控制、图像处理,数学计算,可以很方便地开发各类专业程序。


2.解决方法

 要实现C#调用MATLAB可以分为三步:

第一步:编写M函数,并在MATLAB中测试可以使用

第二步:在MATLAB中使用deploytool建立混编项目

第三步:C#中添加MATLAB的dll引用

 

第一步:编写M函数,并测试可以使

做一个简单的MATLAB算法的封装,只先将MATLAB的cumtrapz进行封装。首先在MATLAB中创建一个.m的文件,cumtrapz()函数输入time序列,在此次对比中,time为总时长为1秒钟,间隔为10us的timing。输入data序列,在此次对比中,data为被积分函数,即正弦函数。y为积分后的值,对值进行处理,赋值给Y。在调用时,只需使用integration(f,x,A),f为信号频率,x为采样率,A为幅值。源码如下,如图1所示:

function Y = integration(f,x,A)

value = linspace(0,1,x);

time = round(value,5);

data = zeros(1,x);

for i=1:1:x

    data(i)=A*sin(2*pi*f*time(i));

end

y = cumtrapz(time,data);

value=mean(y);

Y = y-value;

end

 

图 1  Matlab中.m文件

注意,混编必须是m函数function的形式才能被调用。上述函数简单测试一下,没有问题(复杂的函数一定要多测试,否则后续调试非常困难)。继续下一步。

 

第二步:在MATLAB中使用deploytool建立混编项目

在MATLAB工作区输入命令:deploytool,然后在Compiler弹窗中选择Library Compiler,如下图2所示: 



 

MATLAB Compiler弹窗

在对打包项目进行编辑的界面中,首先选择目标类型为“.NET Assembly”,然后添加刚才编写好的integration.m文件,在界面下方将默认的类名Class1修改为integrationTask,点击“保存”按钮,弹出保存工程,如图3所示,最后点击右上角的“Package”按钮执行打包过程。具体如下图4所示:

 

保存项目

 

4 打包具体步骤

到此为止,打包完成,如图5所示,一个常规简单的Matlab.NET混编已经完成了60%了。打包完成后自动弹出文件夹,如下图6所示:

 

5   打包成功

 

6   生成的文件夹(包含dll文件)

 

第三步:C#中添加MATLAB的dll引用

打开VS2015创建一个窗体的应用程序,主要需要完成的是DLL的引用添加,将打包弹出文件夹中添加for_redistribution_files_only文件夹中的integration.dll

和D:SoftwareMatlab 2017a_Hezibuluo.comtoolboxdotnetbuilderbinwin64v4.0 (前边为MATLAB的安装路径)文件夹下的MWArray.dll添加到项目引用中去,如图7所示。其中MWArray主要的作用是做将MATLAB与C#中的数据进行转换交接。主要的原因是,MATLAB本身来说是一种比较松散的语言,在整个算法编程过程中并没有定义出来类似于C#中的多种数据类型,如double,float或者int等数据类型,所以在混个编程数据交接过程中需要有一个dll进行数据类型的转换的。

 



图 7  在VS中添加引用

同时需要添加以下的命名空间在系统中:

//用户自行添加的命名空间

using integration; //这是我们自己定义的

using standardValue; //这是我们自己定义的

using MathWorks.MATLAB.NET.Arrays; //在MWArray.dll中,最常用的

using MathWorks.MATLAB.NET.Utility; //在MWArray.dll中,最常用的

 

在使用过程中,我们可以这样理解,我们之前编译好的dll就是一个类,我们首先需要将这个类进行实例化,然后每一个我们编写好的.m文件都是一个方法。所以首先要做的就是将类进行实例化,整体的代码如下所示,利用MATLAB中的dll算法继续积分分析同时对积分后的数值解进行分析,其中单击buttonStart时的部分就是混合编程调用积分函数的部分:

namespace test

{

    public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

     private void buttonStart_Click(object sender, EventArgs e)

        {

           

                #region Matlab

 

                //对类进行实例化

                IntergrationTask trapz = new IntergrationTask();

                standardValueTask standardValue = new standardValueTask();

 

                //调用integration方法(频率,采样率,幅值),返回结果

                var result = trapz.integration(f, Fs, A);

                var standardresult = standardValue.standardValue(f, Fs, A);

 

                //将MATLAB的数据转化为中间过渡格式

                MWNumericArray results = (MWNumericArray)result;

                MWNumericArray standardresults = (MWNumericArray)standardresult;

 

                //将中间过渡格式转化为C#的数据格式

                double[,] value = (double[,])results.ToArray(MWArrayComponent.Real);

                //积分标准值

                double [,] sinestandardValue= (double[,])standardresults.ToArray(MWArrayComponent.Real);

 

                double[] m_i = new double[(int)Fs];

                

                double matlaberror =0;


                for (int i = 0; i < m_i.Length; i++)

                {

                    m_i[i] = value[0, i];

                    matlab_i[0, i] = sinestandardValue[0, i];//matlab_i第一列为积分解析解

                    matlab_i[1, i] = m_i[i];//matlab_i第二列为Matlab积分数值解

 

                    //differentValueAll[1,i]  = m_i[i]-matlab_i[0, i] (数值解-解析解)

                    differentValueAll[1, i]= m_i[i] - matlab_i[0, i];

 

                    sum_m += (Math.Pow(differentValueAll[1, i], 2));

                    sum_standard_m += (Math.Pow(sinestandardValue[0, i], 2));

                }

                //积分误差为

                matlaberror= Math.Sqrt(sum_m / sum_standard_m);

 

                fre_error[1, frecount] = matlaberror;

                textBoxMATLABError_i.Text = matlaberror.ToString();

                #endregion

 

                easyChartX_Mat_I.Plot(matlab_i, 0, dt);//将将二维积分数组画出 Matlab积分解析解与数值解

                easyChartX_differentValue.Plot(differentValueAll, 0, dt);//画出积分误差值

 

                f += frequencyGap;

            }

            easyChartXFrequency_Error.Plot(fre_error, 1000, frequencyGap);//Matlab积分误差值


        }

测试结果如图8图9,混合编程的结果与MATLAB中的测试结果一定是一致的。

 

图 8  MATLAB中积分后的函数值

 

图 9  在VS中调用后生成的函数值

 

写在后面的话:

1. 混合编程虽然可以脱离MATLAB环境,但是必须安装MATLAB运行时—MCR,并且开发版本和运行版本的MCR要对应,否则会出错误,我们将在程序中进行说明。其中MCR安装是不需要版权的。

2.本来说做混合编程并不是一个比较复杂的事情,唯一的难点其实是在C#与MATLAB中数据转化的内容,其实这一部分在MATLAB自带的帮助文档是有写的。所以我们只需按照帮助文档的提示去操作就可以了。

3.混合编程过程中,有很多的问题都可以通过通用的搜索引擎中搜索答案,同时如果用MATLAB所生成的3D图形可以在C#中调用并且显示。

4.在相关链接中有一套非常好的C#与MATLAB混编的教学视频,非常推荐。

5.本此使用到了简仪的滤波器dll,所以要求.NET版本必须在4.6.2以上。

6.由于MATLAB是区分x64和x86的,因此在不同版本的MATLAB编译之后对应的C#管理器平台配置也需要选择对应的配置,如该实例是在x64平台下执行的。

5. 相关链接

http://www.cnblogs.com/eniac12/p/4390845.html

http://blog.csdn.net/qq_22033759/article/details/48122383

https://yq.aliyun.com/articles/26005

混合编程视频:

http://www.cnblogs.com/asxinyu/p/4288540.html#_label1

http://www.cnblogs.com/asxinyu/p/Bolg_Category_For_Matlab.html