基于Qt與MATLAB的混合編程技術(shù)
摘要:在Qt雷達仿真系統(tǒng)中,數(shù)據(jù)處理及圖形顯示尤為重要。本文為此提出了一種Qt與MATLAB混合編程的方法。通過VC++和MATLAB混合編程技術(shù),將MATLAB函數(shù)封裝成動態(tài)鏈接庫,Qt調(diào)用這個動態(tài)鏈接庫實現(xiàn)圖形處理功能,從而改善Qt界面中雷達信號仿真問題。
本文引用地址:http://m.butianyuan.cn/article/201609/310493.htm引言
Qt是一個跨平臺的C++圖形用戶界面應(yīng)用程序開發(fā)框架。它包括跨平臺類庫、集成開發(fā)工具和跨平臺IDE[1]。由于強大的跨平臺特性,使用Qt只需一次性開發(fā)應(yīng)用程序,無須重新編寫源代碼,便可跨桌面和嵌入式操作系統(tǒng)運行。在圖形處理方面,Qt提供了用于2D繪圖的QPainter繪圖類和第三方繪圖庫Qwt,可以繪制簡單的圖形,但其過程復(fù)雜、設(shè)置繁瑣,且操作過程不易實現(xiàn)。
MATLAB作為一種高性能的數(shù)值計算和可視化軟件,它集數(shù)值分析、矩陣運算、信號處理和圖形顯示于一體, 構(gòu)成了一個方便、界面友好的用戶環(huán)境。相比Qt而言,MATLAB有非常強大的圖形化顯示矩陣和數(shù)組的能力,用MATLAB生成的圖形可輕松實現(xiàn)添加文字說明、標(biāo)注坐標(biāo)軸、曲線注釋等多種功能,而這些若由Qt來實現(xiàn)則較為復(fù)雜。針對Qt的繪圖缺點,提出了Qt與MATLAB混合編程技術(shù),主要包括兩種方法:Qt調(diào)用MATLAB的引擎和Qt調(diào)用MATLAB生成的動態(tài)鏈接庫。Qt調(diào)用MATLAB引擎加入大量MATLAB庫,功能十分強大,但其編程量巨大,運行效率較低,不利于開發(fā)使用。而使用MATLAB生成的動態(tài)鏈接庫使程序可以脫離MATLAB環(huán)境獨立運行,節(jié)省程序所占用的內(nèi)存資源,提高了程序的執(zhí)行效率。當(dāng)然,由于MATLAB7.0前后不同版本編譯器的不同特點,混合編程方法也會有所不同。下面本文將詳細介紹如何將MATLAB函數(shù)轉(zhuǎn)換為Qt可用的DLL的方法,并應(yīng)用到Qt雷達仿真系統(tǒng)工程中。
1 Qt圖像顯示窗口
1.1 顯示窗口
Qt可以使系統(tǒng)獲得高效的工作性能,是因為它擁有一個重要機制——信號和槽機制[2]。信號和槽用于兩個對象之間的通信,信號和槽機制是Qt的核心特征,也是Qt不同于其他開發(fā)框架最突出的特征。QWidget類是所有用戶界面對象的基類,是Qt中建立用戶界面的主要元素。在雷達仿真系統(tǒng)中,將圖形顯示模塊作為一個封裝的窗口組件嵌入到系統(tǒng)中,窗口組件主要以窗口部件QWidget為基類,嵌入MATLAB的Figure窗口[3],使用信號和槽等實現(xiàn)數(shù)據(jù)處理和圖形繪制。
1.2 繪圖需求
隨著雷達技術(shù)的不斷發(fā)展,雷達系統(tǒng)的復(fù)雜度與日俱增,雷達系統(tǒng)的設(shè)計越來越多地借助仿真來提高工作效率。一套完整的Qt雷達仿真系統(tǒng)必不可少的就是圖形顯示,用于直觀地觀測雷達各個模塊的波形及運動軌跡。Qt提供了2D繪圖系統(tǒng)[2],可以使用API在屏幕和繪圖設(shè)備上進行繪制,主要基于QPainter、QPaintDevice和QPaintEngine這3個類,其中QPainter用來執(zhí)行繪圖操作,QPaintDevice提供繪圖設(shè)備,QPaintEngine提供了一些接口。同時,Qt的第三方繪圖庫QWT可生成各種統(tǒng)計圖,它的目標(biāo)是以基于2D方式的窗體部件來顯示數(shù)據(jù)。然而這兩種繪圖方法的編程過程比較復(fù)雜,尤其在處理大量數(shù)據(jù)和三維圖形顯示時更是難以實現(xiàn)。MATLAB有強大的圖形化顯示矩陣和數(shù)組的能力,同時也能給圖形增加注釋并且打印這些圖形。它既包括一些方便地產(chǎn)生二維、三維技術(shù)專業(yè)圖形的高級繪圖函數(shù),也包括一些可以使用戶靈活控制圖形特點的低級繪圖命令。另外,用戶還可以利用MATLAB的句柄圖形技術(shù)創(chuàng)建圖形用戶界面[4]。這種語言可移植性好、可拓展性極強,所以采用Qt與MATLAB混合編程的方法,才能實現(xiàn)強大的圖形處理功能。圖1為雷達目標(biāo)檢測仿真結(jié)果圖。
2 Qt調(diào)用動態(tài)鏈接庫
2.1 Qt調(diào)用動態(tài)鏈接庫流程
Qt調(diào)用動態(tài)鏈接庫主要有兩種選擇方案,一種是利用VC++調(diào)用MATLAB生成的獨立可執(zhí)行的C++函數(shù)文件創(chuàng)建集成的繪圖動態(tài)鏈接庫,Qt窗口組件來調(diào)用它;另一種是Qt直接調(diào)用MATLAB生成的獨立可執(zhí)行的C++函數(shù)文件創(chuàng)建集成的繪圖動態(tài)鏈接庫,然后Qt窗口組件使用這個動態(tài)鏈接庫文件。由于VC++與MATLAB混合編程技術(shù)相對比較成熟,并得到廣泛應(yīng)用,所以我們選用第一種方案。圖2展示了在Qt中調(diào)用動態(tài)鏈接庫的步驟。
2.2 VC++動態(tài)鏈接庫嵌入到Qt中
Qt窗口組件調(diào)用VC++動態(tài)鏈接庫,實現(xiàn)繪圖和圖形顯示功能,在工程目錄中添加上述dllMATLAB.h、dllMATLAB.dll和dllMATLAB.lib文件。在工程的管理文件.pro中加載需要連接的動態(tài)鏈接庫,添加代碼“LIBS+= -L ./ -ldllMATLAB”。在頭文件中添加動態(tài)鏈接庫提供的頭文件的“dllMATLAB.h”。這樣我們就可以調(diào)用MATLAB函數(shù)庫中的繪圖相關(guān)函數(shù),對數(shù)據(jù)進行圖形處理了。
但是調(diào)用顯示的Figure窗口卻是單獨顯示的,與Qt中窗口組件不一致,為使界面風(fēng)格統(tǒng)一,用戶界面美觀,我們需要將MATLAB的Figure窗口嵌入到Qt窗口組件中。這種方法的基本思路是去除MATLAB 的Figure窗口的標(biāo)題欄及邊框,然后把它移動到Qt窗口組件中,同時設(shè)定Qt窗口組件為父窗口。具體由以下代碼實現(xiàn)。獲取MATLAB 的Figure窗口句柄:
HWND hfigure =FindWindow(NULL,str.toStdWString().c_str());
獲得Qt窗口組件的句柄:
HWND centralWidget = (HWND)(this->winId());
設(shè)定Qt窗口組件為Figure窗體的父窗體:
if(NULL==::SetParent(hfigure, centralWidget))
2.3 創(chuàng)建VC++動態(tài)鏈接庫
要想在Qt中調(diào)用MATLAB的各種繪圖函數(shù),滿足工程需要,使用動態(tài)鏈接庫無疑是最好的選擇。
動態(tài)鏈接庫[6]是Windows操作系統(tǒng)中實現(xiàn)共享函數(shù)庫概念的一種方式,使進程可以調(diào)用不屬于其可執(zhí)行代碼的函數(shù)。DLL可以采用多種編程語言來編寫。例如,可以利用Qt來編寫程序界面,然后調(diào)用VC++編寫的完成繪圖功能的DLL。動態(tài)鏈接庫有助于共享數(shù)據(jù)和資源,簡化項目管理,節(jié)省磁盤空間和內(nèi)存,更易于升級。
2.4 MATLAB數(shù)據(jù)類型與VC++數(shù)據(jù)類型相互轉(zhuǎn)化
我們知道在MATLAB當(dāng)中運算都是基于矩陣的,因此,在VC++中調(diào)用MATLAB函數(shù)時,無論函數(shù)的返回值、參數(shù)必須是矩陣類型(mwArray)[7],而在C++當(dāng)中的二維數(shù)組可以看成一個矩陣,在VC++當(dāng)中可以用下面的函數(shù)將數(shù)組轉(zhuǎn)化成MATLAB中的矩陣類型。例如data= new double[m*n],可以用mwArray mwdata(m,n,data);這樣就可以將二維數(shù)組變量轉(zhuǎn)化成mwArray 類型,進而可以作為MATLAB函數(shù)的參數(shù)。反之,把mwArray 類型的變量轉(zhuǎn)化成C++中的二維數(shù)組:例如存在mwArray 變量mwdata,用函數(shù)size獲得矩陣的大小,row=size(&col,mwdata),其中row,col是函數(shù)的返回值,data=new double[row*col];data.ExtractData(mwdata); 這樣就可以把mwArray類型轉(zhuǎn)化成數(shù)組類型。另外,用GetData()和mxGetPr、mxGetPi組合可以得到指向mwArray對象的指針。
3 VC++和MATLAB混合編程
3.1 VC++與MATLAB混合編程步驟
在工程實踐中,VC++調(diào)用MATLAB 的方法主要有兩種:調(diào)用MATLAB計算引擎和調(diào)用MATLAB生成獨立可執(zhí)行的C++函數(shù)文件。為滿足工程需要,選擇第二種方法。
3.1.1 在MATLAB中進行編譯器設(shè)置
MATALB編譯器是一個運行于MATLAB環(huán)境的獨立工具。其主要功能是把M程序轉(zhuǎn)換成C/C++代碼,然后再調(diào)用外部C/C++編譯器,把產(chǎn)生的源代碼編譯、鏈接成用戶指定的格式[4]。
需要在MATLAB環(huán)境中配置外部C/C++編譯器,在MATLAB命令環(huán)境行輸入mbuid-setup設(shè)置要用到的C/C++編譯器。輸入mex-setup對MEX文件進行配置編譯。
3.1.2 新建M文件并編譯
(1)建立M文件,將工程中需要用到的數(shù)學(xué)函數(shù)庫和圖形庫中的常見函數(shù)plot、mesh、hist、image、figure、fft、contour、set、get等函數(shù)編寫成M函數(shù)。功能相同的函數(shù),參數(shù)個數(shù)不同時要視為兩個不同函數(shù)。
(2)利用mcc命令編譯M文件,在MATLAB環(huán)境中使用mcc命令將M文件編譯成可獨立執(zhí)行的C++函數(shù)文件。
3.1.3 在VC++中進行編譯環(huán)境設(shè)置
首先設(shè)置系統(tǒng)變量,在系統(tǒng)環(huán)境的用戶變量添加MATLAB及VC++軟件的安裝目錄。然后在VC++設(shè)置編譯環(huán)境:
(1)添加MATLAB庫的頭文件和庫函數(shù)的路徑;
(2)設(shè)置運行時動態(tài)鏈接庫;
(3) 導(dǎo)入靜態(tài)鏈接庫文件。
3.1.4 創(chuàng)建動態(tài)鏈接庫
動態(tài)鏈接庫是將功能封裝在一起的模塊,因此,與代碼直接寫入調(diào)用模塊中相比,它不僅可以提高程序的復(fù)用,減少代碼開發(fā)工作量,同時也可以節(jié)省內(nèi)存,提高代碼利用率。
VC++調(diào)用MATLAB混合編程生成可以獨立運行的C++代碼,創(chuàng)建動態(tài)鏈接庫,通過靜態(tài)加載或動態(tài)加載的方式來使用DLL。新建一個空的動態(tài)鏈接庫工程,添加一個頭文件dllMATLAB.h和源文件dllMATLAB.cpp。將mcc編譯后生成的C++文件添加到項目中,對MATLAB中M文件中的函數(shù)重新定義,滿足MATLAB數(shù)據(jù)類型與VC++數(shù)組類型相互轉(zhuǎn)化。編譯生成dllMATLAB.dll和dllMATLAB.lib文件。這樣其他應(yīng)用程序只需將dllMATLAB.h、dllMATLAB.dll、dllMATLAB.lib添加到工程目錄中就可以使用這個動態(tài)鏈接庫,實現(xiàn)調(diào)用MATLAB的繪圖功能了。
3.2 MATLAB不同版本的區(qū)別
值得注意的是,不同MATLAB軟件版本導(dǎo)致混合編程的方法不同。與之前版本相比,MATLAB7.0之后的版本的編譯器發(fā)生了較大變化。其主要新特點及變化包括以下兩個方面:一、不再提供C++數(shù)字庫和圖形庫;二、不再編譯所有的M函數(shù),只是產(chǎn)生必要的C/C++接口函數(shù)。
所以VC++調(diào)用不同版本的MATLAB的動態(tài)鏈接庫的過程也有很大差別,具體表現(xiàn)在三個方面。
3.2.1 mcc命令及編譯產(chǎn)生C++文件不同
MATLAB7.0之前的版本編譯命令為:mcc - B sglcpp (文件名),參數(shù)“ - B sglcpp ”含義是將. m文件編譯成為C++代碼,生成.cpp和.hpp文件,提供圖形庫支持, 并編譯為獨立運行的exe程序。
MATLAB7.0之后版本使用mcc命令。假設(shè)要把M文件編譯成C語言動態(tài)鏈接庫文件“mcc -W lib:(對應(yīng)鏈接庫名稱) -T link:lib (文件名M)”。假設(shè)要把M文件編譯成C++語言動態(tài)鏈接庫文件:“mcc -W cpplib:(對應(yīng)鏈接庫名稱) -T link:lib (文件名M)”。這里我們采用第二種方法編譯運行之后,在目錄下面將會出現(xiàn)以下以.lib、.dll、.exports、.exp、.h和.cpp為后綴的6個文件。
3.2.2 在VC++工程中頭文件及初始化設(shè)置等不同
在MATLAB7.0以前,在VC++程序中使用MATLAB編譯器產(chǎn)生代碼時,必須在VC++源程序中分別包含MATLAB.hpp。從MATALB7.0起,MATLAB的編譯器不再提供MATLAB.hpp,代之以mclmcr.h。
另外,在調(diào)用MATLAB初始化設(shè)置時,MATLAB7.0以前采用以下代碼:
void initialMATLAB() //初始化設(shè)置
{ libmmfileInitialize();//初始化MATLAB數(shù)學(xué)庫
libmwsglmInitialize();//初始化MATLAB圖形庫
mlfHGInitialize(NULL,NULL);}
MATLAB7.0之后版本編譯產(chǎn)生的動態(tài)鏈接庫,對每個M文件都有初始化及釋放設(shè)置,也就是說不需要整體的初始化及釋放設(shè)置,只需對使用的函數(shù)進行初始化,具體參考MATLAB幫助。
3.2.3 程序發(fā)布方法有所不同
由于程序中調(diào)用了MATLAB 數(shù)學(xué)函數(shù)庫或圖形庫中的函數(shù),MATLAB7.0之前版本需要附帶MATLAB的這些函數(shù)庫才能在沒有安裝MATLAB 的機器上運行。以MTALAB6.5為例,我們需要收集libmmfile.dll、libmwservices.dll、libut.dll等函數(shù)庫,并將這些文件添加到應(yīng)用程序Debug目錄或者Release目錄下,這樣程序就可以未裝MATLAB軟件的機器上運行,簡化了MATLAB與C/C++的混合編程,可移植性強。
MATLAB7.0之后版本的編譯器不再提供C++數(shù)字庫和圖形庫,而是使用MATLAB組件運行環(huán)境MCR(一組標(biāo)準(zhǔn)的動態(tài)鏈接庫),它提供了運行編譯后的程序所需的基本環(huán)境[4]。所以要想程序發(fā)布到別的沒有安裝MATLAB的計算機上使用,必須在目標(biāo)計算機上安裝MCR,其文件位于MATLAB 安裝目錄的externlibwin32子目錄MCRInstaller.exe,運行MCRInstaller.exe程序即可自動把需要的庫函數(shù)解壓到當(dāng)前目錄中,這樣程序就可以脫離MATLAB運行。
通過對比發(fā)現(xiàn),不同版本各有優(yōu)勢,在我們的工程項目中選用了MATLAB6.5,這樣要想發(fā)布VC++創(chuàng)建的動態(tài)鏈接庫只需收集庫文件,雖然收集過程復(fù)雜,但是可移植性強,靈活性高,用戶操作簡單。
4 總結(jié)
本文采用Qt與MATLAB混合編程的方法滿足了Qt工程中對數(shù)據(jù)處理和圖形顯示的要求,增強了Qt的繪圖功能。經(jīng)過項目的實踐,調(diào)用MATLAB生成的可獨立執(zhí)行的動態(tài)鏈接庫在項目中得到了較好的應(yīng)用。當(dāng)然,集成的動態(tài)鏈接庫還需要進一步地完善來滿足不同的項目對繪圖及復(fù)雜數(shù)值運算的要求,為用戶提供功能強大的開發(fā)平臺。由于Qt優(yōu)良的跨平臺特性和MATLAB的圖形處理功能,相信未來Qt與MATLAB的混合編程在嵌入式系統(tǒng)的應(yīng)用前景會更加廣闊。
參考文獻:
[1]霍亞飛.Qt Creator快速入門(第2版)[M].北京:北京航空航天大學(xué)出版社,2014.
[2]丁林松,黃麗琴.Qt4圖形設(shè)計與嵌入式開發(fā)[M].北京:人民郵電出版社,2009.
[3]張亮,王繼陽等.MATLAB與C/C++混合編程[M].北京:人民郵電出版社,2008.
[4]董維國.深入淺出MATLAB7.x混合編程[M].北京:機械工業(yè)出版社,2005.
[5]魏鑫,陳輝強,高飛.Qt與MATLAB的混合編程究與實現(xiàn)[J].計算機與現(xiàn)代化,2010,9(1):168-170.
[6]孫鑫,余安萍.VC++深入詳解[M].北京:電子工業(yè)出版社,2006.
[7]劉維.精通MATLAB與C/C++混合程序設(shè)計(第2版)[M].北京:北京航空航天大學(xué)出版社,2008.
[8]馬興義.MATLAB6應(yīng)用開發(fā)指南[M].北京:機械工業(yè)出版社, 2002.
[9]張明友,汪學(xué)剛.雷達系統(tǒng)(第2版)[M].北京:電子工業(yè)出版社,2006.
本文來源于中國科技期刊《電子產(chǎn)品世界》2016年第9期第57頁,歡迎您寫論文時引用,并注明出處。
評論