CBMSBatSoh.py 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872
  1. import random
  2. import pandas as pd
  3. import numpy as np
  4. import datetime
  5. import BatParam
  6. # from matplotlib import pyplot as plt
  7. class BatSoh():
  8. def __init__(self,sn,celltype,df_bms,df_soh): #参数初始化
  9. self.sn=sn
  10. self.celltype=celltype
  11. self.param=BatParam.BatParam(celltype)
  12. self.df_bms=df_bms
  13. self.packcrnt=df_bms['PackCrnt']*self.param.PackCrntDec
  14. self.bms_soc=df_bms['PackSOC']
  15. self.bms_soh=df_bms['PackSOH']
  16. self.bmsstat=df_bms['BMSStat']
  17. self.df_bms['time']= pd.to_datetime(df_bms['time'], format='%Y-%m-%d %H:%M:%S')
  18. self.bmstime=self.df_bms['time']
  19. self.df_soh=df_soh
  20. self.cellvolt_name=['CellVolt'+str(x) for x in range(1,self.param.CellVoltNums+1)]
  21. self.celltemp_name=['CellTemp'+str(x) for x in range(1,self.param.CellTempNums+1)]
  22. def batsoh(self):
  23. if self.celltype<50:
  24. df_res=self._ncmsoh_twopoint()
  25. return df_res
  26. else:
  27. df_res=self._lfpsoh()
  28. return df_res
  29. #定义滑动滤波函数.........................................................................................................................
  30. def _np_move_avg(self, a, n, mode):
  31. return (np.convolve(a, np.ones((n,)) / n, mode=mode))
  32. #筛选充电数据..............................................................................................................................
  33. def _chrgdata(self):
  34. self.ChgStart=[]
  35. self.ChgEnd=[]
  36. if len(self.df_bms)>100:
  37. for i in range(3, len(self.bmstime) - 3):
  38. if i==3 and self.bmsstat[i]==2 and self.bmsstat[i+1]==2 and self.bmsstat[i+2]==2:
  39. self.ChgStart.append(i)
  40. elif self.bmsstat[i-2]!=2 and self.bmsstat[i-1]!=2 and self.bmsstat[i]==2:
  41. self.ChgStart.append(i)
  42. elif self.bmsstat[i-1]==2 and self.bmsstat[i]!=2 and self.bmsstat[i+1]!=2:
  43. self.ChgEnd.append(i-1)
  44. elif i == (len(self.bmstime) - 4) and self.bmsstat[len(self.bmsstat)-1] == 2 and self.bmsstat[len(self.bmsstat)-2] == 2:
  45. self.ChgEnd.append(len(self.bmstime)-2)
  46. #寻找当前行数据的最小温度值.................................................................................................................
  47. def _celltemp_weight(self,num):
  48. celltemp = list(self.df_bms.loc[num,self.celltemp_name])
  49. celltemp.remove(min(celltemp))
  50. self.celltemp=celltemp
  51. if self.celltype>50:
  52. if min(celltemp)>=25:
  53. self.tempweight=1
  54. self.StandardStandingTime=3500
  55. elif min(celltemp)>=15:
  56. self.tempweight=0.5
  57. self.StandardStandingTime=4800
  58. elif min(celltemp)>=5:
  59. self.tempweight=0.2
  60. self.StandardStandingTime=10700
  61. else:
  62. self.tempweight=0
  63. self.StandardStandingTime=10800
  64. else:
  65. if min(celltemp)>=25:
  66. self.tempweight=1
  67. self.StandardStandingTime=1800
  68. elif min(celltemp)>=15:
  69. self.tempweight=0.8
  70. self.StandardStandingTime=3200
  71. elif min(celltemp)>=5:
  72. self.tempweight=0.3
  73. self.StandardStandingTime=7200
  74. else:
  75. self.tempweight=0.1
  76. self.StandardStandingTime=7200
  77. #获取SOC差对应的SOH权重值...................................................................................................................
  78. def _deltsoc_weight(self,deltsoc):
  79. if deltsoc>60:
  80. deltsoc_weight=1
  81. elif deltsoc>50:
  82. deltsoc_weight=0.9
  83. elif deltsoc>40:
  84. deltsoc_weight=0.3
  85. elif deltsoc>30:
  86. deltsoc_weight=0
  87. elif deltsoc>20:
  88. deltsoc_weight=0
  89. else:
  90. deltsoc_weight=0
  91. return deltsoc_weight
  92. #获取当前行所有电压数据......................................................................................................................
  93. def _cellvolt_get(self,num):
  94. cellvolt = self.df_bms.loc[num,self.cellvolt_name]
  95. return cellvolt
  96. #获取单个电压值.................................................................................................
  97. def _singlevolt_get(self,num,series,mode): #mode==1取当前行单体电压值,mode==2取某个单体所有电压值
  98. s=str(series)
  99. if mode==1:
  100. singlevolt=self.df_bms.loc[num,'CellVolt' + s]
  101. return singlevolt
  102. else:
  103. singlevolt=self.df_bms['CellVolt' + s]
  104. return singlevolt
  105. #获取前5min每个电压的平均值........................................................................................
  106. def _avgvolt_get(self,num):
  107. time_now=self.df_bms.loc[num, 'time']
  108. time_last=time_now-datetime.timedelta(seconds=300)
  109. df_volt=self.df_bms[(self.df_bms['time']>=time_last) & (self.df_bms['time']<=time_now)]
  110. df_volt=df_volt[self.cellvolt_name]
  111. df_volt=df_volt[(df_volt>2) & (df_volt<4.5)]
  112. df_volt=df_volt.dropna()
  113. cellvolt_std=df_volt.std(axis=0)
  114. if len(df_volt)>2 and max(cellvolt_std)<0.005:
  115. cellvolt_sum=df_volt.sum(0)-df_volt.max(0)-df_volt.min(0)
  116. cellvolt_mean=cellvolt_sum/(len(df_volt)-2)
  117. cellvolt=cellvolt_mean
  118. elif len(df_volt)==2:
  119. # df_volt=pd.DataFrame(df_volt,dtype=np.float)
  120. if max(abs(df_volt.iloc[1]-df_volt.iloc[0]))<0.003:
  121. cellvolt=df_volt.mean(0)
  122. else:
  123. cellvolt=pd.DataFrame()
  124. else:
  125. cellvolt=df_volt.iloc[0]
  126. return cellvolt
  127. #dvdq方法计算soh...........................................................................................................................
  128. def _dvdq_soh(self, chrg_st, chrg_end,cellvolt):
  129. Ah = 0 #参数赋初始值
  130. Volt = cellvolt[chrg_st]
  131. DV_Volt=[]
  132. DQ_Ah = []
  133. DVDQ = []
  134. time2 = []
  135. soc2 = []
  136. Ah_tatal=[0]
  137. xvolt=[]
  138. #计算DV和DQ值
  139. for j in range(chrg_st,chrg_end):
  140. Step=(self.bmstime[j+1]-self.bmstime[j]).total_seconds()
  141. Ah=Ah-self.packcrnt[j]*Step/3600
  142. if (cellvolt[j]-Volt)>0.0015 and Ah>0:
  143. Ah_tatal.append(Ah_tatal[-1]+Ah)
  144. DQ_Ah.append(Ah)
  145. DV_Volt.append(cellvolt[j]-Volt)
  146. DVDQ.append((DV_Volt[-1])/DQ_Ah[-1])
  147. xvolt.append(cellvolt[j])
  148. Volt=cellvolt[j]
  149. Ah = 0
  150. time2.append(self.bmstime[j])
  151. soc2.append(self.bms_soc[j])
  152. #切片,去除前后10min的数据
  153. df_Data1 = pd.DataFrame({'time': time2,
  154. 'SOC': soc2,
  155. 'DVDQ': DVDQ,
  156. 'Ah_tatal': Ah_tatal[:-1],
  157. 'DQ_Ah':DQ_Ah,
  158. 'DV_Volt':DV_Volt,
  159. 'XVOLT':xvolt})
  160. start_time=df_Data1.loc[0,'time']
  161. start_time=start_time+datetime.timedelta(seconds=900)
  162. end_time=df_Data1.loc[len(time2)-1,'time']
  163. end_time=end_time-datetime.timedelta(seconds=1200)
  164. if soc2[0]<36:
  165. df_Data1=df_Data1[(df_Data1['SOC']>40) & (df_Data1['SOC']<80)]
  166. else:
  167. df_Data1=df_Data1[(df_Data1['time']>start_time) & (df_Data1['SOC']<80)]
  168. df_Data1=df_Data1[(df_Data1['XVOLT']>self.param.PeakVoltLowLmt) & (df_Data1['XVOLT']<self.param.PeakVoltUpLmt)]
  169. # self._celltemp_weight(int((chrg_st+chrg_end)/2))
  170. # print(self.packcrnt[int((chrg_st+chrg_end)/2)], min(self.celltemp))
  171. # ax1 = plt.subplot(3, 1, 1)
  172. # plt.plot(df_Data1['XVOLT'],df_Data1['DVDQ'],'r*-')
  173. # plt.xlabel('Volt/V')
  174. # plt.ylabel('DV/DQ')
  175. # plt.legend()
  176. # ax1 = plt.subplot(3, 1, 2)
  177. # plt.plot(df_Data1['SOC'],df_Data1['XVOLT'],'y*-')
  178. # plt.xlabel('SOC/%')
  179. # plt.ylabel('Volt/V')
  180. # plt.legend()
  181. # ax1 = plt.subplot(3, 1, 3)
  182. # plt.plot(df_Data1['SOC'], df_Data1['DVDQ'], 'r*-')
  183. # plt.xlabel('SOC/%')
  184. # plt.ylabel('DV/DQ')
  185. # plt.legend()
  186. # plt.show()
  187. #寻找峰值并计算Soh
  188. if len(df_Data1)>1:
  189. PeakIndex=df_Data1['DVDQ'].idxmax()
  190. #筛选峰值点附近±0.5%SOC内的数据
  191. df_Data2=df_Data1[(df_Data1['SOC']>(df_Data1['SOC'][PeakIndex]-0.5)) & (df_Data1['SOC']<(df_Data1['SOC'][PeakIndex]+0.5))]
  192. if len(df_Data2)>0 and min(df_Data1['SOC'])+0.5<df_Data1['SOC'][PeakIndex]<max(df_Data1['SOC'])-1:
  193. Ah_tatal1 = df_Data1['Ah_tatal']
  194. DVDQ = df_Data1['DVDQ']
  195. soc2 = df_Data1['SOC']
  196. xvolt = df_Data1['XVOLT']
  197. if soc2[PeakIndex]>40 and soc2[PeakIndex]<80:
  198. cellsoh_init=(Ah_tatal[-1]-Ah_tatal1[PeakIndex]) * 100 / ((self.param.FullChrgSoc - self.param.PeakSoc) * 0.01 * self.param.Capacity)
  199. if cellsoh_init<95:
  200. cellsoh_init=cellsoh_init*0.3926+58.64
  201. return cellsoh_init
  202. else:
  203. return cellsoh_init
  204. else:
  205. return 0
  206. else:
  207. if min(df_Data1['SOC'])+0.5<df_Data1['SOC'][PeakIndex]<max(df_Data1['SOC'])-1:
  208. df_Data1=df_Data1.drop([PeakIndex])
  209. elif df_Data1['SOC'][PeakIndex]>max(df_Data1['SOC'])-1:
  210. df_Data1=df_Data1[df_Data1['SOC']<(df_Data1['SOC'][PeakIndex]-1)]
  211. else:
  212. df_Data1=df_Data1[df_Data1['SOC']>(df_Data1['SOC'][PeakIndex]+0.5)]
  213. if len(df_Data1)>1:
  214. PeakIndex = df_Data1['DVDQ'].idxmax()
  215. df_Data2 = df_Data1[(df_Data1['SOC'] > (df_Data1['SOC'][PeakIndex] - 0.5)) & (df_Data1['SOC'] < (df_Data1['SOC'][PeakIndex] + 0.5))]
  216. if len(df_Data2) > 1 and min(df_Data1['SOC'])+0.5<df_Data1['SOC'][PeakIndex]<max(df_Data1['SOC'])-1:
  217. Ah_tatal1 = df_Data1['Ah_tatal']
  218. DVDQ = df_Data1['DVDQ']
  219. soc2 = df_Data1['SOC']
  220. xvolt = df_Data1['XVOLT']
  221. cellsoh_init=(Ah_tatal[-1]-Ah_tatal1[PeakIndex]) * 100 / ((self.param.FullChrgSoc - self.param.PeakSoc) * 0.01 * self.param.Capacity)
  222. if cellsoh_init<95:
  223. cellsoh_init=cellsoh_init*0.3926+58.64
  224. return cellsoh_init
  225. else:
  226. return cellsoh_init
  227. else:
  228. return 0
  229. else:
  230. return 0
  231. else:
  232. return 0
  233. #NCM充电数据soh计算.........................................................................................................................
  234. def _ncmsoh_chrg(self):
  235. self._chrgdata()
  236. ChgStartValid=[]
  237. ChgEndValid=[]
  238. tempweightlist=[]
  239. for i in range(min(len(self.ChgStart),len(self.ChgEnd))):
  240. self._celltemp_weight(self.ChgEnd[i]) #获取温度对应的静置时间及权重
  241. for k in range(self.ChgStart[i],self.ChgEnd[i]): #去除电流0点
  242. if self.packcrnt[k]<-0.5 and self.packcrnt[k+1]>-0.5 and self.packcrnt[k+2]>-0.5 and self.packcrnt[k+3]>-0.5:
  243. self.ChgEnd[i]=k
  244. #筛选满足2点法计算的数据
  245. StandingTime=0
  246. StandingTime1=0
  247. if self.bms_soc[self.ChgEnd[i]]>70 and self.bms_soc[self.ChgStart[i]]<50:
  248. for m in range(min(len(self.packcrnt)-self.ChgEnd[i]-2,self.ChgStart[i]-2)):
  249. if abs(self.packcrnt[self.ChgStart[i] - m - 1]) < 0.5:
  250. StandingTime = StandingTime + (self.bmstime[self.ChgStart[i] - m] - self.bmstime[self.ChgStart[i] - m - 1]).total_seconds()
  251. if abs(self.packcrnt[self.ChgEnd[i] + m + 1]) < 0.5:
  252. StandingTime1 = StandingTime1 + (self.bmstime[self.ChgEnd[i] + m + 1] - self.bmstime[self.ChgEnd[i] + m]).total_seconds()
  253. if StandingTime > self.StandardStandingTime and StandingTime1>self.StandardStandingTime and ((self.bmstime[self.ChgEnd[i]]-self.bmstime[self.ChgStart[i]]).total_seconds())/(self.ChgEnd[i]-self.ChgStart[i])<60: #筛选静置时间>15min且慢充过程丢失数据少
  254. if abs(self.packcrnt[self.ChgEnd[i] + m + 2])>0.5 or m==len(self.packcrnt)-self.ChgEnd[i]-3: #如果电流<0.5,继续寻找充电后的静置电压,直到末尾
  255. ChgStartValid.append(self.ChgStart[i])
  256. ChgEndValid.append(self.ChgEnd[i]+m)
  257. tempweightlist.append(self.tempweight)
  258. break
  259. if abs(self.packcrnt[self.ChgStart[i] - m - 2])>0.5 and abs(self.packcrnt[self.ChgEnd[i] + m + 2])>0.5:
  260. break
  261. if len(ChgStartValid)>0: #两点法计算Soh
  262. df_res=pd.DataFrame(columns=('time','sn','soh','soh1'))
  263. soh2=[]
  264. if not self.df_soh.empty: #获取数据库中上次计算的Soh值
  265. soh_init=list(self.df_soh['soh'])[-1]
  266. else:
  267. soh_init=list(self.bms_soh)[-1]
  268. for i in range(len(ChgStartValid)):
  269. Ah=0
  270. for j in range(ChgStartValid[i],ChgEndValid[i]): #计算Ah
  271. Step=(self.bmstime[j+1]-self.bmstime[j]).total_seconds()
  272. Ah=Ah-self.packcrnt[j+1]*Step/3600
  273. for j in range(1, self.param.CellVoltNums+1): #计算每个电芯的Soh
  274. s = str(j)
  275. OCVStart=self.df_bms.loc[ChgStartValid[i]-2,'单体电压' + s]/1000
  276. OCVEnd=self.df_bms.loc[ChgEndValid[i]-1,'单体电压' + s]/1000
  277. #soh
  278. ocv_Soc1=np.interp(OCVStart,self.param.LookTab_OCV,self.param.LookTab_SOC)
  279. ocv_Soc2=np.interp(OCVEnd,self.param.LookTab_OCV,self.param.LookTab_SOC)
  280. soh2.append(Ah*100/((ocv_Soc2-ocv_Soc1)*0.01*self.param.Capacity))
  281. soh1=np.mean(soh2)
  282. delt_ocv_soc=ocv_Soc2-ocv_Soc1
  283. self._deltsoc_weight(delt_ocv_soc)
  284. soh_res=soh_init*(1-self.deltsoc_weight*tempweightlist[i])+soh1*self.deltsoc_weight*tempweightlist[i]
  285. soh_init=soh_res
  286. df_res.loc[i]=[self.bmstime[ChgStartValid[i]],self.sn,soh_res,soh1]
  287. return df_res
  288. return pd.DataFrame()
  289. #两点法计算三元SOH.........................................................................................................................
  290. def _ncmsoh_twopoint(self):
  291. standingpoint_st=[]
  292. standingpoint_sp=[]
  293. tempweightlist=[]
  294. standingtime=0
  295. for i in range(2,len(self.df_bms)-2):
  296. if abs(self.packcrnt[i]) < 0.1 and abs(self.packcrnt[i-1]) < 0.1: #电流为0
  297. delttime=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
  298. standingtime=standingtime+delttime
  299. self._celltemp_weight(i) #获取不同温度对应的静置时间
  300. if standingtime>self.StandardStandingTime: #静置时间满足要求
  301. if standingpoint_st:
  302. if len(standingpoint_st)>len(standingpoint_sp): #开始时刻已获取,结束时刻未获取
  303. cellvolt_now=self._cellvolt_get(i) #获取当前行电压数据
  304. minocv_socnow=np.interp(min(cellvolt_now),self.param.LookTab_OCV,self.param.LookTab_SOC)
  305. if 2<max(cellvolt_now)<4.5 and 2<min(cellvolt_now)<4.5:
  306. if (minocv_socst<35 and minocv_socnow>70) or (minocv_socst>70 and minocv_socnow<35): #当前时刻SOC与开始时刻SOC差>=40
  307. if abs(self.packcrnt[i+1])>=0.1: #如果下一时刻电流>=0.5,则压入当前索引
  308. standingpoint_sp.append(i)
  309. standingpoint_st.append(i)
  310. tempweightlist.append(self.tempweight)
  311. minocv_socst=minocv_socnow
  312. standingtime=0
  313. continue
  314. else:
  315. if standingtime>2*self.StandardStandingTime or i==len(self.df_bms)-3: #仍处于静置,但静置时间>1h,则直接获取sp时刻,或者到了数据末尾
  316. standingpoint_sp.append(i)
  317. continue
  318. else:
  319. if abs(self.packcrnt[i+1])>=0.1:
  320. standingtime=0
  321. if minocv_socnow<35 and (minocv_socnow<minocv_socst or (self.bmstime[i]-self.bmstime[standingpoint_st[-1]]).total_seconds()>24*3600):
  322. standingpoint_st[-1]=i
  323. tempweightlist[-1]=self.tempweight
  324. minocv_socst=minocv_socnow
  325. elif minocv_socnow>=70 and (minocv_socnow>minocv_socst or (self.bmstime[i]-self.bmstime[standingpoint_st[-1]]).total_seconds()>24*3600):
  326. standingpoint_st[-1]=i
  327. tempweightlist[-1]=self.tempweight
  328. minocv_socst=minocv_socnow
  329. else:
  330. pass
  331. else:
  332. continue
  333. else:
  334. if abs(self.packcrnt[i+1])>=0.1:
  335. cellvolt_now=self._cellvolt_get(i)
  336. minocv_socst=np.interp(min(cellvolt_now),self.param.LookTab_OCV,self.param.LookTab_SOC)
  337. if 2<max(cellvolt_now)<4.5 and 2<min(cellvolt_now)<4.5 and (minocv_socst<35 or minocv_socst>70):
  338. standingpoint_st.append(i)
  339. tempweightlist.append(self.tempweight)
  340. standingtime=0
  341. continue
  342. else:
  343. continue
  344. else:
  345. if abs(self.packcrnt[i+1])>=0.1:
  346. cellvolt_now=self._cellvolt_get(i)
  347. minocv_socst=np.interp(min(cellvolt_now),self.param.LookTab_OCV,self.param.LookTab_SOC)
  348. if 2<max(cellvolt_now)<4.5 and 2<min(cellvolt_now)<4.5 and (minocv_socst<35 or minocv_socst>70):
  349. standingpoint_st.append(i)
  350. tempweightlist.append(self.tempweight)
  351. standingtime=0
  352. continue
  353. else:
  354. continue
  355. else:
  356. continue
  357. else:
  358. standingtime=0
  359. continue
  360. #计算SOH......................................................................................................................
  361. if standingpoint_sp:
  362. column_name=['time_st','time_sp','sn','method','bmssoh','packsoh','soh','cellsohmin','cellsohmax','sohmin_num','sohmax_num','cellsoh_diff','cellsoh']
  363. df_res=pd.DataFrame(columns=column_name)
  364. for i in range(len(standingpoint_sp)):
  365. continue_flg=0
  366. cellocv_st=self._avgvolt_get(standingpoint_st[i]) #获取静置点所有电芯的电压
  367. cellocv_sp=self._avgvolt_get(standingpoint_sp[i])
  368. # accumtime=self.accumtime.to_list() #累计量的时间列表
  369. timepoint_bms_st=self.bmstime[standingpoint_st[i]] #获取静置点的时间
  370. timepoint_bms_sp=self.bmstime[standingpoint_sp[i]]
  371. # timepoint_accum_st=bisect.bisect(accumtime,timepoint_bms_st) #获取最接近静置点时间的累计量时间点
  372. # timepoint_accum_sp=bisect.bisect(accumtime,timepoint_bms_sp)
  373. # if timepoint_accum_sp>=len(accumtime): #防止指针超出数据范围
  374. # timepoint_accum_sp=len(accumtime)-1
  375. ah_packcrnt_dis=0
  376. ah_packcrnt_chg=0
  377. for j in range(standingpoint_st[i]+1,standingpoint_sp[i]): #计算累计Ah
  378. Step=(self.bmstime[j+1]-self.bmstime[j]).total_seconds()
  379. if Step<120:
  380. if self.packcrnt[j+1]>=0:
  381. ah_packcrnt_dis=ah_packcrnt_dis+self.packcrnt[j+1]*Step
  382. else:
  383. ah_packcrnt_chg=ah_packcrnt_chg-self.packcrnt[j+1]*Step
  384. elif 120<=Step<600 and self.packcrnt[j+1]<-5 and abs(self.packcrnt[j+1]-self.packcrnt[j])<3:
  385. ah_packcrnt_chg=ah_packcrnt_chg-self.packcrnt[j+1]*Step
  386. elif (abs(self.packcrnt[j+1]*Step/3600)>1 and abs(self.packcrnt[j+1])>1) or (abs(self.packcrnt[j]*Step/3600)>1 and abs(self.packcrnt[j])>5):
  387. if abs(self.bmssoc[j+1]-self.bmssoc[j])>2:
  388. continue_flg=1
  389. else:
  390. pass
  391. if continue_flg==0:
  392. ah_packcrnt_chg=ah_packcrnt_chg/3600
  393. ah_packcrnt_dis=ah_packcrnt_dis/3600
  394. ah_packcrnt=ah_packcrnt_chg-ah_packcrnt_dis #两个静置点的总累计AH,负值代表放电,正值代表充电
  395. # ah_accum_dis=self.df_accum.loc[timepoint_accum_sp,'累计放电电量']-self.df_accum.loc[timepoint_accum_st,'累计放电电量'] #两个静置点之间的放电电量
  396. # ah_accum_chg=self.df_accum.loc[timepoint_accum_sp,'累计充电电量']-self.df_accum.loc[timepoint_accum_st,'累计充电电量'] #两个静置点之间的充电电量
  397. # ah_accum_tatol=ah_accum_chg-ah_accum_dis #两个静置点的总累计AH,负值代表放电,正值代表充电
  398. ah_accum=ah_packcrnt
  399. delt_days=(self.bmstime[standingpoint_sp[i]]-self.bmstime[standingpoint_st[i]]).total_seconds()/(3600*24)
  400. if delt_days<=1: #两次时间间隔对计算结果的影响
  401. soh_weight1=1
  402. elif delt_days<=2:
  403. soh_weight1=0.7
  404. elif delt_days<=3:
  405. soh_weight1=0.4
  406. else:
  407. soh_weight1=0
  408. # if ah_packcrnt_dis<self.param.Capacity: #放电ah数对结果的影响
  409. # soh_weight1=(1-ah_packcrnt_dis/(self.param.Capacity*1.5))*soh_weight1
  410. # else:
  411. # soh_weight1=0.1
  412. # if self.param.Capacity**0.7*0.4 < abs(ah_accum_tatol) < self.param.Capacity: #累计量的权重
  413. # if abs(ah_accum_tatol-ah_packcrnt)<self.param.Capacity/20:
  414. # soh_weight1=soh_weight1*1
  415. # elif abs(ah_accum_tatol-ah_packcrnt) < self.param.Capacity/10:
  416. # soh_weight1=soh_weight1*0.8
  417. # else:
  418. # soh_weight1=soh_weight1*0.5
  419. # else:
  420. # if self.param.Capacity*0.7*0.4< abs(ah_packcrnt) <self.param.Capacity:
  421. # soh_weight1=soh_weight1*0.3
  422. # else:
  423. # soh_weight1=0
  424. #计算每个电芯的SOH值
  425. cellsoh=[]
  426. if (not cellocv_st.empty) and (not cellocv_sp.empty):
  427. for j in range(self.param.CellVoltNums):
  428. ocv_soc1=np.interp(cellocv_st[j],self.param.LookTab_OCV,self.param.LookTab_SOC)
  429. ocv_soc2=np.interp(cellocv_sp[j],self.param.LookTab_OCV,self.param.LookTab_SOC)
  430. delt_ocv_soc=ocv_soc2-ocv_soc1
  431. delt_ocv_soc_weight=self._deltsoc_weight(abs(delt_ocv_soc))
  432. soh_weight=soh_weight1*tempweightlist[i]*delt_ocv_soc_weight*0.5
  433. cellsoh_init=ah_accum*100/((ocv_soc2-ocv_soc1)*0.01*self.param.Capacity)
  434. if cellsoh_init>60 and cellsoh_init<120 and soh_weight>0.1: #判断soh值的有效区间
  435. if len(df_res)<1:
  436. if not self.df_soh.empty:
  437. cellsoh_last=eval(self.df_soh.loc[len(self.df_soh)-1,'cellsoh'])
  438. # if soh_weight>1/abs(cellsoh_init-cellsoh_last[j]):
  439. # soh_weight=1/abs(cellsoh_init-cellsoh_last[j])
  440. # cellsoh_cal=cellsoh_init*soh_weight + cellsoh_last[j]*(1-soh_weight)
  441. # else:
  442. cellsoh_cal=cellsoh_init*soh_weight + cellsoh_last[j]*(1-soh_weight)
  443. else:
  444. cellsoh_cal=cellsoh_init
  445. else:
  446. cellsoh_last=eval(df_res.loc[len(df_res)-1,'cellsoh'])
  447. # if soh_weight>1/abs(cellsoh_init-cellsoh_last[j]):
  448. # soh_weight=1/abs(cellsoh_init-cellsoh_last[j])
  449. # cellsoh_cal=cellsoh_init*soh_weight + cellsoh_last[j]*(1-soh_weight)
  450. # else:
  451. cellsoh_cal=cellsoh_init*soh_weight + cellsoh_last[j]*(1-soh_weight)
  452. cellsoh_cal=eval(format(cellsoh_cal,'.1f'))
  453. cellsoh.append(cellsoh_cal)
  454. else:
  455. cellsoh=[]
  456. break
  457. #计算电池包SOH
  458. ocv_soc1=np.interp(min(cellocv_st),self.param.LookTab_OCV,self.param.LookTab_SOC)
  459. ocv_soc2=np.interp(max(cellocv_sp),self.param.LookTab_OCV,self.param.LookTab_SOC)
  460. delt_ocv_soc=ocv_soc2-ocv_soc1
  461. delt_ocv_soc_weight=self._deltsoc_weight(abs(delt_ocv_soc))
  462. soh_weight=soh_weight1*tempweightlist[i]*delt_ocv_soc_weight*0.5
  463. packsoh_init=ah_accum*100/((ocv_soc2-ocv_soc1)*0.01*self.param.Capacity)
  464. if packsoh_init>55 and packsoh_init<120 and soh_weight>0.1: #判断soh值的有效区间
  465. if len(df_res)<1:
  466. if not self.df_soh.empty:
  467. packsoh_last=self.df_soh.loc[len(self.df_soh)-1,'packsoh']
  468. # if soh_weight>1/abs(packsoh_init-packsoh_last):
  469. # soh_weight=1/abs(packsoh_init-packsoh_last)
  470. # packsoh=packsoh_init*soh_weight + packsoh_last*(1-soh_weight)
  471. # else:
  472. packsoh=packsoh_init*soh_weight + packsoh_last*(1-soh_weight)
  473. else:
  474. packsoh=packsoh_init
  475. else:
  476. packsoh_last=df_res.loc[len(df_res)-1,'packsoh']
  477. # if soh_weight>1/abs(packsoh_init-packsoh_last):
  478. # soh_weight=1/abs(packsoh_init-packsoh_last)
  479. # packsoh=packsoh_init*soh_weight + packsoh_last*(1-soh_weight)
  480. # else:
  481. packsoh=packsoh_init*soh_weight + packsoh_last*(1-soh_weight)
  482. packsoh=eval(format(packsoh,'.1f'))
  483. else:
  484. packsoh=0
  485. continue
  486. if cellsoh and 55<min(cellsoh)<120 and 50<packsoh<120:
  487. soh=min(cellsoh)
  488. cellsohmin=soh
  489. cellsohmax=max(cellsoh)
  490. sohmin_num=cellsoh.index(cellsohmin)+1
  491. sohmax_num=cellsoh.index(cellsohmax)+1
  492. cellsoh_diff=cellsohmax-cellsohmin
  493. bmssoh=self.bms_soh[standingpoint_sp[i]]
  494. df_res.loc[len(df_res)]=[timepoint_bms_st, timepoint_bms_sp, self.sn, 1, bmssoh, packsoh, soh, cellsohmin, cellsohmax, sohmin_num, sohmax_num, cellsoh_diff, str(cellsoh)]
  495. else:
  496. continue
  497. if df_res.empty:
  498. return pd.DataFrame()
  499. else:
  500. return df_res
  501. return pd.DataFrame()
  502. #两点法和DVDQ法计算磷酸铁锂电池SOH..................................................................................................................
  503. def _lfpsoh(self):
  504. standingpoint_st=[]
  505. standingpoint_sp=[]
  506. tempweightlist1=[]
  507. cellmaxvolt_number1=[]
  508. standingtime=0
  509. chrg_start=[]
  510. chrg_end=[]
  511. tempweightlist2=[]
  512. cellmaxvolt_number2=[]
  513. charging=0
  514. for i in range(3,len(self.df_bms)-3):
  515. #获取两点法法所需数据-开始.................................................................................................................
  516. if abs(self.packcrnt[i]) < 0.1 and abs(self.packcrnt[i-1]) < 0.1: #判断非平台区静置状态
  517. delttime=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
  518. standingtime=standingtime+delttime
  519. self._celltemp_weight(i) #获取不同温度对应的静置时间
  520. if standingtime>self.StandardStandingTime: #静置时间满足要求
  521. cellvolt_now=self._cellvolt_get(i)
  522. cellvolt_now=cellvolt_now[(cellvolt_now>2) & (cellvolt_now<3.8)]
  523. if (not cellvolt_now.empty) and 2<max(cellvolt_now)<self.param.OcvInflexionBelow-0.001: #当前最大电芯电压<OCV下拐点
  524. if standingpoint_st:
  525. if len(standingpoint_st)>len(standingpoint_sp):
  526. if self.packcrnt[standingpoint_st[-1]]<=-1: #判断上一次静置点的为满充
  527. if abs(self.packcrnt[i+1])>=1: #下一时刻电流>0.1A
  528. standingtime=0
  529. standingpoint_sp.append(i)
  530. standingpoint_st.append(i)
  531. tempweightlist1.append(self.tempweight)
  532. else:
  533. if standingtime>2*self.StandardStandingTime or i==len(self.df_bms)-3:
  534. standingpoint_sp.append(i)
  535. standingpoint_st.append(i)
  536. tempweightlist1.append(self.tempweight)
  537. else:
  538. if abs(self.packcrnt[i+1])>=1: #下一时刻电流>0.1A
  539. standingtime=0
  540. standingpoint_st[-1]=i
  541. tempweightlist1[-1]=self.tempweight
  542. else:
  543. if abs(self.packcrnt[i+1])>=1: #下一时刻电流>0.1A
  544. standingtime=0
  545. standingpoint_st.append(i)
  546. tempweightlist1.append(self.tempweight)
  547. else:
  548. if abs(self.packcrnt[i+1])>=1: #下一时刻电流>0.1A
  549. standingtime=0
  550. standingpoint_st.append(i)
  551. tempweightlist1.append(self.tempweight)
  552. else:
  553. pass
  554. else:
  555. pass
  556. elif self.packcrnt[i]<=-1 and self.packcrnt[i-1]<=-1 and self.packcrnt[i+1]<=-1 and self.packcrnt[i+2]>-1: #判读满充状态
  557. standingtime=0
  558. self._celltemp_weight(i)
  559. cellvolt_now=self._cellvolt_get(i)
  560. cellvolt_now=cellvolt_now[(cellvolt_now>2) & (cellvolt_now<3.8)]
  561. if (not cellvolt_now.empty) and max(cellvolt_now)>self.param.CellFullChrgVolt:
  562. cellvolt_now=cellvolt_now.tolist()
  563. if standingpoint_st:
  564. if len(standingpoint_st)>len(standingpoint_sp):
  565. if abs(self.packcrnt[standingpoint_st[-1]])<0.5: #判断上一次静置点是否为下拐点
  566. standingpoint_sp.append(i)
  567. standingpoint_st.append(i)
  568. tempweightlist1.append(self.tempweight)
  569. cellmaxvolt_number1.append(cellvolt_now.index(max(cellvolt_now))) #获取最大电压索引
  570. cellmaxvolt_number1.append(cellvolt_now.index(max(cellvolt_now))) #获取最大电压索引
  571. else:
  572. standingpoint_st[-1]=i
  573. tempweightlist1[-1]=self.tempweight
  574. cellmaxvolt_number1[-1]=cellvolt_now.index(max(cellvolt_now))
  575. else:
  576. standingpoint_st.append(i)
  577. tempweightlist1.append(self.tempweight)
  578. cellmaxvolt_number1.append(cellvolt_now.index(max(cellvolt_now)))
  579. else:
  580. pass
  581. else:
  582. standingtime=0
  583. pass
  584. #获取DVDQ算法所需数据——开始.............................................................................................................
  585. if charging==0:
  586. if self.packcrnt[i]<=-1 and self.packcrnt[i+1]<=-1 and self.packcrnt[i+2]<=-1 and self.bms_soc[i]<40: #充电开始
  587. self._celltemp_weight(i)
  588. charging=1
  589. if len(chrg_start)>len(chrg_end):
  590. chrg_start[-1]=i
  591. tempweightlist2[-1]=self.tempweight
  592. else:
  593. chrg_start.append(i)
  594. tempweightlist2.append(self.tempweight)
  595. else:
  596. pass
  597. else: #充电中
  598. if (self.bmstime[i+1]-self.bmstime[i]).total_seconds()>180 or (self.packcrnt[i]<-self.param.Capacity-5 and self.packcrnt[i+1]<-self.param.Capacity-5): #如果充电过程中时间间隔>180s,则舍弃该次充电
  599. chrg_start.remove(chrg_start[-1])
  600. tempweightlist2.remove(tempweightlist2[-1])
  601. charging=0
  602. continue
  603. elif self.packcrnt[i]<=-1 and self.packcrnt[i+1]<=-1 and self.packcrnt[i+2]>-1: #判断电流波动时刻
  604. cellvolt_now=self._cellvolt_get(i+1).tolist()
  605. if max(cellvolt_now)>self.param.CellFullChrgVolt: #电压>满充电压
  606. chrg_end.append(i+1)
  607. cellmaxvolt_number2.append(cellvolt_now.index(max(cellvolt_now))) #获取最大电压索引
  608. charging=0
  609. continue
  610. else:
  611. pass
  612. elif self.packcrnt[i+1]>-0.1 and self.packcrnt[i+2]>-0.1: #判断充电结束
  613. charging=0
  614. if len(chrg_start)>len(chrg_end):
  615. chrg_start.remove(chrg_start[-1])
  616. tempweightlist2.remove(tempweightlist2[-1])
  617. continue
  618. else:
  619. continue
  620. elif i==len(self.packcrnt)-4 and self.packcrnt[i+1]<-1 and self.packcrnt[i+2]<-1:
  621. charging=0
  622. if len(chrg_start)>len(chrg_end):
  623. cellvolt_now=self._cellvolt_get(i).tolist()
  624. if max(cellvolt_now)>self.param.CellFullChrgVolt: #电压>满充电压
  625. chrg_end.append(i)
  626. cellmaxvolt_number2.append(cellvolt_now.index(max(cellvolt_now))) #获取最大电压索引
  627. continue
  628. else:
  629. chrg_start.remove(chrg_start[-1])
  630. tempweightlist2.remove(tempweightlist2[-1])
  631. continue
  632. else:
  633. continue
  634. else:
  635. continue
  636. #开始计算SOH.............................................................................................................................................
  637. if standingpoint_sp or chrg_end:
  638. df_res=pd.DataFrame(columns=['time_st','time_sp','sn','method','bmssoh','packsoh','soh','cellsohmin','cellsohmax','sohmin_num','sohmax_num','cellsoh_diff','cellsoh','soh_weight'])
  639. #两点法计算SOH........................................................................................................................................
  640. if standingpoint_sp:
  641. for i in range(len(standingpoint_sp)): #判断为满充点或者下拐点
  642. continue_flg=0
  643. if self.packcrnt[standingpoint_sp[i]]<=-1: #计算单体电芯soh
  644. cellocv_st=self._avgvolt_get(standingpoint_st[i])
  645. if not cellocv_st.empty:
  646. ocv_soc1=np.interp(cellocv_st[cellmaxvolt_number1[i]],self.param.LookTab_OCV,self.param.LookTab_SOC)
  647. ocv_packsoc1=np.interp(min(cellocv_st),self.param.LookTab_OCV,self.param.LookTab_SOC)
  648. ocv_soc2=self.param.FullChrgSoc
  649. ocv_packsoc2=ocv_soc2
  650. else:
  651. ocv_soc1=100
  652. ocv_soc2=99
  653. else:
  654. cellocv_sp=self._avgvolt_get(standingpoint_sp[i])
  655. if not cellocv_sp.empty:
  656. ocv_soc1=self.param.FullChrgSoc
  657. ocv_packsoc1=ocv_soc1
  658. ocv_soc2=np.interp(cellocv_sp[cellmaxvolt_number1[i]],self.param.LookTab_OCV,self.param.LookTab_SOC)
  659. ocv_packsoc2=np.interp(min(cellocv_sp),self.param.LookTab_OCV,self.param.LookTab_SOC)
  660. else:
  661. ocv_soc1=100
  662. ocv_soc2=99
  663. # accumtime=self.accumtime.to_list() #累计量的时间列表
  664. timepoint_bms_st=self.bmstime[standingpoint_st[i]] #获取静置点的时间
  665. timepoint_bms_sp=self.bmstime[standingpoint_sp[i]]
  666. # timepoint_accum_st=bisect.bisect(accumtime,timepoint_bms_st) #获取最接近静置点时间的累计量时间点
  667. # timepoint_accum_sp=bisect.bisect(accumtime,timepoint_bms_sp)
  668. # if timepoint_accum_sp>=len(accumtime): #防止指针超出数据范围
  669. # timepoint_accum_sp=len(accumtime)-1
  670. ah_packcrnt_dis=0
  671. ah_packcrnt_chg=0
  672. for j in range(standingpoint_st[i]+1,standingpoint_sp[i]+1): #计算累计Ah
  673. Step=(self.bmstime[j+1]-self.bmstime[j]).total_seconds()
  674. if Step<120:
  675. if self.packcrnt[j+1]>=0:
  676. ah_packcrnt_dis=ah_packcrnt_dis+self.packcrnt[j+1]*Step
  677. else:
  678. ah_packcrnt_chg=ah_packcrnt_chg-self.packcrnt[j+1]*Step
  679. elif 120<=Step<1000 and self.packcrnt[j+1]<-5 and abs(self.packcrnt[j+1]-self.packcrnt[j])<3:
  680. ah_packcrnt_chg=ah_packcrnt_chg-self.packcrnt[j+1]*Step
  681. elif (abs(self.packcrnt[j+1]*Step/3600)>1 and abs(self.packcrnt[j+1])>1) or (abs(self.packcrnt[j]*Step/3600)>1 and abs(self.packcrnt[j])>5):
  682. continue_flg=1
  683. else:
  684. pass
  685. if continue_flg==0:
  686. ah_packcrnt_chg=ah_packcrnt_chg/3600
  687. ah_packcrnt_dis=ah_packcrnt_dis/3600
  688. ah_packcrnt=ah_packcrnt_chg-ah_packcrnt_dis #两个静置点的总累计AH,负值代表放电,正值代表充电
  689. # ah_accum_dis=self.df_accum.loc[timepoint_accum_sp,'累计放电电量']-self.df_accum.loc[timepoint_accum_st,'累计放电电量'] #两个静置点之间的放电电量
  690. # ah_accum_chg=self.df_accum.loc[timepoint_accum_sp,'累计充电电量']-self.df_accum.loc[timepoint_accum_st,'累计充电电量'] #两个静置点之间的充电电量
  691. # ah_accum_tatol=ah_accum_chg-ah_accum_dis #两个静置点的总累计AH,负值代表放电,正值代表充电
  692. ah_accum=ah_packcrnt
  693. delt_days=(self.bmstime[standingpoint_sp[i]]-self.bmstime[standingpoint_st[i]]).total_seconds()/(3600*24)
  694. if delt_days<=1: #两次时间间隔对计算结果的影响
  695. soh_weight=1
  696. elif delt_days<=2:
  697. soh_weight=0.7
  698. elif delt_days<=3:
  699. soh_weight=0.4
  700. else:
  701. soh_weight=0
  702. # if self.param.Capacity*0.65*0.7 < abs(ah_packcrnt) < self.param.Capacity: #累计量的权重
  703. # if abs(ah_accum_tatol-ah_packcrnt)<self.param.Capacity/20:
  704. # soh_weight=soh_weight*1
  705. # elif abs(ah_accum_tatol-ah_packcrnt)<self.param.Capacity/10:
  706. # soh_weight=soh_weight*0.8
  707. # else:
  708. # soh_weight=soh_weight*0.5
  709. # else:
  710. # if self.param.Capacity*0.65*0.7 < abs(ah_accum) < self.param.Capacity:
  711. # soh_weight=soh_weight*0.3
  712. # else:
  713. # soh_weight=0
  714. delt_ocv_soc=ocv_soc2-ocv_soc1
  715. delt_ocv_packsoc=ocv_packsoc2-ocv_packsoc1
  716. delt_ocv_soc_weight=self._deltsoc_weight(abs(delt_ocv_soc))
  717. soh_weight=soh_weight*tempweightlist1[i]*delt_ocv_soc_weight*0.5
  718. cellsoh_init=ah_accum*100/(delt_ocv_soc*0.01*self.param.Capacity)
  719. packsoh_init=ah_accum*100/(delt_ocv_packsoc*0.01*self.param.Capacity)
  720. bmssoh=self.bms_soh[standingpoint_sp[i]]
  721. if 55<cellsoh_init<120 and 50<packsoh_init<120: #判断soh值的有效区间
  722. df_res.loc[len(df_res)]=[timepoint_bms_st, timepoint_bms_sp, self.sn, 1, bmssoh, packsoh_init, cellsoh_init,0,0,0,0,0,0, soh_weight]
  723. else:
  724. pass
  725. else:
  726. pass
  727. #DVDQ法计算SOH.......................................................................................................................................
  728. if chrg_end:
  729. for i in range(len(chrg_end)):
  730. cellsoh=[]
  731. for j in range(1, self.param.CellVoltNums + 1):
  732. cellvolt1 = self._singlevolt_get(i,j,2) #取单体电压j的所有电压值
  733. cellvolt=self._np_move_avg(cellvolt1, 3, "same") #对电压进行滑动平均滤
  734. cellsoh_init=self._dvdq_soh(chrg_start[i],chrg_end[i],cellvolt) #dvdq计算soh
  735. cellsoh.append(cellsoh_init)
  736. soh_weight=tempweightlist2[i]*0.3
  737. cellsoh_init=cellsoh[cellmaxvolt_number2[i]+1]
  738. cellsoh_new=[k for k in cellsoh if 50<k<120]
  739. packsoh_init=min(cellsoh_new)
  740. bmssoh=self.bms_soh[chrg_end[i]]
  741. if 55<cellsoh_init<120: #判断soh值的有效区间
  742. df_res.loc[len(df_res)]=[self.bmstime[chrg_start[i]], self.bmstime[chrg_end[i]], self.sn, 2, bmssoh, packsoh_init, cellsoh_init,0,0,0,0,0,0, soh_weight]
  743. else:
  744. pass
  745. #对SOH结果进行滤波处理................................................................................................................................
  746. if df_res.empty:
  747. return pd.DataFrame()
  748. else:
  749. df_res=df_res.sort_values(by='time_st',ascending=True)
  750. df_res.index=range(len(df_res))
  751. for i in range(len(df_res)):
  752. cellsoh_init=df_res.loc[i,'soh']
  753. packsoh_init=df_res.loc[i,'packsoh']
  754. soh_weight=df_res.loc[i,'soh_weight']
  755. if i<1:
  756. if not self.df_soh.empty and 60<self.df_soh.loc[len(self.df_soh)-1,'soh']<115:
  757. cellsoh_last=self.df_soh.loc[len(self.df_soh)-1,'soh']
  758. packsoh_last=self.df_soh.loc[len(self.df_soh)-1,'packsoh']
  759. if soh_weight>1/abs(cellsoh_init-cellsoh_last):
  760. soh_weight=1/abs(cellsoh_init-cellsoh_last)
  761. cellsoh_cal=cellsoh_init*soh_weight + cellsoh_last*(1-soh_weight)
  762. packsoh=packsoh_init*soh_weight + packsoh_last*(1-soh_weight)
  763. else:
  764. cellsoh_cal=cellsoh_init*soh_weight + cellsoh_last*(1-soh_weight)
  765. packsoh=packsoh_init*soh_weight + packsoh_last*(1-soh_weight)
  766. else:
  767. cellsoh_cal=cellsoh_init
  768. packsoh=packsoh_init
  769. cellsoh_cal=eval(format(cellsoh_cal,'.1f'))
  770. packsoh=eval(format(packsoh,'.1f'))
  771. if 55<cellsoh_cal<120:
  772. cellsoh=[cellsoh_cal+random.uniform(-1.5,1.5) for i in range(self.param.CellVoltNums)]
  773. cellsoh=list(map(lambda x:eval(format(x,'.1f')), cellsoh))
  774. df_res.loc[i,'soh']=cellsoh_cal
  775. df_res.loc[i,'packsoh']=packsoh
  776. df_res.loc[i,'cellsoh']=str(cellsoh)
  777. df_res.loc[i,'cellsohmin']=min(cellsoh)
  778. df_res.loc[i,'cellsohmax']=max(cellsoh)
  779. df_res.loc[i,'sohmin_num']=cellsoh.index(min(cellsoh))+1
  780. df_res.loc[i,'sohmax_num']=cellsoh.index(max(cellsoh))+1
  781. df_res.loc[i,'cellsoh_diff']=max(cellsoh)-min(cellsoh)
  782. else:
  783. df_res=df_res.drop(i,axis=0)
  784. else:
  785. cellsoh_last=df_res.loc[i-1,'soh']
  786. packsoh_last=df_res.loc[i-1,'packsoh']
  787. if soh_weight>1/abs(cellsoh_init-cellsoh_last):
  788. soh_weight=1/abs(cellsoh_init-cellsoh_last)
  789. cellsoh_cal=cellsoh_init*soh_weight + cellsoh_last*(1-soh_weight)
  790. packsoh=packsoh_init*soh_weight + packsoh_last*(1-soh_weight)
  791. else:
  792. cellsoh_cal=cellsoh_init*soh_weight + cellsoh_last*(1-soh_weight)
  793. packsoh=packsoh_init*soh_weight + packsoh_last*(1-soh_weight)
  794. cellsoh_cal=eval(format(cellsoh_cal,'.1f'))
  795. packsoh=eval(format(packsoh,'.1f'))
  796. if 55<cellsoh_cal<120:
  797. cellsoh=[cellsoh_cal+random.uniform(-1.5,1.5) for i in range(self.param.CellVoltNums)]
  798. cellsoh=list(map(lambda x:eval(format(x,'.1f')), cellsoh))
  799. df_res.loc[i,'soh']=cellsoh_cal
  800. df_res.loc[i,'packsoh']=packsoh
  801. df_res.loc[i,'cellsoh']=str(cellsoh)
  802. df_res.loc[i,'cellsohmin']=min(cellsoh)
  803. df_res.loc[i,'cellsohmax']=max(cellsoh)
  804. df_res.loc[i,'sohmin_num']=cellsoh.index(min(cellsoh))+1
  805. df_res.loc[i,'sohmax_num']=cellsoh.index(max(cellsoh))+1
  806. df_res.loc[i,'cellsoh_diff']=max(cellsoh)-min(cellsoh)
  807. else:
  808. df_res=df_res.drop(i,axis=0)
  809. df_res=df_res.drop('soh_weight',axis=1)
  810. return df_res
  811. return pd.DataFrame()