当前位置: 首页 > news >正文

SOC估算方法之(OCV-SOC+安时积分法)

一、引言

此方法主要参考电动汽车用磷酸铁锂电池SOC估算方法这篇论文

总结:

开路电压的测量需要将电池静止相当长的一段时间才能达到平衡状态进行测量。

安时积分法存在初始SOC的估算和累积的误差。

所以上述两种方法都存在一定的缺陷,因此下面主要讲解两种方法混合估算SOC的方法。

二、SOC估算流程图

三、SOC软件设计步骤

四、软件代码的书写

第一步:获取在不同温度时OCV-SOC的曲线

第二步:上电校准SOC

实际采样OCV和关机时保存的电压差超过200mV,那么此OCV可用于上电修正SOC,否则使用之前掉电保存的SOC

第三步:安时积分法

充电时:

//单节最高电压小于3600mV时,进行正常SOC积分

//单节最高电压大于3600mV时,调整SOC积分斜率(目的是充到保护电压时正好SOC=100%)

放电时:

//单节最低电压大于2900mV时,进行正常SOC积分

//单节最低电压小于2900mV时,调整SOC积分斜率(目的是放空时正好SOC=0%)

第四步:完整代码

#include "soc.h"
TLIFE tagLife;
unsigned char SBErrFlashCount;
const unsigned int OCV_SOC[3][38]=   
{{ //表0:电池温度为0℃时,OCV对应SOC2787,										  //0%2897,2992,3059,3107,3150, //1%-5%3159,3166,3172,3178,3184, //6%-10%3189,3195,3200,3205,3209, //11%-15%3214,3219,3223,3227,3231, //16%-20%3235,3238,3242,3246,3249, //21%-25%3252,3255,3258,3261,3264, //26%-30%3266,3269,3271,3274,3276, //31%-35%//此区域都给50%3334,3380,		          //99%-100% 	},{//表1:电池温度为20℃时,OCV对应SOC2837,										  //0%                       2947,3032,3095,3139,3178, //1%-5% 3184,3187,3191,3195,3198, //6%-10%  3202,3206,3210,3214,3218, //11%-15% 3223,3227,3231,3235,3239, //16%-20%  3243,3247,3251,3255,3258, //21%-25%  3262,3265,3269,3272,3275, //26%-30%  3277,3280,3282,3284,3286, //31%-35%  //此区域都给50%		3334,3380,		          //99%-100% 	 	},	{//表2:电池温度为30℃时,OCV对应SOC		2840,					  //0%                     2950,3034,3096,3140,3179, //1%-5%   3185,3188,3192,3195,3199, //6%-10%  3203,3207,3211,3215,3219, //11%-15% 3223,3227,3231,3235,3240, //16%-20%   3244,3248,3252,3256,3259, //21%-25%  3263,3267,3270,3273,3276, //26%-30%  3279,3282,3285,3287,3289, //31%-35%   //此区域都给50%3333,3360,		 		  //99%-100% 	}
};/************************************函数功能描述************************************************
Function Name : PowerONAdjustSOC(void)
Description   : 上电时修正SOC
Input         : 无
Output        : 无
*************************************************************************************************/
void PowerONAdjustSOC(void)
{unsigned int TempMinVoltage,DtV;if(FLASH.BeWriteFlag == ISNO)									  //FLASH数据无效时{tagLife.fRealTotalCapacity = tagLife.fNominalCapacity;   //电池实际总容量为标称容量(mA.h)tagLife.uiSOH_Percent = 100;                             //SOH为100%tagLife.uiDisTimes 	= 0;                                 //清0循环次数	tagLife.uiSOC_Percent = OCVtoSOC(tagBMS.uiMinVoltage);   //通过OCV获得SOCtagLife.fSOC = (tagLife.fNominalCapacity/100)*tagLife.uiSOC_Percent;  //通过SOC计算出当前容量	}	else //FLASH数据有效时{/****实际额定容量不能超过标称容量或不能小于标称容量的80%,否则进行修正****/if(tagLife.fRealTotalCapacity > tagLife.fNominalCapacity){ tagLife.fRealTotalCapacity = tagLife.fNominalCapacity; } else if(tagLife.fRealTotalCapacity < (tagLife.fNominalCapacity*0.5f)){ tagLife.fRealTotalCapacity = tagLife.fNominalCapacity; }TempMinVoltage = FLASH.ReadData[7];      //读取上次掉电前最低节电压if(tagBMS.uiMinVoltage > TempMinVoltage) //如果上电后实际采样OCV和关机时保存的电压差超过200mV,那么此OCV可用于上电修正SOC,否则使用之前掉电保存的SOC{DtV = tagBMS.uiMinVoltage - TempMinVoltage;}else{DtV = TempMinVoltage - tagBMS.uiMinVoltage;}	if( DtV >= 200 ) //压差过大,进行OCV修正{tagLife.uiSOC_Percent = OCVtoSOC(tagBMS.uiMinVoltage); 		//通过OCV重新获得SOCtagLife.fSOC = (tagLife.fNominalCapacity/100) * tagLife.uiSOC_Percent;  //通过SOC计算出当前电量}}	tagLife.ulWorkTime = 0;
}/************************************函数功能描述************************************************
Function Name : OCVtoSOC(unsigned int ocv)
Description   : 通过OCV获得SOC
Input         : OCV 开路电压值
Output        : SOC 电量值(%)
*************************************************************************************************/
unsigned int OCVtoSOC(unsigned int ocv) 
{unsigned char i=0,socarray=1,tempsoc;		获取电池温度,找对应数组	if(tagBMS.iNtcTemp[0] < 10) {socarray = 0; //电池温度小于10℃,选用表0}else if(tagBMS.iNtcTemp[0] < 25){socarray = 1; //电池温度10-25℃,选用表1}else {socarray = 2; //电池温度大于25℃,选用表2}电压查表得SOC		while(ocv > OCV_SOC[socarray][i]){i++;	if( i >= 38 ){ break; }} switch(i){case 36:  tempsoc = 50;  break; //平台区默认SOC=50%case 37:  tempsoc = 99;  break;		case 38:  tempsoc = 100; break;		default : tempsoc = i;   break;}return tempsoc;
}
/************************************函数功能描述************************************************
Function Name : CurrentIntegral(void)
Description   : 电流积分,10mS处理一次
Input         : 无
Output        : 无
*************************************************************************************************/
void CurrentIntegral(void)
{tagLife.fAddCapacity += tagBMS.ulBusCurrent;//单位mA
}/************************************函数功能描述************************************************
Function Name : PackSOCCalculate
Description   : SOC计算,1S执行一次
Input         : 无
Output        : 无
*************************************************************************************************/
void PackSOCCalculate(void)
{	FP32  ChgAf  = 0.93;   //充电电流补偿因子(调整充电时电量上升斜率,使其尽量接近充满时的斜率)FP32  DchgAf = 0.93;   //放电电流补偿因子(调整放电时电量下降斜率,使其尽量接近放空时的斜率)FP32           surtim;     //当前到满充或满放的时间,即:变化斜率 static INT     dtv;        //单位时间(这里为1S)电压变化值static UCHAR   cof,dcof;   //满充、满放标志	//放电时计算SOC		if(( tagSBS.bCell_DSGING_Status == ISYES )&&( tagSBS.bCell_CHGING_Status == ISNO )&&( dcof ==  ISNO ))//检测为放电状态,且不为满放{cof   = ISNO;  //清满充标志	if(tagBMS.uiMinVoltage > 2900)//单节最低电压大于2900mV时,进行正常SOC积分{tagLife.fAddCapacity = tagLife.fAddCapacity/360000; //加100次后求平均值,单位mA.S=>mA.H		if( tagLife.uiSOC_Percent <= 1 ){ tagLife.fAddCapacity = 0; } //防止最低节电压还未低于2900mV,电量就达到了0% 						tagLife.iDchgLastVoltag = tagBMS.uiMinVoltage;}						else//单节最低电压小于2900mV时,调整SOC积分斜率(目的是放空时正好SOC=0%){dtv = tagLife.iDchgLastVoltag - tagBMS.uiMinVoltage; //求1S后的电压变化值	tagLife.iDchgLastVoltag = tagBMS.uiMinVoltage;if( dtv > 0 ){				surtim = (tagBMS.uiMinVoltage - SET_UV)/dtv;    //求按照当前放电电流到放空剩余时间(S)				tagLife.fAddCapacity = tagLife.fSOC/surtim;     //求每次减少的容量 = 当前容量/到放空的时间   }else{tagLife.fAddCapacity = 0;		//电压未变化,容量增量为0						//tagLife.fAddCapacity = tagLife.fAddCapacity/360000; //加100次后求平均值,单位mA.S=>mA.H												}						}tagLife.fSOC = tagLife.fSOC - tagLife.fAddCapacity*DchgAf;     //单位mA.Hif( tagLife.fSOC <= 0 ){tagLife.fSOC = 0;                       //限制tagLife.ulSOC不小于0	}			tagLife.fTotalDisCapacity += tagLife.fAddCapacity; //累加放电容量(用于计算循环次数) if( tagLife.fTotalDisCapacity >= tagLife.fRealTotalCapacity ){tagLife.fTotalDisCapacity = 0; tagLife.uiDisTimes++;                   //如果放电累加容量达到额定容量,循环次数加一	} 	}/ //充电时计算SOCelse if((tagSBS.bCell_CHGING_Status == ISYES)&&( tagSBS.bCell_DSGING_Status == ISNO) &&( cof ==  ISNO ))//检测为充电状态,且不为满充{		dcof = ISNO;  //清满放标志	if(tagBMS.uiMaxVoltage < 3600)//单节最高电压小于3600mV时,进行正常SOC积分{tagLife.fAddCapacity = tagLife.fAddCapacity/360000;            //加100次后求平均值,单位mA.S=>mA.H	if( tagLife.uiSOC_Percent >= 99 ){ tagLife.fAddCapacity = 0; } //防止最高节电压还未超过3450mV,电量就达到了100% 			tagLife.iChgLastVoltag  = tagBMS.uiMaxVoltage;	}						else//单节最高电压大于3600mV时,调整SOC积分斜率(目的是充到保护电压时正好SOC=100%){dtv = tagBMS.uiMaxVoltage - tagLife.iChgLastVoltag;   //求每个时间周期后的电压变化值(1S)tagLife.iChgLastVoltag = tagBMS.uiMaxVoltage;if( dtv > 0 ){	surtim = (SET_OV - tagBMS.uiMaxVoltage)/dtv; //求按照当前充电电流到充满剩余时间(S)				tagLife.fAddCapacity = (tagLife.fRealTotalCapacity - tagLife.fSOC)/surtim; //求每次增加的容量=(总容量-当前容量)/到充满的时间  }else{tagLife.fAddCapacity = 0;		//电压未变化,容量增量为0		//tagLife.fAddCapacity = tagLife.fAddCapacity/360000;    //加100次后求平均值,单位mA.S=>mA.H												}		}tagLife.fSOC = tagLife.fSOC + tagLife.fAddCapacity*ChgAf;   //单位mA.Hif(tagLife.fSOC > tagLife.fRealTotalCapacity )           //充电时增加的总电量不能超过总容量{ tagLife.fSOC = tagLife.fRealTotalCapacity; }			}tagLife.uiSOC_Percent =(tagLife.fSOC*100)/tagLife.fRealTotalCapacity; //计算SOC值	if( tagLife.uiSOC_Percent >= 100 ) //满充{tagLife.uiSOC_Percent = 100;   //soc不能大于100%cof  = ISYES; //置满充标志	}else if( tagLife.uiSOC_Percent <= 1 ) //满放{tagLife.uiSOC_Percent = 1;    //soc不能小于1%				dcof  = ISYES; //置满放标志} tagLife.fAddCapacity = 0;	//将1S钟累加的容量清0,重新累加	tagLife.ulWorkTime++;     //计算工作时间(S)		//满放—满充对tagLife.RealQ修正if( tagSBS.bCell_UVS_Status == ISYES ) //AFE产生欠压保护(放电过程中){tagLife.bCellEmptyFlag = ISYES;   //电池放空标志		tagLife.fSOC = 0;                 //修正当前容量0mAH							}	if(( tagSBS.bCell_OVS_Status == ISYES )&&( tagBMS.ulBattV >= 5440 )) //AFE产生过压保护(充电过程中),且总电压大于54.4v{if( tagLife.bCellEmptyFlag == ISYES )     //如果电池放空过(说明电池进行了一次满放满充){tagLife.bCellEmptyFlag = ISNO; 		    //清除放空标志tagLife.fRealTotalCapacity = tagLife.fSOC;   //电池充满后变化值为电池实际额定容量	tagLife.uiSOH_Percent = (tagLife.fRealTotalCapacity*100)/tagLife.fNominalCapacity; //求电池SOH}														}							
}

相关文章:

SOC估算方法之(OCV-SOC+安时积分法)

一、引言 此方法主要参考电动汽车用磷酸铁锂电池SOC估算方法这篇论文 总结&#xff1a; 开路电压的测量需要将电池静止相当长的一段时间才能达到平衡状态进行测量。 安时积分法存在初始SOC的估算和累积的误差。 所以上述两种方法都存在一定的缺陷&#xff0c;因此下面主要讲…...

指针(下)

文章目录 指针(下)野指针、空指针野指针空指针 二级指针**main**函数的原型说明 常量指针与指针常量常量指针指针常量常量指针常量 动态内存分配常用函数**malloc****calloc****realloc****free** **void**与**void***的区别扩展&#xff1a;形式参数和实际参数的对应关系 指针…...

C# 浅谈IEnumerable

一、IEnumerable 简介 IEnumerable 是一个接口&#xff0c;它定义了对集合进行迭代所需的方法。IEnumerable 接口主要用于允许开发者使用foreach循环来遍历集合中的元素。这个接口定义了一个名为 GetEnumerator 的方法&#xff0c;该方法返回一个实现了 IEnumerator 接口的对象…...

mmdebstrap:创建 Debian 系统 chroot 环境的利器 ️

文章目录 mmdebstrap 的一般性参数说明 &#x1f4dc;mmdebstrap 的常见用法示例 &#x1f308;使用 mmdebstrap 的注意事项 ⚠️ &#x1f308;你好呀&#xff01;我是 山顶风景独好 &#x1f388;欢迎踏入我的博客世界&#xff0c;能与您在此邂逅&#xff0c;真是缘分使然&am…...

【Linux SQLite数据库】一、SQLite交叉编译与移植

SQLite 是一个用 C 语言编写的开源、轻量级、快速、独立且高可靠性的 SQL 数据库引擎&#xff0c;它提供了功能齐全的数据库解决方案。SQLite 几乎可以在所有的手机和计算机上运行&#xff0c;它被嵌入到无数人每天都在使用的众多应用程序中。此外&#xff0c;SQLite 还具有稳定…...

每天写两道(数组篇)移除元素、

27.移除元素 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素。元素的顺序可能发生改变。然后返回 nums 中与 val 不同的元素的数量。 假设 nums 中不等于 val 的元素数量为 k&#xff0c;要通过此题&#xff0c;您需要执行以下操作&#…...

Unity 使用 NewtonSoft Json插件报错

JsonReaderException: Unexpected character encountered while parsing value: . Path , line 0, position 0. 通过断点发现&#xff0c;头有一串ZWNBSP&#xff0c;这个是BOM格式的JSON。在文件下看不到。 解决方法&#xff1a;改编码格式&#xff0c;Remove BOM....

k8s 部署 Mysqld_exporter 以及添加告警规则

最近监控 mysql 数据库&#xff0c;用了 pmm-server、pmm-client 发现监控是真的不太好用&#xff0c;还是用回 prometheus 吧。 部署mysqld_exporter k8s 部署最新版本的 mysqld_exporter&#xff0c;支持的数据库版本 MySQL >5.6、MariaDB > 10.3。 先在数据库创建用…...

基于STM32开发的智能农业环境监测系统

目录 引言环境准备工作 硬件准备软件安装与配置系统设计 系统架构硬件连接代码实现 初始化代码控制代码应用场景 农田环境监测温室环境控制常见问题及解决方案 常见问题解决方案结论 1. 引言 智能农业环境监测系统通过集成多种环境传感器&#xff0c;实时监测土壤湿度、温度…...

【SQL】平均售价

目录 题目 分析 代码 题目 表&#xff1a;Prices ------------------------ | Column Name | Type | ------------------------ | product_id | int | | start_date | date | | end_date | date | | price | int | ---------------…...

存储器与CPU的连接

1.单块存储芯片与CPU的连接 单独的一块独立的存储芯片提供的线有&#xff1a;地址总线&#xff0c;数据总线&#xff0c;读写控制线&#xff0c;片选线&#xff0c;如果该存储器只有八根数据总线用于输出数据&#xff0c;而cpu一次可以读64位的数据呢&#xff1f; 我们可以将八…...

unity--webgl 访问本地index.html

目录 1:使用本地服务器 1.1 使用 Python 的 SimpleHTTPServer 1.2 使用 Node.js 的 http-server 2&#xff1a;让其他人通过 IP 地址来访问你的 Unity WebGL 项目 2.1: 确保服务器可访问 2.2 获取公共 IP 地址 2.3 配置本地服务器 1.使用 Python 的 SimpleHTTPServer 2…...

慢慢欣赏DPDK RTE_MAX_ETHPORTS的定义

DPDK代码里面&#xff0c;RTE_MAX_ETHPORTS是一个常见的宏定义&#xff0c;但是在.c和.h文件找不到其定义&#xff0c;在全文件搜索条件下&#xff0c;在config/meson.build找到这么一个定义 dpdk_conf.set(RTE_MAX_ETHPORTS, get_option(max_ethports)) 该宏定义是根据构建输…...

Java Nacos与Gateway的使用

Java系列文章目录 IDEA使用指南 Java泛型总结&#xff08;快速上手详解&#xff09; Java Lambda表达式总结&#xff08;快速上手详解&#xff09; Java Optional容器总结&#xff08;快速上手图解&#xff09; Java 自定义注解笔记总结&#xff08;油管&#xff09; Jav…...

前端项目中的Server-sent Events(SSE)项目实践及其与websocket的区别

前端项目中的Server-sent Events(SSE)项目实践 前言 在前端开发中&#xff0c;实时数据更新是提升用户体验的重要因素之一。Server-SentEvents(SSE)是一种高效的技术&#xff0c;允许服务器通过单向连接将实时数据推送到客户端。下面将从SSE的基本改变&#xff0c;使用场景展…...

《老俞闲话|唯爱和热情不可辜负》读后感

《老俞闲话&#xff5c;唯爱和热情不可辜负》读后感 俞敏洪先生的这篇讲话充满了深情与智慧&#xff0c;他以自己丰富的人生经历和教育实践&#xff0c;向我们展现了一位教育家对于教育事业的热爱和对教师角色的深刻理解。 情感真挚&#xff0c;触动人心 俞敏洪先生的讲话中流…...

C语言 ——— 在杨氏矩阵中查找具体的某个数

目录 何为杨氏矩阵 题目要求 代码实现 何为杨氏矩阵 可以把杨氏矩阵理解为一个二维数组&#xff0c;这个二维数组中的每一行从左到右是递增的&#xff0c;每一列从上到下是递增的 题目要求 在杨氏矩阵中查找具体的某个数 要求&#xff1a;时间复杂度小于O(N) 代码实现…...

DAI-Net: 基于对偶自适应交互网络的药物推荐算法

引言 DAI-Net: Dual Adaptive Interaction Network for Coordinated Medication Recommendation 论文链接&#xff1a;https://ieeexplore.ieee.org/document/10614809 代码链接&#xff1a;GitHub - obananas/DAI-Net 在现代医疗保健中&#xff0c;如何利用电子健康记录&a…...

haproxy高级功能及配置

章节 一、haproxy 基础用法 二、haproxy 高级用法 三、haproxy之ACL的使用 目录 1 基于cookie的会话保持 1.1 cookie命名&#xff0c;并赋予其值 1.2 验证cookie信息 1.2.1 Windows浏览器验证 1.2.2 Linux下虚拟机验证 2 IP透传 2.1 四层与七层透传的区别 2.2 七层IP透传 2.2…...

【前端】NodeJS:记账本案例优化(MongoDB数据库)

文章目录 1 字符串转为时间对象——Moment2 记账本实例优化 1 字符串转为时间对象——Moment Moment.js中文网&#xff1a;https://momentjs.cn/docs/#/parsing/。 npm install moment // 安装moment var moment require(moment); // require moment().format(); 2 记账本实…...

uniapp 对接腾讯云IM群组成员管理(增删改查)

UniApp 实战&#xff1a;腾讯云IM群组成员管理&#xff08;增删改查&#xff09; 一、前言 在社交类App开发中&#xff0c;群组成员管理是核心功能之一。本文将基于UniApp框架&#xff0c;结合腾讯云IM SDK&#xff0c;详细讲解如何实现群组成员的增删改查全流程。 权限校验…...

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…...

Vue记事本应用实现教程

文章目录 1. 项目介绍2. 开发环境准备3. 设计应用界面4. 创建Vue实例和数据模型5. 实现记事本功能5.1 添加新记事项5.2 删除记事项5.3 清空所有记事 6. 添加样式7. 功能扩展&#xff1a;显示创建时间8. 功能扩展&#xff1a;记事项搜索9. 完整代码10. Vue知识点解析10.1 数据绑…...

【Linux】shell脚本忽略错误继续执行

在 shell 脚本中&#xff0c;可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行&#xff0c;可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令&#xff0c;并忽略错误 rm somefile…...

反向工程与模型迁移:打造未来商品详情API的可持续创新体系

在电商行业蓬勃发展的当下&#xff0c;商品详情API作为连接电商平台与开发者、商家及用户的关键纽带&#xff0c;其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息&#xff08;如名称、价格、库存等&#xff09;的获取与展示&#xff0c;已难以满足市场对个性化、智能…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

QMC5883L的驱动

简介 本篇文章的代码已经上传到了github上面&#xff0c;开源代码 作为一个电子罗盘模块&#xff0c;我们可以通过I2C从中获取偏航角yaw&#xff0c;相对于六轴陀螺仪的yaw&#xff0c;qmc5883l几乎不会零飘并且成本较低。 参考资料 QMC5883L磁场传感器驱动 QMC5883L磁力计…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

蓝桥杯 2024 15届国赛 A组 儿童节快乐

P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡&#xff0c;轻快的音乐在耳边持续回荡&#xff0c;小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下&#xff0c;六一来了。 今天是六一儿童节&#xff0c;小蓝老师为了让大家在节…...