3. 水下传感器类型与数据特性认知

水下多传感器融合的第一步不是写融合算法,而是把每个传感器的“脾气”摸清楚:它输出什么、多久输出一次、噪声长什么样、在时间和空间上能分辨多细。如果对数据特性没有基本认知,后面的时间同步、坐标变换和滤波融合都会建立在错误的假设上。本节围绕七类常见水下传感器展开,先建立数据特性的整体认识,再用 Python 实际加载并统计一组模拟数据,形成可复用的数据检查流程。

七类传感器的输出与特性对照

从融合视角看,传感器可以分为三类:运动与姿态类(DVL、IMU)、环境参数类(CTD、水听器)、感知成像类(侧扫声呐、多波束声呐、水下相机)。它们的采样率、噪声模型和时空分辨率差异极大,直接决定了融合时的预处理策略。

传感器 典型输出 采样率(示例) 主要噪声/误差 时空分辨率
CTD 电导率、温度、深度(盐度由计算得出) 1~8 Hz 传感器漂移、热滞后、泵流扰动 单点测量,时间分辨率低,空间上仅代表探头附近水体
DVL 三轴对底速度、高度、波束有效标志 1~10 Hz 底质相关偏差、波束丢失、野值 厘米级速度精度,空间上为波束足印范围
IMU 三轴加速度、三轴角速度(可含姿态) 100~400 Hz 零偏、随机游走、温漂、振动耦合 时间分辨率最高,误差随时间累积
侧扫声呐 左右舷回波强度序列(按 ping 组织) 每 ping 数 Hz 至数十 Hz 斑点噪声、增益不均、航迹畸变 沿航迹高分辨率,垂直航迹分辨率随距离下降
多波束声呐 每波束的距离与角度,形成测深点云 每 ping 数 Hz 声速误差、波束角误差、底质影响 扇面覆盖,分辨率随开角和距离变化
水下相机 图像帧(RGB 或灰度) 5~30 fps 水体散射、光照不均、运动模糊 空间分辨率高,有效距离通常仅数米
水听器 声压时域波形(可转频谱) 数十至数百 kHz 采样 环境噪声、平台自噪声、多径 时间连续,空间定位需阵列或配合其它信息

这张表最重要的信息不是具体数值,而是量级差异:IMU 每秒数百个样本,CTD 每秒只有几个,声呐按 ping 组织,相机按帧组织。融合前必须统一到同一时间基准,并对高频数据做降采样或对低频数据做插值,同时保留每个样本的时间戳与有效性标志。

传感器数据特性 → 预处理 → 融合输入 运动与姿态类 IMU:加速度/角速度,100~400 Hz DVL:三轴速度+高度,1~10 Hz 特点:高频、误差随时间累积 关键:零偏标定、野值剔除 环境参数类 CTD:电导率/温度/深度,1~8 Hz 水听器:声压波形,数十~数百 kHz 特点:低频缓变或超高频连续 关键:漂移校正、分帧与频谱化 感知成像类 侧扫/多波束:按 ping 组织 水下相机:图像帧,5~30 fps 特点:数据量大、空间信息丰富 关键:时间戳对齐、几何校正 统一预处理:时间对齐 · 有效性筛选 · 噪声统计 · 坐标统一 ① 以 IMU 高频时钟为基准,其余传感器按最近邻或线性插值对齐 ② 用 DVL 波束有效标志、CTD 量程、图像亮度阈值剔除无效样本 ③ 统计均值、标准差、分位数,判断噪声水平是否符合预期 融合输入:带时间戳、带有效性标志、量纲统一的数据表 后续滤波/图优化只依赖这一层,不再直接读原始文件

用 Python 加载并做初步统计

下面用一组模拟数据演示完整流程。假设一次约 60 秒的潜航记录,IMU 以 100 Hz 输出,DVL 以 5 Hz 输出,CTD 以 2 Hz 输出。数据以 CSV 保存,字段包含时间戳、测量值和有效性标志。示例数值为合理假设,用于说明方法,不代表实测结果。

import numpy as np
import pandas as pd

# 模拟 IMU:100 Hz,含零偏与白噪声
fs_imu = 100.0
t_imu = np.arange(0, 60, 1/fs_imu)
acc_x = 0.02 * np.sin(2*np.pi*0.1*t_imu) + 0.01 + np.random.normal(0, 0.05, t_imu.size)
imu = pd.DataFrame({"t": t_imu, "acc_x": acc_x})

# 模拟 DVL:5 Hz,含少量野值
fs_dvl = 5.0
t_dvl = np.arange(0, 60, 1/fs_dvl)
vx = 0.8 + np.random.normal(0, 0.03, t_dvl.size)
vx[::37] += 1.5          # 人为注入野值
valid = np.ones(t_dvl.size, dtype=bool)
valid[::53] = False      # 模拟波束丢失
dvl = pd.DataFrame({"t": t_dvl, "vx": vx, "valid": valid})

# 模拟 CTD:2 Hz,温度缓慢漂移
fs_ctd = 2.0
t_ctd = np.arange(0, 60, 1/fs_ctd)
temp = 18.5 + 0.002*t_ctd + np.random.normal(0, 0.01, t_ctd.size)
ctd = pd.DataFrame({"t": t_ctd, "temp": temp})

加载后先做三件事:检查时间戳是否单调、统计各通道的均值与标准差、按有效性标志过滤。对 DVL 的野值,可用中位数绝对偏差(MAD)做稳健判别:偏离中位数超过 5 倍 MAD 的样本标记为可疑。对 IMU,重点看静止段的标准差,它近似反映噪声底;若某轴标准差明显偏大,需怀疑振动耦合或安装松动。

def robust_outlier(series, k=5.0):
    med = series.median()
    mad = (series - med).abs().median()
    return (series - med).abs() > k * mad

dvl["suspect"] = robust_outlier(dvl["vx"])
clean = dvl[dvl["valid"] & ~dvl["suspect"]]

print("IMU acc_x 均值/标准差:", imu.acc_x.mean().round(4), imu.acc_x.std().round(4))
print("DVL 原始样本数:", len(dvl), " 清洗后:", len(clean))
print("CTD 温度范围:", ctd.temp.min().round(3), "~", ctd.temp.max().round(3))

示例输出大致为:IMU 加速度均值接近 0.01、标准差约 0.05;DVL 原始 300 个样本,清洗后约 290 个;CTD 温度在 18.5 附近小幅波动。这些数字本身不重要,重要的是形成判断依据:标准差是否与传感器手册的噪声指标同量级、清洗比例是否异常偏高、温度变化速率是否物理上合理。若 DVL 清洗掉的比例超过 10%,就应回头检查底质或安装角度,而不是直接进入融合。

建议把上述检查封装成函数,每次拿到新数据先跑一遍,输出时间跨度、采样率估计、缺失率、各通道统计量和可疑样本数。这份“数据体检报告”比任何融合参数都更早暴露问题。

时空分辨率对融合的直接影响

时间分辨率决定对齐方式:IMU 与 DVL 相差 20 倍采样率,若直接把两者按行拼接,会严重错位;正确做法是以 IMU 时间轴为基准,对 DVL 速度做零阶保持或线性插值,并记录插值引入的误差。空间分辨率决定信息权重:多波束声呐在近距扇面内测深点密集,远距处点稀疏且误差增大,融合建图时应按距离给权重,而不是一视同仁。水下相机的有效距离通常只有几米,超过该距离的图像不应参与几何约束。

噪声特性则决定滤波器的观测噪声矩阵。IMU 的零偏是慢变误差,适合用随机游走建模;DVL 的野值是稀疏大误差,适合用稳健核函数或卡方检验抑制;CTD 的漂移是低频趋势,适合在长时间尺度上做平滑校正。把这些差异写进预处理和噪声模型,融合结果才可信。

不要用同一套噪声参数套用所有传感器,也不要在未检查有效性标志的情况下直接使用 DVL 速度。波束丢失期间的样本往往是保持值或零值,直接参与融合会引入系统性偏差。