报警体系设计

SCADA 系统做得好不好,报警体系是试金石。报警不是"越界就弹一条"那么简单,它要回答四个问题:什么值得报、报给谁、多紧急、怎么处理。先设计报警分类,再谈实现。

常见的报警来源分三类:模拟量越限(温度超过上限、压力低于下限)、数字量状态跳变(急停触发、门打开)、计算量异常(两个传感器读数偏差过大、速率超限)。每一类都要有独立的定义与处置流程,不能混在一个池子里。

本文核心知识点
  • 分级报警按严重程度分优先级。
  • 抑制死区与延时过滤抖动报警。
  • 归档历史数据分层存储与压缩。
  • 趋势实时与历史曲线联动分析。

优先级建议分四级:提示级(不影响生产,仅记录)、警告级(可能影响,需关注)、严重级(必须处理)、紧急级(立即停线或联动保护)。报警阈值不是一拍脑袋定的,要结合工艺设计值、历史数据分布与操作员处理时间综合确定。

SCADA 进阶配图:深蓝渐变背景上中央监控大屏轮廓延伸出报警闪烁光点与历史曲线折线、时钟圆环光影的扁平科技插画
报警、历史与趋势是 SCADA 的三大支柱,缺一不可。

报警处理与抑制

报警最怕"狼来了":同一信号在阈值附近反复抖动,一条接一条报警,操作员很快麻木,真正严重的报警反而被淹没。抑制机制就是对付这个问题的:死区、延时、确认与恢复。

// 带死区与延时的模拟量越限判断
float last_ok_value;   // 上次确认的正常值
uint32_t exceed_ticks; // 持续越限计数

int check_alarm(float v, float hi, float deadband) {
  if (v > hi) {
    if (++exceed_ticks >= 3) {      // 连续 3 拍才报
      if (v - last_ok_value > deadband) {
        last_ok_value = v;
        return ALARM_ACTIVE;        // 触发并记住
      }
    }
  } else {
    exceed_ticks = 0;
    if (v <= hi - deadband) last_ok_value = v; // 复位
  }
  return ALARM_NONE;
}

除了死区与延时,还要设计抑制规则:联锁信号触发时抑制相关报警(比如停泵后"压力低"报警失去意义)、设备检修时挂起该设备的报警、报警确认后只在恢复时再报一次。这些规则让报警列表保持干净、可信。

历史数据归档

历史数据是追溯事故与优化工艺的基础。全部点位按最高频率存既不现实也没必要,正确的做法是分层归档:高频段(秒级)只保留最近数小时,中频段(分钟级)保留数周,低频段(小时级)长期保留。存储引擎用工业时序数据库,专门为这种写入密集、按时间查询的场景设计。

  • 采集频率:按工艺需要定,变化快的点密一点,稳定量一天几条就够。
  • 压缩存储:相邻值变化小于死区时只存首尾,回放时按需插值。
  • 标签模型:点表统一管理,一个标签对应一个物理量及其单位、量程。
  • 断点续传:现场与服务器断连后本地暂存,恢复后补齐,保证数据完整。

归档的性能瓶颈通常在写入端:采集器要批量写、异步写,而不是一条一条同步提交。时序库支持批量写入接口,采集任务攒一批(比如 500 条)再落库,吞吐能差一个数量级。

趋势曲线实现

趋势曲线分实时趋势与历史趋势。实时趋势展示最近几分钟的数据,随采集刷新;历史趋势从归档库拉取任意时间段。实现上都要做三件事:取数、降采样、绘制。取数按查询窗口决定,降采样避免数据点过多把图画成黑块。

// 历史趋势查询 + 降采样(伪代码)
query = "SELECT ts, avg(value) FROM history "
        "WHERE tag='T_101' AND ts BETWEEN ? AND ? "
        "GROUP BY time(1m)"       // 按分钟聚合
for row in db.query(query):
    points.append([row.ts, row.avg])
draw_chart(points);               // 绘制到趋势控件

降采样的粒度按屏幕宽度来:画面上能容纳 2000 个像素点,就把查询窗口分成 2000 段取聚合值,既保证形状又保证流畅。窗口缩放时重新查询,这就是趋势控件"越放大越精细"的原理。