加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

C与MATLAB混合编程之调用MATLAB引擎

(2014-01-06 15:24:30)
标签:

c与matlab混合编程

matlab引擎

分类: 工作札记

Visual Studio调用MATLAB需要的配置已经在《Visual Studio调用MATLAB的配置》一文中给出了详细的步骤,本文将介绍混合编程的示例。

在C中调用MATLAB,据网上介绍主要有3种方法:

1)、在C程序中调用MATLAB引擎;(本文)

2)、将M文件编译生成dll文件供C程序使用;

3)、将MATLAB程序编译成C/C++源文件并嵌入到C程序中。

1、在C程序中调用MATLAB引擎

为了调用MATLAB引擎,首先需要引入相应的头文件。

#include "engine.h"

然后需要加如下几行代码,这样顺利地完成连接。

#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;

}

接下来将C程序中相关的变量变为MATLAB需要的格式,一般使用mxCreateDoubleMatrix、mxCreateLogicalScalar和memcpy函数,将Visual Studio的源数据转换为MATLAB格式。

完成转换后使用engPutVariable将数据送到matlab引擎。

最后调用engEvalString,将MATLAB命令作为其参数,就可以利用MATLAB引擎进行计算了。

计算完成后通过engGetVariable和memcpy函数将结果数据返回给Visual Studio即可。

计算完成后不要忘了清理工作:使用mxDestroyArray清除mxCreateDoubleMatrix产生的变量,最后使用engClose关闭引擎。

下面是一个例子,绘制y=sin(t)的图像

代码:

#include

#include

#include

#include "engine.h"

 

#pragma comment( lib, "libeng.lib" )

#pragma comment( lib, "libmx.lib" )

#pragma comment( lib, "libmat.lib" )

 

int main()

{

Engine *ep;

if (!(ep = engOpen("\0")))

{

fprintf(stderr, "\nCan't start MATLAB engine\n");

return EXIT_FAILURE;

}

 

int Nsample = 50;

const double PI = 3.1415926;

double *t = new double[Nsample] ;

 

for(int i = 0; i <<SPAN style="LINE-HEIGHT: 28px; COLOR: rgb(101,123,131)"> 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);

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\n");

fgetc(stdin);

 

mxDestroyArray(T);

engEvalString(ep, "close;");

 

engClose(ep);

return EXIT_SUCCESS;

}

在调试的时候,会弹出一个错误窗口,提示没有dll动态链接库,如下所示:http://s15/mw690/002jgDYpzy6FvcOciGq0e&690
由于貌似需求的dll文件较多,故将所有dll文件皆进行了拷贝。

调用matlab需要的dll文件在目录“C:\Program Files\MATLAB\R2010b\bin\win64”下。(须与实际安装位置对应)

Visual Studio运行时查找dll的路径是目录“C:\Windows\System32”下。

因此,将目录“C:\Program Files\MATLAB\R2010b\bin\win64”下的所有dll文件都拷贝到了目录“C:\Windows\System32”下。

这样则解决了该错误。

设置好断点,并启动调试后,可以看到启动了matlab的命令行窗口,并绘制出了图形。

http://s16/mw690/002jgDYpzy6FvdrJ7IPdf&690
不需要输入任何命令,只需等待即可。Visual Studio调用MATLAB需要花费较长的时间,即使功能非常简单也是如此。http://s10/mw690/002jgDYpzy6FvdA6zsR39&690
在许多应用中,不仅会有输入参数,而且需要matlab进行计算后,把计算结果传递给Visual Studio,下面以矩阵的运算为例,关于matlab与Visual Studio的接口函数,大家可以参照matlab的help中的“C/C++ and Fortran API Reference”,这些在help中讲解的比较清楚。

需要注意的是,在C语言中数组的序列是以行元素优先的,而在MATLAB中数组序列是以列元素优先的。

#include
#include

using namespace std;

#include    // 使用VC++和Matlab引擎混合编程就必须加这个头文件,它里面包含了
#include

#pragma comment(lib, "libmat.lib")
#pragma comment(lib, "libmx.lib")
#pragma comment(lib, "libeng.lib")

void main()
{
    // 定义循环变量
    int i  = 0, j = 0;

    // 状态变量
    int nStatus = 0;

    // 定义MATLAB引擎指针
    Engine *ep;

    // 定义mxArray变量指针
    mxArray *A, *B;

    // 定义矩阵数组, 注意:VC中矩阵的行列次序与MATLAB正好相反,需要转置
    double arData[3][3] = {{7.5,16.3,9.6},{13.2,8.9,12.3},{9.6,5.4,13.7}};
    double arResData[3][3];

    // 输出原矩阵
    cout<<"原矩阵为:"<<endl;
    for(i = 0; i < 3; i++)
    {
        for(j = 0; j < 3; j++)
        {
            cout<<setw(10)<<arData[i][j]<<" ";
        }
        cout<<endl;
    }

    // 打开MATLAB引擎
    ep = engOpen(NULL);        // 在Windows系统中该函数的参数都为“NULL”。
    if(ep == NULL)
    {
        cout<<"无法打开MATLAB引擎。"<<endl;
        exit(EXIT_FAILURE);
    }

    // 是否显示MATLAB窗口:true-显示;false-隐藏。
    nStatus = engSetVisible(ep, true);           // 设为ture运行时也只是一闪而过

    if(nStatus != 0)
    {
        cout<<"设置MATLAB显示属性失败。"<<endl;
        exit(EXIT_FAILURE);
    }

    // 为mxArray变量分配空间
    A = mxCreateDoubleMatrix(3,3,mxREAL);
    B = mxCreateDoubleMatrix(3,3,mxREAL);
    if(A == NULL || B == NULL)
    {
        cout<<"为mxArray变量分配空间失败。"<<endl;
        exit(EXIT_FAILURE);
    }

    // 将数组中的数据写入到mxArray空间中
    memcpy((void*)mxGetPr(A),(void*)arData,sizeof(arData));  // 使用内存数据复制函数memcpy进行复制

    // 将矩阵变量A写入到MATLAB引擎空间
    nStatus = engPutVariable(ep,"A",A);
    if(nStatus != 0)
    {
        cout<<"矩阵变量写入MATLAB引擎空间失败。"<<endl;
        exit(EXIT_FAILURE);
    }

    // 执行引擎命令求矩阵A的逆矩阵
    nStatus = engEvalString(ep,"B=inv(A)");   // B=inv(A)为要在MATLAB中运行的命令参数
    if(nStatus != 0)
    {
        cout<<"执行MATLAB引擎命令失败。"<<endl;
        exit(EXIT_FAILURE);
    }

    // 从MATLAB引擎空间中读取执行结果
    B = engGetVariable(ep,"B");
    // 将矩阵变量B复制到数组arResData中
    memcpy((void*)arResData,(void*)mxGetPr(B),sizeof(arResData));

    // 释放矩阵变量空间
    mxDestroyArray(A);
    mxDestroyArray(B);   

    // 输出计算结果
    cout<<"逆矩阵为:"<<endl;
    for(i = 0; i < 3; i++)
    {
        for(j = 0; j < 3; j++)
        {
            cout<<setw(10)<<arResData[i][j]<<" ";
        }
        cout<<endl;
         

    // 暂停程序,查看结果
    system("pause");

    // 关闭MATLAB引擎
    engClose(ep);
}

运行结果为

http://s5/mw690/002jgDYpzy6FzTU9n3Se4&690
至此,该方法已经试验成功。

在网络博文《MATLAB引擎方式实现VC与MATLAB混合编程》中,对用该方法所会用到的一些命令进行了总结,第2个例子也是出自该博文。

这种方法,是通过MATLAB引擎调用MATLAB运行,需要在Visual Studio里逐条输入命令,当所需功能较为简单、MATLAB命令较少时,该方法是可以的,如果命令较多则最好换用其他方法。

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有