4. 温度采集技术:NTC/PTC热敏电阻原理、温度传感器布局策略、线性化与查表法

温度采集,在BMS里是个老生常谈但又极其关键的话题。你想想看,电池的脾气可大了——温度高了它要炸,温度低了它不干活。所以,怎么把温度测准、测快、测稳,直接决定了BMS的可靠性。

我个人习惯把温度采集分成三个层次来理解:传感器原理布局策略数据处理。咱们一个一个聊。

4.1 NTC与PTC热敏电阻原理

先说NTC。NTC是负温度系数热敏电阻,温度升高,电阻值下降。这个特性刚好跟金属导体相反。为什么?因为NTC用的是半导体材料,温度一高,载流子浓度增加,导电性变好,电阻自然就降了。

我在项目中遇到过最常用的NTC型号是MF52系列,25℃时标称阻值10kΩ,B值3435K。这个参数组合在BMS领域几乎成了行业默认配置。

NTC的电阻-温度关系可以用Steinhart-Hart方程精确描述:

1/T = A + B·ln(R) + C·[ln(R)]³

其中T是开尔文温度,R是电阻值,A、B、C是三个系数。实际工程中,我们常用简化公式:

R = R₀ · exp[B · (1/T - 1/T₀)]

这里R₀是T₀温度下的阻值,B是材料常数。

关键点:NTC的精度主要取决于B值的精度和阻值公差。普通NTC的B值公差在±1%左右,对应温度误差约±0.5℃。高精度NTC可以做到±0.3%甚至更好。

再说PTC。PTC是正温度系数热敏电阻,温度升高,电阻值也升高。但PTC有个特点——它的电阻变化不是线性的,而是在某个温度点附近发生突变。这个温度点叫居里温度。

PTC在BMS里用得不多,主要用在过温保护场景。比如,把PTC串联在加热回路里,温度一超过居里点,电阻瞬间飙升,电流就被限制住了。说白了,它就是个自恢复保险丝。

我的经验:选NTC时,别光看25℃的阻值,一定要看B值的温度范围。有些便宜货的B值在低温段和高温段差异很大,测出来的温度曲线会严重偏离标称值。我曾经吃过这个亏,后来一律要求供应商提供全温区的实测数据。

4.2 温度传感器布局策略

传感器选好了,往哪儿放?这个问题比你想的复杂得多。

电池模组里,温度分布是不均匀的。电芯正极、负极、极耳、外壳,温度都不一样。你放一个传感器,只能代表那个点的温度,不能代表整个模组。

我建议的布局原则是:

  • 每个模组至少2个传感器:一个放在最热区域(通常是正极极耳附近),一个放在最冷区域(通常是底部或边缘)。
  • 重点关注极耳温度:极耳是电流进出电芯的通道,发热最集中。我见过不少设计只在电芯表面贴NTC,结果极耳都烧红了,表面温度才刚报警。
  • 远离散热风道:如果模组有主动散热,传感器别放在风道正对的位置,否则测出来的是冷却空气的温度,不是电芯的温度。
  • 考虑老化影响:导热硅脂会干涸,导热垫片会老化。我建议传感器安装时用机械固定+导热胶双重保障,别只靠导热胶粘着。

避坑指南:我曾经在一个项目中,把NTC直接贴在电芯铝壳上,用双面胶固定。结果跑了半年,双面胶老化脱落,NTC悬空了,测出来的温度比实际低了10℃。从那以后,我要求所有传感器必须用卡扣或螺丝固定,外加导热硅脂填充。

下面这张图展示了典型的BMS从控温度传感器布局方案:

BMS从控温度传感器布局示意图 电池模组(12串4并示例) 电芯1 电芯2 电芯3 电芯4 电芯5 电芯6 电芯7 电芯8 电芯9 电芯10 电芯11 电芯12 NTC 极耳温度 NTC NTC NTC 底部温度 NTC NTC BMS从控板(温度采集通道) 电芯 NTC传感器 信号线

4.3 线性化与查表法

NTC的电阻-温度曲线是非线性的。在低温段,电阻变化很剧烈;在高温段,变化又很平缓。直接拿ADC采到的电压值去算温度,误差会很大。

怎么解决?两个办法:硬件线性化软件查表法

4.3.1 硬件线性化

硬件线性化,说白了就是给NTC并联一个固定电阻,让分压网络的输出在某个温度区间内尽量接近线性。这个方法在模拟电路时代很流行,现在用得少了。

并联电阻的取值有个经验公式:

R_parallel ≈ R_NTC(T_mid) × (B - 2T_mid) / (B + 2T_mid)

其中T_mid是你关心的温度区间中点,单位是开尔文。比如你要测-20℃到60℃,中点就是20℃(293.15K),B值3435K,那么并联电阻大约是:

R_parallel ≈ 10k × (3435 - 586.3) / (3435 + 586.3) ≈ 7.2kΩ

实际工程中,我一般选6.8kΩ或8.2kΩ的标称值,然后通过软件校准。

我的建议:除非你的MCU没有足够的算力做查表,否则别用硬件线性化。它增加了BOM成本,还引入了额外的温漂误差。现在随便一个Cortex-M0内核的MCU,查个256点的表也就几微秒的事。

4.3.2 软件查表法

这才是目前的主流做法。查表法的核心思想是:提前算好NTC在不同温度下的ADC值,存成一个数组。运行时,把ADC采样值跟表里的值比对,找到最接近的那个温度。

查表法有两种实现方式:

  • 直接查表:ADC值作为索引,温度作为表项。速度快,但表很大(比如12位ADC需要4096个表项)。
  • 二分查找:温度作为索引,ADC值作为表项。表很小(比如-40℃到125℃,每1℃一个点,才166个表项),但需要做二分查找。

我个人习惯用二分查找。下面是一个典型的实现:

/* NTC温度查表 - 二分查找法 */
/* 表项:温度(℃) -> ADC值(12位, 参考电压3.3V, 上拉电阻10kΩ) */

const uint16_t ntc_table[] = {
    4095, 4088, 4076, 4058, 4032,  // -40℃ ~ -36℃
    3996, 3948, 3886, 3808, 3714,  // -35℃ ~ -31℃
    3604, 3478, 3338, 3186, 3024,  // -30℃ ~ -26℃
    2856, 2684, 2512, 2342, 2178,  // -25℃ ~ -21℃
    2020, 1872, 1734, 1606, 1488,  // -20℃ ~ -16℃
    1380, 1282, 1192, 1110, 1036,  // -15℃ ~ -11℃
    968,  906,  850,  798,  750,   // -10℃ ~ -6℃
    706,  666,  628,  594,  562,   // -5℃ ~ -1℃
    532,  504,  478,  454,  432,   // 0℃ ~ 4℃
    410,  390,  372,  354,  338,   // 5℃ ~ 9℃
    322,  308,  294,  282,  270,   // 10℃ ~ 14℃
    258,  248,  238,  228,  220,   // 15℃ ~ 19℃
    212,  204,  196,  190,  184,   // 20℃ ~ 24℃
    178,  172,  166,  160,  156,   // 25℃ ~ 29℃
    152,  148,  144,  140,  136,   // 30℃ ~ 34℃
    132,  128,  124,  120,  116,   // 35℃ ~ 39℃
    112,  108,  104,  100,  96,    // 40℃ ~ 44℃
    92,   88,   84,   80,   76,    // 45℃ ~ 49℃
    72,   68,   64,   60,   56,    // 50℃ ~ 54℃
    52,   48,   44,   40,   36     // 55℃ ~ 59℃
};

int16_t ntc_lookup(uint16_t adc_value)
{
    int16_t low = 0;
    int16_t high = sizeof(ntc_table)/sizeof(ntc_table[0]) - 1;
    int16_t mid;
    
    /* 边界检查 */
    if (adc_value >= ntc_table[low])  return -40;
    if (adc_value <= ntc_table[high]) return 59;
    
    /* 二分查找 */
    while ((high - low) > 1) {
        mid = (low + high) / 2;
        if (adc_value > ntc_table[mid]) {
            high = mid;
        } else {
            low = mid;
        }
    }
    
    /* 线性插值提高精度 */
    int16_t temp_low = -40 + low;
    int16_t temp_high = -40 + high;
    uint16_t adc_low = ntc_table[low];
    uint16_t adc_high = ntc_table[high];
    
    int32_t temp = temp_low + (int32_t)(temp_high - temp_low) * 
                   (adc_value - adc_low) / (adc_high - adc_low);
    
    return (int16_t)temp;
}

关键点:查表法加上线性插值,精度可以做到±0.1℃以内。如果你对精度要求更高,可以用Steinhart-Hart方程直接计算,但MCU算力消耗会大很多。我一般只在实验室校准环节用公式计算,量产产品一律用查表法。

4.3.3 表怎么生成?

表不是手算的,太容易出错了。我一般用Python脚本生成:

# 生成NTC查表数据
import math

R0 = 10000.0   # 25℃时阻值
T0 = 298.15    # 25℃对应的开尔文温度
B = 3435.0     # B值
R_pullup = 10000.0  # 上拉电阻
Vref = 3.3     # 参考电压
ADC_max = 4095 # 12位ADC

def ntc_resistance(temp_c):
    """计算NTC在给定温度下的阻值"""
    temp_k = temp_c + 273.15
    return R0 * math.exp(B * (1/temp_k - 1/T0))

def adc_value(temp_c):
    """计算给定温度对应的ADC值"""
    R_ntc = ntc_resistance(temp_c)
    v_out = Vref * R_ntc / (R_ntc + R_pullup)
    return int(v_out / Vref * ADC_max)

# 生成-40℃到60℃的表,步长1℃
print("const uint16_t ntc_table[] = {")
for temp in range(-40, 61):
    adc = adc_value(temp)
    if (temp - (-40)) % 5 == 0:
        print(f"    {adc:4d},  // {temp:3d}℃")
    else:
        print(f"    {adc:4d},", end="")
print("};")

避坑指南:我曾经在一个项目中,直接用了供应商提供的Excel表格里的数据,没自己验证。结果发现表格里的B值跟实际NTC的B值差了2%。量产了1000套,有300套温度偏差超过3℃。从那以后,我要求每批NTC来料都要抽测,用实测数据重新生成查表。

4.4 小结

温度采集这事儿,说难不难,说简单也不简单。核心就三点:

  • 选对传感器:NTC是主流,B值和阻值精度要盯紧。
  • 放对位置:极耳温度优先,别让传感器悬空。
  • 算对数据:查表法加线性插值,精度够用,效率也高。

嗯,今天就聊到这儿。温度采集这块,你还有什么想深挖的,随时可以问我。


专注资料整理