東北大學(xué) 薛定宇 (原作)
轉(zhuǎn)載時請注明作者信息、網(wǎng)址,謝謝
MATLAB 到 C 語言程序的轉(zhuǎn)換可以由兩種途徑完成,其一是 MATLAB 自己提供的 C 語言翻譯程序 mcc, 另一種是原第 3 方公司 MathTools 開發(fā)的 MATCOM。后者出現(xiàn)較早,功能遠(yuǎn)比 MATLAB 自己的翻譯程序強(qiáng)大,所以 MathTools 公司已經(jīng)被 MathWorks 公司收購,并已將其開發(fā)技術(shù)融于新推出的 MATLAB 6.0 (Release 12) 中。
依本人的觀點(diǎn),二者都不完善,有大量的 MATLAB 函數(shù)及數(shù)據(jù)類型是不能兼容變換的,所以有時會發(fā)現(xiàn)將簡潔的 MATLAB 程序翻譯成 C 語言程序很晦澀。翻譯后的 C 程序幾乎不適合手動去維護(hù),更談不上升級了。
有幾個不兼容的地方是不能令人容忍的,例如 eval() 函數(shù)在 C 翻譯下是不兼容的,最新的 MATLAB 6 才剛剛敢說已經(jīng)部分兼容了,但離真正的兼容還有很長的路要走,有很多艱難的技術(shù)困難需要克服,短時間內(nèi)不可能有突破性的進(jìn)展。另一個大的問題是,眾所周 知,MATLAB 新的控制系統(tǒng)工具箱中定義了大量的 LTI 類,MATLAB 5 開始也允許使用類與對象的概念,這已經(jīng)向“面向?qū)ο蟆钡木幊套吡艘淮蟛剑?MATLAB 到 C 的翻譯明顯都不支持“對象”的數(shù)據(jù)類型,所以在控制系統(tǒng)分析與設(shè)計 (當(dāng)然還有其他的領(lǐng)域) 中這樣的轉(zhuǎn)換幾乎沒有什么實(shí)際意義,所以不要將這樣的轉(zhuǎn)換太理想化。
從轉(zhuǎn)換的程序速度來看,因?yàn)?mcc 和 MATCOM 都沿用了 MATLAB 的程序運(yùn)算機(jī)制,所以不可能大幅度地提高程序運(yùn)行速度。相反地,如果將 MATLAB 程序中明顯的瓶頸部分用 C 語言按照 MEX 格式編寫,則可以大大加快速度。作者在《科學(xué)運(yùn)算語言 MATLAB 5.3 程序設(shè)計及應(yīng)用》一書中以例子做過探討,MCC 可以比快 50%, 而 MEX 的形式可能快上百倍。
〖舉例〗分形問題:從初始點(diǎn)(x0,y0) 出發(fā),按下面的公式生成新的點(diǎn) (x1,y1)
其 中 gi 為 (0,1) 區(qū)間均勻分布的隨機(jī)數(shù)。要求從 (x1,y1) 再生成 (x2,y2),...,直至生成 1,000,000 個點(diǎn)(有點(diǎn)夸張,但太少了用 MATLAB 測時間不準(zhǔn))??梢韵螺d用 MATLAB 的 M-函數(shù)寫的程序、用 Mex_C 寫的程序。程序調(diào)用語句為:
>> N=1000000; v=rand(N,1); tic; [x,y]=frac_tree(0,0,v,N); toc
然后測試一下速度,再想法用 MATCOM 或 MCC 轉(zhuǎn)換一下,再試試速度。問題:MATCOM 程序到底比 M 函數(shù)快多少?我用 Mex_C 實(shí)現(xiàn)的速度可是快100多倍啊!下面有文章介紹,用 MATCOM+VC 能平均快1.5倍 (在別的應(yīng)用上),依作者的觀點(diǎn),為了這區(qū)區(qū) 1.5 倍還不至于自己給自己找麻煩去用 MATCOM。
這樣看,可能 MATLAB 到 C 轉(zhuǎn)換唯一的好處就是它能開發(fā)具有自主版權(quán)的軟件了。 所以本人一般不太贊同用這樣的轉(zhuǎn)換方法去開發(fā)程序,尤其不贊成刻意追求 MATLAB + C 的方式。本人認(rèn)為:除非必要,一般別采用這樣的方法。提出這樣的觀點(diǎn),歡迎商榷。
MATCOM 目前有 BC 和 VC 兩個程序,MATLAB + VC 之家中收錄了一些文章。作者見到有下載區(qū)有這樣的軟件。
在這里給出一個下載區(qū)的鏈接
C++Builder 調(diào)用 Matlab 的實(shí)現(xiàn)方法
國防科技大學(xué)機(jī)電工程與儀器系 張?jiān)浦?nbsp;
摘要:本文簡要敘述了Matlab語言的優(yōu)點(diǎn),介紹了在用Borland C++Builder語言開發(fā)的Windows應(yīng)用程序中,調(diào)用matlab語言實(shí)現(xiàn)科學(xué)計算和圖形繪制的方法。
關(guān)鍵詞:C++Builder Matlab調(diào)用 混合編程
1. 引言
Matlab 是一個高度集成的系統(tǒng),集科學(xué)計算、圖象處理、聲音處理于一體,具有極高的編程效率。近年來,Matlab已經(jīng)從最初的“矩陣實(shí)驗(yàn)室”,滲透到科學(xué)與工程 計算的多個領(lǐng)域,在自動控制、信號處理、神經(jīng)網(wǎng)絡(luò)、模糊邏輯、小波分析等多個方向,都有著廣泛的應(yīng)用。
Borland C++Builder是一種新穎的可視化編程語言。在工程應(yīng)用中,我們一般用C++Builder語言編寫應(yīng)用程序,實(shí)現(xiàn)交互界面、數(shù)據(jù)采集和端口操作 等,但C++Builder在數(shù)值處理分析和算法工具等方面,其效率遠(yuǎn)遠(yuǎn)低于Matlab語言。在準(zhǔn)確方便地繪制數(shù)據(jù)圖形方面,Matlab語言更具有無 可比擬的優(yōu)勢。此外,Matlab還提供功能強(qiáng)大的工具箱。但Matlab的缺點(diǎn)是不能實(shí)現(xiàn)端口操作和實(shí)時控制。因此,若能將兩者結(jié)合運(yùn)用,實(shí)現(xiàn)優(yōu)勢互 補(bǔ),將獲得極大的效益。
本文結(jié)合實(shí)際介紹了應(yīng)用Borland C++Builder3.0開發(fā)的Windos應(yīng)用程序中,對Matlab的調(diào)用方法。
2. C++Builder調(diào)用Matlab的實(shí)現(xiàn)方案
2.1 實(shí)現(xiàn)思路
在高版本的Maltab中(如Matlab V4.2)提供了DDE接口,用戶可以通過Windows的DDE通訊基制實(shí)現(xiàn)外部調(diào)用。這種實(shí)現(xiàn)方式比較簡單,但將增大主程序代碼,影響運(yùn)行速度。
在Windows系統(tǒng)中,DLL是一種很特別的可執(zhí)行文件,可以被多個Windows應(yīng)用程序同時訪問,具有固定的共享數(shù)據(jù)段。該數(shù)據(jù)段的數(shù)據(jù)在DLL被 Windows下載前會一直保留在內(nèi)存中,因此可以通過DLL實(shí)現(xiàn)用戶程序與Matlab之間的數(shù)據(jù)傳輸和函數(shù)調(diào)用。
具體地說, 就是利用Matlab的32位動態(tài)連接庫(DLL),生成相應(yīng)的可以被C++Builder調(diào)用的DLL,用來提供二者之間的基本支撐環(huán)境。只需在用戶程 序中加載該DLL,即可實(shí)現(xiàn)其數(shù)據(jù)段的共享。然后在用戶程序中操作DLL數(shù)據(jù)段的數(shù)據(jù),并通過某種方式在用戶程序中使Matlab執(zhí)行該DLL,就可實(shí)現(xiàn) 用戶程序?qū)atlab的調(diào)用。其形式可以是混合編程或函數(shù)調(diào)用,非常方便而高效。
2.2 實(shí)現(xiàn)方式
Matlab提供了可外部連接的DLL文件,通過將其轉(zhuǎn)換為相應(yīng)的Lib文件,并加以必要的設(shè)置,就可以在C++Builder中直接進(jìn)行Matlab函數(shù)調(diào)用,實(shí)現(xiàn)C++ Builder語言與Matlab語言的混合編程。
2.2.1 運(yùn)行環(huán)境要求
由于Matlab提供的是32位的DLL。其運(yùn)行環(huán)境要求是Matlab V4.2或更高版本。C++Builder可以進(jìn)行32位編程,這里我們采用的是V3.0版本。
2.2.2 C++Builder下LIB文件的生成
Matlab提供的Def文件允許用戶通過Implib命令生成相應(yīng)的Lib文件。其命令格式為:
Implib ???.lib ???.def
在< matlab >\extern\include目錄下,提供了如下三個.Def文件:
_libeng.def,_libmat.def,_libmx.def
通過上述命令可以生成相應(yīng)的三個Lib文件。這些Lib文件中包含了可外部調(diào)用的Matlab函數(shù)的必要信息。
3. C++Builder調(diào)用Matlab實(shí)現(xiàn)計算和繪圖
為清楚起見,作者通過一個簡單的CBuilder例程進(jìn)行說明。該實(shí)例通過調(diào)用Matlab實(shí)現(xiàn)矩陣運(yùn)算并繪制圖形,來演示C++Builder對 Matlab的調(diào)用。在C++Builder編輯環(huán)境中,建立一個新的窗體MyForm,并放置一個按鈕Demo。將工程文件命名為Try.prj,其主 函數(shù)為try.cpp。在主函數(shù)中,我們將使用一個實(shí)現(xiàn)Matlab調(diào)用的子函數(shù)DemoMatlab,作為按鈕Demo的響應(yīng)事件。其源代碼如下:
#i nclude < vcl.h >
#pragma hdrstop
#i nclude "Unit1.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
TMyForm *MyForm;
__fastcall TMyForm::TMyForm(TComponent* Owner)
: TForm(Owner)
{
}
void __fastcall TMyForm::DemoClick(TObject *Sender)
{
DemoMatlab(); //演示Matlab語言調(diào)用
}
---- 為了調(diào)用Matlab中的函數(shù),必須進(jìn)行必要的設(shè)置,將包含這些函數(shù)的文件加入工程文件Try.prj。以下是操作過程:
a. 在頭文件中加入Engine.h。其包含了啟動Matlab調(diào)用和關(guān)閉的函數(shù)聲明。
b. 打開Project|Option…對話框,點(diǎn)擊Directories/Conditionals
在Include Path中,加入目錄路徑< matlab >\extern\include,該路徑包含了engine.h和matlab.h等有用的頭文件。
在Library Path中,加入< matlab >\bin和< matlab >\extern\include。這兩個目錄路徑包含了可外部調(diào)用的DLL和LIB文件。
c. 點(diǎn)選Project|Add to Project…對話框,加入如下庫文件:
_libeng.lib,_libmat.lib和_libmx.lib。
在進(jìn)行了這些必要的設(shè)置之后,我們就可以選用適當(dāng)?shù)暮瘮?shù)來實(shí)現(xiàn)目標(biāo)。 以下是子函數(shù)DemoMatlab的程序代碼。
void DemoMatlab
{
Engine *eng; //定義Matlab引擎
char buffer[200]; //定義數(shù)據(jù)緩沖區(qū)
int array[6]={1,2,3,4,5,6};
mxArray *S = NULL, *T = NULL;
engOpen(NULL); //打開MATLAB 引擎 ---①
S= mxCreateDoubleMatrix(1,6, mxREAL);
// 產(chǎn)生矩陣變量
mxSetName(S, "S");
memcpy((char *) mxGetPr(S),
(char *) array, 6*sizeof(int));
engPutArray(eng, S); //將變量X置入Matlab的工作空間
engEvalString(eng, "T = S/S.^2;");
//計算
engEvalString(eng, "plot(S, T);");
//繪制圖形
…… ……
engOutputBuffer(eng, buffer, 200);
//獲取Matlab輸出
T = engGetArray(eng, "T");
//獲得計算結(jié)果----②
engClose(eng);
//關(guān)閉Matlab引擎,結(jié)束調(diào)用
mxDestroyArray(S);
//釋放變量
mxDestroyArray(T);
}
若還需要執(zhí)行其它功能和任務(wù),那么按照上面介紹的方法,進(jìn)行變量聲明后,在①、②處加寫需要的語句既可。
當(dāng)然,使用這種方法調(diào)用Matlab不能脫離Matlab環(huán)境的支撐。但當(dāng)我們不需要看到Matlab的命令窗口時,可將其賦予Swhide屬性而加以隱藏。
4. 結(jié)語
按照本文介紹的方法來實(shí)現(xiàn)C++Builder下應(yīng)用程序?qū)atlab的調(diào)用,可以充分利用Matlab強(qiáng)大的科學(xué)計算功能和豐富的工具箱,而且具有混 合編程、方便高效的優(yōu)點(diǎn)。這是C++語言和其它高級語言所無法比擬的。按照本文的方法,我們還可以編寫程序來最充分地利用Matlab的其它資源,開發(fā)滿 足自己需要的程序,更有效地完成我們的工作。
VC++ 下如何利用 Matlab 工具箱進(jìn)行數(shù)字信號處理
潘 衛(wèi) 明 趙 敏 張 進(jìn) 芳
(南京航空航天大學(xué) 測試工程系 210016)
摘要:本文詳述了在Vc環(huán)境下如何利用Matlab工具箱進(jìn)行數(shù)字信號處理,全文以Matlab工具箱中功率譜密度分析函數(shù)為例,介紹了通過Matlab自帶的引擎、Matlab自身的編譯器以及利用MathTools公司的Matcom進(jìn)行對工具箱函數(shù)的調(diào)用。
關(guān)鍵詞:Matlab M-文件 引擎 編譯器 Matcom Vc++
Matlab 的信號處理工具箱是信號算法文件的集合,它處理的基本對象是信號與系統(tǒng),信號處理工具箱位于目錄、Toolbox\Signal下,利用工具箱中的文件可 以實(shí)現(xiàn)信號的變換、濾波、譜估計、濾波器設(shè)計等。在其它的環(huán)境如Vc下如果能調(diào)用Matlab工具箱中的文件,會大大地加快一些算法的實(shí)現(xiàn),同時其可靠性 也很高。
利用Matlab引擎
Matlab引擎采用客戶和服務(wù)器計算方式,在運(yùn)用中,Vc的C語言或C++語言的程序 作為前端客戶機(jī),它向Matlab引擎?zhèn)鬟f命令和數(shù)據(jù)信息,并從Matlab引擎接收數(shù)據(jù)信息,它提供了下列幾個函數(shù): engOpen, engGetArray, engPutArray, engEvaString,
engOutputBuffer ,engClose與客戶機(jī)進(jìn)行交互。
下面例程是在Vc下建一個基于對話框的應(yīng)用程序,在對話框中設(shè)置一個Button控件OnMatlabEngine.,在對話框 .cpp文件中加入”engine.h” 和“math.h” 頭文件,下面給出部分程序清單。
Void CtestmatlabDlg::OnMatlabEngine(){
Engine *ep;
mxArray* T=NULL,*result=NULL,*mFs=NULL,*mnfft= NULL;
double datax[1024];
char buffer[1024];
for(int j=0;j<1024;j++)//注:如通過采集卡采集數(shù)據(jù)可將采集的數(shù)據(jù)放在datax[]數(shù)組中,此循環(huán)就不需要
{
double samt=(double)(1.0/1024);
datax[j]=sin(2.0*63.0*samt*3.1415926+1.15*3.1415926);
}
double *pPxx,*pFxx;
if(!(ep=engOpen(" \0"))){//打開Matlab引擎,建立與本地Matlab的連接
fprintf(stderr,"\n Can't start MATLAB engine\n");
exit(-1);
}
double Fs[1]={1024};//因?yàn)镸atlab所有參與運(yùn)算的參數(shù)都是矩陣的形式,因而下列幾行將參數(shù)轉(zhuǎn)變
double nfft[1]={1024};//成Matlab可接受的矩陣形式。
T=mxCreateDoubleMatrix(1,1024,mxREAL);
mnfft=mxCreateDoubleMatrix(1,1,mxREAL);
mFs=mxCreateDoubleMatrix(1,1,mxREAL);
mxSetName(T,"T");
mxSetName(mnfft,"mnfft");
mxSetName(mFs,"mFs");
memcpy((char*)mxGetPr(T),(char*)datax, 1024*sizeof(double));
memcpy((char*)mxGetPr(mnfft),(char*)nfft, sizeof(double));
memcpy((char*)mxGetPr(mFs),(char*)Fs,1*sizeof(double));
engPutArray(ep,T); //將轉(zhuǎn)化的參數(shù)放入引擎中,此時可在Matlab command窗口下查看此參數(shù)
engPutArray(ep,mnfft);
engPutArray(ep,mFs);
engEvalString(ep,"[pxx,fo]=psd(T,mnfft,mFs);"); //利用引擎執(zhí)行工具箱中文件
engOutputBuffer(ep,buffer,512); //如只想看顯示圖形,可將返回參數(shù)去掉,psd無返回參數(shù)缺省情況下會自動畫圖形
result=engGetArray(ep,"pxx");//取出引擎中的數(shù)據(jù)放在所指的區(qū)域中供后續(xù)處理
pPxx=mxGetPr(result);
result=engGetArray(ep,"fo");
pFxx=mxGetPr(result);
engEvalString(ep,"plot(fo,10*log10(pxx));");//利用引擎畫圖
engEvalString(ep,"title('功率譜分析');");
engEvalString(ep,"xlabel('Hz');");
engEvalString(ep,"ylable('db');");
mxDestroyArray(T); //釋放內(nèi)存
mxDestroyArray(mFs);
mxDestroyArray(mnfft);
mxDestroyArray(result);
engEvalString(ep,"close;");
engClose(ep);
}
上述程序在Vc下編譯需要將 libeng.dll和libmx.dll兩個動態(tài)庫利用以下的命令:
lib/def: <自己的Matlab的安裝路徑,下同>e:\ Matlab\extern\include\*.def /machine:ix86 /out:*.lib來生成程序所需的靜態(tài)連接庫libeng.lib和libmx.lib,將libeng.lib和libmx.lib所在的目錄加入 Vc++ project/link/object/library modules下即可。
利用Matlab自身的編譯器調(diào)用工具箱中的函數(shù)
Matlab 的編譯器可將Matlab的M文件轉(zhuǎn)換為為C或C++的源代碼以產(chǎn)生完全脫離Matlab運(yùn)行環(huán)境的獨(dú)立的運(yùn)用程序,但Matlab本身的資料說明編譯器 如用來建立獨(dú)立的運(yùn)用程序,不能調(diào)用Matlab工具箱中的函數(shù),這非常不利于搞一些特殊的算法。本人研究了一段時間發(fā)現(xiàn),工具箱中的函數(shù)既然是M文件就 一定可以用編譯器來編譯,以提供如Vc的調(diào)用函數(shù),但是編譯器只能編譯一個獨(dú)立的M文件,即這個 M文件不依賴于其他的M文件。如果M文件中又調(diào)用了其他的M文件,可將被調(diào)用的M文件拷貝到調(diào)用M文件的相應(yīng)位置,作適當(dāng)?shù)母膭泳涂梢杂糜诰幾g器編譯。編 譯器不支持圖形函數(shù),所以M文件中如有圖形函數(shù)需注釋掉。
當(dāng)Matlab的編譯器mcc加入適當(dāng)?shù)膮?shù)-e(mcc –e *.*)或-p(mcc –p *.*)就可生成將輸入的M文件轉(zhuǎn)換為適用于特定運(yùn)用的C或C++源代碼。這樣如果要在Vc下編譯通過,還需連入以下幾個庫libmmfile.dll, libmatlb.dll, libmcc.dll, libmat.dll. libmx.dll. mibut.dll 以及Matlab C MATH庫,建議采用前述的方法將動態(tài)連接改為靜態(tài)連接。對于C/C++編譯環(huán)境的設(shè)置,在Matlab command窗口下運(yùn)行mex –setup 然后依提示操作,而對于C/C++連接環(huán)境的設(shè)置,運(yùn)行mbuild –setup依提示操作即可。
下面給出利用編譯器將Matlab工具箱中psd.m文件生成可供Vc調(diào)用的函數(shù)。
將psd.m 文件拷貝一份至Matlab\bin目錄下,改寫相應(yīng)調(diào)用的M文件如nargchk.m, hanning.m等。為生成的代碼簡潔,對于采集數(shù)據(jù)處理輸入?yún)?shù)很明了的情況下可作大量的刪減,最終使psd.m成為一個不依賴于其他M文件的獨(dú)立的 M文件,注意千萬注釋掉作圖代碼,最終改成如下形式,限于篇幅給出關(guān)鍵的幾步:
function [Pxx,f]=psd(Fs,nfft,noverlap,x)
window=o,5*(1-cos(2*pi*(1:nfft)’/(nffft+1)));//hanning 窗
dflag=’none’;
window=window(;)
………………………………….
以上只要稍懂Matlab語言和信號處理知識就可完成這項(xiàng)工作。
假設(shè)上述代碼重新存為testwin.m,在Matlab command 窗口下設(shè)置好環(huán)境參數(shù)運(yùn)行mcc –e testwin,則可在Matlab\bin下生成testwin.c ,如運(yùn)行mcc –p testwin 則生成testwin.cpp.
Vc下建立一個基于對話框的文件,然后在對話框里加一個Button控件OnButtonPsd
將上述生成的.c文件的頭文件加入到工程的.cpp中,且將#ifdef_cplusplus
extern “c”{
#end if
c代碼聲明加入Vc的包含文件和生成的.C的包含文件之間
將#ifdef_cplusplus
}
#end if加入.cpp文件未尾
為了簡潔且便于處理將生成的c函數(shù)稍改動,給出部分代碼如下:
void CTestpsdwinDlg::OnButtonPsd(){
mxArray* x_rhs_;//指向采集數(shù)據(jù)存放區(qū)
Fs=23510;//數(shù)據(jù)采集的頻率 nfft=1024;//1024點(diǎn)的fft
double datax[1024]//采集的數(shù)據(jù)
x_rhs_mxCreateDoubleMatrix(1,1024,mxReal);
memcpy(mxGetPr(x_rhs_),datax,1024*sizeof(double));
noverlap=512;
……………….
……………….
mccCopy(&Pxx,&Spec);
mccCopy(&f,&frevgg_vector);
for(int j=0;j<(int)(nfft/2+1);j++)
{
datap[j]=mccGetRealVectorElement(&Pxx, (j+1));//功率譜密度存于datap[]數(shù)組
dataf[j]=mccGetRealVectorElement(&f, (j+1));//相應(yīng)頻率存于數(shù)組dataf[]中
}
mccFreeMatrix(&Pxx);
……………….
SendMessageBox(WM_PAINT,0,0);//利用Vc下的圖形函數(shù)畫圖
Return;
}
如上生成的程序可讀性不太好,而生成的c++代碼則可讀性較好,但千萬注意只能用 Matlab的MATH庫,不可用c++的MATH庫,否則編譯會出錯,限于篇幅在此不述。
3)利用Matcom調(diào)用工具箱中的函數(shù)
Matcom 編譯M文件,先將M文件按照與Matcom的cpp庫的對應(yīng)關(guān)系翻譯為cpp源代碼,然后用對應(yīng)版本的c編譯器將cpp文件編譯成相應(yīng)的exe或dll文 件,所以第一次運(yùn)行要指定c編譯器的路徑,否則無法編譯,指定好的編譯信息就寫在Matcom\bin\matcom.ini文件中,不過這一步按裝 matcom時,它自動尋找編譯器并將其寫入matcom.ini文件中,matcom4.5版中使用TeeChart3.0 OCX控件,因而它支持圖形操作。 我們依然用上述的testwin.m文件,不要將圖形函數(shù)注釋掉,利用Mideva來生成可被Vc調(diào)用的信號處理程序。
運(yùn)行 Mideva在主界面上直打開M文件,在菜單中選擇compile to dll,輸入testwin..在Matcom debug目錄下可以找到這樣的幾個文件,testwin.c ,testwin.h,testwin.cpp,testwin.lib,testwin.dll,testwin.exp等。
將上述testwin.cpp和testwin.h加入工程中,project/add to project/files并且在相應(yīng)的文件中加入”stdafx.h”
加連接庫:Tools\option\directory\ , 選include選項(xiàng),加入e:\matcom45\lib (包含matcom.h)
library選項(xiàng),加入e:\matcom45\lib
4) project\add to project\files 文件類型選項(xiàng)選(.lib)將e:\matcom45\lib\v4501.lib加入工程中編譯運(yùn)行。相應(yīng)代碼如下:
void CtestmatcomDlg::OnpsdButton(){
double datap[512],dataf[512];
initM(MATCOM_VERSION);//初始化matcom庫
Mm Fs,nfft,noverlap;//創(chuàng)建矩陣
Mm x=zeros(1,1024);
Fs=1024;nfft=1024;noverlap=128;
dMm(Pxx_o);dMm(f_o);//創(chuàng)建并命名矩陣
datax[];//數(shù)據(jù)采集的數(shù)據(jù)存于此數(shù)組中
for(int i=1;i<=1024;i++)
{
x.r(1,i)=datax[i+1];//給x陣賦值
}
testwin(Fs,nfft,noverlap,x,i_o,Pxx,f_o);//matcom生成的函數(shù)
for(i=0;i<513;i++){//取出功率譜密度分析結(jié)果
dataf[i]=f_o.r(i+1,1);
datap[i]=Pxx_o.r(i+1,1);}
exitM();
return;
}
可見利用Matcom進(jìn)行M文件轉(zhuǎn)換非常的容易,生成的代碼可讀性很好,以上的轉(zhuǎn)換同時生成了可供Vc調(diào)用的動態(tài)連接庫,其使用和一般的動態(tài)庫一樣使用。 同時需指明Matcom不僅可轉(zhuǎn)換獨(dú)立的不依賴于其它M文件的M文件,同時可轉(zhuǎn)換調(diào)用其它M文件的M文件嵌套。條件是這此M文件在同一個目錄下面,如前所 述的psd.m可直接用上述方法轉(zhuǎn)換,生成了多個重載形式的psd函數(shù)
結(jié)論: 利用Mtlab引擎調(diào)用工具箱中的函數(shù)可節(jié)省大量的系統(tǒng)資源,應(yīng)用程序整體性能較好,但不可脫離Matlab 的環(huán)境運(yùn)行。用Matlab編譯器進(jìn)行工具箱函數(shù)的調(diào)用,須轉(zhuǎn)換相應(yīng)的M文件使其成為獨(dú)立的M文件,且不支持圖形函數(shù),轉(zhuǎn)換的代碼可讀性不太好。用 Matcom 進(jìn)行轉(zhuǎn)換非常方便,生成的代碼可讀性很好,支持圖形函數(shù),且代碼執(zhí)行的速度比不轉(zhuǎn)換平均要快 1.5 倍以上。以上程序在Vc++ 6.0, Matlab 5.2, Matcom 4.5 中調(diào)試通過,以上方法在工程實(shí)踐中已得到很好的運(yùn)用。
通過 VC++ 實(shí)現(xiàn)對 MATLAB 的調(diào)用
成都 .中國科學(xué)院光電技術(shù)研究所 郵編:610209 齊 波 董能力
一 引言
眾所周知,MATLAB是功能非常強(qiáng)大的數(shù)學(xué)軟件,它廣泛應(yīng)用于線性代數(shù)、自動控制理論、數(shù)理統(tǒng)計、數(shù)字信號處理、時間序列分析、動態(tài)系統(tǒng)仿真等領(lǐng)域。因 此如果把MATLAB的程序加入到自己的VC++、VB、POWER STATION及其它語言編制的程序中,將大大減少編程的工作量、保證程序的準(zhǔn)確性,并且繼承VC++良好的用戶界面。下面就以VC++ 為例介紹一下它的外部調(diào)用。
二 程序?qū)崿F(xiàn)
--作者實(shí)現(xiàn)外部調(diào)用的思路是:首先將m文件加入到一段C程序中,然后通過MATLAB中的mex批處理文件將該C文件生成exe文件,然后通過VC++的外部調(diào)用的函數(shù):shellexec()或winexec()實(shí)現(xiàn)調(diào)用。 mex批處理文件的調(diào)用格式如下:
mex -f msvc60engmatopts.bat *.c
c文件的格式如下:
/* engwindemo.c
* This is a simple program that illustrates how to call the MATLAB
* Engine functions from a C program for windows
* Copyright (c) 1996-1998 by The MathWorks, Inc.
* All Rights Reserved.*/
#i nclude < windows.h >
#i nclude < stdlib.h >
#i nclude < stdio.h >
#i nclude < string.h >
#i nclude < d:\matlab\extern\include\engine.h >
void main()
{
Engine *ep;
/*
* Start the MATLAB engine
*/
if (!(ep = engOpen(NULL))) {
MessageBox ((HWND)NULL, (LPSTR)
"Can't start MATLAB engine",
, MB_OK);
exit(-1);
}
engEvalString(ep, "contour(peaks)");
engClose(ep);
}
- 程序中的黑體部分即為要加入的m文件的位置。這樣就生成了與m文件同名的exe文件,通過VC++中的外部調(diào)用函數(shù)便很容易的實(shí)現(xiàn)了對MATLAB的調(diào)用。
三 結(jié) 論
本文給出了VC++等高級程序語言調(diào)用MATLAB中程序(函數(shù))的方法,融合了VC++與MATLAB兩種不同的語言,大大提高了編程效率。不失為一種較好的程序設(shè)計方法。
Matcom: Matlab 與 C++ 結(jié)合的有效途徑
林 嵐* 周云波 楊玉星 林家瑞
作者單位:華中理工大學(xué)生物工程系(武漢 430074)
*男,24歲,碩士研究生
摘 要 本文首先介紹了當(dāng)前在國內(nèi)外十分流行的工程設(shè)計和系統(tǒng)仿真軟件包Matlab的優(yōu)缺點(diǎn),然后展開介紹了Matcom(一種將Matlab與C++結(jié)合的工具)的功能及如何使用,最后對其效果進(jìn)行了總結(jié)。
關(guān)鍵詞 Matlab Visual C++ Matcom ECG
1 工程設(shè)計軟件Matlab特點(diǎn)分析
Matlab 是MathWorks公司于1982年推出的一套高性能的數(shù)值計算和可視化軟件。它集數(shù)值分析、矩陣運(yùn)算、信號處理和圖形顯示于一體,構(gòu)成了一個方便、界 面友好的用戶環(huán)境。它還包括了ToolBox(工具箱)的各類問題的求解工具,可用來求解特定學(xué)科的問題。其特點(diǎn)是:
(1)可 擴(kuò)展性:Matlab最重要的特點(diǎn)是易于擴(kuò)展,它允許用戶自行建立指定功能的M文件。對于一個從事特定領(lǐng)域的工程師來說,不僅可利用Matlab所提供的 函數(shù)及基本工具箱函數(shù),還可方便地構(gòu)造出專用的函數(shù),從而大大擴(kuò)展了其應(yīng)用范圍。當(dāng)前支持Matlab的商用Toolbox(工具箱)有數(shù)百種之多。而由 個人開發(fā)的Toolbox則不可計數(shù)。
(2)易學(xué)易用性:Matlab不需要用戶有高深的數(shù)學(xué)知識和程序設(shè)計能力,不需要用戶深刻了解算法及編程技巧。
(3) 高效性:Matlab語句功能十分強(qiáng)大,一條語句可完成十分復(fù)雜的任務(wù)。如fft語句可完成對指定數(shù)據(jù)的快速傅立葉變換,這相當(dāng)于上百條C語言語句的功 能。它大大加快了工程技術(shù)人員從事軟件開發(fā)的效率。據(jù)MathWorks公司聲稱,Matlab軟件中所包含的Matlab源代碼相當(dāng)于70萬行C代碼。
由于Matlab具有如此之多的特點(diǎn),在歐美高等院校,Matlab已成為應(yīng)用于線性代數(shù)、自動控制理論、數(shù)理統(tǒng)計、數(shù)字信 號處理、時間序列分析、動態(tài)系統(tǒng)仿真等高級課程的基本教學(xué)工具;在研究單位、工業(yè)部門,Matlab也被廣泛用于研究和解決各種工程問題。當(dāng)前在全世界有 超過40萬工程師和科學(xué)家使用它來分析和解決問題。
然而Matlab自身所存在的某些缺點(diǎn)限制了它的應(yīng)用范圍。
(1) Matlab是一種解釋性語言,因此它的實(shí)時效率是相當(dāng)差的。例如在筆者所從事的一個心電信號處理項(xiàng)目中,采用Matlab語言來處理5分鐘的心電數(shù)據(jù), 在486/66系統(tǒng)機(jī)上需要25分鐘,而同樣的算法,用C語言實(shí)現(xiàn),僅需30多秒。由此可見,Matlab的語言執(zhí)行效率是比較低的。
(2)Matlab程序不能脫離其環(huán)境運(yùn)行,因此它不能被用于開發(fā)商用軟件。
(3)Matlab程序可以被直接看到
2 Matcom:Matlab與C++的完美結(jié)合
MathTools公司推出的Matcom(可于http://www.mathtools.com處獲取)可以說是以上問題的完美解決。它可將Matlab的源代碼譯成同等功能的C++源碼。既保持了Matlab的優(yōu)良算法,又保持了C++的高執(zhí)行效率。
下面將詳細(xì)介紹如何使Matlab與C++接口。
運(yùn)行環(huán)境:
Matcom 3.0
Matlab 5.1
Visual C++ 5.0
中文Windows 95
PC:486/66
(1)首先應(yīng)設(shè)置Matcom所對應(yīng)的編譯器類型、數(shù)據(jù)類型。
(2)將你所需要的.M文件翻譯成C源碼。
在這里將用一個簡單的濾波器Matlab源程序:
Lin.m
b=[1 2 1];
a=[1 -1.58 0.64];n=50;
x=[1, ones(1,n-1)];
y=filter(b,a,x);
plot(y./70,'*');
hold on
plot(x,'.');
grid;
下面給出了經(jīng)Matcom翻譯后的C++源程序。Lin.cpp
M b("b",0,0);
M a("a",0,0);
M n("n",0,0);
M x("x",0,0);
M y("y",0,0);
b=(BR(1.0),2.0,1.0);
a=(BR(1.0),-1.58,0.64);
n=50.0;
x=(BR(1.0),ones(1.0,n-1.0));
y=filter(b,a,x);
plot(rdivide(y,70.0),TM("*"));
hold(TM("on"));
plot(x,TM("."));
grid();
(3)Visual C++環(huán)境設(shè)置。
在Visual C++中的"Project / Settings / C, C++ / Preprocessor /Additional include subdirectories" 中填入當(dāng)前Matcom所處的路徑.。(如"c:\matcom\")在Visual C++中的工程窗口處" "Project / Add to Project / Files".加入mlibvc0.lib庫文件。
(4)修改C++源代碼。
注意:
①在頭文件處應(yīng)包含matlib.h.
#define MLIB 0
#i nclude "matlib.h."
②在類成員函數(shù)CMfcApp::InitInstance中調(diào)用. InitM啟動對Matlab函數(shù)的調(diào)用。
BOOL CEcgstarApp::InitInstance()
{
TRACE0("initM\n");
initM(stin,stout,sterr);
......
}
③在類構(gòu)造函數(shù)CMfcApp::CMfcApp.中不要調(diào)用任何Matlab函數(shù)
④在類構(gòu)造函數(shù)CMfcApp::~CmfcApp中調(diào)用exitM結(jié)束對Matlab函數(shù)的調(diào)用。
CEcgstarApp::~CEcgstarApp() { exitM(); }
⑤在程序中合適的位置插入經(jīng)Matcom翻譯過后的C++源碼。
⑥編譯工程文件,就可得到你所需的結(jié)果。
3 結(jié)束語
筆者在從事生物醫(yī)學(xué)工程ECG信號的檢測與處理項(xiàng)目中,對采用不同方法完成同一任務(wù)在代碼量和運(yùn)行時間上進(jìn)行了比較,如表1、表2所列。
表1 ECG檢測核心算法代碼量
全部用C++編寫 全部用Matlab編寫 用Matcom轉(zhuǎn)換后的C編寫
約3400行 約400行 約600行
表2 ECG檢測核心算法運(yùn)行時間
全部用C++編寫 全部用Matlab編寫 用Matcom轉(zhuǎn)換后的C編寫
約30秒 約25分鐘 約1分鐘
由此可見,采用Matcom進(jìn)行程序設(shè)計,這是一種時間、效率上的極好的折衷,它使得你可以將更多的時間放在項(xiàng)目關(guān)鍵問題的思考上,而不是放在算法的實(shí)現(xiàn)和程序的編碼中,對于廣大工程技術(shù)人員的開發(fā)工作是十分有益的。
Matlab 和 C++ 接口中函數(shù)注冊的實(shí)現(xiàn)
李江紅 韓正之
《計算機(jī)應(yīng)用》COMPUTER APPLICATIONS 2000 Vol.20 No.4 P.18-20
作者簡介:李江紅(1970-)男,湖南長沙人,博士研究生,主要研究方向:隨機(jī)決策以及智能控制;韓正之(1947-)男,上海人,教授,主要研究方向:非線性控制以及智能控制。
作者單位:李江紅(上海交通大學(xué)智能工程研究所 上海 200030)
韓正之(上海交通大學(xué)智能工程研究所 上?!?00030)
摘 要:函數(shù)注冊在Matlab和C++接口中起著重要的作用。在介紹函數(shù)注冊作用的基礎(chǔ)上,詳細(xì)分析了函數(shù)注冊的過程及應(yīng)當(dāng)注意的問題,并給出了一種實(shí)現(xiàn)函數(shù)注冊的最簡單的方法。用實(shí)例展示了函數(shù)注冊的具體實(shí)現(xiàn)過程。
關(guān)鍵詞:Matlab;C++;函數(shù)注冊
中圖分類號:TP317,TP319 文獻(xiàn)標(biāo)識碼:A
文章編號:1001-9081(2000)04-0018-03
FUNCTION REGISTERING IN
THE INTERFACE BETWEEN MATLAB AND C++
LI Jiang-hong HAN Zheng-zhi
(Intelligent Engineer Research Institute of Shanghai Jiaotong University, Shanghai 200030 China)
Abstract: Function registration plays an important role in the interface between Matlab and C++. This paper analyzes the procedure of function registering. Each step of function registering is discussed in detail in the paper, and at the end,an example is given for illustration.
Key words:Matlab; C++; function registration
1 研究意義
Matlab為用戶提供了豐富的Windows圖形界面設(shè)計方法,使用戶能夠在利用其強(qiáng)大數(shù)值計算功能的同時設(shè)計出友好的圖形界面。在編程效率、可讀 性、可移植性和可擴(kuò)充性上,Matlab遠(yuǎn)遠(yuǎn)優(yōu)于其它高級編程語言。Matlab能夠設(shè)計出功能強(qiáng)大、界面優(yōu)美、性能穩(wěn)定的高質(zhì)量程序,它受到了越來越多 用戶的歡迎。然而作為一種以解釋方式運(yùn)行的高級計算機(jī)語言,Matlab程序的執(zhí)行效率較低。為了解決這一問題,MathWorks公司提供了 Matlab和C的接口。MathWorks公司提供的Matlab和C的接口方式共有三種:(a)將Matlab程序編譯成MEX文件C或C++文件; (b)在C,C++程序中利用Matlab Engine調(diào)用Matlab函數(shù);(c) 在C,C++程序中利用Matlab C Math Library或Matlab C++ Math Library調(diào)用Matlab函數(shù)。其中通過方式(a)、(b)生成的程序只有在安裝了Matlab系統(tǒng)上才能正常運(yùn)行,而由方式(c) 生成的程序則沒有這樣的要求,它能夠以獨(dú)立執(zhí)行程序的形式運(yùn)行,即使客戶沒有安裝Matlab系統(tǒng)。方式(c)唯一的缺點(diǎn)就是不能利用Matlab中豐富 的圖形句柄處理函數(shù),但是對于VC++等開發(fā)工具而言,這不是一個很嚴(yán)重的問題。因此方式(c)是實(shí)現(xiàn)功能和效率兼顧的最好接口方法[2]。
當(dāng)用方式(c) 生成應(yīng)用程序時,一個重要的問題就是那些以函數(shù)作為自身輸入?yún)?shù)的函數(shù)實(shí)現(xiàn)問題。眾所周知,Matlab提供了一組能完成極值及極值點(diǎn)計算,線性規(guī)劃,二次規(guī)劃以及非線性方程求解等數(shù)值運(yùn)算的優(yōu)化函數(shù)[3]。
在Matlab中使用這組優(yōu)化函數(shù)時,用戶定義的待優(yōu)化函數(shù)必須作為輸入?yún)?shù)傳遞給這些函數(shù)。在優(yōu)化函數(shù)運(yùn)行的過程中,系統(tǒng)將最終執(zhí)行用戶定義的待優(yōu)化 函數(shù),并且這一切無須程序員的參與。但是當(dāng)程序員通過方式(c)在C++程序中調(diào)用Matlab C++ Math Library中的優(yōu)化函數(shù)時,事情就變得比較復(fù)雜。要利用這些優(yōu)化函數(shù)所提供的數(shù)值計算功能,保證用戶定義的待優(yōu)化函數(shù)真正得到執(zhí)行,程序員就必須自己 完成對待優(yōu)化函數(shù)的注冊。因此,函數(shù)注冊的研究具有重要的實(shí)用價值。
2 Matlab和C++接口中函數(shù)注冊
在C++程序中,當(dāng)調(diào)用優(yōu)化函數(shù)等以函數(shù)為輸入?yún)?shù)的函數(shù)時,Matlab C++ Math Library調(diào)用Matlab C Math Library中的mlfFeval()來執(zhí)行作為參數(shù)傳遞的函數(shù)。在mlfFeval()中又是通過對轉(zhuǎn)換函數(shù)的調(diào)用來真正地執(zhí)行作為參數(shù)傳遞的函數(shù)。 轉(zhuǎn)換函數(shù)和映射表是這一過程能夠順利進(jìn)行的重要原因。函數(shù)注冊就是定義函數(shù)的轉(zhuǎn)換函數(shù)并建立相應(yīng)的它的映射表。對于Matlab C++ Math Library中的函數(shù),MathWorks公司都定義了它們轉(zhuǎn)換函數(shù)并建立了它們的映射表,完成了對它們的注冊。但是對于用戶自定義的函數(shù),程序員就必 須自己完成這項(xiàng)工作。
函數(shù)注冊可以分成:(1)定義待注冊函數(shù);(2)定義轉(zhuǎn)換函數(shù);(3)建立映射表;(4)初始化映射表等以下四個部分來完成。下面將對各個部分進(jìn)行詳細(xì)地介紹。
(1) 定義待注冊函數(shù) 待注冊函數(shù)因用戶要求而異。為便于后面的分析,設(shè)用戶定義的函數(shù)為:
mwArray MyFunc(mwArray x){
……//函數(shù)體。
}
注意待注冊函數(shù)的輸入、輸出參數(shù)的類型必須是mwArray。mwArray是Matlab C++ Math Library中最基本的數(shù)據(jù)類,它對應(yīng)Matlab中的基本編程單位—數(shù)組。
(2) 定義轉(zhuǎn)換函數(shù) 轉(zhuǎn)換函數(shù)的功能是完成Matlab C Math Library和用戶函數(shù)之間的翻譯。由于它面向Matlab C Math Library,因此必須用C定義。對(1)中定義的待注冊函數(shù),其轉(zhuǎn)換函數(shù)的一般形式如下(為簡單起見,該轉(zhuǎn)換函數(shù)忽略了錯誤處理代碼):
typedef mwArray (*PMYFUNC) (mwArray);
extern "C" {
int MyThunk (mlfFuncp pFunc, int nArgOut, mxArray **
ArgOut, int nArgIn, mxArray ** ArgIn){
mwArray tmp=mwArray(ArgIn[0],0);
mwArray Out=(*((PMYFUNC)pFunc)) (tmp);
ArgOut[0]=Out.FreezeData( );
return 1
}
}
轉(zhuǎn)換函數(shù)共有5個輸入?yún)?shù),以MyThunk為例,pFunc是指向待注冊函數(shù)的指針;nArgIn、nArgOut, 分別是待注冊函數(shù)的輸入、輸出參數(shù)的個數(shù); ArgIn、ArgOut,則分別是輸入、輸出參數(shù)構(gòu)成的數(shù)組。其中ArgIn[0]對應(yīng)第1個輸入?yún)?shù),ArgIn[1]對應(yīng)第2個輸入?yún)?shù)……。 ArgOut的情形類似。
由于轉(zhuǎn)換函數(shù)面向Matlab C Math Library,因此它的輸入、輸出參數(shù)中的數(shù)組類型只能是mxArray (mwArray是Matlab C Math Library中基本的數(shù)據(jù),它對應(yīng)Matlab中的基本編程單位—數(shù)組);而注冊的函數(shù)又只能接受mwArray類型的參數(shù)。因此,在調(diào)用注冊函數(shù)之前 必須將mxArray型數(shù)據(jù)轉(zhuǎn)化為mwArray型數(shù)據(jù),如MyThunk中:mwArray tmp=mwArray(ArgIn[0],0); 在轉(zhuǎn)換函數(shù)返回之前必須將注冊的函數(shù)的返回值由mwArray型轉(zhuǎn)化為型mxArray,如MyThunk中:ArgOut[0]= Out.FreezeData()。
(3) 建立映射表 映射表的作用是把待注冊函數(shù)的名稱映射到指向該函數(shù)的指針。映射表中的元素由三元組:函數(shù)名稱、函數(shù)指針、轉(zhuǎn)換函數(shù)構(gòu)成。對(1)、(2)中定義的待注冊函數(shù)和轉(zhuǎn)換函數(shù),相應(yīng)的映射表為:
static mlfFuncTabEnt MfuncTab[]={
{"MyFunc", (mlfFuncp) MyFunc, MyThunk}
{0, 0 ,0}
}
其中mlfFuncTabEnt是Matlab C Math Library中用于存儲函數(shù)項(xiàng)的數(shù)據(jù)結(jié)構(gòu)。{0, 0 ,0}表示映射表的結(jié)束。
(4) 初始化映射表 初始化映射表的方式比較單一。例如對(3)中的映射表,程序段:
class feval—init{
feval—init{mlfFevalTableSetup(MfuncTab);}
static feval—init feval—setup;
}
feval—init feval—init::feval—setup;
將完成其初始化。其中mlfFevalTableSetup是Matlab C Math Library中用于初始化映射表的函數(shù)。設(shè)置靜態(tài)對象的目的是保證映射表初始化在系統(tǒng)初始化靜態(tài)變量時就得以完成。
從上面的分析可以看出,函數(shù)注冊的過程比較復(fù)雜。不過MathWorks公司注意到了這個問題,它定義并提供了DECLARE—FEVAL— TABLE, EVAL—ENTRY, END—FEVAL—TABLE等一組宏來幫助用戶簡單、輕松地完成函數(shù)注冊。例如對于(1)中定義的函數(shù)MyFunc,程序段:
DECLARE—FEVAL—TABLE
FEVAL—ENTRY(MyFunc)
END—FEVAL—TABLE
就實(shí)現(xiàn)了對MyFunc的注冊,它取代了(2)、(3)、(4)中的所有工作。事實(shí)上,只要待注冊函數(shù)的輸入?yún)?shù)數(shù)目不大于8,輸出參數(shù)數(shù)目不大于5,就能用這組宏來完成函數(shù)注冊。
3 應(yīng)用實(shí)例
下面的VC++程序通過調(diào)用Matlab C++ Math Library中的fmin(),計算函數(shù)
f(x,y)=ex(4x2+2y2+4xy+2y+1)
在y=2時,位于區(qū)間[-2,2]中使函數(shù)值最小的自變量x的值。
#i nclude "matlab.hpp"
#i nclude <stdlib.h>
/***(1) 定義注冊函數(shù) ***/
mwArray MyFunc(mwArray x,mwArray y){
mwArray mResult=exp(x)*(4*x ^ 2+2*y ^ 2+4*x*y+2*y+1);
return mResult;
}
/***(2) 定義轉(zhuǎn)換函數(shù) ***/
typedef mwArray (*PMYFUNC)(mwArray,mwArray);
extern "C"{
int MyThunk(mlfFuncp pFunc, int nArgOut, mxArray **
ArgOut,int nArgIn, mxArray **ArgIn) {
mwArray tmp1=mwArray( ArgIn[0], 0 );
mwArray tmp2=mwArray( ArgIn[1], 0 );
mwArray Out=(*((PMYFUNC)pFunc))(tmp1,tmp2);
ArgOut[0]=Out.FreezeData();
return 1;
}
}
/***(3) 建立映射表 ***/
static mlfFuncTabEnt MFuncTab[] ={
{ "MyFunc", (mlfFuncp)MyFunc, MyThunk },
{ 0, 0, 0 }
};
/***(4) 初始化映射表 ***/
class feval—init {
feval—init() { mlfFevalTableSetup( MFuncTab ); }
static feval—init feval—setup;
};
feval—init feval—init::feval—setup;
/***可以取代(2)(3)(4)的宏注冊函數(shù) ****/
/*** DECLARE—FEVAL—TABLE ***/
/*** FEVAL—ENTRY(MyFunc) ***/
/*** END—FEVAL—TABLE ***/
/***** 主程序 *****/
void main(void){
mwArray mStart,mEnd,mP,mOption;
mStart=-2,mEnd=2;mP=2.0;
mwArray mResult=fmin("MyFunc",mStart,mEnd,mOption,mP);
cout < < mResult< < endl;
}
參考文獻(xiàn)
[1] 薛定宇. 控制系統(tǒng)計算機(jī)輔助設(shè)計—MATLAB語言及應(yīng)用[M].北京:清華大學(xué)出版社, 1996.17-19.
[2] MATLAB C++ math Libarary User′s Guide[Z]. The Math Works, Inc., 1998.2-18.
[3] 施陽,李俊.MATLAB語言工具箱—TOOLBOX實(shí)用指南[M].西安:西北工業(yè)大學(xué)出版社,1998.100-101.
收稿日期:1999-10-19
Matlab 與 C++ 混合編程
Matlab 是當(dāng)今世界上使用最為廣泛的數(shù)學(xué)軟件,它具有相當(dāng)強(qiáng)大的數(shù)值計算、 數(shù)據(jù)處理、系統(tǒng)分析、圖形顯示,甚至符號運(yùn)算功能,是一個完整的數(shù)學(xué)平臺,在這個平臺上,你只需寥寥數(shù)語就可以完成十分復(fù)雜的功能,大大提高了工程分析計 算的效率。另外由于Matlab的廣泛使用,于是出現(xiàn)了為各個領(lǐng)域?qū)iT使用的工具箱(即在某一研究領(lǐng)域常用數(shù)學(xué)工具的函數(shù)包),這些工具箱的出現(xiàn)更加促進(jìn) 了Matlab的流行。
Matlab強(qiáng)大的功能只能在它所提供的平臺上才能使用,也就是說,你必需在安裝有matlab系統(tǒng)的機(jī) 器上使用.m文件,這樣就給工程計算帶來了很大不便;特 別是,在matlab中,使用的行解釋方式執(zhí)行代碼,這樣大大地限制了代碼執(zhí)行速度。 于是人們想到,能否開發(fā)一個matlab與其他高級語言的接口,這樣就可以把matlab 的強(qiáng)大功能融入各種應(yīng)用程序中,并且通過高級語言編譯器編譯為2進(jìn)制代碼, 從而大大提高了執(zhí)行速度。
于是matlab的5.1 版本提供了自帶的C++ Complier,同時MathTools公司也為 Matlab開發(fā)了m文件高效解釋和調(diào)試IDE:MIDEVA。經(jīng)過近兩年的發(fā)展,matlab 5.3 中的C complier--mcc版本已經(jīng)為2.0,而MIDEVA最新版本為4.5。
將matlab與C混合編程大概有如下三種方法:
用Matlab的mcc將.m文件翻譯為cpp源文件,然后在C編譯器中調(diào)用 也可以用mcc編譯編譯為stand-alone程序。
用Matcom(MIDEVA)將.m文件翻譯為cpp代碼,并編譯為exe或dll 文件。
按照matcom的語法,在VC或BCB中直接書寫matlab語句(與matlab 很相似),這也是我最喜歡用的方法。
方法1和2/3各有利弊,1不支持圖形(支持圖形的庫國內(nèi)現(xiàn)在還沒有D), 1對類支持也不夠,2支持絕大多數(shù)的matlab語句(包括圖形),但對于struct等的支持也有缺陷。
MATLAB5.3 的提供了C/C++數(shù)學(xué)庫,其中的C++數(shù)學(xué)庫功能很強(qiáng),使用它可以用類似MATLAB 的語法編寫C++程序,十分方便。雖然速度上仍然比手工C/C++程序慢,但是由此換來的高效的開發(fā)效率和可靠性往往是值得的。另外mcc命令可以將M文 件轉(zhuǎn)化為C或CPP文件,編譯后可以脫離MATLAB運(yùn)行 ,它們也是使用的C/C++數(shù)學(xué)庫。 不過,MATLAB的數(shù)學(xué)庫在開發(fā)時似乎傾向于編譯獨(dú)立的可執(zhí)行程序,把VC、BC只是作為一個編譯和連接的工具,而沒有過多地考慮在VC、BC的集成環(huán) 境下進(jìn)行開發(fā)。這給我們帶來了不便。 很多網(wǎng)友問起如何將MCC生成的C++程序嵌入到VC。最近對這個問題做了一下嘗試,在這里做一個總結(jié),請大家回去試試。這里只介紹VC的情況,用BC的 網(wǎng)友就自己研究研究吧估計是類似的。
1、設(shè)置項(xiàng)目編譯選項(xiàng) 首先建立一個新的項(xiàng)目,或者打開一個已有的項(xiàng)目,然后選擇菜單
Project->Settings->C/C++
Category:Preprocessor
Preprocessor definitions:
添加: MSVC,IBMPC,MSWIND
Category: Precompiled Headers
選擇: Automatic use of precompiled headers
Through header: stdafx.h
2、調(diào)設(shè)置項(xiàng)目連接選項(xiàng)
首先要從下面幾個函數(shù)定義文件(*.def)生成相應(yīng)的導(dǎo)入庫文件(*.lib)
libmmfile.def
libmcc.def
libmatlb.def
libmx.def
libmat.def
它們位于目錄c:\matlab\extern\include
用下面命令導(dǎo)出庫文件:
lib /def:libmmfile.def /out:libmmfile.lib /machine:ix86
lib /def:libmcc.def /out:libmcc.lib /machine:ix86
lib /def:libmatlb.def /out:libmatlb.lib /machine:ix86
lib /def:libmx.def /out:libmx.lib /machine:ix86
lib /def:libmat.def /out:libmat.lib /machine:ix86
將它們放入你的項(xiàng)目連接選項(xiàng)
Project->Settings->Link
Category:Input
Object/library modules:
添加:libmatpm.lib libmmfile.lib libmcc.lib libmatlb.lib libmx.lib libmat.lib
注1: 中間是空格,不要加逗號
注2: libmatpm.lib是C++ MathLib的庫,如果是只用C,就不用連接它了。
Ignore libraries:
添加: msvcrt.lib 注:
僅在Debug版本中需要。原因不明.
3、設(shè)置編譯環(huán)境
Tools->Options->Directories
Include fiels添加:
c:\matlab\extern\include
c:\matlab\extern\include\cpp
Library fiels添加:
c:\matlab\extern\lib
c:\matlab\extern\include
注:下面這個目錄是那些lib所在的地方。 如果都挪到上面的目錄,這個自然就不要了。
4、編寫程序
用MCC命令生成的CPP文件和自己手工編寫的CPP文件, 其項(xiàng)目設(shè)置是完全相同的, 程序的語法原則上也是一樣的. 只是MCC生成的CPP文件有大量"沒用"的代碼.
(1)添加自己編寫的程序模塊
用下面文件頭:
#i nclude "stdafx.h"
#i nclude "matlab.hpp"
然后, 按照C++ MathLib文檔要求的格式書寫程序.
(2)嵌入mcc生成的文件 在MATLAB下用下面格式的命令生成cpp文件 mcc -t -L Cpp test 得到test.hpp, test.cpp 將test.cpp加入項(xiàng)目, 不做任何改動. 最后,摁F7編譯就可以了。
5、實(shí)例
上面羅羅嗦嗦一大堆,肯定讓你打哈欠了:沒關(guān)系,其實(shí)還是挺簡單的,這里有個VC的project,用C++數(shù)學(xué)庫解決了一個幼兒園的算術(shù)題. 這里說明一下:
MATLAB程序test.m:
function [sum, prod]=test(x,y)
sum = x+y;
prod = x*y;
用來計算兩個數(shù)的和與積。注意這是兩個返回變量的情況。 另外,x,y當(dāng)然可以是數(shù)組。 用mcc命令生成了test.hpp和test.cpp。
文件demo.cpp:
#i nclude "stdafx.h"
#i nclude "matlab.hpp"
#i nclude "test.hpp"
void mccDemo()
{ CString str;
mwArray x, y, sum, prod;
double dx,dy,dsum,dprod;
x = 5.0;
y = 10.0;
sum = test(&prod, x, y);
dx=x(1,1);
dy=y(1,1);
dsum=sum(1,1);
dprod=prod(1,1);
str.Format("%f+%f=%f\n%f*%f=%f", dx,dy,dsum,dx,dy,dprod);
AfxMessageBox(str); }
由于采用了C++數(shù)學(xué)庫,語法很簡單。注意數(shù)組的賦值、其中數(shù)據(jù)的存取,這些都要仔細(xì)地看手冊。 最后是跳出一個消息框,顯示計算結(jié)果。
VC++ 中編譯 MEX 程序
1. 目的
一般情況下,我們都是在MATLAB命令行或DOS命令行下編譯MEX程序。 所用的命令就是:mex filename.c 這有很多不方便的地方:
a. 雖然mex也可以編譯C++的mex程序,但是它的主框架仍是C的 a. 當(dāng)程序有多個模塊時,需要多次使用mex命令,操作很麻煩
b. 不能利用VC特有的ClassWizard自動創(chuàng)建和維護(hù)類
c. 不能用MFC類庫編寫應(yīng)用程序
d. 不能方便地進(jìn)行類似VC的項(xiàng)目管理
這樣一個命令行的編程環(huán)境可能會大大束縛你的想象力... 其實(shí)解決問題的方法很簡單,下面以VC6環(huán)境為例詳細(xì)解說如何在IDE中編譯MEX程序。
2. 步驟
(1)準(zhǔn)備工作 (這里假設(shè)MATLAB的路徑為:C:\MATLAB)
a. 由matlab.def創(chuàng)建庫文件matlab.lib
進(jìn)入c:\matlab\extern\include目錄,用lib命令生成matlib.lib
C:\>cd \matlab\extern\include
C:\MATLAB\extern\include>lib /def:matlab.def /out:matlab.lib
Microsoft (R) Library Manager Version 6.00.8447
Copyright (C) Microsoft Corp 1992-1998. All rights reserved.
LIB : warning LNK4068: /MACHINE not specified; defaulting to IX86
Creating library matlab.lib and object matlab.exp
C:\MATLAB\extern\include>
警告信息不用理它。
b. 修改mex.h
該文件也在C:\MATLAB\extern\include目錄
找到這一行:void mexFunction(
替換為 : __declspec( dllexport ) void mexFunction(
另保存為 :mex_vc.h
(2)啟動VC,創(chuàng)建MFC AppWizard(dll)程序框架
(3)設(shè)置系統(tǒng)選項(xiàng)
a. 設(shè)定頭文件和庫文件路徑
菜單Tools->Options->Directories
Include files:添加c:\matlab\extern\include
Library files:添加c:\matlab\extern\include
b. 設(shè)置編譯連接選項(xiàng)
菜單Project->Settings
C/C++->Preprocessor definitions: 添加MATLAB_MEX_FILE
Link->Object/Library modules: 添加matlab.lib
注1. 其它優(yōu)化、調(diào)試以及頭文件、庫文件等選項(xiàng)看情況調(diào)整
注2. Release版在General->Microsoft Foundation Classes選項(xiàng)中, 必須設(shè)置為Use MFC in a Static Library. 原因不明 (4)編寫DLL主程序
a. 文件名要用.cpp為擴(kuò)展名,頭兩行必須是:
#i nclude "stdafx.h"
#i nclude "mex_vc.h"
b. 編寫mexFunction函數(shù),用如下格式聲明:
void mexFunction(
int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[])
{
...
}
(5) 象普通VC的DLL程序一樣繼續(xù)編寫其它部分程序,加入其它模塊
(6) 調(diào)試錯誤,用F7編譯,生成DLL。我的例子:
--------------------Configuration: MatWave - Win32 Release--------------------
Compiling resources...
Compiling...
StdAfx.cpp
Compiling...
MatWave.cpp
sample.cpp
mex.cpp
Generating Code...
Linking...
Creating library Release/MatWave.lib and object Release/MatWave.exp
LINK : warning LNK4089: all references to "SHELL32.dll" discarded by /OPT:REF
LINK : warning LNK4089: all references to "comdlg32.dll" discarded by /OPT:REF
MatWave.dll - 0 error(s), 2 warning(s)
大功告成,有兩個警告,不理它。 拿到MATLAB里面試試吧,不過要有非法操作和異常退出的心理準(zhǔn)備哦.
另外:如果要在MATLAB運(yùn)行中重新編譯DLL,需先執(zhí)行: clear mex
C++Builder與Matlab混合編程的實(shí)現(xiàn)
長沙 張?jiān)浦?nbsp;
在C++Builder中調(diào)用Matlab工具箱函數(shù),有兩種實(shí)現(xiàn)方式。一種是基于Matlab環(huán)境支持,通過必要的設(shè)置實(shí)現(xiàn);筆者在本刊上曾撰文對這種 方式進(jìn)行了專門的闡述。另一種則是完全脫離Matlab環(huán)境,通過動態(tài)連接庫方式實(shí)現(xiàn)對Matlab工具箱函數(shù)的調(diào)用,這可以通過一種開發(fā)平臺 Mediva來實(shí)現(xiàn)。相對來說,前者的限制因素較多,而后者則較為方便靈活。
一、Mediva軟件平臺
Mediva是Mathtools公司推出的一種Matlab編譯開發(fā)軟件平臺,提供對Matlab程序文件(M文件)的解釋執(zhí)行和開發(fā)環(huán)境支持。該軟件 有為Borland C++、Visual Basic和Dephi等編程語言開發(fā)的不同版本,目前其版本已經(jīng)到了4.5版。軟件大小僅6.5M,可以通過訪問其站點(diǎn) www.mathtools.com免費(fèi)下載試用一個月。 Mediva軟件平臺本身的功能相當(dāng)強(qiáng)大,提供近千個Matlab的基本功能函數(shù),通過必要的設(shè)置,就可以直接實(shí)現(xiàn)與C++的混合編程,而不必再依賴 Matlab;同時,Mediva還提供編譯轉(zhuǎn)換功能,能夠?qū)atlab函數(shù)或編寫的Matlab程序轉(zhuǎn)換為C++形式的DLL,從而實(shí)現(xiàn)脫離 Matlab環(huán)境對Matlab函數(shù)和過程的有效調(diào)用,這樣就有可能實(shí)現(xiàn)對Matlab強(qiáng)大的工具箱函數(shù)的利用。
Mediva的 缺點(diǎn)是C++與Matlab混合編寫的應(yīng)用軟件必須攜帶必要的DLL,從而增大了軟件的體積(約4M),同時也不能對所有的Matlab函數(shù)提供支持,例 如采用類庫進(jìn)行設(shè)計的部分函數(shù)。但盡管如此,對于控制系統(tǒng)計算機(jī)設(shè)計、分析的工作來說,Mediva仍不失為一個好的工具。
由于利用Mediva將Matlab工具箱函數(shù)轉(zhuǎn)換成DLL的內(nèi)容較多,限于篇幅本文在此僅給出對Matlab函數(shù)直接調(diào)用的實(shí)現(xiàn),而將另撰文闡述DLL的實(shí)現(xiàn)。
二、C++Builder直接調(diào)用Matlab函數(shù)
本文假設(shè)已經(jīng)安裝了Mediva軟件或已經(jīng)得到必要的兩個動態(tài)連接庫mdv4300.dll和ago4300.dll。
Mediva提供的近千個Matlab基本功能函數(shù),都可以在C++Builder中直接調(diào)用。這些函數(shù)包括基本的操作、命令、I/O、線性代數(shù)、位 圖、控制等,基本上可以滿足我們的一般需要。當(dāng)然其最大的優(yōu)點(diǎn)就是可以直接在C++Buider中直接調(diào)用而不必考慮安裝龐大的Matlab。
其實(shí)現(xiàn)方式和步驟如下:
1.Lib文件的生成
在Dos下用C++Builder中的Implib.exe,通過如下命令生成mdv4300.lib: implib mdv4300.lib mdv4300.dll
將上述兩個DLL文件和此Lib文件拷貝到當(dāng)前目錄下。
2.實(shí)現(xiàn)與Matlab的混合編程
Matlab.h包含了Mediva中所有類型、常量、函數(shù)的說明和定義,必須將此頭文件放于程序的第一行。Mediva給出的Matlab函數(shù)形式并 不特殊,如繪線函數(shù)Plot,在Mediva中說明為:Mm DLLI plot(cMm varargin);varargin與Matlab 中的意義是一樣的,與輸入變量的個數(shù)相對應(yīng)。所有可以直接使用的函數(shù)都在Matlib.h頭文件中定義,而在mdv4300.dll中實(shí)現(xiàn)。
但在C++Builder中使用Mediva提供的Matlab函數(shù)的格式,與Matlab編程稍有不同,這主要體現(xiàn)在C++中必須進(jìn)行必要的說明上。 例如我們要用繪線函數(shù)Plot來繪制數(shù)組x[100]的紅色圖線。在Matlab中調(diào)用為Plot(x,'r');在C++中調(diào)用則為:Plot(CL (x),TM("r")),其中CL是一個關(guān)鍵字,是多變量輸入時所必須使用的,用以指明調(diào)用的變量;而TM則指明,這是一個字符。
下面我們給出一個示例程序,其功能是對一個1024點(diǎn)的輸入數(shù)組進(jìn)行FFT 變換,并繪制變換后頻譜實(shí)部的火柴桿圖,最后將原數(shù)據(jù)和變換后的數(shù)據(jù)寫入數(shù)據(jù)文件中。
#i nclude "matlib.h"
//必須包含的頭文件
#i nclude < vcl.h >
#pragma hdrstop
#i nclude "TryMatcomU.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
int k=0;
initM(MATCOM_VERSION); //必須進(jìn)行的初始化
Mm cur1,cur2; //定義變量
cur1=zeros(128); cur2=zeros(128); //變量初始化
for (k=1;k< =128;k++)
cur1.r(k)=randM(); //生成一個隨機(jī)數(shù)列
figure(1);
plot(cur1);//圖形顯示該數(shù)列
cur2=fft(cur1,128); //做128點(diǎn)fft變換
figure(2);
//繪制fft變換后實(shí)部的火柴桿圖,注意此處多變量輸入的格式
stem((CL(cur1),real(cur2),TM("r")));
fid=fopen(filename,mode,format) opens
exitM(); //退出調(diào)用
}
如果完全使用C++來實(shí)現(xiàn)本程序的工作,其代碼將超過300行!由此可以看出,C++Builder與Matlab函數(shù)的混合編程可以給我們帶來多么大的方便!
3.變量內(nèi)部狀態(tài)/數(shù)據(jù)的觀察方法
Mediva使用的所有變量均定義為Mm類型。如果在C++Builder中觀察Mm類型變量的內(nèi)部狀態(tài)/數(shù)據(jù),要稍麻煩一些。但在調(diào)試程序時,這又是不可避免的一步,這里舉例給出變量觀察的方法。
例如對上面生成的cur2數(shù)列進(jìn)行觀察,
*cur2.pr 0.1892 cur2(1)的實(shí)部
*cur2.pi 0.0013 cur2(1)的虛部
三、C++Builder調(diào)用Matlab工具箱函數(shù)轉(zhuǎn)換后的DLL
1.Matlab函數(shù)向DLL的轉(zhuǎn)化
Mediva軟件提供了將Matlab函數(shù)轉(zhuǎn)換為DLL的功能,非常方便。但需要注意的是:
1.Matlab5.0以上版本,所有帶有tf類的函數(shù)均無法轉(zhuǎn)換;
2.Matlab4.2以下版本,多數(shù)函數(shù)能夠轉(zhuǎn)換,但轉(zhuǎn)換后大多不能直接使用,而必須加以處理。
MATCOM V4.3中把含有輸入?yún)?shù)的M文件轉(zhuǎn)換成DLL時,生成的DLL無法調(diào)用.以.M為例,
function [x1,x2]=flower(x3)
MATCOM生成的FLOWER.CPP和FLOWER.H中聲明為:
Mm flower(Mm x3, i_o_t, Mm& x1__o, Mm& x2__o) {
begin_scope
x3.setname("x3");
...
}
Mm flower(Mm x3);
Mm flower(Mm x3, i_o_t, Mm& x1__o, Mm& x2__o);
而生成的G_FLOWER.CPP聲明為:
---- void DLLX _stdcall flower_1_1(Mm** in01, Mm **out01)
---- void DLLX _stdcall flower_1_2(Mm** in01, Mm **out01, Mm **out02)
---- 其中對于in01的說明是不正確的.應(yīng)按如下修改。然后,按如下MAKE文件進(jìn)行編譯。
#
# MATCOM makefile
#
all: flower.dll
g_flower.obj: g_flower.cpp
bcc32 -c -Id:\matcom43\ -WD -Id:
\matcom43\lib -H=matlib.csm -a4
-5 -eg_flower.obj g_flower.cpp
flower.dll: flower.obj g_flower.obj
bcc32 -Ld:\matcom43\ -WD -Id:
\matcom43\lib -H=matlib.csm -a4 -5 -eflower.dll
@flower.rsp d:\matcom43\lib\mdv4300b.lib
在CPP中調(diào)用這個函數(shù)之前,一定要先給in01分配空間。
#i nclude "matlib.h"
#pragma hdrstop
#i nclude "flower.h"
#define WIN32_LEAN_AND_MEAN
#i nclude < windows.h >
#i nclude "matlib.h"
#pragma hdrstop
extern "C" {
void DLLX _stdcall flower_1_1(Mm in01, Mm **out01) {
*out01=new Mm();
//*in01=new Mm();
**out01=flower(in01);
exitM();
}
void DLLX _stdcall flower_1_2(Mm in01, Mm **out01, Mm **out02) {
*out01=new Mm(); *out02=new Mm();
//*in01=new Mm();
flower(in01, i_o , **out01, **out02);
exitM();
}
VC++調(diào)用MATLAB Engine
實(shí)驗(yàn)環(huán)境: Pwin98, MATLAB5.3, Visual C++ 6.0 SP3
1 生成幾個連接庫文件
在目錄 c:\matlab\extern\include 下找這幾個文件:
libeng.def libmx.def libmat.def
在DOS行命令下生成三個庫文件:
c:\msdev\bin\lib /def:libmat.def /out:libmat.lib
c:\msdev\bin\lib /def:libeng.def /out:libeng.lib
c:\msdev\bin\lib /def:libmx.def /out:libmx.lib
把生成的三個LIB文件加入你的LINK項(xiàng)
libeng.lib libmx.lib libmat.lib
2 寫包含engine功能的文件
可以參考:
c:\matlab\extern\examples\eng_mat\engwindemo.c
注意: 可以用.CPP做后綴. 比如:MATLAB.CPP
3 設(shè)置編譯選項(xiàng)
把MATLAB.C加入你的PROJECT
MATLAB.C的開頭加入兩行:
#i nclude "stdafx.h"
#i nclude "engine.h"
包含其它頭文件, 自己看情況而定
4 編寫調(diào)用engine的函數(shù)
比如響應(yīng)菜單調(diào)用自己的函數(shù)matlabPlot,而此函數(shù)的實(shí)現(xiàn)在matlab.cpp文件中實(shí)現(xiàn),內(nèi)容如下:
#i nclude "stdafx.h"
#i nclude "engine.h"
int MatlabDraw()
{
Engine *ep;
if (!(ep = engOpen(NULL))) {
MessageBox ((HWND)NULL,"Can't start MATLAB engine","Matlab Draw",MB_OK);
return 0;
}
engEvalString(ep, "x=0:0.01:2*pi;y=sin(x);plot(x,y);");
engEvalString(ep, "title('Matlab Drawing');");
engEvalString(ep, "xlabel('X');");
engEvalString(ep, "ylabel('Y');");
MessageBox(NULL, "Press any key …","MATLAB Draw",MB_OK);
engClose(ep);
return 1;
}
5 設(shè)置其它編譯連接選項(xiàng)
PreProcessor 加上: MATLAB_MEX_FILE
INCLUDE 加上: c:\matlab\extern\include
LIB 加上: c:\matlab\extern\include
最后,如果有必要的話,在DOS命令行運(yùn)行: MATLAB /regserver