|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
" ?3 S1 g$ S6 l/ t8 c7 a
通过把耗时长的函数用c语言实现,并编译成mex函数可以加快执行速度。
# B. t- [6 |1 ^# Y& f
; V. b0 N5 @2 _Matlab本身是不带c语言的编译器的,所以要求你的机器上已经安装有VC,BC或Watcom C中的一种。
' j) o a" z2 ^( t% l; |5 U5 q5 O- p
如果你在安装Matlab时已经设置过编译器,那么现在你应该就可以使用mex命令来编译c语言的程序了。
4 D0 ]1 N1 T- d9 y
9 u6 T5 Z9 D, {7 S# Y9 I如果当时没有选,就在Matlab里键入mex -setup,下面只要根据提示一步步设置就可以了。 |1 f5 V+ x4 V, Q, s ~
' ~# f: w5 |6 X
8 T/ m1 V" _3 }) a为了测试你的路径设置正确与否,把下面的程序存为hello.c。8 D4 G0 ]$ |4 h' Y4 H! T$ K) q9 ^7 j: B
( v/ M" E# H, {1 K- /*hello.c*/
- #include "mex.h"
- void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
- { mexPrintf("hello,world!/n");
- }1 y' k- Z# H3 E" U# g
% @7 N8 s* ^+ i# p2 T2 ^# N
3 u) [$ }% Q( v2 i( g; m9 h" D 假设你把hello.c放在了C:/TEST/下,在Matlab里用CD C:/TEST/ 将当前目录改为C:/ TEST/(注意,仅将C:/TEST/加入搜索路径是没有用的)。现在敲:
) Y; O* P- d4 W& V' m+ Jmex hello.c 6 ~" A4 U( L( P$ H+ X0 P
如果一切顺利,编译应该在出现编译器提示信息后正常退出。如果你已将C:/TEST/加入了搜索路径,现在键入hello,程序会在屏幕上打出一行:! |+ P* a: C3 d& ]
hello,world! , A/ y" L' h! u, c' ~- S3 ~
9 S, h' Q1 t* u整个程序由一个接口子过程 mexFunction构成。/ `+ ^/ w; n. b
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) 0 x p/ d2 R t' ?
前面提到过,Matlab的mex函数有一定的接口规范,就是指这0 ~% r. [" ?* B# h
nlhs:输出参数数目 0 b! o Z; x" h3 t
plhs:指向输出参数的指针
! Q7 \* I! Y, l7 `5 x8 \8 `1 Lnrhs:输入参数数目 " H, f% {% J' }1 _, V
例如,使用
! X4 h4 ^" V, h6 T# C: r[a,b]=test(c,d,e)
, D% x/ w! Q3 Z3 H; r调用mex函数test时,传给test的这四个参数分别是: q( p4 R' v0 \ L
2,plhs,3,prhs' \/ L% F& t3 L5 j
其中:
6 |- w' U! G c& k+ C; x: zprhs[0]=c ; J1 c/ _! z( ^0 f2 X+ z4 Q/ h, F/ @# X
prhs[1]=d
# J# o* Y1 N" t3 kprhs[2]=e
$ K9 a+ R" e: N. `- O% Q7 B2 u0 P: {当函数返回时,将会把你放在plhs[0],plhs[1]里的地址赋给a和b,达到返回数据的目的。
2 g5 `1 D7 [! l细心的你也许已经注意到,prhs和plhs都是指向类型mxArray类型数据的指针。 这个类型是在mex.h中定义的,事实上,在Matlab里大多数数据都是以这种类型存在。当然还有其他的数据类型,可以参考Apiguide.pdf里的介绍。 ( T u4 N% D0 Z& @1 K: t
8 Y4 O# c& Y) h$ r% Q. ]
- //hello.c 2.0
- #include "mex.h"
- void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
- {
- int i;
- i=mxGetScalar(prhs[0]);
- if(i==1)
- mexPrintf("hello,world!/n");
- else
- mexPrintf("大家好!/n");
- }5 m: l0 Q$ W( Y
& }; y& w* d1 h9 Z5 |( ^! [- ?
$ d* z+ i' Q1 t) |; |
将这个程序编译通过后,执行hello(1),屏幕上会打出: hello,world! 7 I6 d) v! O) ` m/ N/ k9 v
而hello(0)将会得到: 大家好!
: \, z. F) l! I, Z
0 x) v4 F5 {3 k9 z1 r9 i4 m" y6 u用到了一个函数:mxGetScalar,调用方式如下: 3 l( Z: x" b: V/ D$ y
i=mxGetScalar(prhs[0]);
5 p2 t% f# U, X4 C b& K"Scalar"就是标量的意思。在Matlab里数据都是以数组的形式存在的,mxGetScalar的作用就是把通过prhs[0]传递进来的mxArray类型的指针指向的数据(标量)赋给C程序里的变量。这个变量本来应该是double类型的,通过强制类型转换赋给了整形变量i。
G# G& i+ G) S$ |7 z: o* T6 A0 _# F8 g. O( i p, O$ P
- //hello.c 2.1
- #include "mex.h"
- void mexFunction(int nlhs, mxArray *plhs[],
- int nrhs, const mxArray *prhs[])
- {
- int *i;
- i=mxGetPr(prhs[0]);
- if(i[0]==1)
- mexPrintf("hello,world!/n");
- else
- mexPrintf("大家好!/n");
- }5 g$ E; l/ v% J5 }% L
- K0 [& Q" R( Z) s) N/ q
% E- n3 X2 v) o. H# ~这样,就通过mxGetPr函数从指向mxArray类型数据的prhs[0]获得了指向double类型的指针。/ N5 b% b& R5 ]& K8 Y
但是,还有个问题,如果输入的不是单个的数据,而是向量或矩阵,那该怎么处理呢 ?通过mxGetPr只能得到指向这个矩阵的指针,如果我们不知道这个矩阵的确切大小,就 & c* u) `% J4 c/ C
没法对它进行计算。
, w( g' f' y. H0 E1 i' U为了解决这个问题,Matlab提供了两个函数mxGetM和mxGetN来获得传进来参数的行数 和列数。下面例程的功能很简单,就是获得输入的矩阵,把它在屏幕上显示出来:
# [. l! U0 L7 O+ @3 t8 T: A/ ]
; O% _, q. i k; P) ]- //show.c 1.0
- #include "mex.h"
- #include "mex.h"
- void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
- {
- double *data;
- int M,N;
- int i,j;
- data=mxGetPr(prhs[0]); //获得指向矩阵的指针
- M=mxGetM(prhs[0]); //获得矩阵的行数
- N=mxGetN(prhs[0]); //获得矩阵的列数
- for(i=0;i<M;i++)
- { for(j=0;j<N;j++)
- mexPrintf("%4.3f ",data[j*M+i]);
- mexPrintf("/n");
- }
- }2 D& R1 x3 o2 D i7 l+ b) t
7 e2 E( j- }& ]/ B- N$ g
3 X& l% t3 W$ |+ w ]: ^
编译完成后,用下面的命令测试一下:
1 f/ _/ w# |* @! G5 f a=1:10;
8 h& z& S. ^2 u9 _: g- X b=[a;a+1]; " \+ j' v+ n- ~; s1 H/ }6 u
show(a)
% y! Y/ ]. L% X9 Z* I. Y show(b) ' H1 S v7 W: f8 D: g$ S. X/ @4 @. n
, q4 I8 @' F% D9 {' z+ U# m需要注意的是,在Matlab里,矩阵第一行是从1开始的,而在C语言中,第一行的序数为零,Matlab里的矩阵元素b(i,j)在传递到C中的一维数组大data后对应于data[j*M+i] 。
9 g( A3 h3 ~$ S( m4 L输入数据是在函数调用之前已经在Matlab里申请了内存的,由于mex函数与Matlab共用同一个地址空间,因而在prhs[]里传递指针就可以达到参数传递的目的。但是,输出参数却需要在mex函数内申请到内存空间,才能将指针放在plhs[]中传递出去。由于返回指针类型必须是mxArray,所以Matlab专门提供了一个函数:mxCreateDoubleMatrix来实现内存的申请,函数原型如下: D7 U+ i% c8 g- k6 a! B: X
mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag)
" G# ~9 p: [% L) u& c: } m:待申请矩阵的行数 ' D& M2 I& h5 i! A" J
n:待申请矩阵的列数 6 p F: g4 S$ W) G
为矩阵申请内存后,得到的是mxArray类型的指针,就可以放在plhs[]里传递回去了。但是对这个新矩阵的处理,却要在函数内完成,这时就需要用到前面介绍的mxGetPr。使用 mxGetPr获得指向这个矩阵中数据区的指针(double类型)后,就可以对这个矩阵进行各种操作和运算了。下面的程序是在上面的show.c的基础上稍作改变得到的,功能是将输 9 u9 S; ^3 {9 d1 a0 h$ |* H) R
# W- H: B8 f( W- { W
! {7 G9 b3 |# F& M4 F9 _6 g- //reverse.c 1.0
- #include "mex.h"
- void mexFunction(int nlhs, mxArray *plhs[],
- int nrhs, const mxArray *prhs[])
- {
- double *inData;
- double *outData;
- int M,N;
- int i,j;
- inData=mxGetPr(prhs[0]);
- M=mxGetM(prhs[0]);
- N=mxGetN(prhs[0]);
- plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL);
- outData=mxGetPr(plhs[0]);
- for(i=0;i<M;i++)
- for(j=0;j<N;j++)
- outData[j*M+i]=inData[(N-1-j)*M+i];
- }
* u5 f5 u: V; F8 B2 `" A& ^ + X- }! n, S5 w5 U
" ]; S% X5 J- u; U8 |' Y当然,Matlab里使用到的并不是只有double类型这一种矩阵,还有字符串类型、稀疏矩阵、结构类型矩阵等等,并提供了相应的处理函数。本文用到编制mex程序中最经常遇到的一些函数,其余的详细情况清参考Apiref.pdf。 ( A- M. O1 V4 u- W( Q1 I
通过前面两部分的介绍,大家对参数的输入和输出方法应该有了基本的了解。具备了这些知识,就能够满足一般的编程需要了。但这些程序还有些小的缺陷,以前面介绍的re由于前面的例程中没有对输入、输出参数的数目及类型进行检查,导致程序的容错性很差,以下程序则容错性较好
1 e: J5 x5 u& D7 P2 K' ~" \. X! j8 Q3 e5 ?# u' H3 J
- #include "mex.h"
- void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
- {
- double *inData;
- double *outData;
- int M,N;
- //异常处理
- //异常处理
- if(nrhs!=1)
- mexErrMsgTxt("USAGE: b=reverse(a)/n");
- if(!mxIsDouble(prhs[0]))
- mexErrMsgTxt("the Input Matrix must be double!/n");
- inData=mxGetPr(prhs[0]);
- M=mxGetM(prhs[0]);
- N=mxGetN(prhs[0]);
- plhs[0]=mxCreateDoubleMatrix(M,N,mxREAL);
- outData=mxGetPr(plhs[0]);
- for(i=0;i<M;i++)
- for(j=0;j<N;j++)
- outData[j*M+i]=inData[(N-1-j)*M+i];
- }; a, s3 e0 m6 Q5 ^# e; W- f
+ d* B' {! U; F' U6 C! F4 q* r6 h X& ]! E* `; y5 o
在上面的异常处理中,使用了两个新的函数:mexErrMsgTxt和mxIsDouble。MexErrMsgTxt在给出出错提示的同时退出当前程序的运行。MxIsDouble则用于判断mxArray中的数据是否double类型。当然Matlab还提供了许多用于判断其他数据类型的函数,这里不加详述。 4 F9 c7 `% c4 P) A U- a: ^) F' U
需要说明的是,Matlab提供的API中,函数前缀有mex-和mx-两种。带mx-前缀的大多是对mxArray数据进行操作的函数,如mxIsDouble,mxCreateDoubleMatrix等等。而带mx前缀的则大多是与Matlab环境进行交互的函数,如mexPrintf,mxErrMsgTxt等等。了解了这一点,对在Apiref.pdf中查找所需的函数很有帮助。
6 }) h0 z5 @0 t9 `( g至此为止,使用C编写mex函数的基本过程已经介绍完了。
. ]1 `$ [3 Q$ ?. m7 d |
|