MATLAB无疑是一款强大的矩阵运算与数据分析软件,内部集成了众多函数。如果在C++编程时可以调用相关的函数将对我们的数据分析研究带来极大的方便。这里就总结一下如何在VS工程中调用MATLAB函数,以及遇到的问题如何解决的方法。
这一步很重要,类似于其他C++库的配置,如:添加包含目录和库路径。
添加库目录(自己的MATLAB安装路径中查找):D:\Program Files (x86)\Matlab2018a\extern\include
添加库路径(自己的MATLAB安装路径中查找):D:\Program Files (x86)\Matlab2018a\extern\lib\win64\microsoft
在Windows环境变量中的系统变量中“Path”中新增下面三项:
D:\Program Files (x86)\Matlab2018a\bin; (安装MATLAB后已经存在不用再添加)
D:\Program Files (x86)\Matlab2018a\bin\win32;
D:\Program Files (x86)\Matlab2018a\bin\win64
在Matlab的command window输入:mex -setup
选择:mex -setup C++
然后再输入:mbuild -setup
选择:mex -setup C++ -client MBUILD
我们将在VS2013 的C++项目中调用MATLAB,调用方式有两种:(1)调用MATLAB引擎; (2)调用MATLAB函数生成的DLL。
首先,添加头文件 #include “engine.h”
然后,引用函数调用依赖库(lib) libeng.lib libmx.lib libmat.lib,之后就可以调用MATLAB引擎。
// import necessary lib
#pragma comment( lib, "libeng.lib")
#pragma comment( lib, "libmx.lib")
#pragma comment( lib, "libmat.lib")
MATLAB引擎调用和文件操作类似:打开、关闭操作。
打开引擎:
Engine *ep;
if (!(ep = engOpen("\0")))
{
fprintf(stderr, "\nCan't start MATLAB engine\n");
return EXIT_FAILURE;
}
定义变量需要转换为matlab的格式。比如使用:mxCreateDoubleMatrix 和 memcpy函数。
将数据传入引擎使用:engPutVariable()。接着调用 engEvalString(ep, “matlab指令”)matlab的指令作为参数进行操作。计算操作等完成后需要清理操作:mxDestroyArray()函数清理mxCreateDoubleMatrix 生成的变量。
engClose()关闭引擎。
完整绘图例子:
#include
#include
#include
#include "engine.h" // add header file
// import necessary lib
#pragma comment( lib, "libeng.lib")
#pragma comment( lib, "libmx.lib")
#pragma comment( lib, "libmat.lib")
int main(void)
{
Engine *ep;
// open engine
if (!(ep = engOpen("\0")))
{
fprintf(stderr, "\nCan't start MATLAB engine\n");
return EXIT_FAILURE;
}
// generate variables
int Nsample = 50;
const double PI = 3.1415926;
double *t = new double[Nsample];
for (int i = 0; i < Nsample; i++)
{
t[i] = i * 2 * PI / Nsample;
}
mxArray *T = NULL, *result = NULL;
T = mxCreateDoubleMatrix(1, Nsample, mxREAL);
memcpy((void *)mxGetPr(T), (void *)t, Nsample*sizeof(t[0]));
engPutVariable(ep, "T", T); // put data to engine
// execute matlab operations
engEvalString(ep, "Y=sin(T);");
engEvalString(ep, "plot(T,Y);");
engEvalString(ep, "title('y=sin(t)');");
engEvalString(ep, "xlabel('t');");
engEvalString(ep, "ylabel('y');");
printf("Hit return to continue\n");
fgetc(stdin);
// clean operation(don't forget!!!)
mxDestroyArray(T);
engEvalString(ep, "close;");
// close engine
engClose(ep);
return EXIT_SUCCESS;
}
效果:
出现错误解决方法:
1>------ 已启动生成: 项目: CMatlab, 配置: Debug Win32 ------
1>main.obj : error LNK2019: 无法解析的外部符号 _mxGetPr_800,该符号在函数 _main 中被引用
1>main.obj : error LNK2019: 无法解析的外部符号 _mxDestroyArray_800,该符号在函数 _main 中被引用
1>main.obj : error LNK2019: 无法解析的外部符号 _mxCreateDoubleMatrix_800,该符号在函数 _main 中被引用
1>main.obj : error LNK2019: 无法解析的外部符号 _engEvalString,该符号在函数 _main 中被引用
1>main.obj : error LNK2019: 无法解析的外部符号 _engOpen,该符号在函数 _main 中被引用
1>main.obj : error LNK2019: 无法解析的外部符号 _engClose,该符号在函数 _main 中被引用
1>main.obj : error LNK2019: 无法解析的外部符号 _engPutVariable,该符号在函数 _main 中被引用
1>E:\shizhenwei\VS2013Projects\CMatlab\Debug\CMatlab.exe : fatal error LNK1120: 7 个无法解析的外部命令
这个问题出在兼容上。我们需要将vs工程变为64位,然后即可解决。
调用MATLAB生成的DLL是一种比较通用的方法,这样每次使用时只需调用这个模块就可以了。
首先,将需要MATLAB完成的功能做成一个MATLAB函数。
然后,利用mcc命令编译,得到h、dll、lib等文件,在C/C++工程中只需加入上述文件即可。
MATLAB函数代码
function showBER(SNR_indB,BER)
semilogy(SNR_indB,BER,'-o','linewidth',2);
grid on
xlabel('E_b/N_0(dB)');
ylabel('BER');
编译后,在MATLAB命令行中输入:
mcc -B csharedlib:showBER showBER.m
得到一组文件
将其中的.dll .h .lib文件拷贝到C工程中,在需要调用绘图模块的cpp文件中加入如下代码:
#include "showBER.h"
#pragma comment( lib, "libeng.lib" )
#pragma comment( lib, "libmx.lib" )
#pragma comment( lib, "libmat.lib" )
#pragma comment( lib, "mclmcrrt.lib" )
#pragma comment( lib, "showBER.lib" )
void main(void)
{
double SNR[] = { 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1.2, 1.3, 1.4, 1.5 };
double BER[] = { 9.728816e-002, 8.099609e-002, 5.633803e-002, 3.733608e-002, 1.253970e-002, 3.936489e-003, 1.206820e-003, 2.104052e-004, 3.109879e-005, 3.365857e-006, 2.565067e-007 };
int len = sizeof(SNR) / sizeof(SNR[0]);
showBERInitialize();
mxArray* xSNR = mxCreateDoubleMatrix(1, len, mxREAL);
memcpy(mxGetPr(xSNR), (void*)SNR, sizeof(SNR));
mxArray* xBER = mxCreateDoubleMatrix(1, len, mxREAL);
memcpy(mxGetPr(xBER), (void*)BER, sizeof(BER));
mlfShowBER(xSNR, xBER);
system("PAUSE");
showBERTerminate();
}
运行效果
其他打包方法可以参考3和4链接中的介绍,亲测可用。
参考
https://blog.csdn.net/guyuealian/article/details/73743654
http://blog.163.com/rongting_chen/blog/static/164906844201252354518462/
https://www.cnblogs.com/jmliao/p/5575202.html
https://blog.csdn.net/zheng_zhiwei/article/details/49002099