Skip to content

Repository files navigation

🔰 MATLAB 與 Python 整合實現

此內容主要說明如何實現 MATLAB 與 Python 協作的應用

MATLAB 與 Python 整合主要有以下三種方法:

  • 在 MATLAB 中呼叫 Python 函式 (Calling Python from MATLAB)
  • 在 Python 環境下呼叫 MATLAB 函式 (Calling MATLAB from Python)
  • 將 MATLAB 函式封裝成 Python package (Packaging MATLAB program to Python package)

對於以上三種情境會有一些對應的條件需求:
使用情境MATLAB InstalledPython InstalledMATLAB Runtime InstalledCompiler SDK Toolbox
在 MATLAB 中呼叫 Python 函式✔️✔️
在 Python 環境下呼叫 MATLAB 函式✔️✔️
將 MATLAB 函式封裝成 Python package✔️✔️

環境設定

 建議直接使用 Anaconda1 安裝並設定路徑,且方便之後根據不同狀況建立獨立環境安裝模組。
MATLAB 從 R2014b 開始支援 Python 2.7,建議至少使用 MATLAB R2020b 以上版本。

版本限制

 MATLAB Interface Engine 有支援對應 Python 版本的限制,詳細請見 MATLAB 官網支援版本列表
以下列出幾版:

MATLAB 版本Python 2.7Python 3.6Python 3.7Python 3.8Python 3.9Python 3.10Python 3.11
R2023b✔️✔️✔️
R2023a✔️✔️✔️
R2022b✔️✔️✔️✔️
R2022a✔️✔️✔️✔️
R2021b✔️✔️✔️✔️
R2021a✔️✔️✔️
R2020b✔️✔️✔️✔️

在 MATLAB 中呼叫 Python 函式

 在 MATLAB 環境底下使用 Python 前可以透過 MATLAB 語法 pyenv2 來確認當前 MATLAB 有讀取到想要使用的 Python 版本。
除此之外 pyenv 具有以下參數可以讓使用者切換 Python 環境以及更改啟動模式

Version:
Version 參數可以用來指定想要使用的 Python 版本

% Example: Set Python execution version for MATLAB interface engine% MATLAB Version: R2022b% 使用 Windows registry (Windows Only)
>> pyenv(Version="3.10")
% 使用完整路徑
>> pyenv(Version="/usr/bin/python")


ExecutionMode:
ExecutionMode 參數設定是否要在和 MATLAB 同一個 process 底下執行 Python 程式碼
'InProcess' : 在 MATLAB process 中運行腳本。在對性能至關重要的使用情況下,請使用此模式。(Default)
'OutOfProcess' : 啟動一個獨立的 process,用於安全執行Python腳本和模組並避免函式庫衝突。

- Python 模組需要使用與 MATLAB 相同的第三方庫的時
- 想要使用 Python 偵錯流程時

% Example: Set Python execution mode for MATLAB interface engine% MATLAB Version: R2022b% 設定執行模式
>> pyenv(ExecutionMode='OutOfProcess')


🔻 在 MATLAB 中調用 Python 函式功能

 在 MATLAB 裡面可以直接使用 py 的前綴詞來使 MATLAB 調用 Python 裡面的既有函式,包含轉換變數型態等動作:

% Example: Create python list in MATLAB% MATLAB Version: R2022b
>> pyList=py.list([1,2,3])
pyList =Pythonlist with values:
[1.0, 2.0, 3.0]
Usestring, double or cell function to convert to a MATLAB array.


除此之外, py 的後綴也可以直接使用已安裝的 Python 模組, py 接上對應已安裝模組, MATLAB 即會自動 import:

% Example: Create scikit-learn regression model in MATLAB% MATLAB Version: R2022b
>> reg_Model=py.sklearn.linear_model.LinearRegression
reg_model =PythonLinearRegression with properties:n_jobs: [1×1 py.NoneType]
copy_X:1positive:0fit_intercept:1
LinearRegression()


使用 py 調用模組時,也可以使用 Tab 鍵來提示模組所含的物件與函式。



🚩 調用使用者自訂義函式 Calling User-defined Function
一般來說除了直接調用 python 函式庫裡面的函示之外,使用者可能會根據自身的需求去撰寫自訂義的函式或是函式庫。 在 MATLAB 中一樣可以透過 py 的前綴去調用這些自訂義的函式來使用。
若是要直接使用 py 前綴來調用使用者自訂義函式,需先確保該程式碼在 Python 的搜尋路徑底下:

在 MATLAB 底下將當下目錄加入 Python 搜尋路徑:

% Example: Add current directory to Python serach path% MATLAB Version: R2022b
>> if count(py.sys.path,'') ==0
insert(py.sys.path,int32(0),'');
end


Python User-defined Function:

# myModule.py# Sample script for calling user-defined function in MATLABimportnumpyasnpdefAddup_randiMat(A_max,B_max):
matA=np.random.randint(0,A_max,(2,2))
matB=np.random.randint(0,B_max,(2,2))
returnmatA+matB


在 MATLAB 中呼叫自訂義 Python 函式

% Example: Call Python user-defined function in matlab% MATLAB Version: R2022b
>> py.myModule.Addup_randiMat(10,5)
ans =Pythonndarray:47113Usedetails function to view the properties of the Python object.Useint64 function to convert to a MATLAB array.


🚩 載入使用者自訂義函式 Import User-defined Function as Module
除了前面提到的使用 py 前綴,MATLAB 也可以將 Python User-defined function script 以 module 的方式載入並儲存成物件變數

% Example: Load python module% MATLAB Version: R2022b
>> module=py.importlib.import_module('myModule')
module =Pythonmodule with properties:np: [1×1 py.module]
Addup_randiMat: [1×1 py.function]
<module'myModule'from'C:\\Users\\Tim\\Desktop\\myModule.py'>


如果 module 有所更動,在 MATLAB 中也可以透過 reload 來更新物件而不用再呼叫一次import

>> py.importlib.reload(module)


🔻 在 MATLAB 中直接執行 Python 程式碼

 在 MATLAB 中可以使用字串的方式來表達 Python 程式碼,並透過 pyrun3 的函式來執行

% Example: Directly run python code % MATLAB Version: R2022b
>> pyCode= [
"Grocery = {'Apple':100, 'Orange':30}";
"Items = Grocery.keys()";
"Prices = Grocery.values()"];
>> [Items, Prices] = pyrun(pyCode, ["Items", "Prices"])
Items =Pythondict_keys with no properties.
dict_keys(['Apple', 'Orange'])
Prices =Pythondict_values with no properties.
dict_values([100, 30])


🔻 在 MATLAB 中執行 Python 腳本

 除了先前提到的 pyrun 使用字串表達 Python 程式碼之外,也可以執行既有的 Python 腳本並把想要的變數傳回 MATLAB workspace 中。 MATLAB 中的 pyrunfile4 讓使用者可以執行既有的程式碼腳本。

Python sample code:

# pyrunfile_demo.py# Demo script for MATLAB 'pyrunfile'importnumpyasnprandomMat=np.random.rand(100,100) # Create 100x100 of random matrix


MATLAB sample code

% Example: Run python script and get variable% MATLAB Version: R2022b
>> result= pyrunfile('pyrunfile_demo','randomMat')
result =Pythonndarray:Columns1 through 80.30910.97410.62380.02950.42980.45620.32160.65160.21240.77490.36960.23100.10580.02050.70970.56820.91840.30280.50640.55270.48720.52260.17890.3618
...
Usedetails function to view the properties of the Python object.Usedouble function to convert to a MATLAB array.


🔻 使用 VScode 執行 Python 偵錯

 在 MATLAB 中調用 Python 的情境下最常遇到的問題就是 Python 端發生錯誤但卻沒辦法像 MATLAB 腳本一樣進入偵錯模式去查看變數變化。
但今天透過 VScode 的介面可以連結 MATLAB 程序來觸發 VScode 的中斷點。

  1. 在終端機輸入以下指令安裝 debugpy 套件:
python -m pip install debugpy


  1. 在想要偵錯的 Python 腳本中引入 debugpy 套件並加入 debugpy.debug_this_thread() 程式碼,範例程式碼可以參考:
# Debug in User-defined Python Script with MATLABimportdebugpydebugpy.debug_this_thread() # Enable Debugging defAddup(x1,x2):
x1+=1x2*=10output=x1+x2returnoutput


  1. 建立 VScode 偵錯調用腳本 launch.json
{
"version": "0.2.0",
"configurations": [
{ "name": "Attach to MATLAB",
"type": "python",
"request": "attach",
"processId": "${command:pickProcess}"
}
]
}

NOTE: Ubuntu users may need to change the value of the ptrace variable using the command below.
$ echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope

  1. 在程式碼中設定中斷點
    image

  2. 確認 MATLAB 中所使用得 Python 環境以及程序ID,如果執行結果的 ExecutionMode 顯示 NotLoaded 可以隨意執行一行 Python 程式碼
    例如: py.list([1,2,3])

>> pyenv
ans =PythonEnvironmentwith properties:Version:"3.9"Executable:"C:\Users\Tim\anaconda3\envs\python39\python.exe"Library:"C:\Users\Tim\anaconda3\envs\python39\python39.dll"Home:"C:\Users\Tim\anaconda3\envs\python39"Status:LoadedExecutionMode:OutOfProcessProcessID:"19460"ProcessName:"MATLABPyHost"


  1. 在 VScode 裡面點選 "Run and Debug" 並選擇 "Attach using Process ID" 連結到剛剛顯示的 MATLAB Process ID
    在 MATLAB 中執行程式碼即可成功觸發 VScode 中斷點偵錯模式
    image
    image
    image


在 Python 環境下呼叫 MATLAB 函式

 MATLAB 在近幾年的版本中推出了許多將特定功能包裝起來的 APP,程式撰寫人員或是跨越不同領域的人能夠快速上手並節省開發時間。
對於習慣在 Python 環境開發的使用者或是想要在 Python 中開發但又希望沿用 MATLAB 特有功能的使用者可以參考本章節內容。

MATLAB 的目前釋出了與 Python 結合的 API 套件 matlabengine 一般可以在你的 MATLAB 安裝路徑底下找到:
>> matlabroot\extern\engines\python

目前在 PyPI 上也有釋出該套件,所以使用者也可以直接透過 pip 指令安裝:

pip install matlabengine


在 Python 透過以下指令可以啟動 MATLAB 程序:

# Example: Start MATLAB API engine in Python# MATLAB Version: R2022b# Python Version: 3.9importmatlab.engineasengsession=eng.start_matlab('-desktop') # '-desktop' 參數會將 MATLAB 桌面顯示出來


除此之外,如果有已經開啟的 MATLAB 程序也可以透過以下指令去連結:

# Example: Using current running MATLAB session# MATLAB Version: R2022b# Python Version: 3.9importmatlab.engineasengmatlab_ID=eng.find_matlab() # 選擇對應的 Process IDsession=eng.connect_matlab(matlab_ID[0])


在 Python 中調用 MATLAB 和直接在 MATLAB 中使用的主要差異在於需要物件前綴和部分需要定義輸出數量。
以單純的產生亂數來看的話,在 Python 中調用 MATLAB 函式如下範例:

# Example: Call MATLAB function in Python# MATLAB Version: R2022b# Python Version: 3.9importmatlab.engineasengsess=eng.start_matlab()
matlab_rand=sess.rand(2)
print(type(matlab_rand))
print(matlab_rand)

輸出:

<class'matlab.double'>
[[0.421761282626275,0.7922073295595544],[0.9157355251890671,0.959492426392903]]


預設的輸出會是 MATLAB 物件的變數型態,可以透過 Numpy 套件轉換成 numpy.array

# Example: Convert MATLAB array to Numpy array# MATLAB Version: R2022b# Python Version: 3.9importnumpyasnpnp_array=np.array(matlab_randprint(type(np_array))
print(np_array)

輸出:

<class'numpy.ndarray'>
[[0.421761282626275,0.7922073295595544]
[0.9157355251890671,0.959492426392903]]


對於有多個輸出的函式需要特別去定義輸出的數量:

# Example: Call MATLAB function with multiple outputs# MATLAB Version: R2022b# Python Version: 3.9matlab_array=matlab.double([1,5,2,8,4,3]) # Convert list to MATLAB arraysorted_array, sort_idx=session.sort(matlab_array, nargout=2)
print(sorted_array, sort_idx)

輸出:

[[1.0,2.0,3.0,4.0,5.0,8.0]] [[1.0,3.0,6.0,5.0,2.0,4.0]]



將 MATLAB 函式封裝成 Python package

 文章前面提到的兩種方式主要是在同時裝有 MATLAB 和 Python 的開發環境下進行協作, 但有另外一種使用情境是開發者想將既有的 MATLAB 演算法套件轉移到 Python 的框架下去使用。
要滿足這個需求除了重新用 Python 撰寫一次以外,比較省時且安全的辦法是將既有演算法轉換成 Python 的套件直接調用。

要將 MATLAB 程式碼編譯成 Python package 主要透過 MATLAB Compiler SDK® 來達成。(MATLAB Compiler Required)*
MATLAB Compiler SDK 除了 Python package 之外也支援多種其他程式語言的函式庫編譯5,如: .NET、C、C++、JAVA 等...

編譯的流程可以分為使用圖形化介面以及程式碼來達成,先以圖形化介面為例:

  1. 在 MATLAB 上放頁籤的畫面可以找到 "Library Compiler" :
    image

  1. 左上角的語言選單中可以找到 "Python Package" 的選項:
    image

  2. 選取想要轉換的 MATLAB 程式碼,建議這裡的專案名稱可以使用後面要用來引入 Python 環境的 Package name

    % addup.m% Sample funciton script for Python package compile functiony= addup(a,b)
    y =a+b;


    image

  3. 編譯完成以後會產生三個資料夾,分別為:

    • for_redistribution
    • for_redistribution_files_only
    • for_testing

    在 for_redistribution_files_only 的資料夾中可以找到 `setup.py` ,透過以下的指令安裝在想要使用的 Python 環境中:
    python setup.py install


  4. 在 Python 環境中僅需先匯入 compiled 後的 package,並使用 initialize() 去啟動 MATLAB Runtime:

    # Example: Call compiled MATLAB function # MATLAB Version: R2022b# Python Version: 3.9importpyPackagemyLib=pyPackage.initialize()
    Result=myLib.addup(10,2)
    print(Result)

    輸出:

    12


Footnotes

  1. Anaconda Official Website [https://www.anaconda.com/download]

  2. MATLAB pyenv Function Documentation [https://www.mathworks.com/help/matlab/ref/pyenv.html]

  3. MATLAB pyrun Function Documentation [https://www.mathworks.com/help/matlab/ref/pyrun.html]

  4. MATLAB pyrunfile Function Documentation [https://www.mathworks.com/help/matlab/ref/pyrunfile.html]

  5. MATLAB Compiler SDK [https://www.mathworks.com/products/matlab-compiler-sdk.html]

About

No description or website provided.

Topics

Resources

Stars

10 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages