Li_plated.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. import pandas as pd
  2. import numpy as np
  3. import datetime
  4. import matplotlib as plt
  5. from scipy.signal import savgol_filter
  6. from LIB.MIDDLE.SaftyCenter.Common import QX_BatteryParam as BatParam
  7. class Liplated_test:
  8. def __init__(self,sn,celltype,df_bms): #参数初始化
  9. self.sn=sn
  10. self.celltype=celltype
  11. self.param=BatParam.BatteryInfo(celltype)#鹏飞param中为BatParam,学琦为BatteryInfo
  12. self.df_bms=pd.DataFrame(df_bms)
  13. self.packcrnt=df_bms['总电流[A]']*self.param.PackCrntDec
  14. self.packvolt=df_bms['总电压[V]']
  15. self.bms_soc=df_bms['SOC[%]']
  16. self.bmstime= pd.to_datetime(df_bms['时间戳'], format='%Y-%m-%d %H:%M:%S')
  17. self.cellvolt_name=['单体电压'+str(x) for x in range(1,self.param.CellVoltNums+1)]
  18. self.celltemp_name=['单体温度'+str(x) for x in range(1,self.param.CellTempNums+1)]
  19. self.bmssta = df_bms['充电状态']
  20. #定义加权滤波函数..................................................................................................
  21. def moving_average(interval, windowsize):
  22. window = np.ones(int(windowsize)) / float(windowsize)
  23. re = np.convolve(interval, window, 'same')
  24. return re
  25. #.............................................析锂检测............................................................................
  26. def liplated_detect(self):
  27. #----------------------------------------筛选充电后静置数据------------------------------------------------------------
  28. chrgr_rest_data_temp = self.df_bms.loc[((self.df_bms['充电状态'] == 0) & (self.df_bms['SOC[%]'] > 98) & (self.df_bms['总电流[A]'] == 0)) |
  29. ((self.df_bms['充电状态'] == 2) & (self.df_bms['SOC[%]'] > 98) & (self.df_bms['总电流[A]'] == 0))]#接近慢充后静置数据
  30. df_lipltd_result = pd.DataFrame(columns=['sn','time','liplated','liplated_amount'])
  31. if not chrgr_rest_data_temp.empty:
  32. chrgr_rest_data = chrgr_rest_data_temp.reset_index(drop=True)
  33. temp_rest_time = chrgr_rest_data['时间戳']
  34. rest_time = pd.to_datetime(temp_rest_time)
  35. delta_time = (np.diff(rest_time)/pd.Timedelta(1, 'min'))#计算时间差的分钟数
  36. pos = np.where(delta_time > 30)#静置数据分段,大于30min时,认为是两个静置过程
  37. splice_num = []
  38. if len(pos[0]) >= 1:
  39. pos_ful_tem = np.insert(pos, 0, 0)
  40. pos_len = len(pos_ful_tem)
  41. data_len = len(rest_time)
  42. pos_ful = np.insert(pos_ful_tem, pos_len, data_len-1)
  43. for item in range(0,len(pos_ful)-1):
  44. splice_num.extend(item*np.ones(pos_ful[item +1]-pos_ful[item]))
  45. splice_num = np.insert(splice_num, 0, 0)
  46. else:
  47. splice_num = np.zeros(len(temp_rest_time))
  48. pos_ful = np.array([0])
  49. chrgr_rest_data['chrgr_rest'] = splice_num
  50. #---------------------------判断数据点数大于30的数据段,对电压微分并画图--------------------------------------------
  51. cellvolt_list = self.cellvolt_name
  52. chrgr_rest_check_data = chrgr_rest_data.drop(['GSM信号','故障等级','故障代码','绝缘电阻','总电流[A]','总电压[V]','充电状态','单体压差','SOC[%]'],axis=1,inplace=False)
  53. chrgr_rest_check_data.fillna(value=0)
  54. df_rest_volt_diffdt = pd.DataFrame()
  55. df_rest_volt_smooth = pd.DataFrame()
  56. k = 0
  57. for j in range(0,len(pos_ful)-1):#len(pos_ful)-1#有几段充电后静置数据
  58. df_test_rest_data = chrgr_rest_check_data.loc[chrgr_rest_check_data['chrgr_rest'] == j]
  59. df_rest_volt_smooth = pd.DataFrame()
  60. df_test_rest_time = pd.to_datetime(df_test_rest_data['时间戳'],format='%Y-%m-%d %H:%M:%S')
  61. df_test_rest_time = df_test_rest_time.reset_index(drop=True)
  62. df_data_length = len(df_test_rest_time)
  63. if (df_data_length > 30) & ((df_test_rest_time[df_data_length - 1] - df_test_rest_time[0])/pd.Timedelta(1, 'min') > 40):#静置时间大于40min
  64. df_test_rest_time_dif_temp = np.diff(df_test_rest_time)/pd.Timedelta(1, 'min')
  65. num_list = []
  66. data_jump_pos = np.where(df_test_rest_time_dif_temp > 3)
  67. if len(data_jump_pos[0]) > 0:
  68. if data_jump_pos[0][0] > 100:
  69. for i in range(0,data_jump_pos[0][0],15):##采样密集时每隔10行取数据
  70. num_list.append(i)
  71. df_rest_data_temp = df_test_rest_data.iloc[num_list]
  72. df_test_rest_data_choose = pd.DataFrame(df_rest_data_temp)
  73. df_test_rest_data_choose_else = df_test_rest_data.iloc[data_jump_pos[0][0]+1:len(df_test_rest_data)-1]
  74. df_rest_data_recon_temp = df_test_rest_data_choose.append(df_test_rest_data_choose_else)
  75. df_rest_data_recon =df_rest_data_recon_temp.reset_index(drop=True)
  76. else:
  77. df_rest_data_recon = df_test_rest_data
  78. else:
  79. df_rest_data_recon = df_test_rest_data
  80. df_rest_time = pd.to_datetime(df_rest_data_recon['时间戳'],format='%Y-%m-%d %H:%M:%S')
  81. df_rest_time = df_rest_time.reset_index(drop=True)
  82. df_rest_time_dif_temp = np.diff(df_rest_time)/pd.Timedelta(1, 'min')
  83. df_rest_volt = df_rest_data_recon[cellvolt_list]
  84. for item in cellvolt_list:
  85. window_temp = int(len(df_rest_volt[item])/3)
  86. if window_temp%2:#滤波函数的窗口长度需为奇数
  87. window = window_temp
  88. else:
  89. window = window_temp - 1
  90. step = min(int(window/3),5)
  91. df_volt_smooth = savgol_filter(df_rest_volt[item],window,step)
  92. df_rest_volt_smooth[item] = df_volt_smooth
  93. df_test_rest_volt_diff_temp = np.diff(df_rest_volt_smooth,axis=0)
  94. df_test_rest_time_dif = pd.DataFrame(df_rest_time_dif_temp)
  95. df_test_rest_volt_diff = pd.DataFrame(df_test_rest_volt_diff_temp)
  96. df_test_rest_volt_diffdt_temp = np.divide(df_test_rest_volt_diff,df_test_rest_time_dif)
  97. df_test_rest_volt_diffdt = pd.DataFrame(df_test_rest_volt_diffdt_temp)
  98. df_test_rest_volt_diffdt = df_test_rest_volt_diffdt.append(df_test_rest_volt_diffdt.iloc[len(df_test_rest_volt_diffdt)-1])
  99. df_test_rest_volt_diffdt.columns = cellvolt_list
  100. if len(df_test_rest_volt_diffdt) > 25:
  101. for item in cellvolt_list:
  102. df_volt_diffdt_smooth = savgol_filter(df_test_rest_volt_diffdt[item],13,3)
  103. df_test_rest_volt_diffdt[item] = df_volt_diffdt_smooth
  104. df_test_rest_volt_diffdt['chrgr_rest'] = k
  105. df_test_rest_volt_diffdt['时间戳'] = list(df_rest_time)
  106. k = k+1
  107. df_rest_volt_diffdt = df_rest_volt_diffdt.append(df_test_rest_volt_diffdt)
  108. df_rest_volt_diffdt.reset_index()
  109. #--------------------------------------------------------确认是否析锂----------------------------------------------------------------------------
  110. for item in range(0,k):
  111. lipltd_confirm = []
  112. lipltd_amount = []
  113. df_check_liplated_temp = df_rest_volt_diffdt.loc[df_rest_volt_diffdt['chrgr_rest'] == item].reset_index(drop = True)
  114. df_lipltd_volt_temp = df_check_liplated_temp[cellvolt_list]
  115. df_lipltd_volt_len = len(df_lipltd_volt_temp)
  116. df_data_temp_add = df_lipltd_volt_temp.iloc[df_lipltd_volt_len-3:df_lipltd_volt_len-1]
  117. df_lipltd_volt_temp_add = df_lipltd_volt_temp.append(df_data_temp_add)
  118. df_lipltd_volt_temp_difdif = np.diff(df_lipltd_volt_temp_add,axis=0)#电压二次微分,判断升降
  119. df_lipltd_volt_temp_difdif = pd.DataFrame(df_lipltd_volt_temp_difdif)
  120. df_lipltd_volt_temp_difdif.columns = cellvolt_list
  121. df_lipltd_volt_temp_difdif_temp = df_lipltd_volt_temp_difdif
  122. df_lipltd_volt_temp_difdif_temp[df_lipltd_volt_temp_difdif_temp >= 0] = 1
  123. df_lipltd_volt_temp_difdif_temp[df_lipltd_volt_temp_difdif_temp < 0] = -1
  124. df_lipltd_volt_temp_difdifdif = np.diff(df_lipltd_volt_temp_difdif_temp,axis=0)#三次微分,利用-2,2判断波分和波谷
  125. df_lipltd_volt_difdifdif = pd.DataFrame(df_lipltd_volt_temp_difdifdif)
  126. df_lipltd_volt_difdifdif.columns = cellvolt_list
  127. df_lipltd_volt_difdifdif['chrgr_rest'] = k
  128. df_lipltd_volt_difdifdif['时间戳'] = list(df_check_liplated_temp['时间戳'])
  129. df_lipltd_volt_difdifdif = df_lipltd_volt_difdifdif.reset_index(drop = True)
  130. df_lipltd_data_temp = df_lipltd_volt_difdifdif.loc[df_lipltd_volt_difdifdif['时间戳'] < (df_check_liplated_temp['时间戳'][0] + datetime.timedelta(minutes=90))]
  131. for cell_name in cellvolt_list:#对每个电芯判断
  132. df_check_plated_data = df_lipltd_data_temp[cell_name]
  133. peak_pos = np.where(df_check_plated_data == -2)
  134. bot_pos = np.where(df_check_plated_data == 2)
  135. if len(peak_pos[0]) & len(bot_pos[0]):
  136. ini_dvdt = df_check_liplated_temp[cell_name][0]
  137. peak_dvdt = df_check_liplated_temp[cell_name][peak_pos[0][0] + 1]
  138. bot_dvdt = df_check_liplated_temp[cell_name][bot_pos[0][0] + 1]
  139. peak_hight = peak_dvdt - ini_dvdt
  140. peak_bot_hight = peak_dvdt - bot_dvdt
  141. liplted_amount_temp = (df_check_liplated_temp['时间戳'][bot_pos[0][0] + 1] - df_check_liplated_temp['时间戳'][0])/pd.Timedelta(1, 'min')
  142. liplted_amount_temp = float(format(liplted_amount_temp, '.3f'))
  143. if ((bot_pos[0][0] - peak_pos[0][0]) > 3) & (df_check_liplated_temp[cell_name][peak_pos[0][0] + 1] < 0) & (peak_bot_hight > 0.05*peak_hight) & (liplted_amount_temp > 15):
  144. lipltd_confirm.append(1)#1为析锂,0为非析锂
  145. lipltd_amount.append(liplted_amount_temp)
  146. else:
  147. lipltd_confirm.append(0)
  148. lipltd_amount.append(0)
  149. else:
  150. lipltd_confirm.append(0)
  151. lipltd_amount.append(0)
  152. lipltd_amount
  153. if any(lipltd_confirm):
  154. df_lipltd_confir_temp = pd.DataFrame({"sn":[self.sn], "time":[df_check_liplated_temp['时间戳'][0]], "liplated":[str(lipltd_confirm)], "liplated_amount":[str(lipltd_amount)]})
  155. df_lipltd_result = df_lipltd_result.append(df_lipltd_confir_temp)
  156. df_lipltd_result = df_lipltd_result.reset_index(drop = True)
  157. df_lipltd_result.sort_values(by = ['time'], axis = 0, ascending=True,inplace=True)#对故障信息按照时间进行排序
  158. # df_lipltd_data.to_csv(r'D:\Work\Code_write\data_analyze_platform\USER\lzx\01算法开发\02析锂检测\liplated\算法开发_检测\滤波后图片\析锂.csv',index=False,encoding='GB18030')
  159. #返回诊断结果...........................................................................................................
  160. if not df_lipltd_result.empty:
  161. return df_lipltd_result
  162. else:
  163. return pd.DataFrame()