BMS——SOC、SOH算法梳理
void BmsSoc_gauging(void)
{
U32 soc_temp;//循环容量16位*100后会溢出
uint16 CellVoltage;
int32 Coulomb,k = 100,CoulombAve;
SoftSoc.AccCounter = 0;
Coulomb = (gAccCoulomb*10)/SOC_SAMPLE_TIME;//提取积分值,扩大了10倍(mAh)
CoulombAve = Coulomb/10;
gAccCoulomb = 0;
if(battery.BatSta == BatteryCharging)
{
Coulomb = (Coulomb*SOC_CHG_EFF)/1000;//根据充电效率计算充电累加
SoftSoc.CoulombK = 100;//积分器增益系数
}
else
{
k = CalcTempDsgCoff();//计算温度放电系数
SoftSoc.CoulombK = k*CalcDsgRate(AbsInt32(Coulomb))/100;//计算放电倍率
Coulomb = Coulomb*SoftSoc.CoulombK/100;
}
Coulomb = Coulomb/20; //单位换算回0.1mAh
if((-Coulomb) >= (int32)SoftSoc.RemainCap)
{
SoftSoc.RemainCap = 0;
}
else
{
SoftSoc.RemainCap += Coulomb;
//循环次数由放电容量计算
if(Coulomb < 0)
{
SoftSoc.TotalDsgCap += Coulomb;// 计算放电总循环容量,用于计算循环次数
}
if(SoftSoc.TotalDsgCap < 0)
{
if((AbsInt32(SoftSoc.TotalDsgCap)/100) >= ((U32)gsThrSoc.CycleCapacity*80/100))
{
SoftSoc.TotalDsgCap = 0;
gsThrSoc.CycleCount ++;
BmsEvent.CycleCount = gsThrSoc.CycleCount;//更新循环次数,更新循环容量
BmsEvent.Record = 1; //允许记录
BmsSoc_GetSoh(); //更新SOH
gsThrSoc.CycleCapacity = BmsSoc_GetCycleCap(100);//更新循环容量
//保存循环容量和循环次数
VirtualEEP_Write(EEP_dCycleCount, (uint8_t *)&gsThrSoc.CycleCount, 2,0);
VirtualEEP_Write(EEP_CycleCapacity,(uint8_t *)&gsThrSoc.CycleCapacity,2,1);//1——立即写
}
}
}
soc_temp = gsThrSoc.CycleCapacity;//用U32不会溢出
if(SoftSoc.RemainCap >= soc_temp * 100)
{
soc_temp = gsThrSoc.CycleCapacity;
SoftSoc.RemainCap = soc_temp * 100;
}
SoftSoc.Soc = SoftSoc.RemainCap/gsThrSoc.CycleCapacity;//更新SOC
//------------------------------------------------------------------
//极限电压强制计算,优先级最高
if(battery.BatSta == BatteryCharging)
{
CellVoltage = SoftSoc.CellVmaxAcc/SOC_SAMPLE_TIME;
if(CellVoltage >= (gsThrSoc.VoltageCap[10]))//满电100%电压
{
if(AbsInt32(CoulombAve) < CHG_END_COULOMB)//电流小于充电截止电流
{
SoftSoc.Soc = 100;
soc_temp = gsThrSoc.CycleCapacity;
SoftSoc.RemainCap = soc_temp * 100;
SoftSoc.SocStatus.B_bit.BATFull = 1;//容量学习标志
}
}
SoftSoc.ChargeCap += Coulomb;//累加本次充电容量
}
else
{
CellVoltage = SoftSoc.CellVminAcc/SOC_SAMPLE_TIME;
}
//------------------------------------------------------------------
//充电保护置100操作
if(SoftSoc.SocStatus.B_bit.EN_OVP100 == 0)
{
if(SoftSoc.Soc < 90)
SoftSoc.SocStatus.B_bit.EN_OVP100 = 1;
}
else
{
if((gBatStatus.B_bit.CELL_OV == TRUE)||(gBatStatus.B_bit.PACK_OV == 1))//发生充电保护时强制置100%
{
SoftSoc.Soc = 100;
soc_temp = gsThrSoc.CycleCapacity;
SoftSoc.RemainCap = soc_temp * 100;
SoftSoc.SocStatus.B_bit.BATFull = 1;
SoftSoc.SocStatus.B_bit.EN_OVP100 = 0;
}
}
//************************************容量学习功能*******************************************************//
if(SoftSoc.Soc < 100)
{
SoftSoc.SocStatus.B_bit.BATFull = 0;
}
if((SoftSoc.SocStatus.B_bit.EN_CALIB)&&(SoftSoc.SocStatus.B_bit.BATFull))
{
if(SoftSoc.Soc == 100) //判断是否满电
{
SoftSoc.SocStatus.B_bit.EN_CALIB = 0;
//学习到的容量值要在电池设计容量的(60%,120%)之间;
soc_temp = gsThrSoc.DesignCapacity*120;
if(SoftSoc.ChargeCap > soc_temp)
{
SoftSoc.ChargeCap = soc_temp;
}
else
{
//计算电池老化系数
soc_temp = BmsSoc_GetCycleCap(100); //计算理论循环容量
SoftSoc.AgingCoeff = (SoftSoc.ChargeCap/soc_temp) - 2;// 容量学习保留2%——充电效率用的100%
gsThrSoc.CycleCapacity = BmsSoc_GetCycleCap(SoftSoc.AgingCoeff); //更新循环容量
soc_temp = gsThrSoc.CycleCapacity;
SoftSoc.RemainCap = soc_temp * 100; //更新剩余容量
}
}
}
//----------------------------------------------------------------------
if((gBatStatus.B_bit.CELL_OV == TRUE)||(gBatStatus.B_bit.PACK_OV == 1)) //发生充电保护时强制置100%
{
SoftSoc.Soc = 100;
soc_temp = gsThrSoc.CycleCapacity;
SoftSoc.RemainCap = soc_temp * 100;
}
if((CellVoltage < gsThrSoc.DsgEndVol)||(gBatStatus.B_bit.CELL_UV == TRUE)) //截止电压
{
SoftSoc.Soc = 0;
SoftSoc.RemainCap = 0;
if(Ext_TempMin > SOC_TMP_ENABLE)
{
SoftSoc.SocStatus.B_bit.EN_CALIB = 1; //允许校准容量
}
}
}
//计算电量
void BmsSoc_Calculate(void)
{
uint16_t SocTmp = 0;
int32_t AccTemp;
if(++SoftSoc.PowOnDelay>10) //等待电压稳定
{
SoftSoc.PowOnDelay = 10;
}
else
{return;}
SoftSoc.CellVmaxAcc += Info.CellVmax;
SoftSoc.CellVminAcc += Info.CellVmin;
if(++SoftSoc.AccCounter >= SOC_SAMPLE_TIME)
{
BmsSoc_gauging(); //到达一个积分周期
SoftSoc.CellVmaxAcc = 0;
SoftSoc.CellVminAcc = 0;
}
AccTemp = gAccCoulomb;
//-------------------------------------------------------------------------
AccTemp = AccTemp*SoftSoc.CoulombK;//积分器增益系数
AccTemp = AccTemp/(SOC_S_TIME*100);
SoftSoc.RmCapTmp = SoftSoc.RemainCap + AccTemp;
if(SoftSoc.RmCapTmp < 0)//剩余容量缓存
{
SoftSoc.RmCapTmp = 0;
}
if(SoftSoc.RmCapTmp > ((U32)((U32)gsThrSoc.CycleCapacity * 100)))
{
SoftSoc.RmCapTmp = (U32)((U32)gsThrSoc.CycleCapacity * 100);
}
//**************通讯SOCOUT显示值计算********************************//
SocTmp = SoftSoc.RmCapTmp/gsThrSoc.CycleCapacity; //更新SOC
if(SocTmp<=99) //改善用户体验
{
SoftSoc.SocOut = SocTmp + 1;
}
else if(SocTmp >= 100)
{
SoftSoc.SocOut = 100;
}
if(SoftSoc.RemainCap == 0)
SoftSoc.SocOut = 0;
//******************强制清零点、置百点、****************************//
if((gBatStatus.B_bit.CELL_OV == TRUE)||(gBatStatus.B_bit.PACK_OV == 1)) //发生充电保护时强制置100%
{
SoftSoc.SocOut = 100;
SoftSoc.RemainCap = (U32)((U32)gsThrSoc.CycleCapacity * 100);
}
if(gBatStatus.B_bit.CELL_UV == TRUE) //截止电压
{
SoftSoc.SocOut = 0;
SoftSoc.RemainCap = 0;
}
//***************************************************************//
}