1. 阈值检测基础:什么是阈值检测?

阈值检测,说白了就是设一个“门槛”。信号超过这个门槛,我们就认为发生了某件事;没超过,就当作没发生。你想想看,这其实是我们做嵌入式信号处理时最常用、最直觉的判断方式。

我刚开始做信号处理那会儿,总觉得阈值检测太简单了,不就是 if (value > THRESHOLD) 吗?后来踩的坑多了才明白——阈值设得好,系统稳如老狗;阈值设得差,误报漏报满天飞。

1.1 阈值检测的数学本质

从数学上看,阈值检测就是一个二元决策问题。给定输入信号 x(t),我们定义一个阈值 T,然后做判断:

if x(t) > T:
    输出 = 1 (事件发生)
else:
    输出 = 0 (事件未发生)

就这么简单?嗯,表面上是。但实际项目中,信号往往带着噪声、漂移、毛刺。这时候阈值 T 怎么选,就成了技术活。

核心要点:阈值检测的本质是在“灵敏度”和“特异性”之间做权衡。阈值设低了,容易误报;设高了,容易漏报。这个平衡点,就是我们要找的“黄金阈值”。

1.2 阈值检测的三大应用场景

我在项目中遇到过不少阈值检测的应用,归纳起来主要有三类:

应用场景 典型例子 阈值类型 常见陷阱
边缘检测 数字图像中的物体轮廓提取 梯度幅值阈值 光照变化导致阈值失效
异常报警 电机电流过载、温度超限 绝对/相对阈值 瞬态尖峰引发误报
峰值识别 心电R波检测、振动频谱峰值 动态/自适应阈值 基线漂移掩盖真实峰值

边缘检测

图像处理里的 Canny 边缘检测,就是典型的阈值应用。它用高低两个阈值:高于高阈值的像素点被确定为强边缘,低于低阈值的被丢弃,介于两者之间的再根据连通性判断。我做过一个工业视觉项目,产品表面划痕检测,一开始固定阈值死活调不好——换了条产线光照不同,阈值就得重调。后来改成自适应阈值,才解决问题。

异常报警

嵌入式系统里最常见的场景。比如电机电流监测,超过额定电流 120% 就报警。但问题是,电机启动瞬间会有浪涌电流,如果阈值设得太死,每次启动都误报。我曾经在一个泵站监控项目里吃过这个亏——客户投诉说系统“神经质”,后来加了延时确认和滞回比较才搞定。

峰值识别

这个在生物医学信号处理里特别常见。心电信号的 R 波检测,就是找信号中的局部极大值。但心电信号有基线漂移,还有各种干扰。我记得有个学生做心电监护仪,用固定阈值检测 R 波,结果病人深呼吸一下,基线一飘,R 波全漏检了。后来我建议他用动态阈值——根据信号幅值的滑动均值实时调整阈值,效果立竿见影。

1.3 阈值检测的核心挑战

为什么阈值检测看起来简单,做起来却容易翻车?我总结了几点:

  1. 噪声干扰:信号中的随机噪声可能导致阈值附近反复跳变
  2. 基线漂移:信号的整体水平随时间变化,固定阈值失效
  3. 幅值变化:同一事件在不同时刻的幅值可能差异很大
  4. 多模态信号:不同工况下信号特征不同,单一阈值无法覆盖

避坑指南:我曾经在一个振动监测项目里,直接用固定阈值做报警。结果设备正常运行时振动幅值就有波动,阈值设低了天天误报,设高了又漏报真实故障。后来我加了滞回比较(hysteresis)——上升阈值和下降阈值分开设,才把误报率降下来。记住:阈值检测不是简单的“一刀切”,要考虑信号的动态特性。

1.4 阈值检测的知识体系

为了让你对本章内容有个整体认识,我画了张结构图:

阈值检测知识体系 阈值检测 边缘检测 异常报警 峰值识别 Canny算子 Sobel算子 滞回比较 延时确认 动态阈值 自适应 核心挑战:噪声干扰 · 基线漂移 · 幅值变化 · 多模态 解决思路:滞回比较 · 动态阈值 · 自适应算法

1.5 阈值检测的工程实现要点

在实际嵌入式系统里实现阈值检测,有几个细节要注意:

工程小技巧:在单片机里做阈值检测,我习惯用“滞回比较”来避免阈值附近的抖动。比如设定上升阈值 T_high 和下降阈值 T_low,T_high > T_low。信号超过 T_high 才触发,低于 T_low 才复位。这样能有效抑制噪声引起的误触发。代码实现也很简单:

// 滞回比较示例
#define T_HIGH  1.2f   // 上升阈值
#define T_LOW   0.8f    // 下降阈值

int hysteresis_compare(float signal, int *state) {
    if (*state == 0 && signal > T_HIGH) {
        *state = 1;   // 触发
        return 1;
    } else if (*state == 1 && signal < T_LOW) {
        *state = 0;   // 复位
        return 0;
    }
    return *state;    // 保持当前状态
}

这段代码我用了好多年,简单可靠。你想想看,如果没有滞回,信号在阈值附近抖动时,输出会频繁跳变,下游的逻辑根本没法处理。

1.6 阈值检测的局限性

阈值检测虽然好用,但不是万能的。我遇到过一些场景,阈值检测根本搞不定:

  • 信噪比太低:信号完全淹没在噪声里,阈值怎么设都没用
  • 信号特征复杂:比如语音信号,单纯用幅值阈值无法区分不同音节
  • 多维度判断:需要同时考虑幅值、频率、相位等多个特征

这时候就需要更高级的方法了——比如我们后面会讲到的自适应阈值、机器学习分类等。但不管多高级的算法,阈值检测都是最基础、最直观的起点。我个人习惯是:能用阈值解决的,绝不引入复杂算法;阈值搞不定的,再考虑升级方案。

嗯,这一章就到这里。阈值检测看似简单,但它是整个课程的基础。后面的章节我们会一步步深入,把阈值检测和时间测量结合起来,解决实际工程中的调优问题。