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