CBMSSafetyWarning.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262
  1. import pandas as pd
  2. import numpy as np
  3. import datetime
  4. import time
  5. from matplotlib import pyplot as plt
  6. import pymannkendall as mk
  7. from LIB.MIDDLE.CellStateEstimation.Common.V1_0_1 import BatParam
  8. class SafetyWarning:
  9. def __init__(self,sn,celltype,df_short,df_uniform,OutLineVol_Rate,df_soh): #参数初始化
  10. self.sn=sn
  11. self.celltype=celltype
  12. self.param=BatParam.BatParam(celltype)
  13. self.df_short=df_short
  14. self.df_uniform=df_uniform
  15. self.OutLineVol_Rate=OutLineVol_Rate
  16. self.df_soh=df_soh
  17. def diag(self):
  18. if self.celltype<=50:
  19. df_res=self._warning_diag()
  20. return df_res
  21. else:
  22. df_res=self._warning_diag()
  23. return df_res
  24. #电池热安全预警诊断功能.................................................................................................
  25. def _warning_diag(self):
  26. df_res=pd.DataFrame(columns=['start_time', 'end_time', 'product_id', 'code', 'level', 'info','advice'])
  27. time_now=datetime.datetime.now()
  28. time_now=time_now.strftime('%Y-%m-%d %H:%M:%S')
  29. time_sp='0000-00-00 00:00:00'
  30. #参数初始化.......................................
  31. voltsigmafault=0
  32. uniformfault=0
  33. cellshortfault=0
  34. volt_rate=[]
  35. R2_list=[]
  36. voltsigmafault_list=[]
  37. uniformfault_list=[]
  38. mk_trend_list=[]
  39. mk_p_list=[]
  40. mk_z_list=[]
  41. mk_Tau_list=[]
  42. mk_slope_list=[]
  43. mk_s_list=[]
  44. mk_svar_list=[]
  45. if not self.df_short.empty:
  46. short_current=self.df_short['short_current']
  47. short_current=short_current.str.replace("[", '')
  48. short_current=short_current.str.replace("]", '')
  49. if not self.OutLineVol_Rate.empty:
  50. volt_column = ['单体电压'+str(i) for i in range(1,self.param.CellVoltNums+1)]
  51. self.OutLineVol_Rate['VolChng_Uni']=self.OutLineVol_Rate['VolChng_Uni'].str.replace("[","")
  52. self.OutLineVol_Rate['VolChng_Uni']=self.OutLineVol_Rate['VolChng_Uni'].str.replace("]","")
  53. self.OutLineVol_Rate['VolOl_Uni']=self.OutLineVol_Rate['VolOl_Uni'].str.replace("[","")
  54. self.OutLineVol_Rate['VolOl_Uni']=self.OutLineVol_Rate['VolOl_Uni'].str.replace("]","")
  55. Volt_3Sigma=self.OutLineVol_Rate['VolOl_Uni'].str.split(',',expand=True)
  56. Volt_3Sigma.columns=volt_column
  57. #电压变化率
  58. VoltChange=self.OutLineVol_Rate['VolChng_Uni'].str.split(',',expand=True)
  59. VoltChange.columns=volt_column
  60. VoltChange['time']=self.OutLineVol_Rate['time']
  61. VoltChange = VoltChange.reset_index(drop=True)
  62. xtime1=VoltChange['time']
  63. time0=time.mktime(VoltChange.loc[0,'time'].timetuple())
  64. for i in range(0,len(VoltChange)):
  65. VoltChange.loc[i,'time']=(time.mktime(VoltChange.loc[i,'time'].timetuple())-time0)/36000
  66. #计算漏电流离群度
  67. if not self.df_short.empty:
  68. self.df_short['cellshort_sigma']=0
  69. for i in range(len(self.df_short)):
  70. cellshort=eval(self.df_short.loc[i,'short_current'])
  71. cellshort_std=np.std(cellshort)
  72. cellshort_mean=np.mean(cellshort)
  73. self.df_short.loc[i,'cellshort_sigma']=str(list((cellshort-cellshort_mean)/cellshort_std))
  74. if not self.df_uniform.empty:
  75. cellvolt_rank=self.df_uniform['cellvolt_rank']
  76. cellvolt_rank=cellvolt_rank.str.replace("[", '')
  77. cellvolt_rank=cellvolt_rank.str.replace("]", '')
  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. VoltChange[volt_column[i]]=VoltChange[volt_column[i]].map(lambda x:eval(x))
  98. y=VoltChange[volt_column[i]]
  99. volt3sigma=np.array(Volt_3Sigma[volt_column[i]].map(lambda x:eval(x)))
  100. volt3sigma_sum=np.sum(volt3sigma<-3)
  101. #电压变化率
  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='单体电压'+str(i+1))
  109. # plt.xlabel('时间', fontsize=25)
  110. # plt.ylabel('SOC差', fontsize=25)
  111. # plt.xticks(fontsize=20)
  112. # plt.yticks(fontsize=20)
  113. # plt.scatter( xtime1,VoltChange[volt_column[i]],marker='o')
  114. # plt.legend(bbox_to_anchor=(1, 0), loc=3, fontsize=16)
  115. # plt.title(self.celltype)
  116. # plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
  117. # plt.rcParams['axes.unicode_minus']=False #用来正常显示负号
  118. # # plt.show()
  119. if volt3sigma_sum>len(volt3sigma)/2:
  120. voltsigmafault=1
  121. else:
  122. voltsigmafault=0
  123. voltsigmafault_list.append(voltsigmafault)
  124. #mana-kendell趋势检验
  125. mk_res=mk.regional_test(np.array(y))
  126. mk_trend_list.append(mk_res.trend)
  127. mk_p_list.append(mk_res.p)
  128. mk_z_list.append(mk_res.z)
  129. mk_Tau_list.append(mk_res.Tau)
  130. mk_slope_list.append(mk_res.slope)
  131. mk_s_list.append(mk_res.s)
  132. mk_svar_list.append(mk_res.var_s)
  133. """
  134. trend:趋势;
  135. h:有无趋势;
  136. p:趋势的显著水平,越小趋势越明显;
  137. z:检验统计量,正代表随时间增大趋势,负代表随时间减小趋势;
  138. Tau:反映两个序列的相关性,接近1的值表示强烈的正相关,接近-1的值表示强烈的负相关;
  139. s:Mann-Kendal的分数,如果S是一个正数,那么后一部分的观测值相比之前的观测值会趋向于变大;如果S是一个负数,那么后一部分的观测值相比之前的观测值会趋向于变小
  140. slope:趋势斜率
  141. """
  142. # print('单体电压{}:\n'.format(i+1), mk_res)
  143. else:
  144. volt_rate.append(0)
  145. R2_list.append(0)
  146. voltsigmafault_list.append(0)
  147. mk_trend_list.append(0)
  148. mk_p_list.append(0)
  149. mk_z_list.append(0)
  150. mk_Tau_list.append(0)
  151. mk_slope_list.append(0)
  152. mk_s_list.append(0)
  153. mk_svar_list.append(0)
  154. #电芯SOC排名判断.............................................................................
  155. if not self.df_uniform.empty:
  156. self.df_uniform['cellvolt_rank'+str(i+1)]=cellvolt_rank.map(lambda x:eval(x.split(',')[i]))
  157. if max(self.df_uniform['cellvolt_rank'+str(i+1)])<5:
  158. uniformfault=1
  159. else:
  160. uniformfault=0
  161. else:
  162. uniformfault=0
  163. uniformfault_list.append(uniformfault)
  164. #漏电流热失控预警确认........................................................
  165. if cellshortfault==1:
  166. faultcode=110
  167. faultlv=4
  168. faultinfo='电芯{}发生热失控安全预警'.format(i+1)
  169. faultadvice='1联系用户远离电池,立刻召回电池'
  170. df_res.loc[0]=[time_now, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  171. break
  172. else:
  173. pass
  174. # plt.show()
  175. #电池电压变化率离群度计算...............................................................................
  176. volt_rate_std=np.std(volt_rate)
  177. volt_rate_mean=np.mean(volt_rate)
  178. volt_rate_3sigma=(np.array(volt_rate)-volt_rate_mean)/volt_rate_std
  179. #mk离群度计算
  180. mk_slope_std=np.std(mk_slope_list)
  181. mk_slope_mean=np.mean(mk_slope_list)
  182. mk_slope_3sigma=(np.array(mk_slope_list)-mk_slope_mean)/mk_slope_std
  183. # mk_s_std=np.std(mk_s_list)
  184. # mk_s_mean=np.mean(mk_s_list)
  185. # mk_s_3sigma=(np.array(mk_s_list)-mk_s_mean)/mk_s_std
  186. mk_z_std=np.std(mk_z_list)
  187. mk_z_mean=np.mean(mk_z_list)
  188. mk_z_3sigma=(np.array(mk_z_list)-mk_z_mean)/mk_z_std
  189. if not self.df_soh.empty and self.celltype<50:
  190. cellsoh=eval(self.df_soh.loc[0,'cellsoh'])
  191. cellsoh_std=np.std(cellsoh)
  192. cellsoh_mean=np.mean(cellsoh)
  193. cellsoh_3sigma=((np.array(cellsoh)-cellsoh_mean)/cellsoh_std)
  194. else:
  195. cellsoh_3sigma=[0]*self.param.CellVoltNums
  196. #电压/SOC变化率
  197. # for i in range(len(volt_rate)):
  198. # 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:
  199. # faultcode=110
  200. # faultlv=4
  201. # faultinfo='电芯{}发生热失控安全预警'.format(i+1)
  202. # faultadvice='2联系用户远离电池,立刻召回电池'
  203. # df_res.loc[0]=[time_now, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  204. # else:
  205. # pass
  206. #mana-kendall趋势检测
  207. for i in range(len(mk_p_list)):
  208. #适用动态工况判断
  209. 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_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:
  210. faultcode=110
  211. faultlv=4
  212. faultinfo='电芯{}发生热失控安全预警'.format(i+1)
  213. faultadvice='2联系用户远离电池,立刻召回电池'
  214. df_res.loc[0]=[time_now, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  215. #适用静态工况判断
  216. 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_slope_3sigma[i]<-3.5 and mk_slope_list[i]<-0.025 and volt_rate_3sigma[i]<-3:
  217. faultcode=110
  218. faultlv=4
  219. faultinfo='电芯{}发生热失控安全预警'.format(i+1)
  220. faultadvice='2联系用户远离电池,立刻召回电池'
  221. df_res.loc[0]=[time_now, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  222. 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_slope_3sigma[i]<-3.5 and mk_slope_list[i]<-0.25 and volt_rate_3sigma[i]<-3:
  223. faultcode=110
  224. faultlv=4
  225. faultinfo='电芯{}发生热失控安全预警'.format(i+1)
  226. faultadvice='2联系用户远离电池,立刻召回电池'
  227. df_res.loc[0]=[time_now, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  228. else:
  229. pass
  230. return df_res