|
@@ -0,0 +1,699 @@
|
|
|
+import pandas as pd
|
|
|
+import numpy as np
|
|
|
+import datetime
|
|
|
+from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import BatParam
|
|
|
+
|
|
|
+class BatDiag:
|
|
|
+ def __init__(self,sn,celltype,df_bms,df_diag_ram_sn,df_bms_ram_sn,df_soh,df_uniform): #参数初始化
|
|
|
+
|
|
|
+ self.sn=sn
|
|
|
+ self.celltype=celltype
|
|
|
+ self.param=BatParam.BatParam(celltype)
|
|
|
+ self.df_bms=df_bms
|
|
|
+ self.df_uniform=df_uniform
|
|
|
+ self.df_soh=df_soh
|
|
|
+ self.df_bms_ram=df_bms_ram_sn.copy()
|
|
|
+ self.df_diag_ram=df_diag_ram_sn.copy()
|
|
|
+ df_bms['时间戳']=pd.to_datetime(df_bms['时间戳'], format='%Y-%m-%d %H:%M:%S')
|
|
|
+
|
|
|
+ if not df_bms_ram_sn.empty:
|
|
|
+ self.df_bms=self.df_bms[self.df_bms['时间戳'] > df_bms_ram_sn.iloc[-1]['time']] #滤除原始数据中的重复数据
|
|
|
+ self.df_bms.reset_index(inplace=True,drop=True) #重置索引
|
|
|
+
|
|
|
+ self.packcrnt=df_bms['总电流[A]']*self.param.PackCrntDec
|
|
|
+ self.packvolt=df_bms['总电压[V]']
|
|
|
+ self.bmstime= df_bms['时间戳']
|
|
|
+ self.bms_soc=df_bms['SOC[%]']
|
|
|
+
|
|
|
+ self.cellvolt_name=['单体电压'+str(x) for x in range(1,self.param.CellVoltNums+1)]
|
|
|
+ # othertemp=['其他温度'+str(x) for x in range(1,self.param.OtherTempNums+1)]
|
|
|
+ self.celltemp_name=['单体温度'+str(x) for x in range(1,self.param.CellTempNums+1)]
|
|
|
+ # self.celltemp_name=celltemp+othertemp
|
|
|
+
|
|
|
+
|
|
|
+ def diag(self):
|
|
|
+ if self.celltype<=50:
|
|
|
+ df_res1,df_res2=self._bat_diag()
|
|
|
+ return df_res1,df_res2
|
|
|
+ else:
|
|
|
+ df_res1,df_res2=self._bat_diag()
|
|
|
+ return df_res1,df_res2
|
|
|
+
|
|
|
+
|
|
|
+ #寻找当前行数据的所有温度值...................................................................................
|
|
|
+ def _celltemp_get(self,num):
|
|
|
+ celltemp = list(self.df_bms.loc[num,self.celltemp_name])
|
|
|
+ return celltemp
|
|
|
+
|
|
|
+ #获取当前行所有电压数据............................................................................................
|
|
|
+ def _cellvolt_get(self,num):
|
|
|
+ cellvolt = list(self.df_bms.loc[num,self.cellvolt_name]/1000)
|
|
|
+ return cellvolt
|
|
|
+
|
|
|
+ #..........................................电池诊断功能..................................................................
|
|
|
+ def _bat_diag(self):
|
|
|
+
|
|
|
+ column_name=['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice']
|
|
|
+ df_res=pd.DataFrame(columns=column_name)
|
|
|
+
|
|
|
+ end_time='0000-00-00 00:00:00'
|
|
|
+ ah_accum=0 #SOC卡滞初始参数
|
|
|
+ as_chg=0 #过流诊断初始参数
|
|
|
+ as_dis=0 #过流诊断初始参数
|
|
|
+ cellvoltvalid=1
|
|
|
+ voltdsc_time=0
|
|
|
+ voltdsc_count=0
|
|
|
+ voltfail_time=0
|
|
|
+ voltfail_count=0
|
|
|
+ voltloose_time=0
|
|
|
+ voltloose_count=0
|
|
|
+ voltover_time=0
|
|
|
+ voltunder_time=0
|
|
|
+ cov_time=0
|
|
|
+ cuv_time=0
|
|
|
+ cdv_time=0
|
|
|
+ pov_time=0
|
|
|
+ puv_time=0
|
|
|
+ ot_time=0
|
|
|
+ ut_time=0
|
|
|
+ dt_time=0
|
|
|
+
|
|
|
+ for i in range(len(self.df_bms)):
|
|
|
+
|
|
|
+ #电压诊断功能.........................................................................................................................................
|
|
|
+ if i<1:
|
|
|
+ cellvolt2=self._cellvolt_get(i)
|
|
|
+ cellvoltmin2=min(cellvolt2)
|
|
|
+ cellvoltmax2=max(cellvolt2)
|
|
|
+ cellvoltmin_index2=cellvolt2.index(cellvoltmin2)
|
|
|
+ cellvoltmax_index2=cellvolt2.index(cellvoltmax2)
|
|
|
+ if not self.df_bms_ram.empty:
|
|
|
+ time1=self.df_bms_ram.iloc[-1]['time']
|
|
|
+ time2=self.bmstime[i]
|
|
|
+ cellvolt1=self.df_bms_ram.iloc[-1]['cellvolt']
|
|
|
+ cellvoltmin1=min(cellvolt1)
|
|
|
+ cellvoltmax1=max(cellvolt1)
|
|
|
+ cellvoltmin_index1=cellvolt1.index(cellvoltmin1)
|
|
|
+ cellvoltmax_index1=cellvolt1.index(cellvoltmax1)
|
|
|
+ else:
|
|
|
+ cellvolt1=cellvolt2
|
|
|
+ time1=self.bmstime[i]
|
|
|
+ time2=self.bmstime[i]
|
|
|
+ cellvoltmin1=cellvoltmin2
|
|
|
+ cellvoltmax1=cellvoltmax2
|
|
|
+ cellvoltmin_index1=cellvoltmin_index2
|
|
|
+ cellvoltmax_index1=cellvoltmax_index2
|
|
|
+ else:
|
|
|
+ time1=self.bmstime[i-1]
|
|
|
+ time2=self.bmstime[i]
|
|
|
+ cellvolt2=self._cellvolt_get(i)
|
|
|
+ cellvoltmin2=min(cellvolt2)
|
|
|
+ cellvoltmax2=max(cellvolt2)
|
|
|
+ cellvoltmin_index2=cellvolt2.index(cellvoltmin2)
|
|
|
+ cellvoltmax_index2=cellvolt2.index(cellvoltmax2)
|
|
|
+ cellvolt1=self._cellvolt_get(i-1)
|
|
|
+ cellvoltmin1=min(cellvolt1)
|
|
|
+ cellvoltmax1=max(cellvolt1)
|
|
|
+ cellvoltmin_index1=cellvolt1.index(cellvoltmin1)
|
|
|
+ cellvoltmax_index1=cellvolt1.index(cellvoltmax1)
|
|
|
+
|
|
|
+ #电压采样断线..........................................................................................................................................
|
|
|
+ if not 'C308' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if (cellvoltmin2<2 and cellvoltmax2>4.5 and abs(cellvoltmax_index2-cellvoltmin_index2)==1) and (cellvoltmin1<2 and cellvoltmax1>4.5 and abs(cellvoltmax_index1-cellvoltmin_index1)==1): #电压断线故障进入
|
|
|
+ cellvoltvalid=0
|
|
|
+ voltdsc_time=voltdsc_time+(time2-time1).total_seconds()
|
|
|
+ if voltdsc_time>self.param.volt_time: #持续时间
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C308'
|
|
|
+ faultlv=3
|
|
|
+ faultinfo='电芯{}和{}电压采样断线'.format(cellvoltmin_index2+1, cellvoltmax_index2+1)
|
|
|
+ faultadvice='通知用户更换电池,电池返厂维修'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ elif (cellvoltmin2<2 and cellvoltmax2>4.5 and abs(cellvoltmax_index2-cellvoltmin_index2)==1) and (cellvoltmin1>2.5 and cellvoltmax1<4.3): #连续跳变
|
|
|
+ cellvoltvalid=0
|
|
|
+ voltdsc_count=voltdsc_count+1
|
|
|
+ if voltdsc_count>=3:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C308'
|
|
|
+ faultlv=3
|
|
|
+ faultinfo='电芯{}和{}电压采样断线'.format(cellvoltmin_index2+1, cellvoltmax_index2+1)
|
|
|
+ faultadvice='通知用户更换电池,电池返厂维修'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ voltdsc_time=0
|
|
|
+ else:
|
|
|
+ cellvoltvalid=0
|
|
|
+ if cellvoltmin2>2 and cellvoltmax2<4.5 and cellvoltmin1>2 and cellvoltmax1<4.5:
|
|
|
+ cellvoltvalid=1
|
|
|
+ time=self.bmstime[i]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C308'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+
|
|
|
+ #电压采样系统失效.............................................................................................................
|
|
|
+ if not 'C309' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if (cellvoltmin2<1 and cellvoltmin1<1) or (cellvoltmax2>5 and cellvoltmax1>5):
|
|
|
+ cellvoltvalid=0
|
|
|
+ voltfail_time=voltfail_time+(time2-time1).total_seconds()
|
|
|
+ if voltfail_time>self.param.volt_time: #持续时间
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C309'
|
|
|
+ faultlv=3
|
|
|
+ faultinfo='电芯电压采样系统失效'
|
|
|
+ faultadvice='通知用户更换电池,电池返厂维修'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ elif (cellvoltmin2<1 and cellvoltmin1>2.5) or (cellvoltmax2>5 and cellvoltmax1<4.5): #连续跳变
|
|
|
+ cellvoltvalid=0
|
|
|
+ voltfail_count=voltfail_count+1
|
|
|
+ if voltfail_count>=3:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C309'
|
|
|
+ faultlv=3
|
|
|
+ faultinfo='电芯电压采样系统失效'
|
|
|
+ faultadvice='通知用户更换电池,电池返厂维修'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ voltfail_time=0
|
|
|
+ else:
|
|
|
+ cellvoltvalid=0
|
|
|
+ if cellvoltmin2>2.5 and cellvoltmax2<4.5 and cellvoltmin1>2.5 and cellvoltmax1<4.5:
|
|
|
+ cellvoltvalid=1
|
|
|
+ time=self.bmstime[i]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C309'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+
|
|
|
+ #电压采样线松动.................................................................................................................
|
|
|
+ if not 'C208' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if cellvoltmin2>2 and cellvoltmax2<4.5 and cellvoltmin1>2 and cellvoltmax1<4.5:
|
|
|
+ cellvolt1_std=np.std(cellvolt1)
|
|
|
+ cellvolt1_mean=np.mean(cellvolt1)
|
|
|
+ cellvolt1_3sigma=(np.array(cellvolt1)-cellvolt1_mean)/cellvolt1_std
|
|
|
+ cellvolt2_std=np.std(cellvolt2)
|
|
|
+ cellvolt2_mean=np.mean(cellvolt2)
|
|
|
+ cellvolt2_3sigma=(np.array(cellvolt2)-cellvolt2_mean)/cellvolt2_std
|
|
|
+ if (min(cellvolt1_3sigma)<-3 and max(cellvolt1_3sigma)>3) and (min(cellvolt2_3sigma)<-3 and max(cellvolt2_3sigma)>3): #连续发生
|
|
|
+ cellvoltvalid=0
|
|
|
+ voltloose_time=voltloose_time+(time2-time1).total_seconds()
|
|
|
+ if voltloose_time>self.param.volt_time:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C208'
|
|
|
+ faultlv=3
|
|
|
+ faultinfo='电芯电压{}和{}采样松动'.format(cellvoltmin_index2+1, cellvoltmax_index2+1)
|
|
|
+ faultadvice='通知技术人员介入诊断'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ elif (min(cellvolt1_3sigma)>-3 and max(cellvolt1_3sigma)<3) and (min(cellvolt2_3sigma)<-3 and max(cellvolt2_3sigma)>3): #连续跳变
|
|
|
+ cellvoltvalid=0
|
|
|
+ voltloose_count=voltloose_count+1
|
|
|
+ if voltloose_count>=3:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C208'
|
|
|
+ faultlv=3
|
|
|
+ faultinfo='电芯电压{}和{}采样松动'.format(cellvoltmin_index2+1, cellvoltmax_index2+1)
|
|
|
+ faultadvice='通知技术人员介入诊断'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ voltloose_time=0
|
|
|
+ else:
|
|
|
+ voltloose_time=0
|
|
|
+ else:
|
|
|
+ cellvoltvalid=0
|
|
|
+ cellvolt1_std=np.std(cellvolt1)
|
|
|
+ cellvolt1_mean=np.mean(cellvolt1)
|
|
|
+ cellvolt1_3sigma=(np.array(cellvolt1)-cellvolt1_mean)/cellvolt1_std
|
|
|
+ cellvolt2_std=np.std(cellvolt2)
|
|
|
+ cellvolt2_mean=np.mean(cellvolt2)
|
|
|
+ cellvolt2_3sigma=(np.array(cellvolt2)-cellvolt2_mean)/cellvolt2_std
|
|
|
+ if(min(cellvolt1_3sigma)>-3 or max(cellvolt1_3sigma)<3) and (min(cellvolt2_3sigma)>-3 or max(cellvolt2_3sigma)<3):
|
|
|
+ cellvoltvalid=1
|
|
|
+ time=self.bmstime[i]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C208'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+
|
|
|
+ if cellvoltvalid==1:
|
|
|
+ #继电器粘连.............................................................................................................................................
|
|
|
+ if not 'C310' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if cellvoltmax2>self.param.CellOvLv2 and cellvoltmax1>self.param.CellOvLv2 and self.packcrnt[i]<0:
|
|
|
+ voltover_time=voltover_time+(time2-time1).total_seconds()
|
|
|
+ if voltover_time>self.param.volt_time:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C310'
|
|
|
+ faultlv=3
|
|
|
+ faultinfo='充电继电器粘连'
|
|
|
+ faultadvice='通知技术人员介入诊断'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ voltover_time=0
|
|
|
+ else:
|
|
|
+ if cellvoltmax2<self.param.CellOvLv2-0.05 and cellvoltmax1<self.param.CellOvLv2-0.05:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C310'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+
|
|
|
+ if not 'C311' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if cellvoltmin2<self.param.CellUvLv2 and cellvoltmin1<self.param.CellUvLv2 and self.packcrnt[i]>0:
|
|
|
+ voltunder_time=voltunder_time+(time2-time1).total_seconds()
|
|
|
+ if voltunder_time>self.param.volt_time:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C311'
|
|
|
+ faultlv=3
|
|
|
+ faultinfo='放电继电器粘连'
|
|
|
+ faultadvice='通知技术人员介入诊断'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ voltunder_time=0
|
|
|
+ else:
|
|
|
+ if cellvoltmin2>self.param.CellUvLv2+0.05 and cellvoltmin1>self.param.CellOvLv2+0.05:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C311'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+
|
|
|
+ #电芯过压.............................................................................................................................................
|
|
|
+ if not 'C501' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if cellvoltmax2>self.param.CellOvLv2 and cellvoltmax1>self.param.CellOvLv2: #二级过压进入
|
|
|
+ cov_time=cov_time+(time2-time1).total_seconds()
|
|
|
+ if cov_time>self.param.volt_time:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C501'
|
|
|
+ faultlv=5
|
|
|
+ faultinfo='电芯{}过压'.format(cellvolt1.index(cellvoltmax1)+1)
|
|
|
+ faultadvice='联系用户立即停止充电,并通知技术运维人员'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ cov_time=0
|
|
|
+ else: #ram当前故障中有该故障,则判断是否退出该故障
|
|
|
+ if cellvoltmax2<self.param.CellOvLv1-0.05 and cellvoltmax1<self.param.CellOvLv1-0.05: #二级过压故障恢复
|
|
|
+ time=self.bmstime[i]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C501'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+
|
|
|
+ #欠压诊断.................................................................................................................
|
|
|
+ if not 'C202' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if cellvoltmin2<self.param.CellUvLv2 and cellvoltmin1<self.param.CellUvLv2: #二级欠压
|
|
|
+ cuv_time=cuv_time+(time2-time1).total_seconds()
|
|
|
+ if cuv_time>self.param.volt_time:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C202'
|
|
|
+ faultlv=2
|
|
|
+ faultinfo='电芯{}欠压'.format(cellvolt1.index(cellvoltmin1)+1)
|
|
|
+ faultadvice='联系用户询问用车场景,技术介入诊断'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ cuv_time=0
|
|
|
+ else:
|
|
|
+ if cellvoltmin2>self.param.CellUvLv1+0.1 and cellvoltmin1>self.param.CellUvLv1+0.1:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C202'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+
|
|
|
+ #电芯压差大.....................................................................................................................................................
|
|
|
+ if not 'C104' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if (cellvoltmax2-cellvoltmin2)>self.param.CellVoltDiffLv2 and (cellvoltmax1-cellvoltmin1)>self.param.CellVoltDiffLv2: #二级电芯压差
|
|
|
+ cdv_time=cdv_time+(time2-time1).total_seconds()
|
|
|
+ if cdv_time>self.param.volt_time:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C104'
|
|
|
+ faultlv=3
|
|
|
+ faultinfo='电芯{}和{}压差大'.format(cellvolt1.index(cellvoltmax1)+1,cellvolt1.index(cellvoltmin1)+1)
|
|
|
+ faultadvice='技术介入诊断'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ cdv_time=0
|
|
|
+ else:
|
|
|
+ if (cellvoltmax2-cellvoltmin2)<self.param.CellVoltDiffLv1-0.05 and (cellvoltmax1-cellvoltmin1)<self.param.CellVoltDiffLv1-0.05: #二级欠压恢复
|
|
|
+ time=self.bmstime[i]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C104'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ cov_time=0
|
|
|
+ cuv_time=0
|
|
|
+ cdv_time=0
|
|
|
+
|
|
|
+ #电池包诊断.....................................................................................................................................
|
|
|
+ if i<1:
|
|
|
+ if not self.df_bms_ram.empty:
|
|
|
+ packvolt1=self.df_bms_ram.iloc[-1]['packvolt']
|
|
|
+ packvolt2=self.packvolt[i]
|
|
|
+ time1=self.df_bms_ram.iloc[-1]['time']
|
|
|
+ time2=self.bmstime[i]
|
|
|
+ else:
|
|
|
+ packvolt1=self.packvolt[i]
|
|
|
+ packvolt2=self.packvolt[i]
|
|
|
+ time1=self.bmstime[i]
|
|
|
+ time2=self.bmstime[i]
|
|
|
+ else:
|
|
|
+ packvolt1=self.packvolt[i-1]
|
|
|
+ packvolt2=self.packvolt[i]
|
|
|
+ time1=self.bmstime[i-1]
|
|
|
+ time2=self.bmstime[i]
|
|
|
+ if packvolt1<2*self.param.CellVoltNums or packvolt2>4.5*self.param.CellVoltNums: #电池包电压有效性
|
|
|
+ packvoltvalid=0
|
|
|
+ else:
|
|
|
+ packvoltvalid=1
|
|
|
+
|
|
|
+ if packvoltvalid==1:
|
|
|
+ if not 'C502' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if packvolt1>self.param.PackVoltOvLv2 and packvolt2>self.param.PackVoltOvLv2: #电池包过压二级进入
|
|
|
+ pov_time=pov_time+(time2-time1).total_seconds()
|
|
|
+ if pov_time>self.param.volt_time:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C502'
|
|
|
+ faultlv=5
|
|
|
+ faultinfo='电池包过压'
|
|
|
+ faultadvice='联系用户立即停止充电,并通知技术运维人员'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ pov_time=0
|
|
|
+ else:
|
|
|
+ if packvolt1<self.param.PackVoltOvLv1-0.05*self.param.CellVoltNums and packvolt2<self.param.PackVoltOvLv1-0.05*self.param.CellVoltNums: #电池包过压二级恢复
|
|
|
+ time=self.bmstime[i]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C502'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+
|
|
|
+ if not 'C203' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if packvolt1<self.param.PackVoltUvLv2 and packvolt2<self.param.PackVoltUvLv2: #电池包二级欠压进入
|
|
|
+ puv_time=puv_time+(time2-time1).total_seconds()
|
|
|
+ if puv_time>self.param.volt_time:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C203'
|
|
|
+ faultlv=2
|
|
|
+ faultinfo='电池包欠压'
|
|
|
+ faultadvice='联系用户询问用车场景,技术介入诊断'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ puv_time=0
|
|
|
+ else:
|
|
|
+ if packvolt1>self.param.PackVoltUvLv1+0.1*self.param.CellVoltNums and packvolt2>self.param.PackVoltUvLv1+0.1*self.param.CellVoltNums: #电池包二级欠压恢复
|
|
|
+ time=self.bmstime[i]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C203'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ pov_time=0
|
|
|
+ puv_time=0
|
|
|
+
|
|
|
+ #温度诊断功能.............................................................................................................
|
|
|
+ if i<1:
|
|
|
+ if not self.df_bms_ram.empty:
|
|
|
+ celltemp1=self.df_bms_ram.iloc[-1]['celltemp']
|
|
|
+ celltemp2=self._celltemp_get(i)
|
|
|
+ time1=self.df_bms_ram.iloc[-1]['time']
|
|
|
+ time2=self.bmstime[i]
|
|
|
+ else:
|
|
|
+ celltemp1=self._celltemp_get(i)
|
|
|
+ celltemp2=self._celltemp_get(i)
|
|
|
+ time1=self.bmstime[i]
|
|
|
+ time2=self.bmstime[i]
|
|
|
+ else:
|
|
|
+ celltemp1=self._celltemp_get(i-1)
|
|
|
+ celltemp2=self._celltemp_get(i)
|
|
|
+ time1=self.bmstime[i-1]
|
|
|
+ time2=self.bmstime[i]
|
|
|
+ celltempmin1=min(celltemp1)
|
|
|
+ celltempmin2=min(celltemp2)
|
|
|
+ celltempmax1=max(celltemp1)
|
|
|
+ celltempmax2=max(celltemp2)
|
|
|
+ #温度有效性判断..........................................................................
|
|
|
+ if celltempmax1>self.param.CellTempUpLmt or celltempmin1<self.param.CellTempLwLmt:
|
|
|
+ celltempvalid=0
|
|
|
+ else:
|
|
|
+ celltempvalid=1
|
|
|
+
|
|
|
+ if celltempvalid==1:
|
|
|
+ #过温判断.............................................................................................................
|
|
|
+ if not 'C302' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if celltempmax1>self.param.CellTempHighLv2 and celltempmax2>self.param.CellTempHighLv2: #二级高温进入
|
|
|
+ ot_time=ot_time+(time2-time1).total_seconds()
|
|
|
+ if ot_time>self.param.temp_time:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C302'
|
|
|
+ faultlv=3
|
|
|
+ faultinfo='温度{}高温'.format(celltemp1.index(celltempmax1)+1)
|
|
|
+ faultadvice='技术介入诊断'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ ot_time=0
|
|
|
+ else: #ram当前故障中有该故障,则判断是否退出该故障
|
|
|
+ if celltempmax1<self.param.CellTempHighLv1-5 and celltempmax2<self.param.CellTempHighLv1-5: #二级高温恢复
|
|
|
+ time=self.bmstime[i]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C302'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+
|
|
|
+ #欠温判断.................................................................................................................
|
|
|
+ if not 'C102' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if celltempmin1<self.param.CellTempLowLv2 and celltempmin2<self.param.CellTempLowLv2: #二级低温进入
|
|
|
+ ut_time=ut_time+(time2-time1).total_seconds()
|
|
|
+ if ut_time>self.param.temp_time:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C102'
|
|
|
+ faultlv=1
|
|
|
+ faultinfo='温度{}低温'.format(celltemp1.index(celltempmin1)+1)
|
|
|
+ faultadvice='技术介入诊断'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ ut_time=0
|
|
|
+ else: #ram当前故障中有该故障,则判断是否退出该故障
|
|
|
+ if celltempmax1>self.param.CellTempLowLv1+2 and celltempmax2>self.param.CellTempLowLv1+2: #二级高温恢复
|
|
|
+ time=self.bmstime[i]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C102'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+
|
|
|
+ #温差判断.............................................................................................................................
|
|
|
+ if not 'C103' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if (celltempmax1-celltempmin1)>self.param.CellTempDiffLv2 and (celltempmax2-celltempmin2)>self.param.CellTempDiffLv2: #二级温差进入
|
|
|
+ dt_time=dt_time+(time2-time1).total_seconds()
|
|
|
+ if dt_time>self.param.temp_time:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C103'
|
|
|
+ faultlv=1
|
|
|
+ faultinfo='温度{}和{}温差大'.format(celltemp1.index(celltempmax1)+1,celltemp1.index(celltempmin1)+1)
|
|
|
+ faultadvice='技术介入诊断'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ dt_time=0
|
|
|
+ else: #ram当前故障中有该故障,则判断是否退出该故障
|
|
|
+ if (celltempmax1-celltempmin1)<self.param.CellTempDiffLv1-2 and (celltempmax2-celltempmin2)>self.param.CellTempDiffLv1-2: #二级温差恢复
|
|
|
+ time=self.bmstime[i]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C103'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+
|
|
|
+ else:
|
|
|
+ ot_time=0
|
|
|
+ ut_time=0
|
|
|
+ dt_time=0
|
|
|
+
|
|
|
+ #电流过流诊断.......................................................................................................................
|
|
|
+ if i>0.5:
|
|
|
+ step=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
|
|
|
+ if step<120 and self.packcrnt[i]>self.param.PackDisOc and self.packcrnt[i-1]>self.param.PackDisOc:
|
|
|
+ as_dis=as_dis+(self.packcrnt[i]-self.param.PackDisOc)*step #ah累计
|
|
|
+ elif step<120 and self.packcrnt[i]<self.param.PackChgOc and self.packcrnt[i-1]<self.param.PackChgOc:
|
|
|
+ as_chg=as_chg+(self.param.PackDisOc-self.packcrnt[i])*step #ah累计
|
|
|
+ else:
|
|
|
+ as_dis=0
|
|
|
+ as_chg=0
|
|
|
+
|
|
|
+ if not 'C306' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if as_dis>100:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C306'
|
|
|
+ faultlv=3
|
|
|
+ faultinfo='电池包放电过流'
|
|
|
+ faultadvice='联系用户询问用车场景,技术介入诊断'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ if self.packcrnt[i]<self.param.PackDisOc-10:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C306'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+
|
|
|
+ if not 'C305' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if as_chg>100:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C305'
|
|
|
+ faultlv=3
|
|
|
+ faultinfo='电池包充电过流'
|
|
|
+ faultadvice='联系用户询问用车场景,技术介入诊断'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ if self.packcrnt[i]>self.param.PackChgOc+10:
|
|
|
+ time=self.bmstime[i]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C305'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+
|
|
|
+ #SOC卡滞、跳变诊断................................................................................................
|
|
|
+ if i<1:
|
|
|
+ bmssoc_st=float(self.bms_soc[i])
|
|
|
+ bmssoc_last=float(self.bms_soc[i])
|
|
|
+ bmssoc_now=float(self.bms_soc[i])
|
|
|
+ else:
|
|
|
+ step=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
|
|
|
+ if step<120:
|
|
|
+ ah_accum=ah_accum-self.packcrnt[i]*step/3600 #ah累计
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ #SOC卡滞............................................................................................................
|
|
|
+ if abs(ah_accum)>self.param.Capacity*0.1:
|
|
|
+ bmssoc_now=float(self.bms_soc[i])
|
|
|
+ if not 'C106' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if abs(bmssoc_now-bmssoc_st)<self.param.SocClamp: #SOC卡滞故障进入
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C106'
|
|
|
+ faultlv=1
|
|
|
+ faultinfo='电池SOC卡滞'
|
|
|
+ faultadvice='技术介入诊断,检修电池BMS软件'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ if abs(bmssoc_now-bmssoc_st)>self.param.SocClamp: #SOC卡滞故障退出
|
|
|
+ time=self.bmstime[i]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C106'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ bmssoc_st=bmssoc_now
|
|
|
+ ah_accum=0
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+
|
|
|
+ #SOC跳变....................................................................................................................
|
|
|
+ bmssoc_last=float(self.bms_soc[i-1])
|
|
|
+ bmssoc_now=float(self.bms_soc[i])
|
|
|
+ if not 'C107' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if step<70 and abs(bmssoc_now-bmssoc_last)>self.param.SocJump: #SOC跳变进入
|
|
|
+ time=self.bmstime[i]
|
|
|
+ code='C107'
|
|
|
+ faultlv=1
|
|
|
+ faultinfo='电池SOC跳变{}%'.format(bmssoc_now-bmssoc_last)
|
|
|
+ faultadvice='技术介入诊断,检修电池BMS软件'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ if abs(bmssoc_now-bmssoc_st)<self.param.SocJump: #SOC跳变故障退出
|
|
|
+ time=self.bmstime[i]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C107'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+
|
|
|
+ #SOC一致性故障报警..........................................................................................................
|
|
|
+ if not self.df_uniform.empty:
|
|
|
+ cellsoc_diff=self.df_uniform.loc[0,'cellsoc_diff']
|
|
|
+ if not 'C201' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if cellsoc_diff>self.param.SocDiff: #SOC一致性差故障进入
|
|
|
+ time=self.bmstime[0]
|
|
|
+ code='C201'
|
|
|
+ faultlv=2
|
|
|
+ faultinfo='电芯{}和{}SOC差过大:{}'.format(int(self.df_uniform.loc[0,'cellmin_num']),int(self.df_uniform.loc[0,'cellmax_num']),cellsoc_diff)
|
|
|
+ faultadvice='技术介入诊断'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ if cellsoc_diff<self.param.SocDiff: #SOC一致性差故障恢复
|
|
|
+ time=self.bmstime[0]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C201'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ cellsoc_diff=3
|
|
|
+
|
|
|
+ #容量过低和一致性故障报警................................................................................................
|
|
|
+ if not self.df_soh.empty:
|
|
|
+ soh=self.df_soh.loc[0,'soh']
|
|
|
+ cellsoh=eval(self.df_soh.loc[0,'cellsoh'])
|
|
|
+ cellsoh=np.array(cellsoh)
|
|
|
+ cellsoh_lowindex=np.argwhere(cellsoh<self.param.SohLow)
|
|
|
+ cellsoh_lowindex=cellsoh_lowindex+1
|
|
|
+ if self.celltype==1 or self.celltype==2 or self.celltype==3 or self.celltype==4:
|
|
|
+ cellsoh_diff=np.max(cellsoh)-np.min(cellsoh)
|
|
|
+ if not 'C204' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if soh<self.param.SohLow: #soh过低故障进入
|
|
|
+ time=self.bmstime[0]
|
|
|
+ code='C204'
|
|
|
+ faultlv=2
|
|
|
+ faultinfo='电池包容量过低:电芯{}'.format(cellsoh_lowindex)
|
|
|
+ faultadvice='检修电池,更换容量过低的电芯或模组'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ if soh>self.param.SohLow+2: #soh过低故障恢复
|
|
|
+ time=self.bmstime[0]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C204'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+
|
|
|
+ if not 'C205' in list(self.df_diag_ram['code']): #当前故障中没有该故障,则判断是否发生该故障
|
|
|
+ if cellsoh_diff>self.param.SohDiff:
|
|
|
+ time=self.bmstime[0]
|
|
|
+ code='C205'
|
|
|
+ faultlv=2
|
|
|
+ faultinfo='电池包容量一致性差:电芯{}'.format(cellsoh_lowindex)
|
|
|
+ faultadvice='检修电池,更换容量过低的电芯或模组'
|
|
|
+ self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, end_time, self.sn, code, faultlv, faultinfo, faultadvice]
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ if cellsoh_diff<self.param.SohDiff-2:
|
|
|
+ time=self.bmstime[0]
|
|
|
+ self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['code']=='C205'].index, 'end_time'] = time
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ pass
|
|
|
+ else:
|
|
|
+ cellsoh_diff=5
|
|
|
+
|
|
|
+ #ram更新.......................................................................
|
|
|
+ df_bms_ram=pd.DataFrame(columns=['time', 'sn', 'packvolt', 'cellvolt', 'celltemp'])
|
|
|
+ df_bms_ram.loc[0]=[self.bmstime[0], self.sn, packvolt2, cellvolt2, celltemp2]
|
|
|
+
|
|
|
+ return self.df_diag_ram, df_bms_ram
|
|
|
+
|