2. 环境光干扰:环境光噪声来源分析、滤光片选型策略、动态阈值调整算法
环境光干扰,说白了就是光学触控系统最头疼的「背景噪音」。你想想看,一个会议室里,上午阳光从东边窗户照进来,下午西晒,晚上还有各种LED灯、荧光灯。这些光线的变化,都会让触控系统的信噪比忽高忽低。
我个人习惯把环境光干扰分成三类:直流分量(稳定的背景光)、交流分量(50Hz/100Hz的灯光频闪)、瞬态分量(人影走过、窗帘飘动)。这三类噪声的处理方式完全不同,咱们一个一个说。
2.1 环境光噪声来源分析
先看一张我整理的噪声来源分类图,这样你心里有个谱。
我在项目中遇到过最头疼的案例:一个客户把触控屏装在落地窗旁边。上午10点到下午2点,阳光直射,传感器信号直接饱和。后来我们加了遮光罩,但效果有限。最后是靠硬件滤光片+软件动态阈值双管齐下才搞定。
2.2 滤光片选型策略
滤光片选型,说白了就是给传感器戴一副「墨镜」。但这副墨镜不能随便戴,得看你的光源波长和传感器响应曲线。
我一般按以下步骤来选:
- 确定光源波长:红外触控常用850nm或940nm。940nm的好处是太阳光中该波段能量较低,抗干扰能力强。
- 匹配传感器峰值:滤光片的中心波长要跟LED的发射波长对齐,偏差控制在±10nm以内。
- 看半带宽(FWHM):带宽越窄,滤除杂光效果越好,但光通量也越低。我一般选30-50nm。
- 考虑入射角:大角度入射时,滤光片的中心波长会蓝移。这个坑我踩过——选了窄带滤光片,结果边缘区域信号弱了一半。
| 滤光片类型 | 中心波长 | 半带宽 | 适用场景 | 注意事项 |
|---|---|---|---|---|
| 窄带干涉滤光片 | 940nm | ±15nm | 强光环境、户外 | 入射角敏感,需垂直安装 |
| 宽带吸收滤光片 | 850nm | ±50nm | 室内、弱光环境 | 成本低,但滤除效果一般 |
| 双带通滤光片 | 850+940nm | ±20nm | 多光源系统 | 价格高,需定制 |
| 长波通滤光片 | 截止800nm | — | 可见光干扰严重 | 会引入部分红外杂光 |
2.3 动态阈值调整算法
硬件滤光片搞定了大部分直流干扰,但环境光还会缓慢变化——比如阴天转晴、灯光老化。这时候就需要动态阈值算法上场了。
我常用的算法有三种,各有优劣:
2.3.1 滑动窗口均值法
最简单,也最实用。维护一个长度为N的采样窗口,实时计算背景光均值,然后在这个均值上加一个偏移量作为触控阈值。
// 滑动窗口均值动态阈值
#define WINDOW_SIZE 100
uint16_t buffer[WINDOW_SIZE];
int index = 0;
uint32_t sum = 0;
uint16_t get_dynamic_threshold(uint16_t current_sample) {
// 移除旧值
sum -= buffer[index];
// 加入新值
buffer[index] = current_sample;
sum += current_sample;
index = (index + 1) % WINDOW_SIZE;
uint16_t mean = sum / WINDOW_SIZE;
// 阈值 = 背景均值 + 固定偏移量
return mean + OFFSET_VALUE;
}
嗯,这里要注意:窗口长度N的选择很关键。N太小,阈值跟着噪声乱跳;N太大,响应太慢。我一般取50-200,具体看采样率。采样率1kHz的话,N=100对应100ms的响应时间,够用了。
2.3.2 自适应偏移量法
固定偏移量有个问题:背景噪声大时容易误触,噪声小时又不够灵敏。我后来改用基于噪声标准差的自适应偏移量。
// 自适应偏移量动态阈值
uint16_t get_adaptive_threshold(uint16_t* buffer, int len) {
uint32_t sum = 0;
for(int i=0; i<len; i++) sum += buffer[i];
uint16_t mean = sum / len;
// 计算标准差
uint32_t var = 0;
for(int i=0; i<len; i++) {
int32_t diff = buffer[i] - mean;
var += diff * diff;
}
uint16_t stddev = sqrt(var / len);
// 阈值 = 均值 + K * 标准差
return mean + K_FACTOR * stddev;
}
K值我一般取3-5。K=3时,理论上99.7%的噪声不会触发误报。但如果你对灵敏度要求高,可以降到2.5。这个我在一个教育平板的项目里调过,最终K=3.2效果最好。
2.3.3 双阈值滞回法
这个技巧是我从按键消抖里借鉴过来的。设置两个阈值:高阈值(触控按下)和低阈值(触控释放)。中间有个滞回区,能有效防止临界状态下的抖动。
| 状态 | 触发条件 | 说明 |
|---|---|---|
| 空闲 → 触控 | 信号 > 高阈值 | 高阈值 = 背景均值 + 偏移量A |
| 触控 → 空闲 | 信号 < 低阈值 | 低阈值 = 背景均值 + 偏移量B(B < A) |
| 滞回区 | 低阈值 < 信号 < 高阈值 | 保持当前状态不变 |
最后说一句:算法再好,也架不住硬件设计有硬伤。如果你发现动态阈值怎么调都不管用,回头检查一下传感器有没有饱和、滤光片有没有装反、光源有没有衰减。这些基础问题不解决,算法就是空中楼阁。