在MATLAB和Python之間建個接口,從Python中調用MATLAB腳本或者是MATLAB的函數。內容不是很難,畢竟現成的接口已經有了,在這兒記錄一下API使用的一些事項。
注:本篇使用的是MATLAB R2017a,windows 10系統。
相關鏈接
https://www.mathworks.com/help/matlab/matlab-engine-for-python.html
https://www.mathworks.com/help/matlab/matlab_external/get-started-with-matlab-engine-for-python.html
API的安裝
MATLAB在安裝的過程中已經准備好了相關文檔。根據教程,首先要找到root\R2017a\extern\engines\python文件夾。這里的root指的是MATLAB安裝的根目錄。對於筆者的電腦,我的全路徑就是C:\Program Files\MATLAB\R2017a\extern\engines\python。打開這個文件夾,可以看見下面這幾個文件。
其中setup.py是我們想要用的文件。定位到它之后,我們在command window里面轉到這個文件夾,然后執行安裝。(啟動command window的時候必須是管理員模式,否則可能會報“沒有權限”的錯誤)
cd C:\Program Files\MATLAB\R2017a\extern\engines\python
python setup.py install
不出差錯的話,到這里安裝過程就結束了。如果你使用的是Python的虛擬環境,那么記得在安裝前先將虛擬環境啟動。
基本調用
這個API調用非常簡單。在Python中,導入如下兩個module就能實現MATLAB的全部控制:
import matlab
import matlab.engine
其中,matlab包含的是一些數據形式,比如int8,int16之類。matlab.engine負責程序的啟動。
engine = matlab.engine.start_matlab() # Start MATLAB process
engine = matlab.engine.start_matlab("-desktop") # Start MATLAB process with graphic UI
上面兩行代碼,第一行指示MATLAB在后端運行;第二行則會啟動MATLAB的圖形界面窗口。調用任何MATLAB函數都通過engine變量來實現。筆者自己調用了一些聲音工具箱中的函數,一點問題都沒有。
>>> engine.sqrt(2.)
1.4142135623730951
變量兼容性
筆者自己嘗試的時候遇到很多變量類型不正確這樣的提示,因為MATLAB函數對於輸入數據的類型有着比較嚴格的要求,比如log2對於int8類型輸入就會報錯。double類型是MATLAB里面用得最多的數據型,所以一般可以將python的數據轉成MATLAB兼容的double類型來解決問題。舉個例子,Python的list類型變量只需加上matlab.double就可以完成轉換。
>>> engine.sqrt([1.,2.,3.,4.,5.])
# Some error
>>> engine.sqrt(matlab.double([1.,2.,3.,4.,5.]))
matlab.double([[1.0,1.4142135623730951,1.7320508075688772,2.0,2.23606797749979]])
調用MATLAB腳本及自定義函數
調用腳本和自定義函數的過程也幾乎一樣,也是從變量engine中去調用。值得注意的是,需要保證你的函數或腳本就在當前的工作路徑下,否則engine會找不到文件而報錯。
比方說,筆者當前的工作路徑下有兩個文件:gaussian_pulse.m和py_matlab.py。
gaussian_pulse.m中的內容是這樣的:
function out = gaussian_pulse(fs, fc, repeat) N = 882;
t = 0:1/fs:(N-1)/fs;
yi = gauspuls(t,fc,1/8);
temp = yi;
for i = 1:repeat-1
temp = cat(2, temp,yi);
end
out = temp;
end
在py_matlab.py中,我定義了engine並調用這個函數:
engine = matlab.engine.start_matlab()
signal = engine.gaussian_pulse(matlab.double([44100]), matlab.double([3000]), matlab.double([5]))
注意到每一個輸入參數我都強制性進行了轉換確保萬無一失。加上方括號也是因為MATLAB的格式需求。
指定輸出個數
默認情況下,API認為接收函數返回結果的參數有1個。這會導致沒有返回值的函數在被調用時報錯:“Too many output arguments”或是其他類似的信息。我們可以人為指定輸出參數為0個來避免這樣的錯誤。
>>> playblocking(player) # playblocking is a MATLAB function with no returns
Error using playblocking
Too many output arguments
>>> playblocking(player, nargout=0)
# Success!
True 與 False
在MATLAB里面邏輯值是true與false,但是在Python里面它們是大寫的True和False。畢竟我們還是在Python環境下編程,所以如果調用某個函數需要用到邏輯值,遵循Python的書寫格式。
后記
官方文檔里還有一些其他非常好的教程,包括標准輸出/錯誤信息重導向、句柄的使用、畫圖等等。鑒於筆者時間原因這些沒有涉及到,有需要的朋友可以從筆者在開篇提供的網站中找到答案。