|
@@ -6,8 +6,8 @@ import matplotlib.pyplot as plt
|
|
|
import BatParam
|
|
|
import DBDownload
|
|
|
|
|
|
-class Soh:
|
|
|
- def __init__(self,sn,df_bms,df_accum): #参数初始化
|
|
|
+class BatSoh:
|
|
|
+ def __init__(self,sn,df_bms,df_accum, host, port, db, user, password, tablename): #参数初始化
|
|
|
|
|
|
self.sn=sn
|
|
|
self.param=BatParam.BatParam(sn)
|
|
@@ -22,7 +22,14 @@ class Soh:
|
|
|
self.df_accum=df_accum
|
|
|
self.accumtime=pd.to_datetime(df_accum['时间戳'], format='%Y-%m-%d %H:%M:%S')
|
|
|
|
|
|
- def soh(self):
|
|
|
+ self.host=host
|
|
|
+ self.port=port
|
|
|
+ self.db=db
|
|
|
+ self.user=user
|
|
|
+ self.password=password
|
|
|
+ self.tablename=tablename
|
|
|
+
|
|
|
+ def batsoh(self):
|
|
|
if self.param.celltype==1 or self.param.celltype==2:
|
|
|
df_res=self._ncmsoh_twopoint()
|
|
|
return df_res
|
|
@@ -32,24 +39,12 @@ class Soh:
|
|
|
return df_res
|
|
|
|
|
|
def getdata(self): #获取已有soh结果
|
|
|
- host='rm-bp10j10qy42bzy0q77o.mysql.rds.aliyuncs.com'
|
|
|
- port=3306
|
|
|
- db='qx_cas'
|
|
|
- user='qx_read'
|
|
|
- password='Qx@123456'
|
|
|
-
|
|
|
- now_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
|
|
- now_time=datetime.datetime.strptime(now_time,'%Y-%m-%d %H:%M:%S')
|
|
|
- start_time=now_time-datetime.timedelta(days=60)
|
|
|
- end_time=str(now_time)
|
|
|
- start_time=str(start_time)
|
|
|
-
|
|
|
- DBManager=DBDownload.DBDownload(host, port, db, user, password)
|
|
|
+
|
|
|
+ DBManager=DBDownload.DBDownload(self.host, self.port, self.db, self.user, self.password)
|
|
|
with DBManager as DBManager:
|
|
|
- df_soh=DBManager.getdata('sn', 'time', 'bms_soh', 'soh', 'soh_err', tablename='soh_result',st=start_time,sp=end_time)
|
|
|
- self.df_soh=df_soh[df_soh['sn']==self.sn]
|
|
|
+ self.df_soh=DBManager.getdata('time_st','time_sp','sn','method','soh','cellsoh', tablename='soh_result', sn=self.sn)
|
|
|
|
|
|
- def np_move_avg(self,a, n, mode="same"): #定义滑动滤波函数
|
|
|
+ def _np_move_avg(self,a, n, mode="same"): #定义滑动滤波函数
|
|
|
return (np.convolve(a, np.ones((n,)) / n, mode=mode))
|
|
|
|
|
|
def _chrgdata(self): #筛选充电数据
|
|
@@ -249,7 +244,7 @@ class Soh:
|
|
|
|
|
|
if standingpoint_sp:
|
|
|
self.getdata() #获取已计算的soh
|
|
|
- column_name=['time_st','time_sp','sn','method','soh','cellsoh1','cellsoh2','cellsoh3','cellsoh4','cellsoh5','cellsoh6','cellsoh7','cellsoh8','cellsoh9','cellsoh10','cellsoh11','cellsoh12','cellsoh13','cellsoh14','cellsoh15','cellsoh16','cellsoh17','cellsoh18','cellsoh19','cellsoh20']
|
|
|
+ column_name=['time_st','time_sp','sn','method','soh','cellsoh']
|
|
|
df_res=pd.DataFrame(columns=column_name)
|
|
|
|
|
|
for i in range(len(standingpoint_sp)):
|
|
@@ -313,43 +308,37 @@ class Soh:
|
|
|
else:
|
|
|
soh_weight1=soh_weight1
|
|
|
|
|
|
- cellsoh=[timepoint_bms_st, timepoint_bms_sp, self.sn, 1]
|
|
|
- for j in range(20): #计算每个电芯的SOH值
|
|
|
- if j<self.param.CellVoltNums:
|
|
|
- ocv_soc1=np.interp(cellocv_st[j],self.param.LookTab_OCV,self.param.LookTab_SOC)
|
|
|
- ocv_soc2=np.interp(cellocv_sp[j],self.param.LookTab_OCV,self.param.LookTab_SOC)
|
|
|
- delt_ocv_soc=ocv_soc2-ocv_soc1
|
|
|
- delt_ocv_soc_weight=self._deltsoc_weight(abs(delt_ocv_soc))
|
|
|
- soh_weight=soh_weight1*tempweightlist[i]*delt_ocv_soc_weight
|
|
|
- cellsoh_init=ah_accum*100/((ocv_soc2-ocv_soc1)*0.01*self.param.Capacity)
|
|
|
-
|
|
|
- if cellsoh_init>55 and cellsoh_init<120: #判断soh值的有效区间
|
|
|
- if len(df_res)<1:
|
|
|
- if not self.df_soh.empty and self.df_soh.shape[1]>10:
|
|
|
- cellsoh_cal=cellsoh_init*soh_weight + list(self.df_soh['cellsoh'+str(j+1)])[-1]*(1-soh_weight)
|
|
|
- else:
|
|
|
- cellsoh_cal=cellsoh_init
|
|
|
+ cellsoh=[]
|
|
|
+ for j in range(self.param.CellVoltNums): #计算每个电芯的SOH值
|
|
|
+ ocv_soc1=np.interp(cellocv_st[j],self.param.LookTab_OCV,self.param.LookTab_SOC)
|
|
|
+ ocv_soc2=np.interp(cellocv_sp[j],self.param.LookTab_OCV,self.param.LookTab_SOC)
|
|
|
+ delt_ocv_soc=ocv_soc2-ocv_soc1
|
|
|
+ delt_ocv_soc_weight=self._deltsoc_weight(abs(delt_ocv_soc))
|
|
|
+ soh_weight=soh_weight1*tempweightlist[i]*delt_ocv_soc_weight
|
|
|
+ cellsoh_init=ah_accum*100/((ocv_soc2-ocv_soc1)*0.01*self.param.Capacity)
|
|
|
+
|
|
|
+ if cellsoh_init>55 and cellsoh_init<120: #判断soh值的有效区间
|
|
|
+ if len(df_res)<1:
|
|
|
+ if not self.df_soh.empty:
|
|
|
+ cellsoh_last=eval(self.df_soh.loc[len(self.df_soh)-1,'cellsoh'])
|
|
|
+ cellsoh_cal=cellsoh_init*soh_weight + cellsoh_last[j]*(1-soh_weight)
|
|
|
else:
|
|
|
- if abs(cellsoh_init-df_res.iloc[-1]['cellsoh'+str(j+1)])<15:
|
|
|
- cellsoh_cal=cellsoh_init*soh_weight*0.5 + df_res.iloc[-1]['cellsoh'+str(j+1)]*(1-soh_weight*0.5)
|
|
|
- else:
|
|
|
- soh_weight=soh_weight*0.2
|
|
|
- cellsoh_cal=cellsoh_init*soh_weight*0.5 + df_res.iloc[-1]['cellsoh'+str(j+1)]*(1-soh_weight*0.5)
|
|
|
- cellsoh.append(cellsoh_cal)
|
|
|
+ cellsoh_cal=cellsoh_init*soh_weight+100*(1-soh_weight)
|
|
|
else:
|
|
|
- cellsoh=[]
|
|
|
- break
|
|
|
- else:
|
|
|
- cellsoh.append(0)
|
|
|
- if len(cellsoh)>4:
|
|
|
- soh_value=cellsoh[4:4+self.param.CellVoltNums]
|
|
|
- soh=min(soh_value)
|
|
|
- cellsoh.insert(4,soh)
|
|
|
- if len(df_res)<1:
|
|
|
- df_res.loc[0]=cellsoh
|
|
|
+ cellsoh_last=eval(df_res.loc[len(df_res)-1,'cellsoh'])
|
|
|
+ if abs(cellsoh_init-cellsoh_last[j])<10:
|
|
|
+ cellsoh_cal=cellsoh_init*soh_weight*0.5 + cellsoh_last[j]*(1-soh_weight*0.5)
|
|
|
+ else:
|
|
|
+ soh_weight=soh_weight*0.2
|
|
|
+ cellsoh_cal=cellsoh_init*soh_weight*0.5 + cellsoh_last[j]*(1-soh_weight*0.5)
|
|
|
+ cellsoh.append(cellsoh_cal)
|
|
|
else:
|
|
|
- df_res.loc[df_res.index.values[-1]+1]=cellsoh
|
|
|
- print(df_res)
|
|
|
+ cellsoh=[]
|
|
|
+ break
|
|
|
+ if cellsoh:
|
|
|
+ soh=min(cellsoh)
|
|
|
+ soh_list=[timepoint_bms_st, timepoint_bms_sp, self.sn, 1, soh, str(cellsoh)]
|
|
|
+ df_res.loc[len(df_res)]=soh_list
|
|
|
else:
|
|
|
continue
|
|
|
if df_res.empty:
|
|
@@ -433,7 +422,9 @@ class Soh:
|
|
|
|
|
|
#获取DVDQ算法所需数据——开始
|
|
|
if i==3 and self.packcrnt[1]<=-1 and self.packcrnt[2]<=-1 and self.packcrnt[3]<=-1:
|
|
|
+ self._celltemp_weight(i)
|
|
|
chrg_start.append(i)
|
|
|
+ tempweightlist2.append(self.tempweight)
|
|
|
charging=1
|
|
|
elif self.packcrnt[i-1]>-1 and self.packcrnt[i]<=-1 and self.packcrnt[i+1]<=-1 and self.packcrnt[i+2]<=-1: #判断充电开始
|
|
|
if self.bms_soc[i]<45:
|
|
@@ -473,7 +464,7 @@ class Soh:
|
|
|
continue
|
|
|
else:
|
|
|
continue
|
|
|
- elif i==len(self.packcrnt)-3 and self.packcrnt[i+1]<-1 and self.packcrnt[i+2]<-1:
|
|
|
+ elif i==len(self.packcrnt)-4 and self.packcrnt[i+1]<-1 and self.packcrnt[i+2]<-1:
|
|
|
charging=0
|
|
|
if len(chrg_start)>len(chrg_end):
|
|
|
cellvolt_now=self._cellvolt_get(i)
|
|
@@ -493,7 +484,7 @@ class Soh:
|
|
|
|
|
|
if standingpoint_sp or chrg_end: #开始计算SOH
|
|
|
self.getdata() #获取已计算的soh
|
|
|
- column_name=['time_st','time_sp','sn','method','soh','cellsoh1','cellsoh2','cellsoh3','cellsoh4','cellsoh5','cellsoh6','cellsoh7','cellsoh8','cellsoh9','cellsoh10','cellsoh11','cellsoh12','cellsoh13','cellsoh14','cellsoh15','cellsoh16','cellsoh17','cellsoh18','cellsoh19','cellsoh20']
|
|
|
+ column_name=['time_st','time_sp','sn','method','soh','cellsoh']
|
|
|
df_res=pd.DataFrame(columns=column_name)
|
|
|
|
|
|
if standingpoint_sp: #两点法计算SOH
|
|
@@ -560,7 +551,6 @@ class Soh:
|
|
|
else:
|
|
|
soh_weight=soh_weight
|
|
|
|
|
|
- cellsoh=[timepoint_bms_st, timepoint_bms_sp, self.sn]
|
|
|
delt_ocv_soc=ocv_soc2-ocv_soc1
|
|
|
delt_ocv_soc_weight=self._deltsoc_weight(abs(delt_ocv_soc))
|
|
|
soh_weight=soh_weight*tempweightlist1[i]*delt_ocv_soc_weight*0.5
|
|
@@ -568,25 +558,20 @@ class Soh:
|
|
|
|
|
|
if cellsoh_init>65 and cellsoh_init<115: #判断soh值的有效区间
|
|
|
if len(df_res)<1:
|
|
|
- if not self.df_soh.empty and self.df_soh.shape[1]>10:
|
|
|
+ if not self.df_soh.empty:
|
|
|
cellsoh_cal=cellsoh_init*soh_weight + list(self.df_soh['soh'])[-1]*(1-soh_weight)
|
|
|
else:
|
|
|
- cellsoh_cal=cellsoh_init
|
|
|
+ cellsoh_cal=cellsoh_init*soh_weight+100*(1-soh_weight)
|
|
|
else:
|
|
|
- if abs(cellsoh_init-df_res.iloc[-1]['soh'])<10:
|
|
|
- cellsoh_cal=cellsoh_init*soh_weight + df_res.iloc[-1]['soh']*(1-soh_weight)
|
|
|
+ cellsoh_last=df_res.loc[len(df_res)-1,'soh']
|
|
|
+ if abs(cellsoh_init-cellsoh_last)<10:
|
|
|
+ cellsoh_cal=cellsoh_init*soh_weight + cellsoh_last*(1-soh_weight)
|
|
|
else:
|
|
|
soh_weight=soh_weight*0.1
|
|
|
- cellsoh_cal=cellsoh_init*soh_weight + df_res.iloc[-1]['soh']*(1-soh_weight)
|
|
|
+ cellsoh_cal=cellsoh_init*soh_weight + cellsoh_last*(1-soh_weight)
|
|
|
|
|
|
- cellsoh.append(1)
|
|
|
- cellsoh.append(cellsoh_cal)
|
|
|
- for j in range(20): #计算每个电芯的SOH值
|
|
|
- cellsoh.append(cellsoh_cal)
|
|
|
- if len(df_res)<1:
|
|
|
- df_res.loc[0]=cellsoh
|
|
|
- else:
|
|
|
- df_res.loc[df_res.index.values[-1]+1]=cellsoh
|
|
|
+ soh_list=[timepoint_bms_st, timepoint_bms_sp, self.sn, 1, cellsoh_cal, str(cellsoh_cal)]
|
|
|
+ df_res.loc[len(df_res)]=soh_list
|
|
|
else:
|
|
|
continue
|
|
|
else:
|
|
@@ -595,7 +580,7 @@ class Soh:
|
|
|
if chrg_end:
|
|
|
for i in range(len(chrg_end)):
|
|
|
cellvolt_max = self.df_bms['单体电压' + str(cellmaxvolt_number2[i]+1)] / 1000 #获取最大电压
|
|
|
- cellvolt=self.np_move_avg(cellvolt_max, 3, mode="same") #对电压进行滑动平均滤波
|
|
|
+ cellvolt=self._np_move_avg(cellvolt_max, 3, mode="same") #对电压进行滑动平均滤波
|
|
|
|
|
|
Ah = 0 #参数赋初始值
|
|
|
Volt = cellvolt[chrg_start[i]]
|
|
@@ -622,40 +607,40 @@ class Soh:
|
|
|
soc2.append(self.bms_soc[j])
|
|
|
|
|
|
#切片,去除前后10min的数据
|
|
|
- Data1 = pd.DataFrame({'time': time2,
|
|
|
+ df_Data1 = pd.DataFrame({'time': time2,
|
|
|
'SOC': soc2,
|
|
|
'DVDQ': DVDQ,
|
|
|
'Ah_tatal': Ah_tatal[:-1],
|
|
|
'DQ_Ah':DQ_Ah,
|
|
|
'DV_Volt':DV_Volt,
|
|
|
'XVOLT':xvolt})
|
|
|
- start_time=Data1.loc[0,'time']
|
|
|
+ start_time=df_Data1.loc[0,'time']
|
|
|
start_time=start_time+datetime.timedelta(seconds=600)
|
|
|
- end_time=Data1.loc[len(time2)-1,'time']
|
|
|
+ end_time=df_Data1.loc[len(time2)-1,'time']
|
|
|
end_time=end_time-datetime.timedelta(seconds=1200)
|
|
|
if soc2[0]<37:
|
|
|
- Data1=Data1[(Data1['SOC']>39) & (Data1['time']<end_time)]
|
|
|
+ df_Data1=df_Data1[(df_Data1['SOC']>39) & (df_Data1['time']<end_time)]
|
|
|
else:
|
|
|
- Data1=Data1[(Data1['time']>start_time) & (Data1['time']<end_time)]
|
|
|
+ df_Data1=df_Data1[(df_Data1['time']>start_time) & (df_Data1['time']<end_time)]
|
|
|
|
|
|
# ax1 = plt.subplot(3, 1, 1)
|
|
|
- # plt.plot(Data1['XVOLT'],Data1['DVDQ'],'r*-')
|
|
|
+ # plt.plot(df_Data1['XVOLT'],df_Data1['DVDQ'],'r*-')
|
|
|
# ax1 = plt.subplot(3, 1, 2)
|
|
|
- # plt.plot(Data1['SOC'],Data1['XVOLT'],'y*-')
|
|
|
+ # plt.plot(df_Data1['SOC'],df_Data1['XVOLT'],'y*-')
|
|
|
# ax1 = plt.subplot(3, 1, 3)
|
|
|
- # plt.plot(Data1['SOC'], Data1['DVDQ'], 'r*-')
|
|
|
+ # plt.plot(df_Data1['SOC'], df_Data1['DVDQ'], 'r*-')
|
|
|
# plt.show()
|
|
|
|
|
|
#寻找峰值并计算Soh和置信度
|
|
|
- if len(Data1['DVDQ'])>1:
|
|
|
- PeakIndex=Data1['DVDQ'].idxmax()
|
|
|
+ if len(df_Data1)>1:
|
|
|
+ PeakIndex=df_Data1['DVDQ'].idxmax()
|
|
|
#筛选峰值点附近±0.5%SOC内的数据
|
|
|
- Data2=Data1[(Data1['SOC']>(Data1['SOC'][PeakIndex]-0.5)) & (Data1['SOC']<(Data1['SOC'][PeakIndex]+0.5))]
|
|
|
+ Data2=df_Data1[(df_Data1['SOC']>(df_Data1['SOC'][PeakIndex]-0.5)) & (df_Data1['SOC']<(df_Data1['SOC'][PeakIndex]+0.5))]
|
|
|
if len(Data2)>2:
|
|
|
- Ah_tatal1 = Data1['Ah_tatal']
|
|
|
- DVDQ = Data1['DVDQ']
|
|
|
- soc2 = Data1['SOC']
|
|
|
- xvolt = Data1['XVOLT']
|
|
|
+ Ah_tatal1 = df_Data1['Ah_tatal']
|
|
|
+ DVDQ = df_Data1['DVDQ']
|
|
|
+ soc2 = df_Data1['SOC']
|
|
|
+ xvolt = df_Data1['XVOLT']
|
|
|
if soc2[PeakIndex]>40 and soc2[PeakIndex]<90:
|
|
|
cellsoh_init=(Ah_tatal[-1]-Ah_tatal1[PeakIndex]) * 100 / ((self.param.FullChrgSoc - self.param.PeakSoc) * 0.01 * self.param.Capacity)
|
|
|
if cellsoh_init<95:
|
|
@@ -665,14 +650,14 @@ class Soh:
|
|
|
else:
|
|
|
continue
|
|
|
else:
|
|
|
- Data1=Data1.drop([PeakIndex])
|
|
|
- PeakIndex = Data1['DVDQ'].idxmax()
|
|
|
- Data2 = Data1[(Data1['SOC'] > (Data1['SOC'][PeakIndex] - 0.5)) & (Data1['SOC'] < (Data1['SOC'][PeakIndex] + 0.5))]
|
|
|
+ df_Data1=df_Data1.drop([PeakIndex])
|
|
|
+ PeakIndex = df_Data1['DVDQ'].idxmax()
|
|
|
+ Data2 = df_Data1[(df_Data1['SOC'] > (df_Data1['SOC'][PeakIndex] - 0.5)) & (df_Data1['SOC'] < (df_Data1['SOC'][PeakIndex] + 0.5))]
|
|
|
if len(Data2) > 2:
|
|
|
- Ah_tatal1 = Data1['Ah_tatal']
|
|
|
- DVDQ = Data1['DVDQ']
|
|
|
- soc2 = Data1['SOC']
|
|
|
- xvolt = Data1['XVOLT']
|
|
|
+ Ah_tatal1 = df_Data1['Ah_tatal']
|
|
|
+ DVDQ = df_Data1['DVDQ']
|
|
|
+ soc2 = df_Data1['SOC']
|
|
|
+ xvolt = df_Data1['XVOLT']
|
|
|
if soc2[PeakIndex]>40 and soc2[PeakIndex]<90:
|
|
|
cellsoh_init=(Ah_tatal[-1]-Ah_tatal1[PeakIndex]) * 100 / ((self.param.FullChrgSoc - self.param.PeakSoc) * 0.01 * self.param.Capacity)
|
|
|
if cellsoh_init<95:
|
|
@@ -684,29 +669,23 @@ class Soh:
|
|
|
else:
|
|
|
continue
|
|
|
|
|
|
- cellsoh=[self.bmstime[chrg_start[i]], self.bmstime[chrg_end[i]], self.sn]
|
|
|
soh_weight=tempweightlist2[i]*0.5
|
|
|
if cellsoh_init>65 and cellsoh_init<115: #判断soh值的有效区间
|
|
|
if len(df_res)<1:
|
|
|
if not self.df_soh.empty and self.df_soh.shape[1]>10:
|
|
|
cellsoh_cal=cellsoh_init*soh_weight + list(self.df_soh['soh'])[-1]*(1-soh_weight)
|
|
|
else:
|
|
|
- cellsoh_cal=cellsoh_init
|
|
|
+ cellsoh_cal=cellsoh_init*soh_weight+100*(1-soh_weight)
|
|
|
else:
|
|
|
- if abs(cellsoh_init-df_res.iloc[-1]['soh'])<10:
|
|
|
- cellsoh_cal=cellsoh_init*soh_weight + df_res.iloc[-1]['soh']*(1-soh_weight)
|
|
|
+ cellsoh_last=df_res.loc[len(df_res)-1,'soh']
|
|
|
+ if abs(cellsoh_init-cellsoh_last)<10:
|
|
|
+ cellsoh_cal=cellsoh_init*soh_weight + cellsoh_last*(1-soh_weight)
|
|
|
else:
|
|
|
soh_weight=soh_weight*0.2
|
|
|
- cellsoh_cal=cellsoh_init*soh_weight + df_res.iloc[-1]['soh']*(1-soh_weight)
|
|
|
+ cellsoh_cal=cellsoh_init*soh_weight + cellsoh_last*(1-soh_weight)
|
|
|
|
|
|
- cellsoh.append(2)
|
|
|
- cellsoh.append(cellsoh_cal)
|
|
|
- for j in range(20): #计算每个电芯的SOH值
|
|
|
- cellsoh.append(cellsoh_cal)
|
|
|
- if len(df_res)<1:
|
|
|
- df_res.loc[0]=cellsoh
|
|
|
- else:
|
|
|
- df_res.loc[df_res.index.values[-1]+1]=cellsoh
|
|
|
+ soh_list=[self.bmstime[chrg_start[i]], self.bmstime[chrg_end[i]], self.sn, 2, cellsoh_cal, str(cellsoh_cal)]
|
|
|
+ df_res.loc[len(df_res)]=soh_list
|
|
|
else:
|
|
|
continue
|
|
|
else:
|