当前位置:文档之家› Matlab和C混合编程的几种方法比较

Matlab和C混合编程的几种方法比较

Matlab和C混合编程的几种方法比较
Matlab和C混合编程的几种方法比较

Matlab和C混合编程的几种方法比较

杨允军整理并调试

第一部分概述

Matlab是Mathworks公司于1982年推出的一套高性能的数值计算和可视化软件,到2005年已发行到R14(Matlab 7.0),主流版本有4.0,5.3,6.1,6.5。它是一种面向科学计算和数值分析的软件,涵盖了通信、短阵运算、图像处理、金融分析、模糊控制、自动控制、信号处理、系统仿真、微分计算等方面。它提供了强大的科学运算、灵活的程序设计流程、高质量的数字图像处理等功能,突出的优点是强大的运算功能和近乎完美的绘图功能。

然而Matlab自身存在的一些不足使其在开发应用系统时受到局限,主要表现为以下几个方面:

(1)Matlab语言是一种解释执行的脚本语言,其程序运行效率低,特别是在编制大型复杂的应用系统时达不到理想的效果。

(2)Matlab编写的M文件是文本文件,很容易被直接读取,无法保护开发者的劳动成果。

(3)Matlab编写的程序只能在Matlab的平台下运行,不具备跨平台的能力,可移植性差。

(4)开发应用系统的界面能力差,很难做出友好的应用界面。

以上几点是VC等高级编程语言所专长的,而VC等高级编程语言在工程计算、复杂的数学计算、数字图形处理方面以及特定的学科领域的计算处理上远远不及Matlab。因此将二者结合起来,各取所长,将能更好地满足实际应用中的需要。

为了实现混合编程,Matlab 5.0以后的版本自带了C语言编译器(Compiler),可以将M 文件转换为C—MEX或C/C ++程序。根据是否需要Matlab环境,一般将Matlab与VC ++混合编程分为两大类:Matlab在后台运行和可以脱离Matlab环境运行。归纳起来Matlab与C接口有如下几种方法:

1.Matlab引擎(Engineer)采用客户/服务器的计算方式,通过Windows的ActiveX通道和Matlab相结合。在具体的应用中,VC ++的程序作为前端客户机,通过调用Matlab

Engineer在后台与Matlab服务器建立连接,实现动态通信。这种方法实现较为简单;不要求连接整个Matlab,只需要嵌入必要的Matlab Engineer库,可大大地节省系统资源,但这种Matlab在后台运行的效率低下。

2.Mideva(Matcom)是Mathtools公司推出的一种Matlab集成编译开发平台,提供对Matlab 程序文件(M文件)的解释执行和开发环境支持。经过简单设置后,Mideva可以将M源文件转换为C/C++,然后添加到MSVC、VB、C++ Builder等的工程中。自从Mathtools公司并入Mathworks公司以后,Matcom就停止了研发,最高版本为Matcom4.5。

3.利用Mideva直接生成EXE文件后,故C++中通过Shell调用,常见的外部函数有shellexec()或weinexec()。这种方法简单方便,但运行时出现一个控制台窗口,而且由于VC和Matlab 之间不能交互,且通用性差,仅适用于VC中调用Matlab,实现图形显示的场合。

4.借用C++编译器将Matlab下的M文件转换成DLL(动态链接库),其他应用程序可直接调用该DLL。

5.在C或者C++程序中使用Matlab提供的C/C++ Math Library函数直接调用Matlab函数。

(没有尝试过)

6.按照Mideva的语法,在VC中直接书写Matlab语句实现Matlab与C的混合编程。

7.Add—in实现Matlab与VC的混合编程是Matlab 6.0提供的一种最方便的方法,通过该方法,VC可直接在其开发环境中将M文件转换为CPP文件,并且可以现场修改M文件进行调试。但是不知道为什么Matlab7.0取消了这种功能。

8.MAT文件方法,也就是将Matlab产生的数据,通过Matlab提供的一些函数,在VC中读取。

这种方法没有交互性可言。

以上几种方法各有利弊,方法1需要在安装有Matlab的环境中运行,可移植性差。方法2、3、4、5、6、7可以脱离Matlab环境运行,移植性较好,但4、5、7 好像不支持图形显示,而且不能编译Matlab的内建函数 build-in 函数(如fft、filter等)。相对来说,Matcom 的Add-in 方法既简单功能又比较强大,但7.0以后的版本是否支持 Matcom 尚不得而知。

以上几种方法大同小异,除了 MEX 方法是在Matlab中调用C语言外,其他都是在VC中调用Matlab,后者是应用的主流。这里举出几种典型的方法及应用实例,大体能满足工程中互相调用的需求。几个实例都调试通过。

第二部分实例

2.1 C-MEX 实例

2.1.1 引言

有时仅仅为了加快运算速度的需要,可以考虑用效率较高的C语言编写耗时大的部分,并且通过Matlab的API接口转化为C-MEX文件(在Windows系统中为DLL文件),和Matlab的普通函数一样调用。

周期谱理论是由W.A.Gardner 等人深入研究并发展的[1],该理论的前提是认为信号具有周期平稳随机性,而大多数的通信信号符合这一特征。周期谱理论在信号检测、分类、参数估计、同步、提取,尤其在低信噪比条件下可以取得满意的效果。周期谱的工程计算分为时域平滑法和频域平滑法,后者是先求出信号的短时Fourier变换,然后作相关,存在计算量大的缺点,在Matlab实现过程中,这个缺点在数据量较大时是无法忍受的。所以,找到一条能减小运算时间的途径是十分必要的。

Matlab是一种解释执行的语言,用向量代替循环是其推荐的方法,但当循环必不可少时,仅仅在Matlab环境内寻找优化途径就力不从心了,这时考虑从Matlab和其他高级语言的接口方面突破。Matlab为了解决上述问题,提供了外部接口,本文主要介绍它与C/C++的接口。Matlab提供了一种生成和调用C-MEX文件的技术,可以将m文件中耗时的代码用C 实现,编译成动态库文件(Windows中为dll),使得其可以作为Matlab的build-in函数使用,这种C-MEX文件的执行效率比Matlab中的m函数要高。C-MEX文件的另一个优势是调试方便,可以在Matlab或借用VC环境进行调试。当然,Matlab还提供了其它一些技术,如Mat文件、引擎方式、m文件编译成动态库在VC中调用等。Mat文件只能传递变量数据,应用有限;引擎方式在程序运行时启用Matlab,慢且不方便;m文件通过Matlab的mcc编译器编译成动态库在VC中调用的方式相对来说完美,但也存在调用动态库时语法复杂的缺点。本文介绍的C-MEX文件的方法接口简单、调用方便,可以大幅度减小周期谱的计算时间。

2.1.2 原理

C-MEX文件其实就是带有Matlab接口的C文件编译好的动态连接库,程序主要由两部

分组成:计算子程序和接口子程序[2][3]。前者包含了用于计算的源代码,用来完成实际的计算工作,用C语言实现;后者它是计算子例行程序同Matlab环境之间的接口,用来完成两者之间的通信任务。接口子例行程序的名称固定为mexFunction,该函数中以mx、mex 开头的函数是Matlab与C的接口函数,mx-函数用来对mxArray结构体类型的操作,mex-函数用来对外传递数据。mexFunction函数有四个参数,分别为prhs、nrhs、plhs和nlhs,其中prhs为一个mxArray结构体类型的指针数组,该数组的数组元素按顺序指向所有的输入参数;nrhs为int类型,用以表示输入参数的个数;plhs也是一个mxArray结构体类型的指针数组,该数组的数组元素按顺序指向所有的输出参数;nlhs为int类型,表示输出参数的个数。以上两个部分是典型的C-MEX文件格式,其工作原理如图1所示。

图1 C-MEX的工作原理

为了能够在Matlab环境下运行这个程序,必须首先配置MEX的编译环境,其配置工作可在Matlab命令窗口中运行mex –setup,会提示选择编译器

[1] Lcc C version 2.4 in D:\MATLAB6P5\sys\lcc

[2] Microsoft Visual C/C++ version 6.0 in D:\Program Files\Microsoft Visual Studio

选择Compiler: Microsoft Visual C/C++ 6.0,就可以在Matlab或者VC环境输入C代码,编译生成C-MEX文件了,接下来介绍C-MEX文件的建立和调试。

2.1.3 实现过程

Matlab中调试MEX文件的错误提示信息不容易理解,在VC中调试可以有效地解决这方面的问题,这里介绍VC环境下编译生成及调试MEX文件的过程。

(一)建立dll工程。在VC中创建DLL工程SCFdll,在def文件中输入LIBRARY SCFdll,EXPORTS mexFunction,表示库文件名或者对外发布的包装为SCFdll。

(二)建立C文件,写运算子程序部分和接口子程序部分。新建C Source文件,加入#include "mex.h"语句,该头文件在目录\extern\include下,所以还要在VC的include搜索路径中包含\extern\include,具体操作为在Tools->Options->Directories 的inlcude搜索路径中添加\extern\include。因为用到了VC的编译器,所以在lib 搜索路径中还要加入\extern\lib\win32\microsoft\msvc60。

在周期谱计算中,我们发现谱相关运算消耗了大量的时间,用C-MEX文件代替这一部分Matlab代码可以大幅度减少耗时。C文件的计算子程序用来完成短时Fourier变换后的相关计算,double SpecR []为短时Fourier变换的实部,double SpecI[]为短时Fourier变换的虚部,DatLen为短时Fourier变换的长度,double SR []为得到的周期谱的实部,double SI []为

得到的周期谱的虚部,N1为搜索带宽的起点,N2为终点,M为平滑次数。代码如下:

/* ----- C++ 源程序-----*/

void spec_smth(double SR[], double SI[], double SpecR[], double SpecI[],

int M, int N1, int N2, int DatLen)

{

int i,v;

double tempR, tempI;

int N = N2-N1;

v=0;

for(i=0;i

{

SR[i] = 0;

SI[i] = 0;

}

for(v=0;v

for(i=0;i

{

SR[i] = SR[i] + SpecR[v+i+N1]*SpecR[v-i-N1+DatLen] + SpecI[v+i+N1]*SpecI[v-i-N1+DatLen];

SI[i] = SI[i] + SpecR[v-i-N1+DatLen]*SpecI[v+i+N1] - SpecR[v+i+N1]*SpecI[v-i-N1+DatLen];

}

}

C文件的接口子程序mexFunction用来完成C语言和Matlab的数据交换,一般用来检验输入输出参数和调用计算子程序。代码如下:

/*----- 接口子程序-----*/

void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray*prhs[] )

{

int M ;

int DatLen ;

int N1 ;

int N2 ;

int N;

double *SR;

double *SI;

double *SpecR;

double *SpecI;

/* Check for proper number of arguments */

/* if (nrhs != 5)

mexErrMsgTxt("Five inputs required."); //mexErrMsgTxt breaks you out of the MEX-file.

if (nlhs != 2)

mexErrMsgTxt("Two outputs required.");

if (mxGetN(prhs[0]) != mxGetN(prhs[1]))

mexErrMsgTxt("I and Q must be the same size.");

*/

/* Distribute the parameters */

DatLen = mxGetN(prhs[0])/2; /* The spectrum is cyclo-spread */

M = mxGetScalar(prhs[2]);

N1 = mxGetScalar(prhs[3]);

N2 = mxGetScalar(prhs[4]);

N = N2-N1;

/* Assign pointers to the various parameters */

SpecR = mxGetPr(prhs[0]);

SpecI = mxGetPr(prhs[1]);

plhs[0] = mxCreateDoubleMatrix(1, N, mxREAL); // malloc space

SR = mxGetPr(plhs[0]); // spectrum for output

plhs[1] = mxCreateDoubleMatrix(1, N, mxREAL); // malloc space

SI = mxGetPr(plhs[1]); // spectrum for output

spec_smth(SR,SI,SpecR,SpecI,M,N1,N2,DatLen);

}

(三)设置matlab.exe为调试环境和路径。Projects->Settings->Debug的Executable debug session中选择matlab.exe作为Debug环境。按F7编译通过后,按F5运行,此时就会自动启动Matlab环境,将SCFdll当成普通函数,在Matlab命令窗口中输入数据STFT, Len和命令SCF=SCFdll(STFT, Len)进行验证。当然,C-MEX文件SCFdll.dll必须在Matlab的搜索路径中。还可以在C文件中设置断点,这为调试带来了很大的方便。因为生成的C-MEX文件最终是在Matlab中作为build-in函数运行,和普通函数没有区别。

2.1.4 总结

测试选取的硬件条件为赛扬2.4,运行环境为Matlab6.5,用两种不同的计算方法对不同长度的数据点的周期谱计算进行了计算时间的测试,测试结果如下表。可以看出,C-MEX 对周期谱计算进行优化的效果是明显的,在本文描述的算法中可以将计算时间缩短为用m 函数直接计算耗时的1/7左右。

2.2 Add-in 实例

2.2.1 引言

在众多的Matlab与VC结合的方法中,Add-in方法简单,结构明了。能在没有Matlab 环境的情况下(配置过程需要用到Matlab环境),将M文件转化为C++文件,从而方便地在VC中调用,Add-in还提供打包功能,自动提取库文件,打包成zip文件后,在没有安装Matlab的机子上解压缩,从而脱离Matlab环境。更重要的是,可以边修改m文件边调试,至于书上介绍的用Matrix View观察变量的做法,我没能实现,遗憾。

但是VC的编译器不能编译Matlab的内建函数的硬伤使得对很多算法的编译不能得心应手,比如该编译器对FFT就无能为力。

滤波器设计是信号处理、自动控制等领域不可回避的问题,用VC等工具实现滤波器的设计相当繁琐,Matlab在这些方面又得天独厚的优势,所以可以考虑在VC中调用Matlab 的滤波器设计工具箱,在VC中直接实现滤波器的设计。

2.2.2 原理

Add-in的原理是将M文件转化为C++文件,经过适当的Matlab的Math C函数连接整合,在VC中调用。

2.2.3 实现过程

VC中Add-in的设置步骤:

(1)在Matlab命令行中键入mex –setup(注意“mex”与“-”之间有空格)和mbuild -setup 命令,按照给出的提示选择MSVC6.0作为编译器。配置好后,Matlab将提示Add-in组件已成功安装到VC。此时别忘了在Matlab命令行中继续键入cd(prefdir)和mccsavepath命令,将Matlab的路径写入VC中的某些文件。

(2)在VC菜单中选择Tools->Customize->Add-ins and Macro Files一栏,勾选MATLAB Add-in,然后关闭,此时下图所示的Matlab add-in的工具条Toolbar1就会出现。

(3) 接下来是在VC的include设置搜索路径。在Tools->Options->Directories的include 搜索路径中添加\extern\include;因为用到了VC的编译器,所以在lib搜索路径中还要加入\extern\lib\win32\microsoft\msvc60。

前期准备到这里就完成了,配置一次,终身管用。下面用Add-in方法,调用Matlab的滤波器设计工具箱,做一个简单的低通滤波器设计。具体步骤如下:

首先建立一个基于对话框的exe工程取名test2,修改对话框的界面如图:

N为滤波器的阶数,WN是归一化带宽,产生的滤波器系数在Filter coefficients编辑框内显示出来。

第二步是点击Toolbar1内的.m++,选择添加myfilter.m文件,源代码如下:

function [b, a] = myfilter(n,wn)

[b, a] = butter(n, wn);

此时出现下图所示的对话框,选择默认,按OK后,自动生成一大堆的m文件和C源和.h 文件,有用的是myfilter.c和myfilter.h。前者是myfilter.m转化而来的C文件,不过太繁琐,只要看后者就可以知道他的功能和调用方法了。

myfilter.h文件里有这几行语句:

extern void InitializeModule_myfilter(void);

extern void TerminateModule_myfilter(void);

extern _mexLocalFunctionTable _local_function_table_myfilter;

extern mxArray * mlfMyfilter(mxArray * * a, mxArray * n, mxArray * wn);

extern void mlxMyfilter(int nlhs, mxArray * plhs[], int nrhs, mxArray * prhs[]);

其中extern void InitializeModule_myfilter(void);和extern void TerminateModule_myfilter(void);明显是初始化语句,extern mxArray * mlfMyfilter(mxArray * * a, mxArray * n, mxArray * wn);为调用形式,具体实现在myfilter.h文件中,能把人看晕。

第三步为Test按钮的响应函数void CTest2Dlg::OnButtonTest()添加代码:

double nOrder; // ??2¨?÷?×êy

double nWn; // ??2¨?÷???1?μ?ê(0~1)

double *pNum = NULL; // ó?à′·μ????2¨?÷?μêy

mxArray *mxArray_nOrder; // mxArray ààDíμ???2¨?÷?×êy

mxArray *mxArray_nWn; // mxArray ààDíμ???2¨?÷???1?μ?ê

mxArray *mxArray_num; // mxArray ààDíμ???2¨?÷?μêy

UpdateData(true);

nOrder = double(m_EditN);

nWn = m_EditWN;

mxArray_nOrder = mxCreateDoubleScalar(nOrder); // mxArray_nOrder3?ê??ˉ

mxArray_nWn = mxCreateDoubleScalar(nWn); // mxArray_nWn3?ê??ˉ

InitializeModule_myfilter(); // μ÷ó?3?ê??ˉ

mxArray_num = mlfMyfilter(NULL, mxArray_nOrder, mxArray_nWn); // oˉêyμ÷ó?

pNum = mxGetPr(mxArray_num); // double ààDíμ???2¨?÷?μêy

TerminateModule_myfilter(); // μ÷ó?mlfMyfilteríê±?

mxDestroyArray(mxArray_nOrder);

mxDestroyArray(mxArray_nWn);

mxDestroyArray(mxArray_num);

mxCreateDoubleScalar、mxGetPr、mxDestroyArray等函数功能可以在Matlab的帮助了找到。代码层次分明:mxArray_nWn = mxCreateDoubleScalar(nWn); 之前的语句用来实现参数的输入;mxArray_num = mlfMyfilter(NULL, mxArray_nOrder, mxArray_nWn)完成滤波器的设计;pNum = mxGetPr(mxArray_num);接收滤波器的系数,最终的滤波器系数保存在指针pNum中,能在VC中使用。至于在实际应用中具体怎么操作,已不在讨论范围之内了。

2.2.4 总结

1. 可以边修改m文件边调试;

2. 点击Toolbar1上的包裹状按钮还可以实现程序的打包,将用到的一些库文件发布成一个压缩文件,在没有安装Matlab的机子上,解压缩,程序照样可以运行,这一点很有诱惑力;

3. 不能编译Matlab的内建函数,图形句柄不能用(不知道是我没调通还是真的不能用)。

总体来讲,这种方法还是值得推荐的。

2.3 Matcom 实例

2.3.1 引言

Matcom的特点:Matcom是一个非常有用的m文件编译器(compiler),它有如下几大优点:

1.它提供了Matlab语言中m文件和其他语言的接口,使m文件可以编译为脱离Matlab 环境独立执行的可执行程序,这样不仅提高了代码的复用率,执行速度快,而且使纯文本的。m文件转化为二进制的可执行文件,增加了知识保护的安全性。

2.它提供了近千个数学函数。对于其他高级语言编辑器来说,提供了一个丰富的数学库,基本上在Matlab上能用的常用函数都可以在高级语言中调用,数学函数主要包括矩阵属性生成函数、数学函数、绘图函数等。

3.它可以编译Matlab的大部分函数,包括fft等,但是不知道为什么,不能编译xcorr这样的函数,有可能是Matlab5.3时候的相关函数不是xcorr(待考证)。

2.3.2 原理

Matcom的工作原理:Matcom的矩阵运算部分是基于一个名为Matrix的C++数学库,这个库提供了绝大多数的关于矩阵类、矩阵操作函数、数值计算函数、数学函数等的定义,在Matcom中是以lib目录下的*.lib以及windows/system/ 对应名称的dll文件提供的。

Matcom的另一大部分就是图形部分,它是用一种非常流行的绘图OCX控件TeeChart3.0来实现的,这种控件对于一般的绘图功能都可以实现,但也存在一定缺陷。在Matcom4.5版本中使用的是TeeChart3.0。绘图函数功能主要在lib文件和window/system/ago*.dll中定义的。

Matcom编译m文件时先将m文件按照与Matcom的cpp库的对应关系,翻译为cpp源代码,然后用对应版本的C编译器将该CPP文件编译为.exe或.dll文件,所以,在第一次运行时让指定C Compiler的路径是必要的,否则将无法编译。指定好的C Compiler的信息写在Matcom/bin/matcom.ini文件中,这些都是在安装的时候自动完成的。

2.3.3 实现过程

按下列步骤完成Matcom add-in的安装:

1.安装Matcom,按提示选择Visual C++的安装路径;

2.运行Visual C++,从菜单条中选择Tools/Customize/Add-ins and Macro Files,选择Browse,改变文件类型为Add-ins(.dll),选定D:\Matcom45\bin\mvcide.dll文件,确定;

3.此时,可以在VisualC+十的开发环境中看到如下图所示工具栏,表明安装成功。

安装完毕后,就可以实现m->cpp的转化以及和Visual C++ 无缝连接了。

本例的“测试”按钮实现一个正弦波的产生及显示。M文件 mcctest 的源代码如下:function mcctest

n = 256;

x = sin([1:n]/n*(16*pi));

y = abs(fft(x));

y = y(1:n/2);

[m i] = max(y);

plot(x);

首先建立一个基于对话框工程matcom_test.exe

点击.m++后载入mcctest.m 文件,在资源管理器中生成一系列的cpp文件,而且库函数v4501v.lib自动添加,方便快捷,一键搞定,如图,

我们会发现在g_mcctest.cpp出现如下代码:

#include "matlib.h"

#pragma hdrstop

#include "mcctest.h"

unsigned int mlibpr=mt_set_MT(0); // 1 if program is multithreaded, 0 otherwise.

int main() {

begin_scope

initM(MA TCOM_VERSION);

mcctest();

exitM();

return 0;

end_scope

}

其中initM(MA TCOM_VERSION); exitM(); 是用来初始化和退出Matcom调用的,mcctest(); 是运算及画图主函数。值得说明的是,该文件只是当VC的控制台console方式下才运行,但该文件给出的语法结构却可以原封不动的Copy到其他的功能函数中。

对测试按钮对应的函数添加代码:

void CMatcom_testDlg::OnButton1()

{

initM(MATCOM_VERSION); // 添加的

mcctest(); // 添加的

exitM(); // 添加的

return; // 添加的

}

添加头文件

#include "matlib.h"

#include "mcctest.h"

运行就可以出现(b)所示的效果。

“计算”按钮用来实现周期谱的计算功能,参数设置中的参数除信号长度外都是归一化参数。M文件SCF_calculate_m.m实现周期谱的运算,源代码如下:

function [SCF] = SCF_calculate_m(dat, DatLen , M, F0, B);

% 各参数的意义略

B = B/2;

Spectrum = fft(dat);

SpecArray = [Spectrum Spectrum];

QN = round(B*DatLen);

M = round(M*DatLen);

NX0 = round(F0*DatLen);

N1 = NX0-QN+1;

N2 = NX0+QN;

SCF = zeros(1,N2-N1+1);

for v = 1:M

SCF= SCF+SpecArray(v+N1:v+N2).*conj(SpecArray(DatLen+v-N1:-1:DatLen-N2+v));

end

plot(abs(SCF));

% [EOF]

对“计算”按钮对应的函数添加代码:

void CMatcom_testDlg::OnButton2()

{

// TODO: Add your control notification handler code here

long ireadlength = m_nDatLen*1024;

long li;

float* SigI;

short shtemp;

// ================================ //

CFileDialog dlg(TRUE,

NULL,

NULL,

OFN_HIDEREADONL Y|OFN_OVERWRITEPROMPT,

// "Binary Files (*.bin)|*.bin|Data Files (*.dat)|*.dat|All Files (*.*)|*.*|", "All Files (*.*)|*.*|",

NULL);

//**********文件读取**********

if(dlg.DoModal()==IDOK)

{

CFile file;

file.Open(dlg.GetPathName(),CFile::modeRead);

// SigI = new float[2*ireadlength];

SigI = new float[ireadlength];

for(li=0; li

{

file.Read(&shtemp,sizeof(short)); // êμ2??aêy?Y?£

SigI[li] = shtemp; // êμ2??aêy?Y?£

}

file.Close();

}

else

return;

initM(MATCOM_VERSION);

Mm M = m_nM;

Mm F0 = m_nF0;

Mm B = m_nB;

Mm Sig = zeros(ireadlength,1);

Mm SCF;

for(li=0; li

{

Sig(li+1,1) = SigI[li]; // êμ2??aêy?Y?£

}

SCF = SCF_calculate_m(Sig, ireadlength, M, F0, B);

exitM();

return;

}

以上代码中,完成周期谱计算的是SCF_calculate_m 函数,其余为数据读取和参数导入部分,在SCF_calculate_m.h 中可以看到SCF_calculate_m 函数原型如下:

Mm SCF_calculate_m(Mm dat, Mm DatLen, Mm M, Mm F0, Mm B);

需要注意的一个问题是,Matcom 的数组下标从1开始,C++中从0开始,所以从(float*)SigI 直接转换为(Mm )Sig 时,用的语句为Sig(li+1,1) = SigI[li];

添加头文件

#include "matlib.h"

#include "SCF_calculate_m.h"

编译运行得到(c )所示的结果,和Matlab 中的SCF_calculate_m 运行结果(d )对比可知,这种方法是可行的,而且速度占优势。

2.3.4 总结

Matcom 是M 向C 转换的理想工具,转换后生成的C++文件和在Matlab 环境中运行时具有明显的速度优势,更重要的是,它解决了Matlab 速度慢、VC++显示和计算函数匮乏的顽疾,使Matlab 和VC++可以很好的结合起来。

Matcom 在两者结合中的应用还有几种方法,比如Matcom 的GUI 、直接将m 文件转换为DLL 然后在其他软件环境中调用。

2.4 DLL 实例

2.4.1 引言

DLL 是一个可执行的二进制文件。把很多通用的功能放在DLL 中,可以供多个应用程

(d

序调用,而不是每个应用程序在连接时都要增加一个库中目标代码的拷贝。可以整体减少文件外部存储空间的占有量,并实现了代码共享。

(l)根据实际问题的需要,在MA TLAB中开发算法。MATLAB的开发环境功能强大,其语言简单直观。而且为用户提供了完善的代码调试工具,用户可以在函数执行的任何时候知道当前局部变量和全局变量的数值。另外,当前用户完成算法的调试工作后,往往希望了解该算法中哪几条语句最消耗计-算时间,MATLAB提供Profiler工具可以很好地解决这一问题。借助于Profiler的强大功能,用户可以完全掌握调用关系比较复杂的程序的执行情况,每一个函数的被调用次数和执行时间都可以清楚地显示出来。用户可以借助编译工具或优化代码工具对算法的瓶颈部分进行处理,尽可能地优化算法,或者将耗时的代码用C实现。这种方法就是前面介绍的MEX方法。

(2)利用Matlab Compiler和VC编译m文件,将开发好的算法转换为C或C++代码,然后生成动态链接库,将算法封装其中。在VC的IDE中开发应用程序的图形用户界面,通过DLL调用已开发好的算法。采取的调用方法一般是通过DLL的头文件获取DLL的功能和函数调用方式,然后在VC中当成普通的C函数调用。这是将要介绍的DLL方法。

2.4.2 原理

DLL方法和前面介绍的Add-in方法大同小异,也是用VC编译器将m文件转化为可以被VC中介编译调用的语言,两者都产生相应的.h文件和.c文件,只是DLL方法的中功能函数有DLL实现,而Add-in方法直接用C/C++代码实现。由以上的介绍,就可以很明白DLL方法需要的为:功能函数的.h文件、.lib文件、.dll文件。下图是Matlab compiler user’s guide中关于独立可执行程序生成的过程,生成DLL的过程也大体相似。Matlab7.0自带的Compiler 4.0比以前的编译器有较大的变化,具体变化不详……

2.4.3 实现过程

以低通滤波器设计为例。M 文件myfilter.m 源代码如下:

function [b, a] = myfilter(wp,ws)

[n, wn] = buttord(wp, ws, 3, 30);

[b, a] = butter(n, wn);

具体步骤为:

1.在VC中建立基于对话框的工程test3,包含wp、ws两个输入编辑框和一个测试按钮;

2.在matlab命令行中键入mcc -t -W lib: filterlib -T link:lib myfilter,生成一大堆文件,我们用到的有三个文件:filterlib.h、filterlib.lib、filterlib.dll,将这三个文件

Copy到test3目录下;

3.在VC中作如下设置:(a)Project->Settings->link->Objects/Library Modules中添加一些库文件名filterlib.lib libmmfile.lib libmatlb.lib libmx.lib libmat.lib libmex.lib

libut.lib libmatpm.lib,每个库干什么用我不是很清楚,参考文件中有说明;(b)

设置VC的搜索路径,具体操作为在Tools->Options->Directories的inlcude搜索

路径中添加\extern\include。因为用到了VC的编译器,所以在lib搜

索路径中还要加入\extern\lib\win32\microsoft\msvc60;

4.在测试按钮对应的函数中添加Matlab的Math C语句和具体的滤波器设计语句:double a;

double b;

double result;

UpdateData(true);

a = m_Editwp;

b = m_Editws;

mxArray *A = mclGetUninitializedArray();

mxArray *B = mclGetUninitializedArray();

mxArray *C = mclGetUninitializedArray();

filterlibInitialize(); // 请注意:不是InitializeModule_filterlib();

mlfAssign(&A,mlfDoubleMatrix(1,1,&a,NULL));

mlfAssign(&B,mlfDoubleMatrix(1,1,&b,NULL));

C = mlfMyfilter(NULL, A, B);

filterlibTerminate();

double *md = mxGetPr(C);

result = md[0];

此时,最终的结果就保存在指针result中。具体怎么取出来并不是难事,这里不作研究。

2.4.4 总结

DLL方法和Add-in方法相似,从实现过程也可以看出来。之所以单独提出来,是因为这种做法具有一定的代表性,调用库来实现算法,看起来都气派!

以上是几种方法,还有其他的,尤其是7.0后的版本,我没有研究过。就以上的方法来

讲,我首推Matcom 的方法,其次是Add-in。

第三部分参考文献

1. VC与Matlab结合方法的分析姚鑫浩

2.基于Matlab Add-in的Matlab/VC混合编程的研究李霞李萌彦

3. 运用mex文件优化Matlab软件性能谢莉萍龙志强谢海斌

4.VC与MATLAB混合编程之DLL实现方法肖永韧解习农刘晓峰

5.

6.

相关主题
文本预览
相关文档 最新文档