Matlab2012a与VS2010(C++)混合编程

Matlab2012a与VS2010(C++)混合编程
Matlab2012a与VS2010(C++)混合编程

Matlab2012a与VS2010(C++)混合编程

经历了各种报错和崩溃,用了近1个月的时间终于把C++的程序调通了。在编程过程中,我在网上找了各种Matlab和C++混编的资料,感觉混编的资料太少,故将自己编程的过程和心得分享给大家,希望能帮到和我一样挣扎在混编领域中的同学。

环境:windows8.1,Matlab2012a,VS2010

需要编的C++程序要实现与Matlab一样的功能,从键盘输入数据,获得计算结果和图像。如下图:

大概的过程:Matlab的m文件→dll→C++调用dll和Matlab中的engine(与图像有关,后面会详细说明)→输出计算结果和图像

1.Matlab编译器设置(电脑安装有VS2010)

(1)mex命令设置

(a) 运行 Matlab ,在 Matlab 的命令窗口 (Command Window) 键入“ mex -setup ”命令后,按回车键,安装 Matlab 编译器;

(b) 命令窗口出现如下提示:

Please choose your compiler for building external interface (MEX) files:

Would you like mex to locate installed compilers [y]/n?

此时键入“y” ,按回车;

(c) 命令窗口出现如下提示:

Please choose your compiler for building external interface (MEX) files:

Would you like mex to locate installed compilers [y]/n? y

Select a compiler:

[1]Microsoft Visual Studio 2010 in G:\ Visual Studio 2010

[0] None

此时键入” 1” ,按回车;选择 Microsoft Visual Studio 2010 的编译器

(d) 命令窗口出现如下提示:

Please verify your choices:

Compiler: Microsoft Visual Studio 2010

Location: G:\ Visual Studio 2010

Are these correct?([y]/n):

此时键入”y” ,按回车;确认选择 Microsoft Visual Studio 2010 的编译器

(2) mbuild 命令设置

(a) 运行 Matlab ,在 Matlab 的命令窗口 (Command Window) 键入“ mbuild -setup ”

命令后,按回车键,安装 Matlab 编译器;

(b) 命令窗口出现如下提示:

Please choose your compiler for building standalone MATLAB applications:

Would you like mbuild to locate installed compilers [y]/n?

此时键入”y” ,按回车;

(c) 命令窗口出现如下提示:

[1] Microsoft Visual Studio 2010 in G:\ Visual Studio 2010

[0] None

此时键入“1” ,按回车;选择 Microsoft Visual Studio 2010 的编译器

(d) 命令窗口出现如下提示:

Please verify your choices:

Compiler: Microsoft Visual Studio 2010

Location: G:\ Visual Studio 2010

Are these correct?([y]/n):

此时键入”y” ,按回车,确认选择 Microsoft Visual Studio 2010 的编译器,编译器设置完成。

2.将Matlab 函数转成DLL 函数

(tips:能封装成dll文件的m文件其内容必须是自定义函数形式)

函数文件RE_1.m ,内容如下:

function [f0,f1,f2]=RE_1(S0,S1,S2)

x = 0:0.01:2*pi;

r =cos(3*x)/5 - (3*cos(6*x))/5 + (7*cos(20*x))/10 + sin(2*x)/10 + (3*sin(13*x))/10 + 10;

r_max = max(r);

r_min = min(r);

r1=r_max;

r2=r_min;

f0=r1-r2;

N=128;

p1=19;

p2=64;

c0=1;

c1=-sin(2*pi*p2/N)/sin(2*pi*(p2-p1)/N);

c2=sin(2*pi*p1/N)/sin(2*pi*(p2-p1)/N);

Sn=c0*S0+c1*S1+c2*S2;

c=[1,c1,c2];

m=[0,p1,p2];

D=zeros(N);

for i=1:N

for j=1:3

if i+m(j)<=N

D(i,i+m(j))=c(j);

else

D(i,mod(i+m(j),N))=c(j);

end

end

end

D;

z=pinv(D);

r=z*Sn;

r_max=max(r);

r_min=min(r);

f1=r_max-r_min;

g1=S0-r;

r1=[r(p1+1:end);r(1:p1)];

g2=((S1-r1)-(S0-r)*cos(2*pi*p1/N))/sin(2*pi*p1/N); a_sum=0;b_sum=0;

for i=1:N

a(i)=(g1(i)*sin(2*pi*(i-1)/N)-g2(i)*cos(2*pi*(i-1)/N))*sin(4*pi*(i-1)/N);

b(i)=(g1(i)*sin(2*pi*(i-1)/N)-g2(i)*cos(2*pi*(i-1)/N))*cos(4*pi*(i-1)/N);

a_sum=a_sum+a(i);

b_sum=b_sum+b(i);

end

A1=2*a_sum/N;

B1=-2*b_sum/N;

s0_re=A1*cos(2*pi*0/N)+B1*sin(2*pi*0/N)+r(1);

for i=1:N-1

s(i)=A1*cos(2*pi*i/N)+B1*sin(2*pi*i/N)+r(i+1);

h_re(i)=s(i);

end

l=[s0_re;h_re'];

r_re=double(l);

r_re_max=max(r_re);

r_re_min=min(r_re);

f2=r_re_max-r_re_min;

end

函数文件RE_2.m ,内容如下:

function [R,R_re]=RE_2(S0,S1,S2)

N=128;

p1=19;

p2=64;

c0=1;

c1=-sin(2*pi*p2/N)/sin(2*pi*(p2-p1)/N);

c2=sin(2*pi*p1/N)/sin(2*pi*(p2-p1)/N);

Sn=c0*S0+c1*S1+c2*S2;

c=[1,c1,c2];

m=[0,p1,p2];

D=zeros(N);

for i=1:N

for j=1:3

if i+m(j)<=N

D(i,i+m(j))=c(j);

else

D(i,mod(i+m(j),N))=c(j);

end

end

end

D;

z=pinv(D);

r=z*Sn;

g1=S0-r;

r1=[r(p1+1:end);r(1:p1)];

g2=((S1-r1)-(S0-r)*cos(2*pi*p1/N))/sin(2*pi*p1/N);

a_sum=0;b_sum=0;

for i=1:N

a(i)=(g1(i)*sin(2*pi*(i-1)/N)-g2(i)*cos(2*pi*(i-1)/N))*sin(4*pi*(i-1) /N);

b(i)=(g1(i)*sin(2*pi*(i-1)/N)-g2(i)*cos(2*pi*(i-1)/N))*cos(4*pi*(i-1) /N);

a_sum=a_sum+a(i);

b_sum=b_sum+b(i);

end

A1=2*a_sum/N;

B1=-2*b_sum/N;

s0_re=A1*cos(2*pi*0/N)+B1*sin(2*pi*0/N)+r(1);

for i=1:N-1

s(i)=A1*cos(2*pi*i/N)+B1*sin(2*pi*i/N)+r(i+1);

h_re(i)=s(i);

end

l=[s0_re;h_re'];

r_re=double(l);

i=[0:2*pi/127:2*pi];

I=0:pi/256:2*pi;

R=spline(i,r',I);

R_re=spline(i,r_re',I);

end

这2个matlab程序很像,只是输出值有所不同。我将RE_1.m封装成接口为mwArray的dll文件;将RE_2.m封装成接口为mxArray的dll文件。具体操作如下:

在 Matlab的 Command Window 下输入命令 :

命令 1 : mcc -W cpplib:RE_2-T link:lib RE_2.m

命令 2 : mcc -W lib:RE_2-T link:lib RE_2.m

(命令 1 生成的 DLL 函数接口的数据类型是 mwArray ,命令 2 生成的 DLL 函数接口的数据类型是 mxArray 。)

生成动态链接库DLL,编译完成后,Matlab会在当前文件夹生成一些文件:

其中RE_2.dll,RE_2.h和RE_2.lib 是所需要的

3.VS2010编译环境设置和工程创建

(1).环境变量及VS2010编译环境设置

(以下地址是我的电脑中文件夹的地址)

①环境变量:

我的电脑→属性→高级系统设置→高级→环境变量→系统变量→Path→编辑添加:(以下是我的电脑中文件夹的地址)

G:\Matlab2012a\bin\win64

G:\Matlab2012a\runtime\win64

G:\Visual Studio 2010\VC\bin

(地址之间用;隔开,且;是英文下输入的)

②VS2010编译环境

项目→属性

1)配置管理器→活动解决方案平台→新建→X64

2)VC++目录

包含目录添加:G:\Matlab2012a\extern\include

库目录添加;G:\Matlab2012a\extern\lib\win64\microsoft

③链接器→输入→附加依赖项

mclmcrrt.lib

RE_1.lib

RE_2.lib

libeng.lib

libmx.lib

libmat.lib

(每一项之间用回车隔开)

P.S:mclmcrrt.lib,RE_1.lib,RE_2.lib是与调用matlab生成的dll有关的;

libeng.lib,libmx.lib,libmat.lib是调用matlab的engine,生成函数图像有关的。

(2)控制台工程程序建立

①在VS2010新建一个名为“RE_test”控制台项目,在应用程序页面选择向导中按如下图

设置:

②把之前matlab生成的RE_1.dll,RE_1.H,RE_1.lib,RE_2.dll,RE_2.h,RE_2.lib这些文件复制到控

制台项目文件夹下

③在解决方案资源管理器“源文件”右键→添加→新建项→C++文件,命名为Test.cpp

4.VS2010(C++)程序

程序内容如下:

#include

#include

#include"RE_1.h"

#include"RE_2.h"

#include

#include

#include"engine.h"

usingnamespace std;

int main()

{

if(!RE_1Initialize()) //初始化动态库RE_1

{

cout<<"initilize failed"<

return -1;

}

//定义输入值S0,S1,S2和输出值f0,f1,f2

mwArray S0(128,1,mxDOUBLE_CLASS,mxCOMPLEX); mwArray S1(128,1,mxDOUBLE_CLASS,mxCOMPLEX); mwArray S2(128,1,mxDOUBLE_CLASS,mxCOMPLEX);

mwArray f0(1,1,mxDOUBLE_CLASS);

mwArray f1(1,1,mxDOUBLE_CLASS);

mwArray f2(1,1,mxDOUBLE_CLASS);

//从屏幕上获取数据,形成数组A,B,C

int g;

double A[128],B[128],C[128];

printf("请输入0号传感器数据:\n");

for(g=0;g<128;g++)

scanf("%lf",&A[g]);

printf("请输入1号传感器数据:\n");

for(g=0;g<128;g++)

scanf("%lf",&B[g]);

printf("请输入2号传感器数据:\n");

for(g=0;g<128;g++)

scanf("%lf",&C[g]);

//将数组A,B,C的值分别赋给S0,S1,S2

S0.SetData(A,128);

S1.SetData(B,128);

S2.SetData(C,128);

RE_1(3,f0,f1,f2,S0,S1,S2);//调用函数进行运算

//获取,显示输出值

double *a=newdouble;

f0.GetData(a,1);

cout<<"设定圆的圆度误差f0="<<*a<

double *b=newdouble;

f1.GetData(b,1);

cout<<"分离圆的圆度误差f1="<<*b<

double *c=newdouble;

f2.GetData(c,1);

cout<<"重构圆的圆度误差f2="<<*c<

getchar();

//关闭动态库RE_1

delete a;delete b; delete c;

RE_1Terminate();

///////////////////////////////////////////////

if(!RE_2Initialize()) //初始化动态库RE_2

{

cout<<"initilize failed"<

return -1;

}

//定义输入值SS0,SS1,SS2和输出值R,R_re

mxArray *SS0,*SS1,*SS2;

mxArray *R=NULL,*R_re=NULL;

//设定SS0,SS1,SS2的内存空间

SS0=mxCreateDoubleMatrix(128,1,mxCOMPLEX);

SS1=mxCreateDoubleMatrix(128,1,mxCOMPLEX);

SS2=mxCreateDoubleMatrix(128,1,mxCOMPLEX);

//将数组A,B,C的值分别赋给SS0,SS1,SS2

memcpy(mxGetPr(SS0),A,128*sizeof(double));

memcpy(mxGetPr(SS1),B,128*sizeof(double));

memcpy(mxGetPr(SS2),C,128*sizeof(double));

mlfRE_2(2,&R,&R_re,SS0,SS1,SS2);//调用函数进行运算

RE_2Terminate();//关闭动态库RE_2

//////////////////////////////////////////////////

Engine *ep;

if (!(ep = engOpen("\0"))) //启动matlab的引擎(engine)

{

fprintf(stderr, "\nCan't start MATLAB engine\n");

return EXIT_FAILURE;

}

//作设定圆的图像

engEvalString(ep,"x=0:0.01:2*pi;");

engEvalString(ep,

"v=10+1.2*cos(x)-0.8*sin(x)+0.1*sin(2*x)+0.2*cos(3*x)-0.6*cos(6*x)+0.3*sin(13*x)+0.7*co s(20*x);");

engEvalString(ep, "polar(x,v);");

engEvalString(ep, "hold on;");

//作分离圆的图像

engPutVariable(ep, "R", R);

engEvalString(ep,"I=0:pi/256:2*pi;;");

engEvalString(ep, "polar(I,R,'r');");

//作重构圆的图像

engPutVariable(ep, "R_re", R_re);

engEvalString(ep,"I=0:pi/256:2*pi;;");

engEvalString(ep, "polar(I,R_re,'g');");

return 0;

}

本程序共分3个部分,分别调用RE_1,RE_2和engine。运行结果:

Matlab Engine是指一组Matlab提供的接口函数,支持C语言, Matlab Engine 采用C/S(客户机/服务器)模式,Matlab作为后台服务器,而C程序作为前台客户机,通过Windows的动态控件与服务器通信,向Matlab Engine传递命令和数据信息,从Matlab Engine接受数据信息。用户可以在前台应用程序中调用这些接口函数,实现对Matlab Engine的控制。采用这种方法几乎能利用Matlab全部功能,但是需要在机器上安装Matlab软件,而且执行效率低,因此在实际应

用中不采用这种方法,在软件开发中也不可行,我认为适合个人使用或做演示用。

(调用engine时,红色引号中的语句完全是matlab的格式)

最后说明:本文唯一目的是分享我matlab和vs2010混编的成果和心得。此文也参考了许多前辈和大神的文章,如有雷同,纯属巧合。真心希望

这篇文章能对正在混编的同学有所帮助。

2016.5.3

相关主题
相关文档
最新文档