,2
(1.空軍工程大學 工程學院,西安 710038;2.北京航空航天大學 后備軍官選拔培訓辦公室,北京 100083)
20世紀70年代,“越戰”的經驗教訓促使美國空軍開始利用技術手段監控、評估空戰訓練過程,客觀實時評估對抗結果,實現訓練模式的變革。
近年來,以新武器裝備快速發展為主要標志的空軍轉型建設快速推進,軍事訓練改革不斷深入??諔鹩柧毾到y運用實時仿真、航電系統信息監控、高帶寬數傳等技術手段,實現對飛機技術狀態、空中動態、訓練質量的實時監控。這些都需要準確、可靠的飛行數據支持。為獲得準確、連續、平滑的數據,客觀公正地評定空中訓練效果,提高訓練質量,本文提出一種空戰訓練系統(Air Combat Training System,ACTS)數據有效性檢驗算法,并通過仿真試驗證明了其有效性。
ACTS的飛行數據通過數據鏈進行傳輸,這里采用兩臺PC以及兩部電臺來進行收發飛行數據的模擬,因此采用串口通信來完成數據的接收[1-2]。
2.1.1串口類及串口初始化
為了充分利用面向對象程序設計在可維護性、易修改性和可重用性三方面優點,廣泛使用了類和對象。其中對于串口的所有操作都封裝在CCommCtrl類中。該類的定義如下:
class CCommCtrl
{
public://公共接口
CCommCtrl();//構造函數
virtual~CCommCtrl();//析構函數
bool OpenPort(char*portname);//打開串口并初始化串口
bool ClosePort();//關閉串口
bool ReadFrom(LPVOID inputData,const unsigned int sizeBuffer, unsigned long&length,LPOVERLAPPED ov);//從串口讀數據
bool WriteTo(LPCVOID outputData,const unsigned int sizeBuffer, unsigned long&length,LPOVERLAPPED ov); //向串口寫數據
bool GetCommStated();//獲得串口的狀態
HANDLE GetCommHandle();//獲得串口的句柄
private://私有變量
bool m-bCommOpen;//指明串口是否打開,true標識打開
HANDLE m-hComm;//串口的句柄
DCB m-dcb;//設備控制塊
};
Windows系統實現串口的通信必須先對串口的通信參數進行初始化,而其中比較重要的是數據傳輸率、奇偶校驗、數據比特數和停止比特數等。
Window API GetCommState()函數可以獲取串口的當前配置。該函數定義如下:
BOOL GetCommState(HANDLE hFile,LPDCB lpDCB);
其中,hFile是由CreateFile()函數返回的指向已打開串口的句柄;lpDCB為指向設備控制塊(DCB)的指針,包含各種串口通信的參數。
2.1.2多線程實現串口通信
報文收發線程以一個UI線程來定義。系統主線程首先通過調用Windows API函數完成對串口的初始化,初始化的參數由DCB結構給出,并在主線程中自定義通信事件消息,初始化完成以后,調用MFC的AfxBeginThread()函數創建報文收發線程,報文收發線程在后臺對串口進行實時監測,當監測到預定義的事件后,進行相應的消息函數處理,與此同時,主線程還可以完成人機交互和協調其它線程的同步。圖1為地面接收數據時線程的處理流程。
圖1 地面數據接收流程圖Fig.1 Flowchart of ground data receiving
為了使主線程有效的控制該線程,在線程類中定義了一個同步事件用來當主線程需要關閉該線程時釋放串口資源,然后關閉該線程。這里通過使用WindowsAPI函數WaitForMultipleObject()來等待不同的事件以選擇不同的處理過程。
代碼實現:
(1)主線程創建并啟動報文接收線程
m-pRecvThread=(CRecvThread*)AfxBeginThread(RUNTIME-CLASS(CRecvThread),THREAD-PRIORITY-NORMAL,0,CREATE-SUSPENDED);
m-pRecvThread->ResumeThread();
(2)報文接收線程打開串口
if(OpenComm()==false))//OpenComm()中實現了串口的打開和設置
{
AfxMessageBox(″Open failure!″);
return 1;
}
(3)創建線程同步事件
OVERLAPPED ov;
HANDLE hWait[2];
ov.hEvent=CreateEvent(0,true,0,0);
m-hThreadTerm=CreateEvent(0,true,0,0);
hWait[0]=ov.hEvent;
hWait[1]=m-hThreadTerm;
(4)等待串口通信事件,如果串口接收到數據,置事件ov.hEvent為有信號
while(abContinue)
{……
if(!::WaitCommEvent(m-CCommCtrl.GetCommHandle(),&dwEventMask,&ov))
{
DWORD error=GetLastError();
ASSERT(GetLastError()==ERROR-IO-PENDING);
}
……
}
(5)WaitForMultipleObjects()等待有用信號的產生,否則無限期的等待
dwWaitResult=WaitForMultipleObjects(2,hWait,FALSE,INFINITE);
(6)如果ov.hEvent為有信號,即串口接收到字符,接收數據并置事件ov.hEvent為無信號
if(dwWaitResult==WAIT-OBJECT-0)
{
……
::ReadFile(m-CCommCtrl.GetCommHandle(),recvTmp,sizeof(recvTmp),&dwBytesRead,&ovRead);
……
ResetEvent(ov.hEvent);
}
(7)如果m-hThreadTerm為有信號,即主線程要終止該線程,關閉串口并置事件m-hThreadTerm為無信號
else if(dwWaitResult==WAIT-OBJECT-0+1)
{
……
m-CCommCtrl.ClosePort();
ResetEvent(m-hThreadTerm);
break;
}
(8)主線程關閉串口接收線程
GetExitCodeThread(m-pRecvThread->m-hThread,&exit);
TerminateThread(m-pRecvThread->m-hThread,exit);
需要發送報文時,由于發送的數據量不大并且是主動的,所以只需要調用串口類CCommCtrl的WriteTo接口即可完成對報文的發送。
Microsoft Windows環境下的網絡編程接口[1,3]是Windows套接字(Windows Socket,Winsock)。Winsock提供了包括TCP/IP、IPX等多種通信協議下的編程接口。不同的Windows版本支持不同的Winsock版本,其中Windows 95等早期版本本身只支持Winsock1.1(16位)下的編程(可以通過安裝相關的軟件包使其支持Winsock2.0),而Windows98、Windows NT4.0、Windows 2000、WindowsXP 則直接支持Winsock2.0(32位)。Winsock2.0是Winsock1.1的擴展,除兼容Winsock1.1 API外,還定義了一套可支持IP多播的與協議無關的API。
系統需要將報文發送到不同的客戶端,并且多播組由報文接收服務器決定,因此采用有根模式來實現網絡數據分發。
使用Winsock 2.0實現IP多播的步驟如下(根節點配置):
2.2.1初始化Winsock資源
在使用Winsock之前,必須調用WSAStartup()函數初始化Windows SocketDLL。它允許應用程序或DLL指定Windows Sockets API要求的版本。
WORD wVersionRequested;
WSADATA wsaData;
wVersionRequested=MAKEWORD(2,2);
int result=WSAStartup(wVersionRequested,&wsaData);//初始化套接字
2.2.2創建套接字
調用WSASocket()函數創建一個使用UDP套接字,它是加入多播組的初始化套接字,以后數據的發送和接收都在該套接字上進行。針對本系統的需求,將參數dwFlags設置為WSA-FLAG-MULTIPOINT-C-ROOT、WSA-FLAG-MULTIPOINT-D-ROO和WSA-FLAG-OVERLAPPED的位和,指明組播方式為有根模式:
Sock=WSASocket(AF-INET,SOCK-DGRAM,IPPROTO-UDP,NULL,0,WSA-FLAG-OVERLAPPED|WSA-FLAG-MULTIPOINT-C-ROOT|WSA-FLAG-MULTIPOINT-D-ROOT);
2.2.3設置套接字的選項
調用setsockopt()函數為套接字設置SO-REUSEADDR選項,以允許套接字綁扎到一個已在使用的地址上:
bFlag=TRUE;//設置套接字選項,使套接字為可重用端口地址
setsockopt(Sock,SOL-SOCKET,SO-REUSEADDR,(char*)&bFlag,1);
2.2.4綁定套接字
調用bind()函數綁定套接字,從而將創建好的套接字與本地地址和本地端口聯系起來。對于多播通信來說,發送和接收數據通常采用同一個端口:
memset(&local,0,sizeof(local));
local.sin-family=AF-INET;
local.sin-port=htons((USHORT)9999);
local.sin-addr.s-addr=htonl(INADDR-ANY);
bind(Sock,(struct sockaddr FAR*)&local,sizeof(local));
2.2.5注冊網絡消息及其網絡事件
WSAAsyncSelect(Sock,m-hWnd,WM-SOCK-MSG,FD-READ);//數據等待被讀入子節點的配置與根節點類似,只是建立套接字時的dwFlags設置有所不同。建立組播的好處就是如果系統需要擴展功能,可以充分利用現有組播框架。
建立好組播組以后,根節點和子節點之間就可以進行通信了,根節點發送報文時只需要調用sendto函數,具體代碼如下:
const char*strMes=LPCTSTR(m-SendMessage);
int nSize=m-SendMessage.GetLength()+1;
sendto(Sock,strMes,nSize,0,(sockaddr*)&Remote,sizeof(Remote));
子節點只需要調用recvfrom函數即可獲得接收到的數據。另外,子節點還可以利用過濾器來實現報文過濾,只接收需要的報文。
實現網絡數據分發的主要意義在于:在接收ACTS飛行數據時,如果報文的數目比較多,利用一個服務器端軟件進行實時監控將比較困難,而通過網絡數據分發模塊,可以將報文發送到多個客戶端,各客戶端可以分別監視部分飛機或地面監控系統的報文信息,從而可以更好更有效地實現ACTS對戰場的實時監視。
VC中使用ADO實現數據庫連接[1]。由于VC在數據庫編程方面的先天缺陷,導致使用VC編寫數據庫操作方面的工作比較復雜,可以利用ADO在VC中實現數據庫編程。
2.3.1引入ADO庫
在Visual C++中使用ADO開發數據庫之前,需要引入ADO庫??梢栽陬^文件中引入ADO庫文件,方法如下:
#import″c:program filescommon filessystemadomsado15.dll″
#include
#include
#include″icrsint.h″
預處理指令#import使程序在編譯過程中引入ADO動態庫(msado15.dll)。接下來的兩個“#include”語句引入了頭文件來定義ADO2.0的類和接口標識。最后的“#include”語句引入了ADO2.0數據綁定擴展。
2.3.2建立數據庫連接
建立數據庫的連接需要使用連接對象(Connection Object)。首先定義一個ConnectionPtr類型的指針,代碼如下:
ConnectionPtr m-pConnection;
然后調用Create Instance方法實例化,代碼如下:
m-pConnection.CreateInstance(uuidof(Connection));
調用Connection對象的Open方法創建數據庫的連接,Open函數的原型如下:
HRESULT Open(-bstr-t ConStr,-bstr-t UserID,-bstr-t Pwd,Long Opts);
其中,ConStr是一個包含連接信息的字符串,UserID是訪問數據庫的用戶名稱,Pwd是訪問數據庫的密碼,Opts為可選參數。如果在連接字符串ConStr中包含了數據庫用戶名和密碼,UserID和Pwd值可以為空。
2.3.3創建命令對象和記錄集對象
CommandPtr m-pCommand;
RecordsetPtr m-pRecordset;
m-pCommand.CreateInstance(″ADODB.Command″);
m-pRecordset.CreateInstance(-uuidof(Recordset));
然后將建立的數據庫連接賦給m-pCommand,這樣利用m-pCommand就可以對打開的數據庫進行SQL操作了:
m-pCommand->ActiveConnection=m-pConnection。
2.3.4將報文數據插入數據庫
在每類報文譯碼類中定義了一個GenerateInsertSQL函數,該函數無參數,返回此類報文的插入SQL語句,這樣,對于某一類報文,其插入數據庫的代碼如下:
//p為指向運行時某種報文的對象的指針
//插入數據字符串
CString sql=p->GenerateInsertSQL();m-pCommand->CommandText=sql;
m-pCommand->Execute(&vNULL,&vNULL,adCmdText);
3.1.1模塊主要功能
有效性檢驗模塊[4]主要實現以下幾個關鍵功能:
(1)根據ID編號或者地址,判斷該飛行數據是屬于哪架飛機的。ACTS可以同時實時監控10架飛機,每架飛機都有自己的ID號,根據ID號就可以劃分該數據屬于哪架飛機的數據;
(2)根據時間戳判斷飛行數據是否延時或丟失。時間戳是判斷數據到達時間的重要依據,有了時間戳才可以準確判斷飛行數據是否發生了延時或者丟失。但前提是只有實現了ACTS各個分系統內的時間同步,才可以利用時間戳來獲取這些數據之間的關系,對這些數據進行分析;
(3)根據各種飛行數據的特征以及先前獲得的經驗值進行預估,根據預估值判斷數據是否正確。對于像一些記錄飛機工作是否正常的數據,我們可以直接根據該類數據正常值的范圍就可以判斷數據是否正確;而對于像記錄飛機航跡的這些實時變化很大的數據,我們就必須在該數據到達之前,利用卡爾曼濾波外推算法,估算出該數據的預估值,然后在該數據到達時進行比對,從而判斷出該數據是否正確;
(4)數據發生延時、丟失或錯誤情況后的處理。飛行數據地面預處理系統要完成工作就是將譯碼后正確、連續的數據送給后續數據處理系統進行結算、實時顯示等操作。所以如果一旦地面接收到的數據發生上述情況,就必須采取相應補償措施進行處理。
3.1.2數據有效性檢驗
有效性檢驗模塊處理數據的過程如圖2所示。
(1)等待譯碼模塊送來的數據;
(2)根據時間戳判斷數據是否延時或丟失。如果該數據在有效時間內到達,則將該數據進行數據正確性檢驗。如果延時或丟失,就在日志中記錄該事件的發生,然后用其它輔助設備的測量值或者預估值代替該數據;
(3)利用正確性檢驗算法進行數據的正確性檢驗。如果數據正確,則將數據存入數據庫并進行進一步的實時解算、顯示等處理。如果數據不正確,就在日志中記錄該事件的發生,然后用其它輔助設備的測量值或者預估值代替該數據,進行后續處理。
圖2 數據有效性檢驗流程圖Fig.2 Data validity inspection flowchart
對數據有效性檢驗算法進行驗證的航跡數據來源于某型飛機的部分試飛數據。數據包括兩部分:
(1)利用本機的機載飛行數據記錄器記錄的數據,由于不經過遠距離無線傳輸,認為是正確數據;
(2)在機載飛行數據記錄器記錄數據的同時,由電臺無線傳輸到地面記錄器的數據,由于實時傳輸過程環境的影響,數據中包含延時、丟失、錯誤等情況。
利用試飛數據來驗證有效性檢驗算法的方法是:選取地面記錄器上的部分出錯的航跡數據,然后由數據有效性檢驗算法對這段錯誤航跡數據進行檢驗和處理,最后將檢驗及處理后的這段航跡數據與機載飛行數據記錄器上的原始航跡數據進行比對。
該組飛行數據采樣記錄頻率為1次/秒,這里選取第462~622 s的大氣機高度數據進行檢驗。這段時間內可能由于傳輸環境惡劣等原因導致第482 s高度值出現明顯偏差,第512 s數據發生延時,第565 s數據丟失。結果如圖3~5所示。
根據上述驗證結果看,有效性檢驗算法檢測出了數據的錯誤、延時和丟失,并進行相應補償處理,得到一組連續的數據。與機載記錄的試飛數據進行比較可以看出,該有效性檢驗算法較準確地恢復了出錯的數據,取得了良好效果。
圖3 地面記錄的試飛數據:飛機從4.5 km下降至2.1 km,改平后上升至3.9 kmFig.3 Ground recording test-fly data:the airplane descended from 4.5 km to 2.1 km and rose to 3.9 km after being steady
圖4 經有效性檢驗算法處理后:飛機從4.5 km下降至2.1 km,改平后上升至3.9 kmFig.4 Data validity inspection algorithm processing:the airplane descended from 4.5 km to 2.1 km and rose to 3.9 km after being steady
圖5 機載記錄的原始試飛數據:飛機從4.5 km下降至2.1 km,改平后上升至3.9 kmFig.5 Airborne recording originality test-fly data:the airplane descended from 4.5 km to 2.1 km and rose to 3.9 km after being steady
本文提出了一種ACTS數據有效性檢驗算法,有效地解決了數據傳輸過程中出現的錯誤、延時和丟失等問題。該檢驗算法對出錯的數據進行了修正,得到準確、連續、平滑的數據,供地面監控系統準確地實時監控及評估。進一步研究重點是對數據有效性檢驗模塊實時性進行分析和驗證。
參考文獻:
[1] 喬林,楊志剛.Visual C++6.0 高級編程技術——MFC與多線程篇[M].北京:中國鐵道出版社,2000.
QIAO Lin,YANG Zhi-gang. Visual C++6.0 Advanced Programming Technology:MFC and Multi-threading[M].Beijing: China Railway Press,2000. (in Chinese)
[2] 李現勇.Visual C++串口通信技術與工程實踐[M].北京:人民郵電出版社,2004.
LI Xian-yong. Visual C++ Serial Communication Technology and Engineering Practice[M].Beijing:People′s Posts& Telecom Press,2004.(in Chinese)
[3] Andrew S Tanenbaum.Computer Networks[M].3rd ed. New York:Prentice Hall International,Inc.,1997.
[4] 王帥.飛行器航跡數據產生及有效性檢測[D].成都:電子科技大學,2004.
WANG Shuai.Aircraft Track Data Generation and Data Validity Inspection[D].Chengdu:University of Electronic Science and Technology of China,2004.(in Chinese)
[5] 梁德文.戰斗機航空電子系統最新的發展趨勢——網絡化[J].電訊技術,2008,48(6):93-97.
LIANG De-wen.Review on the New Development of Fighter Avionics System-Networking [J].Telecommunication Engineering,2008,48(6):93-97.(in Chinese)
[6] DRS Air Combat Training System[Z].Florida:DRS Training & Control System,INC.,2007.
[7] Autonomous Air Combat Maneuvering Instrumentation Training System[Z].Ireal:Isreal Aerospace Industries,Ltd.,2008.