8 路 NTC 巡检的时序预算实战:第 5 通道总偏低 0.3 度,换探头换板子都没用——把采样顺序倒过来,偏低的那一路跟着换了个位置
上一篇《导热硅脂的老化与泵出实战》文末我留了个预告:多通道 NTC 巡采的 MUX 时序与同步采样——电荷注入、采样保持窗口、通道间 skew、巡检 vs 同步采样的判据表,以及”第 5 通道总是偏低 0.3 度”这类现场病怎么定位。这篇全部答上。
先说结论,因为它反直觉:这个 0.3 度跟探头、跟 MUX、跟板子都没有关系,是固件里那个”切换通道后延时一下”的延时不够长。而”不够长”这件事,只能在它和前一个通道的电压差里看见——所以它表现成”某一个通道固定偏”,而不是噪声。
事情起于去年十二月的一台柜子。16S 200Ah 离网储能柜,6 个电芯测点 + 1 路柜内环境 + 1 路功率电感温度,共 8 路 NTC,经一片 74HC4051 进 STM32 的 12bit ADC。巡检正序 0→7,每通道一个 125ms 的 slot,切换后固件延时 2.08µs(500 次空循环,240MHz)再启动 ADC。
运维报的现象很干净:CH5 比其他电芯通道稳定低 0.3 度左右,白天负载高的时候更明显,夜里空载时基本看不出来。换过探头(换了三支)、换过板子(换了两块)、换过 NTC 的批次,0.3 度一动不动。
三条常规排查全部指向”没问题”:探头在恒温槽里 ±0.05K 内;把 CH5 的探头插到 CH3 的座子上,CH5 还是低;把 CH3 的探头插到 CH5 的座子上,CH5 还是低。偏差跟着通道走,不跟着探头走——这时候就该怀疑通道本身,而不是传感器。
但”通道本身”这四个字会把人带偏:MUX 的通道导通电阻、走线、焊点、分压电阻,一个个查下去能耗掉一周。真正的答案在时序上,而且有一个十秒钟就能做完的判决性实验——把扫描顺序倒过来。
结论先行,五条:
- 多路 MUX 不进精度预算,只进时间预算:10k 分压下加一片 8:1 MUX,整条链的误差从 0.366K 变成 0.367K(+0.2%);它唯一会亏的是”建立没做完”的残差,而残差大小 = 前一通道电压差 × exp(−t/τ);
- 这个残差是差模的,所以表现成”某一路固定偏”:电荷注入是共模的(每一路一样大),在通道比对里看不见;前驱残差只打在某一路身上,这才是”第 5 通道总偏”的元凶;
- “等 3~5 个时间常数”这条经验只够 9~10bit:12bit 要 9.01τ,16bit 要 11.78τ(τ 数 = (位数+1)×ln2)。本例 4τ 恰好对应 0.32K,和现场那个 0.3 度严丝合缝;
- 换更贵的 MUX 没用:R_on 从 470Ω 换到 4.5Ω,τ 只从 818ns 降到 781ns(5%),因为 R_th 主导。R_on 在直流上严格为 0(ADC 输入阻抗 MΩ 级,稳态电流 nA 级,I×R_on 是 µV 级)——钱花在 R_on 上,病在时间上;
- 巡检对温度够用,对电流致命:温度一轮 1s 的 skew 只值 1.7mK,随便巡;但 4 路电流若也靠 MUX 巡检(一轮 4ms),200A 阶跃落在窗口中间就是”前两路 0A、后两路 200A”,119 篇那条 15%(30A)的均流判据一次投切就误报。
工具照例全离线:drafts/_tools/mux_scan_calc.py,13 个模式,37 项自检断言,文中每个数字都能复算。链路口径与《NTC 采样链路故障》、《BMS 温度门限参数表》、《探头贴装质量出厂验收》严格一致:B3950/R25 10k/NTC 在下/10k 上拉 3.3V/12bit 满量程 4095/1 LSB=0.806mV。
一、先把链路拆成两级 RC,别混着算
多路巡检的模拟链路,教科书上画成一根线,实际是两个独立的 RC,中间夹着一次开关动作:
NTC 分压 --[R_th]--+--[R_on]--+--[C_sh]-- ADC
| |
C_node 采样开关
- 第一级(MUX 节点):从探头分压点到 MUX 输出脚,源阻抗是戴维南电阻 R_th,负载电容是 MUX 的输出电容 + PCB 走线 + ADC 引脚,统称 C_node。时间常数
τ1 = (R_th + R_on) × C_node。 - 第二级(ADC 采样保持):采样开关闭合后,采样电容 C_sh 从节点取电荷。这一级的源阻抗是
R_th + R_on + R_adc,负载是 C_sh(以及被它拖着的 C_node)。
这两级的判据不一样,必须分别算,然后取慢的那个。 现场最常见的错就是只算了第二级——翻 ADC 手册,查”12bit、C_sh=6pF、t_samp=1.5µs,最大源阻抗 27.7kΩ”,一看自己的 R_th 才 9.8k,判定”没问题”。而第一级要 4.75µs,他给了 2.08µs。
先看 NTC 这一侧的物理量,这是全篇的地基:
| T℃ | R_ntc | R_th(//10k) | V_out | raw | dV/dT | τ1@80pF/120Ω |
|---|---|---|---|---|---|---|
| −40 | 401.9k | 9.76k | 3220.0mV | 3996 | −5.68mV/K | 790ns |
| −20 | 105.4k | 9.13k | 3014.0mV | 3740 | −16.10mV/K | 740ns |
| 0 | 33.62k | 7.71k | 2543.5mV | 3156 | −30.87mV/K | 626ns |
| 12 | 18.29k | 6.47k | 2133.7mV | 2648 | −36.63mV/K | 527ns |
| 25 | 10.00k | 5.00k | 1650.0mV | 2048 | −36.66mV/K | 410ns |
| 45 | 4.35k | 3.03k | 1000.0mV | 1241 | −27.20mV/K | 252ns |
| 55 | 2.98k | 2.29k | 757.3mV | 940 | −21.40mV/K | 193ns |
| 72 | 1.65k | 1.41k | 466.5mV | 579 | −13.28mV/K | 123ns |
| 85 | 1.09k | 0.98k | 323.5mV | 401 | −8.98mV/K | 88ns |
| 125 | 0.36k | 0.35k | 114.3mV | 142 | −2.75mV/K | 37ns |
这张表里有三件事,后面反复用:
第一,R_th 的最大值趋向”上拉电阻本身”,不是”两个电阻的并联最大值”。 NTC 越冷阻值越大,并联结果趋近上拉电阻 10k。所以 −40℃ 时 R_th=9.76k,几乎是 10k 封顶。习惯上想”并联总比两个都小,最大也就 5k”是错的——5k 只出现在 R_ntc=R_pull 的 25℃ 那一点。
第二,冷端建立最慢。 τ 从 125℃ 的 37ns 到 −40℃ 的 790ns,差 21 倍。所以”冬天出问题、夏天正常”这类现象,第一嫌疑永远是时序,不是温漂。
第三,灵敏度在两端都钝。 12~25℃ 处 −36.6mV/K 最好,−40℃ 只有 −5.68mV/K,125℃ 只有 −2.75mV/K。这意味着一件事,后面会算:同样的残差电压,在热端换来的温度误差更大。所以高温通道既是最该准的,又是最不容易准的。
二、第一级:残差 = 前一通道的电压差 × exp(−t/τ)
通道切换那一刻,MUX 输出脚上的电压还停在上一个通道的值。开关合上之后,它按指数曲线上电到新通道的值:
V(t) = V_ch + (V_pred − V_ch) · exp(−t / τ1)
残差 = (V_pred − V_ch) · exp(−t / τ1)
温度误差 = 残差 / (dV/dT)
三个变量,一个比一个重要:
V_pred − V_ch:前一个通道和本通道的电压差。这决定了误差跟”谁”有关。相邻两个电芯温度差 0.5℃,电压差 18mV,残差再大也就 0.5K 的十分之一;但如果前一个通道是柜外环境(−8℃),电压差 0.63V,就是 35 倍;exp(−t/τ1):等待时间的指数衰减。这是唯一你能改的量;1/(dV/dT):把电压误差翻译成温度误差。
把”要等多久”算出来:
| T℃ | τ1 | 等 4τ 的残差(跳变 0.633V) | 到 0.5LSB 的时间(满幅 3.3V) |
|---|---|---|---|
| −40 | 790ns | 2.04K | 7.12µs |
| −20 | 740ns | 0.72K | 6.67µs |
| 0 | 626ns | 0.38K | 5.64µs |
| 12 | 527ns | 0.32K | 4.75µs |
| 25 | 410ns | 0.32K | 3.69µs |
| 55 | 193ns | 0.54K | 1.74µs |
| 85 | 88ns | 1.29K | 0.79µs |
| 125 | 37ns | 4.22K | 0.34µs |
注意最后两列的走势是反的:冷端要等更久,但等不够时的温度误差反而更小;热端等得快,但等不够时温度误差更大。原因就是灵敏度——125℃ 处 1mV 值 0.36K,−40℃ 处 1mV 值 0.18K。
这一栏”4τ 残差”是全篇最关键的一列。它在 12℃ 那里写着 0.32K,和现场那个 0.3 度完全对上。
三、建立深度阶梯:4τ 正好 0.3K,而 4τ 是”看起来很保险”的数
把 exp(−t/τ) 摊成一张阶梯表,用本例的实际参数(跳变 0.633V,12℃ 通道,τ=527ns,灵敏度 −36.63mV/K):
| t/τ | 残差比 | 残差电压 | 温度误差 | 现象 |
|---|---|---|---|---|
| 0.5 | 60.65% | 383.9mV | 10.48K | 整条曲线像前一通道 |
| 1.0 | 36.79% | 232.9mV | 6.36K | 整条曲线像前一通道 |
| 2.0 | 13.53% | 85.7mV | 2.34K | 秒级可见偏置 |
| 3.0 | 4.98% | 31.5mV | 0.86K | 通道比对里露头 |
| 4.0 | 1.83% | 11.6mV | 0.32K | 就是现场这个 0.3 度 |
| 5.0 | 0.67% | 4.3mV | 0.12K | 勉强合格 |
| 6.0 | 0.25% | 1.6mV | 0.04K | 合格 |
| 9.0 | 0.012% | 0.08mV | 0.002K | 12bit 判据线 |
4τ 是这一行里最危险的一行,因为它长得太像一个”已经够保守”的经验值。工程口头禅”等 3~5 个时间常数”就是从 8bit 时代传下来的——那会儿 1 LSB = 12.9mV,等 5τ 就足够。现在的 12bit 是 0.806mV,差了 16 倍,需要的 τ 数也跟着涨。
精确的算法很简单:
所需 τ 数 = ln(ΔV / 0.5LSB)
满幅 3.3V、0.5LSB=0.403mV 时,ln(8188)=9.01。一般化成位数:
| ADC 位数 | 所需 τ 数 |
|---|---|
| 8 bit | 6.24 |
| 10 bit | 7.62 |
| 12 bit | 9.01 |
| 14 bit | 10.40 |
| 16 bit | 11.78 |
规律是 (n+1)×ln2,每多一位加 0.69τ。“等 5 个时间常数”这条经验,对应的其实是 9~10bit——放在 12bit 上,正好落在 0.32K 那一格。
现场那个 2.08µs 是怎么来的?500 次空循环。240MHz 下 for(i=0;i<500;i++) __NOP(); 连循环开销一起算就是这个数——一个没有任何物理依据的数字,恰好落在 4τ 上。这类”凑出来的延时”在固件里非常普遍,它的问题不是短,是短得刚好能被判据容忍:0.32K 不会触发任何告警,也不会让保护误动,只是让 6 个电芯测点中的一个永远低 0.3 度。等到有人拿它做一致性判断(比如122 篇的兄弟温差、124 篇的跟随比),它才开始咬人。
四、第二级:ADC 采样窗口有两个判据,取大的那个
第一级等够了,第二级还有一个坑,而且这个坑在手册里查不到。
(a) C_sh 充电:标准公式,源阻抗上限 R_s ≤ t_samp / ((n+1)·ln2·C_sh)。
| C_sh | t_samp=0.5µs | 1.5µs | 3µs | 10µs |
|---|---|---|---|---|
| 3pF | 18.5kΩ | 55.5kΩ | 111kΩ | 370kΩ |
| 6pF | 9.2kΩ | 27.7kΩ | 55.5kΩ | 185kΩ |
| 10pF | 5.5kΩ | 16.6kΩ | 33.3kΩ | 111kΩ |
按这一条,12bit/6pF/1.5µs 允许 27.7kΩ,现场 R_th 最大 9.8k,看起来绰绰有余。这就是”查完手册觉得没问题”的来源。
(b) 节点跌落恢复:采样开关闭合的瞬间,C_sh 要把自己充到节点电压,这份电荷只能从 C_node 拿。如果 C_node 不够”硬”,节点会被拉下来一个台阶:
跌落 = C_sh / (C_node + C_sh)
本例 C_node=80pF、C_sh=6pF,比例 13.3,跌落 6.98%,满幅时 230mV——按 12℃ 灵敏度算是 6.28K。这个台阶要靠源阻抗重新充回去,时间常数是 R_src × (C_node + C_sh) = 652ns,比 (a) 的 65ns 大 10 倍。
| 采样窗口 | 跌落残留 | 折算温度 |
|---|---|---|
| 0.5µs | 46.5% | 2.92K |
| 1.0µs | 21.6% | 1.36K |
| 1.5µs | 10.0% | 0.63K |
| 3.0µs | 1.0% | 0.06K |
| 5.0µs | 0.05% | 0.003K |
按 (a) 只要 0.41µs,(b) 要 3.26µs,差 6 倍。取大的,t_samp 定 5µs。
判断什么时候 (b) 会咬人,看一个比值:C_node / C_sh。
- 大于 50(输入端带 1nF 以上):节点很”硬”,(b) 自动满足,按 (a) 算就行;
- 10~50(本例 13.3):必须两个都算,取大的;
- 小于 10(16bit ADC 的 C_sh 常有 10~20pF,而 C_node 因为要快所以压得很小):跌落超过 10%,这一级就是主要误差源,只能加缓冲器。
这条判据在现场为什么重要:它是”加了抗干扰电容反而更不准”的另一种解释。加 1nF 会让 C_node/C_sh 变成 167,(b) 消失了——但同时 τ1 涨了 12 倍变成 6.3µs。两个判据是一根跷跷板,你不能只改一头。
五、R_on 不买精度,只买时间
这是本篇最省钱的结论。
MUX 的导通电阻 R_on 常被当成精度指标:CD4051B 在 5V 下 470Ω,74HC4051 在 3.3V 下 120Ω,ADG708 只要 4.5Ω,价格差 20 倍。直觉是”贵的准”。算一下就散了:
τ1 = (R_th + R_on) × C_node
= (9756 + 470) × 80pF = 818ns (CD4051B)
= (9756 + 4.5) × 80pF = 781ns (ADG708)
差 5%。 因为 R_th 是 9.76k,R_on 在它面前就是个零头。
而精度上,R_on 的贡献严格为零。理由是:ADC 输入阻抗是 MΩ 级,稳态时流过分压网络的只有 ADC 的输入漏电流(nA 级),I×R_on 落在 µV 量级,不到 0.5LSB 的百分之一。R_on 只在充电的那一瞬间有电流通过,等建立完成它就不存在了。
所以选型判断变成两条:
- 等待时间给够了,1 块钱的 CD4051 和 20 块的 ADG708 读数一样准;
- 等待时间不够,换 ADG708 也没用——τ 只从 818 降到 781ns,你需要的是 9τ 而不是 9.5τ。
真正有效的提速只有两条路,而且都有代价:
| 手段 | 效果 | 代价 |
|---|---|---|
| 降 R_th(分压电阻 10k→1k) | τ 降 10 倍 | 功耗涨 10 倍(8 路 13mW) |
| 降 C_node(缩短走线、低容 MUX、去掉并联电容) | τ 线性降 | 抗干扰能力下降 |
| 换低 R_on 的 MUX | τ 降 5% | 贵 20 倍 |
80pF 这个数值得说一句:MUX 输出电容 30pF + PCB 走线 20pF + ADC 引脚 10pF + 余量 20pF。把 MUX 到 MCU 的走线从 5cm 缩到 1cm,能省 10~15pF,τ 降 15%——比换 MUX 划算得多。
六、巡检顺序就是误差的指纹(本篇最有用的一条)
到这里可以把现场那个 0.3 度还原了。8 个通道的实际温度:
| CH | 位置 | 实际温度 | V_out | τ1 |
|---|---|---|---|---|
| 0 | 电芯 | 11.8℃ | 2141.0mV | 529ns |
| 1 | 电芯 | 12.1℃ | 2130.0mV | 526ns |
| 2 | 电芯 | 12.4℃ | 2119.0mV | 523ns |
| 3 | 电芯 | 12.0℃ | 2133.7mV | 527ns |
| 4 | 柜外环境 | −8.0℃ | 2767.8mV | 681ns |
| 5 | 电芯 | 12.2℃ | 2126.3mV | 525ns |
| 6 | 电芯 | 12.3℃ | 2122.7mV | 524ns |
| 7 | 电芯 | 11.9℃ | 2137.3mV | 528ns |
CH4 是柜外环境探头,冬天夜里 −8℃,NTC 阻值 402k,分压点被顶到 2768mV。它比相邻的电芯通道高 634mV——这是全表唯一的大跳变。
按正序 0→7 扫描,每个通道的前驱就是它的前一号,算出来的误差:
| CH | 实际℃ | 前驱(温度) | 残差 | ΔT |
|---|---|---|---|---|
| 0 | 11.8 | 7 (11.9℃) | +0.07mV | +0.002K |
| 1 | 12.1 | 0 (11.8℃) | +0.21mV | −0.006K |
| 2 | 12.4 | 1 (12.1℃) | +0.21mV | −0.006K |
| 3 | 12.0 | 2 (12.4℃) | −0.28mV | +0.008K |
| 4 | −8.0 | 3 (12.0℃) | −29.85mV | +1.190K |
| 5 | 12.2 | 4 (−8.0℃) | +12.21mV | −0.333K |
| 6 | 12.3 | 5 (12.2℃) | +0.07mV | −0.002K |
| 7 | 11.9 | 6 (12.3℃) | −0.28mV | +0.008K |
只有 CH4 和 CH5 两位是错的,其余 6 位的误差在 0.01K 以内(不到 0.02 LSB)。这和现场”只有 CH5 偏低”完全对上——CH4 是环境温度,运维根本没人看它。
现在做那个十秒钟的实验:把扫描顺序倒过来,7→0。
| CH | 正序 ΔT | 倒序 ΔT | 倒序时的前驱 |
|---|---|---|---|
| 3 | +0.008K | −0.334K | 4 (−8.0℃) |
| 4 | +1.190K | +1.204K | 5 (12.2℃) |
| 5 | −0.333K | +0.002K | 6 (12.3℃) |
偏低的那一路从 5 号跳到了 3 号,而 5 号自己恢复正常。 跳过去的位置正好是”柜外环境通道的下一个”。
这就是判决性的证据:偏差不是通道的物理属性(否则换顺序不会动),也不是探头的属性(否则换探头会动),而是“谁紧跟在那个大电压差的通道后面采样”这个关系的属性。
顺带解释两个细节,都很容易被误读:
为什么 CH4 自己偏高 1.19K,而 CH5 只偏低 0.33K? 因为 CH4 在 −8℃,灵敏度只有 −25mV/K(冷端钝),同样的 30mV 残差换到 1.19K;CH5 在 12℃,灵敏度 −36.6mV/K,12mV 残差换到 0.33K。冷端是最容易被”同样的电压误差”放大成温度误差的地方——这也是118 篇那张 0℃ 限流表最怕的事:温度读数错了 1 度,限流档位就错一档。
为什么 CH4 的偏差只在冬天夜里出现? 因为 ΔV 就是它和电芯的温差。夏天柜外 30℃、柜内 25℃,差 5℃ → 电压差不到 20mV → 残差 0.4mV → 温度误差 0.01K,淹没在噪声里。冬天 −8℃ vs 12℃,差 20℃ → 电压差 634mV,才浮出来。“季节性出现的通道偏差”这个描述,本身就指向时序——真正的器件问题是常年存在的,只有前驱电压差是季节性的。
七、电荷注入是共模的,前驱残差是差模的
MUX 切换时,开关管的栅极电荷会注入到输出节点。74HC4051 类大约 10pC,ADG708 类 1pC。用同一个 C_node 折算:
ΔV_inj = Q_inj / C_node = 10pC / 80pF = 125mV
125mV 在 12℃ 是 3.41K,在 0℃ 是 4.05K。看起来比前驱残差严重得多,但它有一个关键性质:每一路都一样大。
| 效应 | 大小 | 性质 | 在通道比对里 |
|---|---|---|---|
| 电荷注入 | 125mV(10pC/80pF) | 共模,每路相同 | 看不见 |
| 前驱残差 | 25mV(ΔV=0.63V,4τ) | 差模,只打某几路 | 全暴露 |
所以这两件事的处置完全不同:
- 注入只买时间:它和信号一起衰减,等够了就没了。它唯一的作用是把”所需的等待时间”往上抬一点——把
ΔV + Q/C当成一个更大的等效跳变去算 9τ 就行。本例 125mV 相对 634mV 是 20%,等待时间要多 2%。 - 前驱残差要买结构:换顺序、加缓冲器、或按最坏 ΔV 设计等待时间。改不了就认,但必须在判据里扣掉。
这条区分解释了一个常见困惑:“我把所有通道都短接到同一个基准,读数都很准,为什么现场还是偏?” 因为短接之后 ΔV=0,注入也被同一电压对齐,两个效应同时归零。这个测试测的是”器件好不好”,测不出”时序够不够”。
八、漏电:低功耗大电阻的真实代价
关断通道的漏电流会通过 R_th 变成一个直流偏移。这个偏移不像残差那样会衰减——它一直在。
10k/10k 分压(NTC 在下):
| 器件 / 口径 | I_off | −8℃ | 12℃ | 25℃ | 55℃ | 85℃ |
|---|---|---|---|---|---|---|
| HC4051 类 25℃ 典型 | 0.10nA | 0.0mK | 0.0mK | 0.0mK | 0.0mK | 0.0mK |
| HC4051 类 85℃ 外推 | 6.40nA | 2.1mK | 1.1mK | 0.9mK | 0.7mK | 0.7mK |
| HC4051 类 85℃ 手册上限 | 100nA | 33.4mK | 17.6mK | 13.6mK | 10.7mK | 10.9mK |
| ADG708 类 85℃ 上限 | 0.10nA | 0.0mK | 0.0mK | 0.0mK | 0.0mK | 0.0mK |
最坏一格 33.4mK,占整条链 0.366K 预算的 9%,可以接受。
100k/100k 分压(把功耗降 10 倍,从 1.32mW 降到 0.13mW):
| 器件 / 口径 | I_off | −8℃ | 12℃ | 25℃ | 55℃ | 85℃ |
|---|---|---|---|---|---|---|
| HC4051 类 85℃ 外推 | 6.40nA | 21.4mK | 11.3mK | 8.7mK | 6.9mK | 7.0mK |
| HC4051 类 85℃ 手册上限 | 100nA | 334.5mK | 176.5mK | 136.4mK | 107.2mK | 109.1mK |
| ADG708 类 85℃ 上限 | 0.10nA | 0.3mK | 0.2mK | 0.1mK | 0.1mK | 0.1mK |
最坏一格 334mK,比整条链的器件误差(0.366K)还大。 而且注意它是单向的、常驻的、不随采样时序变化的——它不会像残差那样被”换个顺序”暴露,会安安静静待在那里。
所以低功耗大电阻的结论不是”能”或”不能”,是必须成套换:
| 方案 | 静态功耗 | R_th | τ1 | 漏电(85℃ 上限) | 结论 |
|---|---|---|---|---|---|
| 10k + HC4051 | 1.32mW | 9.9k | 790ns | 33mK | 可以,建立时间 7.1µs |
| 10k + ADG708 | 1.32mW | 9.9k | 781ns | 0.03mK | 过设计,钱花在没用的地方 |
| 100k + HC4051 | 0.13mW | 99k | 7.9µs | 334mK | 不合格 |
| 100k + ADG708 | 0.13mW | 99k | 7.9µs | 0.3mK | 可行,等待时间 71µs |
100k + ADG708 是省电的正确解法:省 1.2mW,付 71µs 的等待时间(slot 125ms 完全付得起),精度不掉。而 100k + HC4051 是”省了电,精度没了”,还查不出来——因为它的指纹是”所有通道一起慢慢偏”,在一致性判据里看不见。
顺带一个量级校验,防止把这件事想得太严重:100k 方案下 R_th 最大 99k,正常工作时这个电阻上的热噪声是 √(4kTRB),B=1kHz 时 1.3µV,折 0.04K。噪声不是问题,漏电才是。
九、缓冲器很容易加错位置
“加个运放做跟随,把源阻抗降下来”——这句话对,但位置决定生死。三种方案,同一个 MUX:
| 方案 | 一级 τ | 二级 τ | 代价 | 解决问题? |
|---|---|---|---|---|
| A 每通道一个跟随器(探头端) | 4.0ns | 90.3ns | 8 颗运放 + 8×0.5mA | 彻底解决 |
| B MUX 后一个共享缓冲器 | 410ns | 90.3ns | 1 颗运放 | 一点没解 |
| C 输入端串 1k + 100nF | 647µs | 747µs | 0 元 | 反向恶化 1500 倍 |
方案 B 是现场最常犯的错。 运放加在 MUX 后面,它只把”ADC 的负载”和”MUX 的输出”隔开——但 MUX 输出脚上那 80pF 还是得由探头自己充,τ1 一点没变(410ns)。而 ADC 那一级的 τ 本来就只有 90ns,不需要救。钱花了,病没治。
方案 A 才是真正的解:跟随器放在探头端,MUX 节点由运放的 50Ω 输出阻抗驱动,τ 从 410ns 掉到 4ns,快了 100 倍。代价是 8 颗运放(4 颗双运放),BOM 加 8~15 块,静态电流加 4mA。8 路以上、且需要 10µs 以内的建立时间时,这个钱值得花。
方案 C 是”为了抗干扰加电容”的典型翻车:100nF 配 6.47k 的 R_th,τ=647µs。等 2.08µs 时衰减 exp(−0.0032)=0.9968,等于每个通道读到的都是前一个通道的电压。
这个失效模式的指纹和”0.3 度”完全不同,很好认:
- 偏 0.3K 那种(时间不够一点点):某一路固定偏,曲线形状不变,只是整体平移;
- 100nF 那种(时间差 300 倍):曲线整体右移一位——把 8 条温度曲线画在一张图上,会发现 CH5 的形状像 CH4、CH6 像 CH5。
第二种情况别去查探头,一查一个准是白查。反推一下:要让 100nF 方案的残差降到 0.3K,等待时间得给到 3ms。slot 是 125ms,付得起——所以 100nF 不是不能用,是必须和 slot 一起重算,不能沿用 2µs。这就是本篇反复出现的主题:时序预算是一个整体,改一头必须回头改另一头。
十、巡检 vs 同步采样:温度够用,电流致命
这是”多路巡检”这个方案该不该用的分水岭。判据只有一个:被测量的时间常数。
先算温度这边的 skew 值多少。8 路 × 125ms = 一轮 1s,第 8 路和第 1 路在时间上差 875ms:
| 工况 | 温升速率 | 一轮 1s 内的变化 |
|---|---|---|
| 1C 充电 | 6.10K/h | 1.69mK |
| 0.5C 充电 | 1.53K/h | 0.43mK |
| 加热膜启动瞬间 | 2.10K/h | 0.58mK |
对照124 篇的判据——兄弟温差 3K、斜率缺口 30%(0.5C 下 460mK/h)——skew 贡献 1.7mK,差两个数量级。温度巡检一轮 1s 完全够用,甚至 10s 也够(探头自身 τ 是 6~8s,比巡检周期还长,采样点之间本来就是相关的)。
电流就完全不是这回事:
- 4 路电流若也靠 MUX 巡检、每路 1ms,一轮 4ms;
- 负载投切、充电机启停是 100ms 级事件,但 MOSFET 关断只要 100µs;
- 200A 的阶跃如果正好落在 4ms 窗口中间,前两路读 0A、后两路读 200A;
- 119 篇的均流判据是”支路电流差 15%(=30A)持续 60s”——一次投切就误报,而且误报会持续 60s。
所以这一条不是”精度问题”,是判据的时间基准问题:任何”多路之间的差”的判据,都要求各路在同一时刻取值。电流类判据必须用:
- MCU 的双 ADC 同步规则组(同时启动转换);
- 或多路采样保持同时进入 hold,再逐个读出;
- 或每路一个独立的 ΣΔ/霍尔传感器(本来就是并行的)。
顺便把这一条推广成一个通用规则,写进设计评审清单:
| 被测量 | 时间常数 | 采样方式 | 一轮 skew 允许值 |
|---|---|---|---|
| 电芯温度 | 6~8s(探头)到 5h(包体) | MUX 巡检 | ≤ 1s |
| 母线电压 | ms~s | 巡检或同步 | ≤ 10ms |
| 支路电流 | µs~ms | 必须同步 | ≤ 100µs |
| 绝缘阻抗 | s | 巡检 | ≤ 1s |
十一、slot 不该平均分
8 路 × 125ms 是最省事的写法,也是最浪费的写法。实际每路只需要 25~30µs:
单通道:等待 10µs + 采样 5µs + 转换 4µs + 开销 6µs = 25µs
占空比:25µs / 125ms = 0.02%
CPU 有 99.98% 的时间可以睡。 如果为了省电把巡检周期拉到 10s,占空比降到 0.00025%,一年省下的电还不够一次误动作的代价。
但平均分的真正问题是它把”快”和”慢”混在一个节奏里。合理的做法是按时间常数分档:
| 档位 | 周期 | 通道 | 实现 |
|---|---|---|---|
| 快 | 1ms | 支路电流、母线电压 | 独立 ADC 通道 + DMA 连续 |
| 中 | 100ms | 功率器件温度、电感温度 | MUX 前 4 路 |
| 慢 | 1s | 电芯温度、环境温度 | MUX 后 4 路 |
| 极慢 | 60s | 绝缘、SOH 辅助量 | 单独任务 |
这样做的额外好处:慢档的等待时间可以给足。电芯温度那 4 路,每路可以给 5ms 的建立时间(本来只要 4.75µs),留 1000 倍余量,什么探头、什么线长都不用怕。而快档不需要 MUX,也就没有 MUX 的时序问题。
一个反过来的坑要提一句:别把”一轮”当成”一个决策窗口”。122 篇的四张门(禁充、限流、加热、降额)需要”同一时刻的全套温度”来做 limiting source 判断。如果 8 路分在 4 个不同的 MUX 上、由 4 个任务分别扫描,就会出现”这一路的温度是 800ms 前的、那一路是 100ms 前的”,在温度快速变化时(比如刚启动加热)判断会抖。做法是每轮结束时打一个时间戳,同一轮的 8 个值算同一次决策,而不是各算各的。
十二、产线自检:交替基准法,两根线就能测出时序够不够
前面所有分析都是”算”,这一节是”测”。而且这个测法不花一分钱。
做法:把 8 路输入交替接到 0.5V / 2.5V 两个基准(偶数路 0.5V,奇数路 2.5V),按真实的扫描顺序和真实的 slot 跑一遍,读 raw 值。
- 每次切换的跳变是 2.0V = 2482 LSB,把建立残差放到最大;
- 理论值:相邻通道 raw 差恰好 2482;
- 判据:偏离超过 12 LSB(约 0.12K)即不合格。
| 等待时间 | 残差 | LSB | 折算温度 | 判定 |
|---|---|---|---|---|
| 2.08µs | 12.46mV | 15.5 | 0.340K | 不合格 |
| 4.00µs | 0.11mV | 0.1 | 0.003K | 合格 |
| 6.00µs | 0.00mV | 0.0 | 0.000K | 合格 |
三行就把现场那个 2.08µs 判死了,和前面算出来的 0.333K 互相印证。
为什么不能”全部短接到同一个点”? 因为那样跳变等于 0,残差恒等于 0,什么也测不出来。这个测试的全部信息量都在”跳变”里,所以基准必须交替。
还有两个细节,都是坑:
第一,测试用的基准源内阻要低。 两个基准若来自同一颗 DAC 的两个通道,输出阻抗几百欧,会串进来。用 TL431 分压 + 运放跟随,或者干脆用两个低阻分压(1k/1k 从 3.3V 和 5V 分出来)。基准的内阻直接加在 R_th 上,会把你测的东西改掉。
第二,产线 25℃ 通过,不代表 −40℃ 合格。 这一条最容易被忽略:
| 温度 | τ1 | 等 4µs = 多少 τ | 残差 |
|---|---|---|---|
| 25℃ | 410ns | 9.77τ | 0.006% |
| −8℃ | 681ns | 5.88τ | 0.280% |
| −40℃ | 790ns | 5.06τ | 0.633% |
同样 4µs,−40℃ 的残差是 25℃ 的 100 倍以上。 产线在 25℃ 测出的”合格”,对冷端毫无预测力——这正是”出厂全过、冬天出问题”的机理。
解法很轻:产线测试时在每个输入端串 4.7kΩ。直流下没有电流流过它,读数不变;但它把 R_th 从 6.5k 抬到 11k,覆盖了 −40℃ 的 9.8k。这时候 12 LSB 的判据就真正代表了最坏情况。
/* 产线自检序列(伪代码,交替基准法) */
for (ch = 0; ch < 8; ch++) {
mux_select(ch);
delay_us(T_SETTLE); /* >= 9 * tau_worst */
raw[ch] = adc_read_12bit(); /* t_samp >= 5us */
}
int32_t d = 0;
for (ch = 0; ch < 7; ch++)
d = MAX(d, abs((raw[ch+1] - raw[ch]) - 2482));
FAIL_IF(d > 12); /* 12 LSB = 0.12K = 0.5% 建立深度 */
十三、排障十步(按命中率排)
下次遇到”某个通道固定偏”,照这个顺序做,前三条能解决八成:
- 把扫描顺序倒过来(7→0),看偏差是否跟着跳到”离群通道的下一个”。是 → 建立时间不足,收工。这条十秒钟,永远第一个做。
- 交换两个通道的探头接线:偏差跟着线走,还是跟着通道走?跟通道 → MUX/时序;跟线 → 探头/接线/分压电阻。
- 示波器看 MUX 输出脚,在 ADC 采样窗口末尾量纹波。大于 0.5 LSB(0.4mV)就是等待时间不够,直接加。
- 把等待时间从 2µs 加到 20µs 再读一遍。偏差消失 → 确诊;不消失 → 看第 5 条。
- 全通道接同一基准,读数极差是否大于 0.1K。是 → ADC 通道差或 MUX 的 R_on 不平坦(直流上本不该有差)。
- 某通道输入并 100nF 后,曲线是否”像前一个通道”。是 → RC 太大,采样窗口被记忆效应吃掉。
- 高温工况(>60℃)偏差是否变大。是 → 关断漏电,换低漏 MUX 或降分压电阻。
- 偏差是否只在负载高/某器件发热时出现。是 → 前驱通道是功率器件温度,跳变大。
- ADC 采样窗口是否按手册最小值配的。是 → 只满足了第二级,第一级没算。
- 固件延时是不是空循环或未校准的 NOP。是 → 编译优化、主频变化都会改它,改用定时器或 ADC 触发。
第 1 条为什么排第一:它是唯一能把”时序”从”器件”里一刀切开的实验。器件问题不会因为顺序改变而改变,时序问题一定会。
十四、时序预算表(可直接抄进设计评审)
| 项目 | 判据 | 本例取值 | 备注 |
|---|---|---|---|
| MUX 切换→启动 ADC 的等待 | ≥ 9τ1(按最坏 R_th) | 10µs | −40℃ 需 7.1µs,留 40% |
| ADC 采样窗口 t_samp | ≥ max(9.01·R_src·C_sh, 5·R_src·(C_node+C_sh)) | 5µs | 两个判据取大 |
| ADC 转换 | 器件固定 | 4µs | @1Msps |
| 单通道总占用 | 等待+采样+转换+开销 | 25µs | 占 slot 的 0.02% |
| 温度巡检周期 | ≤ 最快保护环 τ 的 1/5 | 1s | 8 路 × 125ms |
| 电流采样 | 必须同步 | 双 ADC 同步规则组 | 巡检会误报均流 |
| 交替基准自检 | raw 偏差 ≤ 12 LSB | 产线 100% | 输入端串 4.7k 覆盖冷端 |
| 漏电上限 | I_off × R_th ≤ 0.5 LSB | ≤ 0.4mV | 85℃ 上限口径 |
| R_on 指标 | 只影响 τ,不影响精度 | 470Ω 可接受 | 别为它多花钱 |
最后把本篇的主线收成一句话:加一个 MUX,你付出的不是精度,是时间。精度账上它几乎是白送的(0.366K → 0.367K,+0.2%);时间账上它要求你从”我延时了 2µs”变成”我按最坏 R_th 算了 9τ”。而时间账一旦算错,它不会报错、不会越界、不会触发任何告警——它只会让某一路温度悄悄偏 0.3 度,然后在你拿它做一致性判据的那天,咬你一口。
工具:drafts/_tools/mux_scan_calc.py(13 个模式,37 项自检断言,纯标准库、全离线)。文中数据口径:B3950/R25 10k/NTC 在下/10k 上拉 3.3V/12bit 满量程 4095/1LSB=0.806mV;C_node=80pF(MUX 输出 30 + 走线 20 + ADC 引脚 10 + 余量 20);C_sh=6pF;R_adc=1kΩ;R_on=120Ω(74HC4051@3.3V);Q_inj=10pC;漏电按 HC4051 类 25℃ 典型 0.1nA、85℃ 按 10℃ 翻倍外推 6.4nA、手册上限 100nA 三档给出,具体数值请按自己器件的 datasheet 替换。
另:9 月 26 日那篇《ESD 与浪涌防护实战》里”12.5kV 应为 12.5V”的笔误还没改,等排期。站内至今仍缺《Flash 存储与参数管理》和《固件安全与逆向防护》两个主题,都在待写清单上。
下一篇写多通道巡采的通道间串扰与 MUX 前置滤波的取舍——本篇只把 C_node 当成一个集总电容,实际上 8 路输入引脚之间还有容性耦合,一个高阻通道会通过 3~5pF 的引脚电容”偷看”邻居;以及”输入端到底该不该加 RC、加多大”这个问题的定量答案(滤波带宽 vs 建立时间 vs 通道串扰三者的一张等值线图)。顺带把本篇没展开的”共模注入如何用差分采样消掉”补上。