0. 概述
加速 Simulink 仿真是個老生常談的問題,尤其是系統比較復雜或規模較大的時候,大家都不希望時間耗費在等待上,也正因此,其實已經有很多答案散落在各種地方;考慮到老朽本人玩 Simulink 不多甚至可以說很少,所以這篇以搬磚為主,整理編撰的時候會盡量注明出處,也盡量對各種方法分門別類讓大家可以一目了然。當然,本著嚴謹的技術態度,老朽還會盡量做一些驗證,確保拿出來的東西都是能用得上的。(由于本文涉及的外部鏈接較多,我將一一列在文末,方便大家獲取。)
首先,有必要澄清一下,這里的 Simulink 其實不只是 Simulink,而仿真耗時也不只是模型求解慢。
從模型本身來講,它可能由以下一種或多種情形組合(甚至是全部):
1Simulink(數學)模型
2Simscape(物理)模型
3Stateflow(狀態機)模型
4SimEvents(事件)模型
5MATLAB(腳本)模型
6其它第三方模型(以源代碼或動態庫等方式集成)
其中物理模型可能是 Driveline,Multibody,Electrical,Fluids 以及 Powertain 和 Vehicle Dynamics 中的一種或多種組合。
MATLAB 腳本可能只是一個簡單的計算,一個傳遞函數或狀態方程,也可能是機器學習或深度學習的推斷,亦或是強化學習智能體。
本文重點討論 Simulink 與 Simscape,也會提及其它的方面,對于復雜的情況,建議還是找 MathWorks 官方提供技術支持(版本在更新,技術在發展,過去沒有改善的不表示現在不能改善)。
從仿真耗時來講,它可能會涉及以下時間成本:
1模型編譯/鏈接
2循環初始化
3循環迭代
4輸出/日志(在循環迭代過程中)
5仿真終止(在循環迭代結束時)
列舉完這些方方面面,大概就能有一個概念——仿真加速要針對具體的情況具體分析。
盡管老朽有理由相信來讀這篇文章的大都是有經驗的 Simulink 用戶,但穩妥起見,我們還是從基礎開始——其實,經驗也常常教育我們,涉及到性能的問題,確實有不少情況都是基礎沒打好。
1. 基礎:性能優化相關知識
基礎部分的知識點來自 MATLAB產 品文檔,著急直接上手優化仿真性能的觀眾,可以直接去看這個:優化性能 - MathWorks 官網文檔[1]。但俗話講得好,心急吃不到熱豆腐,耐心點往下看,我相信會有更多收獲。
在看這部分之前,無論你是 Simulink 老用戶還是新用戶,我都要墻裂建議你看一下幫助文檔里仿真原理的相關章節,MathWorks已經提供部分中文化的pdf版本了,其中 Simulink 的工作原理一章已經有中文版了,給懶人們直接上鏈接吧:Simulink 用戶指南 (僅已翻譯的部分 R2021b)[2],翻到第99頁,從這里開始,看完第三章的29頁即可。
如果你的模型里還有 Simscape 或 Stateflow 或 SimEvent 等等,我還要建議你更進一步,把它們的 User's Guide 里有關原理的章節都看一下:
● Simulink 用戶指南 (僅已翻譯的部分 R2021b)[3],第3章 Simulink 的工作原理,共29頁
● Simscape User's Guide:[4]第7章 Model Simulation,共69頁
● Stateflow 用戶指南 (僅已翻譯的部分 R2021b):[5]第3章 Stateflow語義,共24頁
● SimEvents User's Guide:[6]這個有點分散,沒用到就先放放吧,講真老朽也沒看過
關于基礎知識,大家看 MATLAB 幫助文檔學習的話,老朽建議一定要看 PDF 版本的 User's Guide 也就是用戶指南,相比去官網上看或者在幫助界面上看,PDF 版本的用戶指南都要好看的多。
言歸正傳,回到加速 Simulink 仿真的問題,在 Simulink 用戶指南(R2021b 中文版)的動態仿真部分,分別在第31章和第35章,給出了“如何提高仿真性能”以及“加速模型”兩章較為全面的闡述,大家把這些看完看懂的話,老朽相信大家對于自己的仿真為什么會慢,以及怎樣改進模型使仿真能快一些,就已經有譜了。
鑒于以上提到的方方面面,顯然不合適把重點全抄下來,而老朽又想大家即使只看完本文也能做些工作,因此就挑重點半抄半寫吧。
基礎方面,我打算羅列6個要點,考慮到內容真的有點多,沒法具體展開,要細節的話還是去看文檔吧。
1.1 動態系統仿真的3個階段
編譯階段
鏈接階段
仿真環階段
所謂3個階段,就是從你按下綠色的運行按鈕,到仿真跑出結果,Simulink 要干的三件事情。看名字就很好理解它們都是什么,為了讓偷懶的也能看看,就把文檔內容拷貝到本節后面吧。
大多數有關仿真提速的內容都是針對第三階段的,即仿真的循環初始化和循環迭代兩個部分,但作為開篇,我想重點先說說模型編譯。經常有人在大型建模上耗費了大把時間等待模型編譯,加快超大模型的編譯,有幾點知識和經驗需要了解:
01模型的編譯跟 C/C++ 文件的編譯類似,其實是可以支持多 CPU 核(多進程)同時編譯的,前提是你得遵循“基于組件的建模規范”,即在你的模型中合理使用子系統、鏈接子系統、模型引用和子系統引用。具體我們在1.3模型架構里講。
02Simulink 支持增量式加載/編譯,在滿足前一條的情況下,可以通過共享 Simulink Cache 文件來降低編譯耗時,具體參見:共享 Simulink 緩存文件以加快仿真速度[7]。
03如果不是采用普通模式,而是用加速或快速加速模式,則 Simulink 不僅會經歷模型編譯,還會調用 Simulink Coder 的代碼生成功能(雖然不需要為此購買和安裝 Simulink Coder),生成 C/C++ 代碼并調用 C/C++ 編譯器將其編譯為可執行文件,這種情況的模型編譯耗時更長,對架構做的差的超大模型而言,甚至會卡死。這一點在1.5仿真模式中還會再提到。
04通過 Simulink Cache文件(.slxc)來減少模型編譯時間這一功能,到 R2019b 才健全(支持代碼生成和 Stateflow),以此為例,談性能真的不能離開 MATLAB 最新版(后面關于求解器、多處理器和 GPU 都會提到)。
· 模型編譯
當系統的模型處于打開狀態,并且您對模型進行仿真時,將進行仿真的第一個階段。在 Simulink 編輯器中,點擊運行。運行仿真會導致 Simulink 引擎調用模型編譯器。模型編譯器會將模型轉換為可執行形式,這個過程稱為編譯。具體說就是,編譯器會:
? 計算模型的模塊參數表達式,以確定它們的值。
? 確定模型沒有顯式指定的信號屬性,例如,名稱、數據類型、數值類型和維度,并檢查每個模塊是否都接受連接到其輸入的信號。
? 將源信號的屬性傳播到它所驅動的模塊的輸入,以便計算模塊中先前未指定的屬性。
? 執行模塊簡化優化。
? 通過將虛擬子系統替換為它們所包含的模塊,將模型層次結構扁平化。
? 通過基于任務的排序確定模塊執行順序。
? 確定模型中您未顯式指定其采樣時間的所有模塊的采樣時間。
這些事件本質上與您更新模塊圖時發生的情況相同。差別在于 Simulink 軟件作為模型仿真的一部分啟動模型編譯,編譯會直接進入鏈接階段,如“鏈接階段”中所述。而顯式模型更新是針對模型的獨立操作。
編譯模型或模型層次結構時,可以通過點擊進度條旁邊的取消按鈕來取消模型編譯。
· 鏈接階段
在此階段,Simulink 引擎為工作區域(信號、狀態和運行時參數)分配執行模塊圖所需的內存。它還為用于存儲每個模塊的運行時信息的數據結構體分配和初始化內存。對于內置模塊,模塊的主要運行時數據結構體稱為 SimBlock。它存儲指向模塊的輸入和輸出緩沖區以及狀態和工作向量的指針。
方法執行列表
在鏈接階段,Simulink 引擎還會創建方法執行列表。這些列表列出了調用模型的模塊方法以計算其輸出的最有效順序。在模型編譯階段生成的模塊執行順序列表用于構造方法執行列表。
模塊優先級
您可以向模塊分配更新優先級。較高優先級模塊的輸出方法在較低優先級模塊的輸出方法之前執行。僅當這些優先級與其模塊執行順序一致時,才會遵循它們。
· 仿真環階段
鏈接階段完成后,仿真會進入仿真環階段。在此階段,Simulink 引擎使用該模型提供的信息,從仿真開始到完成的時間段內以固定間隔連續計算系統的狀態和輸出。計算狀態和輸出的連續時間點稱為時間步。時間步之間的時間長度稱為步長。步長取決于用來計算系統連續狀態、系統基礎采樣時間以及系統的連續狀態是否具有不連續性。
仿真環階段有兩個子階段:循環初始化階段和循環迭代階段。初始化階段在循環開始時出現一次。迭代階段在從仿真開始到仿真停止的時間段內的每個時間步重復一次。在仿真開始時,模型將指定要仿真的系統的初始狀態和輸出。在每個時間步中,將計算系統的輸入、狀態和輸出的新值,并且將更新該模型以反映計算的值。仿真結束時,該模型將反映系統的輸入、狀態和輸出的最終值。Simulink 軟件會提供數據顯示和日志記錄模塊。您可以通過在模型中包含這些模塊來顯示和/或記錄中間結果。
仿真環階段的速度提升,除了建模本身的影響,在選擇求解器和發揮硬件性能(多核、GPU、超算)方面是相輔相成的,這個也跟 MATLAB 的版本更新有著密切的聯系,除了求解器會在1.4中提到,后面在第2、3、4里都是跟這兩相關的。
1.2 建模方法
假設我們要仿真一個閉環的自動駕駛系統模型。
在這里,用什么方法分別對傳感(Sensors)、感知(Perception)、規劃(Planning)、控制(Control)以及被控對象(Plant model, Passenger Vehicle)和環境/場景(Environment/Scenario)建模,以及如何連接各子系統,對整體上的仿真速度顯然有很大的影響。
從場景建模來說,現在 MATLAB 支持 Unreal Engine,以及 RoadRunner 工具鏈,這一塊已經可以單獨跑了(單機多進程,或者干脆雙機分開跑),你可以看作是一種聯合仿真,在考慮仿真性能優化的時候基本可以忽略它們,堆硬件(GPU)是最直接靠譜的出路——對于多體動力學的仿真,你如果從 UG 或 Solidworks 等軟件導入 3D 模型,在 Simulink 的仿真過程中展示 3D 動態效果,配置一塊獨立顯卡也是非常有必要的。
被控對象建模則有不同的方法。過去我們往往在模型的保真度和計算性能上做取舍,或者結合更抽象高效的數學模型與查表來避免對機電液物理模型的求解并同時達到合適的仿真精度要求,但這對于要考慮整車眾多性能(諸如電池充電狀態、速度曲線、續航能力、熱管理水平等)的系統級仿真而言,模型大了跑起來就很慢,因此借用深度學習和實驗數據構建降階的替代模型就成了一種可能的優雅的選擇。
關于用深度學習來實現模型降階,這里給一篇文章供大家參考:
至于數學模型的構建,更多還是要看我們建模的經驗和水平,Simulink 用戶指南第15章,建模最佳實踐中給出的對串聯 RLC 電路建模求解的例子,就很好的闡釋了什么是“最佳形式的數學模型”,雖然過于簡單了點,但很有參考意義。
關于采用什么樣的方法建模,歸納起來有以下幾點供參考:
· 對于數學模型,嘗試找到它的最佳形式
· 對于多域物理系統,建議優先考慮 Simscape。在必要的情況下(Simscape 不滿足需求)或者對數學方法構建被控對象模型很熟悉的情況下可以用數學方式建模,但自己造輪子要求總歸是比較高的。
使用 Simscape 將跨越機械、電氣、液壓和其他物理領域的系統建模為物理網絡。Simscape 構造描述模型行為的 DAE。軟件將這些方程與模型的其余部分集成,然后直接解算 DAE。Simulink 同時對不同物理領域中的組件變量求解,從而避免代數環問題。
· 對于大型物理網絡,如果所有子系統都是建的詳細模型,則很難讓仿真跑得快,建議充分利用變體,對于分析目標影響不大的子系統,使用諸如查表的方法表達外特性或者抽象的物理模型替代(如用理想開關替代 IGBT,甚至用等效電路替代開關從而進一步提高仿真效率),更進一步,還可以用數據驅動+深度學習的方法來建模。
· 以上基本都是宏觀方向上的,細節在哪里?看這個:Simulink 用戶指南 (僅已翻譯的部分 R2021b)[8],第31章 動態系統仿真 -> 提高仿真性能和準確性 -> 提高性能的建模方法,內容較多,涵蓋“加速初始化階段”、“降低模型交互性”、“降低模型的復雜度”、“選擇和配置求解器”、“保存仿真狀態”各個方面,后面的章節只有求解器會重復,建議細看一下(4頁文檔)。
1.3 模型架構
一個好的模型,跟一份好的代碼,有一個最重要的共同點就是架構都要好。相較于寫代碼不管架構只堆功能(有點難),在 Simulink 里畫模型不看架構顯然更容易過得下去,而且很多情況甚至過得還不錯,但跟代碼一樣,一旦整體規模上去了,就成了災難——好在 Simulink 模型重構還是要比代碼來得簡單些。
一個好的模型架構,不僅意味著易于維護、易于擴展,也意味著易于測試(確保單元測試覆蓋率),更是有效提高仿真性能的基礎。有關模型架構,可以參考 Simulink 用戶指南 (僅已翻譯的部分 R2021b)[9],第22章“大型建模”中的“基于組件的建模規范”和“比較模型組件的功能”,這里抄錄性能相關的部分供參考。事實上,有關建模規范,尤其是在滿足高可靠高完整性的要求方面,有更完備的內容,但這不在本文探討范圍內,有興趣的可以去MathWorks 官網查詢或者聯系 MathWorks 銷售以便跟他們的工程師直接交流。
組件建模要求考慮事項——“性能要求”
? 增量模型加載
? 編譯工件重用
? 降低大型模型的內存使用量
? 消除人為代數環
對于不太想了解這么多細節的人來說,我們簡單歸納幾點在下面,作為大家建模時在仿真性能方面的參考:
· 模型引用!模型引用!模型引用!重要的事情說4遍,多用模型引用(Model Reference)。模型引用對于仿真性能的四個方面均有重要影響
· 子系統引用是 R2019b 版本才出來的,子系統引用的輸入輸出端口支持 Simscape 物理連接
· 模型引用雖然出來很早,但其端口至今仍不支持 Simscape 物理連接(R2022a),因此如果想用模型引用對物理網絡進行分割封裝,需要將端口等效轉換為 Simulink 信號(自行分解物理網絡有難度,可以向 MathWorks 咨詢)
· 子系統引用雖然不支持編譯工件重用,但它支持增量方式加載;換句話說,使用引用子系統不能帶來模型編譯上的效率提升,但對維護超大物理網絡還是有用的
三種組件化技術
在模型架構的最后部分,要提一下利用多 CPU 核提速單一模型仿真的問題,換句話說,就是多線程協同仿真的問題,這個問題重點會在第二章的進階部分講,這里提一下,是因為它跟模型引用密切相關。
1.4 求解器的選擇
求解器的選擇是一個很經典又富有挑戰的話題,說很經典,是因為求解器算法本身大都歲月悠久了,譬如龍格-庫塔(Runge-Kutta)迭代求解非線性常微分方程的方法于 1900 年左右被提出,歐拉方法則更早;而挑戰呢,似乎是 Simulink 不像一些特定領域的專業軟件有默認的甚至固定的求解器(它們往往只需求解某一類問題),在 Simulink 上,你還得自己選求解器(當然,從 R2015b 開始你可以選 auto solver 讓它自動給你選),可選項還挺多,常常不知道該選啥才能跑的快(還得結合模型的特性、精度要求與采樣時間的要求等)。
另一個方面,因為有其它專業軟件在仿真速度方面的比較,也常常有人(包括我自己)會質疑是不是 MATLAB 的求解器不行,而忽略了在建模方法上的差異,這就很容易引錯方向。
考慮到求解器的這些個情況,我就不拷貝黏貼了細節了,去下面兩個鏈接自己看吧:
? 比較求解器[10](參見 Simulink 用戶指南 第3章 Simulink 簡介 -> Simulink 工作原理 -> 比較求解器)
? 選擇求解器[11](參見 Simulink 用戶指南 第3章 Simulink 簡介 -> Simulink 工作原理 -> 比較求解器)
求解器的選擇
當然,關于求解器,老朽也有幾點額外說明:
· 從 R2015b 開始,你可以使用 auto solver(自動求解器),讓 Simulink 自動選擇一個求解器與步長進行仿真。自動求解器根據模型的動態特性,推薦一個固定步長或可變步長求解器,自動確定最大步長值。R2016a 開始自動求解器能計算模型剛度,對于剛性模型會選擇 ode15s 求解。
· 從 R2019a 開始,支持 odeN solver,能快速求解有過零檢測的系統?!癝imulink 提供了一個變步長求解器,允許您使用變步長(無誤差控制)積分來求解動態模型,同時保持過零點的精度”
odeN (Nonadaptive)
? 從 R2018a 在 Simscape 中引入 Partitioning Solver[12] 后(限制較多不太好用),MathWorks Advisory Board(MAB)就在講 Local solver,然后到 R2022a 才真正發布對 Local solver 的支持。通過 Local solver,可以為模型的不同部分(模型引用!)選擇不同的求解器,從而來提高仿真速度。這個新特性允許我們為較慢的模型選擇計算成本更低的求解器。請注意:模型引用模塊上 Local Solver 選項默認是關著的,你得自己打開它。
Local Solver Basics[13]
Use local solver when referencing model[14]
? 從 R2022a 開始,使用固定步長的求解器也可以很好地應對過零檢測了。這對時間步長偏大的情況很有用。給張圖大家自己看看吧~~
定步長求解器的過零檢測
? 看到這里,是不是要說:你看,還是求解器的水平問題嘛~~呃,好吧,求解器確實重要,但更重要的是建模的方法,不然你就得自己造輪子實踐了。
? 無論是 odeN(R2019a)、ode1be(R2020a),還是對 local solver(R2022a)的支持,都未必能解決你的問題,現實的約束常常讓人頭疼,但是很抱歉,關于求解器老朽也只能到這里了,而且具體選哪個,參數怎么設,還是得 case by case 來看,實在搞不定,還是找 MathWorks 直接問吧~~
1.5 仿真模式
前面幾個部分寫得真的是太費力了,這部分還是拷貝粘貼吧。以下內容出自 Simulink 用戶指南第35章加速模型。
加速和快速加速模式使用 Simulink Coder 產品的部分內容創建可執行文件。加速和快速加速模式會替換 Simulink 仿真中常用的解釋代碼,從而縮短模型的運行時間。雖然加速模式會使用一些 Simulink Coder 代碼生成技術,但您不需要安裝 Simulink Coder 軟件即可為您的模型加速。
· 普通模式
在普通模式下,MATLAB 技術計算環境是 Simulink 軟件的基礎環境。Simulink 控制仿真過程中使用的求解器和模型方法。模型方法包括模型輸出的計算等內容。普通模式在一個進程中運行。
普通模式
· 加速模式
默認情況下,加速模式采用即時 (JIT) 加速方式在內存中生成執行引擎,而不是生成 C 代碼或 MEX 文件。您還可以將模型回退到經典加速模式,在這種模式下,Simulink 將生成代碼并將代碼鏈接到 C-MEX SFunction。在加速模式下,模型方法與 Simulink 軟件相分離,它們將作為之后進行仿真時使用的加速目標代碼的一部分。Simulink 會在重用加速目標代碼之前檢查代碼是否為最新版本。有關詳細信息,請參閱“Code Regeneration in Accelerated Models”。在加速模式下,有兩種操作模式。即時加速模式 在此默認模式下,Simulink 在內存中只為頂級模型(而不為引用模型)生成執行引擎。因此,仿真過程中不需要使用 C 編譯器。由于加速目標代碼在內存中,因此只要模型處于打開狀態,就可以重用這些代碼。Simulink 還會序列化加速目標代碼,因此當模型處于打開狀態時,不需要重新構建模型。
即時加速模式
經典加速模式
要使用生成 C 代碼的經典加速模式對您的模型進行仿真,請運行以下命令:
set_param(0, 'GlobalUseClassicAccelMode', 'on');
在此模式下,Simulink 會生成代碼并將代碼鏈接到與 Simulink 軟件進行通信的共享庫。MATLAB 與Simulink 的目標代碼執行過程相同。
經典加速模式
· 快速加速模式
快速加速模式從您的模型中創建一個快速加速獨立可執行文件。這個可執行文件包含求解器和模型方法,但位于 MATLAB 和 Simulink 的外部。它使用外部模式(請參閱“External Mode Communication”(Simulink Coder))與 Simulink 通信。MATLAB 和 Simulink 在一個進程中運行,如果有第二個處理內核可用,獨立可執行文件將在該內核中運行。
快速加速模式
關于如何選擇仿真模式,大家看文檔吧,中文的:選擇仿真模式[15]。提煉幾句話放下面供參考:
· 普通模式在調整模型和顯示結果方面提供了最大的靈活性,但運行速度最慢。
· 加速模式在性能以及與模型的交互方面介于普通和快速加速模式之間。加速模式不支持大多數運行時診斷。
· 快速加速模式的運行速度最快,但此模式不支持調試器或探查器,而且僅適用于模型中的所有模塊可生成 C/C++ 代碼或編譯為 MEX 文件的模型。
另外,快速加速模式支持仿真目標語言為C++也是最近版本才有的功能(似乎文檔里甚至都沒公開),這個主要解決了深度學習不支持C語言代碼生成的問題~~舊版本的話,折中的辦法是先生成 C++,再用 C 封裝,編譯成 dll 或 mex 后再集成進來,道路有點曲折,好在現在不需要這么干了。
1.6 性能問題分析
其實這節應該放到最前面,但考慮到如果不了解基礎光靠工具分析也很難解決根本問題,所以放到這還是更合適些。
Simulink 里其實提供了兩個分析性能的手段,但性能分析要結合前面的建模與求解器一起來做,給張圖:
加速仿真需要關注每個階段
具體的分析收到要落實到兩個工具上,分別是 Performance Advisor 和 Solver Profiler,具體這里就不描述了,大家看文檔更靠譜(這兩部分在 Simulink User's Guide 英文版pdf里才有,因為截至 R2022a 還沒中文化):
· Improve Simulation Performance Using Performance Advisor[16](英文 Simulink User's Guide 第34章)
· Examine Model Dynamics Using Solver Profiler[17](英文 Simulink User's Guide 第35章)
這里,我們來舉一個實戰小栗子,嘗試用 Performance Advisor 找到原因并修改模型使它跑的快起來(如果很熟悉 Simulink,就不用廢那么大功夫了)。
源頭是我這篇文章里提到的問題:老朽筆記:MATLAB 強化學習入門(1+)[18],把強化學習智能體替換成只有推理模型后,仿真變慢了 N 倍,當時沒找到原因。
那么,我們打開模型,然后切換到“調試”菜單,點擊“性能顧問”,打開性能顧問(performance advisor)的界面。
點擊“運行所選檢查”,經過漫長等待,得到報告:
所有問題項看下來,其它都改了,沒有效果,剩下這項:檢查驅動導數端口的離散信號!我們再打開兩個模型,將信號的全部屬性召喚出來(點擊左邊工具條上的雙箭頭圖標,選“全部”即可),很顯然,區別就在 Calculate Observation 模塊的輸出原本是采樣時間為 0.025 的離散信號,變成了連續信號(FiM固定子步),這導致后面的 MATLAB function(evaluatePolicy)以及機器人物理模型的計算量急劇增加。
我們要做的就是修改 Calculate Observation 模塊中最右邊一個模塊 RateTransition 的采樣時間,強制它為 0.025,如此就能得到跟原模型一樣的仿真速度(和精度)了。
至于 Simulink 默認行為為何會變,還是等老朽問完專家再來探討吧。
審核編輯:湯梓紅
-
仿真
+關注
關注
50文章
4099瀏覽量
133718 -
Simulink
+關注
關注
22文章
536瀏覽量
62455
原文標題:如何加速 Simulink 仿真?(上)
文章出處:【微信號:MATLAB,微信公眾號:MATLAB】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論