問題引入
在做實驗的時候,需要用到python和matlab工具來進行不同的處理,比如在run神經網絡的時候,需要使用pytorch框架得到網絡的各個參數,在得到參數后需要使用matlab進行聚類規划。之前的做法是用python腳本耦合其聯系,兩者通信的方式是通過文件。后來發現matlab有針對於python的api引擎,瞬間感覺打開了新世界的大門,只需要在python中調用相關的api,就可以完成matlab的工作,再也不用一個一個復制文件了。
解決思路
首先,我安裝的是matlab R2015b,對應的python版本為3.4,本來一開始的版本是python36,但是由於matlab2015並不兼容py36,解決方法是,一方面可以通過重新安裝高版本的matlab來解決,在高版本的matlab中已經使用了py36的接口。另一方面可以通過修改python版本來實現,通過anconda,可以很簡便地安裝一個新的py版本,具體的使用情況可以查看conda的幫助文檔。
1. 安裝matlab engine的py package
在matlab的官方幫助文檔里:https://ww2.mathworks.cn/help/matlab/matlab_external/install-the-matlab-engine-for-python.html,可以找到
cd "matlabroot/extern/engines/python" python setup.py install
即切換到對應matlab的engines目錄,然后運行安轉腳本。需要注意的是,在安裝之前需要切換py版本到3.4,否則默認是base的python,那樣會出現錯誤。
2. 在py腳本里調用matlab engine
在matlab 文檔 里https://ww2.mathworks.cn/help/matlab/matlab_external/get-started-with-matlab-engine-for-python.html,聲明了對應的matlab engine的啟動和使用,其中包含了matlab數據和python數據類型的對應關系。
在文檔https://ww2.mathworks.cn/help/matlab/matlab_external/call-matlab-functions-from-python.html里,可以更詳細地看到如何使用matlab engine:
import matlab.engine eng = matlab.engine.start_matlab() tf = eng.isprime(37) print(tf) #True
上述的例子是調用了matlab'的判斷素數的接口,首先需要在py文件里導入對應的matlab engine包,然后調用start_matlab()來啟動引擎,然后使用引擎來得到返回值,需要注意的是,eng下的函數調用不會有提示,需要參照matlab的接口。
上述的是有返回值的調用,當函數具有多個返回值時,那么對應的調用方式如下:
import matlab.engine eng = matlab.engine.start_matlab() t = eng.gcd(100.0,80.0,nargout=3) print(t)
注意當使用具有多個返回值函數的時候,會返回一個python cell,對於含有矩陣的數據,會轉換成python的list數據。
當函數沒有返回值時,需要使用以下的方式調用:
import matlab.engine eng = matlab.engine.start_matlab() eng.doc(nargout=0)
即要聲明nargout=0,此時函數不會返回任何參數,如果不聲明,就會報錯。
3. 在python腳本里調用matlab腳本
該文檔的幫助信息在https://ww2.mathworks.cn/help/matlab/matlab_external/call-user-script-and-function-from-python.html,可以看到有兩種方式的調用1.直接調用2.調用函數
如果是直接的腳本,比如在triarea.m里寫下以下內容:
b = 5; h = 3; a = 0.5*(b.* h)
那么在python里就可以直接調用:
import matlab.engine eng = matlab.engine.start_matlab() eng.triarea(nargout=0)
就會得到py的打印輸出,a=7.5000,這是因為雖然無返回值,但是matlab的輸出仍然會顯示在py里。當然更方便的方法是調用函數的形式,生成以下的文件:
function a = triarea(b,h) a = 0.5*(b.* h);
在python中執行以下的調用:
ret = eng.triarea(1.0,5.0) print(ret)
就會得到2.5,需要注意的是,該函數僅返回一個值,因此無需指定nargout的值。