Skip to content

sitdownplz/MATLAB_Integration_Python

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 Installed Python Installed MATLAB Runtime Installed Compiler 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.7 Python 3.6 Python 3.7 Python 3.8 Python 3.9 Python 3.10 Python 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 = 

  Python list with values:

    [1.0, 2.0, 3.0]

    Use string, 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 = 

  Python LinearRegression with properties:

           n_jobs: [1×1 py.NoneType]
           copy_X: 1
         positive: 0
    fit_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 MATLAB

import numpy as np

def Addup_randiMat(A_max,B_max):
    matA = np.random.randint(0,A_max,(2,2))
    matB = np.random.randint(0,B_max,(2,2))

    return matA+matB


在 MATLAB 中呼叫自訂義 Python 函式

% Example: Call Python user-defined function in matlab
% MATLAB Version: R2022b

>> py.myModule.Addup_randiMat(10,5)

ans = 

  Python ndarray:

    4    7
   11    3

    Use details function to view the properties of the Python object.

    Use int64 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 = 

  Python module 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 = 

  Python dict_keys with no properties.

    dict_keys(['Apple', 'Orange'])


Prices = 

  Python dict_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'

import numpy as np

randomMat = 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 = 

  Python ndarray:

  Columns 1 through 8

    0.3091    0.9741    0.6238    0.0295    0.4298    0.4562    0.3216    0.6516
    0.2124    0.7749    0.3696    0.2310    0.1058    0.0205    0.7097    0.5682
    0.9184    0.3028    0.5064    0.5527    0.4872    0.5226    0.1789    0.3618
                                      ...
    Use details function to view the properties of the Python object.
    Use double 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 MATLAB

import debugpy
debugpy.debug_this_thread() # Enable Debugging 

def Addup(x1,x2):
    x1 += 1
    x2 *= 10
    output = x1+x2
    return output


  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 = 

  PythonEnvironment with 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: Loaded
    ExecutionMode: OutOfProcess
        ProcessID: "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.9

import matlab.engine as eng

session = eng.start_matlab('-desktop') # '-desktop' 參數會將 MATLAB 桌面顯示出來


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

# Example: Using current running MATLAB session
# MATLAB Version: R2022b
# Python Version: 3.9

import matlab.engine as eng

matlab_ID = eng.find_matlab() # 選擇對應的 Process ID
session = eng.connect_matlab(matlab_ID[0])


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

# Example: Call MATLAB function in Python
# MATLAB Version: R2022b
# Python Version: 3.9

import matlab.engine as eng

sess = 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.9

import numpy as np

np_array = np.array(matlab_rand
print(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.9

matlab_array = matlab.double([1,5,2,8,4,3]) # Convert list to MATLAB array
sorted_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 
    
    function y = 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.9
    
    import pyPackage
    
    myLib = 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

Watchers

Forks

Releases

No releases published

Packages

No packages published