張 杰
(中國鐵道科學研究院集團有限公司通信信號研究所,北京 100081)
目前,國內大部分計算機聯鎖軟件應用層的設計,采用程序和數據分離的思想[1]。其中,程序實現了模塊化、定型化,而數據根據不同的站場進行配置,這種方法實際上繼承了傳統6502電氣集中的設計思想[2]。
為了實現程序代碼的批量生產,各研制單位分別開發了計算機輔助設計軟件(CAD),它依據平面圖,選取信號機、道岔、軌道區段等對象模塊,畫出站場圖形,根據站場圖形對象的上、下、左、右幾何關系,初步生成對象的鏈接數據,軟件人員根據聯鎖表、驅動采集表、藍圖等設計文件,結合整體、局部的站場特征,設置各對象的屬性,填寫特殊的聯鎖條件,補充零散的代碼,最后,再由CAD軟件整合這些數據,生成待編譯的聯鎖軟件。在此過程中,軟件關鍵的數據[3],如超限、信號顯示關系、帶動防護、場聯、站聯等接口,以及特殊電路要求的特殊代碼,都必須由軟件人員通過縝密的思考,然后逐條、逐項地輸入。此過程容易出現筆誤,遺漏,甚至邏輯錯誤;況且,軟件人員技術水平參差不齊,可能會造成軟件質量不高[4],實現方式不統一的情況。而經驗豐富的專家,已積累了大量、可靠、經過實踐檢驗的知識,并能遵循 “故障導向安全”原則進行設計[5],因此,整合聯鎖軟件專家的經驗,設計專家系統[6],使聯鎖數據實現自動生成,進一步提高生產的智能化,便成為計算機聯鎖軟件編制的實際需求。
聯鎖數據的編制,初始階段有兩步,一是讀圖,編寫需求,然后才是軟件人員編寫代碼。在前一個階段,結合設計人員,根據設計院提供的設計藍圖,把本車站的需求,以文件形式列出,軟件人員拿到需求,和設計藍圖進行核對,一方面為了核實用戶需求,另一方面,為了獲取軟件需要的詳細信息。
開發一個實現聯鎖數據編制的專家系統,首先要解決的就是設計藍圖信息的輸入問題。
考慮到Excel簡單、實用,并且功能十分強大[7],結合設計人員完全可以將“用戶需求”改為Excel格式,和專家系統用同一個文件,這樣,“用戶需求”從開始制作,到專家系統的讀取,試驗階段的核對,都采用同一份Excel文件,可以保證需求文件的一致性,因此,本文優先推薦采用Excel格式文件。
聯鎖是嚴密的邏輯關系,在藍圖上往往以拓撲圖(如信號顯示關系、信號點燈電路)或表格形式(如聯鎖表)來表示[8],要將它們表示在Excel上,可利用Excel的表單控件,如表1所示。

表1 信號關系標準化示例
表1中,本架信號機與后架信號機之間的顯示關系用對應的單元格數值關系來表示。其中,用了大量的表單控件,只用打鉤即可。類似的一些特殊電路,如點燈電路、自閉電路、場聯電路、半自動電路、各種報警信息、防護及帶動、推峰溜放、接近鎖閉、機務段聯系等[9],都可以建立相應Excel表。結合設計人員及聯鎖軟件人員打勾或按格式填寫,形成統一、標準格式的數據。
專家系統屬于人工智能的課題,其內部含有大量的某領域專業知識和經驗[10],它能根據這些知識和經驗,進行推理和判斷,模擬人類專家,進行決策,解決復雜的問題。
一般專家系統由5個部分組成。
(1)知識庫[11]。
(2)綜合數據庫。
(3)推理機。
(4)解釋器。
(5)接口。
結合計算機聯鎖軟件的制作,其輔助設計專家系統的結構如圖1所示。

圖1 聯鎖軟件制作專家系統總體框圖
用戶界面模塊實現軟件人員向推理機輸入各種操作命令,同時,也把流程控制及推理的解釋信息反饋給用戶。數據處理模塊實現推理機和外部數據、用戶信息及推理輸出數據的轉換。推理用的事實、實例,需要從Excel格式的需求文件、Txt格式的IO表、電子版的聯鎖表及CAD生成的初始對象數據中提取,推理輸出的各種聯鎖對象數據也往往是字符串形式,需要轉換后寫入對應的聯鎖對象。因此,數據處理模塊完成數據中轉、變換功能。推理機可以選用由美國航空航天局開發的CLIPS[12],并采用Mark Tomlinson編制的動態庫CLIPS.DLL,以及為該動態庫編制的CLIPSWrap 包裝類。知識庫由經驗豐富的聯鎖軟件制作人員和專家系統開發者共同建立,知識庫是推理的重要基礎[13]。
專家系統的知識庫用于存儲領域的專門知識,包括事實、操作規則等[14]。為了建立知識庫,首先要解決知識表示問題。
按照聯鎖軟件制作的一般流程,先形成需求文件、I/O接口碼位表,軟件人員讀這些文件及藍圖資料,利用CAD工具,輸入帶有邏輯判斷的代碼及數據。專家系統要模擬人的工作,也需要輸入,這里的“輸入”就是知識的表示,聯鎖軟件制作專家系統中,采用事實和面向對象的表示方法。例如,數據處理模塊利用文本格式的I/O表文件,建立模板:
(deftemplate ioinfo "I/O table "
(slot ioname (type STRING)(default "null"));I/O名
(slot io-lsname (type SYMBOL)(default null));聯鎖軟件中的名字
(slot belong-obj (default null));隸屬哪個對象
(slot in_out (type STRING)(allowed-strings "INPUT" "OUTPUT"));類型是輸入還是輸出
(slot chassis (type INTEGER)(range 1 8));機籠號
(slot slotname (type INTEGER));槽號
(slot seq-number (type INTEGER);板號
(range 1 48))
(slot stano (type INTEGER);站場號
(range 0 2)(default 0)))
基于此模板,把IO表轉化為CLIPS事實文件。專家系統利用平面圖、CAD形成的各對象的初步數據,轉化為面向對象的實例表示,如進站信號類,表示為:
(defclass HOME-SIG;
(is-a ILOCK-SIGNAL)
(role concrete) (pattern-match reactive)
(slot no-drive-zxj;不驅ZXJ
(type SYMBOL)
(create-accessor read-write);
(allowed-symbols true false)(default false))
(slot no-drive-txj;不驅TXJ
(type SYMBOL)
(create-accessor read-write);
(allowed-symbols true false)(default false))
(slot no-drive-luxj;不驅LUXJ
(type SYMBOL)
(create-accessor read-write);
(allowed-symbols true false)(default false)) (slot have-mwhite;有引導顯示
(type SYMBOL) (create-accessor read-write)
(allowed-symbols true false null)
(default null))
(slot have-Yellow2;有雙黃顯示
(type SYMBOL) (create-accessor read-write)
(allowed-symbols true false null)
(default null)))
各對象的特殊屬性,即事實及實例的slot值,來源為設計文件及Excel格式的需求文件,利用Excel強大的VBA編程,再由數據處理模塊讀入,修改實例的slot值。
CLIPS采用正向推理機制[15],支持產生式規則。產生式規則可用P→Q表示,P表示一組模式(或叫前提條件),Q是要執行的若干動作和結論。聯鎖關系涉及大量的規則,軟件數據的制作就是利用各種規則進行分類判斷,如果分類的判定樹建立得不好[16],一方面會影響程序執行的效率,另一方面,可能會造成CLIPS產生大量部分匹配,鑒于此,筆者嘗試采用ID3( Iterative Dichotomiser)算法[17]。ID3算法由Ross Quinlan提出,它是在判定樹每個節點處選取能獲得最高信息增益的分支屬性進行分裂。
熵在信息論中被用來度量信息量,熵越大,所含的有用信息越多,其不確定性就越大,在決策樹中,用熵來表示樣本集的不純度,熵越大,越不確定,表示樣本集中的分類越多樣。
設S為數量為n的樣本集,其分類屬性有n個不同取值,用來定義m個不同分類Ci(i=1,2,…,m),則其熵的計算公式為
(1)
設屬性A有v個可能取值,即通過將屬性A設置為分支屬性,能夠將樣本集S劃分為v個子樣本集(S1,S2,….Sv),以A為分支屬性的信息增益為
(2)
下面舉例說明。以特殊的場聯口信號機處理為例,其站場特征為進路內方只有一個區段,并且為場聯軌。搜集典型的10個車站場聯口信號作為樣本,如表2所示。

表2 特殊場聯樣本集
表2中共有10個樣本,其中有襄陽北V場D5105、喬司上到發XL21、僑城東車輛段D12B 、坡底下XZ 采用信號鏈左右換位的作法(其余采用虛按鈕作法)。由以上分析可得,最初判定前的熵為
0.970 951
“有并置”分類屬性的熵
Entropy(有并置)=
同理,無并置屬性的熵為:0.918 296。
因此,設“有并置”的屬性為Y,其作為分支屬性分裂后的信息增益為
Gain(Y)=Entropy(S)-Entropy(S|Y)=
0.005 803
同理,可以計算出,以“并置敵對”、“列調場聯”、“終端按鈕并置”的為分支屬性的信息增益分別為0.556 78,0.144 485,0.321 929,由此可知,“并置敵對”作為分支屬性時,能獲得最大信息增益。所以此處選“并置敵對”為根節點進行劃分。
繼續按照此方法,直至分類完成。
站場特征的識別,是建立規則庫的重要基礎,而站場特征來自車站網絡結構圖[18],因此,如何快速、簡便地訪問網絡圖的各對象,便成為專家系統研究的另一內容。
筆者曾用VC++實現站場網絡的遍歷,然后將識別結果發送給CLIPS;后來嘗試在CLIPS中,用面向對象的知識表示,實現站場遍歷。以下就兩種算法進行比較。
3.3.1 用二叉樹數據結構實現遍歷
樹形結構是結點之間有分支[19],并具有層次關系的結構。二叉樹是樹形結構的一個重要類型,它是n個結點的有限集,它或者是空集(n=0),或者由一個根結點及兩棵互不相交的,分別稱作這個根的左子樹和右子樹的二叉樹組成,左子樹及右子樹的根稱為根結點的左孩子和右孩子,這是個遞歸的定義。
圖2為簡單示例站場,其二叉樹模型如圖3所示(Ф為虛結點)。

圖2 示例部分站場

圖3 示例站場的二叉樹模型
二叉樹的遍歷[20],是指沿某條路徑周游二叉樹,對樹中每個結點訪問一次且僅訪問一次。這里,采用前序遍歷算法,若二叉樹非空,則依次進行如下操作。
(1)訪問根結點。
(2)遍歷左子樹。
(3)遍歷右子樹。
算法流程見圖4。

圖4 示例站場二叉樹遍歷算法流程
3.3.2 CLIPS中用自定義函數實現遍歷
如前所述,本專家系統采用面向對象的知識表示方法,允許為道岔、信號、無岔等編寫自定義消息處理函數。由于自定義函數支持多字段變量作為參數,站場遍歷的實現變得非常簡便。
以下是道岔、信號機的消息函數:
(defmessage-handler ILOCK-SWITCH
bianli( $?r);$?r為多字段變量作參數
(bind $?rinfo (create$ ?r))
(bind ?lastobj (nth$
(length$ $?rinfo) $?rinfo))
;?lastobj變量為消息的最后一個對象
(if (or (eq ?lastobj ?self:normal-link) (eq ?lastobj ?self:reverse-link))
;如果最后的對象是本道岔的定位或反位鏈
then
(send symbol-to-instance-name ?self:front-link) bianli (create$ ?r ?self:myname))
; 向本道岔的前鏈發送遍歷消息,并且多字段變量$?r增加本道岔的信息
else (if (eq ?lastobj ?self:front-link)
then
;如果是從岔前鏈來的消息,則給定位及反位鏈發送遍歷消息。
(send (symbol-to-instance-name ?self:normal-link) bianli (create$ ?r ?self:myname))
(send (symbol-to-instance-name ?self:reverse-link) bianli (create$ ?r ?self:myname)))))
(defmessage-handler OTHER-SIG bianli( $?r)
(send (symbol-to-instance-name ?self:right-link) bianli (create$ ?r ?self:myname)))
其邏輯非常簡單,就是以多字段變量為參數,從進路的始端開始,按照進路方向及對象的鏈接關系(前面數據處理模塊已建立),各對象分別處理自己的消息函數,把需要的特征內容,添加到傳遞的多字段變量,然后,把這個消息往前發,直至進路終端,如果滿足進路終端的要求,則把多字段變量存儲為特征事實。
站場的遍歷在特征獲取、數據生成方面有著廣泛的應用,如存儲溜放區敵對信號的識別、全站進路信息的生成、長調車進路特征的計算等等。基于二叉樹的遍歷算法,在既有的計算機輔助設計軟件中已有應用,但要用堆棧操作,聯鎖對象的邏輯判斷也比較復雜,而CLIPS消息函數的方法把遍歷功能分解為各個對象的消息處理,原理清晰,邏輯簡單,更適合于本專家系統。
聯鎖軟件制作專家系統和用VC++編寫的輔助設計工具CAD互相配合,最終完成聯鎖軟件的生成。因此,涉及到CLIPS和VC++的交互問題[21]。
CLIPS由C語言設計,因此,可以方便地嵌入到VC++。有兩種嵌入方式,一種是直接嵌入,一種是加載動態鏈接庫。本系統采用動態鏈接庫,并使用包裝類CCLIPSWrap,CCLIPSWrap類符合VC++面向對象的設計風格,更有條理,方便用戶使用。
CLIPS和VC++交互技術,實質是兩者如何方便地互傳數據。
本系統采用4種方法。
(1) 用戶定義函數。
例如向CLIPS傳字符串,在VC++中,聲明CString toclip;編寫全局函數:
void* toclips()
{
void *returnValue;
returnValue=g_clips.CLIPSAddSymbol(toclip);
return (returnValue);
}
然后,調用CCLIPSWrap類的AddFunction,
g_clips.AddFunction("toclips",'w',PTIF toclips,"toclips","00"),即可以在CLIPS中調用toclips,方便地得到VC++傳來的字符串。
(2)用CLIPSAssert在CLIPS中建立控制事實。
(3)調用函數CLIPSNextFact()或CLIPSNext FactString搜索所有事實,得到所要修改事實的指針factPtr,再用ReadFactSlot讀,或用WriteFactSlot寫指定的槽值。
(4)調用CCLIPSWrap類的CLIPSDirectPutSlot直接修改實例的槽值。
CLIPS的推理結果或返回的控制事實、實例的槽值,可通過內存緩沖區,方便地傳給VC++。
首先,指定路由,由CCLIPSWrap類的SetRoute Buffer(&arrStrFromclip,"tovc")實現,arrStrFromclip是事先的定義字符串數組,tovc叫做邏輯名[22],可以任意指定,CLIPS常常用邏輯名代表文件、輸入輸出設備、緩沖區等。這樣,在CLIPS規則或函數中,就可以用printout函數將結果寫到字符串數組中,如(printout tovc "出站信號,請核實!")。
無論是從VC++到CLIPS,還是從CLIPS到VC++,都可以先產生文本文件,再由對方加載。
例如,本系統在生成信號機、道岔、無岔區段等類的實例時,先由VC++的WriteString函數將實例以字符串形式寫入文本文件,再由CCLIPSWrap類的CLIPSLoad函數加載此文本文件,生成對象實例。
從CLIPS寫文件也十分方便。比如,要往C盤“cad-data.txt”中寫文件,可以由以下規則實現:
( defrule dd2
(not (star-write-cad-irregular))
;如果以只寫的方式且已經打開文件
(test (open "C:\cad-data.txt" cad_data1 "w"))
=>
(close cad_data1);關閉該文件
(assert (star-write-cad-irregular))
(open "C:\cad-data.txt" cad_data1 "a")
);以添加方式打開文件
( defrule announce-irregular-info
(ioinfo (ioname ?io-name) (belong-obj irregular))
?n <-(star-write-cad-irregular)
=>
(printout cad_data1 "INPUT:" ?io-name crlf))
Open函數中的 cad_data1是邏輯名,"w"、"a"是文件的存取方式,"w"是只寫,"a"是添加。以上兩條規則可以實現往C盤“cad-data.txt”以追加方式寫,不會覆蓋以前的內容。
本文首先介紹當前計算機聯鎖軟件制作的過程,指出其中存在的問題,為減少人為判斷的失誤,提出輔助設計和專家系統相結合,重點論述了知識庫的建立,采用面向對象的知識表示,選取典型的工程案例,詳細說明了ID3算法在建立判定樹的應用,通過ID3計算,可以對分類的判定節點進行優化,提高規則的合法化及程序執行的效率。在站場特征識別方面,重點討論了兩種站場遍歷的算法,第一種算法以二叉樹數據結構為基礎,采用堆棧,實現站場的遍歷;第二種方法直接在CLIPS中用消息傳遞來實現,不需要作數據轉換,邏輯明確,算法簡單,具有相對的優越性。在文章最后,總結了VC++和CLIPS的交互技術,這些實用的技術使VC++和CLIPS傳遞信息更為方便。
經實驗,聯鎖軟件制作專家系統,可以初步達到設計預期的目標,即模擬專家的經驗,在軟件制作過程中,有序可控,對聯鎖關系判斷正確,數據不遺漏,減少重復性的工作。需要指出的是,對特殊的站形、特殊的數據,需要由系統開發人員和聯鎖專家人員共同協作,不斷完善知識庫,以解決專家系統的學習問題。