LFPSoh 20210711.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  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. #获取数据时间段
  34. now_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  35. now_time=datetime.datetime.strptime(now_time,'%Y-%m-%d %H:%M:%S')
  36. start_time=now_time-datetime.timedelta(days=30)
  37. end_time=str(now_time)
  38. strat_time=str(start_time)
  39. #输入一个含有‘SN号’的xlsx
  40. SNdata = pd.read_excel('骑享资产梳理-20210621.xlsx', sheet_name='6060')
  41. SNnums=SNdata['SN号']
  42. for k in range(15):
  43. SNnum=str(SNnums[k])
  44. sn = SNnum
  45. st = '2021-07-06 00:00:00'
  46. et = '2021-07-07 20:00:00'
  47. dbManager = DBManager.DBManager()
  48. df_data = dbManager.get_data(sn=sn, start_time=st, end_time=et, data_groups=['bms'])
  49. data = df_data['bms']
  50. packcrnt=data['总电流[A]']
  51. packvolt=data['总电压[V]']
  52. SOC=data['SOC[%]']
  53. SOH=data['SOH[%]']
  54. bmsstat=data['充电状态']
  55. time= pd.to_datetime(data['时间戳'], format='%Y-%m-%d %H:%M:%S')
  56. #第一步:筛选充电数据
  57. ChgStart=[]
  58. ChgEnd=[]
  59. for i in range(3, len(time) - 3):
  60. if i==3 and bmsstat[i]==2 and bmsstat[i+1]==2 and bmsstat[i+2]==2:
  61. ChgStart.append(i)
  62. elif bmsstat[i-2]!=2 and bmsstat[i-1]!=2 and bmsstat[i]==2:
  63. ChgStart.append(i)
  64. elif bmsstat[i-1]==2 and bmsstat[i]!=2 and bmsstat[i+1]!=2:
  65. ChgEnd.append(i)
  66. elif i == (len(time) - 4) and bmsstat[len(bmsstat)-1] == 2 and bmsstat[len(bmsstat)-2] == 2:
  67. ChgEnd.append(len(time)-1)
  68. #第二步:筛选充电起始Soc<48%,电芯温度>15℃,且满充的数据
  69. ChgStartValid1=[]
  70. ChgEndValid1=[]
  71. ChgStartValid2=[]
  72. ChgEndValid2=[]
  73. for i in range(min(len(ChgStart),len(ChgEnd))):
  74. #获取最小温度值
  75. celltemp = []
  76. for j in range(1, CellTempNums+1):
  77. s = str(j)
  78. temp = data['单体温度' + s]
  79. celltemp.append(temp[ChgEnd[i]])
  80. #寻找最大电压值
  81. cellvolt = []
  82. for j in range(1, CellVoltNums+1):
  83. s = str(j)
  84. volt = max(data['单体电压' + s][ChgStart[i]:ChgEnd[i]]/1000)
  85. cellvolt.append(volt)
  86. #筛选满足2点法计算的数据
  87. StandingTime=0
  88. if max(cellvolt)>CellFullChrgVolt and SOC[ChgStart[i]]<30 and min(celltemp)>5:
  89. for k in reversed(range(ChgStart[i])):
  90. if abs(packcrnt[k - 2]) < 0.01:
  91. StandingTime = StandingTime + (time[k] - time[k-1]).total_seconds()
  92. if StandingTime > 600: # 筛选静置时间>10min
  93. ChgStartValid1.append(ChgStart[i])
  94. ChgEndValid1.append(ChgEnd[i])
  95. break
  96. else:
  97. break
  98. #筛选满足DV/DQ方法的数据
  99. if max(cellvolt)>CellFullChrgVolt and SOC[ChgStart[i]]<45 and min(celltemp)>5:
  100. if ((time[ChgEnd[i]]-time[ChgStart[i]]).total_seconds())/(ChgEnd[i]-ChgStart[i])<60:
  101. ChgStartValid2.append(ChgStart[i])
  102. ChgEndValid2.append(ChgEnd[i])
  103. #第三步:计算充电Soc和Soh
  104. # 两点法计算soh
  105. Soc=[]
  106. Time=[]
  107. Soc_Err=[]
  108. Bms_Soc=[]
  109. Soh1=[]
  110. Time1=[]
  111. Bms_Soh1=[]
  112. Soh_Err1=[]
  113. for i in range(len(ChgStartValid1)):
  114. #寻找最大电压值
  115. cellvolt = []
  116. for j in range(1, CellVoltNums+1):
  117. s = str(j)
  118. volt = max(data['单体电压' + s])
  119. cellvolt.append(volt)
  120. voltmax_index = cellvolt.index(max(cellvolt)) + 1
  121. cellvolt = data['单体电压' + str(voltmax_index)] / 1000
  122. #soc
  123. Soc.append(np.interp(cellvolt[ChgStartValid1[i]-3],LookTab_OCV,LookTab_SOC))
  124. Time.append(time[ChgStartValid1[i]-3])
  125. Bms_Soc.append(SOC[ChgStartValid1[i]-3])
  126. Soc_Err.append(Bms_Soc[-1]-Soc[-1])
  127. #soh
  128. Ocv_Soc=np.interp(cellvolt[ChgStartValid1[i]-3],LookTab_OCV,LookTab_SOC)
  129. Ah=0
  130. for j in range(ChgStartValid1[i],ChgEndValid1[i]):
  131. #计算soc
  132. Step=(time[j]-time[j-1]).total_seconds()
  133. Time.append(time[j])
  134. Bms_Soc.append(SOC[j])
  135. if Soc[-1]-(packcrnt[j]*Step*100)/(3600*Capacity)<100:
  136. Soc.append(Soc[-1]-(packcrnt[j]*Step*100)/(3600*Capacity))
  137. else:
  138. Soc.append(100)
  139. Soc_Err.append(Bms_Soc[-1] - Soc[-1])
  140. #两点法计算soh
  141. Ah=Ah-packcrnt[j]*Step/3600
  142. Soh1.append(Ah*100/((FullChrgSoc-Ocv_Soc)*0.01*Capacity))
  143. Bms_Soh1.append(SOH[i])
  144. Soh_Err1.append(Bms_Soh1[-1]-Soh1[-1])
  145. Time1.append(time[ChgStartValid1[i]])
  146. # DV/DQ法计算soh
  147. Soh2=[]
  148. Time2=[]
  149. Bms_Soh2=[]
  150. Soh_Err2=[]
  151. SohCfd = []
  152. sn_list=[]
  153. for i in range(len(ChgStartValid2)):
  154. #寻找最大电压值
  155. cellvolt1 = []
  156. cellvolt=[]
  157. for j in range(1, CellVoltNums+1):
  158. s = str(j)
  159. volt = data['单体电压' + s]
  160. cellvolt1.append(volt[ChgEndValid2[i]])
  161. voltmax1_index = cellvolt1.index(max(cellvolt1)) + 1
  162. cellvolt1 = data['单体电压' + str(voltmax1_index)] / 1000
  163. #电压采用滑动平均滤波
  164. cellvolt=np_move_avg(cellvolt1, 3, mode="same")
  165. #参数赋初始值
  166. Ah = 0
  167. Volt = cellvolt[ChgStartValid2[i]]
  168. DV_Volt=[]
  169. DQ_Ah = []
  170. DVDQ = []
  171. time2 = []
  172. soc2 = []
  173. Ah_tatal=[0]
  174. xvolt=[]
  175. #计算DV和DQ值
  176. for j in range(ChgStartValid2[i],ChgEndValid2[i]):
  177. Step=(time[j+1]-time[j]).total_seconds()
  178. Ah=Ah-packcrnt[j]*Step/3600
  179. if (cellvolt[j]-Volt)>0.0009 and Ah>0:
  180. Ah_tatal.append(Ah_tatal[-1]+Ah)
  181. DQ_Ah.append(Ah)
  182. DV_Volt.append(cellvolt[j]-Volt)
  183. DVDQ.append((DV_Volt[-1])/DQ_Ah[-1])
  184. xvolt.append(cellvolt[j])
  185. Volt=cellvolt[j]
  186. Ah = 0
  187. time2.append(time[j])
  188. soc2.append(SOC[j])
  189. #切片Soc>50且Soc<80
  190. Data1 = pd.DataFrame({'SOC': soc2,
  191. 'DVDQ': DVDQ,
  192. 'Ah_tatal': Ah_tatal[:-1],
  193. 'DQ_Ah':DQ_Ah,
  194. 'DV_Volt':DV_Volt,
  195. 'XVOLT':xvolt})
  196. Data1=Data1[(Data1['SOC']>50) & (Data1['SOC']<80)]
  197. #寻找峰值并计算Soh和置信度
  198. # 获取最小温度值
  199. celltemp = []
  200. for j in range(1, CellTempNums+1):
  201. s = str(j)
  202. temp = data['单体温度' + s]
  203. celltemp.append(temp[ChgStartValid2[i]])
  204. if len(Data1['DVDQ'])>1:
  205. PeakIndex=Data1['DVDQ'].idxmax()
  206. #筛选峰值点附近±0.5%SOC内的数据
  207. Data2=Data1[(Data1['SOC']>(Data1['SOC'][PeakIndex]-0.5)) & (Data1['SOC']<(Data1['SOC'][PeakIndex]+0.5))]
  208. if len(Data2)>2:
  209. Ah_tatal1 = Data1['Ah_tatal']
  210. DVDQ = Data1['DVDQ']
  211. soc2 = Data1['SOC']
  212. xvolt = Data1['XVOLT']
  213. if soc2[PeakIndex]>50 and soc2[PeakIndex]<80:
  214. DVDQ_SOH=(Ah_tatal[-1]-Ah_tatal1[PeakIndex]) * 100 / ((FullChrgSoc - PeakSoc) * 0.01 * Capacity)
  215. if DVDQ_SOH<95:
  216. DVDQ_SOH=DVDQ_SOH*0.3926+58.14
  217. if DVDQ_SOH>70 and DVDQ_SOH<120:
  218. Soh2.append(DVDQ_SOH)
  219. Bms_Soh2.append(SOH[ChgStartValid2[i]])
  220. Soh_Err2.append(Bms_Soh2[-1] - Soh2[-1])
  221. Time2.append(time[ChgStartValid2[i]])
  222. sn_list.append(SNnum)
  223. #计算置信度
  224. if min(celltemp)<10:
  225. SohCfd.append(50)
  226. elif min(celltemp)<20:
  227. SohCfd.append(80)
  228. else:
  229. SohCfd.append(100)
  230. else:
  231. Data1=Data1.drop([PeakIndex])
  232. PeakIndex = Data1['DVDQ'].idxmax()
  233. Data2 = Data1[(Data1['SOC'] > (Data1['SOC'][PeakIndex] - 0.5)) & (Data1['SOC'] < (Data1['SOC'][PeakIndex] + 0.5))]
  234. if len(Data2) > 3:
  235. Ah_tatal1 = Data1['Ah_tatal']
  236. DVDQ = Data1['DVDQ']
  237. soc2 = Data1['SOC']
  238. xvolt = Data1['XVOLT']
  239. if soc2[PeakIndex]>50 and soc2[PeakIndex]<80:
  240. DVDQ_SOH=(Ah_tatal[-1]-Ah_tatal1[PeakIndex]) * 100 / ((FullChrgSoc - PeakSoc) * 0.01 * Capacity)
  241. if DVDQ_SOH<95:
  242. DVDQ_SOH=DVDQ_SOH*0.3926+58.14
  243. if DVDQ_SOH>70 and DVDQ_SOH<120:
  244. Soh2.append(DVDQ_SOH)
  245. Bms_Soh2.append(SOH[ChgStartValid2[i]])
  246. Soh_Err2.append(Bms_Soh2[-1] - Soh2[-1])
  247. Time2.append(time[ChgStartValid2[i]])
  248. sn_list.append(SNnum)
  249. #计算置信度
  250. if min(celltemp)<10:
  251. SohCfd.append(50)
  252. elif min(celltemp)<20:
  253. SohCfd.append(80)
  254. else:
  255. SohCfd.append(100)
  256. #处理数据
  257. if len(Soh2)>5:
  258. Soh2=np_move_avg(Soh2,5,mode="valid")
  259. result_soh2={'时间': Time2[4::],
  260. 'SN号':sn_list[4::],
  261. 'BMS_SOH': Bms_Soh2[4::],
  262. 'SOH': Soh2,
  263. 'SOH误差': Soh_Err2[4::]}
  264. else:
  265. result_soh2={'时间': Time2,
  266. 'SN号':sn_list,
  267. 'BMS_SOH': Bms_Soh2,
  268. 'SOH': Soh2,
  269. 'SOH误差': Soh_Err2}
  270. #第四步:将数据存入Excel
  271. Result_Soh2=pd.DataFrame(result_soh2)
  272. Result_Soh2.to_csv('BMS_SOH_'+SNnum+'.csv',encoding='GB18030')