文章编号:1671-
637ò(2002)04-0040-05
Matlab 与C /C ++的接口及其在仿真中的应用
周正人, 张凤霞, 赵振宇
(中国航空工业洛阳电光设备研究所,河南洛阳 471009)
摘 要: 介绍了如何利用Matlab 与C /C ++的接口将现有的C 程序代码导入到Matlab 中
使用,以及将Matlab 的m 文件导出到VC 中,从而可以利用Matlab 和VC 的各自优势进行仿真软件的开发。这能够大大提高开发效率。
关 键 词: Matlab; 接口; m 文件; 仿真中图分类号: TP 31; TP 39 文献标识码: B
Matlab C /C ++interface and its
application in simulation
ZHOU Zheng-ren, ZHANG Feng-xia, ZHAO Zhen-yu
(Luoyang I nstitute of E lectro -optical Equipment , Luoyang 471009, China )
Abstract : This paper introduces how to import current C codes to Matlab and export Matlab m files to VC by the Matlab C/C++interface.In this way,simulation software can be developed with the integrated superiority of Matlab and VC ,and the developing efficiency can be increased .Key Wor ds : Matlab ; interface ; m file ; simulation
0 引言
Matlab 是个功能完善的自包容程序设计和数据处理集成环境,在科学运算、数据处理、系统分析、控制系统和科学绘图领域,使用Matlab 具有非常明显的优势。使用它提供的功能、内建函数以及工具箱,无需借助外界的任何帮助,就可高效完成任务。在这个环境中,只需寥寥数语就可以完成十分复杂的功能,在易学易用、编程效率、可读性、可移植性和可扩充性上,Matlab 更是远远胜于其它高级编程语言。
Matlab 的功能非常强大,但也不是完美无缺的。现有的很多大型程序是用C /C ++语言编写的,
不可能完全使用Matlab 语言改写。首要的问题是代
码重用问题;其次,Matlab 作为一种以解释方式执
行的高级计算机语言,其执行效率是较低的,而在火
控解算时需要高效率的执行代码,这样又碰到了执
行效率的问题;Matlab 中的变量不需要事先声明就
可以直接使用,其调试环境的调试功能也不够强大。不过,这些问题Matlab 都通过它的外部接口一一解决了。
在火控系统解算中,许多量都可以使用矢量来
表示,因此可以使用矢量方程法来进行航空火力控制问题的解算。利用矢量方程法解算火控问题,简明扼要,推导严密,适用于解算任意复杂的航空火力控
制问题。所以,可以利用Matlab 强大的矢量和矩阵
收稿日期:2002-01-23
作者简介:周正人(1976-),男,广西兴安人,学士,助理工程师,主要从事火控总体技术研究。
Vol.9 №.4Nov.2002 电光与控制ELECT RONICS OP TICS &CONT ROL
第9卷 第4期
2002年11月
运算功能,来完成火控解算中的矢量运算或者火控系统的仿真,并且可以用其C++数学库把Matlab 的非脚本m文件转化为C++源文件,然后将其嵌入VC工程中进行编译。这样可以利用两者长处进行互补,达到事半功倍的效果。
1 Matlab与C/C++的接口及应用
1.1 概述
Matlab为了解决上述问题,提供了外部接口,本文主要介绍它与C/C++的接口。为了实现代码重用,Matlab提供了一种Mex文件(在Windows操作系统中为Dll文件)技术,可以在不改变现有代码的情况下,使用尽量少的时间和精力把C代码导入到Matlab中,可以象使用Matlab的内部函数一样使用它,从而解决了如何把现有的C代码在Matlab 中加以利用的问题,即如何把C代码导入到Matlab 中,而且这种Mex文件的执行效率比Matlab中的m文件要高,其详细内容在1.2节中讨论。
作为解决问题的途径之一,利用Matlab提供的工具mcc或其提供的一个插件(Add-in)程序,可以把非脚本m文件翻译成C/C++文件,然后将其嵌入VC工程中编译生成二进制代码,从而大大提高运行速度,而且还可以在VC中进行调试。在1.3节中将详细叙述Matlab与C++的接口及其应用问题。当然,Matlab还提供了其它一些技术,如Mat文件、计算引擎等,这些本文不讨论。
1.2 C语言的Mex文件接口及应用
首先看一个最简单的例子:
#include“mex.h”/*必须包含的头文件*/
void Mul(double*x,double*y,double*z)
{
*z=(*x)*(*y);
}/*函数的功能是实现两个数的相乘*/
void mexFunction(int nlhs,mxArray*plhs[], int nrhs,const mxArray*prhs[])
{
double*x,*y,*z;
int row0,col0;
int row1,col1;
/*检查输入输出变量的个数*/
if(nrhs!=2)
(“.”);
else
if(nlhs>1)
mexErrMsgTxt(“too many output arguments.”);
/*输入的元素必须为两个非复数的double 类型数据*/
row0=mxGetM(prhs[0]);
col0=mxGetN(prhs[0]);
if(!mxIsDouble(prhs[0])??mxIsComplex (prhs[0])??
!(row0==1&&col0==1))
mexErrMsgTxt(“inputs must be nocomplex scalar double.”);
row1=mxGetM(prhs[1]);
col1=mxGetN(prhs[1]);
if(!mxIsDouble(prhs[1])??mxIsComplex (prhs[1])??
!(row1==1&&col1==1))
mexErrMsgTxt(“inputs must be nocomplex scalar double.”);
/*为返回参数创建矩阵*/
plhs[0]=mxCreateDoubleMatrix(row0, col0,mxREAL);
/*为输入输出参数赋值*/
x=mxGetPr(prhs[0]);
y=mxGetPr(prhs[1]);
z=mxGetPr(plhs[0]);
/*调用C函数Mul*/
Mul(x,y,z);
}
这个例子实现的是两个数的相乘,各个语句的含义请参见注释;以mx,mex开头的函数是Matlab 与C的接口函数,具体用法请参见Matlab的帮助。该例子的源程序主要由两个不同的部分组成:
1)计算子程序。它包含了所有实际完成计算功能的源代码,用来完成实际的计算工作;
2)入口子程序。它是计算子例行程序同Matlab 环境之间的接口,用来完成两者之间的通信任务。入口子例行程序的名称为mexFunction,拥有四个参数,分别为prhs、nrhs、plhs和nlhs,其中prhs为一个mxArray结构体类型的指针数组,该数组的数组元素按顺序指向所有的输入参数;nrhs为整数类型,它标明了输入参数的个数;plhs同样为一个结构体类型的指针数组,该数组的数组元
41
第4期 周正人等: M atlab与C/C++的接口及其在仿真中的应用
素按顺序指向所有的输出参数;nlhs 为整数类型,它标明了输出参数的个数。
以上两个步骤是典型的C 语言Mex 文件格式。其执行流程如图1所示。为了能够在Matlab 环境下运行这个程序,必须首先配置Mex 的编译环境,其配置工作可在Matlab 环境中运行mex-setup 命令
并按提示进行操作。配置之后,在Matlab 环境下运
行mex filename.c 编译C 文件,然后可在当前目录
下看到一个与C 文件同名的dll 文件,到此为止已
经大功告成。在Matlab 环境下键入filename (2,3)看看结果,
检验一下是否正确。
以上是个非常简单的例子。在C 语言编程中经常用到结构,下面是一个与数据结构有关的例子。
#include “mex.h ”
struct Point {
double x; double y ; double z;};
void Add(struct Point *p){
p->x ++; p->y ++; p ->z ++;}
void mexFunction (int nlhs ,mxArray *plhs [],int nrhs,const mxArray *prhs[])
{
const char *fnames[3]; int nfields ,n ,i ; mxArray *tmp; struct Point p1; double *x [3]; if(nrhs !=1)
(“
.”);
else if(nlhs >1)
mexErrMsgTxt (“too
many
output
argument.”);
else if(!mxIsStruct(prhs[0]))
mexErrMsgTxt (“input must be a structure.”);
/*求得输入结构体的域数和每个域的元素个数*/
nfields =mxGetNumberOfFields (prhs [0]); n=mxGetNumberOfElements(prhs[0]);
for(i=0;i fnames [i]=mxGetFieldNameByNumber (prhs [0],i ); for(i=0;i { tmp =mxGetField (prhs [0],0,fnames [i]); if (mxIsDouble (tmp )!=1) mexErrMsgTxt(“Element is not type of double.”); x [i ]=mxGetPr (tmp ); } 1.=*([0]); 42 电光与控制 第9卷 p1.y=*(x[1]); p1.z=*(x[2]); Add(&p1); /*对输出的结构体矩阵进行初始化并赋值*/ plhs[0]=mxCreateStructMatrix(1,1, nfields,fnames); tmp=mxCreateScalarDouble(p1.x); mxSetField(plhs[0],0,fnames[0],tmp); tmp=mxCreateScalarDouble(p1.y); mxSetField(plhs[0],0,fnames[1],tmp); tmp=mxCreateScalarDouble(p1.z); mxSetField(plhs[0],0,fnames[2],tmp); } 这个例子同第一个的格式是一样的,区别在于一些mx函数的使用上。对于Matlab中的结构类型,其实质还是数组。因此,不一定非要使用上面的实现方式,上面的实现方式是考虑到Matlab的结构类型和C语言中的结构形式相对应。 上面举的两个例子都是单个文件的,如果C函数用到多个文件中的函数,编译时的格式如下:mex file1.c file2.c…,编译后将产生file1.dll的动态链接库文件,可在Matlab工作环境中直接执行。注意: mex命令可以操作多种文件格式,包括.c、.obj和. lib;在链接多个文件时,生成的Mex文件的名字为文件列表中的第一个文件的名字;在将文件列表时,必须写出文件扩展名,并且用空格分开。 1.3 Matlab与C/C++的接口及应用 也许Math Works公司的意思是利用mcc命令将m文件编译生成stand-alone程序。因而没有过多考虑如何将mcc生成的C/C++文件嵌入到VC 工程中,但其新版提供了一个与VC集成得比较好的插件(Add-in)程序可以将m文件翻译成C/C+ +文件,并且可以把VC工程选项自动配置好。下面将详细介绍使用mcc和插件(Add-in)程序将m文件翻译成C/C++文件嵌入到VC工程中的方法。 1.3.1 使用mcc 把mcc产生的C++文件嵌入到VC工程中时,VC工程的配置如下: 新建一个项目或者打开一个已有项目,然后选择菜单: Project->Settings : C/C++选项页: Category:General Preprocessor definitions:增加MSVC,IBMPC, MSWIND Category:Code Generation U se run-time library:Multithreaded DLL Link选项页: Category:Input Object/Library modules:增加libmatlb.lib libmx.lib libmat.lib d:\Matlab6p1\extern\lib\win32\libmatpm. lib Additional Library path:d:\Matlab6p1\extern\ lib\win32\microsoft\msvc60 T ools->Options->Directories Platform:Win32 Show directories for:Include files Directories:增加d:\Matlab6p1\extern\include, d:\Matlab6p1\extern\include\cpp 以上需要增加的库函数不需要用其它工具生成,Math Works公司已经做好,随Matlab一起安装在目录d:\Matlab6p1\extern\lib\win32及子目录下。完成以上的配置工作后,就可以利用mcc命令把m文件翻译成C++文件嵌入到VC工程中去, mcc的命令格式为: mcc-t-L Cpp filename.m 请注意大小写。 这时不仅可以把mcc命令生成的C++文件嵌入到VC工程中进行编译,还可以直接在VC中包含一些必要的头文件(位于d:\Matlab6p1\extern\ include\cpp)后使用matlab的矩阵函数。 下面举一个简单的例子。test.m实现的是两个矩阵的加和减: function[a,b]=test(x,y) a=x+y; b=x-y; 利用mcc-t-L Cpp test.m命令生成test.hpp和test.cpp文件。头文件test.hpp的内容如下: // //MATLAB Compiler: 2.2 //Date:Tue Jan1508:17:192002 //Arguments:“-B”“macro default”“-O”“all”“-O”“fold scalar mxarrays:on” //“-O”“fold non scalar mxarrays:on”“-O”“optimize integer for loops:on”“-O” 43 第4期 周正人等: M atlab与C/C++的接口及其在仿真中的应用 //“array indexing:on”“-O”“optimize conditionals:on”“-t”“-L”“Cpp”“test.m” // #ifndef test hpp #define test hpp1 #include“libmatlb.hpp” extern void InitializeModule test(); extern void TerminateModule test(); extern mexLocalFunctionTable local function table test; extern mwArray test(mwArray*b, mwArray x=mwArray::DIN, mwArray y=mwArray::DIN); #ifdef cplusplus extern“C” #endif void mlxTest(int nlhs,mxArray*plhs[],int nrhs,mxArray*prhs[]); #endif 在VC中调用test函数的主程序文件如下: #include #include“test.hpp” void main() { double data[]={1,3,2,4}; mwArray a(2,2,data),b(2,2,data),c,d; c=test(&d,a,b);