3. 阈值设定策略:静态阈值、动态阈值、自适应阈值算法设计

好,咱们接着聊压力感应的核心——阈值怎么设。

说实话,很多工程师一上来就拍脑袋定个阈值,比如「刷牙压力超过200克就报警」。结果呢?用户刷着刷着,牙刷动不动就震,烦得不行。或者反过来,阈值设太高,牙龈都刷出血了,保护机制还没触发。

阈值设定,说白了就是三个流派:静态阈值动态阈值自适应阈值。我一个个讲,每个都有坑,也有解法。

3.1 静态阈值:简单粗暴,但够用吗?

静态阈值,就是固定一个数值。比如压力超过250克,立刻降速+亮红灯。

优点很明显:实现简单,代码就几行,MCU几乎不占资源。

缺点呢?我踩过坑。有一次做项目,用户反馈说「我刷左边牙齿没问题,刷右边就老报警」。查了半天,发现是用户习惯用右手,刷右侧时手腕角度不对,压力传感器读数偏大。静态阈值没法处理这种个体差异。

静态阈值适合什么场景?

  • 入门级产品,成本敏感,MCU性能弱
  • 标准测试环境,比如实验室验证
  • 安全底线,作为最高保护阈值

关键点:静态阈值要留余量。我一般取「安全压力上限」的70%作为报警阈值。比如安全上限是300克,阈值设在210克左右。为什么?因为传感器有温漂,电池电压变化也会影响读数。

3.2 动态阈值:跟着环境变

动态阈值,就是阈值不是死的,它会根据某些参数自动调整。

举个例子:

  • 根据电池电压调整:电池快没电时,电机驱动力下降,同样的压力传感器读数会偏小。这时候阈值要跟着降,否则保护机制会失效。
  • 根据刷头磨损调整:刷毛用久了变软,同样的按压力度,传感器读数会变小。阈值要动态补偿。
  • 根据用户年龄调整:儿童和成人的牙龈耐受度不同,阈值可以分档。

我记得有个项目,客户要求「牙刷能识别刷头用了多久」。我们就在固件里加了个计数器,每刷一次加1,累计到一定次数后,阈值自动下调10%。效果还不错,用户反馈说「刷到后期感觉保护更灵敏了」。

我的习惯:动态阈值不要调得太频繁。每10次刷牙调整一次就够了,或者每次开机时校准一次。实时调整容易引入噪声,反而让用户觉得牙刷「神经质」。

3.3 自适应阈值:真正的智能

自适应阈值,是动态阈值的升级版。它不光跟着环境变,还跟着用户的使用习惯变。

算法思路是这样的:

  1. 学习阶段:前10次刷牙,记录用户的平均压力值、峰值压力、压力波动范围
  2. 建模阶段:建立用户压力画像。比如「这个用户习惯轻刷,平均压力150克,偶尔到200克」
  3. 调整阶段:根据画像,动态设定阈值。比如取「平均压力+1.5倍标准差」作为报警阈值
  4. 持续更新:每刷一次,更新一次画像,阈值慢慢收敛到最适合用户的值

代码实现大概长这样:

// 自适应阈值算法 - 简化版
typedef struct {
    float avg_pressure;      // 平均压力
    float std_dev;           // 标准差
    uint8_t sample_count;    // 采样次数
    float threshold;         // 当前阈值
} AdaptiveThreshold;

void update_threshold(AdaptiveThreshold *at, float current_pressure) {
    // 更新平均值(滑动平均)
    at->avg_pressure = (at->avg_pressure * at->sample_count + current_pressure) 
                       / (at->sample_count + 1);
    
    // 更新标准差(简化计算)
    float diff = current_pressure - at->avg_pressure;
    at->std_dev = sqrt((at->std_dev * at->std_dev * at->sample_count + diff * diff) 
                       / (at->sample_count + 1));
    
    at->sample_count++;
    
    // 阈值 = 平均压力 + 1.5倍标准差
    // 为什么要1.5倍?经验值。太小容易误报,太大保护失效
    at->threshold = at->avg_pressure + 1.5 * at->std_dev;
    
    // 限制阈值范围,防止异常值
    if (at->threshold < 100) at->threshold = 100;
    if (at->threshold > 400) at->threshold = 400;
}

我曾经踩过的坑:自适应算法在用户更换刷头后,需要重新学习。有一次我忘了加「刷头更换检测」,结果用户换了新刷头,阈值还是旧的,保护机制完全乱套。后来我加了个「刷头计数器」,换刷头后自动重置学习数据。

3.4 三种策略怎么选?

我一般这样建议:

策略 适用场景 MCU资源 用户体验
静态阈值 入门级、成本敏感 极低 一般,可能误报
动态阈值 中端产品、有环境补偿需求 较好,适应环境变化
自适应阈值 高端产品、个性化体验 中等 优秀,越用越准

你想想看,如果做的是99元的入门牙刷,静态阈值就够了。但如果是399元以上的旗舰款,不上自适应算法,用户会觉得「这牙刷不够聪明」。

嗯,这里要注意:自适应算法不是万能的。如果用户刷牙习惯很差(比如每次都用死力刷),算法会「学坏」,阈值越调越高,最后保护机制形同虚设。所以一定要加绝对安全上限,比如超过350克无条件报警。

我个人习惯是「三层保护」:

  • 第一层:自适应阈值,日常使用
  • 第二层:动态阈值,补偿环境变化
  • 第三层:静态阈值,作为最后的安全底线

三层叠加,既保证了用户体验,又不会出安全事故。说白了,就是「让用户感觉不到保护的存在,但保护一直在」。

一个小技巧:自适应算法的学习速度要可调。我一般给用户留个「灵敏度」设置,分三档:快(5次学习)、中(10次)、慢(20次)。快档适合换刷头后快速适应,慢档适合习惯稳定的用户。

好了,阈值设定就聊到这儿。下一章咱们讲「压力感应的硬件选型与电路设计」,到时候我会聊聊怎么选传感器、怎么布板才能抗干扰。这些东西,光看datasheet是学不到的。