SOC_pre_vlt_ori.py 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. import pandas as pd
  2. import numpy as np
  3. from scipy.signal import savgol_filter as svflter
  4. from scipy import interpolate
  5. import os
  6. import joblib
  7. class cell_chracter:
  8. def __init__(self, df_bms, df_param, cellvolt_name, celltemp_name, pack_code): #参数初始化
  9. self.df_bms=pd.DataFrame(df_bms)
  10. self.bmstime= pd.to_datetime(df_bms['time'], format='%Y-%m-%d %H:%M:%S')
  11. self.cellvolt_list=cellvolt_name
  12. self.celltemp_name=celltemp_name
  13. self.capty = float(df_param['capacity'])
  14. np_chrg_ocv = df_param['charge_ocv_v']
  15. np_chrg_soc = df_param['charge_ocv_soc']
  16. np_dschrg_ocv = df_param['discharge_ocv_v']
  17. np_dschrg_soc = df_param['discharge_ocv_soc']
  18. np_ocv = (np.array(np_chrg_ocv) + np.array(np_dschrg_ocv))/2
  19. np_soc = (np.array(np_chrg_soc) + np.array(np_dschrg_soc))/2
  20. self.LookTab_OCV = np_ocv
  21. self.LookTab_SOC = np_soc
  22. abs_model_file=f"{os.path.dirname(os.path.abspath(__file__))}/model/V_1_0_0/"
  23. self.Dnn_predict = joblib.load(abs_model_file + 'Dnnmodel.pkl')
  24. self.inputnorm_x = joblib.load(abs_model_file + 'normorlized_x')
  25. self.inputnorm_y = joblib.load(abs_model_file + 'normorlized_y')
  26. self.pack_code = pack_code
  27. def states_cal(self):
  28. def find_peak_triangleNum(filter_signal, peak_width):
  29. # 判断是否有凸起
  30. length_data = len(filter_signal)
  31. thre = 0.7*np.percentile(filter_signal, 95) # 设置阈值高度 95%是前400个点的20个波峰点
  32. botthre = np.percentile(filter_signal, 20) # 设置阈值低度 5%是400个点的后20个波峰点
  33. # 在整个区域内找极值
  34. l = []
  35. bot = []
  36. for i in range(1,length_data-1):
  37. if (filter_signal[i-1] < filter_signal[i]) and (filter_signal[i]>filter_signal[i+1]) and (filter_signal[i]>thre):
  38. l.append(i)
  39. elif (filter_signal[i] == filter_signal[i-1]) and (filter_signal[i]>thre):
  40. l.append(i) # 最高点前后可能有相等的情况
  41. if (filter_signal[i-1] > filter_signal[i]) and (filter_signal[i]<filter_signal[i+1]) and (filter_signal[i]<botthre):
  42. bot.append(i)
  43. elif (filter_signal[i] == filter_signal[i-1]) and (filter_signal[i]<botthre):
  44. bot.append(i) # 最高点前后可能有相等的情况
  45. CC = len(l) # 统计极值得个数
  46. cou = 0
  47. ll = l.copy()
  48. for j in range(1, CC):
  49. if l[j]-l[j-1] < peak_width: # 此判断用于将位于同一个峰内的极值点去掉
  50. if l[j] > l[j-1]: # 同一个峰内的数据,将小的值替换成0
  51. ll[j-1] = 0
  52. else:
  53. ll[j] = 0
  54. cou = cou+1
  55. rcou = CC - cou
  56. ll = [i for i in ll if i > 0] # 去掉0的值
  57. peak_index = []
  58. # 找到每个区间内波峰最大值
  59. # 截断每个区间再求区间最大值的索引
  60. for i in range(len(ll)):
  61. if i == 0:
  62. index_range = np.array(l)[np.array(l) <= ll[i]]
  63. else:
  64. index_range = np.array(l)[(np.array(l)<=ll[i]) & (np.array(l)>ll[i-1])]
  65. # 找到每个区间最大值得索引
  66. if len(index_range) > 0:
  67. peak_index.append(index_range[np.argmax(filter_signal[index_range],axis=0)])
  68. DD = len(bot) # 统计极值得个数
  69. cou = 0
  70. botm = bot.copy()
  71. for j in range(1, DD):
  72. if bot[j]-bot[j-1] < peak_width: # 此判断用于将位于同一个峰内的极值点去掉
  73. if bot[j] < bot[j-1]: # 同一个峰内的数据,将大的值替换成0
  74. botm[j] = 0
  75. else:
  76. botm[j-1] = 0
  77. cou = cou+1
  78. Dcou = DD - cou
  79. botm = [i for i in botm if i > 0] # 去掉0的值
  80. bot_index = []
  81. # 找到每个区间内波峰最大值
  82. # 截断每个区间再求区间最大值的索引
  83. for i in range(len(botm)):
  84. if i == 0:
  85. botindex_range = np.array(bot)[np.array(bot) >= botm[i]]
  86. else:
  87. botindex_range = np.array(bot)[(np.array(bot) >= botm[i]) & (np.array(bot) < botm[i-1])]
  88. # 找到每个区间最小值得索引
  89. if len(botindex_range) > 0:
  90. bot_index.append(botindex_range[np.argmin(filter_signal[botindex_range],axis=0)])
  91. return [rcou, peak_index, Dcou, bot_index]#
  92. def soc_cal_ncm(df_data_temp1):
  93. data_ori_temp = df_data_temp1.copy()
  94. itemsn = data_ori_temp['sn'].iloc[0]
  95. data_ori_delNan = data_ori_temp.dropna(axis = 0, subset = ["pack_crnt", "pack_soc"])#删除电压、电流、bms状态值为Nan值所在行"CellVoltage",
  96. data_ori_delnone = data_ori_delNan.drop(data_ori_delNan[(data_ori_delNan['pack_soc'] == "") | (data_ori_delNan['pack_crnt'] == "")].index)#删除电压、电流、bms状态值为空值所在行(data_ori_delNan['CellVoltage'] == "") |
  97. data_ori = data_ori_delnone.fillna(method ='backfill', inplace = False , axis = 0)
  98. celltemp_name = self.celltemp_name#电芯温度数量
  99. #---------------------------------充电过程判断--------------------------------------
  100. def clean_dead_value(series, num_dead_thresh):
  101. slide_list = [series.index[0]]
  102. slide_list_all = []
  103. for i in range(series.index[0],series.index[-1]):
  104. j = i + 1
  105. diff = series[j] - series[i]
  106. if diff == 0:
  107. slide_list.append(j)
  108. else:
  109. slide_list.clear()
  110. slide_list.append(j)
  111. if len(slide_list) >= num_dead_thresh:
  112. target_list = slide_list.copy()
  113. slide_list_all.append(target_list)
  114. index= [] # 将找到的满足条件的index合并
  115. for i in range(len(slide_list_all) - 1):
  116. if set(slide_list_all[i]) < set(slide_list_all[i + 1]):
  117. index.append(i)
  118. m = {i: element for i, element in enumerate(slide_list_all)}
  119. [m.pop(i) for i in index]
  120. return list(m.values())
  121. df_data_chrg_chek = data_ori.copy()
  122. df_data_chrg_chek.reset_index(drop = True, inplace = True)
  123. df_data_chrg_chek['crnt_flg'] = 0
  124. df_data_chrg_chek.loc[df_data_chrg_chek['pack_crnt'] > 0, 'crnt_flg'] = 1
  125. df_data_chrg_chek.loc[df_data_chrg_chek['pack_crnt'] < 0, 'crnt_flg'] = -1
  126. df_data_chrg_chek['sts_flg'] = 2
  127. df_sts_chrg = pd.DataFrame(columns=list(df_data_chrg_chek.columns))
  128. df_crnt_flg = df_data_chrg_chek['crnt_flg']
  129. num_dead_thresh = 15#判断连续多少个数据为阈值
  130. indexs_to_delelte = clean_dead_value(df_crnt_flg, num_dead_thresh)#获得连续数据所在的行
  131. rest_num = len(indexs_to_delelte)
  132. if rest_num > 0:#仅有一个连续数据时
  133. for splice_item in range(0, rest_num):#rest_num
  134. df_data_temp = df_data_chrg_chek.iloc[indexs_to_delelte[splice_item][0]:indexs_to_delelte[splice_item][-1]]#获得电流连续数据
  135. df_data_temp.reset_index(drop = True, inplace = True)
  136. df_soc_temp = df_data_temp['pack_soc']
  137. delta_soc = round((df_soc_temp.iloc[-1] - df_soc_temp.iloc[0]), 3)
  138. df_time_temp = pd.to_datetime(df_data_temp['time'])
  139. delta_time = (df_time_temp.iloc[-1] - df_time_temp.iloc[0])/pd.Timedelta(1, 'hours')
  140. if all(df_data_temp['crnt_flg'] == 0):#静置判断
  141. if delta_time > 0.17:
  142. df_data_temp['sts_flg'] = 0
  143. df_sts_chrg = df_sts_chrg.append(df_data_temp)
  144. df_sts_chrg.reset_index(drop = True, inplace = True)
  145. elif all(df_data_temp['crnt_flg'] == -1):#充电判断
  146. if (delta_time >= 0.03) and delta_soc >= 30:
  147. df_data_temp['sts_flg'] = 1
  148. df_sts_chrg = df_sts_chrg.append(df_data_temp)
  149. df_sts_chrg.reset_index(drop = True, inplace = True)
  150. elif all(df_data_temp['crnt_flg'] == 1):#充电判断
  151. if (delta_time >= 0.03) and delta_soc >= 30:
  152. df_data_temp['sts_flg'] = 1
  153. df_sts_chrg = df_sts_chrg.append(df_data_temp)
  154. df_sts_chrg.reset_index(drop = True, inplace = True)
  155. df_dschrg = pd.concat([df_data_chrg_chek, df_sts_chrg, df_sts_chrg]).drop_duplicates(subset = ['time', 'pack_soc'], keep = False)
  156. data_temp = pd.concat([df_dschrg, df_sts_chrg])
  157. data_temp.sort_values(by = 'time', inplace = True)
  158. data_temp.reset_index(drop = True, inplace = True)
  159. df_chrg_temp = data_temp.loc[data_temp['sts_flg'] == 1]
  160. df_chrg_temp.reset_index(inplace = True, drop = True)
  161. SOC_pre_cal = pd.DataFrame(columns = ['sn', 'time', 'soc_ori', 'soc_pre', 'soc_error', 'odo', 'method', 'battery_type'])
  162. data_temp_rest = data_temp[abs(data_temp['pack_crnt']) > 0.02*self.capty]
  163. np_dschrg_time = pd.to_datetime(data_temp_rest['time'])
  164. dff_dschrg_time = np.diff(np_dschrg_time)/pd.Timedelta(1, 'min')#放电过程前后时间差
  165. rest_dschrg_pos = np.where(dff_dschrg_time > 120)#筛选前后时间差大于30min的位置及时间点,判断为两次放电
  166. if (len(rest_dschrg_pos[0]) > 0):
  167. df_celvlt = data_temp_rest[self.cellvolt_list]
  168. df_celvlt_min = df_celvlt.min(axis = 1)
  169. df_celvlt_max = df_celvlt.max(axis = 1)
  170. LookTab_OCV = self.LookTab_OCV
  171. LookTab_SOC = self.LookTab_SOC
  172. for item_rest in rest_dschrg_pos[0]:
  173. if (abs(data_temp_rest['pack_crnt'].iloc[item_rest + 1]) < 0.03*self.capty) and (abs(data_temp_rest['pack_crnt'].iloc[item_rest + 1]) > 0.1):
  174. min_volt = min(LookTab_OCV)
  175. max_volt = max(LookTab_OCV)
  176. soc_interplt = interpolate.interp1d(LookTab_OCV, LookTab_SOC, kind = 'linear')#OCV-SOC插值函数
  177. df_celvlt_min[df_celvlt_min < min_volt] = min_volt + 0.0005
  178. df_celvlt_max[df_celvlt_max > max_volt] = max_volt - 0.0005
  179. cellvltmin = df_celvlt_min[item_rest + 1]
  180. cellvltmax = df_celvlt_max[item_rest + 1]
  181. SOC_now = data_temp_rest['pack_soc'].iloc[item_rest + 1]
  182. SOC_min = round(soc_interplt(cellvltmin)[0], 1)
  183. SOC_max = round(soc_interplt(cellvltmax)[0], 1)
  184. if SOC_min < 30:
  185. SOC_cal = 0.8*SOC_min + 0.2*SOC_max
  186. SOC_del = abs(SOC_cal - SOC_now)
  187. SOC_real = str([SOC_max, SOC_min, SOC_cal])
  188. method = 1
  189. elif SOC_max > 90:
  190. SOC_cal = 0.8*SOC_max + 0.2*SOC_min
  191. SOC_del = abs(SOC_cal - SOC_now)
  192. SOC_real = str([SOC_max, SOC_min, SOC_cal])
  193. method = 2
  194. else:
  195. SOC_cal = 0.5*(SOC_max + SOC_min)
  196. SOC_del = abs(SOC_cal - SOC_now)
  197. SOC_real = str([SOC_max, SOC_min, SOC_cal])
  198. method = 3
  199. if SOC_del > 5:
  200. time_pre = data_temp_rest['time'].iloc[item_rest + 1]
  201. odo_now = data_temp_rest['odo'].iloc[item_rest + 1]
  202. SOC_pre_cal.loc[len(SOC_pre_cal)] = [itemsn, time_pre, SOC_now, SOC_real, SOC_del, odo_now, method, 'NCM']
  203. return SOC_pre_cal
  204. def soc_cal_lfp(df_data_temp2):
  205. data_ori_temp = df_data_temp2.copy()
  206. itemsn = data_ori_temp['sn'].iloc[0]
  207. data_ori_delNan = data_ori_temp.dropna(axis = 0, subset = ["pack_crnt", "pack_soc"])#删除电压、电流、bms状态值为Nan值所在行"CellVoltage",
  208. data_ori_delnone = data_ori_delNan.drop(data_ori_delNan[(data_ori_delNan['pack_soc'] == "") | (data_ori_delNan['pack_crnt'] == "")].index)#删除电压、电流、bms状态值为空值所在行(data_ori_delNan['CellVoltage'] == "") |
  209. data_ori = data_ori_delnone.fillna(method ='backfill', inplace = False , axis = 0)
  210. def clean_dead_value(series, num_dead_thresh):
  211. slide_list = [series.index[0]]
  212. slide_list_all = []
  213. for i in range(series.index[0],series.index[-1]):
  214. j = i + 1
  215. diff = series[j] - series[i]
  216. if diff == 0:
  217. slide_list.append(j)
  218. else:
  219. slide_list.clear()
  220. slide_list.append(j)
  221. if len(slide_list) >= num_dead_thresh:
  222. target_list = slide_list.copy()
  223. slide_list_all.append(target_list)
  224. index= [] # 将找到的满足条件的index合并
  225. for i in range(len(slide_list_all) - 1):
  226. if set(slide_list_all[i]) < set(slide_list_all[i + 1]):
  227. index.append(i)
  228. m = {i: element for i, element in enumerate(slide_list_all)}
  229. [m.pop(i) for i in index]
  230. return list(m.values())
  231. df_data_chrg_chek = data_ori.copy()
  232. df_data_chrg_chek.reset_index(drop = True, inplace = True)
  233. df_data_chrg_chek['crnt_flg'] = 0
  234. df_data_chrg_chek.loc[df_data_chrg_chek['pack_crnt'] > 0, 'crnt_flg'] = 1
  235. df_data_chrg_chek.loc[df_data_chrg_chek['pack_crnt'] < 0, 'crnt_flg'] = -1
  236. df_data_chrg_chek['sts_flg'] = 2
  237. df_sts_chrg = pd.DataFrame(columns=list(df_data_chrg_chek.columns))
  238. df_crnt_flg = df_data_chrg_chek['crnt_flg']
  239. num_dead_thresh = 15#判断连续多少个数据为阈值
  240. indexs_to_delelte = clean_dead_value(df_crnt_flg, num_dead_thresh)#获得连续数据所在的行
  241. rest_num = len(indexs_to_delelte)
  242. if rest_num > 0:#仅有一个连续数据时
  243. for splice_item in range(0, rest_num):#rest_num
  244. df_data_temp = df_data_chrg_chek.iloc[indexs_to_delelte[splice_item][0]:indexs_to_delelte[splice_item][-1]]#获得电流连续数据
  245. df_data_temp.reset_index(drop = True, inplace = True)
  246. df_soc_temp = df_data_temp['pack_soc']
  247. delta_soc = round((df_soc_temp.iloc[-1] - df_soc_temp.iloc[0]), 3)
  248. df_time_temp = pd.to_datetime(df_data_temp['time'])
  249. delta_time = (df_time_temp.iloc[-1] - df_time_temp.iloc[0])/pd.Timedelta(1, 'hours')
  250. if all(df_data_temp['crnt_flg'] == 0):#静置判断
  251. if delta_time > 0.17:
  252. df_data_temp['sts_flg'] = 0
  253. df_sts_chrg = df_sts_chrg.append(df_data_temp)
  254. df_sts_chrg.reset_index(drop = True, inplace = True)
  255. elif all(df_data_temp['crnt_flg'] == -1):#充电判断
  256. if (delta_time >= 0.03) and delta_soc >= 30:
  257. df_data_temp['sts_flg'] = 1
  258. df_sts_chrg = df_sts_chrg.append(df_data_temp)
  259. df_sts_chrg.reset_index(drop = True, inplace = True)
  260. elif all(df_data_temp['crnt_flg'] == 1):#充电判断
  261. if (delta_time >= 0.03) and delta_soc >= 30:
  262. df_data_temp['sts_flg'] = 1
  263. df_sts_chrg = df_sts_chrg.append(df_data_temp)
  264. df_sts_chrg.reset_index(drop = True, inplace = True)
  265. df_dschrg = pd.concat([df_data_chrg_chek, df_sts_chrg, df_sts_chrg]).drop_duplicates(subset = ['time', 'pack_soc'], keep = False)
  266. data_temp = pd.concat([df_dschrg, df_sts_chrg])
  267. data_temp.sort_values(by = 'time', inplace = True)
  268. data_temp.reset_index(inplace = True, drop = True)
  269. celltemp_name = self.celltemp_name#电芯温度数量
  270. #---------------------------------充电过程判断--------------------------------------
  271. df_chrg_temp = data_temp.loc[data_temp['sts_flg'] == 1]
  272. df_chrg_temp.reset_index(inplace = True, drop = True)
  273. df_chracter_ofc = pd.DataFrame()
  274. SOC_rlt_final = pd.DataFrame()
  275. SOC_pre_cal = pd.DataFrame(columns = ['sn', 'time', 'soc_ori', 'soc_pre', 'soc_error', 'odo', 'method'])
  276. SOC_pre_cal_dnn = pd.DataFrame(columns = ['sn', 'time', 'soc_ori', 'soc_pre', 'soc_error', 'odo', 'method'])
  277. data_temp_rest = data_temp[abs(data_temp['pack_crnt']) > 0.02*self.capty]
  278. np_dschrg_time = pd.to_datetime(data_temp_rest['time'])
  279. dff_dschrg_time = np.diff(np_dschrg_time)/pd.Timedelta(1, 'min')#放电过程前后时间差
  280. rest_dschrg_pos = np.where(dff_dschrg_time > 120)#筛选前后时间差大于30min的位置及时间点,判断为两次放电
  281. if (len(rest_dschrg_pos[0]) > 0):
  282. df_celvlt = data_temp_rest[self.cellvolt_list]
  283. df_celvlt_min = df_celvlt.min(axis = 1)
  284. df_celvlt_max = df_celvlt.max(axis = 1)
  285. LookTab_OCV = self.LookTab_OCV
  286. LookTab_SOC = self.LookTab_SOC
  287. ocv_interplt = interpolate.interp1d(LookTab_SOC, LookTab_OCV, kind = 'linear')#OCV-SOC插值函数
  288. ocv_pre_val = ocv_interplt(25)
  289. for item_rest in rest_dschrg_pos[0]:
  290. if (abs(data_temp_rest['pack_crnt'].iloc[item_rest + 1]) < 0.02*self.capty) and (abs(data_temp_rest['pack_crnt'].iloc[item_rest + 1]) > 0.3) and\
  291. (df_celvlt_min.iloc[item_rest + 1] < ocv_pre_val) and (df_celvlt_min.iloc[item_rest + 1] > 2):
  292. min_volt = min(LookTab_OCV)
  293. soc_interplt = interpolate.interp1d(LookTab_OCV, LookTab_SOC, kind = 'linear')#OCV-SOC插值函数
  294. df_celvlt_min[df_celvlt_min < min_volt] = min_volt + 0.0005
  295. cellvltmin = df_celvlt_min[item_rest + 1]
  296. cellvltmax = df_celvlt_max[item_rest + 1]
  297. SOC_now = data_temp_rest['pack_soc'].iloc[item_rest + 1]
  298. SOC_min = round(soc_interplt(cellvltmin)[0], 1)
  299. SOC_max = round(soc_interplt(cellvltmax)[0], 1)
  300. if SOC_min < 30:
  301. SOC_cal = 0.8*SOC_min + 0.2*SOC_max
  302. SOC_del = abs(SOC_cal - SOC_now)
  303. SOC_real = str([SOC_max, SOC_min, SOC_cal])
  304. method = 2
  305. elif SOC_max > 90:
  306. SOC_cal = 0.8*SOC_max + 0.2*SOC_min
  307. SOC_del = abs(SOC_cal - SOC_now)
  308. SOC_real = str([SOC_max, SOC_min, SOC_cal])
  309. method = 2
  310. else:
  311. SOC_cal = 0.5*(SOC_max + SOC_min)
  312. SOC_del = abs(SOC_cal - SOC_now)
  313. SOC_real = str([SOC_max, SOC_min, SOC_cal])
  314. method = 0
  315. if SOC_del > 5:
  316. time_pre = data_temp_rest['time'].iloc[item_rest + 1]
  317. odo_now = data_temp_rest['odo'].iloc[item_rest + 1]
  318. SOC_pre_cal.loc[len(SOC_pre_cal)] = [itemsn, time_pre, SOC_now, SOC_real, SOC_del, odo_now, method]
  319. #------------------------------------DNN方法估计SOC
  320. if (not df_chrg_temp.empty) and (self.pack_code == 'JX18020'):
  321. para_lvbo = 7
  322. chrgr_time = pd.to_datetime(df_chrg_temp['time'])
  323. delta_time = (np.diff(chrgr_time)/pd.Timedelta(1, 'min'))#计算时间差的分钟数
  324. pos = np.where(delta_time > 10)#充电数据分段,大于10min时,认为是两个充电过程
  325. dvsocchrcter = []
  326. splice_num = []
  327. if len(pos[0]) >= 1:
  328. pos_ful_tem = np.insert(pos, 0, 0)
  329. pos_len = len(pos_ful_tem)
  330. data_len = len(chrgr_time)
  331. pos_ful = np.insert(pos_ful_tem, pos_len, data_len-1)
  332. for item in range(0,len(pos_ful)-1):
  333. splice_num.extend(item*np.ones(pos_ful[item +1]-pos_ful[item]))
  334. splice_num = np.insert(splice_num, 0, 0)
  335. else:
  336. splice_num = np.zeros(len(chrgr_time))
  337. pos_ful = np.array([0])
  338. if len(splice_num) > 0:
  339. df_chrg_temp['chrgr_rest'] = splice_num
  340. chrgr_splice_num = np.unique(df_chrg_temp['chrgr_rest'])#判断有几段充电数据
  341. if len(chrgr_splice_num) > 0:#特征参数中增加一列,电压微分中波峰到满充位置电量,进行SOH计算
  342. for item_chrgr in chrgr_splice_num:
  343. df_chrgr_splice_data = df_chrg_temp.loc[(df_chrg_temp['chrgr_rest'] == item_chrgr)]
  344. df_chrgr_splice_data.reset_index(inplace = True, drop = True)
  345. df_soc_temp = df_chrgr_splice_data['pack_soc']
  346. df_time_temp = pd.to_datetime(df_chrgr_splice_data['time'])
  347. delta_soc = round((df_soc_temp.iloc[-1] - df_soc_temp.iloc[0]), 3)
  348. if (df_soc_temp.iloc[0] < 40) and (len(df_soc_temp) > 30):
  349. delta_time = round((df_time_temp.iloc[-1] - df_time_temp.iloc[0])/pd.Timedelta(1, 'hours'), 3)
  350. rate_chrg = round(delta_soc/(100*delta_time), 2)
  351. df_celvlt_max = df_chrgr_splice_data['cell_volt_max']
  352. df_crnt = abs(df_chrgr_splice_data['pack_crnt'])
  353. df_soc = df_chrgr_splice_data['pack_soc']
  354. if (df_celvlt_max.iloc[-1] > 3.55) and (df_crnt.iloc[-1] < 0.1*self.capty) and (df_soc.iloc[-1] < 95):
  355. SOC_now = df_soc.iloc[-1]
  356. SOC_real = 100
  357. SOC_del = 100 - SOC_now
  358. method = 3
  359. time_pre = df_chrgr_splice_data['time'].iloc[-1]
  360. odo_now = df_chrgr_splice_data['odo'].iloc[0]
  361. if SOC_del > 5:
  362. SOC_pre_cal.loc[len(SOC_pre_cal)] = [itemsn, time_pre, SOC_now, SOC_pre_cal, SOC_del, odo_now, method]
  363. df_celvltdff = df_celvlt_max.diff()
  364. df_celvltdff.fillna(method ='bfill', inplace = True , axis = 0)
  365. df_celvltdff.reset_index(inplace = True, drop = True)
  366. df_celvltdffsmth = svflter(df_celvltdff, para_lvbo, 3)
  367. df_time_temp = pd.to_datetime(df_chrgr_splice_data['time'])
  368. np_dff_time = np.diff(df_time_temp)/pd.Timedelta(1, 'hours')
  369. np_dff_time_new = np.append(np_dff_time, 0)
  370. np_chrg_ah = np.multiply(np.array(np_dff_time_new),-1*np.array(df_chrgr_splice_data['pack_crnt']))
  371. chrg_ahlst = [sum(np_chrg_ah[:i]) for i in range(1, len(np_chrg_ah)+1)]
  372. df_chrg_ah = pd.DataFrame(chrg_ahlst)
  373. df_chrg_ah.columns = ['chrgah']
  374. df_data_tem = df_chrgr_splice_data[['time','sn', 'pack_crnt','pack_volt','pack_soc', 'odo', 'cell_volt_max',
  375. 'cell_temp_max', 'cell_temp_min']]
  376. df_data = pd.concat([df_data_tem, df_chrg_ah], axis = 1)
  377. df_data.rename(columns = {'cell_temp_max':'max_T', 'cell_temp_min':'min_T', 'cell_volt_max':'frst'}, inplace = True) #'mileage':'odo',
  378. df_data.drop(df_data[(df_data[['max_T', 'min_T']] < -30).any(axis = 1) | (df_data[['max_T', 'min_T']] > 125).any(axis = 1)].index, inplace = True)
  379. df_data.drop(df_data[(df_data['frst'] < 2) | (df_data['frst'] > 5)].index, inplace = True)
  380. df_data.reset_index(drop = True, inplace = True)
  381. datalen = len(df_data)
  382. diff_vlt = df_data['frst'].diff()
  383. # 使用 cumsum() 函数标记下降区域
  384. down_regions = (diff_vlt >= 0).cumsum()
  385. # 使用 groupby() 和 transform() 函数计算每个区域的长度
  386. region_sizes = down_regions.groupby(down_regions).transform('size')
  387. # 使用 where() 函数删除连续3次以上下降位置的数据
  388. data_series_filtered = df_data.where(region_sizes < 10)
  389. nan_elements = data_series_filtered.isna()
  390. # 使用 np.where() 函数查找所有 NaN 元素的位置
  391. nan_indices = np.where(nan_elements == True)[0]
  392. if len(nan_indices)>0:
  393. last_num = nan_indices[-1]
  394. else:
  395. last_num = 0
  396. df_data_real = df_data.iloc[last_num:]
  397. df_data_real.reset_index(drop= True, inplace=True)
  398. df_dataana = df_data_real.loc[(df_data_real['pack_soc'] > 30) & (df_data_real['pack_soc'] < 80)]
  399. df_dataana.reset_index(drop = True, inplace = True)
  400. if (len(df_dataana) > 20):# and (rate_chrg <= 0.95)
  401. def dats_interp(input1, input2, datalen):
  402. cap_frst = list(np.linspace(input1.iloc[0], input1.iloc[-1], datalen, endpoint = False))#len(df_dataana['chrgah'])
  403. fuc_inter = interpolate.interp1d(input1, input2, kind = 'nearest')#定义差值函数
  404. vlt_splce_temp = list(fuc_inter(cap_frst))
  405. return vlt_splce_temp
  406. crntabs = list(abs(df_dataana['pack_crnt']))
  407. df_dataana['abscrnt'] = crntabs
  408. crntnum = df_dataana.loc[:,'abscrnt'].value_counts() #统计电芯数量这一列每个元素出现的个数
  409. crntmaxNums = int(crntnum.idxmax())
  410. df_data_cal = df_dataana.loc[(abs(df_dataana['pack_crnt']) > crntmaxNums-4) & (abs(df_dataana['pack_crnt']) < crntmaxNums+4)]
  411. df_data_cal = df_data_cal.iloc[3:-2]
  412. df_data_cal.reset_index(drop= True, inplace=True)
  413. if (len(df_data_cal) > 10):# and (all(abs(dff_soc) < 2))and (crntmaxNums/self.capty < 0.95)
  414. rate_end = round(abs(df_data['pack_crnt'].iloc[-1])/self.capty, 3)
  415. df_data_cal['frst'] = svflter(df_data_cal['frst'], para_lvbo, 3)
  416. split_len = int(1.2*(df_data_cal['pack_soc'].iloc[-1] - df_data_cal['pack_soc'].iloc[0]))
  417. if split_len > 10:
  418. cap_frst = list(np.linspace(df_data_cal['chrgah'].iloc[0], df_data_cal['chrgah'].iloc[-1], split_len, endpoint = False))#len(df_dataana['chrgah'])
  419. vlt_splce_temp = dats_interp(df_data_cal['chrgah'], df_data_cal['frst'], split_len)
  420. soc_splt = dats_interp(df_data_cal['chrgah'], df_data_cal['pack_soc'], split_len)
  421. crnt_splt = dats_interp(df_data_cal['chrgah'], df_data_cal['pack_crnt'], split_len)
  422. maxt_splt = dats_interp(df_data_cal['chrgah'], df_data_cal['max_T'], split_len)
  423. mint_splt = dats_interp(df_data_cal['chrgah'], df_data_cal['min_T'], split_len)
  424. odo_splt = [df_data_cal['odo'].iloc[0]]*split_len
  425. time_splt = dats_interp(df_data_cal['chrgah'], df_data_cal['time'], split_len)
  426. pkvlt_splt_temp = dats_interp(df_data_cal['chrgah'], df_data_cal['pack_volt'], split_len)
  427. pkvlt_splt = svflter(pkvlt_splt_temp, para_lvbo, 3)
  428. vlt_splce = svflter(vlt_splce_temp, para_lvbo, 3)
  429. np_dff_vlt = np.diff(vlt_splce)
  430. np_dff_cap = np.diff(cap_frst)
  431. np_dff_dv_dq_temp = np.divide(np_dff_vlt, np_dff_cap)
  432. np_dff_dv_dq = np.insert(np_dff_dv_dq_temp, 0, np_dff_dv_dq_temp[0])
  433. df_dvdq_data = pd.DataFrame()
  434. df_dvdq_data['pack_soc'] = soc_splt
  435. df_dvdq_data['pack_crnt'] = crnt_splt
  436. df_dvdq_data['frst'] = vlt_splce
  437. df_dvdq_data['max_T'] = maxt_splt
  438. df_dvdq_data['min_T'] = mint_splt
  439. df_dvdq_data['odo'] = odo_splt
  440. df_dvdq_data['chrgah'] = cap_frst
  441. df_dvdq_data['pack_volt'] = pkvlt_splt
  442. df_dvdq_data['time'] = pd.to_datetime(time_splt)#, utc=True, unit='ms').tz_convert('Asia/Shanghai')
  443. df_dvdq_data['dffsoc'] = df_dvdq_data['pack_soc'].diff()
  444. df_dvdq_data['dffah'] = df_dvdq_data['chrgah'].diff()
  445. df_dvdq_data['dv_dq'] = np_dff_dv_dq
  446. df_dvdq_data['fr_vlt_dvdq'] = vlt_splce#电压
  447. df_dvdq_data.fillna(method = 'bfill', inplace = True , axis = 0)
  448. delta_soc = df_dvdq_data['pack_soc'].iloc[-1] - df_dvdq_data['pack_soc'].iloc[0]
  449. if all(df_dvdq_data['dffsoc'] < 3) and delta_soc > 10:
  450. df_dvdq_data['df_dq_lvb'] = svflter(df_dvdq_data['dv_dq'], para_lvbo, 3, mode = 'nearest')#
  451. df_data = df_dvdq_data.copy()#loc[(df_dataana['pack_soc'] > 30) & (df_dataana['pack_soc'] < 70)]
  452. df_data.reset_index(drop = True, inplace = True)
  453. dvsocchrcter = []
  454. if len(df_data) > 10:
  455. cellvltname = ['fr_vlt_dvdq']#, 'send', 'thrd'
  456. cellvltahname = ['df_dq_lvb']#, 'dffsendvlt', 'dffthdvlt'
  457. maxsoc = 0
  458. for itemnum in range(0, 1):
  459. snchrcter = []
  460. np_vlt_ori = np.array(df_data[cellvltahname[itemnum]])#dffminvlt
  461. np_vltori_smth = svflter(np_vlt_ori, para_lvbo, 3)
  462. rcoumax, peak_indexmax, rcoumin, peak_indexmin = find_peak_triangleNum(np_vltori_smth, 7)#, rcoumin, peak_indexmin
  463. if (len(peak_indexmax) > 0) and (len(peak_indexmin) > 0):
  464. peak_fst = np_vltori_smth[peak_indexmax[0]]
  465. botm_fst = np_vltori_smth[peak_indexmin[0]]
  466. pkbtmratfst = botm_fst/peak_fst
  467. else:
  468. peak_fst = -1
  469. if (peak_fst>0):#and (botm_fst>0) and (abs(pkbtmratfst) >= 0.2) and (abs(pkbtmratfst) <= 0.8)
  470. maxindex = peak_indexmax[0]
  471. maxsoc = np.array(df_data['pack_soc'])[maxindex]
  472. snchrcter.append(itemsn)
  473. snchrcter.append(np.array(df_data['time'])[maxindex])#df_data.loc[0, 'time']
  474. snchrcter.append(np.array(df_data[cellvltname[itemnum]])[maxindex])#电压
  475. snchrcter.append(maxsoc)
  476. snchrcter.append(pkbtmratfst)
  477. snchrcter.append(np.array(df_data['max_T'])[maxindex])#最大电芯温度
  478. snchrcter.append(np.array(df_data['min_T'])[maxindex])#最大电芯温度
  479. snchrcter.append(round(np.array(df_data['pack_crnt'])[maxindex]/self.capty, 3))#倍率
  480. snchrcter.append(df_data['odo'].iloc[0])#里程
  481. snchrcter.append(np.array(df_data['pack_volt'])[maxindex])#里程
  482. dvsocchrcter.append(snchrcter)
  483. df_chracter_ofc= pd.DataFrame(dvsocchrcter)#各电芯的电压微分特征值
  484. peak_pos = abs(maxsoc - df_dvdq_data['pack_soc'].iloc[0])
  485. if (not df_chracter_ofc.empty) and (peak_pos > 3):
  486. setcolumns = ['sn', 'time', 'frstvlt', 'soc_ori', 'pkbtmfst', 'frstmaxT', 'frstminT', 'rate', 'odo', 'pack_vlt']
  487. df_chracter_ofc.columns = setcolumns
  488. df_chracter_ofc['rate'] = np.abs(df_chracter_ofc['rate'])
  489. else:
  490. df_chracter_ofc = pd.DataFrame()
  491. if (not df_chracter_ofc.empty):
  492. DataArray = df_chracter_ofc.values
  493. Y = DataArray[:, 3]#SOC值
  494. X = DataArray[:, [2,5,6,7,8,9]] #电压、峰谷比,温度,rate,odo4,
  495. X = np.array(X)#转化为array,自变量
  496. Y = np.array(Y)#转化为array,因变量soc
  497. paraminput_x = self.inputnorm_x.fit_transform(X)
  498. Soc_ori = np.array(Y)
  499. SOC_pre_dnn_ori = self.Dnn_predict.predict(paraminput_x)
  500. SOC_pre = self.inputnorm_y.inverse_transform(SOC_pre_dnn_ori.reshape(-1, 1)).reshape(-1)
  501. SOC_error = (SOC_pre - Soc_ori)
  502. SOC_error_abs = abs(SOC_error)
  503. # if max(SOC_error_abs) > 5:
  504. df_chracter_ofc['soc_pre'] = SOC_pre
  505. df_chracter_ofc['soc_error'] = SOC_error.astype('float')
  506. df_chracter_ofc['soc_pre'] = df_chracter_ofc['soc_pre'].round(3)
  507. df_chracter_ofc['soc_error'] = df_chracter_ofc['soc_error'].round(3)
  508. df_soc_rlt = df_chracter_ofc[(df_chracter_ofc['soc_pre'] < 60) & (df_chracter_ofc['soc_pre'] > 35) &
  509. (df_chracter_ofc['soc_ori'] < 60) & (df_chracter_ofc['soc_ori'] > 35)]
  510. df_soc_rlt.reset_index(drop = True, inplace = True)
  511. if not df_soc_rlt.empty:
  512. SOC_rlt = df_soc_rlt[['sn', 'time', 'soc_ori', 'soc_pre', 'soc_error', 'frstvlt', 'pkbtmfst', 'frstmaxT',
  513. 'frstminT', 'rate', 'odo']]
  514. SOC_rlt['soc_pre'] = SOC_rlt['soc_pre'].round(1)
  515. SOC_rlt['soc_error'] = SOC_rlt['soc_error'].round(1)
  516. # SOC_clms = ['frstsoc', 'SOC_pre', 'SOC_error', 'frstvlt', 'pkbtmfst', 'frstmaxT', 'frstminT', 'rate']
  517. # df_cellname = SOC_rlt.groupby(['time'])['cellname'].apply(list)
  518. # cellname = df_cellname.values[0]
  519. # namenum = 'cellnum:' + str(list(map(int, [i[12:] for i in cellname])))
  520. # SOC_rltlst = []
  521. # SOC_rltlst.append(self.sn)
  522. # SOC_rltlst.append(namenum)
  523. # SOC_rltlst.append(SOC_rlt['time'].iloc[0])
  524. # for itemsoc in SOC_clms:
  525. # df_cellname = SOC_rlt.groupby(['time'])[itemsoc].apply(list)
  526. # cellname = df_cellname.values[0]
  527. # SOC_rltlst.append(str(cellname))
  528. # SOC_rltlst.append(SOC_rlt['odo'].iloc[0])
  529. # SOC_rlt_final = pd.DataFrame(SOC_rltlst).T
  530. # SOC_rlt_final.columns = ['sn', 'cellname', 'time', 'soc_ori', 'soc_pre', 'soc_error', 'frstvlt', 'pkbtmfst', 'frstmaxT', 'frstminT', 'rate', 'odo']
  531. SOC_pre_cal_dnn = SOC_rlt[['sn', 'time', 'soc_ori', 'soc_pre', 'soc_error', 'odo']]
  532. SOC_pre_cal_dnn['method'] = 1
  533. df_soc_rlt_con = pd.concat([SOC_pre_cal, SOC_pre_cal_dnn])
  534. df_soc_rlt_con.reset_index(drop = True, inplace = True)
  535. if not df_soc_rlt_con.empty:
  536. df_soc_rlt_con['battery_type'] = 'lfp'
  537. soc_pre_method = list(df_soc_rlt_con['method'])
  538. if 3 in soc_pre_method:
  539. SOC_out = df_soc_rlt_con[(df_soc_rlt_con['method'] == 3)]
  540. elif 2 in soc_pre_method:
  541. SOC_out = df_soc_rlt_con[(df_soc_rlt_con['method'] == 2)]
  542. elif 1 in soc_pre_method:
  543. SOC_out = df_soc_rlt_con[(df_soc_rlt_con['method'] == 1)]
  544. else:
  545. SOC_out = pd.DataFrame()
  546. else:
  547. SOC_out = pd.DataFrame()
  548. return SOC_out #SOC_rlt_final, SOH_rlt_final
  549. df_data = self.df_bms.copy()
  550. df_data = df_data.loc[:, ~df_data.columns.duplicated()]
  551. # def states_cal(self):
  552. # SOC_rlt = pd.DataFrame(columns = ['sn', 'time', 'soc_ori', 'soc_pre', 'soc_error', 'odo', 'method', 'battery_type'])
  553. if max(self.LookTab_OCV) > 4:
  554. SOC_rlt = df_data.groupby('sn').apply(soc_cal_ncm)
  555. else:
  556. SOC_rlt = df_data.groupby('sn').apply(soc_cal_lfp)
  557. if not SOC_rlt.empty:
  558. SOC_rlt.rename(columns={"soc_ori":"soc", "soc_pre":"soc_real", "soc_error":"soc_delta"}, inplace = True)
  559. SOC_rlt.drop(columns=['battery_type'], inplace = True)
  560. fillna = len(SOC_rlt)*[np.nan]
  561. SOC_rlt['soc_max'] = fillna
  562. SOC_rlt['soc_min'] = fillna
  563. SOC_rlt['cell_soc_delta'] = fillna
  564. return SOC_rlt
  565. else:
  566. return pd.DataFrame(columns = ['sn', 'time', 'soc_max', 'soc_min', 'soc', 'soc_real', 'soc_delta',
  567. 'odo', 'method', 'cell_soc_delta'])