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