Forráskód Böngészése

三元和磷酸铁锂电芯SOH算法

qingfeng 3 éve
szülő
commit
213d21e7b3

+ 308 - 0
LIB/FRONTEND/soh/LFPSoh 20210711.py

@@ -0,0 +1,308 @@
+# 获取数据
+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=[]
+
+#获取数据时间段
+now_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+now_time=datetime.datetime.strptime(now_time,'%Y-%m-%d %H:%M:%S')
+start_time=now_time-datetime.timedelta(days=1)
+end_time=str(now_time)
+strat_time=str(start_time)
+
+#输入一个含有‘SN号’的xlsx
+SNdata = pd.read_excel('骑享资产梳理-20210621.xlsx', sheet_name='6060')
+SNnums=SNdata['SN号']
+for k in range(15):
+    SNnum=str(SNnums[k])
+    sn = SNnum
+    st = '2021-07-06 00:00:00'
+    et = '2021-07-07 20:00:00'
+
+    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')

+ 21 - 43
LIB/FRONTEND/soh/NCMSoh 20210716.py

@@ -4,6 +4,7 @@ from LIB.BACKEND import DBManager
 import os
 import pandas as pd
 import numpy as np
+import datetime
 # import matplotlib.pyplot as plt
 
 #参数输入
@@ -27,6 +28,14 @@ Time3=[]
 Bms_Soh3=[]
 Soh_Err3=[]
 sn_list=[]
+
+#获取数据时间段
+now_time=datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
+now_time=datetime.datetime.strptime(now_time,'%Y-%m-%d %H:%M:%S')
+start_time=now_time-datetime.timedelta(days=31)
+end_time=str(now_time)
+strat_time=str(start_time)
+
 #输入一个含有‘SN号’的xlsx
 SNdata = pd.read_excel('骑享资产梳理-20210621.xlsx', sheet_name='6040骑享')
 SNnums=SNdata['SN号']
@@ -34,14 +43,13 @@ for k in range(len(SNnums)):
     SNnum=str(SNnums[k])
 
     sn = SNnum
-    st = '2021-07-06 00:00:00'
-    et = '2021-07-07 20:00:00'
+    st = strat_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']
-    print(data)
+    # print(data)
 
     packcrnt=data['总电流[A]']
     packvolt=data['总电压[V]']
@@ -64,8 +72,6 @@ for k in range(len(SNnums)):
             elif i == (len(time) - 4) and bmsstat[len(bmsstat)-1] == 2 and bmsstat[len(bmsstat)-2] == 2:
                 ChgEnd.append(len(time)-2)
 
-        print(ChgStart)
-        print(ChgEnd)
         #第二步:筛选充电起始Soc<45% & SOC>85%,电芯温度>5℃
         ChgStartValid1=[]
         ChgEndValid1=[]
@@ -91,7 +97,6 @@ for k in range(len(SNnums)):
             if len(packvolt[ChgStart[i]:ChgEnd[i]])>0:
                 packvoltMAX=max(packvolt[ChgStart[i]:ChgEnd[i]])
 
-                    
                 #筛选满足2点法计算的数据
                 StandingTime=0
                 StandingTime1=0
@@ -110,32 +115,13 @@ for k in range(len(SNnums)):
                         if abs(packcrnt[ChgStart[i] - m - 2])>0.5 and abs(packcrnt[ChgEnd[i] + m + 2])>0.5:
                             break
 
-                    #筛选满充的数据
-                    # for m in range(min(len(packcrnt)-ChgEnd[i],ChgStart[i]-2)):
-                    #     if abs(packcrnt[ChgStart[i] - m - 2]) < 0.1 and  abs(packcrnt[ChgEnd[i] + m + 2]) < 0.1:
-                    #         StandingTime = StandingTime + (time[ChgStart[i] - m] - time[ChgStart[i] - m - 1]).total_seconds()
-                    #         if StandingTime>1200 and  packvoltMAX>PackFullChrgVolt:
-                    #             ChgStartValid2.append(ChgStart[i])
-                    #             ChgEndValid2.append(ChgEnd[i])
-                    #             break
-                    #         elif abs(packcrnt[ChgStart[i] - m - 2])>0.5:
-                    #             break
-                    #     else:
-                    #         break
-
-
-        print(ChgStart)
-        print(ChgEnd)
-        print(ChgStartValid1)
-        print(ChgEndValid1)
-        print(StandingNum)
-
         # 计算soh
         Soh1=[]
         Soh2=[]
         Time1=[]
         Bms_Soh1=[]
         Soh_Err1=[]
+        sn_list1=[]
         #两点法计算Soh
         if len(ChgStartValid1)>0:
             for i in range(len(ChgStartValid1)):
@@ -158,30 +144,22 @@ for k in range(len(SNnums)):
                 Bms_Soh1.append(SOH[ChgStartValid1[i]])
                 Soh_Err1.append(Bms_Soh1[-1]-Soh1[-1])
                 Time1.append(time[ChgStartValid1[i]])
-
-            
-            Soh3.append(np.mean(Soh1))
-            Bms_Soh3.append(np.mean(Bms_Soh1))
-            Soh_Err3.append(np.mean(Soh_Err1))
-            Time3.append(time[ChgStartValid1[-1]])
-            sn_list.append(SNnum)
-
-                # ax1 = plt.subplot(3, 1, 1)
-                # plt.plot(xvolt[10:-10],DVDQ[10:-10],'r*-')
-                # ax1 = plt.subplot(3, 1, 2)
-                # plt.plot(soc2[10:-10],xvolt[10:-10],'y*-')
-                # ax1 = plt.subplot(3, 1, 3)
-                # plt.plot(soc2[10:-10], DVDQ[10:-10], 'r*-')
-                # plt.show()
+                sn_list1.append(SNnum)
+       
+            # Soh3.append(np.mean(Soh1))
+            # Bms_Soh3.append(np.mean(Bms_Soh1))
+            # Soh_Err3.append(np.mean(Soh_Err1))
+            # Time3.append(time[ChgStartValid1[-1]])
+            # sn_list.append(SNnum)
 
         #第四步:将数据存入Excel
             result_soh2={'时间': Time1,
+                'SN号': sn_list1,
                 'BMS_SOH': Bms_Soh1,
                 'SOH': Soh1,
                 'SOH误差': Soh_Err1}
 
             Result_Soh2=pd.DataFrame(result_soh2)
-            print(Result_Soh2)
             Result_Soh2.to_csv('BMS_SOH_'+SNnum+'.csv',encoding='GB18030')
 
 #     result_soh1={'时间': Time3,

+ 6 - 0
LIB/FRONTEND/soh/soh表头及数据类型.xlsx

@@ -0,0 +1,6 @@
+表头	名称	数据类型
+时间	time	timestamps
+SN号	sn	str
+BMS_SOH	bms_soh	float64
+SOH	soh	float64
+SOH误差	soh_err	float64