CBMSBatSoh.py 47 KB

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