# 获取数据 from LIB.BACKEND import DBManager import os import pandas as pd import numpy as np import datetime # import matplotlib.pyplot as plt #参数输入 Capacity = 54 PackFullChrgVolt=69.99 CellFullChrgVolt=3.5 CellVoltNums=20 CellTempNums=4 FullChrgSoc=98 PeakSoc=57 # #40Ah-OCV # LookTab_SOC = [0, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100] # 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, # 3.8031, 3.8440, 3.8888, 3.9376, 3.9891, 4.0451, 4.1068, 4.1830] #55Ah-OCV 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] 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] #定义滑动滤波函数 def np_move_avg(a, n, mode="same"): return (np.convolve(a, np.ones((n,)) / n, mode=mode)) #参数初始化 dvdq_soh=[] dvdq_soh_err=[] bms_soh=[] dvdq_time=[] dvdq_sohcfd=[] sn_list=[] #输入一个含有‘SN号’的xlsx def cal_soh(sn, end_time, start_time): #获取数据时间段 end_time = end_time strat_time = start_time SNnum=str(sn) sn = SNnum st = start_time et = end_time dbManager = DBManager.DBManager() df_data = dbManager.get_data(sn=sn, start_time=st, end_time=et, data_groups=['bms']) data = df_data['bms'] packcrnt=data['总电流[A]'] packvolt=data['总电压[V]'] SOC=data['SOC[%]'] SOH=data['SOH[%]'] bmsstat=data['充电状态'] time= pd.to_datetime(data['时间戳'], format='%Y-%m-%d %H:%M:%S') #第一步:筛选充电数据 ChgStart=[] ChgEnd=[] for i in range(3, len(time) - 3): if i==3 and bmsstat[i]==2 and bmsstat[i+1]==2 and bmsstat[i+2]==2: ChgStart.append(i) elif bmsstat[i-2]!=2 and bmsstat[i-1]!=2 and bmsstat[i]==2: ChgStart.append(i) elif bmsstat[i-1]==2 and bmsstat[i]!=2 and bmsstat[i+1]!=2: ChgEnd.append(i) elif i == (len(time) - 4) and bmsstat[len(bmsstat)-1] == 2 and bmsstat[len(bmsstat)-2] == 2: ChgEnd.append(len(time)-1) #第二步:筛选充电起始Soc<48%,电芯温度>15℃,且满充的数据 ChgStartValid1=[] ChgEndValid1=[] ChgStartValid2=[] ChgEndValid2=[] for i in range(min(len(ChgStart),len(ChgEnd))): #获取最小温度值 celltemp = [] for j in range(1, CellTempNums+1): s = str(j) temp = data['单体温度' + s] celltemp.append(temp[ChgEnd[i]]) #寻找最大电压值 cellvolt = [] for j in range(1, CellVoltNums+1): s = str(j) volt = max(data['单体电压' + s][ChgStart[i]:ChgEnd[i]]/1000) cellvolt.append(volt) #筛选满足2点法计算的数据 StandingTime=0 if max(cellvolt)>CellFullChrgVolt and SOC[ChgStart[i]]<30 and min(celltemp)>5: for k in reversed(range(ChgStart[i])): if abs(packcrnt[k - 2]) < 0.01: StandingTime = StandingTime + (time[k] - time[k-1]).total_seconds() if StandingTime > 600: # 筛选静置时间>10min ChgStartValid1.append(ChgStart[i]) ChgEndValid1.append(ChgEnd[i]) break else: break #筛选满足DV/DQ方法的数据 if max(cellvolt)>CellFullChrgVolt and SOC[ChgStart[i]]<45 and min(celltemp)>5: if ((time[ChgEnd[i]]-time[ChgStart[i]]).total_seconds())/(ChgEnd[i]-ChgStart[i])<60: ChgStartValid2.append(ChgStart[i]) ChgEndValid2.append(ChgEnd[i]) #第三步:计算充电Soc和Soh # 两点法计算soh Soc=[] Time=[] Soc_Err=[] Bms_Soc=[] Soh1=[] Time1=[] Bms_Soh1=[] Soh_Err1=[] for i in range(len(ChgStartValid1)): #寻找最大电压值 cellvolt = [] for j in range(1, CellVoltNums+1): s = str(j) volt = max(data['单体电压' + s]) cellvolt.append(volt) voltmax_index = cellvolt.index(max(cellvolt)) + 1 cellvolt = data['单体电压' + str(voltmax_index)] / 1000 #soc Soc.append(np.interp(cellvolt[ChgStartValid1[i]-3],LookTab_OCV,LookTab_SOC)) Time.append(time[ChgStartValid1[i]-3]) Bms_Soc.append(SOC[ChgStartValid1[i]-3]) Soc_Err.append(Bms_Soc[-1]-Soc[-1]) #soh Ocv_Soc=np.interp(cellvolt[ChgStartValid1[i]-3],LookTab_OCV,LookTab_SOC) Ah=0 for j in range(ChgStartValid1[i],ChgEndValid1[i]): #计算soc Step=(time[j]-time[j-1]).total_seconds() Time.append(time[j]) Bms_Soc.append(SOC[j]) if Soc[-1]-(packcrnt[j]*Step*100)/(3600*Capacity)<100: Soc.append(Soc[-1]-(packcrnt[j]*Step*100)/(3600*Capacity)) else: Soc.append(100) Soc_Err.append(Bms_Soc[-1] - Soc[-1]) #两点法计算soh Ah=Ah-packcrnt[j]*Step/3600 Soh1.append(Ah*100/((FullChrgSoc-Ocv_Soc)*0.01*Capacity)) Bms_Soh1.append(SOH[i]) Soh_Err1.append(Bms_Soh1[-1]-Soh1[-1]) Time1.append(time[ChgStartValid1[i]]) # DV/DQ法计算soh Soh2=[] Time2=[] Bms_Soh2=[] Soh_Err2=[] SohCfd = [] sn_list=[] for i in range(len(ChgStartValid2)): #寻找最大电压值 cellvolt1 = [] cellvolt=[] for j in range(1, CellVoltNums+1): s = str(j) volt = data['单体电压' + s] cellvolt1.append(volt[ChgEndValid2[i]]) voltmax1_index = cellvolt1.index(max(cellvolt1)) + 1 cellvolt1 = data['单体电压' + str(voltmax1_index)] / 1000 #电压采用滑动平均滤波 cellvolt=np_move_avg(cellvolt1, 3, mode="same") #参数赋初始值 Ah = 0 Volt = cellvolt[ChgStartValid2[i]] DV_Volt=[] DQ_Ah = [] DVDQ = [] time2 = [] soc2 = [] Ah_tatal=[0] xvolt=[] #计算DV和DQ值 for j in range(ChgStartValid2[i],ChgEndValid2[i]): Step=(time[j+1]-time[j]).total_seconds() Ah=Ah-packcrnt[j]*Step/3600 if (cellvolt[j]-Volt)>0.0009 and Ah>0: Ah_tatal.append(Ah_tatal[-1]+Ah) DQ_Ah.append(Ah) DV_Volt.append(cellvolt[j]-Volt) DVDQ.append((DV_Volt[-1])/DQ_Ah[-1]) xvolt.append(cellvolt[j]) Volt=cellvolt[j] Ah = 0 time2.append(time[j]) soc2.append(SOC[j]) #切片Soc>50且Soc<80 Data1 = pd.DataFrame({'SOC': soc2, 'DVDQ': DVDQ, 'Ah_tatal': Ah_tatal[:-1], 'DQ_Ah':DQ_Ah, 'DV_Volt':DV_Volt, 'XVOLT':xvolt}) Data1=Data1[(Data1['SOC']>50) & (Data1['SOC']<80)] #寻找峰值并计算Soh和置信度 # 获取最小温度值 celltemp = [] for j in range(1, CellTempNums+1): s = str(j) temp = data['单体温度' + s] celltemp.append(temp[ChgStartValid2[i]]) if len(Data1['DVDQ'])>1: PeakIndex=Data1['DVDQ'].idxmax() #筛选峰值点附近±0.5%SOC内的数据 Data2=Data1[(Data1['SOC']>(Data1['SOC'][PeakIndex]-0.5)) & (Data1['SOC']<(Data1['SOC'][PeakIndex]+0.5))] if len(Data2)>2: Ah_tatal1 = Data1['Ah_tatal'] DVDQ = Data1['DVDQ'] soc2 = Data1['SOC'] xvolt = Data1['XVOLT'] if soc2[PeakIndex]>50 and soc2[PeakIndex]<80: DVDQ_SOH=(Ah_tatal[-1]-Ah_tatal1[PeakIndex]) * 100 / ((FullChrgSoc - PeakSoc) * 0.01 * Capacity) if DVDQ_SOH<95: DVDQ_SOH=DVDQ_SOH*0.3926+58.14 if DVDQ_SOH>70 and DVDQ_SOH<120: Soh2.append(DVDQ_SOH) Bms_Soh2.append(SOH[ChgStartValid2[i]]) Soh_Err2.append(Bms_Soh2[-1] - Soh2[-1]) Time2.append(time[ChgStartValid2[i]]) sn_list.append(SNnum) #计算置信度 if min(celltemp)<10: SohCfd.append(50) elif min(celltemp)<20: SohCfd.append(80) else: SohCfd.append(100) else: Data1=Data1.drop([PeakIndex]) PeakIndex = Data1['DVDQ'].idxmax() Data2 = Data1[(Data1['SOC'] > (Data1['SOC'][PeakIndex] - 0.5)) & (Data1['SOC'] < (Data1['SOC'][PeakIndex] + 0.5))] if len(Data2) > 3: Ah_tatal1 = Data1['Ah_tatal'] DVDQ = Data1['DVDQ'] soc2 = Data1['SOC'] xvolt = Data1['XVOLT'] if soc2[PeakIndex]>50 and soc2[PeakIndex]<80: DVDQ_SOH=(Ah_tatal[-1]-Ah_tatal1[PeakIndex]) * 100 / ((FullChrgSoc - PeakSoc) * 0.01 * Capacity) if DVDQ_SOH<95: DVDQ_SOH=DVDQ_SOH*0.3926+58.14 if DVDQ_SOH>70 and DVDQ_SOH<120: Soh2.append(DVDQ_SOH) Bms_Soh2.append(SOH[ChgStartValid2[i]]) Soh_Err2.append(Bms_Soh2[-1] - Soh2[-1]) Time2.append(time[ChgStartValid2[i]]) sn_list.append(SNnum) #计算置信度 if min(celltemp)<10: SohCfd.append(50) elif min(celltemp)<20: SohCfd.append(80) else: SohCfd.append(100) #处理数据 if len(Soh2)>5: Soh2=np_move_avg(Soh2,5,mode="valid") result_soh2={'时间': Time2[4::], 'SN号':sn_list[4::], 'BMS_SOH': Bms_Soh2[4::], 'SOH': Soh2, 'SOH误差': Soh_Err2[4::]} else: result_soh2={'时间': Time2, 'SN号':sn_list, 'BMS_SOH': Bms_Soh2, 'SOH': Soh2, 'SOH误差': Soh_Err2} #第四步:将数据存入Excel Result_Soh2=pd.DataFrame(result_soh2) # Result_Soh2.to_csv('BMS_SOH_'+SNnum+'.csv',encoding='GB18030') return Result_Soh2