VC中調用matlab函數

VC中調用matlab函數

Visual C++是當前主流的應用程序開發環境之一,開發環境強大,開發的程序執行速度快。但在科學計算方面函數庫顯得不夠豐富、讀取、顯示數據圖形不方便。Matlab是一款將數值分析、矩陣計算、信號處理和圖形顯示結合在一起,包含大量高度集成的函數可供調用,適合科學研究、工程設計等衆多學科領域使用的一種簡潔、高效的編程工具。不過由於Matlab使用的是解釋性語言,大大限制了它的執行速度和應用場合。基於VC和Matlab混合編程是很多熟悉VC++編程而又需要進行科學計算、數據仿真的科研人員常用的一種方式,其中最簡單也最直接的方法就是調用Matlab引擎。本文以下部分將詳細介紹通過VC++6.0調用Matlab6.5引擎來達到VC++與Matlab數據共享編程的方法。

  1. 什麼是Matlab引擎

  所謂Matlab引擎(engine),是指一組Matlab提供的接口函數,支持C/C++、Fortran等語言,通過這些接口函數,用戶可以在其它編程環境中實現對Matlab的控制。可以主要功能有:

  ★ 打開/關閉一個Matlab對話;

  ★ 向Matlab環境發送命令字符串;

  ★ 從Matlab環境中讀取數據;

  ★ 向Matlab環境中寫入數據。

  與其它各種接口相比,引擎所提供的Matlab功能支持是最全面的。通過引擎方式,應用程序會打開一個新的Matlab進程,可以控制它完成任何計算和繪圖操作。對所有的數據結構提供100%的支持。同時,引擎方式打開的Matlab進程會在任務欄顯示自己的圖標,打開該窗口,可以觀察主程序通過engine方式控制Matlab運行的流程,並可在其中輸入任何Matlab命令。

  實際上,通過引擎方式建立的對話,是將Matlab以ActiveX控件方式啓動的。在Matlab初次安裝時,會自動執行一次:

matlab /regserver

  將自己在系統的控件庫中註冊。如果因爲特殊原因,無法打開Matlab引擎,可以在Dos命令提示符後執行上述命令,重新註冊。

  2. 配置編譯器

  要在VC中成功編譯Matlab引擎程序,必須包含引擎頭文件engine.h並引入Matlab對應的庫文件libmx.lib、libmat.lib、libeng.lib。具體的說,打開一個工程後,做如下設置(以VC6爲例):

  1) 通過菜單工程/選項,打開設置屬性頁,進入Directories頁面,在目錄下拉列表框中選擇Include files,添加路徑:"C:/matlab/extern/include"(假定matlab安裝在C:/matlab目錄)。

  2) 選擇Library files,添加路徑:C:/matlab/extern/lib/win32/microsoft/msvc60。

  3) 通過菜單工程/設置,打開工程設置屬性頁,進入Link頁面,在Object/library modules編輯框中,添加文件名libmx.lib libmat.lib libeng.lib。

  以上步驟1)、2)只需設置一次,而步驟3)對每個工程都要單獨設定,對於其它C++編譯器如Borland C++ Builder,設置大體相同,不再贅述。

  3. 引擎API詳解

  在調用Matlab引擎之前,首先應在相關文件中加入一行:#include "enging.h",該文件包含了引擎API函數的說明和所需數據結構的定義。可以在VC中調用的引擎函數分別如下:

  3.1 引擎的打開和關閉

  engOpen-打開Matlab engine

  函數聲明:

Engine *engOpen(const char *startcmd);

  參數startcmd是用來啓動Matlab引擎的字符串參數,在Windows操作系統中只能爲NULL。

  函數返回值是一個Engine類型的指針,它是在engine.h中定義的engine數據結構。

  EngClose-關閉Matlab 引擎

  函數聲明:

int engClose(Engine *ep);

  參數ep代表要被關閉的引擎指針。

  函數返回值爲0表示關閉成功,返回1表示發生錯誤。

  例如,通常用來打開/關閉Matlab引擎的代碼如下:

Engine *ep; //定義Matlab引擎指針。
if (!(ep=engOpen(NULL))) //測試是否啓動Matlab引擎成功。
{
MessageBox("Can't start Matlab engine!" );
exit(1);
}
. …………
engClose(ep); //關閉Matlab引擎。

  3.2 向Matlab發送命令字符串

  engEvalString-發送命令讓Matlab執行。

  函數聲明:

int engEvalString(Engine *ep, Const char *string);

  參數ep爲函數engOpen返回的引擎指針,字符串string爲要matlab執行的命令。

  函數返回值爲0表示成功執行,返回1說明執行失敗(如命令不能被Matlab正確解釋或Matlab引擎已經關閉了)。

  3.3 獲取Matlab命令窗口的輸出

  要在VC中獲得函數engEvalString發送的命令字符串被Matlab執行後在matlab窗口中的輸出,可以調用engOUtputBuffer函數。

  函數聲明:

int engOutputBuffer(Engine *ep, char *p, int n);

  參數ep爲Matlab引擎指針,p爲用來保存輸出結構的緩衝區,n爲最大保存的字符個數,通常就是緩衝區p的大小。該函數執行後,接下來的engEvalString函數所引起的命令行輸出結果會在緩衝區p中保存。如果要停止保存,只需調用代碼:engOutputBuffer(ep, NULL, 0)。

  3.4 讀寫Matlab數據

  3.4.1從Matlab引擎工作空間中獲取變量。

mxArray *engGetVariable(Engine *ep, const char *name);

  參數ep爲打開的Matlab引擎指針,name爲以字符串形式指定的數組名。

  函數返回值是指向name數組的指針,類型爲mxArray*(mxArray數據類型在本文第4節詳細簡介)。

  3.4.2 向Matlab引擎工作空間寫入變量。

int engPutVariable(Engine *ep, const char *name, const mxArray *mp);

  參數ep爲打開的Matlab引擎指針,mp爲指向被寫入變量的指針,name爲變量寫入後在Matlab引擎工作空間中的變量名。
函數返回值爲0表示寫入變量成功,返回值爲1表示發生錯誤。

  3.5 調用引擎時顯示/隱藏Matlab主窗口

  默認情況下,以engine方式調用Matlab的時候,會打開Matlab主窗口,可在其中隨意操作。但有時也會干擾應用程序的運行,可用以下設置是否顯示該窗口。

int engSetVisible(Engine *ep, bool value);

  參數ep爲打開的Matlab引擎指針,value爲是否顯示的標誌,取值true(或1)表示顯示Matlab窗口,取值false(或0)表示隱藏Matlab窗口。

  函數返回值爲0表示設置成功,爲1表示有錯誤發生。

  要獲得當前Matlab窗口的顯示/隱藏情況,可以調用函數:

int engGetVisible(Engine *ep, bool *value);

  參數ep爲打開的Matlab引擎指針,Value爲用來保存顯示/隱藏情況的變量(採用指針方式傳遞)。

  函數返回值爲0表示獲取成功,爲1表示有錯誤發生。
4. 數據類型mxArray的操作

  在上節的Matlab引擎函數中,所有與變量有關的數據類型都是mxArray類型。數據結構mxArray以及大量的mx開頭的函數,廣泛用於Matlab 引擎程序和Matlab C數學庫中。mxArray是一種很複雜的數據結構,與Matlab中的array相對應,我們只需熟悉Matlab的array類型和幾個常用的mxArray函數即可。

  在VC中,所有和Matlab的數據交互都是通過mxArray來實現的,在使用mxArray類型的程序中,應包含頭文件matrix.h,不過在引擎程序中,一般會包含頭文件engine.h,該文件裏面已經包含了matrix.h,因此無需重複包含。

  4.1 創建和清除mxArray型數據

  Matlab有很多種變量類型,對應於每種類型,基本上都有一個函數用於創建,但它們都有相同的數據結構,就是mxArray。

  數組的建立採用mxCreatexxx形式的函數,例如新建一個double類型數組,可用函數mxCreateDoubleMatrix,函數形式如下:

mxArray *mxCreateDoubleMatrix(int m, int n, mxComplexity ComplexFlag);

  參數m和n爲矩陣的函數和列數。ComplexFlag爲常數,用來區分矩陣中元素是實數還是複數,取值分別爲mxREAL和mxCOMPLEX。

  例如,創建一個3行5列的二維實數數組,可用如下語句:

mxArray *T = mxCreateDoubleMatrix(3, 5, mxREAL);

  對應的,要刪除一個數組mxDestroyArray,該函數聲明如下:

void mxDestroyArray(mxArray *array_ptr);

  參數array_ptr爲要刪除的數組指針。

  例如,要刪除上面創建的數組T,可用如下語句:

mxDestroyArray(T);

  類似的創建函數還有:

mxArray *mxCreateString(const char *str);

  創建一個字符串類型並初始化爲str字符串。

  一般的在VC與Matlab交互中,以上兩種類型就夠了,其它類型數組的創建這裏不再介紹。

  4.2 管理mxArray數據類型

  4.2.1 管理mxArray數據大小

  要獲得mxArray數組每一維上元素的個數,可以用mxGetM和mxGetN函數。其中mxGetM用來獲得數組第一維的元素個數,對於矩陣來說就是行數。

int mxGetM(const mxArray *array_ptr); //返回array_ptr對應數組第一維的元素個數(行數)
int mxGetN(const mxArray *array_ptr); //返回array_ptr對應數組其它維的元素個數,對於矩陣來說是列數。對於多維數組來說是從第2維到最後一維的各維元素個數的乘積。

  要獲得某一特定維的元素個數,則要用函數:

const int *mxGetDimensions(const mxArray *array_ptr);

  該函數返回array_ptr各維的元素個數保存在一個int數組中返回。對於常用的矩陣來說,用mxGetM和mxGetN兩個函數就可以了。

  另外還可以通過mxGetNumberOfDimensions來獲得數組的總的維數,用mxSetM、mxSetN設置矩陣的行數和列數,函數說明如下:


mxGetNumberOfDimensions(const mxArray *array_ptr); //返回數組的維數
void mxSetM(mxArray *array_ptr, int m); //設置數組爲m行
void mxSetN(mxArray *array_ptr, int n); //設置數組爲n列


  4.2.2 判斷mxArray數組類型

  在對mxArray類型的變量進行操作之前,可以驗證以下其中的數組的數據類型,比如是否爲double數組、整數、字符串、邏輯值等,以及是否爲某種結構、類、或者是特殊類型,比如是否爲空數組,是否爲inf、NaN等。常見的判斷函數有:

bool mxIsDouble(const mxArray *array_ptr);
bool mxIsComplex(const mxArray *array_ptr);
bool mxIsChar(const mxArray *array_ptr);
bool mxIsEmpty(const mxArray *array_ptr);
bool mxIsInf(double value);
…… ……

 

  這些函數比較簡單,意義自明,不再解釋。

  4.2.3 管理mxArray數組的數據

  對於常用的double類型的數組,可以用mxGetPr和mxGetPi兩個函數分別獲得其實部和虛部的數據指針,這兩個函數的聲明如下:

double *mxGetPr(const mxArray *array_ptr); //返回數組array_ptr的實部指針
double *mxGetPi(const mxArray *array_ptr); //返回數組array_ptr的虛部指針

 

  這樣,就可以通過獲得的指針對mxArray類型的數組中的數據進行讀寫操作。例如可以用函數engGetVariable從Matlab工作空間讀入mxArray類型的數組,然後用mxGetPr和mxGetPi獲得數據指針,對並其中的數據進行處理,最後調用engPutVariable函數將修改後的數組重新寫入到Matlab工作空間。具體實現見第5節程序實例。

5. 程序實例

  對大部分軟件研發人員來說利用VC編程方便、高效,但是要顯示數據圖形就不那麼容易了,這時候不防藉助Matlab引擎輔助畫圖做數據分析。下面通過實例演示如何利用VC調用Matlab繪圖,程序的主要功能是在VC中對數組x計算函數值y=sin(x) ±log(x),然後調用Matlab繪製y對x的圖形。

  在VC中新建工程,編寫代碼如下:

#include <iostream>
#include <math.h>
#include "engine.h"
using namespace std;
void main()
{
 const int N = 50;
 double x[N],y[N];
 int j = 1;
 for (int i=0; i<N; i++) //計算數組x和y
 {
  x[i] = (i+1);
  y[i] = sin(x[i]) + j * log(x[i]); //產生-之間的隨機數賦給xx[i];
  j *= -1;
 }
 Engine *ep; //定義Matlab引擎指針。
 if (!(ep=engOpen(NULL))) //測試是否啓動Matlab引擎成功。
 {
  cout <<"Can't start Matlab engine!" <<endl;
  exit(1);
 }

 //定義mxArray,爲行,N列的實數數組。
 mxArray *xx = mxCreateDoubleMatrix(1,N, mxREAL);
 mxArray *yy = mxCreateDoubleMatrix(1,N, mxREAL); //同上。

 memcpy(mxGetPr(xx), x, N*sizeof(double)); //將數組x複製到mxarray數組xx中。
 memcpy(mxGetPr(yy), y, N*sizeof(double)); //將數組x複製到mxarray數組yy中。

 engPutVariable(ep, "xx",xx); //將mxArray數組xx寫入到Matlab工作空間,命名爲xx。
 engPutVariable(ep, "yy",yy); //將mxArray數組yy寫入到Matlab工作空間,命名爲yy。

 //向Matlab引擎發送畫圖命令。plot爲Matlab的畫圖函數,參見Matlab相關文檔。
 engEvalString(ep, "plot(xx, yy); ");

 mxDestroyArray(xx); //銷燬mxArray數組xx和yy。
 mxDestroyArray(yy);

 cout <<"Press any key to exit!" <<endl;
 cin.get();
 engClose(ep); //關閉Matlab引擎。
}


6. 小結

  本文詳細的介紹了Matlab引擎使用方法並演示了一個簡單的利用VC調用Matlab畫圖的程序實例。大多數時候,程序員可以利用Matlab強大的數據讀寫、顯示能力和VC編程的高效率。例如,在Matlab中要讀入一幅任意格式的圖像均只需一條命令i=imread('test.jp');圖像數據矩陣便存放在了二維數組i中,可以通過VC讀入該數組進行相關處理再調用Matlab顯示,這種混合編程方式能大大提高工作效率。

  當然,利用VC編譯的Matlab引擎程序,運行環境中還必須Matlab的支持,如果要編譯完全脫離Matlab的程序,可採用其它方式,如利用第三方Matcom程序編譯獨立的可執行程序等

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章