avatar

蜗牛札记

记录技术、生活与一点点折腾

  • 首页
  • PetBoxX
  • NAS 折腾
  • VPS & 网络
  • 工具软件
  • Linux 运维
  • 关于
主页 PetBoxX 恒温区风扇控制的演变:固定 PWM、hold_ready 重置,与动态微调
文章

PetBoxX 恒温区风扇控制的演变:固定 PWM、hold_ready 重置,与动态微调

发表于 最近 更新于 最近
作者 Snailszzy
18~23 分钟 阅读

本文记录 PetBoxX 孵化箱固件在"恒温维持阶段"风扇控制策略的三次演变,从最初的固定 PWM、引入 hold_ready 累计判断,到最终的按风扇资质归一化的动态微调。最后讨论哪种方案在理论和实测数据上更优。


背景:PTC + 风扇的控温物理模型

PetBoxX 使用 PTC(正温度系数)陶瓷加热片作为热源,配合顶部直流风扇做强制对流。

PTC 有一个关键特性:自限温。当 PTC 温度升高,其电阻急剧上升,发热功率自动下降。这意味着在稳定工况下,PTC 不需要外部功率控制——只要供电,它会自己找到平衡温度。

箱内实际温度由两个量共同决定:

温度上升速率 ∝ PTC 发热功率 - 风扇散热功率
  • PTC 功率:由 TRIAC 控制(过零点触发延迟),近目标时已降至较低水平
  • 风扇功率:由 PWM 占空比控制,影响对流强度(热量从加热片到传感器的传输速率)

因此,风扇速度决定了热量分配效率,而不只是"散热"。风速太低,热空气不能充分循环,传感器附近可能偏冷;风速太高,PTC 产生的热量被快速带走,反而降温。


方案一:固定 PWM(hold_lock = true)

实现

bool hold_ready = g_fan_hold_lock || (hold_elapsed_s >= g_fan_hold_dwell_s);

// hold_ready 时:
stage_pct_f = (float)g_fan_hold_pct;  // 固定不变

将 g_fan_hold_lock = true 后,hold_ready 永远为真,风扇 PWM 锁定在由风扇资质测试(fan_qualify)确定的最优 hold_pct 值,不随温度误差变化。

测试观察

实测开启 hold_lock 后,RPM 读数仍在 1106~1135 之间来回跳动。初看像是 PWM 在变,但深入分析后确认这是FG 脉冲量化误差,而不是实际转速变化:

FG:2 脉冲/转,采样窗口约 1034ms
RPM 分辨率 = 60,000,000 / (1,034,483 × 2) ≈ 29 RPM/步

风扇实际 PWM 完全固定,观测到的 ±30 RPM 抖动来自整数计数量化,无法消除(除非拉长采样窗口或做 N 次平均)。

优点

  • 实现最简单,无计算开销
  • 消除了控制算法本身引入的 PWM 跳变
  • 对于"找到了正确的 hold_pct"的场景,理论上最优

缺点

  • hold_pct 是 fan_qualify 在特定工况下测定的,换了环境(室温、负载、箱体差异)后可能不再是最优值
  • 完全开环:温度偏移 0.3°C 后,控制器不会做任何响应(只靠 TRIAC 控制 PTC 功率)
  • 依赖 TRIAC 的精度和一致性,量化粗糙(50Hz 交流,延迟步长约 200μs)

方案二:hold_ready 累计判断与重置

实现

// 每个控制周期(约 dt_s ≈ 200ms)
if (err_mag_c <= g_fan_hold_err_c) {
    hold_elapsed_s += dt_s;   // 误差在区间内,累计时间
} else {
    hold_elapsed_s = 0.0f;    // 误差超出区间,重置
}
bool hold_ready = (hold_elapsed_s >= g_fan_hold_dwell_s);

hold_ready 不是立即触发的——需要温度在 ±hold_err_c(默认 ±0.3°C)区间内持续稳定 hold_dwell_s(默认若干秒)之后,才认为进入恒温状态,切换到 hold_pct。

在 hold_ready 尚未触发时(near_wait 阶段),使用线性插值:

// 按误差比例从 0 爬升到 hold_pct
stage_pct_f = lerp_clamp(err_pos_c, 0.0f, g_fan_hold_err_c,
                          0.0f, (float)g_fan_hold_pct);

这样做的意图

避免箱温刚进入目标区间就立刻切到 hold 档,给系统一段"稳定确认期",防止瞬时超调误触发。

问题:smooth_floor 的干扰

引入 hold_ready 机制后,发现一个副作用:在 near_wait 阶段,smooth_floor 保护逻辑会将风扇下限抬升到 near_pct:

if (!g_fan_hold_lock && err_pos_c >= FAN_LINEAR_ERR_C) {
    float smooth_floor = lerp_clamp(err_pos_c, ...);
    fan_floor = fmaxf(fan_floor, smooth_floor);
}

当温度在 hold_err_c 边界附近轻微震荡时,hold_elapsed_s 反复重置,风扇在 lerp 输出 和 smooth_floor 覆盖 之间跳动,产生明显的 PWM 抖动。这反而比固定 PWM 更差。


方案三:按风扇资质归一化的动态微调(当前实现)

核心思路

进入 hold_ready 状态后,不再固定在 hold_pct,而是根据当前温度误差与资质测试余量做小幅调整:

const float ratio = 0.3f;
float t = err_c / g_fan_hold_err_c;   // 归一化误差,[-1, +1]

float micro;
if (t > 0.0f) {
    // 偏冷:向上借用余量,上限 = near_pct - hold_pct
    float up_headroom = (float)(g_fan_near_pct - g_fan_hold_pct);
    micro = fminf(t, 1.0f) * up_headroom * ratio;
} else {
    // 偏热:向下让出余量,下限 = hold_pct - heat_min_pct
    float dn_headroom = (float)(g_fan_hold_pct - g_fan_heat_min_pct);
    micro = fmaxf(t, -1.0f) * dn_headroom * ratio;
}
stage_pct_f = g_fan_hold_pct + micro;

为什么归一化到 fan_qualify 余量

不同风扇的 hold_pct、near_pct、heat_min_pct 由 fan_qualify 测定,反映该风扇在当前箱体的实际特性。若用固定的 ±3% 微调,对于 hold_pct = 15% 的强风扇和 hold_pct = 35% 的弱风扇效果截然不同。

归一化后,ratio = 0.3 的含义是:在 hold_err_c 边界处,最多使用 30% 的余量空间,对所有风扇都有同等的相对影响力。

举例:

风扇档位hold_pctnear_pctup_headroom最大向上微调 (ratio=0.3)
弱风扇35%50%15%+4.5%
强风扇15%28%13%+3.9%
典型M箱22%32%10%+3.0%

微调量和余量成正比,不会让弱风扇突然跳到一个可能过热的区间。


三方案对比

维度固定 PWMhold_ready 累计重置动态微调(当前)
实现复杂度最低中中
控制连续性完全开环阶梯切换连续小步调整
温度偏移响应无(靠 TRIAC)无(hold 期间)有(±hold_err_c 范围内)
跨风扇适配性依赖 fan_qualify 精度同左归一化,自适应
smooth_floor 冲突无(hold_lock 跳过)有(边界抖动)无(hold_ready 后不触发)
RPM 抖动来源仅 FG 量化(不可消除)算法跳变 + FG 量化温误差变化 + FG 量化

理论分析:哪种最好?

PTC 系统的开环稳定性

PTC 加热片本身已经提供了一定的自稳能力:靠近目标温度时功率自动下降。在小箱体、低热容量的孵化场景中,这种自稳能力相当强。

理论上,对于一个热容量小、PTC 自限温准确的系统,固定 PWM 已经足够。 原因:

  1. 热时间常数长(箱体热容 > 几分钟),风扇的小幅变化对温度的影响需要等待才能显现
  2. TRIAC 控制的 PTC 功率本身就是主要调节手段,风扇是辅助
  3. 动态微调的 ±3~5% PWM 变化,在一个几分钟热时间常数的系统里,几乎是噪声量级

动态微调的实际价值

动态微调的价值不在于"控温精度提高了多少",而在于:

  1. 应对环境变化:室温从 20°C 突变到 30°C,固定 hold_pct 下温度会漂移;动态微调在漂移超过 hold_err_c 时开始响应
  2. 消除算法抖动:比 hold_ready 的阶梯切换更平滑,不会因边界震荡产生 PWM 跳变
  3. 无需 hold_lock:不依赖特殊的调试开关,日常运行就是动态的,但微调幅度被限制在 30% 余量以内,不激进

需要什么数据才能下结论

目前没有做过受控对比实验。要验证三方案的实际效果,需要:

  1. 同一台设备、同一环境,分别运行三种策略各 2 小时,记录 1s 精度温度曲线
  2. 计算各策略的温度标准差(σ)和最大偏差(peak-to-peak)
  3. 在室温变化(如开空调、关门)等扰动下重复上述测试

初步预期:

  • 无扰动、稳定室温:三者 σ 相近(均 < 0.2°C),固定 PWM 最平稳
  • 有环境扰动:动态微调能更快响应,σ 略小
  • 风扇老化/磨损导致 hold_pct 漂移:动态微调最鲁棒

当前策略的局限

动态微调目前还有两个已知局限:

  1. 只在 hold_err_c 区间内微调(默认 ±0.3°C),超出区间就回到 near/fast 阶段,微调不连续
  2. 没有积分项:对持续的温度偏置(steady-state offset),微调只能补偿到 ratio × headroom,无法完全消除

如果未来要进一步提升,下一步可以考虑在 hold 区间引入一个轻量积分累加器,对超过 30s 的持续偏置做额外补偿。但这需要更谨慎的抗积分饱和设计,不在本次讨论范围内。


小结

固定 PWM动态微调(当前)
最优场景室温恒定、fan_qualify 准确、不需要自适应有环境扰动、多台设备风扇特性不一致
主要风险环境变化时无响应过于激进的 ratio 可能加剧抖动
现状可作为调试/基准模式(hold_lock=true)默认运行模式

两者并不互斥——hold_lock 开关保留了固定 PWM 的调试路径,在需要隔离变量测试时可以随时启用。

PetBoxX
PetBoxX
许可协议:  CC BY 4.0
分享

相关文章

5月 14, 2026

PetBoxX 恒温区风扇控制的演变:固定 PWM、hold_ready 重置,与动态微调

本文记录 PetBoxX 孵化箱固件在"恒温维持阶段"风扇控制策略的三次演变,从最初的固定 PWM、引入 hold_ready 累计判断,到最终的按风扇资质归一化的动态微调。最后讨论哪种方案在理论和实测数据上更优。 背景:PTC + 风扇的控温物理模型 PetBoxX 使用 PTC(正温度系数)陶瓷

5月 14, 2026

PetBoxX 育雏喷雾系统设计:区间湿度控制 + 水位自动补水

记录 PetBoxX ESP32-S3 固件中喷雾育雏模块的完整设计思路,方便日后查阅。 涉及两个相互独立但协同工作的子系统:湿度区间状态机(humidity_ctrl)和水位自动补水任务(mist_autofill)。 整体架构 育雏期的湿度管理分两层,职责完全分离: 模块 职责 控制的硬件 hu

5月 12, 2026

宠物保温箱恒温控制系统设计笔记

记录 PetBoxX 项目从不稳定到 ±0.1°C 恒温的全过程——硬件结构、PID 调参、热安全联锁、多箱型固件管理、风扇资质测试。 硬件结构 ┌─────────────────────────┐ │ PTC Heater [ Top ] │ │ PWM Fan [Mid

下一篇

上一篇

PetBoxX 育雏喷雾系统设计:区间湿度控制 + 水位自动补水

最近更新

  • PetBoxX 恒温区风扇控制的演变:固定 PWM、hold_ready 重置,与动态微调
  • PetBoxX 育雏喷雾系统设计:区间湿度控制 + 水位自动补水
  • 宠物保温箱恒温控制系统设计笔记
  • AutoTune 分段控制执行范围
  • 从零搭建 Halo 博客:Docker + Caddy + PostgreSQL 完整指南

热门标签

Halo PetBox PetBoxX

目录

©2026 蜗牛札记. 保留部分权利。

使用 Halo 主题 Chirpy