張恩紅,尹海燕
(1.廣東省氣象探測數(shù)據(jù)中心,廣東廣州 510080;2.廣東省氣象計算機應(yīng)用開發(fā)研究所,廣東廣州 510080)
由于科學(xué)技術(shù)的進步和探測技術(shù)水平的提高,采集的觀測數(shù)據(jù)和加工的產(chǎn)品數(shù)據(jù)量越來越大,傳統(tǒng)的數(shù)據(jù)傳輸格式已無法滿足全球數(shù)據(jù)交換業(yè)務(wù)的需求。為了便于全球數(shù)據(jù)的交換使用,盡量減少數(shù)據(jù)傳輸壓力,提高數(shù)據(jù)交換效率,世界氣象組織(WMO)一直在推行氣象數(shù)據(jù)格式的標(biāo)準(zhǔn)化,即推行二進制的表格驅(qū)動碼,包括BUFR、GRIB和CREX碼。現(xiàn)在全球很多國家都已經(jīng)采用這個規(guī)范進行數(shù)據(jù)編碼和共享傳輸。我國也完成了數(shù)據(jù)格式的轉(zhuǎn)換工作。這個業(yè)務(wù)的推廣,給數(shù)據(jù)使用的用戶帶來一個新的問題,那就是數(shù)據(jù)解碼技術(shù)的更換與升級。
為了能夠及時用上新格式的數(shù)據(jù),WMO提供了編碼規(guī)范,專家學(xué)者們開始研究BUFR格式數(shù)據(jù)的解碼及應(yīng)用軟件的開發(fā)。王穎等[1]詳細闡述了我國氣象行業(yè)推進表格驅(qū)動碼工作的進展與取得的成果。隨著氣象衛(wèi)星的發(fā)展,觀測手段頗為豐富,在氣象預(yù)報與分析中廣泛應(yīng)用[2-5]。王素娟等[6]詳細分析氣象衛(wèi)星風(fēng)速的BUFR碼格式,并且編寫了相關(guān)的數(shù)據(jù)寫入軟件,實現(xiàn)了數(shù)據(jù)的業(yè)務(wù)化;張曉等[7]、袁雨暉[8]、陳增鏡等[9]、王恩文等[10]、高雅潔[11]分別從不同的應(yīng)用方向做了相關(guān)的應(yīng)用研究。本研究著重討論如何利用python語言對壓縮格式的BUFR碼進行解碼,并提出在解碼中可能存在的問題,供同行參考。
BUFR的基本格式已經(jīng)在很多文章有介紹,最全面的是世界氣象組織(WMO)《氣象編碼手冊》[12],中國氣象局也組織專家翻譯并編寫了《表格驅(qū)動碼編碼手冊》[13]。本研究摘取部分重點內(nèi)容,進行分解說明。
BUFR文件的編碼主要包括6部分:指示符段、標(biāo)識段、(選編段)、數(shù)據(jù)描述段、數(shù)據(jù)段、結(jié)束段,每段功能的詳細說明請參考WMO相關(guān)文檔。在BUFR的壓縮格式解碼中,前3段無重要信息,按文件說明常規(guī)解碼即可,重點是數(shù)據(jù)描述段的解碼。指示符段的長度為8個八位組。前4個八位組是國際電報字符5號碼表示的BUFR;八位組5—7(24比特)是以二進制形式表示的整個BUFR信息的長度(包括指示符段);八位組8是以二進制表示的BUFR碼的版本號。標(biāo)識段的前3個八位組是以二進制形式表示的段長,并以八位組為單位。數(shù)據(jù)描述段的重點包括1—3八位組記錄本段的長度,取決于后面的數(shù)據(jù)解讀;5—6八位組描述本數(shù)據(jù)集的子集個數(shù),決定了后面數(shù)據(jù)解壓縮時讀取數(shù)據(jù)的個數(shù);在第7個八位組中,第1 bit位描述數(shù)據(jù)的性質(zhì),1表示觀測數(shù)據(jù)、0表示其他數(shù)據(jù),第2 bit位描述數(shù)據(jù)的格式,1表示壓縮格式、0表示非壓縮格式。第8—9個八位組記錄該數(shù)據(jù)集的要素描述表的代碼。
第8—9組(字節(jié))的內(nèi)容說明:
從八位組8開始的描述符集合,稱作“數(shù)據(jù)描述”。每個描述符占兩個八位組,分為F(2位)、X(6位)和Y(8位)共3個部分。
(1)如果F=0,描述符為要素描述符。X和Y的值將直接地對應(yīng)表2中的一個入口,X表示類,Y表示類中的入口。
(2)如果F=1,描述符為重復(fù)描述符,該描述符按照相關(guān)規(guī)則對重復(fù)數(shù)據(jù)描述運算符作出定義。X值和Y值分別定義運算符的作用范圍和重復(fù)次數(shù)。如果Y=0,則為延遲重復(fù),并由下一個要素描述符定義一個數(shù)據(jù)項作為重復(fù)數(shù);該描述符也可以通過其Y值指示后面的數(shù)據(jù)和后面的描述符一起重復(fù)。
(3)如果F=2,描述符為運算符描述符。X值指示《表格驅(qū)動碼編碼手冊》的表C中的一種運算,Y值的含義取決于具體的運算。
(4)如果F=3,描述符為序列描述符。此時,X值和Y值直接地對應(yīng)《表格驅(qū)動碼編碼手冊》表D中的一個入口。表D的每一個入口包含一系列要素描述符、數(shù)據(jù)描述運算符和序列描述符。一個序列描述符等同于它在表D入口所對應(yīng)的一組描述符。
以W_XX-EUMETSAT-Darmstadt,SURFACE+SATELLITE,JASON2+OGDR_C_EUMS_20160730103615_d_297_135_20160730100932.bin文件為例,從文件的解報內(nèi)容來看,第3段的第7個八位組的二進制值是11000000,第1 bit值為“1”,說明是觀測數(shù)據(jù);第2 bit值為“1”,說明該數(shù)據(jù)格式是壓縮格式,這個信息非常重要,取決于后面的數(shù)據(jù)格式問題,若出錯,后面的工作將無法繼續(xù)。第8個八位組的二進制值為11101000和第9 個八位組的二進制值為00001010,從表1的說明可知,F(xiàn)=3,X=40,Y=10,則可知應(yīng)該是對表參照碼1的 3 40 010的要素描述符,該文件的要素描述如表1所示。再根據(jù)表1中的表參照碼2到《表格驅(qū)動碼編碼手冊》[13]中查找對應(yīng)的要素說明信息,包括該要素的單位、比例因子n、基準(zhǔn)值VB、數(shù)據(jù)寬度(占bit數(shù),測量值V)。實際值(VR)的計算公式為VR=V·10n+VB。
表1 要素描述符
由于BUFR數(shù)據(jù)的壓縮格式可以節(jié)約很多的空間,在大數(shù)據(jù)量的觀測中,為了減少數(shù)據(jù)傳輸?shù)膲毫?,?jīng)常采用BUFR碼的壓縮格式。壓縮形式的二進制數(shù)據(jù)的格式可描述如下:
鑒于非壓縮格式的數(shù)據(jù)特點,數(shù)據(jù)處理的流程圖如圖1所示。
圖1 數(shù)據(jù)解碼流程示意圖
首先需要從指示段獲取子集個數(shù)S,即后面的要素增量的個數(shù),然后讀取配置文件,獲取需要讀取數(shù)據(jù)的要素個數(shù),然后根據(jù)配置文件中定義的要素占位長度獲取數(shù)據(jù),直到完全讀取完所有要素的數(shù)據(jù)。要想正確解碼需要以下幾個步驟:第一步需要獲取每個要素的基準(zhǔn)值占位寬度,這個值可以通過表1的“表參照碼1”“表參照碼2”組合獲得;第二步,根據(jù)要素基準(zhǔn)值的占位符長度,通過程序讀取指定寬度的bit值,然后還得按每個字節(jié)8 bit的結(jié)構(gòu),重新組織所獲取的二進制數(shù)據(jù),這是二進制數(shù)據(jù)的難點之處,數(shù)據(jù)處理的方法可以分為幾種情況(表2);第三步,也是非壓縮格式解碼最關(guān)鍵一步,即獲取NBINC1的值,該值是判定是否有增量值及確定增量值所有占有bit位數(shù)的量。數(shù)據(jù)獲取方法很簡單,根據(jù)定義,這個數(shù)值的寬度是固定,在基礎(chǔ)值之后的6 bit數(shù)據(jù),當(dāng)然,這6 bit的數(shù)據(jù)可能是在同一個字節(jié)里,也可能是在連續(xù)的兩個字節(jié)里。編碼如:NBINC1=((ord(data2)&0x7e)>>1),在一個字節(jié)中的連續(xù)6 bit或者n_NBINC1=((ord(data5)&0x0f)<<2)+((ord(data1)&0xc0)>>6)在兩個字節(jié)中,前一字節(jié)4 bit加上后一字節(jié)2 bit。當(dāng)NBINC1=0時,該要素的值是不變的,即每個記錄的值都一樣,當(dāng)NBINC1>0時,該值為要素增量數(shù)據(jù)的占位寬度的bit數(shù)量。最后根據(jù)NBINCs的值獲取相應(yīng)增量數(shù)據(jù),這里需要連續(xù)獲取數(shù)據(jù)子集個數(shù)增量值。
表2 字節(jié)重組方案
由于氣象衛(wèi)星的觀測范圍廣、數(shù)據(jù)采集的量大,因此,數(shù)據(jù)傳輸?shù)碾y度也很大,對數(shù)據(jù)傳輸技術(shù)要求很高。壓縮格式的BUFR碼,很適合氣象衛(wèi)星數(shù)據(jù)的存儲與傳輸,在實際業(yè)務(wù)中,已經(jīng)大量使用?;谝陨系腂UFR碼解碼分析,以歐洲衛(wèi)星中心(EUMETSAT)的Jason2衛(wèi)星為例,分析基于python語言的解碼過程重點和難點內(nèi)容,其中主程序的程序結(jié)構(gòu)和部分重要代碼如下:
從程序結(jié)構(gòu)來看,第1行是引用了自建的函數(shù)(其中,readbufr_pole_tide_height:獲取潮汐高度;readbufr_inverted_corr:反向的氣壓表訂正;readbufr_sea_surf_anomaly:海平面高度距平,是自己創(chuàng)建的函數(shù)。),可以看出,這是一個主體程序,還有附帶很多其他程序(函數(shù)或者函數(shù)庫)。一個復(fù)雜的數(shù)據(jù)處理文件,很難在一個程序中完全實現(xiàn),那樣既不容易調(diào)試也不容解讀程序;第4—7行是獲取該數(shù)據(jù)有多少個記錄數(shù),在壓縮格式BUFR解碼中是至關(guān)重要的信息,后面每一個要素數(shù)據(jù)的獲取都需要用到,如果該數(shù)值錯誤,將導(dǎo)致所有解碼結(jié)果都錯誤;第35—36行,是定義數(shù)據(jù)輸出文件,并打開一個可以支持寫入的文件,后續(xù)所有解碼數(shù)據(jù)均需要寫入該文件,確保數(shù)據(jù)統(tǒng)一輸出;第35行,是調(diào)用了1個自建函數(shù),輸入的3個參數(shù),分別是該要素的數(shù)據(jù)起始字節(jié)位置、輸入文件、輸出文件,有了這3個參數(shù)在函數(shù)體了就可以根據(jù)《表格驅(qū)動碼編碼手冊》[13]中定義的比例因子、基準(zhǔn)值、數(shù)據(jù)寬度等信息獲取相應(yīng)的數(shù)據(jù),并且輸出到指定的輸出文件,其中數(shù)據(jù)起始字節(jié)位置數(shù)值的計算非常復(fù)雜(該值是從上一個要素解碼后計算出來的),首先要知道起始位置(L1),再加上該要素基礎(chǔ)值的占位寬度(n),再加上NBINC1的占位6 bit,最后加上增量值的占位寬度(s)乘以要素格式(N),起始位L=L1+(n+6+s×N)/8[+1],其中[+1]是需要根據(jù)該要素占位bit數(shù)決定,bit總數(shù)除以8,余數(shù)少于起始字節(jié)起始bit,則不用[+1],反之,則要[+1];第36、37兩行也是必須的,正常關(guān)閉程序前面打開的文件,否則形成垃圾信息占用系統(tǒng)內(nèi)存。
在壓縮格式BUFR的解碼中,由于編碼結(jié)構(gòu)的復(fù)雜性和不確定性,常常容易出現(xiàn)解碼錯誤的現(xiàn)象,并且難以判定是否錯誤。本研究針對容易出錯的情形進行分析。
錯誤1:取值順序與輸出值的順序。Bufr格式是二進制格式的文件,實際存儲數(shù)據(jù)是二進制的0、1形式保存,從第1位到最后一位。數(shù)據(jù)的抽取也是從第1位往后逐bit位抽取的,但是,在取完值之后,需要重新按計算機的8 bit為一個字節(jié)的結(jié)構(gòu)從后往前組織數(shù)據(jù)。
錯誤2:多字節(jié)值的生成;在取值過程中,有些要素的寬度是占用很多bit的,例如,“C波段海洋范圍”占位寬度31 bit,此時,獲取的31 bit,需要分為4字節(jié),而且是從后往前排,即最后3個字節(jié)各8 bit,最前一個字節(jié)7 bit,從前往后分別記為:a、b、c、d字節(jié),計算值為a×256×256×256+b×256×256+c×256+d。在實際計算時,容易從前往后取bit組成新的字節(jié),并且容易計算成a+b+c+d的值。
錯誤3:NBINC s的取值;NBINC s的固定長度是6 bit,該值的大小取決于后面增量的bit數(shù),因此,該值的準(zhǔn)確獲取非常重要。在計算的結(jié)果判斷上有個重要的方法,即該值的小于或者等于初始值的占位寬度,如果是大于初值占位數(shù),一般都錯誤,需要重新檢查數(shù)值的獲取及重組方法。常見錯誤是:由于NBINCs取值結(jié)構(gòu)簡單,忽略了錯誤的存在,導(dǎo)致取值大于初值占位寬度,從而導(dǎo)致后續(xù)的取值大相徑庭。
本研究通過實際壓縮格式BUFR文件的解碼實例,詳細分析了分析解碼過程,列出了解碼的重要步驟。詳細闡述了實際解碼過程中遇到問題的解決方法,為后來者提供參考,減少錯誤重犯,大大提高了解碼編程的效率和準(zhǔn)確性。