4. 传感器校准:光照、温湿度、霍尔的数据校准与滤波

传感器数据不准,智能窗帘就是个摆设。光照传感器报阴天,窗帘却关上了;温湿度飘得离谱,电机反而开始保护性停机。这些坑,我踩过不少。

今天咱们就聊聊三种核心传感器的校准与滤波。说白了,就是让传感器说真话。

核心原则:传感器原始数据 ≠ 真实物理量。校准解决系统性偏差,滤波消除随机噪声。两者缺一不可。

4.1 光照传感器校准

光照传感器最容易出问题的地方,是安装位置和量程匹配。我见过有人把传感器装在窗帘盒内侧,结果永远读不到直射光。

4.1.1 两点校准法

这是最实用的方法。你只需要两个已知照度值:一个暗场(比如0 lux),一个标准光源(比如1000 lux)。

// 光照传感器两点校准示例
float raw_dark = analogRead(LIGHT_SENSOR_PIN);  // 遮光时读数
float raw_light = analogRead(LIGHT_SENSOR_PIN);  // 标准光源下读数

float scale = 1000.0 / (raw_light - raw_dark);
float offset = -raw_dark * scale;

// 校准后的照度值
float lux = raw_value * scale + offset;

我个人习惯在安装时做一次现场校准。拿一个手持照度计,对比五个点,取平均值。嗯,这样能消除传感器个体差异。

小技巧:如果传感器输出非线性(比如某些模拟光敏电阻),可以分段线性插值。每200 lux一个区间,精度能到±5%。

4.1.2 滤波策略

光照变化快,但窗帘动作慢。你不需要每毫秒都响应。

  • 移动平均滤波:取最近10次采样平均值,适合平稳光照场景。
  • 限幅滤波:相邻两次差值超过50 lux则丢弃,防止闪电或手电筒误触发。
  • 加权递推平均:新数据权重0.3,历史数据权重0.7,兼顾响应速度和稳定性。

我曾经遇到一个项目,客户说窗帘在阴天乱动。查了半天,是窗外树叶晃动造成光照剧烈波动。加上限幅滤波后,问题解决。

4.2 温湿度传感器校准

温湿度传感器的问题通常是漂移和交叉敏感。温度不准,湿度就别想准。

4.2.1 温度补偿

大多数数字温湿度传感器(如SHT30、DHT22)内部有温度补偿。但如果你用模拟输出型,就得自己做。

// 温度补偿湿度示例
float temp = read_temperature();  // 当前温度
float raw_humidity = read_humidity_raw();

// 标准补偿公式(以25°C为基准)
float compensated_humidity = raw_humidity / (1.0 + 0.0012 * (temp - 25.0));

为什么是0.0012?这是典型高分子湿敏电容的温度系数。不同传感器略有差异,建议查数据手册。

4.2.2 湿度校准的坑

湿度传感器在极端环境下容易饱和。我遇到过在浴室安装的案例,湿度长期90%以上,传感器读数直接飘到105%。

注意:湿度超过95%时,传感器可能进入非线性区。此时数据只能做定性参考,不能用于精确控制。建议增加超限报警。

4.2.3 滤波方法

温湿度变化慢,但噪声来源多(比如电机散热、人体靠近)。

  • 一阶低通滤波:Y(n) = α * X(n) + (1-α) * Y(n-1),α取0.1~0.3。
  • 中值滤波:取最近5次采样的中间值,能有效去除脉冲干扰。
  • 滑动窗口滤波:窗口大小根据环境变化速度调整。室内取30秒,室外取10秒。

我个人偏爱一阶低通滤波,计算量小,效果也够用。但要注意,α太小会让响应变慢,窗帘可能半天不反应。

4.3 霍尔传感器校准

霍尔传感器用于检测窗帘位置和电机转速。它的校准核心是消除磁滞和安装偏差。

4.3.1 零点校准

霍尔传感器在无磁场时输出不一定是0。你需要记录无磁场时的基准值。

// 霍尔传感器零点校准
float hall_baseline = 0;
for (int i = 0; i < 100; i++) {
    hall_baseline += analogRead(HALL_PIN);
    delay(1);
}
hall_baseline /= 100;  // 取平均作为零点

// 实际使用时减去零点
float hall_value = analogRead(HALL_PIN) - hall_baseline;

4.3.2 磁滞补偿

霍尔传感器有磁滞效应——正向和反向经过同一位置时,输出值不同。这在窗帘限位检测中很要命。

方向 理论位置 实际读数 偏差
正向(开) 100% 98% -2%
反向(关) 0% 2% +2%

怎么解决?我建议做双向校准。记录正向和反向的阈值,分别用于开和关的判断。

经验值:大多数线性霍尔传感器的磁滞在1%~3%之间。如果你用的传感器偏差超过5%,建议更换。

4.3.3 转速测量滤波

霍尔传感器测转速时,脉冲间隔不稳定。直接计算会抖动。

// 转速测量:脉冲间隔法 + 中值滤波
unsigned long pulse_times[5];  // 存储最近5次脉冲时间
int index = 0;

void pulse_interrupt() {
    pulse_times[index] = micros();
    index = (index + 1) % 5;
}

float get_rpm() {
    // 取中间3个间隔的平均值
    unsigned long intervals[4];
    for (int i = 0; i < 4; i++) {
        intervals[i] = pulse_times[(index + i) % 5] - 
                       pulse_times[(index + i + 1) % 5];
    }
    // 排序后取中间两个
    // ... 排序代码省略
    float avg_interval = (intervals[1] + intervals[2]) / 2.0;
    return 60000000.0 / avg_interval;  // 微秒转RPM
}

你想想看,如果直接用单次脉冲间隔,电机稍微抖一下,转速就跳变。中值滤波能有效剔除异常脉冲。

4.4 传感器数据融合策略

单个传感器总有局限。我习惯把光照、温湿度、霍尔数据做简单融合,提高可靠性。

传感器数据融合流程图 光照传感器 温湿度传感器 霍尔传感器 两点校准 温度补偿 零点+磁滞 限幅+移动平均 一阶低通滤波 中值滤波 数据融合 → 窗帘控制决策 校准消除系统偏差,滤波消除随机噪声,融合提高决策可靠性

举个例子:光照传感器报暗,但霍尔传感器显示窗帘已经全开。这时候如果直接关窗帘,就错了。融合策略会判断:光照数据是否在合理范围?温湿度是否正常?霍尔位置是否可信?

我的融合原则:至少两个传感器一致才执行动作。单一传感器触发时,先做二次确认,延迟200ms再判断。

4.5 调试与验证

校准完怎么知道对不对?我习惯用串口打印原始值和校准值对比。

// 调试输出示例
Serial.print("Raw: "); Serial.print(raw_lux);
Serial.print(" | Cal: "); Serial.print(cal_lux);
Serial.print(" | Filtered: "); Serial.println(filtered_lux);

观察几分钟,看数据是否稳定。如果校准值还在跳,说明滤波参数需要调整。

嗯,这里要注意:不要在生产环境直接改参数。先在测试环境验证,确认没问题再部署。

重要:每次更换传感器硬件后,必须重新校准。不同批次的传感器,零点偏移可能差10%以上。

好了,传感器校准这块就聊到这儿。记住:校准是基础,滤波是保障,融合是升华。把这三步做好,你的智能窗帘就不会犯低级错误。