灵敏度核心参数:电流阈值、时间窗口与去抖滤波

堵转检测的灵敏度,说白了就是三个旋钮:电流阈值、时间窗口、去抖滤波。调得好,电机该保护时保护,不该报时绝不乱报。调不好,要么电机烧了还没反应,要么正常转两下就给你停机。

我刚开始做电机驱动那会儿,就吃过这个亏。阈值设得太低,生产线上一晚上误报七八次,产线组长差点拿扳手来找我。后来才明白,这三个参数不是孤立调的,它们是一个整体。

1. 电流阈值:堵转的第一道防线

电流阈值,就是判断“电流大到算堵转”的那个门限值。设高了,堵死了也不报;设低了,正常负载波动就触发。

核心原则:阈值 = 额定电流 × 系数 + 安全余量

这个系数怎么取?我一般分三步走:

  1. 测稳态电流:让电机带额定负载稳定运行,记录电流波形。取平均值作为基准。
  2. 测启动电流:电机启动瞬间电流通常是额定值的 3-7 倍。这个峰值不能触发堵转。
  3. 定阈值:阈值设在稳态电流的 1.5-2.5 倍之间。具体看负载特性。
应用场景 推荐阈值倍数 说明
小风扇、水泵 1.5 - 2.0 倍 负载平稳,波动小
电动工具、压缩机 2.0 - 3.0 倍 启动冲击大,需避开
工业伺服、机器人关节 1.2 - 1.8 倍 精度要求高,余量小

注意:千万别把阈值设成固定值。温度变化、电源电压波动都会让电流漂移。我习惯在代码里做动态校准——每隔一段时间重新采样空载电流,自动调整基准。

2. 时间窗口:别让瞬间冲击骗了你

光有电流阈值还不够。电机启动瞬间、负载突变时,电流都会冲上去。如果一超阈值就报堵转,那误报率会高得离谱。

时间窗口就是干这个的:电流超过阈值,并且持续超过设定时间,才判定为堵转。

我个人习惯把时间窗口分成两段:

  • 确认时间:电流超阈值后,等待一段时间(比如 50-200ms),确认不是瞬态冲击。
  • 保护动作时间:确认堵转后,再持续一段时间(比如 500ms-2s),才执行停机或降速。

为什么要分两段?我遇到过一种情况:电机堵转后,电流会先冲高,然后因为绕组发热电阻变大,电流反而降下来一点。如果只设一段窗口,可能刚确认堵转,电流又掉回阈值以下,导致保护被撤销。分两段就能避免这种“假恢复”。

经验值:对于大多数直流无刷电机,确认时间设在 100ms 左右比较稳妥。启动冲击通常持续 20-50ms,100ms 足够避开。保护动作时间我一般设 1s,既不会误停,也不会让电机长时间堵转。

3. 去抖滤波算法:把噪声滤干净

电流采样信号里全是噪声——PWM 开关噪声、电机反电动势干扰、传感器量化误差。如果不做滤波,阈值判断会像抽风一样乱跳。

我常用的去抖滤波有三种,各有各的适用场景:

算法 原理 优点 缺点
滑动平均滤波 取最近 N 个采样值的平均值 平滑效果好,实现简单 有延迟,N 越大延迟越大
中值滤波 取最近 N 个采样值的中位数 抗脉冲干扰能力强 计算量大,需要排序
一阶低通滤波 y[n] = α × x[n] + (1-α) × y[n-1] 延迟可控,计算量小 对高频噪声抑制有限

我个人最常用的是一阶低通滤波 + 中值滤波组合。先过中值滤波去掉尖峰脉冲,再用一阶低通平滑波形。α 值我一般取 0.1-0.3,响应速度和滤波效果比较平衡。

// 一阶低通滤波示例
#define ALPHA 0.2f

static float filtered_current = 0.0f;

float lowpass_filter(float raw_current) {
    filtered_current = ALPHA * raw_current + (1.0f - ALPHA) * filtered_current;
    return filtered_current;
}

// 中值滤波示例(窗口大小 5)
#define WINDOW_SIZE 5

float median_filter(float sample) {
    static float buffer[WINDOW_SIZE] = {0};
    static uint8_t index = 0;
    float temp[WINDOW_SIZE];
    
    buffer[index++] = sample;
    if (index >= WINDOW_SIZE) index = 0;
    
    // 拷贝并排序
    memcpy(temp, buffer, sizeof(temp));
    // 简单冒泡排序(实际项目用快速排序或选择排序)
    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];
}

踩坑提醒:我曾经在一个项目里只用滑动平均滤波,窗口设了 32 个点。结果堵转发生后,电流已经冲到 10A 了,滤波输出才爬到 6A,延迟了将近 300ms。等保护动作时,电机已经冒烟了。从那以后,我坚持滤波窗口不超过 8 个点,或者用一阶低通替代。

4. 三个参数的协同关系

阈值、时间窗口、滤波算法,不是各自为战。它们必须一起调,才能达到最佳效果。

我画了一张图,帮你理清它们的关系:

堵转检测三参数协同关系图 堵转检测决策 电流阈值 时间窗口 去抖滤波 阈值设高 → 灵敏度低 阈值设低 → 易误报 需配合负载特性 窗口长 → 响应慢 窗口短 → 易误报 需避开启动冲击 滤波强 → 延迟大 滤波弱 → 噪声多 需平衡响应与平滑 调参顺序建议 先定滤波 → 再调阈值 → 最后配时间窗口 每调一个参数,都要重新验证另外两个

调参顺序我建议这样走:

  1. 先定滤波参数:把电流信号处理干净,保证进入判断逻辑的数据是可靠的。
  2. 再调电流阈值:在滤波后的信号上,观察正常工况和堵转工况的电流差异,定出合理的阈值。
  3. 最后配时间窗口:用实际堵转测试和正常启停测试,反复调整确认时间和保护动作时间。

一个小技巧:我习惯在调试阶段把三个参数都做成可在线修改的变量,通过串口或调试接口实时调整。这样不用每次改参数都重新编译烧录,调试效率能提升好几倍。等参数调好了,再固化到代码里。

这三个参数调好了,堵转检测的灵敏度基本就稳了。剩下的就是根据具体应用场景做微调。记住一点:没有一套参数能通吃所有电机。每换一种负载,每换一个电机型号,都得重新走一遍调参流程。别偷懒,偷懒的代价就是现场出问题,然后半夜被电话叫醒。