http://www.matlabsky.com/thread-38774-1-1.html
本文轉載於MathWorks 中國高級工程師董淑成的帖子內容。為了方便閱讀,對原文進行了重新整理編輯。
之前有網友引發了一些討論,為了方便大家進一步討論,專門開貼,討論基於模型的設計。題目有點大,以我的個人經歷,我只能說說基於模型的嵌入式軟件設計,我先拋磚引玉吧。
先胡亂問幾個大問題:
- 什么叫基於模型的設計?
- 為什么要基於模型的設計?
- 基於模型的設計過程中,需要做什么事情?
再問幾個小問題:
- 模型驗證是否必要?
- 模型驗證有哪些工作可以做?
- 模型驗證是否一定需要被控對象模型?
- 代碼生成效率如何?
- 底層驅動是否要建模?
- Embedded Coder(以前的RTW Embedded Coder)支持哪些芯片?
- MIL、SIL、PIL、HIL的目的和實現方式?
- 如何定點化?
- 如何做代碼集成?
也希望版上的網友提出各自的問題及見解,我們一起討論。
什么叫基於模型的設計?
這是一個很大的話題,因為本人能力所限,僅討論使用Simulink模型開發嵌入式軟件的設計過程。也就是說,我只能聊基於模型的嵌入式軟件設計。
我的理解是,通過對算法建模進行軟件設計的過程,都可以叫基於模型的設計。
當然,如果僅限於算法建模,把Simulink/Stateflow當做Visio使用,而不去進行其他環節的工作,這樣的基於模型設計是不完整的,可能對你的開發效率不會有很大的提升。
如果想通過基於模型的設計提升軟件開發團隊的開發效率,提高軟件品質,我覺得至少有如下幾點可以考慮:
- 算法模型的驗證
- 文檔自動化
- 代碼和模型的等效性驗證
傳統的開發過程中,我們有一個環節,需求捕獲,也即,從系統需求分解出軟件需求。
在基於模型的設計過程中,我們同樣可以通過分析系統需求,獲得軟件需求。當然,根據系統需求的詳細程度,我們可以考慮是否要寫專門的軟件需求。
在基於模型的軟件設計中,我們主要關心的是系統的功能需求,或者說可以通過軟件實現的功能需求。如果這部分需求在系統需求文檔里已經有非常清楚的定義,那么我們可以以系統需求文檔作為依據建立模型。
當然,如果系統需求不是足夠清楚,那我們有必要編寫專門的軟件需求文檔。如果不考慮Simulink/Stateflow的應用上的問題,也就是說,如果我們都是熟練的Simulink/Stateflow用戶,那么建模過程的主要工作是需求分析,通俗點講,需求弄清楚了,建模也就是非常簡單的事情了。當然,建模的時候,要考慮未來的驗證、實現以及后期維護的問題。
我個人的體會,這個階段,不要着急建模,一定要先弄清需求,另外,建模的時候,模型架構非常重要。
有了模型之后,接下來要做什么事情?代碼生成?
這是很多比較初級的用戶容易犯的錯誤,犯這個錯誤的用戶,很大程度上是因為沒有弄清楚為什么要做基於模型的設計?
為什么要做基於模型的設計?我相信很多用戶沒有仔細考慮這個問題,很多用戶做基於模型的設計的理由是:國外的公司都這么做,同行其他公司都這么做......
弄清為什么要基於模型的設計,也就是要弄清楚基於模型的設計到底可以給我們帶來哪些好處?
很多人會非常自然的想到,代碼生成,代碼生成可以提高軟件開發效率。沒錯,代碼生成是一個很大的好處,但,代碼生成不是唯一的,也不是最大的好處。
代碼生成最大的好處是,算法的早期驗證,之前NASA有研究表明,開發初期引入的bug,如果到了晚期才發現出來,那么修復這一的bug,會產生非常大的費用。所以,我們期望能夠盡早的發現開發過程中引入的bug。
如何盡早的發現設計上的錯誤?傳統的開發模式里,我們使用review的方式去發現錯誤,在質量體系ISO9001里面有定義,任何一份設計,都必須要評審。評審的目的,也就是為了發現這個階段的錯誤,以防錯誤被帶到后續的開發過程中。
而評審的效率,卻是非常低下的。我想凡是參加評審的網友都會有體會。比如,我在做完一份設計之后,我會邀請我的同事來評審我的工作,而參加評審的這些同事,往往不能有足夠的時間了解我的這份工作,而只能在評審會上聽我介紹我做的工作,這樣的評審,可能會發現一些非常明顯的問題,除此之外的,很難發現問題。
評審作為一種非常傳統的驗證方式,並不能及時發現設計過程中引入的各種錯誤。而仿真,從效率上講,要遠高於評審,仿真更容易發現設計中的問題。
仿真是可以運行的,如果我們設定一些輸入,運行模型之后,我們會得到相應的輸出,我們很容易觀測到此時的輸出是否是我們期望的輸出。
另外還有好處,仿真的結果是確定的,給定輸入,就會得到確定的輸出,當然,期望輸出也是確定的。而不像評審,同樣的文字,對於不同人,可能理解成不同的含義。
文檔自動化
代碼生成和早期驗證之外,基於模型的設計,還可以給我們帶來其他好處,比如文檔自動化。
我們經常聽到這樣的說法:
- 我們終於把軟件發布出去了,現在可以有時間補文檔了...
- 下個月要audit了,所有同事都在補文檔....
這里我要問:為什么要補文檔?
補文檔,我們可以從中得到兩個方面的信息:
1.文檔很重要,不能沒有,至少從質量體系上要求我們必須有文檔
2.工程師都不願意寫文檔,是啊,如果願意寫文檔的話,在開發過程中自然會把各類文檔寫起來的。
好,工程師不願意寫,開發過程中又不能少,如果計算機可以幫我們寫,豈不是很美好的事情。基於模型的設計,可以幫助我們實現文檔自動化,至少有相當大的一部分文檔可以讓計算機替我們寫。
圖形化設計
其實,基於模型的設計,還有一個天然的優勢:圖形化設計。
對於工程師來講,圖形化的東西,本身就比文字更容易理解,否則我們在軟件開發過程中也不會去畫流程圖和狀態機了。
所以總結一下,基於模型的設計可以從以下方面給我們提供便利:
1. 圖形化設計
2. 早期驗證
3. 代碼生成
4. 文檔自動化
前面我大概論述了為什么要做基於模型的設計,或者說基於模型的設計可以給我們帶來哪些好處。這些好處,最終會大大提高開發效率,並且改善軟件品質。
下面,我在說說基於模型的設計(MBD)里有哪些事情要做?
劉博士說的沒錯,基於模型的設計,自然模型最重要,如何建模,毫無疑問是最為重要的環節。
在軟件產品開發中,建模活動里,耗時最多的,就應該是需求分析了,需求分析不僅包括如何正確理解軟件需求,而且要考慮如何通過模型實現,真正的畫模型的時間,相比之下並不多,如果Simulink/Stateflow用的熟的話,真正打開MATLAB畫模型的時間占建模階段總時間的1/3都不到。
建模之后,接下來就是模型驗證,驗證,英文單詞Verification,英文里面還有另外一個詞Validation--確認,很多人不清楚這兩個詞之間的區別,通俗點講:Verification是考察你是否正確的做了一件事,而Validation,則是考察你是否做出了正確的東西。一個強調的是過程,一個在乎的是結果。
閑話少說,咱們繼續回到模型驗證上來,通常模型驗證包含如下活動:建模標准的檢查、評審、單元測試、快速原型。(如果說的不完善,歡迎大家補充)
建模標准的檢查,可以通過模型檢查工具自動完成,建模標准檢查的意義,和傳統開發模式里C編碼標准的意義一致,這里不展開了。
有關評審和單元測試,再專門開貼說吧。
- 模型驗證之后,接下來就可以做代碼生成了,有關代碼生成,也專門討論吧。
- 代碼生成之后,需要做代碼驗證,基於模型的開發過程里面,SIL、PIL都是常用的代碼驗證方式。
- 在代碼做完SIL或者PIL測試之后,要考慮軟件集成了,即應用層軟件,也就是通過Simulink模型生成的軟件,和底層驅動軟件之間的集成。
- 軟件集成之后,后面的事情,基本上和傳統的開發模式差不多了,當然,相對於傳統的開發模式,你可以多一個HIL環節出來,不過話又說回來,即便是傳統的開發模式,也一樣可以有HIL這個環節的。
有關HIL的實現及目的,以后再說。
再說說模型驗證的必要性。
我在進入MathWorks之后,接觸過很多客戶,不少客戶在最初引入基於模型設計的時候,根本不在意模型驗證工作,他們經常在模型編譯通過之后就拿去生成代碼,有了代碼之后將代碼下載到各種快速原型設備上去測試算法,Simulink的仿真功能基本上成了擺設。並且在這個階段,不管我如何苦口婆心的給他們介紹模型驗證的重要性,在他們那邊,卻總有各種各樣的借口去省略模型驗證環節,“項目時間太緊,模型來不及測”,“我們知道規范的開發流程,但是現在人手不夠”。
當然,這類用戶經常在這樣折騰了一段時間之后,還是要回到模型測試上來,他們最終會發現,在HIL設備上測試算法,實在太難,當然,也有堅持的,堅持的結果就是他們所謂的基於模型的設計,開發效率比傳統的開發模式高不了多少。
其實,這個問題我們可以這么去看,模型階段的測試,我們是可以分模塊進行的,而HIL上測試,基本上是集成之后的軟件。比如,一個軟件有10個模塊,在HIL設備上,你很難分離出每個模塊的bug,而如果是按模塊做單元測試,則就是針對的一個具體的模塊。打一個不算恰當的比方,我們都知道一塊2克拉的鑽石,價格肯定不是一塊1克拉鑽石的兩倍。類似的,如果每個軟件模塊有2個bug,那么你從集成好的軟件里去消除這20個bug,耗費的精力肯定不是從每個單元模塊里去消除bug所耗精力的總和。
說白了,早期驗證是非常重要的,很多軟件工程的教材里都有相關的統計數據說明早期驗證的重要性,對應到基於模型的開發過程,能在模型級別做的驗證,一定不要拖到后續的環節中。
中國有句老話,“心急吃不了熱豆腐”,“項目時間緊”或者“人手不夠”不能成為我們忽略模型測試的借口。
繼續說一下MBD開發過程中都有哪些驗證工作(verification)要做。
模型出來並且可以編譯之后,首先要做建模標准檢查,這個過程使用工具(比如MathWorks公司的Simulink Verification & Validation提供的model advisor)自動化的完成,檢查過后,修改模型中不符合公司建模規則的項目。
接下來,就可以進行模型評審了,也就是說,評審的模型有兩個前提,一是可以編譯的,二是符合公司建模規則的。這兩個前提可以幫助我們消除模型中的一些低級錯誤,避免在評審過程中有太多的時間花費在這些錯誤上。因為評審是建模的工程師和其他同事共同參與的活動,做到上述兩個前提,也是對其他同事工作時間的一種尊重。
評審之后,建模的工程師會修改評審中發現的問題,問題多的話,一般會要求修改之后再進行“再評審”,直到在評審中不會發現大量問題。
接下來,我們可以使用Simulink Design Verifier進行模型的結構分析,借助於Simulink Design Verifier自動生成測試用例的功能,去檢查結構上是否存在問題,比如是否有不合理的邏輯設計,是否有運行不到的分支等。
再往后,就可以進行模型單元級別的功能測試了。軟件開發過程中,對單元測試的要求是很高的,一般會根據應用的安全性、可靠性要求,給出測試的覆蓋率要求。
這個過程中工作量最大的應該是測試用例設計以及測試向量的生成。測試用例設計,我們一般會根據需求去設計測試用例,當然,也會結合模型結構設計測試用例,這樣說來,這里的測試,已經包含了黑盒測試和白盒測試。有了測試用例,如何把測試用例轉換為測試向量,這也是非常重要的環節。我們知道,在MBD開發過程中,代碼都可以自動生成,其他環節,我們要努力做到自動化實現。我們可以使用MATLAB腳本開發一些轉換工具用於將測試用例轉換為測試向量,我們還可以通過腳本實現測試過程的自動化。
測試的指標,即測試覆蓋率是否達到公司的要求或者行業的要求。
單元級別的功能測試完成之后,我們自然會進行集成測試,當然,集成測試是分階段、有步驟的,我們可以先把一些單元模塊集成為組件級,進行組件級的集成測試,然后再將組件集成為系統級,進行系統級測試。集成測試和單元測試關注的內容不同,集成測試,我們更關注於單元模塊之間的借口關系、調用關系等等,所以,單元測試中要求的判定覆蓋率、MCDC覆蓋率等,在集成測試中沒有這樣的要求。
條件允許的情況下,集成測試之前或者之后,可以通過快速原型的方式和實物相連,進行測試。
集成測試通過之后,我們基本上可以認為模型或者說算法是正確的了。接下來,我們就可以進行代碼生成了。
代碼生成之后,會跟着做SIL、PIL、HIL等測試,所有這些In-the-Loop測試都不是必須的,工程師應該根絕項目的實際情況,選擇合理的測試方案,當然,建議SIL測試不要省略,原因在於這種測試的確非常方便做,並且也的確會發現一些代碼生成過程中出現的問題。
前面提到模型驗證,下面再說說代碼生成。
代碼生成的前提是模型已經是驗證過的模型,或者說,是正確的模型。
正確的模型包含兩層含義,模型做過足夠多的驗證,驗證的結果都是正確的。前面提到的各種驗證方式,都有必要做,對於功能測試來講,還有必要達到足夠高的覆蓋率要求。
做到以上這些,就可以考慮進行代碼生成工作了,代碼生成是否就是按一下“Code Generation”按鈕的工作呢?工程項目開發中,沒那么簡單,代碼生成過程中,工程師要做的主要工作是數據管理工作,除此之外,還會有一些代碼相關的配置,比如函數原型、比如代碼文件等等。
數據管理主要是對Simulink/Stateflow模型中的兩類數據進行管理,一是信號,一是參數。對應於C代碼,我們可以簡單的把信號對應到變量上,而參數,則是不通過程序運行而發生變化的,參數的變化,一般是通過人工調節完成的,也就是參數調節,參數調節的目的是為了選擇合適的參數以得到最佳的性能。
數據管理的方式,使用的是數據對象進行數據管理,這里的“對象”二字,和我們經常聽到的“面向對象編程”里面的“對象”意義相同。Simulink為用戶事先定義好兩個包,一個是Simulink Package,一個是mpt Package。以Simulink Package為例,包里面有類,分別為Simulink.Signal和Simulink.Parameter兩個類。用戶可以通過這兩個類定義相應的對象(Object),然后通過類提供的屬性(Property)定義數據的屬性。其實這兩個類里面除了屬性之外,還定義了方法(Method),一般情況下,我們管理數據,使用屬性就夠了。
當然,不管是Simulink Package還是mtp Package,都不能完全滿足用戶的所有要求,所以,很多時候,需要用戶定義自己的Package。依然按照面向對象里面的一些概念,我們可以從Simulink Package或者mpt Package繼承並創建自己的包。所有我們關心的數據都通過數據對象的方式做了定義之后,接下來的工作,就是按下按鈕,生成代碼了。
------------------------------------------------------------------------------------
因為前面預留的帖子不夠多,所以,就繼續在這個帖子里討論一下自動生成的代碼吧。
首先說一下大家很關心的效率問題,代碼效率,我之前做過對比,比一般的工程師寫的代碼效率要高,當然,我相信對於那種C代碼高手,一定可以寫出效率更高的代碼。不過我想強調的是,自動生成的代碼,是可以用的,不要有任何心理障礙,畢竟,我們項目開發中的多數工程師也不是絕對的C語言高手。另外,關於效率,我最近也做過一次對比,就在這個帖子最開頭提到的那個貼子里,雖然代碼沒有人去做編譯,但從代碼行數來看,和一個寫了6年C代碼的工程師的代碼基本差不多。
再說說代碼可讀性的問題,很多人和我強調代碼的可讀性不如手寫的好,我有條件的承認這一點。為什么是有條件的承認呢,我想說,如果你對模型做足夠多的配置,生成的代碼可讀性基本上可以和手寫的差不多。當然,我更想強調,在基於模型的開發過程中,我們是不讀代碼的(如果一定要讀,那也是讀那個.h文件),我們有其他方式保證代碼是正確的,無須讀代碼。
再有一個問題,就是代碼的集成問題,很多人也比較關心自動生成的代碼如何集成到底層代碼或者如何與其他手寫代碼做集成的問題,我一般會問他,如果這個模塊的代碼是手寫的,你會怎么集成?他當然知道手寫代碼該怎么集成,好,自動生成的代碼也同樣可以集成。做代碼集成的時候,我們關心的就是那個.h文件。
有關底層驅動的建模
我一直認為在產品化項目開發中,底層驅動是沒有必要建模的。
原因如下:
1)底層驅動在Simulink環境下不能仿真;
2)底層驅動建模需要熟悉另外一種腳本語言——TLC;
3)產品化項目的底層軟件往往很大,有些項目的底層軟件甚至大於應用層軟件,如此大的軟件轉換成Simulink下的TLC實現,不容易操作。
當然,有人會說,一旦有了底層驅動模型,就可以非常方便的實現Simulink模型到單片機hex文件的一鍵式實現,的確這樣做貌似讓整個開發過程的自動化程度得以提升,但是,不要忘記,你要開發出一個安全、可靠的底層模塊庫,會需要大量的時間投入,尤其在使用TLC設計的時候,TLC本身就是另外一種新的語言,同時這種語言所提供的調試環境也不盡如人意;相反,如果不使用這種一鍵式的模式,而是采用手工集成的方式實現自動生成的應用層代碼與底層代碼做集成,也是非常簡單,非常輕松的事情。
總結一下,一鍵式的實現hex文件生成並不能明顯提高開發效率,而開發出這樣一個底層模塊庫,卻需要花費大量的時間。
----------------------------------------------------------------------------------------
到MathWorks工作以來,經常被客戶問到這樣的問題:MATLAB的代碼生成支持什么芯片?
支持什么芯片?MATLAB生成的是ANSI C代碼,支持所有編譯器,也就是支持所有芯片。當然,我說的是應用層代碼的生成,不包括底層驅動代碼。
我也知道很多人問這個問題的時候,心里面想着的是Target Support Package這樣一個工具包,這個包里面的確提供了一些MCU或者DSP的底層驅動模塊,借助於這些模塊,我們可以生成底層代碼。不過,繼續強調一下,在很多工程化的項目里,這不是一個產品化的解決方案,這種方案更適合於做算法的快速驗證。也正是因為這不是一個產品化的方案,所以這個產品的用戶非常少,以至於MATLAB從2011a開始,不再單獨銷售這個模塊,並不承諾以后會繼續更新這個模塊,這個模塊連同IDE Link被打包到Embedded Coder產品中,只有你購買了Embedded Coder,你就可以使用這個模塊了。
--------------------------------------------------------------------------------------------
再說說In-the-Loop測試的問題
我們經常聽到的有MIL、SIL、PIL、HIL等,在基於模型設計的開發過程中,是否都要做這些In-the-Loop測試?
我認為所有的In-the-Loop都不是一定要做的,不過,我非常建議不要省略SIL環節。
1)MIL,模型在環測試,在Simulink環境里,除建立控制器模型之外,還需要建立被控對象模型,講控制器和被控對象連接起來並形成閉環,讓控制器去控制被控對象。
是否一定要做這個In-the-Loop呢?或者說,是否一定要有被控對象模型呢?其實不一定,這取決於模型驗證的可能方式。在不少應用里,控制器模型的輸出是開關量,工程師可以很方便的通過設定輸入並給出期望輸出,這樣的情況,被控對象是沒必要的,比如,汽車電子里面的車身控制,控制一個燈的開或者關,只需要知道輸出是ON或者OFF即可,沒必要去做一個燈泡的模型放到Simulink里。
2)SIL,軟件在環測試,軟件在環測試,應該說是從模型在環測試引申過來的,區別只是把控制器的模型換成了由控制器模型生成的C代碼編譯成的S-function,SIL的目的是為了驗證生成的代碼和模型在功能上是否一致,或者說驗證生成的代碼和模型在功能上是否等效。
驗證等效性,是否一定需要被控對象模型?不必要,既然驗證生成的代碼和模型的一致性,那只需要給生成代碼和用於代碼生成的模型相同的輸入,比較它們在相同的輸入條件下,輸出是否一致即可。
3)PIL,PIL有兩個目的,一是為了等效性驗證,二是為了測量模型生成的代碼在目標處理器上的運行時間。有關運行時間的測量,如果你選擇的處理器足夠強大,或者你非常把握目標代碼的運行不會超限,那么PIL的意義就要打折扣了。
4)HIL測試的目的是為了驗證控制器的,HIL過程中,會把被控對象的模型生成C代碼並編譯成可執行的文件放到工控機上運行,以便工控機替代真是的被控對象,然后把控制器和工控機連接起來,實現閉環控制,從控制器的角度上看,就相當於工作到實際控制系統之中。HIL經常被用於以下幾種情形:
a)被控對象非常昂貴,如果控制器不成熟會導致被控對象的損害;
b)被控對象失效會危及人身安全;
c)開發過程中,先開發出了控制器,而被控對象還沒有開發出來。