|
@@ -0,0 +1,674 @@
|
|
|
|
+import pandas as pd
|
|
|
|
+import numpy as np
|
|
|
|
+import matplotlib.pyplot as plt
|
|
|
|
+# from pymysql import paramstyle
|
|
|
|
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import BatParam
|
|
|
|
+
|
|
|
|
+class BatInterShort():
|
|
|
|
+ def __init__(self,sn,celltype,df_bms,df_soh,df_last,df_last1,df_last2,df_last3,df_lfp): #参数初始化
|
|
|
|
+
|
|
|
|
+ if (not df_lfp.empty) and celltype>50:
|
|
|
|
+ df_lfp.drop(['sn'],axis=1)
|
|
|
|
+ df_bms=pd.concat([df_lfp, df_bms], ignore_index=True)
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+
|
|
|
|
+ self.sn=sn
|
|
|
|
+ self.celltype=celltype
|
|
|
|
+ self.param=BatParam.BatParam(celltype)
|
|
|
|
+ self.df_bms=df_bms
|
|
|
|
+ self.packcrnt=df_bms['总电流[A]']*self.param.PackCrntDec
|
|
|
|
+ self.packvolt=df_bms['总电压[V]']
|
|
|
|
+ self.bms_soc=df_bms['SOC[%]']
|
|
|
|
+ self.bmstime= pd.to_datetime(df_bms['时间戳'], format='%Y-%m-%d %H:%M:%S')
|
|
|
|
+
|
|
|
|
+ self.df_soh=df_soh
|
|
|
|
+ self.df_last=df_last
|
|
|
|
+ self.df_last1=df_last1
|
|
|
|
+ self.df_last2=df_last2
|
|
|
|
+ self.df_last3=df_last3
|
|
|
|
+ self.df_lfp=df_lfp
|
|
|
|
+
|
|
|
|
+ self.cellvolt_name=['单体电压'+str(x) for x in range(1,self.param.CellVoltNums+1)]
|
|
|
|
+ self.celltemp_name=['单体温度'+str(x) for x in range(1,self.param.CellTempNums+1)]
|
|
|
|
+
|
|
|
|
+ def intershort(self):
|
|
|
|
+ if self.celltype<=50:
|
|
|
|
+ df_res, df_ram_last, df_ram_last1, df_ram_last3=self._ncm_intershort()
|
|
|
|
+ return df_res, df_ram_last, df_ram_last1,self.df_last2, df_ram_last3,self.df_lfp
|
|
|
|
+
|
|
|
|
+ else:
|
|
|
|
+ df_res, df_ram_last, df_ram_last1, df_ram_last2, df_ram_last3, df_ram_lfp=self._lfp_intershort()
|
|
|
|
+ return df_res, df_ram_last, df_ram_last1, df_ram_last2, df_ram_last3, df_ram_lfp
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ #定义滑动滤波函数....................................................................................
|
|
|
|
+ def _np_move_avg(self,a, n, mode="same"):
|
|
|
|
+ return (np.convolve(a, np.ones((n,)) / n, mode=mode))
|
|
|
|
+
|
|
|
|
+ #寻找当前行数据的最小温度值.............................................................................
|
|
|
|
+ def _celltemp_weight(self,num):
|
|
|
|
+ celltemp = list(self.df_bms.loc[num,self.celltemp_name])
|
|
|
|
+ celltemp=np.mean(celltemp)
|
|
|
|
+ self.celltemp=celltemp
|
|
|
|
+ if self.celltype==99:
|
|
|
|
+ if celltemp>=25:
|
|
|
|
+ self.tempweight=1
|
|
|
|
+ self.StandardStandingTime=3600
|
|
|
|
+ elif celltemp>=15:
|
|
|
|
+ self.tempweight=0.6
|
|
|
|
+ self.StandardStandingTime=7200
|
|
|
|
+ elif celltemp>=5:
|
|
|
|
+ self.tempweight=0.
|
|
|
|
+ self.StandardStandingTime=10800
|
|
|
|
+ else:
|
|
|
|
+ self.tempweight=0.1
|
|
|
|
+ self.StandardStandingTime=10800
|
|
|
|
+ else:
|
|
|
|
+ if celltemp>=20:
|
|
|
|
+ self.tempweight=1
|
|
|
|
+ self.StandardStandingTime=3600
|
|
|
|
+ elif celltemp>=10:
|
|
|
|
+ self.tempweight=0.8
|
|
|
|
+ self.StandardStandingTime=3600
|
|
|
|
+ elif celltemp>=5:
|
|
|
|
+ self.tempweight=0.6
|
|
|
|
+ self.StandardStandingTime=7200
|
|
|
|
+ else:
|
|
|
|
+ self.tempweight=0.2
|
|
|
|
+ self.StandardStandingTime=10800
|
|
|
|
+
|
|
|
|
+ #获取当前行所有电压数据........................................................................................
|
|
|
|
+ def _cellvolt_get(self,num):
|
|
|
|
+ cellvolt = np.array(self.df_bms.loc[num,self.cellvolt_name])/1000
|
|
|
|
+ return cellvolt
|
|
|
|
+
|
|
|
|
+ #获取当前行所有soc差...........................................................................................
|
|
|
|
+ def _celldeltsoc_get(self,num,dict_baltime,capacity):
|
|
|
|
+ cellsoc=[]
|
|
|
|
+ celldeltsoc=[]
|
|
|
|
+ for j in range(1, self.param.CellVoltNums+1): #获取每个电芯电压对应的SOC值
|
|
|
|
+ cellvolt=self.df_bms.loc[num,'单体电压' + str(j)]/1000
|
|
|
|
+ ocv_soc=np.interp(cellvolt,self.param.LookTab_OCV,self.param.LookTab_SOC)
|
|
|
|
+ if j in dict_baltime.keys():
|
|
|
|
+ ocv_soc=ocv_soc+dict_baltime[j]*self.param.BalCurrent/(capacity*3600) #补偿均衡电流
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+ cellsoc.append(ocv_soc)
|
|
|
|
+
|
|
|
|
+ if self.celltype==1 or self.celltype==2:
|
|
|
|
+ consum_num=7
|
|
|
|
+ cellsoc1=cellsoc[:self.param.CellVoltNums-consum_num] #切片,将bms耗电的电芯和非耗电的电芯分离开
|
|
|
|
+ cellsocmean1=(sum(cellsoc1)-max(cellsoc1)-min(cellsoc1))/(len(cellsoc1)-2)
|
|
|
|
+ cellsoc2=cellsoc[self.param.CellVoltNums-consum_num:]
|
|
|
|
+ cellsocmean2=(sum(cellsoc2)-max(cellsoc2)-min(cellsoc2))/(len(cellsoc2)-2)
|
|
|
|
+
|
|
|
|
+ for j in range(len(cellsoc)): #计算每个电芯的soc差
|
|
|
|
+ if j<self.param.CellVoltNums-consum_num:
|
|
|
|
+ celldeltsoc.append(cellsoc[j]-cellsocmean1)
|
|
|
|
+ else:
|
|
|
|
+ celldeltsoc.append(cellsoc[j]-cellsocmean2)
|
|
|
|
+ return np.array(celldeltsoc), np.array(cellsoc)
|
|
|
|
+
|
|
|
|
+ else:
|
|
|
|
+ cellsocmean=(sum(cellsoc)-max(cellsoc)-min(cellsoc))/(len(cellsoc)-2)
|
|
|
|
+ for j in range(len(cellsoc)): #计算每个电芯的soc差
|
|
|
|
+ celldeltsoc.append(cellsoc[j]-cellsocmean)
|
|
|
|
+ return np.array(celldeltsoc), np.array(cellsoc)
|
|
|
|
+
|
|
|
|
+ #获取所有电芯的As差
|
|
|
|
+ def _cellDeltAs_get(self,chrg_st,chrg_end,dict_baltime):
|
|
|
|
+ cellAs=[]
|
|
|
|
+ celldeltAs=[]
|
|
|
|
+ for j in range(1, self.param.CellVoltNums+1): #获取每个电芯电压>峰值电压的充入As数
|
|
|
|
+ if j in dict_baltime.keys(): #补偿均衡电流
|
|
|
|
+ As=-self.param.BalCurrent*dict_baltime[j]
|
|
|
|
+ else:
|
|
|
|
+ As=0
|
|
|
|
+ As_tatol=0
|
|
|
|
+ symbol=0
|
|
|
|
+ for m in range(chrg_st+1,chrg_end):
|
|
|
|
+ As=As-self.packcrnt[m]*(self.bmstime[m]-self.bmstime[m-1]).total_seconds()
|
|
|
|
+ if symbol<5:
|
|
|
|
+ if self.df_bms.loc[m,'单体电压'+str(j)]/1000>self.param.PeakCellVolt[symbol]:
|
|
|
|
+ As_tatol=As_tatol+As
|
|
|
|
+ symbol=symbol+1
|
|
|
|
+ else:
|
|
|
|
+ continue
|
|
|
|
+ else:
|
|
|
|
+ cellAs.append(As_tatol/5)
|
|
|
|
+ break
|
|
|
|
+
|
|
|
|
+ if self.celltype==99:
|
|
|
|
+ consum_num=10
|
|
|
|
+ cellAs1=cellAs[:self.param.CellVoltNums-consum_num] #切片,将bms耗电的电芯和非耗电的电芯分离开
|
|
|
|
+ cellAsmean1=(sum(cellAs1)-max(cellAs1)-min(cellAs1))/(len(cellAs1)-2)
|
|
|
|
+ cellAs2=cellAs[self.param.CellVoltNums-consum_num:]
|
|
|
|
+ cellAsmean2=(sum(cellAs2)-max(cellAs2)-min(cellAs2))/(len(cellAs2)-2)
|
|
|
|
+
|
|
|
|
+ for j in range(len(cellAs)): #计算每个电芯的soc差
|
|
|
|
+ if j<self.param.CellVoltNums-consum_num:
|
|
|
|
+ celldeltAs.append(cellAs[j]-cellAsmean1)
|
|
|
|
+ else:
|
|
|
|
+ celldeltAs.append(cellAs[j]-cellAsmean2)
|
|
|
|
+ else:
|
|
|
|
+ cellAsmean=(sum(cellAs)-max(cellAs)-min(cellAs))/(len(cellAs)-2)
|
|
|
|
+ for j in range(len(cellAs)): #计算每个电芯的soc差
|
|
|
|
+ celldeltAs.append(cellAs[j]-cellAsmean)
|
|
|
|
+
|
|
|
|
+ return np.array(celldeltAs)
|
|
|
|
+
|
|
|
|
+ #计算每个电芯的均衡时长..........................................................................................................................
|
|
|
|
+ def _bal_time(self,dict_bal):
|
|
|
|
+ dict_baltime={}
|
|
|
|
+ dict_baltime1={}
|
|
|
|
+ for key in dict_bal:
|
|
|
|
+ count=1
|
|
|
|
+ x=eval(key)
|
|
|
|
+ while x>0:
|
|
|
|
+ if x & 1==1: #判断最后一位是否为1
|
|
|
|
+ if count in dict_baltime.keys():
|
|
|
|
+ dict_baltime[count] = dict_baltime[count] + dict_bal[key]
|
|
|
|
+ else:
|
|
|
|
+ dict_baltime[count] = dict_bal[key]
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+ count += 1
|
|
|
|
+ x >>= 1 #右移一位
|
|
|
|
+
|
|
|
|
+ dict_baltime=dict(sorted(dict_baltime.items(),key=lambda dict_baltime:dict_baltime[0]))
|
|
|
|
+ for key in dict_baltime: #解析均衡的电芯编号
|
|
|
|
+ if self.celltype==1: #科易6040
|
|
|
|
+ if key<14:
|
|
|
|
+ dict_baltime1[key]=dict_baltime[key]
|
|
|
|
+ elif key<18:
|
|
|
|
+ dict_baltime1[key-1]=dict_baltime[key]
|
|
|
|
+ else:
|
|
|
|
+ dict_baltime1[key-3]=dict_baltime[key]
|
|
|
|
+ elif self.celltype==1: #科易4840
|
|
|
|
+ if key<4:
|
|
|
|
+ dict_baltime1[key-1]=dict_baltime[key]
|
|
|
|
+ elif key<8:
|
|
|
|
+ dict_baltime1[key-1]=dict_baltime[key]
|
|
|
|
+ elif key<14:
|
|
|
|
+ dict_baltime1[key-3]=dict_baltime[key]
|
|
|
|
+ elif key<18:
|
|
|
|
+ dict_baltime1[key-4]=dict_baltime[key]
|
|
|
|
+ else:
|
|
|
|
+ dict_baltime1[key-6]=dict_baltime[key]
|
|
|
|
+ else:
|
|
|
|
+ dict_baltime1=dict_baltime
|
|
|
|
+ return dict_baltime1
|
|
|
|
+
|
|
|
|
+ #三元电池的内短路电流计算...........................................................................................................................................................
|
|
|
|
+ def _ncm_intershort(self):
|
|
|
|
+ df_res=pd.DataFrame(columns=['time_st', 'time_sp', 'sn', 'method','short_current','baltime'])
|
|
|
|
+ df_ram_last=self.df_last
|
|
|
|
+ df_ram_last1=self.df_last1
|
|
|
|
+ df_ram_last3=self.df_last3
|
|
|
|
+
|
|
|
|
+ #容量初始化
|
|
|
|
+ if self.df_soh.empty:
|
|
|
|
+ batsoh=self.df_bms.loc[0,'SOH[%]']
|
|
|
|
+ capacity=self.param.Capacity*batsoh/100
|
|
|
|
+ else:
|
|
|
|
+ batsoh=self.df_soh.loc[len(self.df_soh)-1,'soh']
|
|
|
|
+ capacity=self.param.Capacity*batsoh/100
|
|
|
|
+
|
|
|
|
+ #参数初始化
|
|
|
|
+ if df_ram_last.empty:
|
|
|
|
+ firsttime=1
|
|
|
|
+ dict_bal={}
|
|
|
|
+ else:
|
|
|
|
+ deltsoc_last=df_ram_last.loc[0,'deltsoc']
|
|
|
|
+ cellsoc_last=df_ram_last.loc[0,'cellsoc']
|
|
|
|
+ time_last=df_ram_last.loc[0,'time']
|
|
|
|
+ firsttime=0
|
|
|
|
+ dict_bal={}
|
|
|
|
+ if df_ram_last1.empty:
|
|
|
|
+ firsttime1=1
|
|
|
|
+ dict_bal1={}
|
|
|
|
+ else:
|
|
|
|
+ deltsoc_last1=df_ram_last1.loc[0,'deltsoc1']
|
|
|
|
+ time_last1=df_ram_last1.loc[0,'time1']
|
|
|
|
+ firsttime1=0
|
|
|
|
+ dict_bal1={}
|
|
|
|
+ if df_ram_last3.empty:
|
|
|
|
+ standingtime=0
|
|
|
|
+ standingtime1=0
|
|
|
|
+ else:
|
|
|
|
+ standingtime=df_ram_last3.loc[0,'standingtime']
|
|
|
|
+ standingtime1=df_ram_last3.loc[0,'standingtime1']
|
|
|
|
+ dict_bal1={}
|
|
|
|
+ if abs(self.packcrnt[0])<0.01 and standingtime>1 and standingtime1>1:
|
|
|
|
+ standingtime=standingtime+(self.bmstime[0]-df_ram_last3.loc[0,'time3']).total_seconds()
|
|
|
|
+ standingtime1=standingtime1+(self.bmstime[0]-df_ram_last3.loc[0,'time3']).total_seconds()
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+
|
|
|
|
+ for i in range(1,len(self.df_bms)-1):
|
|
|
|
+
|
|
|
|
+ if firsttime1==0: #满电静置算法--计算均衡状态对应的均衡时间
|
|
|
|
+ try:
|
|
|
|
+ balstat=int(self.df_bms.loc[i,'单体均衡状态'])
|
|
|
|
+ if balstat>0.5:
|
|
|
|
+ bal_step=(self.bmstime[i+1]-self.bmstime[i]).total_seconds() #均衡步长
|
|
|
|
+ bal_step=int(bal_step)
|
|
|
|
+ if str(balstat) in dict_bal1.keys():
|
|
|
|
+ dict_bal1[str(balstat)]=dict_bal1[str(balstat)]+bal_step
|
|
|
|
+ else:
|
|
|
|
+ dict_bal1[str(balstat)]=bal_step
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+ except:
|
|
|
|
+ dict_bal1={}
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+
|
|
|
|
+ if abs(self.packcrnt[i]) < 0.1 and abs(self.packcrnt[i-1]) < 0.1 and abs(self.packcrnt[i+1]) < 0.1:
|
|
|
|
+ delttime=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
|
|
|
|
+ standingtime=standingtime+delttime
|
|
|
|
+ standingtime1=standingtime1+delttime
|
|
|
|
+ self._celltemp_weight(i)
|
|
|
|
+
|
|
|
|
+ #长时间静置法计算内短路-开始.....................................................................................................................................
|
|
|
|
+ if firsttime==1:
|
|
|
|
+ if standingtime>self.StandardStandingTime*2: #静置时间满足要求
|
|
|
|
+ standingtime=0
|
|
|
|
+ cellvolt_now=self._cellvolt_get(i)
|
|
|
|
+ cellvolt_min=min(cellvolt_now)
|
|
|
|
+ cellvolt_max=max(cellvolt_now)
|
|
|
|
+ cellvolt_last=self._cellvolt_get(i-1)
|
|
|
|
+ deltvolt=max(abs(cellvolt_now-cellvolt_last))
|
|
|
|
+
|
|
|
|
+ if 2<cellvolt_min<4.5 and 2<cellvolt_max<4.5 and deltvolt<0.005:
|
|
|
|
+ dict_baltime={} #获取每个电芯的均衡时间
|
|
|
|
+ deltsoc_last, cellsoc_last=self._celldeltsoc_get(i,dict_baltime,capacity)
|
|
|
|
+ time_last=self.bmstime[i]
|
|
|
|
+ firsttime=0
|
|
|
|
+ df_ram_last.loc[0]=[self.sn,time_last,deltsoc_last,cellsoc_last] #更新RAM信息
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+ elif standingtime>3600*10:
|
|
|
|
+ standingtime=0
|
|
|
|
+ cellvolt_now=self._cellvolt_get(i)
|
|
|
|
+ cellvolt_min=min(cellvolt_now)
|
|
|
|
+ cellvolt_max=max(cellvolt_now)
|
|
|
|
+ cellvolt_last=self._cellvolt_get(i-1)
|
|
|
|
+ deltvolt=max(abs(cellvolt_now-cellvolt_last))
|
|
|
|
+
|
|
|
|
+ if 2<cellvolt_min<4.5 and 2<cellvolt_max<4.5 and deltvolt<0.005:
|
|
|
|
+ dict_baltime=self._bal_time(dict_bal) #获取每个电芯的均衡时间
|
|
|
|
+ deltsoc_now, cellsoc_now=self._celldeltsoc_get(i,dict_baltime,capacity)
|
|
|
|
+ time_now=self.bmstime[i]
|
|
|
|
+ if -5<max(cellsoc_now-cellsoc_last)<5:
|
|
|
|
+ df_ram_last.loc[0]=[self.sn,time_now,deltsoc_now,cellsoc_now] #更新RAM信息
|
|
|
|
+
|
|
|
|
+ list_sub=deltsoc_now-deltsoc_last
|
|
|
|
+ list_pud=(0.01*capacity*3600*1000)/(time_now-time_last).total_seconds()
|
|
|
|
+ leak_current=list_sub*list_pud
|
|
|
|
+ # leak_current=np.array(leak_current)
|
|
|
|
+ leak_current=np.round(leak_current,3)
|
|
|
|
+ leak_current=list(leak_current)
|
|
|
|
+
|
|
|
|
+ df_res.loc[len(df_res)]=[time_last,time_now,self.sn,1,str(leak_current),str(dict_baltime)] #计算结果存入Dataframe
|
|
|
|
+ time_last=time_now #更新时间
|
|
|
|
+ deltsoc_last=deltsoc_now #更新soc差
|
|
|
|
+ dict_bal={}
|
|
|
|
+ else:
|
|
|
|
+ firsttime=1
|
|
|
|
+ else:
|
|
|
|
+ try:
|
|
|
|
+ balstat=int(self.df_bms.loc[i,'单体均衡状态'])
|
|
|
|
+ if balstat>0.5:
|
|
|
|
+ bal_step=(self.bmstime[i+1]-self.bmstime[i]).total_seconds() #均衡步长
|
|
|
|
+ bal_step=int(bal_step)
|
|
|
|
+ if str(balstat) in dict_bal.keys():
|
|
|
|
+ dict_bal[str(balstat)]=dict_bal[str(balstat)]+bal_step
|
|
|
|
+ else:
|
|
|
|
+ dict_bal[str(balstat)]=bal_step
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+ except:
|
|
|
|
+ dict_bal={}
|
|
|
|
+
|
|
|
|
+ #满电静置法计算内短路-开始.....................................................................................................................................................
|
|
|
|
+ if self.StandardStandingTime<standingtime1:
|
|
|
|
+ standingtime1=0
|
|
|
|
+ cellvolt_now1=self._cellvolt_get(i)
|
|
|
|
+ cellvolt_max1=max(cellvolt_now1)
|
|
|
|
+ cellvolt_min1=min(cellvolt_now1)
|
|
|
|
+ cellvolt_last1=self._cellvolt_get(i-1)
|
|
|
|
+ deltvolt1=max(abs(cellvolt_now1-cellvolt_last1))
|
|
|
|
+ cellsoc_now1=np.interp(cellvolt_max1,self.param.LookTab_OCV,self.param.LookTab_SOC)
|
|
|
|
+
|
|
|
|
+ if cellsoc_now1>=self.param.FullChrgSoc-10 and 2<cellvolt_min1<4.5 and 2<cellvolt_max1<4.5 and deltvolt1<0.005:
|
|
|
|
+ if firsttime1==1:
|
|
|
|
+ dict_baltime1={} #获取每个电芯的均衡时间
|
|
|
|
+ deltsoc_last1, cellsoc_last1=self._celldeltsoc_get(i,dict_baltime1,capacity)
|
|
|
|
+ time_last1=self.bmstime[i]
|
|
|
|
+ firsttime1=0
|
|
|
|
+ df_ram_last1.loc[0]=[self.sn,time_last1,deltsoc_last1] #更新RAM信息
|
|
|
|
+ else:
|
|
|
|
+ dict_baltime1=self._bal_time(dict_bal1) #获取每个电芯的均衡时间
|
|
|
|
+ time_now1=self.bmstime[i]
|
|
|
|
+ if (time_now1-time_last1).total_seconds()>3600*12:
|
|
|
|
+ deltsoc_now1, cellsoc_now1=self._celldeltsoc_get(i,dict_baltime1,capacity)
|
|
|
|
+ df_ram_last1.loc[0]=[self.sn,time_now1,deltsoc_now1] #更新RAM信息
|
|
|
|
+
|
|
|
|
+ list_sub1=deltsoc_now1-deltsoc_last1
|
|
|
|
+ list_pud1=(0.01*capacity*3600*1000)/(time_now1-time_last1).total_seconds()
|
|
|
|
+ leak_current1=list_sub1*list_pud1
|
|
|
|
+ # leak_current1=np.array(leak_current1)
|
|
|
|
+ leak_current1=np.round(leak_current1,3)
|
|
|
|
+ leak_current1=list(leak_current1)
|
|
|
|
+
|
|
|
|
+ df_res.loc[len(df_res)]=[time_last1,time_now1,self.sn,2,str(leak_current1),str(dict_baltime1)] #计算结果存入Dataframe
|
|
|
|
+ time_last1=time_now1 #更新时间
|
|
|
|
+ deltsoc_last1=deltsoc_now1 #更新soc差
|
|
|
|
+ dict_bal1={}
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+
|
|
|
|
+ else:
|
|
|
|
+ df_ram_last=pd.DataFrame(columns=['sn','time','deltsoc','cellsoc']) #电流>0,清空上次静置的SOC差
|
|
|
|
+ dict_bal={}
|
|
|
|
+ firsttime=1
|
|
|
|
+ standingtime=0
|
|
|
|
+ standingtime1=0
|
|
|
|
+ pass
|
|
|
|
+
|
|
|
|
+ #更新RAM的standingtime
|
|
|
|
+ df_ram_last3.loc[0]=[self.sn,self.bmstime[len(self.bmstime)-1],standingtime,standingtime1]
|
|
|
|
+
|
|
|
|
+ #返回计算结果
|
|
|
|
+ if df_res.empty:
|
|
|
|
+ return pd.DataFrame(), df_ram_last, df_ram_last1, df_ram_last3
|
|
|
|
+ else:
|
|
|
|
+ return df_res, df_ram_last, df_ram_last1, df_ram_last3
|
|
|
|
+
|
|
|
|
+ #磷酸铁锂电池内短路计算程序.............................................................................................................................
|
|
|
|
+ def _lfp_intershort(self):
|
|
|
|
+ column_name=['time_st', 'time_sp', 'sn', 'method','short_current','baltime']
|
|
|
|
+ df_res=pd.DataFrame(columns=column_name)
|
|
|
|
+ df_ram_last=self.df_last
|
|
|
|
+ df_ram_last1=self.df_last1
|
|
|
|
+ df_ram_last2=self.df_last2
|
|
|
|
+ df_ram_last3=self.df_last3
|
|
|
|
+ df_ram_lfp=pd.DataFrame(columns=self.df_bms.columns.tolist())
|
|
|
|
+
|
|
|
|
+ #容量初始化
|
|
|
|
+ if self.df_soh.empty:
|
|
|
|
+ batsoh=self.df_bms.loc[0,'SOH[%]']
|
|
|
|
+ capacity=self.param.Capacity*batsoh/100
|
|
|
|
+ else:
|
|
|
|
+ batsoh=self.df_soh.loc[len(self.df_soh)-1,'soh']
|
|
|
|
+ capacity=self.param.Capacity*batsoh/100
|
|
|
|
+ #参数初始化
|
|
|
|
+ if df_ram_last.empty:
|
|
|
|
+ firsttime=1
|
|
|
|
+ dict_bal={}
|
|
|
|
+ else:
|
|
|
|
+ deltsoc_last=df_ram_last.loc[0,'deltsoc']
|
|
|
|
+ cellsoc_last=df_ram_last.loc[0,'cellsoc']
|
|
|
|
+ time_last=df_ram_last.loc[0,'time']
|
|
|
|
+ firsttime=0
|
|
|
|
+ dict_bal={}
|
|
|
|
+ if df_ram_last1.empty:
|
|
|
|
+ firsttime1=1
|
|
|
|
+ dict_bal1={}
|
|
|
|
+ else:
|
|
|
|
+ deltsoc_last1=df_ram_last1.loc[0,'deltsoc1']
|
|
|
|
+ time_last1=df_ram_last1.loc[0,'time1']
|
|
|
|
+ firsttime1=0
|
|
|
|
+ dict_bal1={}
|
|
|
|
+ if df_ram_last2.empty:
|
|
|
|
+ firsttime2=1
|
|
|
|
+ charging=0
|
|
|
|
+ dict_bal2={}
|
|
|
|
+ else:
|
|
|
|
+ deltAs_last2=df_ram_last2.loc[0,'deltAs2']
|
|
|
|
+ time_last2=df_ram_last2.loc[0,'time2']
|
|
|
|
+ firsttime2=0
|
|
|
|
+ charging=0
|
|
|
|
+ dict_bal2={}
|
|
|
|
+ if df_ram_last3.empty:
|
|
|
|
+ standingtime=0
|
|
|
|
+ standingtime1=0
|
|
|
|
+ else:
|
|
|
|
+ standingtime=df_ram_last3.loc[0,'standingtime']
|
|
|
|
+ standingtime1=df_ram_last3.loc[0,'standingtime1']
|
|
|
|
+ dict_bal1={}
|
|
|
|
+ if abs(self.packcrnt[0])<0.01 and standingtime>1 and standingtime1>1:
|
|
|
|
+ standingtime=standingtime+(self.bmstime[0]-df_ram_last3.loc[0,'time3']).total_seconds()
|
|
|
|
+ standingtime1=standingtime1+(self.bmstime[0]-df_ram_last3.loc[0,'time3']).total_seconds()
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+
|
|
|
|
+ for i in range(1,len(self.df_bms)-1):
|
|
|
|
+
|
|
|
|
+ #静置法计算内短路..........................................................................................................................
|
|
|
|
+ if firsttime1==0: #满电静置算法--计算均衡状态对应的均衡时间
|
|
|
|
+ try:
|
|
|
|
+ balstat=int(self.df_bms.loc[i,'单体均衡状态'])
|
|
|
|
+ if balstat>0.5:
|
|
|
|
+ bal_step=(self.bmstime[i+1]-self.bmstime[i]).total_seconds() #均衡步长
|
|
|
|
+ bal_step=int(bal_step)
|
|
|
|
+ if str(balstat) in dict_bal1.keys():
|
|
|
|
+ dict_bal1[str(balstat)]=dict_bal1[str(balstat)]+bal_step
|
|
|
|
+ else:
|
|
|
|
+ dict_bal1[str(balstat)]=bal_step
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+ except:
|
|
|
|
+ dict_bal1={}
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+
|
|
|
|
+ if abs(self.packcrnt[i]) < 0.1 and abs(self.packcrnt[i-1]) < 0.1 and abs(self.packcrnt[i+1]) < 0.1:
|
|
|
|
+ delttime=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
|
|
|
|
+ standingtime=standingtime+delttime
|
|
|
|
+ standingtime1=standingtime1+delttime
|
|
|
|
+ self._celltemp_weight(i)
|
|
|
|
+
|
|
|
|
+ #长时间静置法计算内短路-开始.....................................................................................................................................
|
|
|
|
+ if firsttime==1:
|
|
|
|
+ if standingtime>self.StandardStandingTime: #静置时间满足要求
|
|
|
|
+ standingtime=0
|
|
|
|
+ cellvolt_now=self._cellvolt_get(i)
|
|
|
|
+ cellvolt_min=min(cellvolt_now)
|
|
|
|
+ cellvolt_max=max(cellvolt_now)
|
|
|
|
+ cellvolt_last=self._cellvolt_get(i-1)
|
|
|
|
+ deltvolt=max(abs(cellvolt_now-cellvolt_last))
|
|
|
|
+
|
|
|
|
+ if 2<cellvolt_max<self.param.OcvInflexionBelow-0.002 and 2<cellvolt_min<4.5 and abs(deltvolt)<0.003:
|
|
|
|
+ dict_baltime={} #获取每个电芯的均衡时间
|
|
|
|
+ deltsoc_last, cellsoc_last=self._celldeltsoc_get(i,dict_baltime,capacity)
|
|
|
|
+ time_last=self.bmstime[i]
|
|
|
|
+ firsttime=0
|
|
|
|
+ df_ram_last.loc[0]=[self.sn,time_last,deltsoc_last,cellsoc_last] #更新RAM信息
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+ elif standingtime>3600*10:
|
|
|
|
+ standingtime=0
|
|
|
|
+ cellvolt_now=np.array(self._cellvolt_get(i))
|
|
|
|
+ cellvolt_min=min(cellvolt_now)
|
|
|
|
+ cellvolt_max=max(cellvolt_now)
|
|
|
|
+ cellvolt_last=np.array(self._cellvolt_get(i-1))
|
|
|
|
+ deltvolt=max(abs(cellvolt_now-cellvolt_last))
|
|
|
|
+
|
|
|
|
+ if 2<cellvolt_max<self.param.OcvInflexionBelow-0.002 and 2<cellvolt_min<4.5 and abs(deltvolt)<0.003:
|
|
|
|
+ dict_baltime=self._bal_time(dict_bal) #获取每个电芯的均衡时间
|
|
|
|
+ deltsoc_now, cellsoc_now=self._celldeltsoc_get(i, dict_baltime,capacity) #获取每个电芯的SOC差
|
|
|
|
+ time_now=self.bmstime[i]
|
|
|
|
+ if -5<max(cellsoc_now-cellsoc_last)<5:
|
|
|
|
+ df_ram_last.loc[0]=[self.sn,time_now,deltsoc_now,cellsoc_now] #更新RAM信息
|
|
|
|
+
|
|
|
|
+ list_sub=deltsoc_now-deltsoc_last
|
|
|
|
+ list_pud=(0.01*capacity*3600*1000)/(time_now-time_last).total_seconds()
|
|
|
|
+ leak_current=list_sub*list_pud
|
|
|
|
+ # leak_current=np.array(leak_current)
|
|
|
|
+ leak_current=np.round(leak_current,3)
|
|
|
|
+ leak_current=list(leak_current)
|
|
|
|
+
|
|
|
|
+ df_res.loc[len(df_res)]=[time_last,time_now,self.sn,1,str(leak_current),str(dict_baltime)] #计算结果存入Dataframe
|
|
|
|
+ time_last=time_now #更新时间
|
|
|
|
+ deltsoc_last=deltsoc_now #更新soc差
|
|
|
|
+ dict_bal={}
|
|
|
|
+ else:
|
|
|
|
+ firsttime=1
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+ else:
|
|
|
|
+ try:
|
|
|
|
+ balstat=int(self.df_bms.loc[i,'单体均衡状态'])
|
|
|
|
+ if balstat>0.5:
|
|
|
|
+ bal_step=(self.bmstime[i+1]-self.bmstime[i]).total_seconds() #均衡步长
|
|
|
|
+ bal_step=int(bal_step)
|
|
|
|
+ if str(balstat) in dict_bal.keys():
|
|
|
|
+ dict_bal[str(balstat)]=dict_bal[str(balstat)]+bal_step
|
|
|
|
+ else:
|
|
|
|
+ dict_bal[str(balstat)]=bal_step
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+ except:
|
|
|
|
+ dict_bal={}
|
|
|
|
+
|
|
|
|
+ #非平台区间静置法计算内短路-开始.....................................................................................................................................................
|
|
|
|
+ if standingtime1>self.StandardStandingTime:
|
|
|
|
+ standingtime1=0
|
|
|
|
+ cellvolt_now1=self._cellvolt_get(i)
|
|
|
|
+ cellvolt_max1=max(cellvolt_now1)
|
|
|
|
+ cellvolt_min1=min(cellvolt_now1)
|
|
|
|
+ cellvolt_last1=self._cellvolt_get(i-1)
|
|
|
|
+ deltvolt1=max(abs(cellvolt_now1-cellvolt_last1))
|
|
|
|
+
|
|
|
|
+ if 2<cellvolt_max1<self.param.OcvInflexionBelow-0.002 and 2<cellvolt_min1<4.5 and deltvolt1<0.005:
|
|
|
|
+ if firsttime1==1:
|
|
|
|
+ dict_baltime1=self._bal_time(dict_bal1) #获取每个电芯的均衡时间
|
|
|
|
+ deltsoc_last1, cellsoc_last1=self._celldeltsoc_get(i,dict_baltime1,capacity)
|
|
|
|
+ time_last1=self.bmstime[i]
|
|
|
|
+ firsttime1=0
|
|
|
|
+ df_ram_last1.loc[0]=[self.sn,time_last1,deltsoc_last1] #更新RAM信息
|
|
|
|
+ else:
|
|
|
|
+ dict_baltime1=self._bal_time(dict_bal1) #获取每个电芯的均衡时间
|
|
|
|
+ deltsoc_now1, cellsoc_now1=self._celldeltsoc_get(i,dict_baltime1,capacity)
|
|
|
|
+ time_now1=self.bmstime[i]
|
|
|
|
+ df_ram_last1.loc[0]=[self.sn,time_now1,deltsoc_now1] #更新RAM信息
|
|
|
|
+
|
|
|
|
+ if (time_now1-time_last1).total_seconds()>3600*12:
|
|
|
|
+ list_sub1=deltsoc_now1-deltsoc_last1
|
|
|
|
+ list_pud1=(0.01*capacity*3600*1000)/(time_now1-time_last1).total_seconds()
|
|
|
|
+ leak_current1=list_sub1*list_pud1
|
|
|
|
+ # leak_current1=np.array(leak_current1)
|
|
|
|
+ leak_current1=np.round(leak_current1,3)
|
|
|
|
+ leak_current1=list(leak_current1)
|
|
|
|
+
|
|
|
|
+ df_res.loc[len(df_res)]=[time_last1,time_now1,self.sn,2,str(leak_current1),str(dict_baltime1)] #计算结果存入Dataframe
|
|
|
|
+ time_last1=time_now1 #更新时间
|
|
|
|
+ deltsoc_last1=deltsoc_now1 #更新soc差
|
|
|
|
+ dict_bal1={}
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+
|
|
|
|
+ else:
|
|
|
|
+ df_ram_last=pd.DataFrame(columns=['sn','time','deltsoc','cellsoc']) #电流>0,清空上次静置的SOC差
|
|
|
|
+ dict_bal={}
|
|
|
|
+ firsttime=1
|
|
|
|
+ standingtime=0
|
|
|
|
+ standingtime1=0
|
|
|
|
+ pass
|
|
|
|
+
|
|
|
|
+ #获取充电数据——开始..............................................................................................................
|
|
|
|
+ try:
|
|
|
|
+ balstat=int(self.df_bms.loc[i,'单体均衡状态']) #统计均衡状态
|
|
|
|
+ if balstat>0.5:
|
|
|
|
+ bal_step=(self.bmstime[i+1]-self.bmstime[i]).total_seconds() #均衡步长
|
|
|
|
+ bal_step=int(bal_step)
|
|
|
|
+ if str(balstat) in dict_bal2.keys():
|
|
|
|
+ dict_bal2[str(balstat)]=dict_bal2[str(balstat)]+bal_step
|
|
|
|
+ else:
|
|
|
|
+ dict_bal2[str(balstat)]=bal_step
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+ except:
|
|
|
|
+ dict_bal2={}
|
|
|
|
+
|
|
|
|
+ #判断充电状态
|
|
|
|
+ if self.packcrnt[i]<=-1 and self.packcrnt[i+1]<=-1 and self.packcrnt[i-1]<=-1:
|
|
|
|
+ if charging==0:
|
|
|
|
+ if self.bms_soc[i]<40:
|
|
|
|
+ cellvolt_now=self._cellvolt_get(i)
|
|
|
|
+ if min(cellvolt_now)<self.param.CellFullChrgVolt-0.15:
|
|
|
|
+ charging=1
|
|
|
|
+ chrg_start=i
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+
|
|
|
|
+ else: #充电中
|
|
|
|
+ cellvolt_now=self._cellvolt_get(i)
|
|
|
|
+ if (self.bmstime[i+1]-self.bmstime[i]).total_seconds()>180 or (self.packcrnt[i]>self.param.Capacity/3 and self.packcrnt[i+1]>self.param.Capacity/3): #如果充电过程中时间间隔>180s,则舍弃该次充电
|
|
|
|
+ charging=0
|
|
|
|
+ continue
|
|
|
|
+ elif min(cellvolt_now)>self.param.CellFullChrgVolt-0.13: #电压>满充电压-0.13V,即3.37V
|
|
|
|
+ self._celltemp_weight(i)
|
|
|
|
+ if i-chrg_start>10 and self.celltemp>10:
|
|
|
|
+ chrg_end=i+1
|
|
|
|
+ charging=0
|
|
|
|
+
|
|
|
|
+ #计算漏电流值...................................................................
|
|
|
|
+ if firsttime2==1:
|
|
|
|
+ dict_baltime={}
|
|
|
|
+ deltAs_last2=self._cellDeltAs_get(chrg_start,chrg_end,dict_baltime)
|
|
|
|
+ time_last2=self.bmstime[chrg_end]
|
|
|
|
+ df_ram_last2.loc[0]=[self.sn,time_last2,deltAs_last2] #更新RAM信息
|
|
|
|
+ else:
|
|
|
|
+ dict_baltime=self._bal_time(dict_bal2) #获取每个电芯的均衡时间
|
|
|
|
+ deltAs_now2=self._cellDeltAs_get(chrg_start,chrg_end,dict_baltime) #获取每个电芯的As差
|
|
|
|
+ time_now2=self.bmstime[chrg_end]
|
|
|
|
+ df_ram_last2.loc[0]=[self.sn,time_now2,deltAs_now2] #更新RAM信息
|
|
|
|
+
|
|
|
|
+ list_sub2=deltAs_now2-deltAs_last2
|
|
|
|
+ list_pud2=-1000/(time_now2-time_last2).total_seconds()
|
|
|
|
+ leak_current2=list_sub2*list_pud2
|
|
|
|
+ # leak_current=np.array(leak_current)
|
|
|
|
+ leak_current2=np.round(leak_current2,3)
|
|
|
|
+ leak_current2=list(leak_current2)
|
|
|
|
+
|
|
|
|
+ df_res.loc[len(df_res)]=[time_last2,time_now2,self.sn,3,str(leak_current2),str(dict_baltime)] #计算结果存入Dataframe
|
|
|
|
+ deltAs_last2=deltAs_now2
|
|
|
|
+ time_last2=time_now2
|
|
|
|
+ dict_bal2={}
|
|
|
|
+
|
|
|
|
+ else:
|
|
|
|
+ charging=0
|
|
|
|
+ continue
|
|
|
|
+ elif i==len(self.df_bms)-2: #数据中断后仍在充电,将前段充电数据写入RAM
|
|
|
|
+ df_ram_lfp=self.df_bms.iloc[chrg_start:]
|
|
|
|
+ df_ram_lfp['sn']=self.sn
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+ else:
|
|
|
|
+ pass
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ #更新RAM
|
|
|
|
+ df_ram_last3.loc[0]=[self.sn,self.bmstime[len(self.bmstime)-1],standingtime,standingtime1]
|
|
|
|
+
|
|
|
|
+ #返回结果
|
|
|
|
+ if df_res.empty:
|
|
|
|
+ return pd.DataFrame(), df_ram_last, df_ram_last1, df_ram_last2, df_ram_last3,df_ram_lfp
|
|
|
|
+ else:
|
|
|
|
+ return df_res, df_ram_last, df_ram_last1, df_ram_last2, df_ram_last3, df_ram_lfp
|