Skip to main content

自定义四维二进制格式

现有格式存在的问题

经常被用来保存气象数据的格式已经非常多,如nc、grib、hdf、micaps等等,为何我们我们还要定义新的数据存储格式呢?

这主要是因为咱们的应用通常运行于浏览器端,数据从服务器到看到要经过后端解码筛选、网络传输、前端解析、前端渲染这几个阶段,这样的场景要求我们的数据必须要能够快速的被获取、快速的传输、快速的解码,而传统的数据格式定义在很多时候无法同时满足这些要求,如:

  1. GRIB/NC格式被大量用于存储数值模式输出结果,而这个格式定义非常灵活,目前还没有解码器能够直接在浏览器对该格式进行完美解码,自行编写编码器设计的依赖库众多,也不是一个短期能够完成的任务,后端实时解码又会降低数据获取的效率。
  2. Micaps/MUSIC等文本格式虽然简单易懂,但是如果精细化的网格数据直接文本存储会造成尺寸过大,传输过慢,而且前端也需要二次解析,但是对于内网高带宽应用也是合适的。
  3. OPeNDAP数据规范是为数不多的比较适合的开箱即用的数据服务系统,但是由于其为了支持各类投影,在返回数据时同步返回了经纬度网格的二维场,大大增加了数据传输量,但不失为一个极好的内网数据服务端。

新的数据格式

为了解决以上问题,我们针对前端渲染的需要定义了一个新的简单的数据格式,具体如下:

ZIP(文件头JSONString长度(int)+JSONString+DATA[t,z,y,x])

格点数据首先是4个字节的整型,表示JSONString区域的长度(不含该整型4字节本身), 然后是JSON转成二进制字符串的头文件部分,头文件具体格式见头文件部分。

最后是数据部分,数据部分首先保存第一个时次的第一个层次的二维数据场,数据场中纬度在外层,经度在内层,如下所示: data[time][level][y][x]

最后为了缩小文件尺寸的同时保证前端解压效率,使用zip格式进行存储。

头文件长度

前四个字节是头文件区域的长度,是四个字节的int,不包括自身。

头文件描述
示例
{
    "xStart": 112.35,
    "yStart": 36.0,
    "xDelta": 0.025,
    "yDelta": 0.025,
    "xSize": 307,
    "ySize": 301,
    "xEnd": 120.0,
    "yEnd": 43.5,
    "times": 3,
    "levels": 3,
    "timestamp": 1595574600,
    "levelList": [
        "150",
        "450",
        "750"
    ],
    "timeList": [
        "0",
        "10",
        "20"
    ],
    "dataType": "Int8",
    "undef": 255.0,
    "dataScale": 1.0,
    "dataOffset": 0.0,
    "units": null,
    "littleEndian": true,
    "properties": {},
    "unsigned": true
}
关键字名                                        类型                    描述
xStart float 起始经度
yStart float 起始纬度
xEnd float 结束经度
yEnd float 结束纬度
xDelta float 经度间隔
yDelta float 纬度间隔
xSize int 经度格点数
ySize int 纬度格点数
times int 时间个数
levels int level个数
timestamp long 时间
levelList 数组 层级数组,单位是米,如果是其他单位,在使用前前端需要先预处理为米
timeList 数组 时间(毫秒时间戳)数组,用于业务系统识别时间,框架本身不用
dataType string Int8或Int16或Int32或Float32
undef float 缺省值
dataScale float 数据的缩放倍数,比如数据已经被放大了2倍再存储,则该值存储为0.5(即数据精度为0.5)。在存储时,存储值=(原始值-offset)/scale如雷达有效反射率可能在-30~100之间,希望能够存储到0.5的精度,就可以将offset设置为-30,scale设置为0.5,然后通过上述公式算出实际存储值,这时候的存储值即可用uint8来表示(dataType=”Int8”,unsiged=true),以便节约存储空间。
dataOffset float 数据的偏移量,比如数据增加了66再存储,则该值为-66
units string 单位
littleEndian boolean 保持为true,暂时不支持大端
unsigned boolean 无符号为true,否则为false
properties Map对象 自由数据
数据区域

数据区域支持四个维度,其中时间在最外层,接下来是层次,然后是纬度,最后是经度。其中时间和层次可以只有一个时次和一个层次。

使用示例

该类数据格式在框架中由QEGridDataProvider负责解析,具体使用示例如下: