13、TSP噪声抑制:共模噪声、差模噪声、滤波算法
触摸屏的噪声问题,说白了就是信号里混进了不该有的东西。我做驱动这么多年,遇到最多的Bug就是噪声引起的。有时候明明手指没动,坐标却在那跳来跳去,用户一投诉,老板就来找我喝茶。
嗯,今天咱们就把噪声这事彻底讲清楚。先搞清楚噪声从哪来,再想办法把它滤掉。
13.1 噪声的分类:共模与差模
触摸屏的噪声,按传输方式可以分为两类:共模噪声和差模噪声。这两兄弟长得像,但处理方式完全不同。
| 类型 | 定义 | 典型来源 | 影响 |
|---|---|---|---|
| 共模噪声 | 两根信号线上幅度相同、相位相同的噪声 | 电源纹波、地弹、充电器干扰 | 导致整屏偏移、灵敏度下降 |
| 差模噪声 | 两根信号线上幅度相同、相位相反的噪声 | LCD耦合、射频干扰、触摸人体引入 | 导致坐标抖动、鬼点 |
我举个例子你就明白了。共模噪声就像两个人同时被推了一下,方向一样,所以他们的相对位置没变。差模噪声呢,就像两个人面对面站着,一个人被往前推,另一个被往后推,距离一下就拉开了。
关键点:共模噪声影响的是整体基准,差模噪声影响的是差分信号。触摸屏的检测原理本身就是基于差分电容变化,所以差模噪声更致命。
13.2 共模噪声的抑制方法
共模噪声的抑制,我个人的习惯是从源头和传输路径两方面下手。
13.2.1 硬件层面
- 差分走线:TX和RX线尽量平行、等长,这样共模噪声在两端产生的电压一致,可以被后级电路抵消。
- 共模扼流圈:在FPC接口处加一个小磁珠或共模滤波器。我在项目里用过0603封装的共模扼流圈,效果立竿见影。
- 电源去耦:触摸屏的AVDD供电一定要干净。我建议在电源入口放一个10μF+0.1μF的组合电容。
13.2.2 软件层面
- 基准校准:每次上电后做一次无触摸时的基准扫描,把共模偏移量记录下来,后续扫描时减去这个基准值。
- 动态基线跟踪:环境变化时(比如插了充电器),基准会漂移。我写过一段代码,每隔100ms检测一次无触摸区域的均值,动态更新基准。
避坑指南:我曾经在一个项目里发现,插上充电器后触摸完全失灵。排查了两天,最后发现是充电器的共模噪声通过地线耦合到了触摸屏。解决方案很简单——在充电器地和触摸屏地之间加一个1MΩ电阻+0.1μF电容的隔离网络。
13.3 差模噪声的抑制方法
差模噪声比共模噪声难搞。为什么?因为它直接叠加在有用信号上,幅度可能比信号本身还大。
13.3.1 硬件屏蔽
- LCD与TSP之间的屏蔽层:现在的手机基本都在LCD和触摸屏之间加了一层ITO屏蔽层,接地处理。没有这层的话,LCD的刷新噪声会直接耦合到触摸屏上。
- 走线间距:TX和RX之间的间距不要太小,我一般控制在0.1mm以上,减少串扰。
13.3.2 软件滤波
软件滤波是差模噪声抑制的主力。常用的算法有下面几种:
- 均值滤波:连续采N个点,取平均值。简单粗暴,但会引入延迟。
- 中值滤波:采N个点,排序后取中间值。对脉冲噪声效果极好。
- 卡尔曼滤波:适合运动轨迹预测,计算量稍大,但效果最好。
我的经验:实际项目中,我通常把均值滤波和中值滤波组合使用。先做一次3点中值滤波去掉毛刺,再做一次5点均值滤波平滑轨迹。这个组合在延迟和效果之间取得了很好的平衡。
13.4 滤波算法的代码实现
下面是我在一个量产项目里用过的滤波代码,你可以直接参考:
/* 中值滤波:取3个点的中值 */
int median_filter(int x0, int x1, int x2) {
int tmp;
if (x0 > x1) { tmp = x0; x0 = x1; x1 = tmp; }
if (x1 > x2) { tmp = x1; x1 = x2; x2 = tmp; }
if (x0 > x1) { tmp = x0; x0 = x1; x1 = tmp; }
return x1; // 中间值
}
/* 滑动均值滤波:窗口大小为N */
#define N 5
int buf[N];
int idx = 0;
int sum = 0;
int moving_average(int new_val) {
sum -= buf[idx];
buf[idx] = new_val;
sum += buf[idx];
idx = (idx + 1) % N;
return sum / N;
}
/* 组合滤波:先中值,再均值 */
int combo_filter(int raw_x, int raw_y) {
static int x_buf[3], y_buf[3];
static int x_idx = 0, y_idx = 0;
x_buf[x_idx] = raw_x;
y_buf[y_idx] = raw_y;
x_idx = (x_idx + 1) % 3;
y_idx = (y_idx + 1) % 3;
int x_med = median_filter(x_buf[0], x_buf[1], x_buf[2]);
int y_med = median_filter(y_buf[0], y_buf[1], y_buf[2]);
return moving_average(x_med); // 这里只演示X轴,Y轴同理
}
注意:滤波窗口大小N不是越大越好。N越大,延迟越大。手指快速滑动时,过大的窗口会导致轨迹严重滞后。我一般把N控制在3~7之间,具体值需要根据触摸屏的扫描频率来调。
13.5 噪声抑制的整体流程
下面这张图展示了从原始数据到最终坐标的完整处理链路。你想想看,噪声在每个环节都可能混进来,所以我们要层层设防。
13.6 实际项目中的避坑经验
最后分享几个我在项目中踩过的坑,希望能帮你少走弯路。
坑1:滤波算法导致触摸延迟
我曾经在一个项目里用了10点均值滤波,结果用户反馈打字时感觉「黏手」。后来我把窗口降到5点,同时配合预测算法,才解决了问题。记住:滤波不是越强越好,用户体验才是第一位的。
坑2:充电器噪声的诡异表现
有一次客户反馈,用某品牌充电器时触摸屏偶尔会跳点。我排查了很久,发现是充电器内部的地线和触摸屏地线之间存在共模电压差。解决方案是在触摸屏的FPC上增加一个共模扼流圈,问题解决。
坑3:LCD噪声的频域特性
LCD的刷新频率通常是60Hz或120Hz,这个频率的谐波可能会落在触摸屏的扫描频段内。我建议在驱动初始化时,先扫描一遍所有通道的噪声频谱,然后避开噪声大的频段来配置触摸屏的工作频率。这个方法我在三个项目里用过,效果都很稳定。
好了,关于TSP噪声抑制的内容就这些。噪声问题虽然烦人,但只要掌握了共模和差模的区别,再配合合适的滤波算法,大部分问题都能解决。嗯,多动手调试,慢慢就有感觉了。
公众号:蓝海资料掘金营,微信deep3321