4. 灵敏度调整策略:静态阈值法、动态自适应阈值法、机器学习辅助阈值法

聊到堵转检测的灵敏度,说白了就是怎么定那个「触发线」。线定高了,电机都卡死半天了你还没报警,这叫漏报;线定低了,负载稍微波动一下它就乱叫,这叫误报。我这些年调过的项目,十有八九的坑都出在这个平衡点上。

这一章咱们就掰开揉碎,把三种主流的阈值设定策略讲透。从最基础的静态阈值,到能自动跟着工况跑的动态自适应,再到最近开始冒头的机器学习辅助方案。每种方法我都会结合实战经验,告诉你它适合什么场景、有什么坑。

堵转检测阈值策略知识体系 阈值设定策略 静态阈值法 固定门限 实现简单 适合工况稳定的场景 动态自适应阈值法 滑动窗口 + 统计量 能跟随负载变化 需调窗口长度和系数 机器学习辅助阈值法 特征提取 + 分类器 适应复杂工况 需要训练数据和算力 选型原则:简单场景用静态,波动场景用动态,复杂场景上机器学习 三者不是互斥关系,实际项目中常组合使用

4.1 静态阈值法:最朴素但最可靠的基础方案

静态阈值法,就是给电流、转速或者功率设一个固定值。超过它就判堵转,没超过就正常跑。听起来简单吧?但就是这种简单的方法,在工业现场占了至少六成以上的应用。

我习惯把静态阈值分成两类:绝对阈值和相对阈值。

类型 定义 典型值 适用场景
绝对阈值 直接设定电流/功率上限 额定电流 × 1.5 ~ 2.0 负载基本恒定的设备
相对阈值 以空载或额定值为基准 空载电流 + 30% ~ 50% 电机参数一致性好的产线
我的经验:绝对阈值适合「一刀切」的场景,比如水泵、风扇。相对阈值更适合电机个体差异大的情况。我曾经在一个项目里,同一批次的电机空载电流能差15%,用绝对阈值根本没法调,换成相对阈值后问题就解决了。

静态阈值法的实现代码也很直接。下面是一个基于电流采样的例子:

/* 静态阈值法堵转检测 */
#define STALL_CURRENT_THRESHOLD  3.5f   /* 堵转电流阈值,单位A */
#define STALL_TIME_THRESHOLD_MS  200    /* 持续堵转时间阈值,单位ms */

uint8_t StallDetect_Static(float phase_current, uint32_t timestamp_ms)
{
    static uint32_t stall_start_time = 0;
    static uint8_t  stall_flag = 0;
    
    if (phase_current > STALL_CURRENT_THRESHOLD)
    {
        if (stall_flag == 0)
        {
            stall_start_time = timestamp_ms;
            stall_flag = 1;
        }
        else if ((timestamp_ms - stall_start_time) > STALL_TIME_THRESHOLD_MS)
        {
            return 1;   /* 确认堵转 */
        }
    }
    else
    {
        stall_flag = 0; /* 电流回落,清除标志 */
    }
    
    return 0;
}
注意:静态阈值最怕的就是「临界抖动」。当电流刚好在阈值附近来回跳时,检测结果会反复翻转。我建议加一个滞回区间,比如阈值设为3.5A,恢复值设为3.0A,这样能有效避免频繁报警。

4.2 动态自适应阈值法:让阈值跟着工况跑

静态阈值搞不定的场景,说白了就是负载变化太大。比如工业机器人,空载时电流才2A,抓起工件瞬间冲到8A。你要是把阈值设在6A,空载堵转漏报;设在4A,抓工件时误报。怎么办?让阈值自己学会「看情况」。

动态自适应阈值法的核心思路就一句话:用最近一段时间的电流统计量,实时更新阈值。我常用的方案是滑动窗口均值加上一个偏移量。

具体做法分三步:

  1. 维护一个滑动窗口,比如存最近100个电流采样值
  2. 计算窗口内的统计量,最常用的是均值 + 标准差
  3. 动态生成阈值:阈值 = 均值 + K × 标准差

这里的K值很关键。K太小,阈值太敏感,容易误报;K太大,阈值太迟钝,容易漏报。我一般从K=3开始试,然后根据现场反馈微调。

/* 动态自适应阈值法 - 滑动窗口实现 */
#define WINDOW_SIZE     100
#define K_FACTOR        3.0f

typedef struct {
    float buffer[WINDOW_SIZE];
    int   index;
    float sum;
    float sum_sq;
} SlidingWindow;

void Window_Update(SlidingWindow *win, float new_val)
{
    float old_val = win->buffer[win->index];
    win->buffer[win->index] = new_val;
    win->index = (win->index + 1) % WINDOW_SIZE;
    
    win->sum    += (new_val - old_val);
    win->sum_sq += (new_val*new_val - old_val*old_val);
}

float Window_GetThreshold(SlidingWindow *win)
{
    float mean = win->sum / WINDOW_SIZE;
    float variance = (win->sum_sq / WINDOW_SIZE) - (mean * mean);
    float std = sqrtf(variance > 0 ? variance : 0);
    
    return mean + K_FACTOR * std;
}

避坑指南:我曾经在一个伺服驱动器项目里,直接用全速运行时的数据训练阈值,结果电机低速运行时频繁误报。为什么?因为低速时电流纹波大,标准差偏大,阈值被抬得太高了。后来我改成按转速区间分别维护滑动窗口,问题才解决。

动态自适应阈值法有几个参数需要调:

参数 作用 调大后果 调小后果
窗口长度 决定阈值对变化的响应速度 响应慢,适应滞后 响应快,但易受瞬态干扰
K系数 控制阈值与均值的距离 阈值高,易漏报 阈值低,易误报
更新频率 多久重新计算一次阈值 计算开销小,但更新不及时 实时性好,但CPU负载高

4.3 机器学习辅助阈值法:当规则搞不定时,让数据说话

说实话,大部分场景用动态自适应就够了。但有些工况实在太复杂——比如电梯门机,负载随门的位置、速度、温度、磨损程度都在变。你写规则写到吐血,还是会有漏网之鱼。这时候就该考虑机器学习辅助了。

注意我说的是「辅助」,不是「替代」。机器学习在堵转检测里的角色,是帮你找到一个更精准的阈值边界,而不是完全取代传统的检测逻辑。

我常用的做法是:提取特征 → 训练分类器 → 输出动态阈值系数。

特征一般选这几个:

  • 电流的均值、峰值、有效值
  • 电流的上升速率(di/dt)
  • 转速的波动幅度
  • 功率因数角的变化

分类器我推荐用轻量级的,比如决策树或逻辑回归。别一上来就上神经网络,嵌入式平台扛不住。下面是一个用逻辑回归做阈值辅助决策的伪代码:

/* 机器学习辅助阈值 - 逻辑回归示例 */
/* 特征向量: [电流均值, 电流峰值, di/dt, 转速波动] */

float features[4];
float weights[4] = {0.35, 0.25, 0.20, 0.20};  /* 训练得到的权重 */
float bias = -1.2f;

float StallProbability(float *feat)
{
    float z = bias;
    for (int i = 0; i < 4; i++)
        z += weights[i] * feat[i];
    
    /* Sigmoid函数,输出0~1的概率值 */
    return 1.0f / (1.0f + expf(-z));
}

/* 使用概率值动态调整阈值 */
float GetAdaptiveThreshold(float base_threshold, float *features)
{
    float prob = StallProbability(features);
    /* 概率高时降低阈值,提高灵敏度 */
    return base_threshold * (1.0f - 0.3f * prob);
}
我的建议:机器学习辅助方案不要一上来就追求高精度。先跑一个简单的逻辑回归模型,看看效果。如果准确率能到95%以上,就别折腾了。我在一个风机项目里试过,逻辑回归比手工调参的静态阈值法误报率降低了60%,而且只占用了不到2KB的RAM。

4.4 三种策略的对比与选型建议

说了这么多,到底该用哪种?我整理了一个对比表,方便你快速决策:

对比维度 静态阈值法 动态自适应阈值法 机器学习辅助阈值法
实现难度 ★☆☆☆☆ ★★★☆☆ ★★★★☆
计算开销 极低 低~中 中~高
适应能力 无 中等 强
调试工作量 低 中 高(需采集数据)
误报率 较高 中等 较低
适用场景 负载稳定、要求低成本 负载波动、中等复杂度 工况复杂、对误报敏感
最后提醒一句:别为了用机器学习而用机器学习。我见过有人给一个水泵控制器上了神经网络,结果训练数据没覆盖全工况,现场误报比原来还多。选方案之前,先问问自己:动态自适应真的搞不定吗?如果搞不定,是参数没调好,还是方法本身不行?想清楚再动手。