周小娟
(西安外事學(xué)院 計算機中心,陜西 西安 710077)
Matlab是一款優(yōu)秀的,功能強大的科學(xué)計算軟件,它為航空航天,控制,機械,電子,電力,生物,財務(wù)等眾多領(lǐng)域提供功能強大的數(shù)值計算和仿真工具。Matlab環(huán)境下的M語音,簡單靈活,使用方便,但做為一種編程語言,在圖形界面開發(fā)方面和Java,C++等高級語音相比卻顯得不夠強大。Matlab雖然提供了一些圖形開發(fā)功能,并且利用這些功能開發(fā)相對簡單的圖形界面也很受歡迎,但對于稍微復(fù)雜一些的圖形界面和大型專業(yè)的軟件產(chǎn)品,這些功能就無法實現(xiàn)了。因此在大型專業(yè)軟件產(chǎn)品開發(fā)中,必須研究一種新的開發(fā)方法,將Java,C++等高級語言的圖形界面開發(fā)優(yōu)勢和Matlab數(shù)據(jù)計算和仿真的優(yōu)勢結(jié)合起來,開發(fā)更為專業(yè)的軟件產(chǎn)品。幸運的是,Matlab已經(jīng)提供了和Java,C,C++等高級開發(fā)語言的接口,因此將Matlab程序整合進Java,C,C++程序是可行的。
Matlab提供將M程序編譯為C/C++動態(tài)庫或者Java包的功能。 在Deployment Tool中用戶可以選擇要編譯的M文件以及編譯結(jié)果的類型,然后Deployment Tool將調(diào)用編譯器mcc(MATLAB COMPILER COMMAND)對目標文件進行編譯。mcc具有將M文件編譯為C/C++動態(tài)庫,Java包,可執(zhí)行文件的能力,是Matlab和其它語言混合編程中必須使用的一個工具。Matlab還提供另外一個工具mbuild將C/C++程序編譯為可執(zhí)行文件或者動態(tài)庫,mbuild內(nèi)部將調(diào)用操作系統(tǒng)已經(jīng)安裝的編譯器進行編譯。
Java語言具有優(yōu)秀的圖形界面開發(fā)能力,常用的圖形開發(fā)庫有基于 AWT(Abstract Window Toolkit)的 Java-Swing 開發(fā)技術(shù)和基于 SWT(Standard Widget Toolkit)的 Eclipse開發(fā)技術(shù)。AWT具有和Java類似的和操作系統(tǒng)無關(guān)的特征,因此在Windows上開發(fā)的AWT程序,在Linux上運行具有相同的界面風(fēng)格。SWT使用操作系統(tǒng)提供的圖形界面,和程序運行的操作系統(tǒng)具有直接關(guān)系,因此在Windows上開發(fā)的SWT程序,具有Windows操作系統(tǒng)的風(fēng)格,在Linux上運行時具有Linux操作系統(tǒng)的風(fēng)格。因為SWT直接調(diào)用的是操作系統(tǒng)本身的圖形庫,因此SWT可以提供完全的圖形界面,功能比AWT要強大的多。本文將使用SWT在W indowsXP操作系統(tǒng)上進行Java程序圖形界面的開發(fā)。
在Java中調(diào)用Matlab程序有兩種方法:1.將Matlab程序編譯為Java包,然后在Java程序中調(diào)用Java包中的類和方法;2.將Matlab程序編譯為C/C++動態(tài)庫,然后通過JNI(Java Native Interface)在Java程序中調(diào)用。第一種方法的實施比較簡單,直接在Matlab中調(diào)用Deployment Tool就可以完成;第二種方法的實施比較復(fù)雜一些,需要編寫Java Native類和C/C++代碼,但在執(zhí)行效率方面具有優(yōu)勢。因此在這兩種方法的選擇上以程序的規(guī)模和效率為參考進行,如果Matlab程序的規(guī)模比較小,處理的數(shù)據(jù)量比較小,可以選擇第一種方法,反之選擇第二種方法。對于執(zhí)行效率比較重要的程序來說,可以用兩種方法來實現(xiàn)混合編程,然后通過對比選擇效率高的一種方法進行實施。下面對這兩種方法的實現(xiàn)過程分別進行描述。
將Matlab程序編譯為Java包,然后在Java程序中調(diào)用Java包中的類和方法,這種混合編程方法相對比較簡單。具體步驟如下:
1)在Matlab命令行輸入deploytool啟動Deployment Project對話框。
2)在對話框中輸入編譯項目名稱及其位置,并選擇Java Package為編譯類型。
圖1 創(chuàng)建編譯項目Fig.1 Create a deployment project
3)在Java Package頁面中,通過添加類為要生成的Java類命名,然后通過添加文件為這個類添加相關(guān)的M文件。
圖2 為編譯項目命名要創(chuàng)建的Java類并添加M文件Fig.2 Add Java class and M files for the deployment project
4)點擊Java Package頁面右上方的Build按鈕進行編譯。
編譯完成后,在編譯項目所在目錄將生成一個以編譯項目名稱命名的目錄,在這個目錄內(nèi)有兩個子目錄distrib和src。distrib子目錄放置編譯好的Java包和幫助文檔,這些都是我們期望的結(jié)果,其中Java包就是混合編程中Java一方需要用到的唯一文件。src子目錄內(nèi)放置的是Java包中類的代碼文件,這些文件是中間產(chǎn)物,混合編程中Java一方不需要這些文件。因此一般不需要關(guān)心src子目錄中的產(chǎn)物。
混合編程中在Matlab一方編譯生成Java包后,Matlab的編程任務(wù)就完成了。下面需要在混合編程中Java一方調(diào)用該Java包中的類和方法。具體的調(diào)用方法如下,
1)將Matlab生成的Java包包含在Java項目的classpath中。這就保證了Java包中的類在當(dāng)前Java項目內(nèi)可以訪問到;
2)在調(diào)用Matlab算法的Java類文件中導(dǎo)入com.mathworks.toolbox.javabuilder.*和MATLAB編譯生成的Java類;
import com.mathworks.toolbox.javabuilder.*;
import rankine_package.*;
3)在調(diào)用Matlab算法的Java類文件就可以直接使用MATLAB編譯生成的類了;
rankineClass MLRankine=new rankineClass();
Object[]Output=MLRankine.rankine(1, Input);
這個例子中,rankineClass就是在Matlab中編譯生成的Java類,其方法rankine()就是M文件rankine.m中實現(xiàn)的Matlab算法,第一個參數(shù)的值1表示這個算法的返回值只有一個。
將Matlab程序編譯為C/C++動態(tài)庫,然后在C/C++程序中調(diào)用該動態(tài)庫生成另外一個動態(tài)庫,最后通過JNI(Java Native Interface)在Java程序中調(diào)用Matlab程序中的函數(shù)對應(yīng)的C/C++函數(shù),這種混合編程方法相對比較復(fù)雜。具體步驟如下:
1)首先必須選擇并設(shè)置Matlab中mcc和mbuild在編譯時使用的C/C++編譯器。通過在Matlab中輸入 “mbuild–setup”,Matlab會把當(dāng)前操作系統(tǒng)已經(jīng)安裝的C/C++編譯器列出來,這時候只需要選擇要使用的一個編譯器就可以了。如果當(dāng)前系統(tǒng)沒有安裝任何編譯器,需要安裝一個。在Linux操作系統(tǒng)上,可以安裝gcc。在Windows操作系統(tǒng)上,可以安裝Microsoft Visual Studio for C/C++。
2)在設(shè)置好編譯器后,就可以啟動deployment tool將要使用的M文件編譯為C/C++動態(tài)庫了。編譯過程和2.1節(jié)一樣,只不過編譯類型需要選擇C動態(tài)庫,或者C++動態(tài)庫。編譯結(jié)果中distrib目錄中有4個結(jié)果文件在后續(xù)的步驟中要用到:一個*.dll文件,這是編譯的結(jié)果動態(tài)庫包含MATLAB程序?qū)?yīng)的函數(shù);一個*.h文件,動態(tài)庫中函數(shù)的列表,在調(diào)用動態(tài)庫的程序中需要用到;一個*.lib文件,動態(tài)庫對應(yīng)的靜態(tài)庫;一個*.exports文件,羅列了所有*.h中的函數(shù)名稱。在*.h文件中,每一個Matlab程序的函數(shù)都有一個對應(yīng)的C/C++函數(shù),除此之外,還有兩個函數(shù)也必須被用到,它們是xxxInitialize()和 xxxTerminate(),其中 xxx 是編譯項目的名稱。xxxInitialize()必須在調(diào)用任何Matlab函數(shù)對應(yīng)的C/C++函數(shù)之前調(diào)用,xxxTerminate()必須在所有調(diào)用完成后,程序結(jié)束前調(diào)用。
3)在編譯完 Matlab程序后,就可以進行 JNI(Java Native Interface)程序的開發(fā)了,通過JNI程序?qū)崿F(xiàn)在Java圖形界面程序中調(diào)用C/C++動態(tài)庫。
①首先必須在Java圖形界面程序中聲明一個Java類包含若干native方法。這些native方法中,必須有兩個native方法分別和 xxxInitialize()和 xxxTerminate()對應(yīng),其它的 native方法分別和*.h中要被用到的函數(shù)對應(yīng)。下面就是一個這樣的類聲明的例子,
在這個例子中,通過System.load()函數(shù)裝載的C/C++動態(tài)庫libjnirankine.dll就是JNI要生成的動態(tài)庫。這個動態(tài)庫實現(xiàn)了這個Java類中的所有native函數(shù),而這些native函數(shù)分別調(diào)用了Matlab程序編譯結(jié)果動態(tài)庫中的函數(shù)。
圖3 一個包含native函數(shù)的Java類的例子Fig.3 A Java class example with native methods
②通過javac命令將這個Java類進行編譯生成jniRankine.class,然后調(diào)用javah–jni jniRankine生成一個*.h文件jniRankine.h。javah工具將所有native函數(shù)轉(zhuǎn)化為了JNI中的C/C++函數(shù)。這時候需要開發(fā)者手動生成一個jniRankine.c或者jniRankine.cpp來實現(xiàn)jniRankine.h中的所有函數(shù)。jniRankine.c或者jniRankine.cpp必須包含Matlab程序編譯結(jié)果中的*.h文件,然后在jniRankine.c或者jniRankine.cpp中的各個函數(shù)中調(diào)用對應(yīng)的Matlab程序編譯結(jié)果中的C/C++函數(shù)。這樣就完成了JNI的編程。最后通過在Matlab中運行如下mbuild命令編譯jniRankine.h以及jniRankine.c或者jniRankine.cpp,并鏈接Matlab程序編譯結(jié)果庫,生成 libjnirankine.dll,
mbuild-I“C:Program FilesJavajdk1.7.0_05include” -I“C:Program FilesJavajdk1.7.0_05includewin32” jnirankine.cpp rankineDll.exports rankineDll.lib
-link shared-output libjnirankine
在這個命令中I參數(shù)后面是JDK的安裝路徑,rankine Dll.exports和rankineDll.lib是Matlab程序編譯的結(jié)果,libjnirankine是編譯結(jié)果。
③最后在Java圖形界面程序中就可以像使用一般的Java類一樣調(diào)用jniRankine類中的方法進而應(yīng)用Matlab程序中的算法了。必須保證Matlab編譯結(jié)果中的*.dll文件在java.library.path中可以找到。
文中使用第1章中描述的兩種方法分別實現(xiàn)了計算理想朗肯循環(huán)的熱力學(xué)性質(zhì)的程序,程序比較簡單,方便讀者明白程序結(jié)構(gòu)和流程。程序的開發(fā)環(huán)境為Eclipse和Matlab。在開發(fā)機器上安裝了JDK1.7.0_05來支持Eclipse環(huán)境和第一種方法中的Java包的編譯;在開發(fā)機器上還安裝了Microsoft Visual Studio10.0 for C++來支持第二種方法中C++程序的編譯。
圖4 理想朗肯循環(huán)的熱力學(xué)性質(zhì)計算程序的圖形界面Fig.4 GUI of thermodynamic efficiency of Ideal Rankine Cycle calculating program
程序的界面通過使用SWT圖形開發(fā)技術(shù)開發(fā),如圖4所示,在WindowsXP操作系統(tǒng)上運行時,SWT程序界面風(fēng)格和WindowsXP保持一致。在窗口的左邊部分是計算時的輸入?yún)?shù),“Load Defaults”按鈕會自動給各個輸入?yún)?shù)填充默認值。點擊 “Calculate”按鈕程序就會調(diào)用Matlab程序的算法進行熱力學(xué)性質(zhì)的計算,并將計算結(jié)果顯示在窗口的右半部分的輸入框中。
Matlab的基本構(gòu)成和功能決定了Java-Matlab混合編程的可行性,利用這種混合開發(fā)技術(shù)可以開發(fā)出功能強大,界面友好,具有良好擴展性和維護性的模塊化的科學(xué)計算程序。這種混合開發(fā)技術(shù)可以使得進行圖形界面開發(fā)的Java程序員和進行數(shù)值運算開發(fā)的Matlab程序員分離開來,彼此專注于自己擅長的方面,降低的開發(fā)難度,提高了開發(fā)效率。
[1]Hanselman D,Littlefield B.精通MATLAB7[M].北京:清華大學(xué)出版社,2006.
[2]李傳軍.C語言與MATLAB接口--編程與實例[M].北京:北京郵電大學(xué)出版社,2004.
[3]羅星月.Matlab與C語言程序的應(yīng)用編程接口[EB/OL].(2007).http://www.builder.com.cn/2007/1030/591033.shtml.
[4]Muller Held.JMatLink[EB/OL].(2006).www.held-muellerde/JMatLink/.
[5]The Mathworks,Inc.Matlab幫助文檔:Matlab builder for Java[S].2007
[6]廖云伢,王建新,盛羽.基于Java與Matlab集成的虛擬實驗平臺的設(shè)計與實現(xiàn)[J].計算機應(yīng)用,2007,27(2):394-399.LIAO Yun-ya,WANG Jian-xin,SHENG Yu.Design and implementation of virtual lab platform based on integration of java and matlab[J].Journal of Computer Applications,2007,27(2):394-399.
[7]張崇明,汪春梅,朱品昌,等.使用Java擴展Matlab[J].計算機工程與設(shè)計,2006,27(9):1563-1565.ZHANG Chong-ming,WANG Chun-mei,ZHU Pin-chang,et al.Extending matlab using java[J].Computer Engineering and Design,2006,27(9):1563-1565.