Java 調用matlab 函數接口
Java調用matlab函數接口有兩種方式:
l 一種是通過matlab把函數打成jar包;
l 一種是把matlab編譯成dll後,用C++再封裝成java能支持的數據類型的dll。
注意:不論用這兩種方式中的哪一種,最終部署時都需要matlab環境(MCR,在matlab安裝路徑下有)。
1. 方式一:matlab直接打jar包
1.1. 利用matlab自帶工具打jar包
1.1.1. 建立jar包
在matlab的Commond Window中輸入deploytool回車,則會出現下圖:
Name即給jar包起個包名,建議填寫與項目名稱有關係的名稱;Location是打jar包的工程放到哪裏;Target選擇Java Package,如下圖:
點擊OK後會多出如下子窗口,則第一步工作完成。
1.1.2. 向jar包中添加類
Java是面向對象的,所以要封裝數據接口得先有個類。
點擊Deployment Tool窗口中的Add Class,填寫相應的類名,建議填寫模塊名稱,如圖:
1.1.3. 向類中添加函數接口
假設一個函數接口寫在一個m文件中,比如estimate_yaw.m中封裝了函數:
function [status] = estimate_yaw(station_id, turbine_id, year_num, month_num)
% 簡介: 計算指定風機在某段時間的偏航系統評分
% 輸入: station_id 場站編號,數值類型
% turbine_id 風機編號,數值類型
% year_num 用於計算偏航評分的數據的年份,數值類型
% month_num 用於計算偏航評分的數據的月份,數值類型
% 輸出: status 程序運行狀態
end
則點擊Deployment Tool窗口中的YawScore的類下面的Add Files,選擇要添加的數據接口對應的m文件,比如這裏是estimate_yaw.m,如圖即爲添加接口後的效果:
1.1.4. 編譯
點擊Deployment Tool窗口的編譯按鈕接口開始編譯jar包,如圖:
編譯完成後到第一步中填寫的Location中的路徑下會有個與jar包包名相同的文件夾,其中包含distrib和src子文件夾,而jar包就在src文件夾下。
注:如果編譯失敗,報找不到javac命令,意味着需要java環境。下載並安裝jdk,配置好JAVA_HOME和CLASSPATH環境變量後,需要重啓matlab。
1.2. Java調用jar包
Java調用matlab編譯的jar包還需要javabuilder.jar包做支持,在$(MATLABPATH)\ toolbox\javabuilder\jar\文件夾下。
Java在調用jar包中的接口時,第一個參數表示接口的返回參數個數,後面纔是matlab函數中的參數。另外,要注意數據類型對應,全部數據類型包括:
詳細的使用方法參見matlab的幫助文檔中的MATLAB Builder JA分支,如圖:
2. 方式二:通過C++封裝matlab編譯的dll
2.1. matlab編譯動態庫
64位電腦上安裝的matlab一般是64位的,那麼其matlab編譯器也是64位的,根據Matlab幫助文檔的提示,要想生成32位的動態庫,必須要有32位的Matlab編譯器,且編譯時要在DOS中編譯,增加參數-win32即可。如果系統本身就是32位的就不用考慮這些了。
如果第一次使用Matlab編譯動態庫,要先做準備工作:mex -setup 以及mbuild
Matlab編譯動態庫命令:mcc
ü 方式一:mcc -l model_hhl.m
ü 方式二:mcc -W cpplib:libModelHHL -T link:lib model_hhl.m
其中方式二中的libModelHHL 表示生成的lib文件的名稱。兩種方式的區別是:方式一生成的動態庫數據接口類型是mxArry,是C中的結構體,使用時需要注意內存管理;方式二生成的動態庫數據接口類型是mwArry,是C++中的類,使用時走的是面向對象思想,內存會隨着析構函數而釋放。如果不能很好的操作內存,一般建議用第二種。
編譯完成後,在m文件所在目錄下產生一堆文件中,需要的文件有三個:.h、.dll和.lib三個文件。三個文件的作用:.h是頭文件,向程序員說明數據接口是如何定義、如何調用的;.lib是庫文件,相當於索引,告訴機器到哪個位置去找哪個函數或者哪個類(函數和類都是dll導出的);.dll是二進制可執行文件,用來執行你封裝的程序的。
PS:將m文件編譯爲不依賴環境的exe方法:mcc -m program.m
2.2. C++封裝動態庫
Matlab編譯出dll後,把.h,.lib,.dll三個文件拷貝出來待用。
Windows下開發C++項目,一般選用VS/VC集成開發環境,配置環境相對便捷,其代碼補全的功能也令許多開發人員愛不釋手,所以這裏選擇使用VS開發封裝dll的C++項目。
2.2.1. 創建C++ dll工程並導出接口函數
在VS中新建項目時選擇win32項目,如圖:
注:如果想要編寫62位dll的話也是選擇win32項目,代碼編寫完以後配置編譯選項就可以了。
確定後,在win32應用程序嚮導中選擇應用程序類型爲DLL,附件選項選擇導出符號即可。
完成後系統會自動生成一個dll工程,裏面有幾個導出dll的例子,包括導出類,導出函數,導出變量,如下:
爲了便於java調用,建議導出函數時使用extern "C" LIBMATLABFUN_API而不是extern LIBMATLABFUN_API。後者導出的函數的函數名稱會被加入一些奇怪的符號,具體原因請參考《深度探索C++對象模型》。
2.2.2. C++開發環境——VS如何配置環境
創建工程後首先要配置好環境,保證你的程序能知道:
l 到哪裏找你需要調用的matlab編譯出的dll對應的lib文件;
l 你需要調用的matlab編譯出的dll對應的lib文件叫什麼名字(根據這個lib文件就可以找到dll模塊);
全部的系統默認的路徑在屬性頁中的VC++目錄中可以查看,如果.h和.lib文件不在這些路徑下,則要另外配置。那麼要配置什麼呢?其實很簡單!告訴VS到哪裏找頭文件(.h),到哪裏找庫文件(.lib)就行了。
ü 頭文件路徑配置
選中項目,右鍵菜單中選擇屬性 -> C/C++ -> 常規 -> 附件包含目錄
ü 庫文件路徑配置
選中項目,右鍵菜單中選擇屬性 -> 鏈接器 -> 常規 -> 附加庫目錄
選中項目,右鍵菜單中選擇屬性 -> 鏈接器 -> 輸入 -> 附加依賴項(把要用的庫文件名字加上,比如libModelHHL.lib,不用帶路徑)
配置路徑的時候可以使用絕對路徑,也可以使用相對路徑(用一個點表示當前目錄,用兩個點表示當前目錄的上一級,比如.\include\表示當前目錄下的include目錄)。爲了便於工程拷貝到其他電腦時配置環境方便,建議用相對路徑,但是一定要弄清楚當前工作目錄是什麼(創建項目的時候,選擇是否創建解決方案目錄對工作路徑是有影響的,一般可以通過項目自動生成的.h或者.cpp文件判斷當前路徑是什麼)。
爲了便於C++項目的維護,一般都會把頭文件專門放在.\include\中,把.lib文件放到.\lib\中,把.dll文件以及它所依賴的dll都放到當前項目生成的exe或者dll的目錄下。
另外,如果配置環境的時候用到系統環境變量,則要注意兩點:一個是,配置系統環境變量的時候不要加分號,否則在VS裏面用系統環境變量時會造成路徑分割,比如MatlabPath變量配的時候是D:\Program Files\MATLAB\R2010b\;那麼VS裏面$(MatlabPath)\extern\include\會變成D:\Program Files\MATLAB\R2010b\和\extern\include\兩個路徑;另一個是設置了系統環境變量後要重啓電腦,否則會出現問題;PS:如果設置了MatlabPath後,啓動Matlab出現??? Undefined function or variable 'matlabrc'錯誤提示,刪除MatlabPath後matlab就可以正常運行了。如果嫌麻煩,就把要用到的.h、.lib、.dll文件拷貝到工程目錄下後配置下環境。
配置環境的時候要注意配的是DEBUG還是RELEASE,是win32還是X64。一般配環境出現的問題無外乎以下三種:
l 找不到xxx.h文件
l 找不到xxx.lib文件
l 無法解析XXX 命令
找不到頭文件說明頭文件配置沒配置好,檢查一下附加包含目錄是否正確,或者頭文件是否存在;找不到lib文件說明庫文件沒配置好,檢查一下附加庫目錄對不對,或者lib文件是否存在;無法解析XXX命令多半是沒有配置lib文件,或者dll文件的問題,可能是dll文件找不到,可能是dll和對應的lib不是同一個版本,可能是與調用dll的程序平臺不一樣(32位或64位),一般從這幾個方向入手就可以找到問題所在。
使用C++封裝matlab生成的庫時,配置好環境時需要拷貝的頭文件如下:
配置好環境後,在代碼中要與matlab生成的dll接口交互,需要包含的頭文件:
#include "matrix.h"
#include "mclmcr.h"
注意,包含這兩個頭文件時,必須晚於包含matlab編譯dll時生成的頭文件,否則會報錯,不能識別mclInitializeApplication函數。
需要加載的庫:
mclmcrrt.lib
mclmcr.lib
如果環境配置好以後,報錯說無法解析xxx,請檢查matlab編譯的dll是32位還是64位,和應用程序編譯配置的位數是否一樣。
2.2.3. C++中如何調用dll動態庫
由於要用C++封裝matlab編譯的dll,那麼在C++中如何調用dll呢?
有三種方式:
l 配置環境的時候,在附加依賴項中已添加要用到的庫:那麼包含頭文件後就可以直接像調用同一個項目的類或者函數一樣調用了。
l 配置環境的時候,在附加依賴項中沒有添加要用到的庫,那麼在要用庫文件的cpp文件中包含頭文件,並使用comment說明要加載哪個庫。例如#pragma comment(lib,”xxx.lib”)
l 配置環境的時候,在附加依賴項中沒有添加要用到的庫,那麼在要用庫文件的cpp文件中使用windows函數加載動態庫。
具體使用哪種方式看項目實際情況或者個人喜好。
2.2.4. C++調用matlab編譯的dll中的接口時如何捕捉異常
try
{
//調用接口
}
catch(const mwException &e)
{
std::cerr<<e.what()<<std::endl;
}
catch(...)
{
}
2.2.5. C++中如何轉換數據類型與Matlab生成的動態庫數據接口匹配
使用C接口時數據類型的轉換方法:
l double -> mxArray
double turbine_id = 1;
mxArray *a;
double id_1[]={turbine_id};
a=mxCreateDoubleMatrix(1,1,mxREAL);
memcpy(mxGetPr(a),id_1,sizeof(double));
mxDestroyArray(a);
a=0;
l char* -> mxArray
const char* starttime = “2013-07-01 00:00:00”;
mxArray *st;
st=mxCreateString(starttime);
更多數據類型轉換可參考matlab幫助文檔中的說明,如下:
使用C++接口時數據類型的轉換方法:
l double -> mwArray
double turbineID = 1;
mwArray mTurbineID(1, 1, mxDOUBLE_CLASS);
mTurbineID.SetData(&turbineID,1);
l char* -> mwArray
const char* starttime = “2013-07-01 00:00:00”;
mwArray mStartTime(startTime);
mwArray還支持其他類型的數據,可參考matlab幫助文檔:
2.2.6. C++調用matlab dll的程序流程
主要是兩個環境的初始化與終止,一個是matlab環境,一個是dll接口。
//要使用matlab的東西,要先初始化matlab環境
mclInitializeApplication()
//要使用matlab編譯的dll,要先調用dll的初始化方法
//具體名字在matlab編譯生成的頭文件找
model_hhlInitialize()
//同上
model_hhlTerminate()
mclTerminateApplication()
需要注意mclInitializeApplication不可以重複調用,如果需要重複執行dll內容,可以使用全局變量判斷是否已經初始化,再確定是否需要執行mclInitializeApplication函數初始化。
2.2.7. 如何在C++中調試dll
在測試程序的工程中,選中解決方案,在右鍵菜單中選擇添加已有項目,把dll的那個工程加進來,最主要的是要保證dll工程生成的pdb調試文件要能被測試程序的工程找到纔可以調試dll工程。
2.3. Java調用dll
Java調用dll有多種方法,主要是兩類:
1、Jni
2、Jna或者Jnative之類的第三方庫
網上有比較多的例子,包括數據類型轉換,自行查找相關資料。
附件是兩種方案的demo。或者可以到http://down.51cto.com/data/1871622 處下載本文以及demo。