本節書摘來自華章出版社《資訊實體融合系統(cps)設計、模組化與仿真——基于 ptolemy ii 平台》一書中的第2章,第2.6節,作者:[美]愛德華·阿什福德·李(edward ashford lee),更多章節内容可以通路雲栖社群“華章計算機”公衆号檢視
ptolemy ii可以定義面向角色的類(actor-oriented class)(lee et al., 2009a)。這些類被定義後可以用于執行個體(instance)和子類(subclass)的建立,它們都使用了類繼承(inheritance)的概念。類為角色提供通用的定義(或模闆)。執行個體是類的一個單獨的、特定的實作,一個子類源于父類——它包含和父類相同的結構,但可能有一些修改。這種方法提高了設計的子產品化,詳見下面的例子。
例2.1 結合在2.3節中開發的模型,如圖2-29所示。假設希望建立信道角色的多個執行個體,如圖2-30所示。在圖2-30中,正弦波信号通過5個不同的信道(注意正弦波和信道之間的黑色菱形關系符号,它表示将相同的信号分别廣播到5個信道)。信道的輸出被疊加在一起并以圖形顯示。結果是一條明顯比單信道輸出正弦波清晰的正弦波。(在通信系統中,這種技術稱為分集系統。信道的多個副本(每個副本都攜帶獨立噪聲)用于實作可靠通信。)
盡管上述方法有效,但依然是個糟糕的設計,原因有兩點。首先在模型中,5個信道是通過硬連接配接實作的(将在下一節解釋這個問題)。其次,每個信道都是圖2-29中複合角色的副本。是以,如果信道的設計需要改變,所有5個副本都必須改變。是以這種方法使得模型難以維護或修改。
使用類和執行個體的一個小的優勢就是,模型的xml檔案表示會更小,因為類的設計隻給出一次,而不是多次。
一個更好的方法是定義一個channel類,然後用這個類的執行個體來實作分集系統。為了實作這種修改,從圖2-29中的設計開始,将連向信道的連接配接删去,如圖2-31所示。然後單擊并選擇convert to class。(注意,如果第一步沒有将那些連接配接删去,那麼當進行試圖轉化時會出現錯誤提示)角色圖示會獲得一個藍色邊框,它是一個視覺上的提示,提示這是一個類而不是一個普通的角色(它是執行個體)。

圖2-31 建立并使用一個信道(channel)類
類在模型執行中不起任何作用,它隻是必須被執行個體化元件的定義而已。按照慣例,将類置于模型的頂部,挨着訓示器,因為它們都是表示聲明。
還請注意,除了使用convert to class外,還可以從utilities庫裡拖拽一個composite classde?nition的執行個體,然後選擇open actor并填入類定義。然後給這個類定義起一個具體的名字,比如channel。
當已經定義了一個類時,可以通過右擊然後選擇create instance或者按control+n鍵來建立一個執行個體。如此重複5次,建立5個執行個體,如圖2-31所示。雖然這和圖2-30的設計看起來很相似,但是實際上這是一個更好的設計,原因前文已經講過。試着對這個類進行一些改變,比如說,為它建立一個自定義圖示,如圖2-32所示,可見類的變化将傳播到類的每個執行個體。
如果在圖2-32的任一個執行個體(或類)上調用open actor,就會看到相同的信通(channel)模型。實際是類的定義。在這個階層化模型内所做的任何改變都會自動地傳遞到所有的執行個體。比如,使用者可以試着修改noisepower參數的值并觀察結果。
如果想檢視執行個體而不是類定義,可以在一個執行個體上選擇open instance。打開的視窗隻顯示該執行個體。從類定義繼承的每個子元件都由粉紅色虛線框高亮顯示。
2.6.1 執行個體中參數值的重寫
預設情況下,圖2-32中的所有channel類的執行個體都有相同的圖示和相同的參數值。然而,每個執行個體都可以通過重寫這些值進行定制。比如說,在圖2-33中,對自定義圖示進行了修改以獲得不同的顔色,且第5個執行個體有了一個額外的圖形元素。這些修改是由右擊執行個體圖示并選擇edit custom icon來實作的。若執行個體中類的參數進行了重寫,那麼更新類不會影響該執行個體,隻會影響沒有重寫的執行個體。
2.6.2 子類和繼承
假設需要對一些信道進行修改,用另一種形式的正弦波向其添加幹擾。一種不錯的方法是建立channel類的一個子類,如圖2-34所示。建立方法是右擊類的圖示,并選擇create subclass。産生的子類圖示出現在父類圖示的上方,使用者可自行移動。
圖2-34 圖2-33的模型,有一個還未被重寫的channel的子類
子類包含父類的所有元素,但子類的圖示被一個粉紅色的虛線框環繞。這些元素都是繼承而來的,并不能從子類中删除(若試圖這樣做将出現錯誤提示)。但是,你可以改變參數值并添加額外的元素。如圖2-35所示的設計,它額外增加了一對名為interferenceamplitude和interferencefrequency的參數如一對實作幹擾(interference)的角色。
圖2-35 圖2-34的子類,被重寫過,加入了正弦幹擾
圖2-36中的模型将最後的信道替換為子類的一個執行個體,并用圖顯示正弦幹擾。
類的執行個體有兩種位置:第一,類的執行個體位于這個類本身所在的複合角色中;第二,類的執行個體位于一個複合角色中,且這個複合角色本身以及類本身都包含在一個模型中(就是說,類的執行個體位于子模型中)。為子模型添加一個執行個體,隻需簡單地從包含這個類的複合模型中複制(或剪切),然後将它粘貼到子模型中。
圖2-36 使用圖2-35中子類的模型和執行圖
2.6.3 模型間類的共享
通過将類的定義儲存在獨立檔案中,一個類可以被多個模型共享。我們将用channel類來說明這種技術。首先,在channel類上右擊并調用open actor,然後在file菜單上選擇save as。出現如圖2-37所示的對話框。标記為save submodel only的方框是預設未選中的。如果複選框未被選中,那麼整個模型會被儲存。在我們的例子中,我們想隻儲存信道子模型,是以需要選中複選框。
把類定義儲存在一個模型可以通路到的地方是很重要的。一般地,ptolemy ii搜尋與類路徑(classpath)相關的類定義,類路徑由一個名為classpath的環境變量給出。原則上,你可以設定這個環境變量使它包括你想要搜尋的任何目錄。然而,在實際中,改變classpath可能會導緻其他程式出問題,是以我們建議将檔案存儲在ptolemyii安裝目錄或根目錄下名為“.ptolemyii”的目錄中。在這兩種情況下,ptolemy會發現存儲在這些目錄中的類檔案。
如果将channel類儲存在名為channel.xml且位于目錄$ptii/myactors下的檔案中,這裡$ptii表示ptolemy ii的安裝位置。該類定義可以用在任何模型裡,如下方式:打開模型并在graph菜單中選擇instantiate entity,如圖2-38所示。在類路徑中輸入與$ptii相關的類的全名,在本例中是myactors.channel。
當擁有一個定義在檔案中的channel類的執行個體時,可将其添加到userlibrary。userlibrary在vergil庫浏覽視窗的左側,如圖2-39所示。右擊執行個體并選擇save actor in library。如圖2-39所示,這使得另一個視窗被打開并顯示使用者庫。使用者庫本身就是一個存儲在xml檔案中的ptolemy ii模型。當你儲存庫模型時,對于任何vergil視窗(對于同一使用者),類執行個體在userlibrary視窗就變成可用的。注意,在使用者庫中儲存類定義本身(相對于類的一個執行個體)結果會不同。在這種情況下,使用者庫将提供一個新的類定義而不是類的執行個體。
圖2-37 一個類可以單獨儲存在一個檔案中,然後在多個模型中共享。如圖所示,在某些平台上,顯示有save submodel only複選框的對話框會獨立出現。在其他平台上,複選框被整合到一個整體對話框中。對于其他平台,複選框将內建在一個單獨的對話框中
圖2-38 在檔案中定義的類,可以在graph菜單中使用instantiate entity來建立
圖2-39 類的執行個體在自己的檔案中定義,可以在userlibrary(使用者庫)中找到