為實(shí)現(xiàn)一些相對復(fù)雜的系統(tǒng)開發(fā)或建模仿真,可以借助MathWorks? Simulink在圖形化的工程界面中編輯和測試模型,或者使用MathWorks提供的現(xiàn)成實(shí)例與模塊以零基礎(chǔ)快速搭建所需的仿真環(huán)境。但若要讓他人運(yùn)行自己搭建的模型,并根據(jù)需要自行修改部分模型參數(shù),或是發(fā)布為可供他人使用的仿真工具,則需要將模型打包為獨(dú)立的可執(zhí)行文件,并設(shè)計(jì)前端圖形化界面以查看仿真輸出結(jié)果、修改仿真參數(shù)。
模型打包的官方推薦做法是使用MATLAB?自帶的Simulink Compiler工具,將編譯好的 Simulink模型和用于設(shè)置、運(yùn)行和分析仿真的 MATLAB代碼一起打包,且可以附帶由 MATLAB App設(shè)計(jì)工具設(shè)計(jì)的UI。該方法理論上實(shí)現(xiàn)不難,打包出的程序只需Runtime環(huán)境即可運(yùn)行。但MATLAB App設(shè)計(jì)工具并非主流前端設(shè)計(jì)工具,需要學(xué)習(xí)成本,且制作的UI界面較為簡單,不滿足對前端界面要求較高的場景;此外,打包生成的代碼可讀性較差,網(wǎng)上現(xiàn)有的案例資源等又極少,一旦報(bào)錯(cuò),很難定位錯(cuò)誤,效率不高。
(資料圖)
解決方案提出:
為解決該問題,就需要拋棄官方提供的MATLAB App設(shè)計(jì)工具和Simulink Compiler打包工具,自行設(shè)計(jì)前端界面、獲取Simulink運(yùn)行數(shù)據(jù)并打包發(fā)布。一種可行的方案是通過主流前端設(shè)計(jì)工具制作前端GUI界面,并通過外部會(huì)話訪問MATLAB,以此控制Simulink模型運(yùn)行并獲取運(yùn)行時(shí)的數(shù)據(jù),如可以采用官方提供的用于Python的MATLAB Engine API(/help/matlab/matlab_external/),通過Python會(huì)話在后臺調(diào)用MATLAB,將仿真實(shí)時(shí)狀態(tài)和模型參數(shù)等顯示在以PyQt制作的前端UI界面中,最后通過Pyinstaller打包發(fā)布。
該方案可以實(shí)現(xiàn)復(fù)雜的前端軟件設(shè)計(jì)與Simulink模型仿真相結(jié)合,且體積不大、兼容性較好,但需安裝有MATLAB環(huán)境而非Runtime,即發(fā)布給他人時(shí)除軟件本體外還需附帶完整MATLAB安裝包或?qū)Ψ揭寻惭bMATLAB(若未安裝則Simulink仿真部分不可用,但不影響軟件其他功能)。本質(zhì)上Simulink模型并沒有被編譯發(fā)布,只是調(diào)用了相關(guān)api接口使模型在后臺仿真運(yùn)行。官方文檔(/help/matlab/)中也指出了:
“MATLAB Engine API for Python 可提供一個(gè)包,供 Python 將 MATLAB 作為計(jì)算引擎來調(diào)用。引擎應(yīng)用程序需要已安裝版本的 MATLAB;您無法在只有 MATLAB Runtime 的機(jī)器上運(yùn)行 MATLAB Engine。”
目前,該方案在網(wǎng)上可供參考的資源不多,文中可能存在錯(cuò)誤和可優(yōu)化的部分。我使用的Simulink模型為純電動(dòng)汽車建模(EvReferenceApplication),模型細(xì)節(jié)可參考的我的另一篇文章(/article1)。前端GUI界面使用PyQt5設(shè)計(jì),制作一個(gè)小型仿真系統(tǒng)軟件界面來控制電動(dòng)汽車模型仿真的啟停以及部分模型參數(shù)的修改,同時(shí)實(shí)時(shí)讀取并顯示仿真輸出數(shù)據(jù)。軟件界面設(shè)計(jì)需在保證功能完整的前提下盡量高效美觀。
安裝用于 Python 的 MATLAB Engine API
安裝前需要確認(rèn)電腦中的Python和MATLAB版本是否兼容,可以查看官方文檔頁面。(/support/requirements/)
在MATLAB根目錄\extern\engines\python文件夾中找到,即自動(dòng)安裝腳本文件;控制臺進(jìn)入該目錄(若Python安裝在虛擬環(huán)境則要在對應(yīng)虛擬環(huán)境終端進(jìn)入),輸入指令python install,安裝會(huì)自動(dòng)執(zhí)行。安裝完成后MATLAB Engine會(huì)以Python包的形式存在,可以通過pip list查詢。
除此之外,MATLAB R2022b及以上也可以通過pip安裝,詳情可參考官方文檔。(/help/matlab/matlab_external/)
MATLAB Engine需要讀取_文件中的地址信息來調(diào)用電腦中的MATLAB,該文件默認(rèn)存放于Python包文件夾\matlab\engine中,且僅在安裝時(shí)自動(dòng)生成,記錄本機(jī)MATLAB地址。若本機(jī)MATLAB地址改變、_文件丟失等都會(huì)導(dǎo)致尋址失敗。因此不難想到,若要在打包發(fā)布時(shí)將MATLAB Engine以python包的形式包含,移植到他人電腦中運(yùn)行,則必須手動(dòng)修改_文件中的地址信息為對方電腦中的MATLAB地址,否則無法正常運(yùn)行。
MATLAB Engine需要讀取的文件地址信息(即_文件)如下:
修改python包代碼
為保證MATLAB Engine在打包移植后仍能正常讀取配置文件,獲取目標(biāo)系統(tǒng)環(huán)境信息及MATLAB地址,需對包中部分代碼進(jìn)行修改。
在本機(jī)Python包文件夾\matlab\engine\__init__.py中找到調(diào)用_文件所在代碼:
_arch_filename = (_module_folder, "_")
將其改為:
_arch_filename = (('.'), "")
其中“”可以是任意文本文件,需自行編寫代碼,在程序運(yùn)行時(shí)根據(jù)當(dāng)前系統(tǒng)環(huán)境在程序運(yùn)行根目錄下生成該文件,從而實(shí)現(xiàn)MATLAB Engine包尋址。
在python中調(diào)用MATLAB Engine
官方文檔(/help/matlab/matlab_external/)中給出了在python中調(diào)用MATLAB Engine的代碼示例和說明可供參考,但大多較為簡略,且實(shí)際編程時(shí)還需結(jié)合以編程方式運(yùn)行仿真(/help/simulink/ug/),用代碼代替Simulink? UI 與仿真進(jìn)行交互,如果以前從未接觸過Simulink的代碼形式,可能遇到不少問題。本仿真系統(tǒng)中用到的部分代碼見下表。
其中,本仿真系統(tǒng)用到的部分set_param中的parameter參數(shù)與對應(yīng)的value值見下表。需注意表中所有參數(shù)均為字符串。
另外需要注意的是,在python中調(diào)用MATLAB Engine相當(dāng)于訪問外部會(huì)話,屬于耗時(shí)操作,若寫在主程序線程中將會(huì)導(dǎo)致線程阻塞,影響前端GUI界面運(yùn)行,需要利用多線程通信來解決該問題。
打包發(fā)布
使用pyinstaller打包發(fā)布python程序,但pyinstaller無法正確識別MATLAB Engine包,此時(shí)需要手動(dòng)復(fù)制該包;若需要打包為單一可執(zhí)行程序(.exe),則需要配置hooks來添加指定包。
在主程序.py目錄下新建文件夾,命名為hooks,其內(nèi)新建py文件,內(nèi)容如下:
from import collect_all
datas, binaries, hiddenimports = collect_all('matlab')
打包時(shí)額外添加指令:--additional-hooks-dir=hooks。如:
pyinstaller -F -w --additional-hooks-dir=hooks 主程序.py
即可正確打包為單一可執(zhí)行程序。
由于B站專欄格式限制,部分內(nèi)容或代碼可能存在格式異常。原文內(nèi)容請前往/article1