3. 位移数据异常值识别与清洗规则配置
为什么清洗规则要“先分类、再处置”
雷达位移序列中的异常并非同一种性质:跳变是相邻采样点之间的突变,负值是物理上不可能的累计位移方向,超量程是超出设备标称测量范围的读数。三类异常的成因不同(多路径反射、遮挡失锁、解算发散、设备重启等),处置方式也不同——跳变适合“标记并插值”,负值适合“置空并告警”,超量程适合“整段剔除”。因此规则配置的核心是把判定条件与处置动作解耦,并让每一次处置都留下可追溯的日志。
规则参数与处置动作的配置表
下面这份配置表可直接作为规则引擎的输入。阈值需结合设备标称量程与测点历史波动水平设定,示例中的数值仅作教学演示,实际项目应按监测设计文件调整。
| 规则 | 判定条件 | 处置动作 | 日志字段 | 是否告警 |
|---|---|---|---|---|
| R1 跳变 | |d(t) − d(t−1)| > 20 mm | 标记 JUMP,用前后有效值线性插值 | 时间、测点、原值、插值 | 否(累计频次超限再告警) |
| R2 负值 | d(t) < 0 mm | 置为 NULL,不参与后续速率计算 | 时间、测点、原值 | 是 |
| R3 超量程 | d(t) > 500 mm 或 NaN | 整段剔除,标记 RANGE | 时间、测点、原值、剔除原因 | 是 |
可运行的清洗实现
以下 Python 代码实现上述三条规则,输入为按时间排序的位移记录列表,输出清洗后序列与清洗日志。代码自包含,可直接运行验证。
import math
# 规则参数(示例值,实际按监测设计调整)
JUMP_THRESHOLD = 20.0 # mm
RANGE_MAX = 500.0 # mm
def clean_displacement(records):
"""
records: [{'t': str, 'point': str, 'd': float or None}, ...] 按时间升序
返回: (cleaned, logs)
"""
cleaned, logs = [], []
prev_valid = None
for i, rec in enumerate(records):
t, pid, d = rec['t'], rec['point'], rec['d']
action = None
# R3 超量程 / 缺失
if d is None or (isinstance(d, float) and math.isnan(d)) or d > RANGE_MAX:
action = 'RANGE'
logs.append({'t': t, 'point': pid, 'rule': 'R3',
'raw': d, 'action': '剔除'})
cleaned.append({'t': t, 'point': pid, 'd': None, 'flag': 'RANGE'})
continue
# R2 负值
if d < 0:
action = 'NEG'
logs.append({'t': t, 'point': pid, 'rule': 'R2',
'raw': d, 'action': '置空'})
cleaned.append({'t': t, 'point': pid, 'd': None, 'flag': 'NEG'})
continue
# R1 跳变
if prev_valid is not None and abs(d - prev_valid) > JUMP_THRESHOLD:
# 用前一个有效值暂代,后续可做线性插值
logs.append({'t': t, 'point': pid, 'rule': 'R1',
'raw': d, 'action': '插值'})
cleaned.append({'t': t, 'point': pid, 'd': prev_valid, 'flag': 'JUMP'})
continue
# 正常值
prev_valid = d
cleaned.append({'t': t, 'point': pid, 'd': d, 'flag': 'OK'})
return cleaned, logs
if __name__ == '__main__':
raw = [
{'t': 't1', 'point': 'P07', 'd': 12.4},
{'t': 't2', 'point': 'P07', 'd': 12.6},
{'t': 't3', 'point': 'P07', 'd': 41.9},
{'t': 't4', 'point': 'P07', 'd': -3.2},
{'t': 't5', 'point': 'P07', 'd': 999.0},
]
cleaned, logs = clean_displacement(raw)
for c in cleaned:
print(c)
print('--- 清洗日志 ---')
for lg in logs:
print(lg)
结果判读与验证要点
- t3 跳变:41.9 与前一有效值 12.6 相差 29.3 mm,超过 20 mm 阈值,被标记 JUMP 并以 12.6 暂代;若需更平滑,可在前后有效值之间做线性插值。
- t4 负值:−3.2 mm 被置为 NULL 并写入 R2 日志,后续速率计算应跳过该点,避免出现虚假的“回弹”速率。
- t5 超量程:999.0 mm 超过 500 mm 上限,整条记录剔除并标记 RANGE,同时应触发设备自检流程。
- 日志完整性:每条被处置的记录都必须包含时间、测点、规则编号、原值与动作,便于事后追溯与规则调优。
规则顺序会影响结果:若先判负值再判跳变,则负值不会被误判为跳变;建议按“超量程→负值→跳变”的顺序执行,命中即终止后续判定。
阈值不是越小越好。跳变阈值过小会把真实加速变形误判为异常而插值抹平,反而掩盖预警信号;应结合测点历史波动统计(如 3σ 或分位数)设定,并保留人工复核通道。