LFPSoh_20210711.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. # 获取数据
  2. from LIB.BACKEND import DBManager
  3. import os
  4. import pandas as pd
  5. import numpy as np
  6. import datetime
  7. # import matplotlib.pyplot as plt
  8. #参数输入
  9. Capacity = 54
  10. PackFullChrgVolt=69.99
  11. CellFullChrgVolt=3.5
  12. CellVoltNums=20
  13. CellTempNums=4
  14. FullChrgSoc=98
  15. PeakSoc=57
  16. # #40Ah-OCV
  17. # LookTab_SOC = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100]
  18. # LookTab_OCV = [3.3159, 3.4502, 3.4904, 3.5277, 3.5590, 3.5888, 3.6146, 3.6312, 3.6467, 3.6642, 3.6865, 3.7171, 3.7617,
  19. # 3.8031, 3.8440, 3.8888, 3.9376, 3.9891, 4.0451, 4.1068, 4.1830]
  20. #55Ah-OCV
  21. LookTab_SOC = [0.00, 2.40, 6.38, 10.37, 14.35, 18.33, 22.32, 26.30, 30.28, 35.26, 40.24, 45.22, 50.20, 54.19, 58.17, 60.16, 65.14, 70.12, 75.10, 80.08, 84.06, 88.05, 92.03, 96.02, 100.00]
  22. LookTab_OCV = [2.7151, 3.0298, 3.1935, 3.2009, 3.2167, 3.2393, 3.2561, 3.2703, 3.2843, 3.2871, 3.2874, 3.2868, 3.2896, 3.2917, 3.2967, 3.3128, 3.3283, 3.3286, 3.3287, 3.3288, 3.3289, 3.3296, 3.3302, 3.3314, 3.3429]
  23. #定义滑动滤波函数
  24. def np_move_avg(a, n, mode="same"):
  25. return (np.convolve(a, np.ones((n,)) / n, mode=mode))
  26. #参数初始化
  27. dvdq_soh=[]
  28. dvdq_soh_err=[]
  29. bms_soh=[]
  30. dvdq_time=[]
  31. dvdq_sohcfd=[]
  32. sn_list=[]
  33. #输入一个含有‘SN号’的xlsx
  34. SNdata = pd.read_excel('骑享资产梳理-20210621.xlsx', sheet_name='6060')
  35. SNnums=SNdata['SN号']
  36. def cal_soh(sn, end_time, start_time):
  37. #获取数据时间段
  38. end_time = end_time
  39. strat_time = start_time
  40. SNnum=str(sn)
  41. sn = SNnum
  42. st = start_time
  43. et = end_time
  44. dbManager = DBManager.DBManager()
  45. df_data = dbManager.get_data(sn=sn, start_time=st, end_time=et, data_groups=['bms'])
  46. data = df_data['bms']
  47. packcrnt=data['总电流[A]']
  48. packvolt=data['总电压[V]']
  49. SOC=data['SOC[%]']
  50. SOH=data['SOH[%]']
  51. bmsstat=data['充电状态']
  52. time= pd.to_datetime(data['时间戳'], format='%Y-%m-%d %H:%M:%S')
  53. #第一步:筛选充电数据
  54. ChgStart=[]
  55. ChgEnd=[]
  56. for i in range(3, len(time) - 3):
  57. if i==3 and bmsstat[i]==2 and bmsstat[i+1]==2 and bmsstat[i+2]==2:
  58. ChgStart.append(i)
  59. elif bmsstat[i-2]!=2 and bmsstat[i-1]!=2 and bmsstat[i]==2:
  60. ChgStart.append(i)
  61. elif bmsstat[i-1]==2 and bmsstat[i]!=2 and bmsstat[i+1]!=2:
  62. ChgEnd.append(i)
  63. elif i == (len(time) - 4) and bmsstat[len(bmsstat)-1] == 2 and bmsstat[len(bmsstat)-2] == 2:
  64. ChgEnd.append(len(time)-1)
  65. #第二步:筛选充电起始Soc<48%,电芯温度>15℃,且满充的数据
  66. ChgStartValid1=[]
  67. ChgEndValid1=[]
  68. ChgStartValid2=[]
  69. ChgEndValid2=[]
  70. for i in range(min(len(ChgStart),len(ChgEnd))):
  71. #获取最小温度值
  72. celltemp = []
  73. for j in range(1, CellTempNums+1):
  74. s = str(j)
  75. temp = data['单体温度' + s]
  76. celltemp.append(temp[ChgEnd[i]])
  77. #寻找最大电压值
  78. cellvolt = []
  79. for j in range(1, CellVoltNums+1):
  80. s = str(j)
  81. volt = max(data['单体电压' + s][ChgStart[i]:ChgEnd[i]]/1000)
  82. cellvolt.append(volt)
  83. #筛选满足2点法计算的数据
  84. StandingTime=0
  85. if max(cellvolt)>CellFullChrgVolt and SOC[ChgStart[i]]<30 and min(celltemp)>5:
  86. for k in reversed(range(ChgStart[i])):
  87. if abs(packcrnt[k - 2]) < 0.01:
  88. StandingTime = StandingTime + (time[k] - time[k-1]).total_seconds()
  89. if StandingTime > 600: # 筛选静置时间>10min
  90. ChgStartValid1.append(ChgStart[i])
  91. ChgEndValid1.append(ChgEnd[i])
  92. break
  93. else:
  94. break
  95. #筛选满足DV/DQ方法的数据
  96. if max(cellvolt)>CellFullChrgVolt and SOC[ChgStart[i]]<45 and min(celltemp)>5:
  97. if ((time[ChgEnd[i]]-time[ChgStart[i]]).total_seconds())/(ChgEnd[i]-ChgStart[i])<60:
  98. ChgStartValid2.append(ChgStart[i])
  99. ChgEndValid2.append(ChgEnd[i])
  100. #第三步:计算充电Soc和Soh
  101. # 两点法计算soh
  102. Soc=[]
  103. Time=[]
  104. Soc_Err=[]
  105. Bms_Soc=[]
  106. Soh1=[]
  107. Time1=[]
  108. Bms_Soh1=[]
  109. Soh_Err1=[]
  110. for i in range(len(ChgStartValid1)):
  111. #寻找最大电压值
  112. cellvolt = []
  113. for j in range(1, CellVoltNums+1):
  114. s = str(j)
  115. volt = max(data['单体电压' + s])
  116. cellvolt.append(volt)
  117. voltmax_index = cellvolt.index(max(cellvolt)) + 1
  118. cellvolt = data['单体电压' + str(voltmax_index)] / 1000
  119. #soc
  120. Soc.append(np.interp(cellvolt[ChgStartValid1[i]-3],LookTab_OCV,LookTab_SOC))
  121. Time.append(time[ChgStartValid1[i]-3])
  122. Bms_Soc.append(SOC[ChgStartValid1[i]-3])
  123. Soc_Err.append(Bms_Soc[-1]-Soc[-1])
  124. #soh
  125. Ocv_Soc=np.interp(cellvolt[ChgStartValid1[i]-3],LookTab_OCV,LookTab_SOC)
  126. Ah=0
  127. for j in range(ChgStartValid1[i],ChgEndValid1[i]):
  128. #计算soc
  129. Step=(time[j]-time[j-1]).total_seconds()
  130. Time.append(time[j])
  131. Bms_Soc.append(SOC[j])
  132. if Soc[-1]-(packcrnt[j]*Step*100)/(3600*Capacity)<100:
  133. Soc.append(Soc[-1]-(packcrnt[j]*Step*100)/(3600*Capacity))
  134. else:
  135. Soc.append(100)
  136. Soc_Err.append(Bms_Soc[-1] - Soc[-1])
  137. #两点法计算soh
  138. Ah=Ah-packcrnt[j]*Step/3600
  139. Soh1.append(Ah*100/((FullChrgSoc-Ocv_Soc)*0.01*Capacity))
  140. Bms_Soh1.append(SOH[i])
  141. Soh_Err1.append(Bms_Soh1[-1]-Soh1[-1])
  142. Time1.append(time[ChgStartValid1[i]])
  143. # DV/DQ法计算soh
  144. Soh2=[]
  145. Time2=[]
  146. Bms_Soh2=[]
  147. Soh_Err2=[]
  148. SohCfd = []
  149. sn_list=[]
  150. for i in range(len(ChgStartValid2)):
  151. #寻找最大电压值
  152. cellvolt1 = []
  153. cellvolt=[]
  154. for j in range(1, CellVoltNums+1):
  155. s = str(j)
  156. volt = data['单体电压' + s]
  157. cellvolt1.append(volt[ChgEndValid2[i]])
  158. voltmax1_index = cellvolt1.index(max(cellvolt1)) + 1
  159. cellvolt1 = data['单体电压' + str(voltmax1_index)] / 1000
  160. #电压采用滑动平均滤波
  161. cellvolt=np_move_avg(cellvolt1, 3, mode="same")
  162. #参数赋初始值
  163. Ah = 0
  164. Volt = cellvolt[ChgStartValid2[i]]
  165. DV_Volt=[]
  166. DQ_Ah = []
  167. DVDQ = []
  168. time2 = []
  169. soc2 = []
  170. Ah_tatal=[0]
  171. xvolt=[]
  172. #计算DV和DQ值
  173. for j in range(ChgStartValid2[i],ChgEndValid2[i]):
  174. Step=(time[j+1]-time[j]).total_seconds()
  175. Ah=Ah-packcrnt[j]*Step/3600
  176. if (cellvolt[j]-Volt)>0.0009 and Ah>0:
  177. Ah_tatal.append(Ah_tatal[-1]+Ah)
  178. DQ_Ah.append(Ah)
  179. DV_Volt.append(cellvolt[j]-Volt)
  180. DVDQ.append((DV_Volt[-1])/DQ_Ah[-1])
  181. xvolt.append(cellvolt[j])
  182. Volt=cellvolt[j]
  183. Ah = 0
  184. time2.append(time[j])
  185. soc2.append(SOC[j])
  186. #切片Soc>50且Soc<80
  187. Data1 = pd.DataFrame({'SOC': soc2,
  188. 'DVDQ': DVDQ,
  189. 'Ah_tatal': Ah_tatal[:-1],
  190. 'DQ_Ah':DQ_Ah,
  191. 'DV_Volt':DV_Volt,
  192. 'XVOLT':xvolt})
  193. Data1=Data1[(Data1['SOC']>50) & (Data1['SOC']<80)]
  194. #寻找峰值并计算Soh和置信度
  195. # 获取最小温度值
  196. celltemp = []
  197. for j in range(1, CellTempNums+1):
  198. s = str(j)
  199. temp = data['单体温度' + s]
  200. celltemp.append(temp[ChgStartValid2[i]])
  201. if len(Data1['DVDQ'])>1:
  202. PeakIndex=Data1['DVDQ'].idxmax()
  203. #筛选峰值点附近±0.5%SOC内的数据
  204. Data2=Data1[(Data1['SOC']>(Data1['SOC'][PeakIndex]-0.5)) & (Data1['SOC']<(Data1['SOC'][PeakIndex]+0.5))]
  205. if len(Data2)>2:
  206. Ah_tatal1 = Data1['Ah_tatal']
  207. DVDQ = Data1['DVDQ']
  208. soc2 = Data1['SOC']
  209. xvolt = Data1['XVOLT']
  210. if soc2[PeakIndex]>50 and soc2[PeakIndex]<80:
  211. DVDQ_SOH=(Ah_tatal[-1]-Ah_tatal1[PeakIndex]) * 100 / ((FullChrgSoc - PeakSoc) * 0.01 * Capacity)
  212. if DVDQ_SOH<95:
  213. DVDQ_SOH=DVDQ_SOH*0.3926+58.14
  214. if DVDQ_SOH>70 and DVDQ_SOH<120:
  215. Soh2.append(DVDQ_SOH)
  216. Bms_Soh2.append(SOH[ChgStartValid2[i]])
  217. Soh_Err2.append(Bms_Soh2[-1] - Soh2[-1])
  218. Time2.append(time[ChgStartValid2[i]])
  219. sn_list.append(SNnum)
  220. #计算置信度
  221. if min(celltemp)<10:
  222. SohCfd.append(50)
  223. elif min(celltemp)<20:
  224. SohCfd.append(80)
  225. else:
  226. SohCfd.append(100)
  227. else:
  228. Data1=Data1.drop([PeakIndex])
  229. PeakIndex = Data1['DVDQ'].idxmax()
  230. Data2 = Data1[(Data1['SOC'] > (Data1['SOC'][PeakIndex] - 0.5)) & (Data1['SOC'] < (Data1['SOC'][PeakIndex] + 0.5))]
  231. if len(Data2) > 3:
  232. Ah_tatal1 = Data1['Ah_tatal']
  233. DVDQ = Data1['DVDQ']
  234. soc2 = Data1['SOC']
  235. xvolt = Data1['XVOLT']
  236. if soc2[PeakIndex]>50 and soc2[PeakIndex]<80:
  237. DVDQ_SOH=(Ah_tatal[-1]-Ah_tatal1[PeakIndex]) * 100 / ((FullChrgSoc - PeakSoc) * 0.01 * Capacity)
  238. if DVDQ_SOH<95:
  239. DVDQ_SOH=DVDQ_SOH*0.3926+58.14
  240. if DVDQ_SOH>70 and DVDQ_SOH<120:
  241. Soh2.append(DVDQ_SOH)
  242. Bms_Soh2.append(SOH[ChgStartValid2[i]])
  243. Soh_Err2.append(Bms_Soh2[-1] - Soh2[-1])
  244. Time2.append(time[ChgStartValid2[i]])
  245. sn_list.append(SNnum)
  246. #计算置信度
  247. if min(celltemp)<10:
  248. SohCfd.append(50)
  249. elif min(celltemp)<20:
  250. SohCfd.append(80)
  251. else:
  252. SohCfd.append(100)
  253. #处理数据
  254. if len(Soh2)>5:
  255. Soh2=np_move_avg(Soh2,5,mode="valid")
  256. result_soh2={'时间': Time2[4::],
  257. 'SN号':sn_list[4::],
  258. 'BMS_SOH': Bms_Soh2[4::],
  259. 'SOH': Soh2,
  260. 'SOH误差': Soh_Err2[4::]}
  261. else:
  262. result_soh2={'时间': Time2,
  263. 'SN号':sn_list,
  264. 'BMS_SOH': Bms_Soh2,
  265. 'SOH': Soh2,
  266. 'SOH误差': Soh_Err2}
  267. #第四步:将数据存入Excel
  268. Result_Soh2=pd.DataFrame(result_soh2)
  269. # Result_Soh2.to_csv('BMS_SOH_'+SNnum+'.csv',encoding='GB18030')
  270. return Result_Soh2