VC++和Matlab(轉(zhuǎn))MATLAB 2007-11-27 14:41:11 閱讀896 評論0 字號:大中小 引用:http://www./detail.asp?hw_id=2630 一、前言 Matlab是由Mathworks公司推出的一種應(yīng)用軟件,,最早用于線性代數(shù)的教學(xué),,由于其豐富的矩陣運算,,強大的擴(kuò)展能力和可靠性,,已經(jīng)被廣泛用于信號處理,,系統(tǒng)辨識,仿真,,多變量控制,,最優(yōu)控制,模糊控制,,數(shù)學(xué)工具,,神經(jīng)網(wǎng)絡(luò),它的工具箱內(nèi)容涉及信號處理,,自動控制,圖像處理,,經(jīng)濟(jì),,數(shù)學(xué),化學(xué)等不同領(lǐng)域,。同時,,MathWorks公司從創(chuàng)立至今始終追蹤各領(lǐng)域的最新進(jìn)展,這無疑是最明智,,最富遠(yuǎn)見的舉措,。對廣大用戶來說,無疑提供了成功的機會,。對于各種理論方案研究來說,,Matlab無疑有它的先天優(yōu)勢,,其強大的數(shù)據(jù)處理能力和豐富的工具箱,,使得它的編程極為簡單,,可以極大地縮短應(yīng)用程序開發(fā)周期,提高編程效率和縮短理論方案研制周期,。 總之,,對于純理論方案來說,Matlab語言是優(yōu)勢多多,。但由于Matlab是為了方便用戶而編制的,,采用的是類似Basic一樣解釋型機制的語言。所以Matlab語言執(zhí)行效率很低,,只有C語言的十分之一,,對于對實時性或速度要求較高的場合來說,Matlab就不太適應(yīng)了,。Matlab是一種高級語言,,對底層硬件的控制能力很差,所以對于半實物仿真和偏工程化的產(chǎn)品來說,,Matlab并不是一個很好的語言,。對于發(fā)布軟件公司來說,也希望發(fā)布的是一個可執(zhí)行應(yīng)用軟件,,而不是一個只是Matlab原代碼的產(chǎn)品,。 所以把Matlab語言轉(zhuǎn)換成可執(zhí)行文件,具有較強的工程實用價值,。Microsoft的Visual C++面世以來就受到了風(fēng)靡全球,,其強大硬件控制能力和系統(tǒng)集成功能使無數(shù)程序員對它一見傾心。Matlab在它的5.1 版本后,,就逐漸增加了對C的支持,,本文就對此問題作一簡單探討,歡迎大家批評指正,。 二,、Matlab與C語言混合編程方法簡介。 Matlab與C語言混合編程有四種方法 A.采用Matlab與C的接口規(guī)范來編程,。 Matlab與C語言的接口采用稱為MEX的動態(tài)鏈接庫方式進(jìn)行,。按MEX接口規(guī)范編寫的C原程序經(jīng)過編譯可生成Matlab動態(tài)鏈接子程序,它十分類似于Matlab的內(nèi)建函數(shù),,可有Matlab直接調(diào)用,。采用此規(guī)范可實現(xiàn)對Matlab原代碼的加密,。 B.用Matlab引擎來編程 Matlab引擎采用的是客戶機/服務(wù)器(Client/Server)的計算方式,。所謂客戶機/服務(wù)器計算,就是把應(yīng)用處理負(fù)載分布到客戶機和服務(wù)器上的工作模式,??蛻魴C與服務(wù)器即可以存在于同一臺計算機,,也可以通過網(wǎng)絡(luò)共享信息。一般情況下,,客戶機是運行軟件的前端PC機,,并且知道如何與服務(wù)器通訊;服務(wù)器于此對應(yīng),,是接受信息,,并采用相應(yīng)行動的機器。由于客戶機于服務(wù)器共同承擔(dān)處理負(fù)載,,可使系統(tǒng)性能得到極大提高,。在一個實際應(yīng)用中,可用VC活其它C,C++語言作為前端客戶機,,它向Matlab引擎發(fā)送命令和數(shù)據(jù)信息,,可從Matlab引擎獲得計算結(jié)果。 C. 用Matlab下的.m文件轉(zhuǎn)化為VC可調(diào)用動態(tài)鏈接庫(DLL),。 下面詳述 D.直接用C編程,,通過對Matlab的數(shù)學(xué)庫函數(shù)的調(diào)用實現(xiàn)Matlab語言的一般功能。 下面詳述 由于采用方法A和方法B都脫離不了Matlab 運行環(huán)境,,這里不作詳細(xì)介紹,,下文主要介紹方法C和方法D。 三,、 如何把Matlab下的.m文件轉(zhuǎn)化為VC 可調(diào)用的動態(tài)鏈接庫 3.1VC下的DLL簡介 在軟件的開發(fā)過程中,,DLL已成為常見的編程單元。DLL雖然是可執(zhí)行文件,,但它不能獨立運行,,只能被其它應(yīng)用程序調(diào)用。在VC6.0中,,MFC支持三種新式DLL a.通常形式的靜態(tài)DLL b.通常形式的動態(tài)MFC的DLL c.擴(kuò)展DLL(動態(tài)鏈接MFC) 本文采用通常形式的靜態(tài)DLL開發(fā)和使用DLL應(yīng)注意以下幾點,。 a.DLL頭文件(.H)DLL頭文件是指DLL中說明輸出的類和符號(Symbols),如函數(shù)原型和數(shù)據(jù)結(jié)構(gòu)的.H文件,。一方面,,它是類和符號原型說明文件,另一方面,,當(dāng)在其它應(yīng)用程序中調(diào)用DLL時,,要將該文件包含應(yīng)用程序中的源文件中。 b.DLL的引入庫文件(.LIB)引入庫文件是DLL在編譯,,鏈接成功后的生成的文件,。它的主要作用是:當(dāng)其它應(yīng)用程序編譯調(diào)用DLL時,要將該文件引入應(yīng)用程序。 c.DLL文件(.DLL)DLL是應(yīng)用程序調(diào)用DLL運行時,,真正可執(zhí)行的代碼文件,。 在開發(fā)一個DLL 應(yīng)用程序時,要用到這三個文件,。 3.2 Matlab下的Mcc簡介 MCC同樣是Mathworks公司出品的一種應(yīng)用軟件,。可在/matlab/bin 下找到它,,它的作用是把.m文件轉(zhuǎn)換成C/C++文件器,。Mcc(版本2.0)用法格式是Mcc [ -選項 ] fun [fun2 …],如果指定的fun是.m文件,,則每個文件都會被轉(zhuǎn)換成C/C++文件,,如指定fun的是.c文件,這些c和相關(guān)的c文件將被傳遞給mex和mbuild 程序編譯,。Mcc的用法很復(fù)雜,,具體使用可參見MCC2.0 Online Help. 3.3用.m文件創(chuàng)建一個VC可調(diào)用的DLL文件示例 3.31編輯一個子調(diào)用的.m文件 基于說明問題起見,用Matlab的edit編了一個簡單的myfunc.m文件,, 程序如下圖所示:
fuction y=myfunct(x,b)定義一子調(diào)用,程序中 其中x為輸入變量,,b為控制選項,b=1時以角度值輸入,,b=其它時,, 以弧度值輸入,程序通過插值方法求得x的正弦值返回給y,。 3.32Matlab編譯前的準(zhǔn)備工作,。 a. 對Matlab編譯環(huán)境進(jìn)行設(shè)置 在Matlab環(huán)境中運行mex -setup,按屏幕提示要求選擇編譯器類型,,位置等有關(guān)信息,。如下圖所示:
b.在Matlab環(huán)境中運行mbuild -setup,設(shè)置方法與上面基本相同,, 這兒就不詳述了,,mcc和mbuild的設(shè)置結(jié)果分別保存在mexopts.bat和compopts.bat文件中。 3.33 用mcc將myfunc.m轉(zhuǎn)換為matlab可調(diào)用的DLL 在Matlab環(huán)境中運行mcc -t -h -L C -W lib:ppp -T link:lib myfunc.m 下面分別介紹各選項的意義 -t 把M代碼轉(zhuǎn)換成目標(biāo)語言,。 -h 把輔助編譯器選項打開,,打開此選項意味著可以鏈入除Matlab已有的函數(shù)外,還可以鏈入作者自編的子函數(shù),。 -W lib:ppp 表示生成DLL所需的ppp.h ppp.lib ppp.dll -T link:lib 表示編譯生成的目標(biāo)(Target)文件類型為DLL 編譯完成后,,將生成如下一些文件 ppp.exp ppp.lib myfunc.c ppp.c ppp.exports myfunc.h ppp.dll ppp.h, 其中有用的文件有三個,分別是ppp.h,ppp.lib,ppp.dll,, 它們將會被添加到VC程序中去,。 3.34 用MFC編譯一個VC++6.0可執(zhí)行文件 1.由于dll不能獨立運行,,所以要用VC6.0創(chuàng)建一個EXE可執(zhí)行程序。 在VC6.0中創(chuàng)建一個基于對話框的MFC工程,,名為mytest,具體過程參見一般的VC教程,。在本例中mytest工程路徑為e:\mat2c\mytest 2.對VC編程環(huán)境進(jìn)行設(shè)置,。選擇VC編譯器主菜單下Tools->options-> directories,選擇Show Directories for列表框,分別把Matlab的包含文件路徑(如c:\matlab\ertern\include),,庫文件(如C:\matlab\extern\lib)路徑添加到VC路徑中去,。 3.把ppp.h,ppp.lib,,ppp.dll三個復(fù)制到e:\mat2c\mytest目錄下,,以便Vc調(diào)用DLL時能找到這三個文件。 對對話框IDD_MYTEST_DIALOG資源進(jìn)行編輯,,如下圖所示
“ 請輸入數(shù)值“,,”輸出正弦值“為兩個靜態(tài)文本框,兩個Edit為編輯框,,分別用來接受輸入數(shù)值和輸出數(shù)值,。對應(yīng)的變量為雙精度類型的m_din, 和m_dout.。角度“,,”弧度“選項表示輸入數(shù)值單位制,對應(yīng)的變量為m_select,。“計算“按鈕則啟動計算功能,定義它的ID為ID_ON_ON_CALCULATE,,相應(yīng)的消息處理函數(shù)為OnOnCalculate(),; 要使VC能調(diào)用DLL,還必須對VC進(jìn)行以下操作。 (1)引入頭文件和庫文件 在mytestdlg.cpp的頭部加入一行:#include “ppp.h”在project>settings->link下的object/libray modules下加入ppp.lib libmx.lib libmat.lib libmatlb.lib libmmfile.lib 目的是讓VC能調(diào)用ppp.dll,,引入libmx.lib libmat.lib libmatlb.lib 和libmmfile.lib的 目的是讓VC能調(diào)用matlab的數(shù)學(xué)庫函數(shù)和一些功能性函數(shù)編譯VC與matlab的代碼接口,,和作者直接用C寫的一些代碼。 (2)對ppp.h做一點改動,。 在#include “matlab.h”語句之后,,加入-行extern “C”{,在最后一行#endif之前加入一行},。改動后的ppp.h文件內(nèi)容如下: #ifndef MLF_V2 #define MLF_V2 1 #endif
#ifndef __ppp_h #define __ppp_h 1
#include "matlab.h" extern "C" { extern mxArray * mlfMyfunc(mxArray * x, mxArray * b); extern void mlxMyfunc(int nlhs, mxArray * plhs[], int nrhs, mxArray * prhs[]); extern void pppInitialize(void); extern void pppTerminate(void); } #endif,。
(3)對VC與Matlab接口進(jìn)行編程 對“計算”按鈕消息處理函數(shù)編程如下 void CMytestDlg::OnOnCalculate() { // TODO: Add your control notification handler code here UpdateData(TRUE); pppInitialize(); static double a[1] = { 0.0 }; static double b[1]= { 0.0 }; a[0]=m_din; b[0]=m_select+1; mxArray * A = mclGetUninitializedArray(); mxArray * B = mclGetUninitializedArray(); mxArray * C = mclGetUninitializedArray(); mlfAssign(&A, mlfDoubleMatrix(1, 1, a, NULL)); mlfAssign(&B, mlfDoubleMatrix(1, 1, b, NULL)); mlfAssign(&C, mlfMyfunc(A, B)); double * md=mxGetPr(C); m_dout=md[0]; mxDestroyArray(A); mxDestroyArray(B); mxDestroyArray(C); pppTerminate(); UpdateData(FALSE); } 為了使讀者有一個更深入的了解。對以上關(guān)鍵性代碼加以說明,。UpdateData(TRUE)表示從屏幕接收數(shù)據(jù),,a[0]=m_din;表示a[0]存放m_din,即輸入的待計算數(shù)值, b[0]=m_select+1;表示 b[0] “角度“,,”弧度“的選擇值,。 由于Matlab的計算基本單位是矩陣,而VC支持的基本數(shù)據(jù)類型是int,double等,所以要編寫Matlab與vc之間的接口代碼,。如本例中C=myfunc(A,B)的函數(shù),,它編譯成動態(tài)鏈接庫后C形式代碼為mlfAssign(&C, mlfMyfunc(A, B))。 要使Vc能調(diào)用它,,必須首先創(chuàng)建三個mxArray *型指針變量 mxArray * A, mxArray * B, mxArray *C指向A,B,C矩陣(mxArray * A = mclGetUninitializedArray(); mxArray *B= ……),,由于A,B是輸入變量,故使用 mlfAssign(&A, mlfDoubleMatrix(1, 1, a, NULL)),,mlfAssign(&B, mlfDoubleMatrix(1, 1, b, NULL))語句使得A,B矩陣中的元素與 double a[1],,static double b[1]內(nèi)容保持相同。 再使用mlfAssign(&C, mlfMyfunc(A, B))語句調(diào)用ppp.dll中的mlfMyfunc函數(shù)計算并返回結(jié)果到C中. double * md=mxGetPr(C)語句作用是取得返回doulbe *指針,,這樣m_dout=md[0]使得m_dout取得的內(nèi)容就是C矩陣中的第一個元素(即在Matlab語言中為C(1) 的元素,,在C/C++語言中,0指示的是數(shù)組的第一個元素). 這樣一個DLL 調(diào)用就完成了,,最終通過UpdateData(FALSE)語句把運算結(jié)果顯示出來了,。 以上程序中的某些函數(shù)用法中參見Matlab中的C Math幫助文件。 (4)作完以上工作后,,DLL就已被成功鏈入VC,,再經(jīng)VC編譯器編譯鏈接即可生成可執(zhí)行文件,運行程序,,在對話框中輸入60,,選擇角度選項, 按計算按鈕即可得到結(jié)果,。
4.直接用C編程 直接用C編程也是可以的,,它是通過對Matlab的數(shù)學(xué)庫函數(shù)的調(diào)用來 實現(xiàn)的,如果能用Matlab實現(xiàn)的語句,,就用不著非得用C直接編程因為直接用C編程與把.m文件通過mcc轉(zhuǎn)換成的C代碼是一樣的的如要實現(xiàn)Matlab中的以下三行功能: A=[1 2 3 4]; B=[4 3 2 1]; C=A+B; 自己直接用C要這樣寫 static double a[4] = { 1.0, 2.0, 3.0, 4.0 }; static double b[4] = { 4.0, 3.0, 2.0, 1.0 }; mxArray * A = mclGetUninitializedArray(); mxArray * B = mclGetUninitializedArray(); mxArray * C = mclGetUninitializedArray(); mlfAssign(&A, mlfDoubleMatrix(1, 4, a,, NULL)); mlfAssign(&B, mlfDoubleMatrix(1, 4, b, NULL)); mlfAssign(&C, mlfPlus(A, B)); 而如果用mcc把上面三行轉(zhuǎn)化為C代碼以后為: static double __Array0_r[4] = { 1.0, 2.0, 3.0, 4.0 }; static double __Array1_r[4] = { 4.0, 3.0, 2.0, 1.0 }; mxArray * A = mclGetUninitializedArray(); mxArray * B = mclGetUninitializedArray(); mxArray * C = mclGetUninitializedArray(); mlfAssign(&A, mlfDoubleMatrix(1, 4, __Array0_r, NULL)); mlfAssign(&B, mlfDoubleMatrix(1, 4, __Array1_r, NULL)); mlfAssign(&C, mlfPlus(A, B)); 它們實質(zhì)上是一樣的,直接用C編程不如先寫.m代碼,,再用mcc工具轉(zhuǎn)換,。 對Matlab與VC編譯器環(huán)境的配置工作與上面第3節(jié)介紹的一樣。 注意:libmx.lib libmatlb.lib libmmfile.lib libmat.lib 文件并不是Matlab自帶的,,Matlab只提供了libmx.dll libmatlb.dll libmmfile.dll libmat.dll 用戶需要自己編譯,,在VC有兩種方式實現(xiàn)(推薦方式(2)) (1)VC集成編譯環(huán)境中打開 matlab\extern\examples\cppmath\msvc 下的工程文件msvc42.mak,選project->settings->C/C++->code generation 為Debug Multithread Dll選項,,Build即可,。 (2)把VC的bin目錄下的vcvars32.bat拷貝的C盤根目錄下運行msconfig將vcars32.bat添加的Auoexec.bat中去。 重新啟動計算機,。 回到MS_DOS方式下在matlab\extern\include運行 lib /def:libmat.def /machine:ix86 /out:libeng.lib lib /def:libmatlb.def /machine:ix86 /out:libmatlab.lib lib /def:libmmfile.def /machine:ix86 /out:libmmfile.lib lib /def:libmx.def /machine:ix86 /out:libmx.lib
不論是方式(1)還是(2),,生成的libmx.lib libmatlb.lib libmmfile.lib libmat.lib文件都要拷貝到c:\matlab\extern\lib(也就是添加到VC的編譯路徑中去),。 本文中的文件路徑可能跟讀者計算機中的路徑有所不同,請參照修改,。 |
|