资讯动态

BMS中SOH与SOP估算策略:分开设计、算法落地与验收避坑

发布时间:2026/10/29 20:57:39 来源:尧图企业网站定制
简介面向电动汽车电池管理系统研发人员、高校学习者与动力电池算法入门者的技术总结文档聚焦BMS中电池健康状态与功率状态估算帮助读者梳理SOH、SOP的建模思路、适用条件与工程选型框架。文档按SOH三类方法耐久性模型开环、电池模型闭环、开路电压和SOP两类方法电池模型、电池内阻展开并整理SOH与SOP联合估算、优缺点比较穿插内阻与SOH关系模型、HPPC测试、参数辨识及加速老化实验案例便于对照算法原理、实验流程和工程取舍。文档还给出容量衰减定义、电池内阻在线辨识、复合脉冲法流程等细节方便从概念到实现逐步理解。资源包共1个docx文件约787KB内容集中适合检索、摘录与二次整理已有3674人学习下载可作为BMS状态估算知识梳理、方案对比与工程实践参考。1. 从一次低温限功率说起SOH 与 SOP 两套估算策略为什么要分开设计某整车项目冬季标定时遇到一个反直觉的现象仪表显示电量还有 32%驾驶员深踩加速踏板输出功率却被压在 45 kW 以下仪表亮起功率受限提示可诊断口读回来的 SOH 是 94%看上去电池还很健康。问题不在 SOH而在 SOP —— 低温下直流内阻翻倍10 秒峰值放电功率从 180 kW 量级掉到 60 kW 量级。SOH 回答的是“这块电池还剩多少容量”SOP 回答的是“此刻这一秒它能放出多大功率”两者输入不同、时间尺度不同、误差传播路径也不同硬塞进一个估算器里必然互相干扰。这套 BMS 中 SOH 与 SOP 的估算策略方案从需求边界、软件架构落位、单模块实现一直写到验收指标面向正在做电池管理系统毕设或课程设计的人也面向要交付一套可验收估算模块的从业者。2. 需求与总体架构双状态量在 BMS 软件里的落位2.1 SOH 与 SOP 的输入输出边界先划清楚工程上最容易出问题的不是算法本身而是接口没定死。SOH 按容量定义公式是 SOH(C_standard−C_fade)/C_standard×100%其中 C_fade 是已损失容量C_standard 是标称容量行业里那条 80% 的更换线IEEE 1188 中给出的判据就是它的告警阈值。它需要的是长周期信息累计安时、充电末端的 OCV 驻点、直流内阻的慢变化趋势、温度分区、循环次数。SOP 则完全相反它描述短时峰值功率典型取 10 秒或 30 秒窗口输入是当前 SOC、当前温度下的内阻、电压上下限、电流限值输出是千瓦级的功率数字每秒刷新。把这两个量的接口列成表后面所有模块都围着这张表写联调时少吵很多架。状态量主要输入输出更新周期精度目标SOH累计安时、OCV-SOC 标定表、直流内阻、温度、循环次数容量健康度百分比分钟级充电末端强制触发±3%SOPSOC、温度、直流内阻、电压上下限、电流限值、极化参数10 s 峰值充/放功率 kW1 s±5% 或 ±10 kWSOC电流、OCV、温度、可用容量0100%100 ms±2%注意表里 SOH 的输出写的是“百分比”而不是“安时”这是刻意的对外只暴露归一化健康度绝对容量留在模块内部避免上层应用拿到安时数后自己再算一遍算出两套不一致的容量。2.2 三层软件架构与任务调度周期估算模块在 BMS 软件里通常落在中间层我一般把它拆成三层信号层负责电流、电压、温度采样和零漂修正周期 10 ms估计层跑 SOC、SOH、SOP 三个观测器按各自时间尺度调度应用层拿估计结果做功率限制、热管理和仪表显示。在模块化电池管理系统MBMS架构下这三层还会按从控、主控拆分从控只负责采样与均衡估计层统一放在主控好处是所有状态量共享同一份时间基准。调度骨架可以先写成这样把周期和触发条件固化下来比散落在各处的 if 判断好维护得多# 估计层调度骨架单位 ms TASKS [ {name: soc_ekf, period: 100, trigger: always}, {name: sop_calc, period: 1000, trigger: always}, {name: soh_update, period: 60000, trigger: charge_tail or rest_ocv}, {name: param_ident, period: 30000, trigger: current_excitation}, ] def schedule(tick_ms, ctx): for t in TASKS: if tick_ms % t[period] ! 0: continue if t[trigger] charge_tail and not ctx.is_charge_tail: continue # 只有激励足够时才允许辨识内阻避免静置段污染参数 if t[trigger] current_excitation and abs(ctx.current) 10: continue run_task(t[name], ctx)这段代码的关键不在循环而在两个 gate充电末端触发和电流激励门限。SOH 的容量修正是强依赖工况的随便哪个时刻都去更新只会把估计值拉花内阻辨识同样静置或小电流段信噪比太低识别出来的 R0 基本是噪声。参数period按项目实际总线负载调整SOP 的 1 s 是下限再快没有意义因为热管理和功率限制的执行周期就在这个量级。2.3 数据链路与时序约束谁先算、谁等谁三个观测量之间存在硬依赖SOC 依赖可用容量可用容量来自 SOHSOP 依赖 SOC 和内阻而内阻又参与 SOH 的修正。如果时序不管冷启动那几十秒里就会出现“SOH 还没就绪SOC 用铭牌容量积分SOP 用默认内阻硬算”的连锁误差。我的处理方式是给每个量设一个“可信标志位 降级值”上电后 SOH 从上次下电时写入的非易失存储里读回标记为“缓存值”SOC 按缓存容量积分SOP 则统一乘以 0.8 的安全系数直到内阻辨识收敛再解除。时序上还有一条容易被忽略SOP 计算所用的内阻必须和 SOH 修正所用的内阻是同一个来源、同一个温度插值表。曾经有个项目两处各写了一份温度补偿系数夏天没问题一到零下就出现 SOP 显示还有 90 kW、实际 60 kW 就触发欠压保护的情况查了两周才发现是两份表不一致。这条血泪经验后来被我写进了接口规范所有温度相关的参数只允许存在一份标定表谁要用谁引用。3. SOH 估算落地开环模型、OCV 法与内阻特征三条路径3.1 开环耐久性模型解决什么、不解决什么基于耐久性模型的开环方法思路是从机理或外特性出发描述容量衰退固体电解质膜电阻随循环增长、电池端子电压抬升、活性锂损失把内部电化学过程的退化规律写成随循环次数和温度变化的函数直接预测容量衰减和内阻增长。它的价值在前期电芯选型、寿命包络设计、整车质保策略都靠这套模型给出趋势线。但开环方法不能当作在线估计的主路径。它是“按典型工况标定出来的平均人”个体差异、实际使用工况、温度历史一概不认跑上两年误差拉到 10 个点很常见。我通常把它放在两个位置一是作为 SOH 观测器的先验给闭环算法一个合理的初始值和变化速率上限二是作为异常检测的参照当在线估计值偏离开环预测超过阈值时报警提示可能存在的单体异常或采样故障。这个用法比拿它直接输出 SOH 靠谱得多。3.2 OCV-SOC 区间电量法只在曲线斜率大的地方用OCV 法的实验基础是一条被反复验证的结论电池容量衰减对 OCV 曲线形状的影响并不明显OCV 与 SOC 的对应关系在整个老化过程保持相对稳定。既然曲线不动那就在固定的 OCV 区间里看能充进或放出多少电量电量少了就是容量掉了。做法是在两个 OCV 驻点之间积分安时用实测安时比上标称安时。import numpy as np def soh_by_ocv_window(ocv_table, ocv_hi, ocv_lo, ah_measured, cap_nominal): ocv_table: [(soc, ocv), ...] 按 soc 升序标定 ah_measured: 两驻点之间实测积分安时Ah cap_nominal: 标称容量Ah socs np.array([p[0] for p in ocv_table], dtypefloat) ocvs np.array([p[1] for p in ocv_table], dtypefloat) # 由 OCV 反查 SOC必须单调段内插值平坦段直接拒绝 soc_hi float(np.interp(ocv_hi, ocvs, socs)) soc_lo float(np.interp(ocv_lo, ocvs, socs)) d_soc abs(soc_hi - soc_lo) if d_soc 0.20: # 区间太窄误差放大 5 倍以上 return None ah_nominal d_soc * cap_nominal soh ah_measured / ah_nominal return min(max(soh, 0.0), 1.0)有三个约束必须写进代码里。第一区间宽度门限d_soc小于 20% 直接返回空宁可不更新也不给错值。第二只用曲线斜率大的区间磷酸铁锂在中段 30%70% 电压几乎是平台几毫伏的采样误差就能对应十几个点的 SOC 偏差这一带做 OCV 法属于玄学。第三温度分区OCV-SOC 关系受温度影响非常明显至少要在 0 ℃、25 ℃、45 ℃ 三档分别标定中间温度插值否则冬天和夏天会算出两个 SOH。3.3 内阻特征参数法从加速老化试验到一次线性拟合内阻法的物理依据很直白容量衰减的过程通常伴随内阻增加。难点在于把“内阻—容量”这条关系标定准。原文给出的测试流程可以作为标准作业指导我把它整理成可复现的步骤将电池置于 25 ℃ 高低温交变湿热试验箱中先以 1 C 放电至截止电压 2.7 V静置 1 h以 1 C 恒流充电至 4.2 V转 4.2 V 恒压充电至电流降到 0.05 C 截止此时记录当前最大可充电量由容量定义直接得到当前 SOH静置 1 h以 1 C 恒流放电 0.1 h把 SOC 调到 90%静置 30 min以 0.2 C 充电 10 min每 1 s 记录一次充电电压以 0.2 C 放电 10 min每 1 s 记录一次放电电压以 1 C 放电 0.1 h 把 SOC 调到 80%重复步骤 1 至 9直到 SOC 降到 10%。每个循环 5 次后插一次内阻测试用步骤 7、8 的电压数据按能量法算出内阻同时用步骤 3 的最大可充电量算出 SOH就得到一对 (R, SOH) 样本。同一批次不同单体之间做归一化处理后内阻值与 SOH 通常呈现线性度很高的一次函数关系拟合与反解可以这样写import numpy as np def fit_r_soh(samples): samples: [{soh: 0.95, r_mohm: 2.10}, ...] 返回 R a*SOH b 的系数与拟合优度 soh np.array([s[soh] for s in samples], dtypefloat) r np.array([s[r_mohm] for s in samples], dtypefloat) a, b np.polyfit(soh, r, 1) # 内阻随 SOH 下降而上升a 应为负 pred a * soh b ss_res float(np.sum((r - pred) ** 2)) ss_tot float(np.sum((r - r.mean()) ** 2)) r2 1.0 - ss_res / ss_tot return a, b, r2 def soh_from_r(r_meas, a, b, r_limit0.15): r_meas 为温度归一化后的内阻a 接近 0 时直接拒绝输出 if abs(a) 1e-6: return None soh (r_meas - b) / a return min(max(soh, 0.0), 1.0)参数说明几个关键点a必须为负如果拟合出来是正的说明样本里混了不同温度或不同批次的数据先清洗再谈精度r2低于 0.9 时这条线性关系在本批次上不成立别硬用r_meas一定要先做温度归一化同一块电池 25 ℃ 和 −10 ℃ 的内阻能差一倍以上不归一化的内阻法在实车上没有意义。这个模型的优点是测试方法简单、参数识别快捷缺点也明显它对温度极度敏感且单体内阻差异会直接放大成 SOH 误差所以我一般让内阻法只做修正通道主通道还是容量法。3.4 闭环修正RLS 与卡尔曼滤波的角色分配开环和特征法给出了“慢趋势”闭环负责把趋势拉回真实值。常见组合是递推最小二乘法在线辨识等效电路模型参数卡尔曼滤波估计 SOC再用容量观测器修正 SOH。多时间尺度联合估计有两种典型做法一种是双时间尺度卡尔曼滤波先用递推最小二乘法识别一阶或二阶 RC 模型的标称参数对 SOC 的依赖关系量化模型性能退化一个观测器实时估 SOC另一个离线估 SOH用模型精度退化程度反过来确定 SOH 观测器的时间尺度另一种是把等效电路模型与可用容量变化直接关联建立集总参数模型宏观尺度估 SOH、微观尺度估 SOC两路估计器把不同时间尺度的测量信息融合起来在 NEDC 工况下同时收敛。落到代码上宏观与微观的比例关系是核心参数我一般取 1:300 左右即 SOC 每 100 ms 一步、SOH 每 30 s 一步。SOH 那一路必须加变化率限幅单步修正不超过 0.5%否则一次异常充电就能把健康度从 95% 拉到 88%用户第二天看到续航凭空少 30 km 会直接投诉。# 宏观/微观双尺度调度示意 MICRO_STEP_MS 100 MACRO_RATIO 300 # 30 s 更新一次 SOH MAX_SOH_STEP 0.005 # 单次修正上限 0.5% def joint_estimate(k, ctx): soc ekf_micro_step(ctx) # 微观SOC 每 100 ms 更新 if k % MACRO_RATIO 0: soh_raw macro_observer(ctx, soc) # 宏观基于容量/内阻的慢观测 delta soh_raw - ctx.soh ctx.soh max(-MAX_SOH_STEP, min(MAX_SOH_STEP, delta)) ctx.cap_usable ctx.cap_nominal * ctx.soh # 回灌给 SOC 使用 return soc, ctx.soh最后一行cap_usable的回灌是整套方案里最容易被跳过、也最容易翻车的一步。SOH 更新完不回灌容量SOC 的安时积分仍然用旧容量在跑两个量就会长期各说各话越跑越偏。4. SOP 估算落地HPPC 复合脉冲法与多约束二分查找4.1 HPPC 测试流程与 10 秒峰值功率标定复合脉冲法是工程上用得最广、实现也最简单的一类 SOP 估计方法它基于内阻模型用当前 SOC 下的开路电压和内阻推算瞬时峰值功率。它的短板要提前说清楚模型简单、计算量小但实车电流变化剧烈而且传统复合脉冲法没有把充放电电流阈值和 SOC 限制纳入约束估出来的峰值功率偏大看着漂亮真到急加速时会直接触发欠压保护。混合脉冲功率特性HPPC测试是它的标准实现。流程是先用恒流恒压把电池充满再恒流放到某个 SOC 点静置 1 h然后脉冲放电 10 s、静置 40 s、脉冲充电 10 sSOC 从 90% 每隔 10% 降到 10%共九轮。10 s 这个窗口不是拍脑袋定的城市工况急加速持续时间约 10 s高速工况约 25 s紧急制动在城市工况 510 s、高速工况 33 s取 10 s 放电峰值功率作为 SOP 的定义值覆盖面最广。def hppc_discharge_power(ocv_dis, v_pulse_end, i_pulse, v_min): ocv_dis: 脉冲前开路电压v_pulse_end: 脉冲末端电压 i_pulse: 脉冲电流v_min: 放电截止电压 r_dis (ocv_dis - v_pulse_end) / i_pulse # 放电直流内阻 if r_dis 0: return None # 内阻为负采样或时序有问题 p_dis v_min * (ocv_dis - v_min) / r_dis # 10 s 峰值放电功率 return r_dis, p_disr_dis出现负值是最常见的异常八成是脉冲开始时刻和电压采样没对齐或者静置时间不够、极化没消。p_dis的公式本质是把负载看成纯阻性端电压降到下限时能输出的功率实际标定时还要乘一个安全系数通常取 0.9。4.2 功率模型的参数化SOC、内阻、温度三个输入把上面的计算在每个 SOC 点和每个温度点都跑一遍就得到一张二维标定表模型形式是 P_adj f(SOC, R_adj, T)其中 R_adj 是温度修正后的内阻3.0 V 是电池下限电压SOC、内阻、温度是输入峰值功率是输出。这张表通常在 −10 ℃、0 ℃、25 ℃、45 ℃ 四个温度点、九个 SOC 点上标定共 36 个节点实车上用双线性插值取值。插值本身不难难的是标定点的边界处理。低于最低标定温度时不能外推直接取最低温那一档的值再打八折高于最高标定温度时同理。外推出来的功率没有任何实验支撑夏天高温时外推得到的高功率会让整车以为还能满功率输出实际一踩就过热保护。4.3 多参数约束法与二分查找实现真正能上车的做法是把电压、电流、SOC 三个约束同时纳入预测 10 s 持续峰值功率。SOC 约束给出允许的最大充放电电流电压约束给出端电压不越界的电流上限两者取小之后再在功率域上做二分查找找到满足所有约束的最大功率。恒功率工况下端电压和功率的关系可以解析求解放电时 V (OCV − √(OCV² − 4PR)) / 2充电时取加号那一支。有了这个关系二分就不用反复迭代电路方程了。import math def v_at_power(ocv, r, p, dischargeTrue): 恒功率下的端电压解析解返回 (V, I)无解返回 (None, None) sign 1.0 if discharge else -1.0 disc ocv * ocv - 4.0 * r * p * sign if disc 0: return None, None v (ocv - math.sqrt(disc)) / 2.0 if discharge else (ocv math.sqrt(disc)) / 2.0 if v 0: return None, None return v, p / v def peak_power_bisect(ocv, r, v_lim, i_lim, dischargeTrue, iters30): 二分查找满足电压与电流双约束的最大功率 lo, hi 0.0, v_lim * i_lim * 2.0 # 上界放宽保证解在区间内 for _ in range(iters): mid (lo hi) / 2.0 v, i v_at_power(ocv, r, mid, discharge) ok (v is not None) and (v v_lim if discharge else v v_lim) and (i i_lim) if ok: lo mid else: hi mid return lo * 0.9 # 留 10% 安全裕度iters30对 30 次二分已经能把区间收敛到 1e-9 量级实际 15 次足够多算只是浪费 CPU。i_lim取 SOC 约束电流与硬件电流上限的较小值放电时v_lim是 3.0 V 下限充电时是 4.2 V 上限函数里通过discharge开关切换。最后乘的 0.9 是安全裕度这个系数不要省模型误差、采样误差、单体不一致全在这 10% 里消化。4.4 非参数模型与黑箱方法的适用边界支持向量机、机器学习这类非参数模型把 SOP 当成一个黑箱拟合问题输入 SOC、温度、内阻、历史电流统计特征输出峰值功率。它在训练集覆盖的工况内精度可以做得很高但和所有黑箱模型一样需要大量数据训练、训练时间长换一款电芯就得重新采数据重训泛化到没见过的温度区间表现不可控。我的建议是把位置分清车端在线估计用参数化模型加多约束可解释、可标定、可复现非参数模型放在云端或离线标定环节用来生成和校准那张二维功率表或者做异常检测的对照。这样既不浪费数据侧的能力也不会把不可解释的黑箱塞进安全相关链路里。5. 避坑与排查联合估计里最容易翻车的五处现场5.1 五个高频故障的现象、原因与处置第一条SOH 会跳变甚至超过 100%。现象是换季标定时 SOH 从 96% 跳到 103%诊断报文里容量比标称还大。原因通常是分母用了铭牌额定容量没有做温度和倍率修正低温大倍率放电时实际可放出容量本来就小于额定值算出来自然偏高。处置办法是把容量基准定义成一个明确工况25 ℃、0.33 C所有容量测量先归一化到这个工况再比较。第二条OCV 法在平台区给出离谱结果。现象是磷酸铁锂电池在 50% SOC 附近每次充电都能算出不同的 SOH波动能到 8 个点。原因就是前面说的曲线平坦段几毫伏误差放大成十几个点 SOC。处置是加区间宽度门限d_soc低于 20% 直接拒绝更新并且只在充电末端静置足够久、极化充分消退时触发。第三条内阻没做温度归一化冬季 SOP 直接砍半。现象是零下十度早上第一脚电门SOP 显示 60 kW实际 40 kW 就欠压。原因是低温内阻本身就在上升再加上温度补偿表缺失或只有一份常温表双重放大。处置是内阻辨识结果统一折算到 25 ℃ 基准温度分区至少四档标定表只有一份谁用谁引用。第四条SOH 更新后没回灌容量SOC 长期漂移。现象是同一台车同一段路表显电量消耗比实际充电量少 5%跑长途时续航估算越来越乐观。原因是 SOH 模块算完自己存着SOC 的安时积分还在用出厂容量。处置是把可用容量作为唯一可信源SOH 更新后立即回灌并且加变化率限幅与迟滞防止抖动。第五条峰值功率估大急加速触发欠压保护。现象是 SOP 报 180 kW实际输出到 120 kW 就报欠压故障。原因是直接用了复合脉冲法的简化公式没纳入电流阈值和 SOC 限制模型把电池当成了理想电压源。处置是切到多参数约束加二分查找输出再乘安全裕度并且把 SOP 的下降沿做成速率限制避免功率限值一秒内跳变引发驾驶性抱怨。5.2 排查顺序与必须埋的日志点出问题时不要一上来就怀疑算法。我的排查顺序固定为四步先看信号质量电流零漂、电压采样同步、温度探头位置再看模型参数辨识出来的 R0、R1、C1 是否在物理合理区间再看约束与限幅是不是某一层限幅把结果吃掉了最后才回头查标定表和拟合系数。百分之七十的问题出在前两步算法本身反而是最不容易错的。日志埋点也要按这个顺序设计每个环节输出中间量而不是只输出最终值def log_snapshot(ctx): return { t_ms: ctx.tick, i_raw: ctx.current, i_zero_drift: ctx.i_offset, v_cell_min: ctx.v_min, v_cell_max: ctx.v_max, t_cell: ctx.temp, r0_mohm: ctx.r0, r0_norm25: ctx.r0_norm, # 归一化前后都记 soc: ctx.soc, soh_raw: ctx.soh_raw, soh_out: ctx.soh, sop_raw_kw: ctx.sop_raw, sop_out_kw: ctx.sop, limit_flag: ctx.limit_flag, # 哪一层限的幅 }limit_flag这个字段看起来不起眼但它能一眼看出结果是被电压约束、电流约束还是安全裕度限掉的省掉大量“为什么功率上不去”的扯皮。r0和r0_norm同时记录是为了区分“内阻真的涨了”和“温度补偿算错了”这两个原因的处理方式完全不同。6. 验收与答辩怎么证明这套估算策略站得住验收不要只报一个平均误差那样很容易被问穿。我一般准备一张三列的表指标、测试条件、判定门限。SOH 精度看三个工况下的最大偏差常温满充满放、低温大倍率、高温存储后门限 ±3%SOP 看 10 s 峰值功率与实际触发保护功率的差值门限 ±5% 或不超 10 kW收敛性看从冷启动到 SOH 稳定的时间门限 30 min 内鲁棒性做故障注入人为把某一路温度采样置为无效值看系统是否降级而不是输出错误值。验收项测试条件判定门限SOH 精度25 ℃、0 ℃、45 ℃ 三档满充满放最大偏差 ≤ ±3%SOP 精度10 s 脉冲SOC 20%90%偏差 ≤ ±5% 或 10 kW收敛时间冷启动至上电稳定≤ 30 min工况覆盖NEDC 及城市/高速典型工况全程无越界保护误触发故障降级温度或电流采样失效注入输出降级值并置故障位答辩时讲三个数就够了误差带、收敛时间、失效兜底。误差带说明精度收敛时间说明工程可用性失效兜底说明你敢不敢把这块代码放上车。最容易被追问的是“你的 SOH 和 SOC 会不会互相带偏”这时候把 3.4 节那段回灌逻辑和变化率限幅讲出来再补一句“SOH 单步修正不超过 0.5%”基本就稳了。从那次两份温度表打架的事之后我每次做状态估计都强制走一遍“接口对齐—单一标定源—中间量落日志”这三步哪怕工期再紧也不跳过。这套流程不玄学就是把每个可能出错的地方提前钉死。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑