1. 调用MATLAB的方法
Matlab是强大的数学工具,有些时候我们需要自己解一些题,但又不想自己写算法的时候,就可以使用Matlab提供的外部调用功能,也就是说你的程序只需要编写其他部分,而计算交给Matlab实现。
实现外部调用有三种方法:
1.
在C或者Fortran语言中调用(本文介绍)
2.
与Matlab通讯
在UNIX下使用管道(pipe),在Windows下使用COM和DDE方式
3.
使用WebService接口
如果希望在更大的范围内进行数据交换和计算,比如Internet,可以使用这个接口
本文只介绍第一种方法,如果有人对后两者感兴趣,或者哪天我有空再对后面的两种做介绍。“C或者Fortran语言中调用MATLAB”又称为使用MATLAB引擎,在Matlab的使用手册中,详细的解释了如何使用这个功能。
2. 工作原理
工作流程如下图所示:
Matlab提供了一组C和Fortran的接口函数,我们简单看一下C的接口函数:
C Engine Routines
Function
Purpose
Start up
MATLAB engine
Shut
down MATLAB engine
Get a
MATLAB array from the MATLAB engine
Send a
MATLAB array to the MATLAB engine
Execute
a MATLAB command
Create a
buffer to store MATLAB text output
Start a
MATLAB engine session for single, nonshared use
Determine visibility of
MATLAB engine session
Show or
hide MATLAB engine session
很简单明确的接口吧,一看名字就基本上猜出来用法了。详细使用请看MATLAB的参考手册,如果有需要帮助的可以告诉我。
3. 简单的例子
我们假设需要做如下的运算:
A =
pascal(3);
B = magic(3);
X = A + B
pascal(n)是产生n大小的pascal方阵,在我国一般称为杨辉三角形。
magic(n)产生n大小的幻方,也就是横竖对角线相加的数是相等的。
最后一句话是两个Matrix相加。
在MATLAB中的结果如下:
>> A = pascal(3)
A =
1 1 1
1 2 3
1 3 6
>> B = magic(3)
B =
8 1 6
3 5 7
4 9 2
>> X = A + B
X =
9 2 7
4 7 10
5 12 8
假设我们要自己写代码实现上面的运算。我在WindowsXP(SP2), MATLAB6.5,
VC7.0下实现。具体的步骤是:
1). 设置环境变量PATH
PATH里面要包括MATLAB的exe, dll那个路径 %MATLAB_PATH%\bin\win32
2). 设置VC的路径
运行VC
include增加MATLAB的include路径 %MATLAB_PATH%\extern\include
lib增加%MATLAB_PATH%\extern\lib\win32\microsoft\msvc70
3).
在VC中新建一个console项目(也可以是win32,mfc等其他项目),项目的link输入增加libeng.lib和libmx.lib
4). main函数的代码:
#include
#include
#include
void
print_matrix_2d(mxArray * matrix, const char * matrix_name)
{
//Get the
datatype name of the matrix
const char *
name = mxGetClassName(matrix);
//Get the
data, that is double in this example
double* k =
(double*)mxGetPr(matrix);
//get row and column dimention
int row =
mxGetM(matrix);
int col =
mxGetN(matrix);
//print the matrix
printf("%s =
\n", matrix_name);
for(int i =
0; i < row; i++) {
printf(" ");
for(int j = 0; j < col; j++)
printf("%d ", (int)(*(k + i * col +
j)));
printf("\n");
}
}
int
main(int argc, char * argv[])
{
Engine
*ep;
mxArray *A =
NULL, *B = NULL, *X = NULL;
//Open the MATLAB Engine
if (!(ep =
engOpen("\0"))) {
fprintf(stderr, "\nCan't start MATLAB engine\n");
return EXIT_FAILURE;
}
//Run command in matlab
//A =
pascal(3); B = magic(3); X = A + B;
engEvalString(ep, "A = pascal(3)");
engEvalString(ep, "B = magic(3)");
engEvalString(ep, "X = A + B");
//Get results
A =
engGetVariable(ep, "A");
B =
engGetVariable(ep, "B");
X =
engGetVariable(ep, "X");
//print matrix
print_matrix_2d(A, "A");
print_matrix_2d(B, "B");
print_matrix_2d(X, "X");
printf("Done!\n");
//release results
mxDestroyArray(X);
mxDestroyArray(B);
mxDestroyArray(A);
//close MATLAB Engine
engClose(ep);
return
EXIT_SUCCESS;
}
上面的代码很简单,看一下其中的注释参考一下MATLAB的文档就可以理解了。至于为什么要把哪个指针写成(int)(*(k
+ i * col +
j)),是因为在C++里做的,C++对指针类型检查比较严格,而且虽然返回的是double,但实际上我们知道,这个例子中是integer的数据类型。这个还有其他写法,不过这不是我们现在的讨论重点。
5). 运行结果:
A
=
1 1 1
1 2 3
1 3 6
B =
8 3 4
1 5 9
6 7 2
X =
9 4 5
2 7 12
7 10 8
Done!
运行的时候开始会比较慢,这是因为在打开MATLAB引擎,这将会造成一些系统的开销,但是计算的时候会很快。
MATLAB支持窗体式的调用,这意味着你甚至可以重新写一个跟MATLAB界面完全不同的界面。另外,在UNIX系统下,MATLAB可以不在同一台机器上,他有一种方法可以允许调用在不同主机上的MATLAB,这暗示着你可以搭建一个MATLAB服务器。
详细情况请参考MATLAB的文档。
(这个例子比较简单,如果有任何错误或者问题,请给我留言......不知道有没有人看呢还,哈哈)