SpringBoot工控告警防抖实战:解决瞬时抖动误告警
·
标签
#SpringBoot #工控告警 #防抖滤波 #SCADA #工业物联网
摘要
工业设备模拟量数值普遍存在瞬时抖动、瞬间跳变问题,直接开启越限告警会产生大量误报。本文基于上一篇基础告警引擎,新增延时防抖、持续校验、数据滤波机制,彻底解决工控、地铁 ISCS 项目高频误告警痛点,代码无损兼容原有告警逻辑,生产直接替换上线。
一、前言
上一篇我们实现了工控基础告警:越限告警 + 突变告警。
但是!裸奔的告警逻辑在现场根本无法直接用。
真实工控、轨交现场通病:
- 传感器信号干扰,数值瞬间跳一下马上恢复
- 485/网口采集偶尔出现瞬时脏数据
- 设备启停瞬间数值抖动
如果不做防抖,系统会一秒几十条误告警,运维直接崩溃、项目验收不通过。
所以本篇必须补上:工业级告警防抖 + 持续校验机制
只有「持续异常才算告警,瞬时抖动直接过滤」。
二、工业防抖核心原理(现场标准)
- 不触发瞬时告警
数值第一次超限不立即告警 - 延时持续校验
必须连续 N 次采集 / 持续 N 秒异常 - 稳定异常才触发告警
- 恢复也需要防抖:数值回落正常后,持续稳定再消除告警
完美适配地铁 BAS、电力监控、工厂 SCADA 标准逻辑。
三、新增告警规则字段(支持防抖配置)
在原有 AlarmRule 新增防抖参数,兼容上篇所有代码
import lombok.Data;
@Data
public class AlarmRule {
// 点位 ID
private String pointId;
// 设备 ID
private String deviceId;
// 告警类型 1 越限 2 突变
private Integer alarmType;
// 上下限
private Double maxValue;
private Double minValue;
private Double changeThreshold;
// ========== 本篇新增防抖参数 ==========
// 防抖持续次数:连续多少次异常才告警
private int filterCount = 3;
// 恢复防抖次数
private int recoverFilterCount = 3;
// 点位信息
private String pointName;
private String systemType;
}
四、点位防抖缓存实体(记录连续异常次数)
import lombok.Data;
@Data
public class AlarmCacheInfo {
// 连续异常次数
private int errorCount;
// 连续正常次数
private int normalCount;
// 当前是否处于告警状态
private boolean isAlarmStatus;
}
五、升级后【带防抖完整告警引擎】(核心源码)
import org.springframework.stereotype.Component;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Component
public class AlarmFilterEngine {
// 点位防抖缓存 key:pointId
private final Map<String, AlarmCacheInfo> alarmCacheMap = new ConcurrentHashMap<>();
/**
* 带防抖的告警判断
* @return true=真正触发告警 / false=抖动或正常
*/
public boolean checkAlarmWithFilter(CollectDataDTO data, AlarmRule rule) {
String pointId = data.getPointId();
double currVal = data.getValue();
// 获取该点位缓存,没有则初始化
AlarmCacheInfo cache = alarmCacheMap.getOrDefault(pointId, new AlarmCacheInfo());
// 1、判断当前数据是否异常
boolean isError = isOverLimit(currVal, rule) || isValueJump(pointId, currVal, rule);
if (isError) {
// 数据异常:异常次数累加、正常次数清零
cache.setErrorCount(cache.getErrorCount() + 1);
cache.setNormalCount(0);
// 未处于告警状态,且连续异常达到防抖阈值 → 正式触发告警
if (!cache.isAlarmStatus() && cache.getErrorCount() >= rule.getFilterCount()) {
cache.setAlarmStatus(true);
alarmCacheMap.put(pointId, cache);
return true;
}
} else {
// 数据正常:正常次数累加、异常次数清零
cache.setNormalCount(cache.getNormalCount() + 1);
cache.setErrorCount(0);
// 当前处于告警状态,且持续正常达到恢复阈值 → 解除告警
if (cache.isAlarmStatus() && cache.getNormalCount() >= rule.getRecoverFilterCount()) {
cache.setAlarmStatus(false);
}
}
alarmCacheMap.put(pointId, cache);
return false;
}
// 越限判断
private boolean isOverLimit(double val, AlarmRule rule) {
return val > rule.getMaxValue() || val < rule.getMinValue();
}
// 突变判断
private boolean isValueJump(String pointId, double curr, AlarmRule rule) {
Double lastVal = LastValueCache.get(pointId);
if (lastVal == null) return false;
return Math.abs(curr - lastVal) > rule.getChangeThreshold();
}
}
六、全局历史值缓存工具类(适配突变防抖)
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class LastValueCache {
private static final Map<String, Double> LAST_MAP = new ConcurrentHashMap<>();
public static void put(String pointId, Double val) {
LAST_MAP.put(pointId, val);
}
public static Double get(String pointId) {
return LAST_MAP.get(pointId);
}
}
七、业务调用方式(完全兼容旧代码)
// 获取实时数据
CollectDataDTO data = collectService.getRealTimeData();
// 获取告警规则
AlarmRule rule = ruleService.getRuleByPointId(data.getPointId());
// 防抖校验
boolean realAlarm = alarmFilterEngine.checkAlarmWithFilter(data, rule);
if (realAlarm) {
// 正式告警:入库 + 推送大屏
tdEngineService.saveAlarm(data, rule);
websocketService.pushAlarm(data, rule);
}
// 更新历史值,用于下一次突变判断
LastValueCache.put(data.getPointId(), data.getValue());
八、工业 / 轨交现场标准配置参数
- 普通模拟量(温度 / 压力 / 液位)
防抖次数:3 次 - 波动大的电流、功率点位
防抖次数:5~8 次 - 开关量、状态量
可关闭防抖或 2 次即可
九、现场落地优势(8 年轨交经验总结)
- 彻底消灭瞬时误告警
95% 以上的信号抖动、瞬时脏数据全部过滤 - 不丢失真实故障
真实持续异常一定会触发告警 - 告警恢复更平稳
设备恢复稳定后才消除告警,避免反复闪断 - 完全兼容上一版代码
无缝升级,无需改动原有存储、推送逻辑
十、总结
本篇在基础告警之上,补齐工业防抖、延时校验核心能力,
至此你的告警系统达到商用 SCADA、地铁 ISCS 验收标准。
不再乱告警、不再刷屏、运维体验拉满。
持续连载更新
本专栏基于 8 年轨道交通工控落地经验,从零手写一套完整工业物联网 SCADA 架构。
需要全套可运行源码的朋友评论区扣【源码】,关注持续更新!
更多推荐

所有评论(0)