4. 快速瞬变光抑制:针对频闪灯、阳光直射的滤波策略
频闪灯和阳光直射,这两个东西是触控工程师的噩梦。我做过一个项目,客户在展厅用射灯一照,整个触摸面板直接“抽风”——乱跳、误触、死机,全来了。
为什么会这样?因为光电传感器对光的变化太敏感了。频闪灯每秒闪烁几十到几百次,阳光直射带来的是直流分量饱和。这两种干扰,用常规的均值滤波根本扛不住。
这一章,我们就专门聊怎么对付它们。
4.1 干扰的本质:光噪声的时频特征
先搞清楚敌人长什么样。
| 干扰类型 | 频率范围 | 幅度特征 | 对触控的影响 |
|---|---|---|---|
| 频闪灯(LED/荧光灯) | 50 Hz – 2 kHz | 周期性脉冲,占空比低 | 触发虚假触摸,信号抖动 |
| 阳光直射 | DC – 0.1 Hz | 缓慢变化,幅度极大 | 基线漂移,ADC 饱和 |
| 混合光照 | 全频段 | 叠加噪声 | 信噪比急剧下降 |
频闪灯的问题在于它的上升沿极陡。传感器在光脉冲到来的一瞬间,输出信号会跳变几十甚至上百个 LSB。如果你用滑动平均,窗口长度不够,这个跳变就会直接穿透滤波器,被误判为触摸。
阳光直射则是另一种麻烦。它不会让你误触,但会让你的基线一直往上飘。飘到 ADC 上限,传感器就“瞎”了。
4.2 频闪抑制:中值滤波 + 自适应窗口
对付频闪,我个人最推荐的是中值滤波。不是均值,是中值。
为什么?因为频闪脉冲是稀疏的。在一个窗口里,正常信号占大多数,脉冲只是少数几个点。均值会把脉冲的误差“平均”到所有点上,而中值直接扔掉异常值。
核心思路:用中值滤波剔除光脉冲尖峰,保留真实的触摸信号。
我习惯的窗口长度是 5 到 9 个采样点。太短了抑制效果差,太长了延迟大。具体选多少,要看你的扫描频率和频闪灯的基频。
// 快速中值滤波示例(窗口长度 5)
uint16_t median_filter_5(uint16_t *buf) {
uint16_t a = buf[0], b = buf[1], c = buf[2], d = buf[3], e = buf[4];
uint16_t tmp;
// 排序网络,5个元素比较9次
if (a > b) { tmp = a; a = b; b = tmp; }
if (d > e) { tmp = d; d = e; e = tmp; }
if (a > c) { tmp = a; a = c; c = tmp; }
if (b > c) { tmp = b; b = c; c = tmp; }
if (a > d) { tmp = a; a = d; d = tmp; }
if (c > d) { tmp = c; c = d; d = tmp; }
if (b > e) { tmp = b; b = e; e = tmp; }
if (b > c) { tmp = b; b = c; c = tmp; }
if (d > e) { tmp = d; d = e; e = tmp; }
return c; // 中值
}
嗯,这里要注意:中值滤波的延迟是窗口长度的一半。如果你的触摸响应要求 10 ms 以内,窗口对应的采样时间不能超过 20 ms。
小技巧:如果频闪频率是 100 Hz(周期 10 ms),你的采样周期是 1 ms,那么窗口长度 5 刚好覆盖半个周期,能有效抑制脉冲。
4.3 阳光直射抑制:高通滤波 + 基线跟踪
阳光直射是低频干扰。说白了,它和触摸信号在频域上是分开的。触摸是快速变化(手指按下到抬起通常 50-200 ms),阳光是缓慢漂移(秒级甚至分钟级)。
所以,一个简单的一阶高通滤波器就能把阳光干扰滤掉。
// 一阶高通滤波器,用于抑制阳光直射
// alpha 通常取 0.95 ~ 0.99
uint16_t highpass_filter(uint16_t raw, uint16_t *prev_out, float alpha) {
float out = alpha * (*prev_out) + alpha * (raw - *prev_out);
*prev_out = (uint16_t)out;
return raw - (uint16_t)out; // 高通输出 = 原始值 - 低通值
}
这个滤波器的截止频率是:
f_c = (1 - alpha) / (2 * π * T_s)
假设采样周期 T_s = 1 ms,alpha = 0.99,那么 f_c ≈ 1.6 Hz。也就是说,低于 1.6 Hz 的缓慢变化会被抑制,而手指触摸(通常 5-10 Hz)基本不受影响。
我曾经踩过一个坑:alpha 设得太接近 1(比如 0.999),滤波器响应太慢。阳光突然照过来时,基线要好几秒才能稳定。那段时间里,触摸完全没法用。后来我把 alpha 改成动态调整——检测到基线快速漂移时,临时降低 alpha 值,加快收敛。
4.4 综合策略:两级级联滤波架构
实际产品中,频闪和阳光往往是同时存在的。我建议用两级滤波:
- 第一级:中值滤波 — 剔除频闪脉冲尖峰
- 第二级:高通滤波 — 抑制阳光直射导致的基线漂移
顺序不能反。如果先高通再中值,高通滤波器会把脉冲尖峰“展宽”,变成一段持续的高电平,中值滤波反而不好处理。
经验值参考:
- 中值窗口长度:5(采样率 1 kHz 时,延迟 2.5 ms)
- 高通 alpha:0.97 ~ 0.99(截止频率 1.6 ~ 4.8 Hz)
- 总延迟:约 3-5 ms,不影响触摸手感
4.5 知识结构图:快速瞬变光抑制策略
下面这张图展示了整个滤波策略的流程和决策逻辑。
4.6 实战避坑指南
讲几个我实际项目中遇到的坑,你们以后碰到了能少走弯路。
坑一:中值滤波导致触摸灵敏度下降
有一次我发现,加了中值滤波后,轻触(力度很轻的那种)经常识别不到。排查了半天,发现是窗口长度太大(设了 15),把真实的触摸信号也当成噪声滤掉了。后来改成自适应窗口——检测到信号变化率大时缩小窗口,平稳时放大窗口。
坑二:高通滤波器引入相位延迟
高通滤波器会改变信号的相位。如果你同时用多个传感器做差分检测,相位不一致会导致误判。我的解决办法是:所有通道使用相同的滤波器参数,并且在软件里做同步采样。
坑三:阳光直射下的 ADC 饱和
这个最要命。阳光太强时,光电传感器的输出直接顶到 ADC 上限,滤波算法再牛也没用。硬件上必须加自动增益控制(AGC)或者动态偏置调整。软件上,我习惯在滤波前先做一次饱和检测——如果连续 N 个采样点都接近 ADC 最大值,直接触发增益切换。
4.7 小结
快速瞬变光抑制,说白了就是两招:中值滤波打脉冲,高通滤波压漂移。顺序别搞反,参数别设死,留点自适应空间。
你想想看,如果能把频闪和阳光都搞定,你的触控产品在户外、展厅、舞台这些场景下,基本就稳了。