CBMSBatUniform.py 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387
  1. import pandas as pd
  2. import numpy as np
  3. import datetime
  4. import bisect
  5. import matplotlib.pyplot as plt
  6. import BatParam
  7. class BatUniform:
  8. def __init__(self,sn,celltype,df_bms,df_volt,df_temp,df_accum): #参数初始化
  9. self.sn=sn
  10. self.celltype=celltype
  11. CellVoltNums=int(df_volt.loc[5,'单体电池总数'])
  12. if CellVoltNums==110:
  13. self.celltype=99
  14. else:
  15. self.celltype==100
  16. self.param=BatParam.BatParam(self.celltype)
  17. self.df_volt=df_volt
  18. self.df_temp=df_temp
  19. self.packcrnt=(df_volt['可充电储能装置电流(A)'].astype('float'))*self.param.PackCrntDec
  20. self.packvolt=df_volt['可充电储能装置电压(V)'].astype('float')
  21. self.bms_soc=df_bms['SOC']
  22. # self.bms_soh=df_volt['SOH[%]']
  23. self.bmstime= pd.to_datetime(df_volt['上报时间'], format='%Y-%m-%d %H:%M:%S')
  24. self.param.CellVoltNums=CellVoltNums
  25. self.param.CellTempNums=int(df_temp.loc[5,'可充电储能温度探针个数'])
  26. def batuniform(self):
  27. if self.celltype==1 or self.celltype==2 or self.celltype==3 or self.celltype==4 or self.celltype==100:
  28. df_res=self._ncm_uniform()
  29. return df_res
  30. elif self.celltype==99:
  31. df_res=self._lfp_uniform()
  32. return df_res
  33. else:
  34. return pd.DataFrame()
  35. #定义滑动滤波函数........................................................................................................................................
  36. def _np_move_avg(self,a, n, mode="same"):
  37. return (np.convolve(a, np.ones((n,)) / n, mode=mode))
  38. #寻找当前行数据的最小温度值................................................................................................................................
  39. def _celltemp_weight(self,num):
  40. celltemp = []
  41. for j in range(1, self.param.CellTempNums+1):
  42. s = str(j)
  43. celltemp.append(self.df_temp.loc[num, s+'.0'])
  44. celltemp.remove(min(celltemp))
  45. self.celltemp=celltemp
  46. if self.celltype==99:
  47. if min(celltemp)>=20:
  48. self.tempweight=1
  49. self.StandardStandingTime=1800
  50. elif min(celltemp)>=10:
  51. self.tempweight=0.6
  52. self.StandardStandingTime=3600
  53. elif min(celltemp)>=5:
  54. self.tempweight=0.
  55. self.StandardStandingTime=3600
  56. else:
  57. self.tempweight=0.1
  58. self.StandardStandingTime=7200
  59. else:
  60. if min(celltemp)>=20:
  61. self.tempweight=1
  62. self.StandardStandingTime=1800
  63. elif min(celltemp)>=10:
  64. self.tempweight=0.8
  65. self.StandardStandingTime=2400
  66. elif min(celltemp)>=5:
  67. self.tempweight=0.6
  68. self.StandardStandingTime=3600
  69. else:
  70. self.tempweight=0.2
  71. self.StandardStandingTime=7200
  72. #获取当前行所有电压数据............................................................................................................................
  73. def _cellvolt_get(self,num):
  74. cellvolt=[]
  75. for j in range(1, self.param.CellVoltNums+1):
  76. s = str(j)
  77. cellvolt.append(self.df_volt.loc[num,s+'.0'])
  78. return(cellvolt)
  79. #寻找DVDQ的峰值点,并返回..........................................................................................................................
  80. def _dvdq_peak(self, time, soc, cellvolt, packcrnt):
  81. cellvolt = self._np_move_avg(cellvolt, 3, mode="same")
  82. Soc = 0
  83. Ah = 0
  84. Volt = cellvolt[0]
  85. DV_Volt = []
  86. DQ_Ah = []
  87. DVDQ = []
  88. time1 = []
  89. soc1 = []
  90. soc2 = []
  91. xvolt=[]
  92. for m in range(1, len(time)):
  93. Step = (time[m] - time[m - 1]).total_seconds()
  94. Soc = Soc - packcrnt[m] * Step * 100 / (3600 * self.param.Capacity)
  95. Ah = Ah - packcrnt[m] * Step / 3600
  96. if (cellvolt[m]-Volt)>0.0019 and Ah>0:
  97. DQ_Ah.append(Ah)
  98. DV_Volt.append(cellvolt[m]-Volt)
  99. DVDQ.append((DV_Volt[-1])/DQ_Ah[-1])
  100. xvolt.append(cellvolt[m])
  101. Volt=cellvolt[m]
  102. Ah = 0
  103. soc1.append(Soc)
  104. time1.append(time[m])
  105. soc2.append(soc[m])
  106. #切片,去除前后10min的数据
  107. df_Data1 = pd.DataFrame({'time': time1,
  108. 'SOC': soc2,
  109. 'DVDQ': DVDQ,
  110. 'AhSoc': soc1,
  111. 'DQ_Ah':DQ_Ah,
  112. 'DV_Volt':DV_Volt,
  113. 'XVOLT':xvolt})
  114. start_time=df_Data1.loc[0,'time']
  115. start_time=start_time+datetime.timedelta(seconds=900)
  116. end_time=df_Data1.loc[len(time1)-1,'time']
  117. end_time=end_time-datetime.timedelta(seconds=1200)
  118. if soc2[0]<36:
  119. df_Data1=df_Data1[(df_Data1['SOC']>40) & (df_Data1['SOC']<80)]
  120. else:
  121. df_Data1=df_Data1[(df_Data1['time']>start_time) & (df_Data1['SOC']<80)]
  122. df_Data1=df_Data1[(df_Data1['XVOLT']>self.param.PeakVoltLowLmt) & (df_Data1['XVOLT']<self.param.PeakVoltUpLmt)]
  123. # print(packcrnt[int(len(time)/2)], min(self.celltemp))
  124. # ax1 = plt.subplot(3, 1, 1)
  125. # plt.plot(df_Data1['XVOLT'],df_Data1['DVDQ'],'g*-')
  126. # plt.xlabel('Volt/V')
  127. # plt.ylabel('DV/DQ')
  128. # plt.legend()
  129. # ax1 = plt.subplot(3, 1, 2)
  130. # plt.plot(df_Data1['SOC'],df_Data1['XVOLT'],'y*-')
  131. # plt.xlabel('SOC/%')
  132. # plt.ylabel('Volt/V')
  133. # plt.legend()
  134. # ax1 = plt.subplot(3, 1, 3)
  135. # plt.plot(df_Data1['SOC'], df_Data1['DVDQ'], 'r*-')
  136. # plt.xlabel('SOC/%')
  137. # plt.ylabel('DV/DQ')
  138. # plt.legend()
  139. # plt.show()
  140. if len(df_Data1)>2: #寻找峰值点,且峰值点个数>2
  141. PeakIndex = df_Data1['DVDQ'].idxmax()
  142. df_Data2 = df_Data1[(df_Data1['SOC'] > (df_Data1['SOC'][PeakIndex] - 0.5)) & (df_Data1['SOC'] < (df_Data1['SOC'][PeakIndex] + 0.5))]
  143. if len(df_Data2) > 2 and df_Data1.loc[PeakIndex,'XVOLT']<self.param.PeakVoltUpLmt-0.019:
  144. return df_Data1['AhSoc'][PeakIndex]
  145. else:
  146. df_Data1 = df_Data1.drop([PeakIndex])
  147. PeakIndex = df_Data1['DVDQ'].idxmax()
  148. df_Data2 = df_Data1[(df_Data1['SOC'] > (df_Data1['SOC'][PeakIndex] - 0.5)) & (df_Data1['SOC'] < (df_Data1['SOC'][PeakIndex] + 0.5))]
  149. if len(df_Data2) > 2 and df_Data1.loc[PeakIndex,'XVOLT']<self.param.PeakVoltUpLmt-0.019:
  150. return df_Data1['AhSoc'][PeakIndex]
  151. else:
  152. return 0
  153. else:
  154. return 0
  155. #三元电池一致性计算.................................................................................................................................
  156. def _ncm_uniform(self):
  157. column_name=['time','sn','cellsoc_diff','cellvolt_diff','cellmin_num','cellmax_num']
  158. df_res=pd.DataFrame(columns=column_name)
  159. standingtime=0
  160. for i in range(1,len(self.df_volt)-2):
  161. if abs(self.packcrnt[i]) < 0.1 and abs(self.packcrnt[i-1]) < 0.1: #电流为0
  162. delttime=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
  163. standingtime=standingtime+delttime
  164. self._celltemp_weight(i) #获取不同温度对应的静置时间
  165. if standingtime>self.StandardStandingTime: #静置时间满足要求
  166. if abs(self.packcrnt[i+1]) >= 0.1:
  167. standingtime=0
  168. cellvolt_now=self._cellvolt_get(i) #获取当前行电压数据
  169. cellvolt_last=self._cellvolt_get(i-1)
  170. cellvolt_min=min(cellvolt_now)
  171. cellvolt_max=max(cellvolt_now)
  172. cellvolt_maxlast=max(cellvolt_last)
  173. if 3<cellvolt_min<4.5 and 3<cellvolt_max<4.5 and abs(cellvolt_maxlast-cellvolt_max)<0.003:
  174. cellmin_num=cellvolt_now.index(cellvolt_min)+1
  175. cellmax_num=cellvolt_now.index(cellvolt_max)+1
  176. cellsoc_min=np.interp(cellvolt_min,self.param.LookTab_OCV,self.param.LookTab_SOC)
  177. cellsoc_max=np.interp(cellvolt_max,self.param.LookTab_OCV,self.param.LookTab_SOC)
  178. cellvolt_diff=(cellvolt_max-cellvolt_min)*1000
  179. cellsoc_diff=cellsoc_max-cellsoc_min
  180. cellsoc_diff=eval(format(cellsoc_diff,'.1f'))
  181. cellvolt_diff=eval(format(cellvolt_diff,'.0f'))
  182. df_res.loc[len(df_res)]=[self.bmstime[i], self.sn, cellsoc_diff, cellvolt_diff, cellmin_num, cellmax_num]
  183. elif standingtime>3600*12:
  184. standingtime=0
  185. cellvolt_now=self._cellvolt_get(i) #获取当前行电压数据
  186. cellvolt_last=self._cellvolt_get(i-1)
  187. cellvolt_min=min(cellvolt_now)
  188. cellvolt_max=max(cellvolt_now)
  189. cellvolt_maxlast=max(cellvolt_last)
  190. if 3<cellvolt_min<4.5 and 3<cellvolt_max<4.5 and abs(cellvolt_maxlast-cellvolt_max)<0.003:
  191. cellmin_num=cellvolt_now.index(cellvolt_min)+1
  192. cellmax_num=cellvolt_now.index(cellvolt_max)+1
  193. cellsoc_min=np.interp(cellvolt_min,self.param.LookTab_OCV,self.param.LookTab_SOC)
  194. cellsoc_max=np.interp(cellvolt_max,self.param.LookTab_OCV,self.param.LookTab_SOC)
  195. cellvolt_diff=(cellvolt_max-cellvolt_min)*1000
  196. cellsoc_diff=cellsoc_max-cellsoc_min
  197. cellsoc_diff=eval(format(cellsoc_diff,'.1f'))
  198. cellvolt_diff=eval(format(cellvolt_diff,'.0f'))
  199. df_res.loc[len(df_res)]=[self.bmstime[i], self.sn, cellsoc_diff, cellvolt_diff, cellmin_num, cellmax_num]
  200. elif i>=len(self.df_volt)-4:
  201. standingtime=0
  202. cellvolt_now=self._cellvolt_get(i) #获取当前行电压数据
  203. cellvolt_last=self._cellvolt_get(i-1)
  204. cellvolt_min=min(cellvolt_now)
  205. cellvolt_max=max(cellvolt_now)
  206. cellvolt_maxlast=max(cellvolt_last)
  207. if 3<cellvolt_min<4.5 and 3<cellvolt_max<4.5 and abs(cellvolt_maxlast-cellvolt_max)<0.003:
  208. cellmin_num=cellvolt_now.index(cellvolt_min)+1
  209. cellmax_num=cellvolt_now.index(cellvolt_max)+1
  210. cellsoc_min=np.interp(cellvolt_min,self.param.LookTab_OCV,self.param.LookTab_SOC)
  211. cellsoc_max=np.interp(cellvolt_max,self.param.LookTab_OCV,self.param.LookTab_SOC)
  212. cellvolt_diff=(cellvolt_max-cellvolt_min)*1000
  213. cellsoc_diff=cellsoc_max-cellsoc_min
  214. cellsoc_diff=eval(format(cellsoc_diff,'.1f'))
  215. cellvolt_diff=eval(format(cellvolt_diff,'.0f'))
  216. df_res.loc[len(df_res)]=[self.bmstime[i], self.sn, cellsoc_diff, cellvolt_diff, cellmin_num, cellmax_num]
  217. break
  218. else:
  219. continue
  220. else:
  221. continue
  222. else:
  223. standingtime=0
  224. continue
  225. if df_res.empty: #返回计算结果
  226. return pd.DataFrame()
  227. else:
  228. return df_res
  229. #磷酸铁锂电池一致性计算.........................................................................................................................
  230. def _lfp_uniform(self):
  231. column_name=['time','sn','cellsoc_diff','cellvolt_diff','cellmin_num','cellmax_num']
  232. df_res=pd.DataFrame(columns=column_name)
  233. standingtime=0
  234. chrg_start=[]
  235. chrg_end=[]
  236. charging=0
  237. for i in range(3,len(self.df_volt)-3):
  238. #静置电压法计算电芯一致性
  239. if abs(self.packcrnt[i]) < 0.1 and abs(self.packcrnt[i-1]) < 0.1: #电流为0
  240. delttime=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
  241. standingtime=standingtime+delttime
  242. self._celltemp_weight(i) #获取不同温度对应的静置时间
  243. if standingtime>self.StandardStandingTime: #静置时间满足要求
  244. cellvolt_now=self._cellvolt_get(i) #获取当前行电压数据
  245. cellvolt_last=self._cellvolt_get(i-1)
  246. cellvolt_min=min(cellvolt_now)
  247. cellvolt_max=max(cellvolt_now)
  248. cellvolt_maxlast=max(cellvolt_last)
  249. if abs(self.packcrnt[i+1]) >= 0.1 and abs(cellvolt_maxlast-cellvolt_max)<0.003:
  250. standingtime=0
  251. if 2 < cellvolt_max < self.param.OcvInflexionBelow-0.02:
  252. cellmin_num=cellvolt_now.index(cellvolt_min)+1
  253. cellmax_num=cellvolt_now.index(cellvolt_max)+1
  254. cellsoc_min=np.interp(cellvolt_min,self.param.LookTab_OCV,self.param.LookTab_SOC)
  255. cellsoc_max=np.interp(cellvolt_max,self.param.LookTab_OCV,self.param.LookTab_SOC)
  256. cellvolt_diff=(cellvolt_max-cellvolt_min)*1000
  257. cellsoc_diff=cellsoc_max-cellsoc_min
  258. cellsoc_diff=eval(format(cellsoc_diff,'.1f'))
  259. cellvolt_diff=eval(format(cellvolt_diff,'.0f'))
  260. df_res.loc[len(df_res)]=[self.bmstime[i], self.sn, cellsoc_diff, cellvolt_diff, cellmin_num, cellmax_num]
  261. elif i>=len(self.df_volt)-4:
  262. standingtime=0
  263. if 2 < cellvolt_max < self.param.OcvInflexionBelow-0.02:
  264. cellmin_num=cellvolt_now.index(cellvolt_min)+1
  265. cellmax_num=cellvolt_now.index(cellvolt_max)+1
  266. cellsoc_min=np.interp(cellvolt_min,self.param.LookTab_OCV,self.param.LookTab_SOC)
  267. cellsoc_max=np.interp(cellvolt_max,self.param.LookTab_OCV,self.param.LookTab_SOC)
  268. cellvolt_diff=(cellvolt_max-cellvolt_min)*1000
  269. cellsoc_diff=cellsoc_max-cellsoc_min
  270. cellsoc_diff=eval(format(cellsoc_diff,'.1f'))
  271. cellvolt_diff=eval(format(cellvolt_diff,'.0f'))
  272. df_res.loc[len(df_res)]=[self.bmstime[i], self.sn, cellsoc_diff, cellvolt_diff, cellmin_num, cellmax_num]
  273. else:
  274. pass
  275. else:
  276. pass
  277. else:
  278. standingtime=0
  279. pass
  280. #获取DVDQ算法所需数据——开始............................................................................................................
  281. if charging==0: #判断充电开始
  282. if self.packcrnt[i]<=-1 and self.packcrnt[i+1]<=-1 and self.packcrnt[i+2]<=-1 and float(self.bms_soc[i].strip('%'))<40: #充电开始
  283. charging=1
  284. if len(chrg_start)>len(chrg_end):
  285. chrg_start[-1]=i
  286. else:
  287. chrg_start.append(i)
  288. else:
  289. pass
  290. else: #充电中
  291. if (self.bmstime[i+1]-self.bmstime[i]).total_seconds()>180 or (self.packcrnt[i]>self.param.Capacity/3 and self.packcrnt[i+1]>self.param.Capacity/3): #如果充电过程中时间间隔>180s,则舍弃该次充电
  292. chrg_start.remove(chrg_start[-1])
  293. charging=0
  294. continue
  295. elif self.packcrnt[i]<=-1 and self.packcrnt[i+1]<=-1 and self.packcrnt[i+2]>-1: #判断电流波动时刻
  296. cellvolt_now=self._cellvolt_get(i+1)
  297. if max(cellvolt_now)>self.param.CellFullChrgVolt: #电压>满充电压
  298. chrg_end.append(i+1)
  299. charging=0
  300. continue
  301. else:
  302. pass
  303. elif self.packcrnt[i+1]>-0.1 and self.packcrnt[i+2]>-0.1: #判断充电结束
  304. charging=0
  305. if len(chrg_start)>len(chrg_end):
  306. if float(self.bms_soc[i].strip('%'))>90:
  307. chrg_end.append(i)
  308. else:
  309. chrg_start.remove(chrg_start[-1])
  310. continue
  311. else:
  312. continue
  313. elif i==len(self.packcrnt)-4 and self.packcrnt[i+1]<-1 and self.packcrnt[i+2]<-1:
  314. charging=0
  315. if len(chrg_start)>len(chrg_end):
  316. if float(self.bms_soc[i].strip('%'))>90: #soc>90
  317. chrg_end.append(i)
  318. continue
  319. else:
  320. chrg_start.remove(chrg_start[-1])
  321. continue
  322. else:
  323. continue
  324. else:
  325. continue
  326. # if chrg_end: #DVDQ方法计算soc差
  327. # peaksoc_list=[]
  328. # for i in range(len(chrg_end)):
  329. # peaksoc_list = []
  330. # self._celltemp_weight(chrg_start[i])
  331. # if min(self.celltemp)>10:
  332. # for j in range(1, self.param.CellVoltNums + 1):
  333. # s = str(j)
  334. # cellvolt = self.df_volt[s+'.0']
  335. # cellvolt = list(cellvolt[chrg_start[i]:chrg_end[i]])
  336. # time = list(self.bmstime[chrg_start[i]:chrg_end[i]])
  337. # packcrnt = list(self.packcrnt[chrg_start[i]:chrg_end[i]])
  338. # soc = list(self.bms_soc[chrg_start[i]:chrg_end[i]])
  339. # peaksoc = self._dvdq_peak(time, soc, cellvolt, packcrnt)
  340. # if peaksoc>1:
  341. # peaksoc_list.append(peaksoc) #计算到达峰值点的累计Soc
  342. # else:
  343. # pass
  344. # if len(peaksoc_list)>self.param.CellVoltNums/2:
  345. # peaksoc_max=max(peaksoc_list)
  346. # peaksoc_min=min(peaksoc_list)
  347. # peaksoc_maxnum=peaksoc_list.index(peaksoc_min)+1
  348. # peaksoc_minnum=peaksoc_list.index(peaksoc_max)+1
  349. # cellsoc_diff=peaksoc_max-peaksoc_min
  350. # cellsoc_diff=eval(format(cellsoc_diff,'.1f'))
  351. # df_res.loc[len(df_res)]=[self.bmstime[chrg_start[i]], self.sn, cellsoc_diff, 0, peaksoc_minnum, peaksoc_maxnum]
  352. # else:
  353. # pass
  354. # # plt.show()
  355. # else:
  356. # pass
  357. if df_res.empty:
  358. return pd.DataFrame()
  359. else:
  360. df_res.sort_values(by='time', ascending=True, inplace=True)
  361. return df_res