C++ MATLAB 混合编程——VS项目调用MATLAB函数

引言

MATLAB无疑是一款强大的矩阵运算与数据分析软件,内部集成了众多函数。如果在C++编程时可以调用相关的函数将对我们的数据分析研究带来极大的方便。这里就总结一下如何在VS工程中调用MATLAB函数,以及遇到的问题如何解决的方法。

VS配置

这一步很重要,类似于其他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配置

在Matlab的command window输入:mex -setup
选择:mex -setup C++


这里写图片描述

然后再输入:mbuild -setup
选择:mex -setup C++ -client MBUILD


这里写图片描述

配置结束

这里写图片描述

测试

我们将在VS2013 的C++项目中调用MATLAB,调用方式有两种:(1)调用MATLAB引擎; (2)调用MATLAB函数生成的DLL。

方式1调用MATLAB引擎

首先,添加头文件 #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 <stdlib.h>
#include <stdio.h>
#include <string.h>
#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位,然后即可解决。

方式2调用MATLAB生成的dll

调用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

相关文章
相关标签/搜索