4、报警死区与滤波技术:死区设置原则、一阶滞后滤波、中值滤波在抑制抖动报警中的应用

各位做SCADA的同行,咱们今天聊聊报警抖动这个老难题。

说实话,做SCADA系统最烦人的不是大故障,而是那些频繁跳变、忽闪忽灭的抖动报警。我见过一个项目,操作员被一个压力报警折腾得直接关掉了报警声音——你想想看,这多危险。所以,死区和滤波技术,是每个SCADA工程师必须掌握的看家本领。

4.1 死区设置原则:别让微小的波动触发报警

死区,说白了就是给报警阈值加一个“缓冲带”。比如你设定温度高于80℃报警,那79.9℃和80.1℃之间来回跳,系统就会反复报警、恢复、再报警。加个死区,就能避免这种尴尬。

死区设置的核心原则:

  • 死区宽度 = 信号正常波动范围的1.5~2倍。我习惯先采集一段正常运行数据,看看信号波动的峰值,然后乘以1.5。比如波动范围是±0.5℃,死区就设1℃左右。
  • 死区不能太大。太大了会掩盖真实故障。我曾经见过一个项目,死区设了10%,结果设备都快烧了还没触发报警——这就是教训。
  • 区分上死区和下死区。有些系统支持非对称死区,比如上升沿死区小一点(快速响应),下降沿死区大一点(避免频繁恢复)。

举个例子:一个液位报警,高限设为80%,死区设为2%。那么实际触发逻辑是:液位超过80%报警,但必须降到78%以下才恢复。这2%的缓冲,就能过滤掉液面波动带来的误报。

我的经验:死区设置最好做成可配置参数,不要写死在程序里。现场调试时,你永远不知道信号会怎么波动。我一般会在HMI上留一个“死区调整”页面,让调试人员现场微调。

4.2 一阶滞后滤波:平滑信号的经典方法

一阶滞后滤波,其实就是个低通滤波器。它的原理很简单:当前输出 = 上次输出 × (1-α) + 当前输入 × α。α越小,滤波效果越强,但响应也越慢。

嗯,这里要注意:α的取值很关键。我一般这样选:

  • 对于快速变化的信号(如压力),α取0.3~0.5
  • 对于缓慢变化的信号(如温度),α取0.1~0.2
  • 对于特别抖动的信号(如流量),α可以低到0.05
// 一阶滞后滤波示例(C语言风格)
float filter_value = 0.0;  // 滤波后的值
float alpha = 0.2;         // 滤波系数

float low_pass_filter(float raw_value) {
    filter_value = filter_value * (1 - alpha) + raw_value * alpha;
    return filter_value;
}

这个算法简单到令人发指,但效果出奇的好。我记得在某个水处理项目中,原水流量信号抖得像心电图,用了α=0.1的一阶滞后滤波后,信号平滑得像丝绸一样。当然,代价是响应慢了大概3~5秒——对于水处理来说完全能接受。

避坑指南:我曾经在快速响应的保护系统中用过一阶滞后滤波,结果差点出事。因为滤波延迟导致保护动作慢了半秒,设备差点烧了。所以记住:保护逻辑不要加滤波,报警逻辑可以加

4.3 中值滤波:对付脉冲干扰的利器

中值滤波,说白了就是取一堆数据点的中间值。比如连续采5个点,排序后取第3个。这种方法对付尖峰脉冲特别有效——因为脉冲值要么最大要么最小,肯定被排到两端去了。

我一般这样用中值滤波:

  • 采样窗口大小:3、5、7个点。窗口越大,滤波效果越强,但延迟也越大。我个人习惯用5点中值,效果和延迟比较均衡。
  • 采样间隔:根据信号变化速度来定。快速信号用短间隔(如100ms),慢速信号用长间隔(如1s)。
  • 适用场景:电磁干扰严重的环境、传感器接触不良、通信丢包等情况。
// 5点中值滤波示例
#define WINDOW_SIZE 5
float buffer[WINDOW_SIZE] = {0};
int index = 0;

float median_filter(float raw_value) {
    float temp[WINDOW_SIZE];
    
    // 存入最新值
    buffer[index] = raw_value;
    index = (index + 1) % WINDOW_SIZE;
    
    // 复制并排序
    for (int i = 0; i < WINDOW_SIZE; i++) {
        temp[i] = buffer[i];
    }
    // 冒泡排序(简单示意)
    for (int i = 0; i < WINDOW_SIZE - 1; i++) {
        for (int j = 0; j < WINDOW_SIZE - i - 1; j++) {
            if (temp[j] > temp[j+1]) {
                float t = temp[j];
                temp[j] = temp[j+1];
                temp[j+1] = t;
            }
        }
    }
    // 返回中间值
    return temp[WINDOW_SIZE / 2];
}

中值滤波 vs 一阶滞后滤波:

特性 中值滤波 一阶滞后滤波
对脉冲干扰 完全消除 只能衰减
对随机噪声 效果一般 效果很好
响应延迟 固定(窗口大小决定) 可调(α决定)
计算量 较大(需要排序) 很小

4.4 组合使用:实战中的最佳实践

在实际项目中,我很少只用一种滤波方法。通常的做法是:

  1. 先做中值滤波,干掉明显的脉冲干扰。比如用3点中值,延迟很小。
  2. 再做一阶滞后滤波,平滑掉随机噪声。α取0.2左右。
  3. 最后加死区判断,过滤掉微小的波动。

举个例子,我在一个化工项目中处理反应釜温度信号:

// 组合滤波示例
float process_temperature(float raw_temp) {
    // 第一步:3点中值滤波
    float med = median_filter_3(raw_temp);
    
    // 第二步:一阶滞后滤波
    float smooth = low_pass_filter(med, 0.15);
    
    // 第三步:死区判断(假设报警阈值150℃,死区2℃)
    if (smooth > 150.0) {
        alarm_active = TRUE;
    } else if (smooth < 148.0) {
        alarm_active = FALSE;
    }
    // 148~150之间保持原状态不变
    
    return smooth;
}

这套组合拳打下来,报警抖动基本能消除90%以上。剩下的10%,要么是真正的故障,要么是传感器本身有问题——那就不是滤波能解决的了。

我的建议:滤波参数不要一次设死。先在调试模式下跑几天,看看信号的实际波动情况,再微调参数。我一般会在系统中保留原始信号和滤波后的信号,方便对比调试。

好了,关于报警死区和滤波技术,今天就聊到这儿。记住一句话:滤波是为了让报警更准确,而不是让报警变迟钝。把握好这个度,你的SCADA系统才能既灵敏又稳定。