CBMSBatDiag.py 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. import pandas as pd
  2. import numpy as np
  3. import datetime
  4. import BatParam
  5. class BatDiag:
  6. def __init__(self,sn,celltype,df_bms,df_soh,df_soc,df_uniform,df_diag_ram): #参数初始化
  7. self.sn=sn
  8. self.celltype=celltype
  9. self.param=BatParam.BatParam(celltype)
  10. self.df_bms=df_bms
  11. self.df_soh=df_soh
  12. self.df_soc=df_soc
  13. self.df_uniform=df_uniform
  14. self.df_diag_ram=df_diag_ram.copy()
  15. self.packcrnt=df_bms['PackCrnt']*self.param.PackCrntDec
  16. self.packvolt=df_bms['PackVolt']
  17. self.bms_soc=df_bms['PackSOC']
  18. self.bmstime= pd.to_datetime(df_bms['time'], format='%Y-%m-%d %H:%M:%S')
  19. self.cellvolt_name=['CellVolt'+str(x) for x in range(1,self.param.CellVoltNums+1)]
  20. self.celltemp_name=['CellTemp'+str(x) for x in range(1,self.param.CellTempNums+1)]
  21. def diag(self):
  22. if len(self.df_bms)>1:
  23. if self.celltype<=50:
  24. df_res=self._ncm_diag()
  25. return df_res
  26. else:
  27. df_res=self._ncm_diag()
  28. return df_res
  29. else:
  30. return pd.DataFrame()
  31. #定义滑动滤波函数.............................................................................................
  32. def _np_move_avg(self,a, n, mode="same"):
  33. return (np.convolve(a, np.ones((n,)) / n, mode=mode))
  34. #寻找当前行数据的所有温度值...................................................................................
  35. def _celltemp_get(self,num):
  36. celltemp = list(self.df_bms.loc[num,self.celltemp_name])
  37. return celltemp
  38. #获取当前行所有电压数据............................................................................................
  39. def _cellvolt_get(self,num):
  40. cellvolt = list(self.df_bms.loc[num,self.cellvolt_name])
  41. return cellvolt
  42. #..........................................三元电池诊断功能..................................................................
  43. def _ncm_diag(self):
  44. #参数初始化
  45. bmssoc_st=float(self.bms_soc[0]) #SOC卡滞初始参数
  46. ah_accum=0 #SOC卡滞初始参数
  47. as_chg=0 #过流诊断初始参数
  48. as_dis=0 #过流诊断初始参数
  49. time1=self.bmstime[0] #温升速率初始参数
  50. temp1=np.array(self._celltemp_get(0)) #温升速率初始参数
  51. temprate_cnt=0
  52. ot_time=0
  53. ut_time=0
  54. dt_time=0
  55. cov_time=0
  56. cuv_time=0
  57. cdv_time=0
  58. pov_time=0
  59. puv_time=0
  60. vv_time=0
  61. tv_time=0
  62. celltempvalid=1
  63. cellvoltvalid=1
  64. time_sp='0000-00-00 00:00:00'
  65. for i in range(1,len(self.df_bms)):
  66. time=self.bmstime[i]
  67. #温度诊断功能.............................................................................................................
  68. celltemp0=self._celltemp_get(i-1)
  69. celltemp1=self._celltemp_get(i)
  70. celltempmin0=min(celltemp0)
  71. celltempmin1=min(celltemp1)
  72. celltempmax0=max(celltemp0)
  73. celltempmax1=max(celltemp1)
  74. #温度有效性判断............................................................................................
  75. if not 2 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  76. if celltempmax0>self.param.CellTempUpLmt or celltempmin0<self.param.CellTempLwLmt:
  77. tv_time=tv_time+(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
  78. if tv_time>55:
  79. celltempvalid=0
  80. faultcode=2
  81. faultlv=2
  82. cellnum1=np.where(np.array(celltemp1)<self.param.CellTempLwLmt)[0]+1
  83. cellnum2=np.where(np.array(celltemp1)>self.param.CellTempUpLmt)[0]+1
  84. cellnum=list(cellnum1)+list(cellnum2)
  85. faultinfo='电芯温度{}无效'.format(cellnum)
  86. faultadvice='丢失温度信息,无法全面监控电池安全;请停止充放电,并检修电池采样系统及数据传输系统'
  87. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  88. else:
  89. pass
  90. else: #不作处理
  91. celltempvalid=1
  92. tv_time=0
  93. else: #ram当前故障中有该故障,则判断是否退出该故障
  94. if celltempmax0<self.param.CellTempUpLmt-10 and celltempmin0>self.param.CellTempLwLmt+10:
  95. celltempvalid=1
  96. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==2].index[0], 'time_sp'] = time
  97. else:
  98. celltempvalid=0
  99. if celltempvalid==1:
  100. #过温判断.............................................................................................................
  101. if not 4 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  102. if celltempmax0>self.param.CellTempHighLv2 and celltempmax1>self.param.CellTempHighLv2: #二级高温进入
  103. ot_time=ot_time+(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
  104. if ot_time>self.param.temp_time:
  105. faultcode=4
  106. faultlv=3
  107. cellnum=np.where(np.array(celltemp1)>self.param.CellTempHighLv2)[0]+1
  108. faultinfo='电芯温度{}过温'.format(list(cellnum))
  109. faultadvice='高温下充放电,会导致容量衰减过快,并存在热失控风险;请停止充放电,开启电池冷却功能,并通知电池技术人员介入分析'
  110. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  111. else:
  112. pass
  113. else:
  114. ot_time=0
  115. else: #ram当前故障中有该故障,则判断是否退出该故障
  116. if celltempmax0<self.param.CellTempHighLv1-5 and celltempmax1<self.param.CellTempHighLv1-5: #二级高温恢复
  117. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==4].index[0], 'time_sp'] = time
  118. else:
  119. pass
  120. #欠温判断.................................................................................................................
  121. if not 6 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  122. if celltempmin0<self.param.CellTempLowLv2 and celltempmin1<self.param.CellTempLowLv2: #二级低温进入
  123. ut_time=ut_time+(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
  124. if ut_time>self.param.temp_time:
  125. faultcode=6
  126. faultlv=3
  127. cellnum=np.where(np.array(celltemp1)<self.param.CellTempLowLv2)[0]+1
  128. faultinfo='电芯温度{}过低'.format(list(cellnum))
  129. faultadvice='低温下充电,会导致析锂,存在电池安全与寿命衰减过快风险;请停止充放电,并开启电池加热功能'
  130. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  131. else:
  132. pass
  133. else:
  134. ut_time=0
  135. else: #ram当前故障中有该故障,则判断是否退出该故障
  136. if celltempmax0>self.param.CellTempLowLv1+2 and celltempmax1>self.param.CellTempLowLv1+2: #二级高温恢复
  137. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==6].index[0], 'time_sp'] = time
  138. else:
  139. pass
  140. #温差判断.............................................................................................................................
  141. if not 8 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  142. if (celltempmax0-celltempmin0)>self.param.CellTempDiffLv2 and (celltempmax1-celltempmax0)>self.param.CellTempDiffLv2: #二级温差进入
  143. dt_time=dt_time+(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
  144. if dt_time>self.param.temp_time:
  145. faultcode=8
  146. faultlv=3
  147. faultinfo='电芯温度{}和{}温差大'.format(celltemp1.index(celltempmax1)+1,celltemp1.index(celltempmin1)+1)
  148. faultadvice='存在电芯的老化速率不一致的风险;请检查电池温度采样系统'
  149. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  150. else:
  151. pass
  152. else:
  153. dt_time=0
  154. else: #ram当前故障中有该故障,则判断是否退出该故障
  155. if (celltempmax0-celltempmin0)<self.param.CellTempDiffLv1-2 and (celltempmax1-celltempmax0)>self.param.CellTempDiffLv1-2: #二级温差恢复
  156. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==8].index[0], 'time_sp'] = time
  157. else:
  158. pass
  159. #温升判断
  160. time2=self.bmstime[i]
  161. delttime=(time2-time1).total_seconds()
  162. if delttime>20:
  163. temp2=np.array(self._celltemp_get(i))
  164. celltemp_rate=(max(temp2-temp1)*60)/delttime #计算最大温升速率
  165. temp1=temp2 #更新初始温度
  166. time1=time2 #更新初始时间
  167. if not 9 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  168. if celltemp_rate>self.param.CellTempRate:
  169. temprate_cnt=temprate_cnt+1
  170. if temprate_cnt>2: #温升故障进入
  171. faultcode=9
  172. faultlv=3
  173. faultinfo='电芯温升速率过快:{}℃/min'.format(celltemp_rate)
  174. faultadvice='温升速率过快,存在热失控风险;禁止充放电,并通知电池技术人员介入分析'
  175. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  176. else:
  177. pass
  178. else: #ram当前故障中有该故障,则判断是否退出该故障
  179. pass
  180. else:
  181. if celltemp_rate<self.param.CellTempRate-1: #温升故障恢复
  182. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==9].index[0], 'time_sp'] = time
  183. else:
  184. pass
  185. else:
  186. ot_time=0
  187. ut_time=0
  188. dt_time=0
  189. #电压诊断功能.................................................................................................
  190. cellvolt0=self._cellvolt_get(i-1)
  191. cellvolt1=self._cellvolt_get(i)
  192. cellvoltmin0=min(cellvolt0)
  193. cellvoltmax0=max(cellvolt0)
  194. cellvoltmin1=min(cellvolt1)
  195. cellvoltmax1=max(cellvolt1)
  196. cellvoltmin_index0=cellvolt0.index(cellvoltmin0)
  197. cellvoltmax_index0=cellvolt0.index(cellvoltmax0)
  198. cellvoltmin_index1=cellvolt1.index(cellvoltmin1)
  199. cellvoltmax_index1=cellvolt1.index(cellvoltmax1)
  200. #电压断线诊断...................................................................................................
  201. if not 10 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  202. if (cellvoltmin0<2 and cellvoltmax0>4.5 and abs(cellvoltmax_index0-cellvoltmin_index0)==1) and (cellvoltmin1<2 and cellvoltmax1>4.5 and abs(cellvoltmax_index1-cellvoltmin_index1)==1): #电压断线故障进入
  203. vv_time=vv_time+(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
  204. if vv_time>55:
  205. cellvoltvalid=0
  206. faultcode=10
  207. faultlv=2
  208. faultinfo='{}号电芯和{}号电芯电压采样断线'.format(cellvolt0.index(cellvoltmax0)+1,cellvolt0.index(cellvoltmin0)+1)
  209. faultadvice='丢失部分电压信息,无法全面监控电池安全;禁止充放电,请检查电池电压采样系统'
  210. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  211. else:
  212. pass
  213. else:
  214. cellvoltvalid=1
  215. vv_time=0
  216. else: #ram当前故障中有该故障,则判断是否退出该故障
  217. if cellvoltmin0>2 and cellvoltmax0<4.5: #电压断线故障恢复
  218. cellvoltvalid=1
  219. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==10].index[0], 'time_sp'] = time
  220. else:
  221. cellvoltvalid=0
  222. #电压无效诊断.......................................................................................................
  223. if not 11 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  224. if (cellvoltmin0<0.5 and cellvoltmin1<0.5) or (cellvoltmax0>4.5 and cellvoltmax1>4.5):
  225. cellvoltvalid=0
  226. faultcode=11
  227. faultlv=2
  228. cellnum1=np.where(np.array(cellvolt1)<0.5)[0]+1
  229. cellnum2=np.where(np.array(cellvolt1)>4.5)[0]+1
  230. cellnum=list(cellnum1)+list(cellnum2)
  231. faultinfo='电芯电压{}采样无效'.format(cellnum)
  232. faultadvice='丢失电压信息,无法全面监控电池安全;禁止充放电,请检查电池电压采样系统'
  233. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  234. else:
  235. cellvoltvalid=1
  236. else:
  237. if cellvoltmin0>2 and cellvoltmax0<4.5 and cellvoltmin1>2 and cellvoltmax1<4.5: #电压断线故障恢复
  238. cellvoltvalid=1
  239. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==11].index[0], 'time_sp'] = time
  240. else:
  241. cellvoltvalid=0
  242. if cellvoltvalid==1:
  243. #过压诊断.............................................................................................................
  244. if not 12 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  245. if cellvoltmax0>self.param.CellOvLv2 and cellvoltmax1>self.param.CellOvLv2 and self.packcrnt[i]<-0.5: #二级过压进入
  246. cov_time=cov_time+(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
  247. if cov_time>self.param.volt_time:
  248. faultcode=12
  249. faultlv=3
  250. cellnum=np.where(np.array(cellvolt1)>self.param.CellOvLv2)[0]+1
  251. faultinfo='{}号电芯过压'.format(list(cellnum))
  252. faultadvice='过压可能导致电池析锂,存在电池安全与寿命衰减过快风险;禁止充电,若持续>10min,请通知电池技术人员介入分析'
  253. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  254. else:
  255. pass
  256. else:
  257. cov_time=0
  258. else: #ram当前故障中有该故障,则判断是否退出该故障
  259. if cellvoltmax0<self.param.CellOvLv1-0.05 and cellvoltmax1<self.param.CellOvLv1-0.05: #二级过压故障恢复
  260. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==12].index[0], 'time_sp'] = time
  261. else:
  262. pass
  263. #欠压诊断.................................................................................................................
  264. if not 14 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  265. if cellvoltmin0<self.param.CellUvLv2 and cellvoltmin1<self.param.CellUvLv2: #二级欠压
  266. cuv_time=cuv_time+(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
  267. if cuv_time>self.param.volt_time:
  268. faultcode=14
  269. faultlv=3
  270. cellnum=np.where(np.array(cellvolt1)<self.param.CellUvLv2)[0]+1
  271. faultinfo='{}号电芯欠压'.format(list(cellnum))
  272. faultadvice='欠压可能导致电池过放;禁止放电,请充电,若欠压持续>10min,通知电池技术人员介入分析'
  273. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  274. else:
  275. pass
  276. else:
  277. cuv_time=0
  278. else:
  279. if cellvoltmin0>self.param.CellUvLv1+0.1 and cellvoltmin1>self.param.CellUvLv1+0.1:
  280. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==14].index[0], 'time_sp'] = time
  281. else:
  282. pass
  283. #电芯压差大.....................................................................................................................................................
  284. if not 16 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  285. if (cellvoltmax0-cellvoltmin0)>self.param.CellVoltDiffLv2 and (cellvoltmax1-cellvoltmin1)>self.param.CellVoltDiffLv2: #二级电芯压差
  286. cdv_time=cdv_time+(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
  287. if cdv_time>self.param.volt_time:
  288. faultcode=16
  289. faultlv=3
  290. faultinfo='{}号电芯和{}号电芯压差大'.format(cellvolt1.index(cellvoltmax1)+1,cellvolt1.index(cellvoltmin1)+1)
  291. faultadvice='容量/内阻不一致;请均衡电池,若均衡无法解决问题,请通知电池技术人员介入分析'
  292. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  293. else:
  294. pass
  295. else:
  296. cdv_time=0
  297. else:
  298. if (cellvoltmax0-cellvoltmin0)<self.param.CellVoltDiffLv1-0.05 and (cellvoltmax1-cellvoltmin1)<self.param.CellVoltDiffLv1-0.05: #二级欠压恢复
  299. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==16].index[0], 'time_sp'] = time
  300. else:
  301. pass
  302. else:
  303. cov_time=0
  304. cuv_time=0
  305. cdv_time=0
  306. #电池包诊断.....................................................................................................................................
  307. if self.packvolt[i-1]>2*self.param.CellVoltNums and self.packvolt[i]<4.5*self.param.CellVoltNums: #电池包电压有效性
  308. packvoltvalid=1
  309. else:
  310. packvoltvalid=0
  311. if packvoltvalid==1:
  312. if not 18 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  313. if self.packvolt[i-1]>self.param.PackVoltOvLv2 and self.packvolt[i]>self.param.PackVoltOvLv2 and self.packcrnt[i]<-0.5: #电池包过压二级进入
  314. pov_time=pov_time+(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
  315. if pov_time>self.param.volt_time:
  316. faultcode=18
  317. faultlv=3
  318. faultinfo='电池包过压'
  319. faultadvice='过压会导致电池析锂,存在电池安全与寿命衰减过快风险;请停止充电,若过压持续>10min,通知电池技术人员介入分析'
  320. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  321. else:
  322. pass
  323. else:
  324. pov_time=0
  325. else:
  326. if self.packvolt[i-1]<self.param.PackVoltOvLv1 and self.packvolt[i]<self.param.PackVoltOvLv1: #电池包过压二级恢复
  327. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==18].index[0], 'time_sp'] = time
  328. else:
  329. pass
  330. if not 20 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  331. if self.packvolt[i-1]<self.param.PackVoltUvLv2 and self.packvolt[i]<self.param.PackVoltUvLv2: #电池包二级欠压进入
  332. puv_time=puv_time+(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
  333. if puv_time>self.param.volt_time:
  334. faultcode=20
  335. faultlv=3
  336. faultinfo='电池包欠压'
  337. faultadvice='欠压可能导致电池过放;请停止放电,并充电,若欠压持续>10min,请通知电池技术人员介入分析'
  338. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  339. else:
  340. pass
  341. else:
  342. puv_time=0
  343. else:
  344. if self.packvolt[i-1]>self.param.PackVoltUvLv1 and self.packvolt[i]>self.param.PackVoltUvLv1: #电池包二级欠压恢复
  345. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==20].index[0], 'time_sp'] = time
  346. else:
  347. pass
  348. else:
  349. pov_time=0
  350. puv_time=0
  351. #电流过流诊断.......................................................................................................................
  352. step=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
  353. if step<60 and self.packcrnt[i]>self.param.PackDisOc and self.packcrnt[i-1]>self.param.PackDisOc:
  354. as_dis=as_dis+(self.packcrnt[i]-self.param.self.PackDisOc)*step #ah累计
  355. elif step<60 and self.packcrnt[i]<self.param.PackChgOc and self.packcrnt[i-1]<self.param.PackChgOc:
  356. as_chg=as_chg+(self.param.PackChgOc-self.packcrnt[i])*step #ah累计
  357. else:
  358. as_dis=0
  359. as_chg=0
  360. if not 22 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  361. if as_dis>100:
  362. faultcode=22
  363. faultlv=3
  364. faultinfo='电池包放电过流'
  365. faultadvice='长时间过流会导致电池欠压及温升过快;请停止放电,若持续>5min,断开继电器,并通知电池技术人员介入分析'
  366. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  367. else:
  368. pass
  369. else:
  370. if self.packcrnt[i-1]<self.param.PackDisOc-10 and self.packcrnt[i]<self.param.PackDisOc-10:
  371. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==22].index[0], 'time_sp'] = time
  372. else:
  373. pass
  374. if not 21 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  375. if as_chg>100:
  376. faultcode=21
  377. faultlv=3
  378. faultinfo='电池包充电过流'
  379. faultadvice='过流会导致电池析锂,存在电池安全与寿命衰减过快风险;请停止充电,若持续>5min,断开继电器,并通知电池技术人员介入分析'
  380. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  381. else:
  382. pass
  383. else:
  384. if self.packcrnt[i-1]>self.param.PackChgOc+10 and self.packcrnt[i]>self.param.PackChgOc+10:
  385. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==21].index[0], 'time_sp'] = time
  386. else:
  387. pass
  388. #SOC卡滞、跳变诊断................................................................................................
  389. step=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
  390. if step<120:
  391. ah_accum=ah_accum-self.packcrnt[i]*step/3600 #ah累计
  392. else:
  393. pass
  394. #SOC卡滞............................................................................................................
  395. if abs(ah_accum)>self.param.Capacity*0.1:
  396. bmssoc_now=float(self.bms_soc[i])
  397. if not 27 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  398. if abs(bmssoc_now-bmssoc_st)<self.param.SocClamp: #SOC卡滞故障进入
  399. faultcode=27
  400. faultlv=1
  401. faultinfo='电池SOC卡滞'
  402. faultadvice='请通知电池供应商检查电池BMS软件是否正常'
  403. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  404. else:
  405. pass
  406. else:
  407. if abs(bmssoc_now-bmssoc_st)>self.param.SocClamp: #SOC卡滞故障退出
  408. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==27].index[0], 'time_sp'] = time
  409. else:
  410. pass
  411. bmssoc_st=bmssoc_now
  412. ah_accum=0
  413. else:
  414. pass
  415. #SOC跳变....................................................................................................................
  416. bmssoc_last=float(self.bms_soc[i-1])
  417. bmssoc_now=float(self.bms_soc[i])
  418. if not 28 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  419. if step<30 and abs(bmssoc_now-bmssoc_last)>self.param.SocJump and 1<bmssoc_now<=100 and 1<bmssoc_last<=100: #SOC跳变进入
  420. faultcode=28
  421. faultlv=1
  422. faultinfo='电池SOC跳变'
  423. faultadvice='请通知电池供应商检查电池BMS软件是否正常'
  424. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  425. else:
  426. pass
  427. else:
  428. if abs(bmssoc_now-bmssoc_st)<self.param.SocJump: #SOC跳变故障退出
  429. time=self.bmstime[i]
  430. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==28].index[0], 'time_sp'] = time
  431. else:
  432. pass
  433. # #BMS故障报警........................................................................................................
  434. # if not 1 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  435. # if self.bmsfault1[i-1] is None or self.bmsfault1[i] is None:
  436. # self.bmsfault1[i-1]=0
  437. # self.bmsfault1[i]=0
  438. # if self.bmsfault1[i-1]>0 or self.bmsfault1[i]>0: #BMS故障进入
  439. # time=self.bmstime[0]
  440. # faultcode=1
  441. # faultlv=2
  442. # faultinfo='BMS故障报警:{}'.format(self.bmsfault1[i-1])
  443. # faultadvice='检修电池'
  444. # self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  445. # else:
  446. # pass
  447. # else:
  448. # if self.bmsfault1[i-1]==0 and self.bmsfault1[i]==0: #BMS故恢复
  449. # time=self.bmstime[i]
  450. # self.df_diag_ram[self.df_diag_ram[self.df_diag_ram['faultcode']==1].index[0], 'time_sp'] = time
  451. #SOC过低故障报警............................................................................................................
  452. if not self.df_soc.empty:
  453. if not 26 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  454. if self.df_soc.loc[0, 'packsoc']<self.param.SocLow: #SOC过低故障进入
  455. time=self.df_soc.loc[0, 'time']
  456. faultcode=26
  457. faultlv=1
  458. faultinfo='电池包电量过低'
  459. faultadvice='电量过低会引起电池过放;请停止放电,并充电'
  460. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  461. else:
  462. pass
  463. else:
  464. if self.df_soc.loc[0, 'packsoc']>self.param.SocLow: #SOC过低故障退出
  465. time=self.df_soc.loc[0, 'time']
  466. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==26].index[0], 'time_sp'] = time
  467. else:
  468. pass
  469. else:
  470. pass
  471. #SOC一致性故障报警..........................................................................................................
  472. if not self.df_uniform.empty:
  473. cellsoc_diff=self.df_uniform.loc[0,'cellsoc_diff']
  474. if not 25 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  475. if cellsoc_diff>self.param.SocDiff: #SOC一致性差故障进入
  476. time=self.bmstime[0]
  477. faultcode=25
  478. faultlv=1
  479. faultinfo='电芯{}和{}SOC差过大:{}'.format(self.df_uniform.loc[0,'cellmin_num'],self.df_uniform.loc[0,'cellmax_num'],cellsoc_diff)
  480. faultadvice='请均衡电池,若无法解决,请通知电池技术人员介入分析'
  481. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  482. else:
  483. pass
  484. else:
  485. if cellsoc_diff<self.param.SocDiff: #SOC一致性差故障恢复
  486. time=self.bmstime[0]
  487. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==25].index[0], 'time_sp'] = time
  488. else:
  489. cellsoc_diff=3
  490. #容量过低和一致性故障报警................................................................................................
  491. if not self.df_soh.empty:
  492. soh=self.df_soh.loc[0,'soh']
  493. cellsoh=eval(self.df_soh.loc[0,'cellsoh'])
  494. cellsoh=np.array(cellsoh)
  495. cellsoh_lowindex=np.argwhere(cellsoh<self.param.SohLow)
  496. cellsoh_lowindex=cellsoh_lowindex+1
  497. cellsoh_diff=max(cellsoh)-min(cellsoh)
  498. if not 23 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  499. if soh<self.param.SohLow: #soh过低故障进入
  500. time=self.bmstime[0]
  501. faultcode=23
  502. faultlv=1
  503. faultinfo='电池包容量过低:{}号电芯'.format(cellsoh_lowindex)
  504. faultadvice='电池容量过低,会导致电池放电电量不足;建议更换容量过低的电芯或模组'
  505. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  506. else:
  507. pass
  508. else:
  509. if soh>self.param.SohLow+2: #soh过低故障恢复
  510. time=self.bmstime[0]
  511. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==23].index[0], 'time_sp'] = time
  512. else:
  513. pass
  514. if not 24 in list(self.df_diag_ram['faultcode']): #当前故障中没有该故障,则判断是否发生该故障
  515. cellsohmin=min(cellsoh)
  516. cellsohmax=max(cellsoh)
  517. if cellsoh_diff>self.param.SohDiff:
  518. time=self.bmstime[0]
  519. faultcode=24
  520. faultlv=1
  521. faultinfo='电池包容量一致性差:{}号和{}号电芯'.format(list(cellsoh).index(cellsohmin)+1,list(cellsoh).index(cellsohmax)+1)
  522. faultadvice='电池容量不一致性差,会导致电池放电电量不足;建议更换容量过低的电芯或模组'
  523. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  524. else:
  525. pass
  526. else:
  527. if cellsoh_diff<self.param.SohDiff-2:
  528. time=self.bmstime[0]
  529. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==24].index[0], 'time_sp'] = time
  530. else:
  531. pass
  532. #soh长时间未标定
  533. if not 100 in list(self.df_diag_ram['faultcode']):
  534. time=self.bmstime[0]
  535. if (time-self.df_soh.loc[0,'time_st']).total_seconds()>30*24*3600:
  536. faultcode=100
  537. faultlv=1
  538. faultinfo='电池包状态长时间未标定'
  539. faultadvice='电池长时间未标定,存在电池状态估算不准确风险,请对电池进行:放电至SOC<10%-静置>1h-充满,操作'
  540. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  541. else:
  542. pass
  543. else:
  544. time=self.bmstime[0]
  545. if (time-self.df_soh.loc[0,'time_st']).total_seconds()<29*24*3600:
  546. self.df_diag_ram.loc[self.df_diag_ram[self.df_diag_ram['faultcode']==100].index[0], 'time_sp'] = time
  547. else:
  548. pass
  549. else:
  550. #soh长时间未标定
  551. if not 100 in list(self.df_diag_ram['faultcode']):
  552. time=self.bmstime[0]
  553. faultcode=100
  554. faultlv=1
  555. faultinfo='电池包状态长时间未标定'
  556. faultadvice='电池长时间未标定,存在电池状态估算不准确风险,请对电池进行:放电至SOC<10%-静置>1h-充满,操作'
  557. self.df_diag_ram.loc[len(self.df_diag_ram)]=[time, time_sp, self.sn, faultcode, faultlv, faultinfo, faultadvice]
  558. else:
  559. pass
  560. #电池健康度评分.....................................................................................................
  561. column_name=['time', 'sn', 'healthstate', 'healthadvice']
  562. df_health=pd.DataFrame(columns=column_name)
  563. healthstate=100
  564. healthadvice=''
  565. df_fault_now=self.df_diag_ram[self.df_diag_ram['time_sp']=='0000-00-00 00:00:00']
  566. df_fault_now.drop(df_fault_now.index[df_fault_now['falut_code']==100],inplace=True)
  567. df_fault_now.reset_index(inplace=True,drop=True)
  568. fault_num=len(df_fault_now)
  569. fltlv=df_fault_now['faultlv']
  570. fltlv1=np.sum(fltlv<1.5)
  571. fltlv2=np.sum(fltlv<2.5)-fltlv1
  572. fltlv3=np.sum(fltlv<3.5)-fltlv1-fltlv2
  573. fltlv4=np.sum(fltlv<4.5)-fltlv1-fltlv2-fltlv3
  574. fltlv5=np.sum(fltlv<5.5)-fltlv1-fltlv2-fltlv3-fltlv4
  575. if fltlv5>0:
  576. healthstate=healthstate-fltlv1*10-fltlv2*20-fltlv3*30-fltlv4*50-fltlv5*100
  577. healthadvice=healthadvice+',电池发生{}个故障'.format(fault_num)
  578. elif fltlv4>0:
  579. healthstate=healthstate-50
  580. healthadvice=healthadvice+',电池发生{}个故障'.format(fault_num)
  581. elif fltlv3>0:
  582. healthstate=healthstate-30
  583. healthadvice=healthadvice+',电池发生{}个故障'.format(fault_num)
  584. elif fltlv2>0:
  585. healthstate=healthstate-15
  586. healthadvice=healthadvice+',电池发生{}个故障'.format(fault_num)
  587. elif fltlv1>0:
  588. healthstate=healthstate-5
  589. healthadvice=healthadvice+',电池发生{}个故障'.format(fault_num)
  590. #电池寿命
  591. if not self.df_soh.empty:
  592. if soh>85:
  593. pass
  594. elif soh>=80:
  595. healthstate=healthstate-5
  596. healthadvice=healthadvice+',电池SOH较低'
  597. elif soh>=70:
  598. healthstate=healthstate-15
  599. healthadvice=healthadvice+',电池SOH过低'
  600. else:
  601. healthstate=healthstate-30
  602. healthadvice=healthadvice+',电池寿命用尽'
  603. #电池寿命一致性
  604. if cellsoh_diff>15:
  605. healthstate=healthstate-10
  606. healthadvice=healthadvice+',电池SOH一致性很差'
  607. elif cellsoh_diff>10:
  608. healthstate=healthstate-5
  609. healthadvice=healthadvice+',电池SOH一致性较差'
  610. elif cellsoh_diff>5:
  611. healthstate=healthstate-1
  612. else:
  613. pass
  614. #SOC一致性
  615. if not self.df_uniform.empty:
  616. if cellsoc_diff>20:
  617. healthstate=healthstate-10
  618. healthadvice=healthadvice+',电池SOC一致性很差'
  619. elif cellsoc_diff>10:
  620. healthstate=healthstate-5
  621. healthadvice=healthadvice+',电池SOC一致性较差'
  622. elif cellsoc_diff>5:
  623. healthstate=healthstate-1
  624. else:
  625. pass
  626. if healthstate<0:
  627. healthstate=0
  628. elif healthstate>100:
  629. healthstate=100
  630. else:
  631. pass
  632. healthstate=int(healthstate)
  633. if len(healthadvice)>0.5:
  634. healthadvice=healthadvice[1:]
  635. else:
  636. healthadvice='电池运行状态良好'
  637. df_health.loc[0]=[self.bmstime[len(self.bmstime)-1], self.sn, healthstate, healthadvice]
  638. #返回诊断结果...........................................................................................................
  639. df_res=self.df_diag_ram
  640. if not df_res.empty:
  641. pass
  642. else:
  643. df_res=pd.DataFrame()
  644. if not df_health.empty:
  645. pass
  646. else:
  647. df_health=pd.DataFrame()
  648. return df_res, df_health