3. 原始数据文件结构与元数据解析
拿到一台海流ADCP的原始数据,第一步不是急着画流速剖面,而是先弄清楚“文件里到底装了什么”。ADCP原始数据通常由头文件(header)与数据块(data block/ensemble)交替组成,头文件描述设备配置、坐标系统、时间基准和数据结构,数据块则按固定节拍记录每个测量集合(ensemble)的观测值。若头文件解析错误,后续的坐标旋转、时间对齐和深度换算都会系统性偏移,因此元数据解析是质量控制的第一道关口。
一、两类主流格式的组织方式
RDI(Teledyne RD Instruments)格式以二进制为主,常见扩展名包括 .000、.ENR、.ENS、.STA、.LTA。其文件由一系列“ensemble”构成,每个 ensemble 前有 2 字节的 ID 码(如 0x7F7F 表示标准 ensemble),随后是长度字段、头信息、固定/可变数据段和校验和。头信息中包含系统配置(频率、波束数、盲区、单元长度、单元数量)、坐标变换参数(倾斜、航向、磁偏角)、时间戳(年、月、日、时、分、秒、百分秒)以及工作模式(宽带/窄带)。
Nortek 格式常见为 .ad2(Signature/Aquadopp)或 .vec(Vector),同样采用“配置块 + 数据块”结构,但字段布局与 RDI 不同。Nortek 的配置块记录频率、波束几何、采样率、坐标系统(BEAM/XYZ/ENU)、声速、磁偏角等;数据块按时间顺序记录每个 profile 的波束速度、相关度、振幅和状态位。解析时需按官方定义逐字段读取,不能凭经验套用 RDI 的偏移量。
pycurrents、adcpreader、dolfyn)试读,确认 ensemble 长度与字段偏移是否自洽。二、头文件中的关键元数据
头文件信息可归纳为四类,每一类都直接影响后续处理:
- 几何与采样参数:换能器频率、波束倾角(常见 20° 或 30°)、单元长度(cell size)、单元数量、盲区(blank beyond transmit)、脉冲重复频率。它们决定剖面深度范围与垂向分辨率。
- 坐标系统:原始波束坐标(BEAM)、仪器坐标(XYZ)、地球坐标(ENU 或 EAST-NORTH-UP)。头文件中的坐标变换标志位决定数据是否需要旋转,以及旋转所需的角度来源。
- 时间基准:RTC(实时时钟)时间、是否使用 UTC、是否含闰秒处理、时间戳分辨率(RDI 常见到 0.01 s)。时间基准错误会导致与潮汐、风场等外部数据无法对齐。
- 姿态与磁参数:倾斜计、罗经的安装偏移、磁偏角(declination)、是否启用磁校正。这些参数参与从 XYZ 到 ENU 的旋转。
三、坐标系统与时间基准的解析要点
坐标系统的核心是“先定义、后旋转、全程一致”。以 RDI 为例,BEAM 坐标下四个波束速度指向换能器各波束方向;XYZ 坐标以仪器为原点,X 轴指向换能器标记方向;ENU 坐标以地理东、北、天为轴。从 XYZ 到 ENU 需要航向(heading)、倾斜(pitch/roll)和磁偏角,旋转顺序通常为:先绕 X 轴倾斜校正,再绕 Z 轴航向旋转,最后叠加磁偏角。若头文件中磁偏角为 0 而实际作业区偏角为 −8°,则 ENU 流速方向会整体偏转约 8°,这在海流方向分析中是不可接受的系统误差。
时间基准方面,需确认三件事:时间戳是 UTC 还是本地时间;RTC 是否在布放前与 GPS 对时;是否存在“时间回绕”或跳变。实际解析时,建议将每个 ensemble 的时间戳转换为统一的 UTC 秒(如 Unix 时间),并检查相邻 ensemble 的时间间隔是否等于设定采样间隔(例如 600 s)。若出现间隔为 0 或负值,说明时间字段解析错位或 RTC 异常,应标记为可疑数据。
四、解析实操:从字节到可用字段
以 RDI 标准 ensemble 为例,解析流程可概括为:读取 2 字节 ID → 读取 2 字节 ensemble 字节数 → 按头文件偏移表读取系统配置、时间、坐标变换参数 → 读取固定数据段(波束速度、相关度、振幅、状态位)→ 读取可变数据段(如底部跟踪、GPS)→ 校验和比对。若校验失败,该 ensemble 应标记为损坏并跳过,而不是强行使用。
下面是一段示意性的解析伪代码,用于说明字段读取顺序(参数为教学示例,非实测值):
# 示意:RDI ensemble 头解析(字段偏移需按实际固件版本核对)
id_code = read_u16(f) # 0x7F7F 表示标准 ensemble
ens_bytes = read_u16(f) # 本 ensemble 总字节数
spare = read_u8(f)
num_beams = read_u8(f) # 常见 4
num_cells = read_u16(f) # 示例:60
cell_size_m = read_u16(f) / 100.0 # 示例:1.00 m
blank_m = read_u16(f) / 100.0 # 示例:1.50 m
year, month, day, hour, minute, sec, hundredth = read_time(f)
coord_flag = read_u8(f) # 0=BEAM, 1=XYZ, 2=ENU
heading = read_u16(f) / 100.0 # 示例:135.20°
pitch = read_i16(f) / 100.0
roll = read_i16(f) / 100.0
declination = read_i16(f) / 100.0 # 示例:-8.00°
解析完成后,应做三项自检:其一,num_cells × cell_size_m + blank_m 是否与设备标称剖面范围一致;其二,coord_flag 与后续处理流程是否匹配(若已是 ENU,则不应重复旋转);其三,时间戳转换后的相邻间隔是否稳定。三项自检通过,才进入速度数据的质量控制环节。
五、常见陷阱与处理建议
格式误判:把 Nortek 文件按 RDI 偏移读取,会得到看似合理但完全错误的数值。应先用魔数和官方文档确认格式,再选择对应解析器。坐标重复旋转:部分数据已由设备内部输出 ENU,若处理脚本再次应用航向旋转,方向会二次偏转。时间基准混用:RTC 未对时或使用本地时间,会导致与潮汐表、风场数据错位数小时。磁偏角缺失:头文件偏角为 0 但实际不为 0,属于系统性方向误差,需在元数据阶段修正并记录。
综上,原始数据文件结构与元数据解析的本质,是把二进制字节翻译成“可信任的物理量与参照系”。只有头文件中的几何、坐标、时间和姿态参数被正确读出并交叉验证,后续的流速剖面才具备可比性与可复现性。