CBMSSafetyWarning.py 13 KB

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