您的位置:首页 > 编程语言 > MATLAB

远程计算_使用Matlab计算引擎

2015-06-13 00:06 495 查看

0 环境

win7 32bit

vs2008

matlab r2013b

1 准备工作

确保vs与matlab均已正确安装

添加环境变量
PATH
D:\Program Files\MATLAB\R2013b\bin\win32
,(我的matlab安装在
D:\Program Files\MATLAB\
,如果不是这个路径则做相应修改,64bit系统路径最后则为win64,下同)

vs设置,工具 -> 选项 -> 项目和解决方案 -> VC++ 路径,Platform选择Win32,然后

Include files中添加
D:\Program Files\MATLAB\R2013b\extern\include


Library files中添加
D:\Program Files\MATLAB\R2013b\extern\lib\win32\microsoft


注意高版本的VS如2013已经将该设置迁移到项目属性中。

附加依赖项设置,项目属性 -> 配置属性 -> 链接器 -> 输入 -> 附加依赖项,编辑加入
libeng.lib
。(也可直接在代码中加入
#pragma comment(lib, "libeng.lib")
语句)

关于以上路径设置的说明

环境变量Path:指定系统搜索路径(此处用于查找
libeng.dll
等dll文件),也可不设置而是将该路径下所有用到的dll文件拷贝到当前路径中

头文件路径:指定头文件的搜索路径(此处为
engine.h
文件以及该文件中包含的其他头文件),也可不设置,但包含头文件时需要使用完整路径,这样头文件较多时会比较麻烦

库文件路径:指定库文件的搜索路径(此处为
libeng.lib
文件),可以不设置,但
#pragma comment
时需要使用lib文件的完整路径,或者将该文件拷贝到当前路径下

2 引擎函数介绍

下表列出了本文用到的所有引擎函数

函数说明
engOpen启动matlab计算引擎(创建了一个matlab进程并建立联系)
engClose关闭引擎(关闭创建的matlab进程)
engSetVisible设置引擎窗口是否可见
engOutputBuffer设置引擎文本输出缓冲区(每次使用
engEvalString
执行新命令都会使缓冲区清空并填入新的结果),执行代码
engOutputBuffer(ep, NULL, 0)
可停用缓冲区
engEvalString执行matlab命令
engOpen

[函数原型]
Engine* engOpen(const char* startcmd)


[参数说明] 用于启动matlab的字符串命令,Windows中为
NULL


[返回值] 引擎指针

engClose

[函数原型]
int engClose(Engine* ep)


[参数说明] 引擎指针,即
engClose
函数的返回值

[返回值] 0成功,1失败

engSetVisible

[函数原型]
int engSetVisible(Engine* ep, bool newVal)


[参数说明]
ep
为引擎指针;
newVal
true
表示显示引擎窗口,
false
表示隐藏引擎窗口

[返回值] 0成功,1失败

engOutputBuffer

[函数原型]
int engOutputBuffer(Engine* ep, char* buffer, int buflen)


[参数说明]
ep
为引擎指针;
buffer
为文本输出缓冲区指针;
buflen
为缓冲区大小

[返回值] 0成功,1失败

engEvalString

[函数原型]
int engEvalString(Engine* ep, const char* string)


[参数说明]
ep
为引擎指针;
string
为要执行的命令文本

[返回值] 0成功,1失败

3 引擎使用

包括打开与设置引擎、执行命令、关闭引擎三个部分

打开引擎并设置。包括打开引擎、设置不可见、设置输出缓冲区以及设置工作空间为当前路径,代码如下

// 打开并设置Matlab引擎
int MatlabOpen(Engine** ep, const char* sPath, char* sBuffer, int nBufLen)
{
// 启动matlab引擎
if (!(*ep = engOpen(NULL))) // 启动引擎
{
return 1;   // 启动失败
}
// 设置
engSetVisible(*ep, false);      // 设置窗口不可视
engOutputBuffer(*ep, sBuffer, nBufLen); // 设置Matlab输出缓冲区
// 修改工作路径
char sWorkPath[MAX_PATH];
sprintf_s(sWorkPath, MAX_PATH, "cd '%s'", sPath);
engEvalString(*ep, sWorkPath);
return 0;
}


关闭引擎。代码如下

// 关闭Matlab引擎
int MatlabClose(Engine* ep)
{
return engClose(ep);
}


执行命令。执行命令获取文本结果,如果有画图命令则将Figure保存为图片

// 执行Matlab命令
// 返回图片个数
int MatlabExec(Engine* ep, const char* mCmd)
{
int nFig = 0;   // 图片个数
engOutputBuffer(ep, matbuf, MATBUFSIZE);    // 恢复输出缓冲区
engEvalString(ep, mCmd);    // 执行命令
engOutputBuffer(ep, matbuffig, MATBUFFIGSIZE);  // 临时缓冲区,保存检测是否有Figure的结果
// 判断是否有figure并处理
engEvalString(ep, "isempty(findall(0,'Type','Figure'))");
if (strlen(matbuffig) > 13 && '0' == matbuffig[13]) // 有Figure
{
char savefig[100] = {0};
char gettype[20] = {0};
int i = 1;
sprintf_s(gettype, 20, "get(1,'Type');");
engEvalString(ep, gettype);
while(matbuffig[0] == 0)    // 空
{
// 将Figure保存为图片
sprintf_s(savefig, 100, "set(%d,'color','white');f=getframe(%d);imwrite(f.cdata,'figure%d.png');", i, i, i);
engEvalString(ep, savefig);
nFig++;
// 下一个
sprintf_s(gettype, 20, "get(%d,'Type');", ++i);
engEvalString(ep, gettype);
}
engEvalString(ep, "close all"); // 关闭所有Figure
}
return nFig;    // 返回图片个数
}


4 示例

由于关于Matlab计算引擎的操作都要在同一个线程内执行,而项目需要在其他多个线程中执行matlab命令,因此考虑采用线程消息的方式实现。即在主线程中启用计算引擎,其他线程通过向主线程发送消息来请求计算,命令通过消息参数传递。完整代码如下

#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include "engine.h"

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

#define WM_CALC WM_USER+200   // 请求计算消息

// 全局变量
#define MATBUFSIZE 10240
#define MATBUFFIGSIZE 256
char matbuf[MATBUFSIZE] = {0};          // Matlab输出缓冲区
char matbuffig[MATBUFFIGSIZE] = {0};    // 临时输出缓冲区
DWORD dwMainThreadId = 0;               // 主线程ID

// 函数声明
DWORD WINAPI ThreadTest(LPVOID lpParam);    // 测试线程
int MatlabOpen(Engine** ep, const char* sPath, char* sBuffer, int nBufLen);
int MatlabClose(Engine* ep);
int MatlabExec(Engine* ep, const char* mCmd);

int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
// 获取线程ID
dwMainThreadId = GetCurrentThreadId();

// 启动matlab引擎
Engine* ep = NULL;          // matlab引擎
char path[MAX_PATH];        // 当前路径
strcpy_s(path, MAX_PATH, __argv[0]);
(_tcsrchr(path, '\\'))[1] = 0;  // 只保留路径部分
if (MatlabOpen(&ep, path, matbuf, MATBUFSIZE))
{
return 0;
}

// 创建测试线程
CreateThread(NULL, 0, ThreadTest, 0, 0, NULL);

// 线程消息循环
MSG msg;
PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
while(GetMessage(&msg, NULL, 0, 0))
{
if (msg.message == WM_CALC) // 请求计算消息
{
MatlabExec(ep, (char*)msg.wParam);  // 执行matlab命令
}
}

// 关闭matlab引擎
MatlabClose(ep);

return (int) msg.wParam;
}

// 测试线程
DWORD WINAPI ThreadTest(LPVOID lpParam)
{
Sleep(1000);
PostThreadMessage(dwMainThreadId, WM_CALC, WPARAM("pi"), 0);    // 输出pi
Sleep(1000);
PostThreadMessage(dwMainThreadId, WM_CALC, WPARAM("plot(sin(0:0.1:10))"), 0);   // 画正弦曲线
Sleep(5000);
PostThreadMessage(dwMainThreadId, WM_QUIT, 0, 0);   // 退出程序
return 0;
}

// MatlabOpen、MatlabClose、MatlabExec三个函数的实现分别见3.1、3.2、3.3,此处不再列出
// ……


测试结果:

第一次计算后matbuf值为
"ans =  3.1416"


exe路径下生成文件
figure1.png
,如下图



本文原文链接 /article/10927863.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: