CBMSSafetyWarning.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. import pandas as pd
  2. import numpy as np
  3. import datetime
  4. import time
  5. import pymannkendall as mk
  6. import BatParam
  7. class SafetyWarning:
  8. def __init__(self,sn,celltype,df_short,df_uniform,OutLineVol_Rate,df_soh): #参数初始化
  9. self.sn=sn
  10. self.celltype=celltype
  11. self.param=BatParam.BatParam(celltype)
  12. self.df_short=df_short
  13. self.df_uniform=df_uniform
  14. self.OutLineVol_Rate=OutLineVol_Rate
  15. self.df_soh=df_soh
  16. def diag(self):
  17. if self.celltype<=50:
  18. df_res=self._warning_diag()
  19. return df_res
  20. else:
  21. df_res=self._warning_diag()
  22. return df_res
  23. #电池热安全预警诊断功能.................................................................................................
  24. def _warning_diag(self):
  25. df_res=pd.DataFrame(columns=['time_st','time_sp','sn','faultcode','faultlv','faultinfo','faultadvice'])
  26. time_now=datetime.datetime.now()
  27. time_now=time_now.strftime('%Y-%m-%d %H:%M:%S')
  28. time_sp='0000-00-00 00:00:00'
  29. #参数初始化.......................................
  30. voltsigmafault=0
  31. uniformfault=0
  32. cellshortfault=0
  33. volt_rate=[]
  34. R2_list=[]
  35. voltsigmafault_list=[]
  36. uniformfault_list=[]
  37. mk_trend_list=[]
  38. mk_p_list=[]
  39. mk_z_list=[]
  40. mk_Tau_list=[]
  41. mk_slope_list=[]
  42. mk_s_list=[]
  43. mk_svar_list=[]
  44. if not self.df_short.empty:
  45. short_current=self.df_short['short_current']
  46. short_current=short_current.str.replace("[", '')
  47. short_current=short_current.str.replace("]", '')
  48. if not self.OutLineVol_Rate.empty:
  49. volt_column = ['CellVolt'+str(i) for i in range(1,self.param.CellVoltNums+1)]
  50. self.OutLineVol_Rate['VolChng_Uni']=self.OutLineVol_Rate['VolChng_Uni'].str.replace("[","")
  51. self.OutLineVol_Rate['VolChng_Uni']=self.OutLineVol_Rate['VolChng_Uni'].str.replace("]","")
  52. self.OutLineVol_Rate['VolOl_Uni']=self.OutLineVol_Rate['VolOl_Uni'].str.replace("[","")
  53. self.OutLineVol_Rate['VolOl_Uni']=self.OutLineVol_Rate['VolOl_Uni'].str.replace("]","")
  54. Volt_3Sigma=self.OutLineVol_Rate['VolOl_Uni'].str.split(',',expand=True)
  55. Volt_3Sigma.columns=volt_column
  56. #电压变化率
  57. VoltChange=self.OutLineVol_Rate['VolChng_Uni'].str.split(',',expand=True)
  58. VoltChange.columns=volt_column
  59. VoltChange['time']=self.OutLineVol_Rate['time']
  60. VoltChange = VoltChange.reset_index(drop=True)
  61. xtime1=VoltChange['time']
  62. time0=time.mktime(VoltChange.loc[0,'time'].timetuple())
  63. for i in range(0,len(VoltChange)):
  64. VoltChange.loc[i,'time']=(time.mktime(VoltChange.loc[i,'time'].timetuple())-time0)/36000
  65. #计算漏电流离群度
  66. if not self.df_short.empty:
  67. self.df_short['cellshort_sigma']=0
  68. for i in range(len(self.df_short)):
  69. cellshort=eval(self.df_short.loc[i,'short_current'])
  70. cellshort_std=np.std(cellshort)
  71. cellshort_mean=np.mean(cellshort)
  72. self.df_short.loc[i,'cellshort_sigma']=str(list((cellshort-cellshort_mean)/cellshort_std))
  73. if not self.df_uniform.empty:
  74. cellvolt_rank=self.df_uniform['cellvolt_rank']
  75. cellvolt_rank=cellvolt_rank.str.replace("[", '')
  76. cellvolt_rank=cellvolt_rank.str.replace("]", '')
  77. # plt.figure()
  78. for i in range(self.param.CellVoltNums):
  79. #漏电流故障判断...........................................................................
  80. if not self.df_short.empty:
  81. self.df_short['cellshort'+str(i+1)]=short_current.map(lambda x:eval(x.split(',')[i]))
  82. cellshort=self.df_short['cellshort'+str(i+1)]
  83. index_list=cellshort[cellshort<self.param.LeakCurrentLv2].index
  84. if len(index_list)>1:
  85. for j in range(1,len(index_list)):
  86. if index_list[j]-index_list[j-1]==1:
  87. cellshort_sigma1=eval(self.df_short.loc[index_list[j],'cellshort_sigma'])
  88. cellshort_sigma2=eval(self.df_short.loc[index_list[j-1],'cellshort_sigma'])
  89. if cellshort_sigma1[i]<-3 or cellshort_sigma2[i]<-3:
  90. cellshortfault=1
  91. else:
  92. pass
  93. else:
  94. pass
  95. #电压变化率及电压离群度.................................................................................
  96. if not self.OutLineVol_Rate.empty and VoltChange.iloc[-1]['time']*36000>18*3600 and len(VoltChange)>5:
  97. volt3sigma=np.array(Volt_3Sigma[volt_column[i]].map(lambda x:eval(x)))
  98. volt3sigma_sum=np.sum(volt3sigma<-3)
  99. #电压变化率
  100. VoltChange[volt_column[i]]=VoltChange[volt_column[i]].map(lambda x:eval(x))
  101. y=VoltChange[volt_column[i]]
  102. a1,b1=np.polyfit(VoltChange['time'].tolist(),y.tolist(),1)
  103. y1=a1*VoltChange['time']+b1
  104. y_mean=y.mean()
  105. R2=1-(np.sum((y1-y)**2))/(np.sum((y-y_mean)**2))
  106. R2_list.append(R2)
  107. volt_rate.append(a1)
  108. # plt.plot(xtime1,y1,label=a1)
  109. # plt.scatter( xtime1,VoltChange[volt_column[i]],marker='o')
  110. # plt.legend(loc='best')
  111. # plt.title('CellVolt'+str(i+1))
  112. # plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
  113. # plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
  114. # plt.show()
  115. if volt3sigma_sum>len(volt3sigma)/2:
  116. voltsigmafault=1
  117. else:
  118. voltsigmafault=0
  119. voltsigmafault_list.append(voltsigmafault)
  120. #mana-kendell趋势检验
  121. mk_res=mk.regional_test(np.array(y))
  122. mk_trend_list.append(mk_res.trend)
  123. mk_p_list.append(mk_res.p)
  124. mk_z_list.append(mk_res.z)
  125. mk_Tau_list.append(mk_res.Tau)
  126. mk_slope_list.append(mk_res.slope)
  127. mk_s_list.append(mk_res.s)
  128. mk_svar_list.append(mk_res.var_s)
  129. """
  130. trend:趋势;
  131. h:有无趋势;
  132. p:趋势的显著水平,越小趋势越明显;
  133. z:检验统计量,正代表随时间增大趋势,负代表随时间减小趋势;
  134. Tau:反映两个序列的相关性,接近1的值表示强烈的正相关,接近-1的值表示强烈的负相关;
  135. s:如果S是一个正数,那么后一部分的观测值相比之前的观测值会趋向于变大;如果S是一个负数,那么后一部分的观测值相比之前的观测值会趋向于变小
  136. slope:趋势斜率
  137. """
  138. # print('单体电压{}:\n'.format(i+1), mk_res)
  139. else:
  140. volt_rate.append(0)
  141. R2_list.append(0)
  142. voltsigmafault_list.append(0)
  143. mk_trend_list.append(0)
  144. mk_p_list.append(0)
  145. mk_z_list.append(0)
  146. mk_Tau_list.append(0)
  147. mk_slope_list.append(0)
  148. mk_s_list.append(0)
  149. mk_svar_list.append(0)
  150. #电芯SOC排名判断.............................................................................
  151. if not self.df_uniform.empty:
  152. self.df_uniform['cellvolt_rank'+str(i+1)]=cellvolt_rank.map(lambda x:eval(x.split(',')[i]))
  153. if max(self.df_uniform['cellvolt_rank'+str(i+1)])<5:
  154. uniformfault=1
  155. else:
  156. uniformfault=0
  157. else:
  158. uniformfault=0
  159. uniformfault_list.append(uniformfault)
  160. #漏电流热失控预警确认........................................................
  161. if cellshortfault==1:
  162. faultcode=110
  163. faultlv=4
  164. faultinfo='电芯{}发生热失控安全预警'.format(i+1)
  165. faultadvice='断开继电器,远离电池,并通知电池技术人员介入分析'
  166. df_res.loc[0]=[time_now, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  167. break
  168. else:
  169. pass
  170. #电池电压变化率离群度计算...............................................................................
  171. volt_rate_std=np.std(volt_rate)
  172. volt_rate_mean=np.mean(volt_rate)
  173. volt_rate_3sigma=(np.array(volt_rate)-volt_rate_mean)/volt_rate_std
  174. #mk离群度计算
  175. mk_slope_std=np.std(mk_slope_list)
  176. mk_slope_mean=np.mean(mk_slope_list)
  177. mk_slope_3sigma=(np.array(mk_slope_list)-mk_slope_mean)/mk_slope_std
  178. mk_z_std=np.std(mk_z_list)
  179. mk_z_mean=np.mean(mk_z_list)
  180. mk_z_3sigma=(np.array(mk_z_list)-mk_z_mean)/mk_z_std
  181. if not self.df_soh.empty and self.celltype<50:
  182. cellsoh=eval(self.df_soh.loc[0,'cellsoh'])
  183. cellsoh_std=np.std(cellsoh)
  184. cellsoh_mean=np.mean(cellsoh)
  185. cellsoh_3sigma=((np.array(cellsoh)-cellsoh_mean)/cellsoh_std)
  186. else:
  187. cellsoh_3sigma=[0]*self.param.CellVoltNums
  188. #电压/SOC变化率
  189. # for i in range(len(volt_rate)):
  190. # if volt_rate[i]<self.param.TrwVoltRate and volt_rate_3sigma[i]<-3 and abs(cellsoh_3sigma[i])<2.5 and voltsigmafault_list[i]==1:
  191. # faultcode=110
  192. # faultlv=4
  193. # faultinfo='电芯{}发生热失控安全预警'.format(i+1)
  194. # faultadvice='2联系用户远离电池,立刻召回电池'
  195. # df_res.loc[0]=[time_now, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  196. # else:
  197. # pass
  198. #mana-kendall趋势检测
  199. for i in range(len(mk_p_list)):
  200. #适用动态工况判断
  201. if mk_trend_list[i]=='decreasing' and mk_p_list[i]<self.param.mk_p and mk_z_list[i]<self.param.mk_z and mk_Tau_list[i]<self.param.mk_Tau and mk_s_list[i]<self.param.mk_s and mk_svar_list[i]>self.param.mk_svar and mk_slope_3sigma[i]<-3 and mk_slope_list[i]<self.param.mk_slope and abs(cellsoh_3sigma[i])<2.5 and volt_rate_3sigma[i]<-3:
  202. faultcode=110
  203. faultlv=4
  204. faultinfo='电芯{}发生热失控安全预警'.format(i+1)
  205. faultadvice='2联系用户远离电池,立刻召回电池'
  206. df_res.loc[0]=[time_now, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  207. #适用静态工况判断
  208. elif self.celltype<=50 and mk_trend_list[i]=='decreasing' and mk_p_list[i]<self.param.mk_p and mk_z_list[i]<-6 and (mk_Tau_list[i]<-0.9 or mk_z_3sigma[i]<-3) and mk_s_list[i]<self.param.mk_s and mk_svar_list[i]>self.param.mk_svar and mk_slope_3sigma[i]<-3.5 and mk_slope_list[i]<-0.03 and volt_rate_3sigma[i]<-3:
  209. faultcode=110
  210. faultlv=4
  211. faultinfo='电芯{}发生热失控安全预警'.format(i+1)
  212. faultadvice='2联系用户远离电池,立刻召回电池'
  213. df_res.loc[0]=[time_now, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  214. elif self.celltype>50 and mk_trend_list[i]=='decreasing' and mk_p_list[i]<self.param.mk_p and mk_z_list[i]<-6 and (mk_Tau_list[i]<-0.95 or mk_z_3sigma[i]<-3) and mk_s_list[i]<self.param.mk_s and mk_svar_list[i]>self.param.mk_svar and mk_slope_3sigma[i]<-3.5 and mk_slope_list[i]<-0.4 and volt_rate_3sigma[i]<-3:
  215. faultcode=110
  216. faultlv=4
  217. faultinfo='电芯{}发生热失控安全预警'.format(i+1)
  218. faultadvice='2联系用户远离电池,立刻召回电池'
  219. df_res.loc[0]=[time_now, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  220. else:
  221. pass
  222. # plt.show()
  223. return df_res