zoukankan      html  css  js  c++  java
  • VC与Matlab混合编程

    本文主要介绍VCMatlab混合编程的两种方法,并详细介绍了VCMatlab传递复杂数据:结构体的方法,有详细代码说明。

    Matlab 主要面对科学计算、可视化以及交互式程序设计的高科技计算环境,但由于Matlab开发平台上开发的程序不能脱离Matlab运行环境,因而在处理一些实际应用问题时显得灵活性不足,而VC++则在一定程度上能够弥补这一漏洞,因此,将二者结合共用,各献其长,可以为科研工作和工程开发提供更为强大的技术支持。

    Matlab作为控制系统设计的一种通用工具,它可以很方便的和VC进行连接。一般而言,MatlabVC混合编程的实现方法有很多种,这里主要介绍以下两种:

    1.  VC调用Matlab Engine的方式:

    Matlab Engine是一组Matlab提供的接口函数,支持C/C++语言,Matlab Engine采用C/S(客户机/服务器)模式,Matlab作为后台服务器,而C/C++程序作为前台客户机,向Matlab Engine传递执行命令和数据信息,从Matlab Engine接收执行结果。用户可以在前台应用程序中调用这些接口函数,实现对Matlab Engine的控制。采用这种方法几乎能利用Matlab全部功能,但是需要在机器上安装Matlab软件,缺点是执行效率较低。下面简单介绍下这种方式的实现步骤:

    1.1 API接口介绍

    先来介绍一组Matlab提供的引擎API接口:(仅作简单功能介绍,详细参数说明请参考Matlab帮助)

    Engine* engOpen(const char* startcmd)启动Matlab引擎

    int engClose(Engine* ep) 关闭Matlab引擎

    int engEvalString(Engine* ep, const char* string)执行Matlab表达式

    mxArray* engGetArray(Engine* ep, const char* name)获取一个变量数组的值

    int engPutArray(engine* ep, const mxArray* mp)设置一个变量数组的值

    int engPutVariable(Engine *ep, const char *name, const mxArray *pm)同上

    mxArray *engGetVariable(Engine *ep, const char *name)获取一个变量

    int engOutputBuffer(Engine* ePchar* pint n)获取输出字符串

    1.2   VC环境配置

    要想在VC集成环境下调用Matlab引擎实现VCMatlab的混合编程,一般需要经过以下几个必要的步骤:(以下以Matlab2008aVS2005版本为例)

    1)添加include路径:将“\extern\include(Matlab的安装路径下)路劲添加到VC编译器的include

    2)添加lib路径:将“\extern \lib\win32\microsoft (Matlab的安装路径下) 路径添加到VC编译器的lib

    3)加载lib:需要加载至少libmx.liblibmat.liblibeng.lib三个库

    4include头文件:在要使用 engine 函数的地方包含engine.h头文件

     

    1.3   引擎调用

    接下来就可以在VC中调用Matlab引擎了,简单的示例代码如下:

    #include "engine.h"
    
    #pragma comment(lib, "libeng.lib")
    #pragma comment(lib, "libmx.lib")
    #pragma comment(lib, "libmat.lib")
    
    void TestDeno()
    {
        Engine* pEng = NULL;
        if (!(pEng = engOpen(NULL)))
        {
            printf("Open matlab enging fail!");
            return;
        }
    
        //call Engine plot A*sin(t)+B A=2 B=1
    
        mxArray *A = NULL;
    
        double init = 2;
        A = mxCreateDoubleMatrix(1, 1, mxREAL);
        memcpy((void*) mxGetPr(A), (void*)&init, sizeof (double));
        engPutVariable(pEng, "A", A);
    
        init = 1;
        memcpy((void*) mxGetPr(A), (void*)&init, sizeof (double));
        engPutVariable(pEng, "B", A);
    
        mxDestroyArray(A);
    
        Sleep(3*60*1000);
    
        engEvalString(pEng, "t=0:0.2:7;plot(t,A*sin(t)+B);");
    
        if(NULL != pEng)
        {
            engClose(pEng);
        }
    }

    示例代码通过VC调用Matlab引擎,绘制正弦曲线,相对简单,就不再详细解释,效图如下:

      

    2. VC调用Matlab DLL的方式

    DLL是一个可执行的二进制文件。把很多通用的功能放在DLL中,可以供各种应用程序调用,这样可以很好的减少外部存储空间的占有量,并实现代码的共享。Matlab也支持将m程序编译成dll,供其他语言(包括VCVBFortran)调用,下面先简单介绍下Matlab DLL的编译步骤:

    2.1  Matlab DLL制作

    1)配置Matlab的编译器跟,要将mexmbuil两个都配置成本机上安装的VCmbuild的配置方法同mex

    2)编译m函数成为dll,在matlab命令空间中使用mcc命令编译m文件:(mcc的使用参考Matlab帮助)

    示例:将一个Matlab函数MyFun 编译成libMyFun 的命令:

    mcc –W cpplib:libMyFun –T link:lib MyFun

    参数说明:-W控制编译之后的封装格式,cpplib表示c++lib,冒号之后是编译输出lib名,-T表示目标,link:lib表示连接到lib的目标,MyFun是待编译的m文件名,编译成功之后,会输出三个文件:libMyFun.lib libMyFun.dll libMyFun.h

     

    2.2 DLLVC中调用

    要想在VC集成环境下调用MatlabDLL,实现VCMatlab的混合编程,一般需要经过以下几个必要的步骤:(以下以Matlab2008aVS2005版本为例)

    1VC环境配置,同前面VC调用Matlab引擎方式类似,也需要配置VC的编译环境,其中include路径、lib路径和前一种方式相同,加载的lib变更为:mclmcrrt.liblibmx.liblibmat.libmclmcr.lib四个,include的头文件变更为:mclmcr.hmatrix.hmclcppclass.h三个。

    2DLL中函数的调用,先看一下m函数编译成C++Dll之后的函数声明,例matlab函数:function [y, out] = CaculateFun(x, in)编译之后对应c++的声明:void MW_CALL_CONVCaculateFun(int nargout, mwArray& y, mwArray& out, const mwArray& x, const mwArray& in)参数int nargout指定调用时,输出参数个数,紧跟的后续nargout个参数yout为输出参数,后续再剩下的多个参数xin为输入参数

    3)注意事项:在VC调用dll中的函数之前需要调用函数libFunInitialize始化,调用完函数以后需要调用函数libFunTerminatemclTerminateApplication终止。

    准备好了上述步骤,就可以在VC中调用DLL中函数的了,简单的示例代码如下:

    // include matlab sys head file
    #include "mclmcr.h"
    #include "matrix.h"
    #include "mclcppclass.h"
    
    // include lib head file
    #include "libCaculateFun.h"
    
    // link matlab sys lib
    #pragma comment(lib, "mclmcrrt.lib")
    #pragma comment(lib, "libmx.lib")
    #pragma comment(lib, "libmat.lib")
    #pragma comment(lib, "mclmcr.lib")
    
    // link lib
    #pragma comment(lib, "libCaculateFun.lib")
    
    void TestDeno()
    {
        // init lib
        if (!(libCaculateFunInitialize()))
        {
            std::cout<<"Could not init lib !"<<endl;
            return -1;
        }
    
        double xxxx[2] = {0};
        double inin    = 0;
    
        double yyyy[2] = {0};
        double outo    = 0;
    
        // 为函数参数分配内存空间
        mwArray mwXX(1, 2, mxDOUBLE_CLASS);
        mwArray mwIn(1, 1, mxDOUBLE_CLASS);
    
        mwArray mwYY(1, 2, mxDOUBLE_CLASS);
        mwArray mwOut(1, 2, mxDOUBLE_CLASS);
    
        // 为输入参数赋值
        mwXX.SetData(&xxxx, 2);
        mwIn.SetData(&inin, 1);
    
        // 调用计算函数
        CaculateFun(2, mwYY, mwOut, mwXX, mwIn);
    
        // 获取输出参数
        outo = mwOut.Get(1, 1);
    
        // lib Terminate
        libCaculateFunTerminate();
    
        // MCR Terminate
        mclTerminateApplication();
    }

    示例代码通过VC调用Matlab DLL,将变量xxxx的值付给yyyy,将变量inin的值付给outo,相对简单,就不再详细解释。

    3.  VCMatlab函数传递参数

    前面在介绍两种混合编程的方式时,示例代码中已经涉及到了参数的传递问题,对于VC中的简单数据类型:变量、数组等,网上已经有很多资料介绍,前面示例代码中也有所体现,这里不再详细说明。

    关于复杂数据结构:用户自定义结构体类型,处理起来比较麻烦,网上能找到的资料也较少,由于前面提及的两种方式,在传递参数时,使用的数据类型是不一致的:引擎方式只能是mxArray类型,而DLL方式的参数只能是mwArray,因此需要分别介绍将结构体转换成这两种类型的方法:

    先来定义两个结构体:

    // 三维坐标系中的点
    struct Postion
    {
        double x;
        double y;
        double z;
    };
    
    // 名字标示的一个坐标点
    struct Coordinate
    {
        struct Postion pos;
        char name[ARRAYSIZE];
    };

    分别介绍将如上两个结构体转成Matlab能使识别的Array的方法

    (1)结构体转换成mxArray:解释比较多余,就直接上代码吧:

    mxArray *Staruct2mxArray(struct Postion *pStaruct)
    {
        mxArray *pm, *mx;
        mwSize m = 1, n = 1;
        const int nfields = 3;
        const char *fieldnames[3] = {"x","y","z"};
        const mwIndex index = 0;
    
        pm = mxCreateStructMatrix(m, n, nfields, fieldnames);
    
        mx = mxCreateNumericMatrix(m, n, mxDOUBLE_CLASS, mxREAL);
        memcpy(mxGetPr(mx), &(pStaruct->x), sizeof(double));
        mxSetFieldByNumber(pm, index, 0, mx);
    
        mx = mxCreateNumericMatrix(m, n, mxDOUBLE_CLASS, mxREAL);
        memcpy(mxGetPr(mx), &(pStaruct->y), sizeof(double));
        mxSetFieldByNumber(pm, index, 1, mx);
    
        mx = mxCreateNumericMatrix(m, n, mxDOUBLE_CLASS, mxREAL);
        memcpy(mxGetPr(mx), &(pStaruct->z), sizeof(double));
        mxSetFieldByNumber(pm, index, 2, mx);
    
        return pm;
    }
    
    mxArray *Staruct2mxArray(struct Coordinate *pStaruct)
    {
        mxArray *pm, *mx;
        mwSize m = 1, n = 1;
        const int nfields = 2;
        const char *fieldnames[2] = {"pos","name"};
        const mwIndex index = 0;
    
        pm = mxCreateStructMatrix(m, n, nfields, fieldnames);
    
        mx = Staruct2mxArray(&(pStaruct->pos));
        mxSetFieldByNumber(pm, index, 0, mx);
    
        n = ARRAYSIZE;
        mx = mxCreateNumericMatrix(m, n, mxCHAR_CLASS, mxREAL);
        memcpy(mxGetPr(mx), pStaruct->name, sizeof(char)*ARRAYSIZE);
        mxSetFieldByNumber(pm, index, 1, mx);
    
        return pm;
    }

    (2)结构体转换成mwArray

    mwArray Staruct2mwArray(struct Postion *pStaruct)
    {
        mwSize m = 1, n = 1;
        const int nfields = 3;
        const char *fieldnames[3] = {"x","y","z"};
    
        mwArray pm(m, n, nfields, fieldnames);
    
        mwArray mx(pStaruct->x);
        pm(fieldnames[0], 1, 1) = mx;
    
        mwArray my(pStaruct->y);
        pm(fieldnames[1], 1, 1) = my;
    
        mwArray mz(pStaruct->z);
        pm(fieldnames[2], 1, 1) = mz;
    
        return pm;
    }
    
    mwArray Staruct2mwArray(struct Coordinate *pStaruct)
    {
        mwSize m = 1, n = 1;
        const int nfields = 2;
        const char *fieldnames[2] = {"pos","name"};
        const mwIndex index = 0;
    
        mxArray pm(m, n, nfields, fieldnames);
    
        mxArray mpos = Staruct2mwArray(&(pStaruct->pos));
        pm(fieldnames[0], 1, 1) = mpos;
    
        mxArray mname(pStaruct->name);
        pm(fieldnames[1], 1, 1) = mname;
    
        return pm;
    }

    (3)mxArray转换成结构体:

    struct Coordinate *mwArray2Staruct(mwArray pm)
    {
        // 代码仅处理 name 字段 pos 字段是三个简单类型省略
        struct Coordinate *pStaruct = new struct Coordinate;
    
        const int nfields = 2;
        const char *fieldnames[2] = {"pos","name"};
    
        mwArray mwStr = pm.Get(fieldnames[1], 1, 1);
        char *str = strdup(mwStr.ToString());
    
        memcpy(pStaruct->name,str,sizeof(char)*ARRAYSIZE);
    
        return pStaruct;
    }

    (4)mwArray转换成结构体:

    struct Coordinate *mxArray2Staruct(mxArray *pm)
    {
        // 代码仅处理 name 字段 pos 字段是三个简单类型省略
        struct Coordinate *pStaruct = new struct Coordinate;
    
        mxArray * mxname = mxGetFieldByNumber(pm, 1, 1)
        mxArray * str = mxGetPr(mxname);
    
        memcpy(pStaruct->name,str,sizeof(char)*ARRAYSIZE);
    
        return pStaruct;
    }
  • 相关阅读:
    运算符
    JS的基本概念和数据类型
    开源基于Canal的开源增量数据订阅&消费中间件
    用AntDeploy如何更新Agent
    AntDeploy发布前端项目到IIS(脱离vs单独使用)
    截图上传录屏gif上传工具推荐
    netcore开发windows普通服务(非Web)并一键发布到服务器
    一键发布部署vs插件[AntDeploy]开源了
    基于python的Elasticsearch索引的建立和数据的上传
    浅谈闭包
  • 原文地址:https://www.cnblogs.com/xpvincent/p/2893046.html
Copyright © 2011-2022 走看看