浏览代码

Merge remote-tracking branch 'origin/dev' into pro

lmstack 3 年之前
父节点
当前提交
a54f1f42a7

+ 1 - 1
LIB/BACKEND/DBManager.py

@@ -31,7 +31,7 @@ class DBManager():
         self.connect()
         return self
 
-    def __exit__(self):
+    def __exit__(self, exc_type, exc_val, exc_tb):
         self.close()
 
     def connect(self):

+ 77 - 0
LIB/MIDDLE/CellStateEstimation/SOH/V1_0_0/BatParam.py

@@ -0,0 +1,77 @@
+
+#定义电池参数
+
+from types import CellType
+import sys
+
+
+class BatParam:
+
+    def __init__(self,sn):
+
+        if 'PK500' in sn:
+            self.celltype=1 #6040三元电芯
+        elif 'PK502' in sn:
+            self.celltype=2 #4840三元电芯
+        elif 'PK504' in sn:
+            self.celltype=99    #60ah林磷酸铁锂电芯
+        elif 'MGMCLN750' in sn: 
+            self.celltype=3 #CATL 50ah三元电芯
+        elif 'MGMLXN750' in sn:
+            self.celltype=4 #力信50ah三元电芯
+        else:
+            print('未找到对应电池编号!!!')
+            sys.exit()
+
+        if self.celltype==1: #6040
+            self.Capacity = 41
+            self.PackFullChrgVolt=69.99
+            self.CellFullChrgVolt=4.2
+            self.CellVoltNums=17
+            self.CellTempNums=4
+            self.FullChrgSoc=98
+            self.PeakSoc=57
+            self.LookTab_SOC = [0,	    3.5348,	8.3581,	13.181,	18.004,	22.827,	27.651,	32.474,	37.297,	42.120,	46.944,	51.767,	56.590,	61.413,	66.237,	71.060,	75.883,	80.707,	85.530,	90.353,	95.176,	100]
+            self.LookTab_OCV = [3.3159,	3.4384,	3.4774,	3.5156,	3.5478,	3.5748,	3.6058,	3.6238,	3.638,	3.6535,	3.6715,	3.6951,	3.7279,	3.7757,	3.8126,	3.8529,	3.8969,	3.9446,	3.9946,	4.0491,	4.109,	4.183]
+        
+        elif self.celltype==2: #4840
+            self.Capacity = 41
+            self.PackFullChrgVolt=69.99
+            self.CellFullChrgVolt=4.2
+            self.CellVoltNums=14
+            self.CellTempNums=4
+            self.FullChrgSoc=98
+            self.PeakSoc=57
+            self.LookTab_SOC = [0,	    3.5348,	8.3581,	13.181,	18.004,	22.827,	27.651,	32.474,	37.297,	42.120,	46.944,	51.767,	56.590,	61.413,	66.237,	71.060,	75.883,	80.707,	85.530,	90.353,	95.176,	100]
+            self.LookTab_OCV = [3.3159,	3.4384,	3.4774,	3.5156,	3.5478,	3.5748,	3.6058,	3.6238,	3.638,	3.6535,	3.6715,	3.6951,	3.7279,	3.7757,	3.8126,	3.8529,	3.8969,	3.9446,	3.9946,	4.0491,	4.109,	4.183]
+       
+        elif self.celltype==99:   #60ah磷酸铁锂电芯
+            self.Capacity = 54
+            self.PackFullChrgVolt=69.99
+            self.CellFullChrgVolt=3.5
+            self.OcvInflexionBelow=3.285
+            self.OcvInflexion2=3.296
+            self.OcvInflexion3=3.328
+            self.OcvInflexionAbove=3.4
+            self.CellVoltNums=20
+            self.CellTempNums=4
+            self.FullChrgSoc=98
+            self.PeakSoc=57
+            self.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]
+            self.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]
+        
+        elif self.celltype==3:
+            self.Capacity = 50
+            self.PackFullChrgVolt=80
+            self.CellFullChrgVolt=4.2
+            self.CellVoltNums=20
+            self.CellTempNums=4
+            self.FullChrgSoc=98
+            self.PeakSoc=57
+            self.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]
+            self.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]
+        
+        else:
+            print('未找到对应电池编号!!!')
+            sys.exit()
+

+ 732 - 0
LIB/MIDDLE/CellStateEstimation/SOH/V1_0_0/CloudBMSSoh.py

@@ -0,0 +1,732 @@
+import pandas as pd
+import numpy as np
+import datetime
+import bisect
+import matplotlib.pyplot as plt
+import BatParam
+import DBDownload
+
+class Soh:
+    def __init__(self,sn,df_bms,df_accum):  #参数初始化
+
+        self.sn=sn
+        self.param=BatParam.BatParam(sn)
+        self.df_bms=df_bms
+        self.packcrnt=df_bms['总电流[A]']
+        self.packvolt=df_bms['总电压[V]']
+        self.bms_soc=df_bms['SOC[%]']
+        self.bms_soh=df_bms['SOH[%]']
+        self.bmsstat=df_bms['充电状态']
+        self.bmstime= pd.to_datetime(df_bms['时间戳'], format='%Y-%m-%d %H:%M:%S')
+
+        self.df_accum=df_accum
+        self.accumtime=pd.to_datetime(df_accum['时间戳'], format='%Y-%m-%d %H:%M:%S')
+
+    def soh(self):
+        if self.param.celltype==1 or self.param.celltype==2:
+            df_res=self._ncmsoh_twopoint()
+            return df_res
+            
+        elif self.param.celltype==99:
+            df_res=self._lfpsoh()
+            return df_res
+
+    def getdata(self):  #获取已有soh结果
+        host='rm-bp10j10qy42bzy0q77o.mysql.rds.aliyuncs.com'
+        port=3306
+        db='qx_cas'
+        user='qx_read'
+        password='Qx@123456'
+
+        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=60)
+        end_time=str(now_time)
+        start_time=str(start_time)
+
+        DBManager=DBDownload.DBDownload(host, port, db, user, password)
+        with DBManager as DBManager:
+            df_soh=DBManager.getdata('sn', 'time', 'bms_soh', 'soh', 'soh_err', tablename='soh_result',st=start_time,sp=end_time)
+            self.df_soh=df_soh[df_soh['sn']==self.sn]
+    
+    def np_move_avg(self,a, n, mode="same"): #定义滑动滤波函数
+        return (np.convolve(a, np.ones((n,)) / n, mode=mode))
+
+    def _chrgdata(self):    #筛选充电数据
+        self.ChgStart=[]
+        self.ChgEnd=[]
+        if len(self.packvolt)>100:
+            for i in range(3, len(self.bmstime) - 3):
+                if i==3 and self.bmsstat[i]==2 and self.bmsstat[i+1]==2 and self.bmsstat[i+2]==2:
+                    self.ChgStart.append(i)
+                elif self.bmsstat[i-2]!=2 and self.bmsstat[i-1]!=2 and self.bmsstat[i]==2:
+                    self.ChgStart.append(i)
+                elif self.bmsstat[i-1]==2 and self.bmsstat[i]!=2 and self.bmsstat[i+1]!=2:
+                    self.ChgEnd.append(i-1)
+                elif i == (len(self.bmstime) - 4) and self.bmsstat[len(self.bmsstat)-1] == 2 and self.bmsstat[len(self.bmsstat)-2] == 2:
+                    self.ChgEnd.append(len(self.bmstime)-2)
+    
+    def _celltemp_weight(self,num):   #寻找当前行数据的最小温度值
+        celltemp = []
+        for j in range(1, self.param.CellTempNums+1):
+            s = str(j)
+            celltemp.append(self.df_bms.loc[num,'单体温度' + s])
+        celltemp.remove(min(celltemp))
+        if self.param.celltype==99:
+            if min(celltemp)>=20:
+                self.tempweight=1
+                self.StandardStandingTime=1800
+            elif min(celltemp)>=10:
+                self.tempweight=0.6
+                self.StandardStandingTime=3600
+            elif min(celltemp)>=5:
+                self.tempweight=0.
+                self.StandardStandingTime=7200
+            else:
+                self.tempweight=0.1
+                self.StandardStandingTime=10800
+        else:
+            if min(celltemp)>=20:
+                self.tempweight=1
+                self.StandardStandingTime=900
+            elif min(celltemp)>=10:
+                self.tempweight=0.8
+                self.StandardStandingTime=1200
+            elif min(celltemp)>=5:
+                self.tempweight=0.6
+                self.StandardStandingTime=1800
+            else:
+                self.tempweight=0.2
+                self.StandardStandingTime=3600
+
+    def _deltsoc_weight(self,deltsoc):   #获取SOC差对应的SOH权重值
+        if deltsoc>60:   
+            deltsoc_weight=1
+        elif deltsoc>50:
+            deltsoc_weight=0.9
+        elif deltsoc>40:
+            deltsoc_weight=0.7
+        elif deltsoc>30:
+            deltsoc_weight=0.5
+        elif deltsoc>20:
+            deltsoc_weight=0.3
+        else:
+            deltsoc_weight=0
+        return deltsoc_weight
+
+    def _cellvolt_get(self,num): #获取当前行所有电压数据
+        cellvolt=[]
+        for j in range(1, self.param.CellVoltNums+1): 
+            s = str(j)
+            cellvolt.append(self.df_bms.loc[num,'单体电压' + s]/1000)
+        return(cellvolt)
+                
+    def _ncmsoh_chrg(self):     #NCM充电数据soh计算 
+        self._chrgdata()
+        self.getdata()
+        ChgStartValid=[]
+        ChgEndValid=[]
+        tempweightlist=[]
+        for i in range(min(len(self.ChgStart),len(self.ChgEnd))): 
+            self._celltemp_weight(self.ChgEnd[i])               #获取温度对应的静置时间及权重            
+            for k in range(self.ChgStart[i],self.ChgEnd[i]):   #去除电流0点
+                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:
+                    self.ChgEnd[i]=k
+   
+            #筛选满足2点法计算的数据
+            StandingTime=0
+            StandingTime1=0
+            if self.bms_soc[self.ChgEnd[i]]>70 and self.bms_soc[self.ChgStart[i]]<50:
+                for m in range(min(len(self.packcrnt)-self.ChgEnd[i]-2,self.ChgStart[i]-2)):
+                    if abs(self.packcrnt[self.ChgStart[i] - m - 1]) < 0.5:
+                        StandingTime = StandingTime + (self.bmstime[self.ChgStart[i] - m] - self.bmstime[self.ChgStart[i] - m - 1]).total_seconds()
+                    if abs(self.packcrnt[self.ChgEnd[i] + m + 1]) < 0.5:
+                        StandingTime1 = StandingTime1 + (self.bmstime[self.ChgEnd[i] + m + 1] - self.bmstime[self.ChgEnd[i] + m]).total_seconds()
+                    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且慢充过程丢失数据少
+                        if abs(self.packcrnt[self.ChgEnd[i] + m + 2])>0.5 or m==len(self.packcrnt)-self.ChgEnd[i]-3: #如果电流<0.5,继续寻找充电后的静置电压,直到末尾
+                            ChgStartValid.append(self.ChgStart[i])
+                            ChgEndValid.append(self.ChgEnd[i]+m)
+                            tempweightlist.append(self.tempweight)
+                            break
+                    if abs(self.packcrnt[self.ChgStart[i] - m - 2])>0.5 and abs(self.packcrnt[self.ChgEnd[i] + m + 2])>0.5:
+                        break
+
+        if len(ChgStartValid)>0:   #两点法计算Soh
+            df_res=pd.DataFrame(columns=('time','sn','soh','soh1'))
+            soh2=[]
+            if not self.df_soh.empty:  #获取数据库中上次计算的Soh值
+                soh_init=list(self.df_soh['soh'])[-1]
+            else:
+                soh_init=list(self.bms_soh)[-1]
+
+            for i in range(len(ChgStartValid)):
+                Ah=0
+                for j in range(ChgStartValid[i],ChgEndValid[i]):  #计算Ah
+                    Step=(self.bmstime[j+1]-self.bmstime[j]).total_seconds()
+                    Ah=Ah-self.packcrnt[j+1]*Step/3600
+
+                for j in range(1, self.param.CellVoltNums+1):    #计算每个电芯的Soh
+                    s = str(j)
+                    OCVStart=self.df_bms.loc[ChgStartValid[i]-2,'单体电压' + s]/1000
+                    OCVEnd=self.df_bms.loc[ChgEndValid[i]-1,'单体电压' + s]/1000
+                    #soh
+                    ocv_Soc1=np.interp(OCVStart,self.param.LookTab_OCV,self.param.LookTab_SOC)
+                    ocv_Soc2=np.interp(OCVEnd,self.param.LookTab_OCV,self.param.LookTab_SOC)
+                
+                    soh2.append(Ah*100/((ocv_Soc2-ocv_Soc1)*0.01*self.param.Capacity))
+                soh1=np.mean(soh2)
+                delt_ocv_soc=ocv_Soc2-ocv_Soc1
+                self._deltsoc_weight(delt_ocv_soc)
+                soh_res=soh_init*(1-self.deltsoc_weight*tempweightlist[i])+soh1*self.deltsoc_weight*tempweightlist[i]
+                soh_init=soh_res
+                df_res.loc[i]=[self.bmstime[ChgStartValid[i]],self.sn,soh_res,soh1]
+            
+            return df_res
+        return pd.DataFrame()
+
+    def _ncmsoh_twopoint(self):
+        standingpoint_st=[]
+        standingpoint_sp=[]
+        tempweightlist=[]
+        standingtime=0
+        for i in range(3,len(self.df_bms)-3):
+
+            if abs(self.packcrnt[i]) < 0.3:     #电流为0
+                delttime=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
+                standingtime=standingtime+delttime
+                self._celltemp_weight(i)     #获取不同温度对应的静置时间
+
+                if standingtime>self.StandardStandingTime:      #静置时间满足要求
+                    if standingpoint_st:                        
+                        if len(standingpoint_st)>len(standingpoint_sp):     #开始时刻已获取,结束时刻未获取
+                            cellvolt_now=self._cellvolt_get(i-1)     #获取当前行电压数据
+                            minocv_socnow=np.interp(min(cellvolt_now),self.param.LookTab_OCV,self.param.LookTab_SOC)
+                            cellvolt_st=self._cellvolt_get(standingpoint_st[-1])   #获取开始时刻静置后的电压数据
+                            minocv_socst=np.interp(min(cellvolt_st),self.param.LookTab_OCV,self.param.LookTab_SOC)
+
+                            if abs(minocv_socst-minocv_socnow)>=40:   #当前时刻SOC与开始时刻SOC差>=20
+                                if abs(self.packcrnt[i+2])>=0.3:    #如果下一时刻电流>=0.5,则压入当前索引
+                                    standingpoint_sp.append(i)
+                                    standingpoint_st.append(i)
+                                    tempweightlist.append(self.tempweight)
+                                    standingtime=0
+                                    continue
+                                else:
+                                    if standingtime>3600 or i==len(self.df_bms)-2:   #仍处于静置,但静置时间>1h,则直接获取sp时刻,或者到了数据末尾
+                                        standingpoint_sp.append(i)
+                                        tempweightlist.append(self.tempweight)
+                                        continue
+                            else:
+                                if minocv_socst<50 and minocv_socnow<minocv_socst and abs(self.packcrnt[i+2])>=0.3:
+                                    standingpoint_st[-1]=i
+                                    standingtime=0
+                                    continue
+                                elif minocv_socst>=50 and minocv_socnow>minocv_socst and abs(self.packcrnt[i+2])>=0.3:
+                                    standingpoint_st[-1]=i
+                                    standingtime=0
+                                    continue
+                                else:
+                                    continue
+                        else:
+                            if abs(self.packcrnt[i+2])>=0.5:
+                                standingpoint_st.append(i)
+                                standingtime=0
+                                continue
+                            else:
+                                continue
+                    else:
+                        if abs(self.packcrnt[i+2])>0.5:
+                            standingpoint_st.append(i)
+                            standingtime=0
+                            continue
+                        else:
+                            continue
+                else:
+                    continue
+            else:
+                standingtime=0
+                continue
+
+        if standingpoint_sp:
+            self.getdata()  #获取已计算的soh
+            column_name=['time_st','time_sp','sn','method','soh','cellsoh1','cellsoh2','cellsoh3','cellsoh4','cellsoh5','cellsoh6','cellsoh7','cellsoh8','cellsoh9','cellsoh10','cellsoh11','cellsoh12','cellsoh13','cellsoh14','cellsoh15','cellsoh16','cellsoh17','cellsoh18','cellsoh19','cellsoh20']
+            df_res=pd.DataFrame(columns=column_name)
+
+            for i in range(len(standingpoint_sp)):
+                cellocv_st=self._cellvolt_get(standingpoint_st[i])    #获取静置点所有电芯的电压
+                cellocv_sp=self._cellvolt_get(standingpoint_sp[i])
+                accumtime=self.accumtime.to_list()  #累计量的时间列表
+                timepoint_bms_st=self.bmstime[standingpoint_st[i]]   #获取静置点的时间
+                timepoint_bms_sp=self.bmstime[standingpoint_sp[i]]
+                timepoint_accum_st=bisect.bisect(accumtime,timepoint_bms_st)   #获取最接近静置点时间的累计量时间点
+                timepoint_accum_sp=bisect.bisect(accumtime,timepoint_bms_sp)
+                if timepoint_accum_sp>=len(accumtime):  #防止指针超出数据范围
+                    timepoint_accum_sp=len(accumtime)-1
+                
+                ah_packcrnt_dis=0
+                ah_packcrnt_chg=0
+                for j in range(standingpoint_st[i]+2,standingpoint_sp[i]): #计算累计Ah
+                    Step=(self.bmstime[j+1]-self.bmstime[j]).total_seconds()
+                    if self.packcrnt[j+1]>=0:
+                        ah_packcrnt_dis=ah_packcrnt_dis+self.packcrnt[j+1]*Step
+                    else:
+                        ah_packcrnt_chg=ah_packcrnt_chg-self.packcrnt[j+1]*Step  
+                ah_packcrnt_chg=ah_packcrnt_chg/3600
+                ah_packcrnt_dis=ah_packcrnt_dis/3600
+                ah_packcrnt=ah_packcrnt_chg-ah_packcrnt_dis     #两个静置点的总累计AH,负值代表放电,正值代表充电
+     
+                ah_accum_dis=self.df_accum.loc[timepoint_accum_sp,'累计放电电量']-self.df_accum.loc[timepoint_accum_st,'累计放电电量']  #两个静置点之间的放电电量
+                ah_accum_chg=self.df_accum.loc[timepoint_accum_sp,'累计充电电量']-self.df_accum.loc[timepoint_accum_st,'累计充电电量']  #两个静置点之间的充电电量
+                ah_accum_tatol=ah_accum_chg-ah_accum_dis  #两个静置点的总累计AH,负值代表放电,正值代表充电
+                ah_accum=ah_packcrnt
+
+                delt_days=(self.bmstime[standingpoint_sp[i]]-self.bmstime[standingpoint_st[i]]).total_seconds()/(3600*24)
+                if delt_days<=1: #两次时间间隔对计算结果的影响
+                    soh_weight1=1
+                elif delt_days<=2:
+                    soh_weight1=0.9
+                elif delt_days<=3:
+                    soh_weight1=0.4
+                else:
+                    soh_weight1=0
+                
+                if ah_packcrnt_dis<self.param.Capacity: #放电ah数对结果的影响
+                    soh_weight1=(1-ah_packcrnt_dis/self.param.Capacity*1.5)*soh_weight1
+                else:
+                    soh_weight1=0
+            
+                if self.param.Capacity**0.7*0.4 < abs(ah_accum_tatol) < self.param.Capacity:    #累计量的权重
+                    if abs(ah_accum_tatol-ah_packcrnt)<self.param.Capacity/20:
+                        soh_weight1=soh_weight1*1
+                    elif abs(ah_accum_tatol-ah_packcrnt) < self.param.Capacity/10:
+                        soh_weight1=soh_weight1*0.8
+                    else:
+                        soh_weight1=0.5
+                else:
+                    if self.param.Capacity*0.7*0.4< abs(ah_packcrnt) <self.param.Capacity:
+                        soh_weight1=soh_weight1*0.5
+                    else:
+                        soh_weight1=0
+                
+                if ah_packcrnt_chg + ah_packcrnt_dis > self.param.Capacity:    #总Ah数对结果的影响
+                    soh_weight1=soh_weight1*0.6
+                else:
+                    soh_weight1=soh_weight1
+
+                cellsoh=[timepoint_bms_st, timepoint_bms_sp, self.sn, 1]
+                for j in range(20):    #计算每个电芯的SOH值
+                    if j<self.param.CellVoltNums:
+                        ocv_soc1=np.interp(cellocv_st[j],self.param.LookTab_OCV,self.param.LookTab_SOC)
+                        ocv_soc2=np.interp(cellocv_sp[j],self.param.LookTab_OCV,self.param.LookTab_SOC)
+                        delt_ocv_soc=ocv_soc2-ocv_soc1
+                        delt_ocv_soc_weight=self._deltsoc_weight(abs(delt_ocv_soc))
+                        soh_weight=soh_weight1*tempweightlist[i]*delt_ocv_soc_weight
+                        cellsoh_init=ah_accum*100/((ocv_soc2-ocv_soc1)*0.01*self.param.Capacity)
+
+                        if cellsoh_init>55 and cellsoh_init<120:    #判断soh值的有效区间
+                            if len(df_res)<1:
+                                if not self.df_soh.empty and self.df_soh.shape[1]>10:
+                                    cellsoh_cal=cellsoh_init*soh_weight + list(self.df_soh['cellsoh'+str(j+1)])[-1]*(1-soh_weight)
+                                else:
+                                    cellsoh_cal=cellsoh_init
+                            else:
+                                if abs(cellsoh_init-df_res.iloc[-1]['cellsoh'+str(j+1)])<15:
+                                    cellsoh_cal=cellsoh_init*soh_weight*0.5 + df_res.iloc[-1]['cellsoh'+str(j+1)]*(1-soh_weight*0.5)
+                                else:
+                                    soh_weight=soh_weight*0.2
+                                    cellsoh_cal=cellsoh_init*soh_weight*0.5 + df_res.iloc[-1]['cellsoh'+str(j+1)]*(1-soh_weight*0.5)
+                            cellsoh.append(cellsoh_cal)
+                        else:
+                            cellsoh=[]
+                            break
+                    else:
+                        cellsoh.append(0)
+                if len(cellsoh)>4:
+                    soh_value=cellsoh[4:4+self.param.CellVoltNums]
+                    soh=min(soh_value)
+                    cellsoh.insert(4,soh)
+                    if len(df_res)<1:
+                        df_res.loc[0]=cellsoh
+                    else:
+                        df_res.loc[df_res.index.values[-1]+1]=cellsoh
+                        print(df_res)
+                else:
+                    continue
+            if df_res.empty:
+                return pd.DataFrame()
+            else:
+                return df_res
+        return pd.DataFrame()
+
+    def _lfpsoh(self):
+        standingpoint_st=[]
+        standingpoint_sp=[]
+        tempweightlist1=[]
+        cellmaxvolt_number1=[]
+        standingtime=0
+        chrg_start=[]
+        chrg_end=[]
+        tempweightlist2=[]
+        cellmaxvolt_number2=[]
+        charging=0
+
+        for i in range(3,len(self.df_bms)-3):
+
+            #获取两点法法所需数据-开始
+            if abs(self.packcrnt[i]) < 0.2:     #判断非平台区静置状态
+                delttime=(self.bmstime[i]-self.bmstime[i-1]).total_seconds()
+                standingtime=standingtime+delttime
+                self._celltemp_weight(i)     #获取不同温度对应的静置时间
+
+                if standingtime>self.StandardStandingTime and abs(self.packcrnt[i+2])>0.1:  #静置时间满足要求,且下一时刻电流>0.1A
+                    standingtime=0
+                    cellvolt_now=self._cellvolt_get(i)
+                    if max(cellvolt_now)<self.param.OcvInflexionBelow:      #当前最大电芯电压<OCV下拐点
+                        if standingpoint_st:
+                            if len(standingpoint_st)>len(standingpoint_sp):
+                                if self.packcrnt[standingpoint_st[-1]]<-1:     #判断上一次静置点的是否为满充
+                                    standingpoint_sp.append(i)
+                                    standingpoint_st.append(i)
+                                    tempweightlist1.append(self.tempweight)
+                                else:
+                                    standingpoint_st[-1]=i
+                                    tempweightlist1[-1]=self.tempweight
+                            else:
+                                standingpoint_st.append(i)
+                                tempweightlist1.append(self.tempweight)
+                        else:
+                            standingpoint_st.append(i)
+                            tempweightlist1.append(self.tempweight)
+                    else:
+                        pass
+                else:
+                    pass
+            
+            elif self.packcrnt[i]<=-1 and self.packcrnt[i-1]<=-1 and self.packcrnt[i+1]<=-1 and self.packcrnt[i+2]>-1:    #判读满充状态
+                standingtime=0
+                self._celltemp_weight(i)
+                cellvolt_now=self._cellvolt_get(i)
+                if max(cellvolt_now)>self.param.CellFullChrgVolt:
+                    if standingpoint_st:
+                        if len(standingpoint_st)>len(standingpoint_sp):
+                            if abs(self.packcrnt[standingpoint_st[-1]])<0.5:     #判断上一次静置点是否为下拐点
+                                standingpoint_sp.append(i)
+                                standingpoint_st.append(i)
+                                tempweightlist1.append(self.tempweight)
+                                cellmaxvolt_number1.append(cellvolt_now.index(max(cellvolt_now))) #获取最大电压索引
+                                cellmaxvolt_number1.append(cellvolt_now.index(max(cellvolt_now))) #获取最大电压索引
+                            else:
+                                standingpoint_st[-1]=i
+                                tempweightlist1[-1]=self.tempweight
+                                cellmaxvolt_number1[-1]=cellvolt_now.index(max(cellvolt_now))
+                    else:
+                        standingpoint_st.append(i)
+                        tempweightlist1.append(self.tempweight)
+                        cellmaxvolt_number1.append(cellvolt_now.index(max(cellvolt_now)))
+                else:
+                    pass
+            
+            else:
+                standingtime=0
+                pass
+            #获取两点法所需数据-结束
+
+            #获取DVDQ算法所需数据——开始
+            if i==3 and self.packcrnt[1]<=-1 and self.packcrnt[2]<=-1 and self.packcrnt[3]<=-1:
+                chrg_start.append(i)
+                charging=1
+            elif self.packcrnt[i-1]>-1 and self.packcrnt[i]<=-1 and self.packcrnt[i+1]<=-1 and self.packcrnt[i+2]<=-1:     #判断充电开始
+                if self.bms_soc[i]<45:
+                    self._celltemp_weight(i)
+                    charging=1
+                    if len(chrg_start)>len(chrg_end):
+                        chrg_start[-1]=i
+                        tempweightlist2[-1]=self.tempweight
+                    else:
+                        chrg_start.append(i)
+                        tempweightlist2.append(self.tempweight)
+                else:
+                    pass
+            else:
+                pass
+
+            if charging==1: #充电中
+                if (self.bmstime[i+1]-self.bmstime[i]).total_seconds()>180:  #如果充电过程中时间间隔>180s,则舍弃该次充电
+                    chrg_start.remove(chrg_start[-1])
+                    tempweightlist2.remove(tempweightlist2[-1])
+                    charging=0
+                    continue
+                elif self.packcrnt[i]<=-1 and self.packcrnt[i+1]<=-1 and  self.packcrnt[i+2]>-1:  #判断电流波动时刻
+                    cellvolt_now=self._cellvolt_get(i+1)
+                    if max(cellvolt_now)>self.param.CellFullChrgVolt:   #电压>满充电压
+                        chrg_end.append(i+1)
+                        cellmaxvolt_number2.append(cellvolt_now.index(max(cellvolt_now)))   #获取最大电压索引
+                        charging=0
+                        continue
+                    else:
+                        pass
+                elif self.packcrnt[i+1]>-0.1 and self.packcrnt[i+2]>-0.1 and self.packcrnt[i+3]>-0.1:   #判断充电结束
+                    charging=0
+                    if len(chrg_start)>len(chrg_end):
+                        chrg_start.remove(chrg_start[-1])
+                        tempweightlist2.remove(tempweightlist2[-1])
+                        continue
+                    else:
+                        continue
+                elif i==len(self.packcrnt)-3 and self.packcrnt[i+1]<-1 and self.packcrnt[i+2]<-1:
+                    charging=0
+                    if len(chrg_start)>len(chrg_end):
+                        cellvolt_now=self._cellvolt_get(i)
+                        if max(cellvolt_now)>self.param.CellFullChrgVolt:   #电压>满充电压
+                            chrg_end.append(i)
+                            cellmaxvolt_number2.append(cellvolt_now.index(max(cellvolt_now)))   #获取最大电压索引
+                            continue
+                        else:
+                            chrg_start.remove(chrg_start[-1])
+                            tempweightlist2.remove(tempweightlist2[-1])
+                            continue
+                    else:
+                        continue   
+            else:
+                pass
+            #获取DVDQ算法所需数据——结束
+        
+        if standingpoint_sp or chrg_end:       #开始计算SOH
+            self.getdata()  #获取已计算的soh
+            column_name=['time_st','time_sp','sn','method','soh','cellsoh1','cellsoh2','cellsoh3','cellsoh4','cellsoh5','cellsoh6','cellsoh7','cellsoh8','cellsoh9','cellsoh10','cellsoh11','cellsoh12','cellsoh13','cellsoh14','cellsoh15','cellsoh16','cellsoh17','cellsoh18','cellsoh19','cellsoh20']
+            df_res=pd.DataFrame(columns=column_name)
+        
+            if standingpoint_sp:    #两点法计算SOH
+                for i in range(len(standingpoint_sp)):  #判断为满充点或者下拐点
+                    if self.packcrnt[standingpoint_sp[i]]<=-1:
+                        cellocv_st=self._cellvolt_get(standingpoint_st[i])    
+                        ocv_soc1=np.interp(cellocv_st[cellmaxvolt_number1[i]],self.param.LookTab_OCV,self.param.LookTab_SOC)
+                        ocv_soc2=self.param.FullChrgSoc
+                    else:
+                        cellocv_sp=self._cellvolt_get(standingpoint_sp[i])
+                        ocv_soc1=self.param.FullChrgSoc
+                        ocv_soc2=np.interp(cellocv_sp[cellmaxvolt_number1[i]],self.param.LookTab_OCV,self.param.LookTab_SOC)
+
+                    cellocv_sp=self._cellvolt_get(standingpoint_sp[i])
+                    accumtime=self.accumtime.to_list()  #累计量的时间列表
+                    timepoint_bms_st=self.bmstime[standingpoint_st[i]]   #获取静置点的时间
+                    timepoint_bms_sp=self.bmstime[standingpoint_sp[i]]
+                    timepoint_accum_st=bisect.bisect(accumtime,timepoint_bms_st)   #获取最接近静置点时间的累计量时间点
+                    timepoint_accum_sp=bisect.bisect(accumtime,timepoint_bms_sp)
+                    if timepoint_accum_sp>=len(accumtime):  #防止指针超出数据范围
+                        timepoint_accum_sp=len(accumtime)-1
+                    
+                    ah_packcrnt_dis=0
+                    ah_packcrnt_chg=0
+                    for j in range(standingpoint_st[i]+2,standingpoint_sp[i]+1): #计算累计Ah
+                        Step=(self.bmstime[j+1]-self.bmstime[j]).total_seconds()
+                        if self.packcrnt[j+1]>=0:
+                            ah_packcrnt_dis=ah_packcrnt_dis+self.packcrnt[j+1]*Step
+                        else:
+                            ah_packcrnt_chg=ah_packcrnt_chg-self.packcrnt[j+1]*Step
+                    ah_packcrnt_chg=ah_packcrnt_chg/3600
+                    ah_packcrnt_dis=ah_packcrnt_dis/3600          
+                    ah_packcrnt=ah_packcrnt_chg-ah_packcrnt_dis     #两个静置点的总累计AH,负值代表放电,正值代表充电
+        
+                    ah_accum_dis=self.df_accum.loc[timepoint_accum_sp,'累计放电电量']-self.df_accum.loc[timepoint_accum_st,'累计放电电量']  #两个静置点之间的放电电量
+                    ah_accum_chg=self.df_accum.loc[timepoint_accum_sp,'累计充电电量']-self.df_accum.loc[timepoint_accum_st,'累计充电电量']  #两个静置点之间的充电电量
+                    ah_accum_tatol=ah_accum_chg-ah_accum_dis  #两个静置点的总累计AH,负值代表放电,正值代表充电
+                    ah_accum=ah_accum_tatol
+
+                    delt_days=(self.bmstime[standingpoint_sp[i]]-self.bmstime[standingpoint_st[i]]).total_seconds()/(3600*24)
+                    if delt_days<=1: #两次时间间隔对计算结果的影响
+                        soh_weight=1
+                    elif delt_days<=2:
+                        soh_weight=0.9
+                    elif delt_days<=3:
+                        soh_weight=0.4
+                    else:
+                        soh_weight=0
+                    
+                    if self.param.Capacity*0.65*0.7 < abs(ah_packcrnt) < self.param.Capacity:    #累计量的权重
+                        if abs(ah_accum_tatol-ah_packcrnt)<self.param.Capacity/20:
+                            soh_weight=soh_weight*1
+                        elif abs(ah_accum_tatol-ah_packcrnt)<self.param.Capacity/10:
+                            soh_weight=soh_weight*0.8
+                        else:
+                            soh_weight=soh_weight*0.5
+                    else:
+                        if self.param.Capacity*0.65*0.7 < abs(ah_accum) < self.param.Capacity:
+                            soh_weight=soh_weight*0.5
+                        else:
+                            soh_weight=0
+                    if ah_accum_dis+ah_accum_chg>self.param.Capacity:
+                        soh_weight=soh_weight*0.6
+                    else:
+                        soh_weight=soh_weight
+
+                    cellsoh=[timepoint_bms_st, timepoint_bms_sp, self.sn]
+                    delt_ocv_soc=ocv_soc2-ocv_soc1
+                    delt_ocv_soc_weight=self._deltsoc_weight(abs(delt_ocv_soc))
+                    soh_weight=soh_weight*tempweightlist1[i]*delt_ocv_soc_weight*0.5
+                    cellsoh_init=ah_accum*100/((ocv_soc2-ocv_soc1)*0.01*self.param.Capacity)
+
+                    if cellsoh_init>65 and cellsoh_init<115:    #判断soh值的有效区间
+                        if len(df_res)<1:
+                            if not self.df_soh.empty and self.df_soh.shape[1]>10:
+                                cellsoh_cal=cellsoh_init*soh_weight + list(self.df_soh['soh'])[-1]*(1-soh_weight)
+                            else:
+                                cellsoh_cal=cellsoh_init
+                        else:
+                            if abs(cellsoh_init-df_res.iloc[-1]['soh'])<10:
+                                cellsoh_cal=cellsoh_init*soh_weight + df_res.iloc[-1]['soh']*(1-soh_weight)
+                            else:
+                                soh_weight=soh_weight*0.1
+                                cellsoh_cal=cellsoh_init*soh_weight + df_res.iloc[-1]['soh']*(1-soh_weight)
+
+                        cellsoh.append(1)
+                        cellsoh.append(cellsoh_cal)
+                        for j in range(20):    #计算每个电芯的SOH值
+                            cellsoh.append(cellsoh_cal)
+                        if len(df_res)<1:
+                            df_res.loc[0]=cellsoh
+                        else:
+                            df_res.loc[df_res.index.values[-1]+1]=cellsoh
+                    else:
+                        continue
+            else:
+                pass
+
+            if chrg_end:
+                for i in range(len(chrg_end)):
+                    cellvolt_max = self.df_bms['单体电压' + str(cellmaxvolt_number2[i]+1)] / 1000     #获取最大电压
+                    cellvolt=self.np_move_avg(cellvolt_max, 3, mode="same")     #对电压进行滑动平均滤波
+                    
+                    Ah = 0  #参数赋初始值
+                    Volt = cellvolt[chrg_start[i]]
+                    DV_Volt=[]
+                    DQ_Ah = []
+                    DVDQ = []
+                    time2 = []
+                    soc2 = []
+                    Ah_tatal=[0]
+                    xvolt=[]
+                    #计算DV和DQ值
+                    for j in range(chrg_start[i],chrg_end[i]):
+                        Step=(self.bmstime[j+1]-self.bmstime[j]).total_seconds()
+                        Ah=Ah-self.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(self.bmstime[j])
+                            soc2.append(self.bms_soc[j])
+
+                    #切片,去除前后10min的数据
+                    Data1 = pd.DataFrame({'time': time2,
+                                            'SOC': soc2,
+                                            'DVDQ': DVDQ,
+                                            'Ah_tatal': Ah_tatal[:-1],
+                                            'DQ_Ah':DQ_Ah,
+                                            'DV_Volt':DV_Volt,
+                                            'XVOLT':xvolt})
+                    start_time=Data1.loc[0,'time']
+                    start_time=start_time+datetime.timedelta(seconds=600)
+                    end_time=Data1.loc[len(time2)-1,'time']
+                    end_time=end_time-datetime.timedelta(seconds=1200)
+                    if soc2[0]<37:
+                        Data1=Data1[(Data1['SOC']>39) & (Data1['time']<end_time)]
+                    else:
+                        Data1=Data1[(Data1['time']>start_time) & (Data1['time']<end_time)]
+            
+                    # ax1 = plt.subplot(3, 1, 1)
+                    # plt.plot(Data1['XVOLT'],Data1['DVDQ'],'r*-')
+                    # ax1 = plt.subplot(3, 1, 2)
+                    # plt.plot(Data1['SOC'],Data1['XVOLT'],'y*-')
+                    # ax1 = plt.subplot(3, 1, 3)
+                    # plt.plot(Data1['SOC'], Data1['DVDQ'], 'r*-')
+                    # plt.show()
+
+                    #寻找峰值并计算Soh和置信度
+                    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]>40 and soc2[PeakIndex]<90:
+                                cellsoh_init=(Ah_tatal[-1]-Ah_tatal1[PeakIndex]) * 100 / ((self.param.FullChrgSoc - self.param.PeakSoc) * 0.01 * self.param.Capacity)
+                                if cellsoh_init<95:
+                                    cellsoh_init=cellsoh_init*0.3926+58.14
+                                else:
+                                    pass
+                            else:
+                                continue
+                        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) > 2:
+                                Ah_tatal1 = Data1['Ah_tatal']
+                                DVDQ = Data1['DVDQ']
+                                soc2 = Data1['SOC']
+                                xvolt = Data1['XVOLT']
+                                if soc2[PeakIndex]>40 and soc2[PeakIndex]<90:
+                                    cellsoh_init=(Ah_tatal[-1]-Ah_tatal1[PeakIndex]) * 100 / ((self.param.FullChrgSoc - self.param.PeakSoc) * 0.01 * self.param.Capacity)
+                                    if cellsoh_init<95:
+                                        cellsoh_init=cellsoh_init*0.3926+58.14
+                                    else:
+                                        pass
+                                else:
+                                    continue
+                            else:
+                                continue
+                        
+                        cellsoh=[self.bmstime[chrg_start[i]], self.bmstime[chrg_end[i]], self.sn]
+                        soh_weight=tempweightlist2[i]*0.5
+                        if cellsoh_init>65 and cellsoh_init<115:    #判断soh值的有效区间
+                            if len(df_res)<1:
+                                if not self.df_soh.empty and self.df_soh.shape[1]>10:
+                                    cellsoh_cal=cellsoh_init*soh_weight + list(self.df_soh['soh'])[-1]*(1-soh_weight)
+                                else:
+                                    cellsoh_cal=cellsoh_init
+                            else:
+                                if abs(cellsoh_init-df_res.iloc[-1]['soh'])<10:
+                                    cellsoh_cal=cellsoh_init*soh_weight + df_res.iloc[-1]['soh']*(1-soh_weight)
+                                else:
+                                    soh_weight=soh_weight*0.2
+                                    cellsoh_cal=cellsoh_init*soh_weight + df_res.iloc[-1]['soh']*(1-soh_weight)
+                            
+                            cellsoh.append(2)
+                            cellsoh.append(cellsoh_cal)
+                            for j in range(20):    #计算每个电芯的SOH值
+                                cellsoh.append(cellsoh_cal)
+                            if len(df_res)<1:
+                                df_res.loc[0]=cellsoh
+                            else:
+                                df_res.loc[df_res.index.values[-1]+1]=cellsoh
+                        else:
+                            continue
+                    else:
+                        continue
+            else:
+                pass
+
+            if df_res.empty:
+                return pd.DataFrame()
+            else:
+                return df_res
+        return pd.DataFrame()
+
+
+
+
+
+
+
+
+            
+                
+

+ 60 - 0
LIB/MIDDLE/CellStateEstimation/SOH/V1_0_0/DBDownload.py

@@ -0,0 +1,60 @@
+import pymysql
+import time
+import pandas as pd
+
+class DBDownload:
+
+    def __init__(self, host='', port='', db='', user='', password=''):
+        self.host = host
+        self.port = port
+        self.db = db
+        self.user = user
+        self.password = password
+        pass
+
+    def __enter__(self):
+        self.connect()
+        return self
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        self.close()
+
+    def connect(self):
+        conn_success_flag = 0
+        while not conn_success_flag:
+            try:
+                self.conn = pymysql.connect(host=self.host, port=self.port, user=self.user, password=self.password, database=self.db)
+            except Exception as e:
+                conn_success_flag = 0
+                print("数据库连接失败 :{}".format(e))
+                time.sleep(5)
+            else:
+                conn_success_flag = 1
+                print('数据库连接成功!')
+                self.cursor = self.conn.cursor()
+
+    def getdata(self,*param,tablename,st,sp):
+        print('数据获取中......')
+        param=list(param)
+        str=''
+        for i in range(len(param)):
+            if i<1:
+                str=str+param[i]
+            else:
+                str=str+','+param[i]
+        self.cursor.execute("select %s from %s where time between '%s' and '%s'" %(str,tablename,st,sp))
+        res = self.cursor.fetchall()
+        df_res = pd.DataFrame(res, columns=param)
+        df_res = df_res.reset_index(drop=True)
+        return(df_res)
+
+    def close(self):
+        try:
+            self.cursor.close()
+            self.conn.close()
+        except Exception as e:
+            print(e)
+        else:
+            print('数据库已断开连接!')
+    
+    

二进制
LIB/MIDDLE/CellStateEstimation/SOH/V1_0_0/SOH表单.xlsx


+ 24 - 0
LIB/MIDDLE/CellStateEstimation/SOH/V1_0_0/log.py

@@ -0,0 +1,24 @@
+import logging
+import traceback
+
+class Mylog:
+
+    def __init__(self,log_name,log_level):
+        self.name=log_name
+        self.level=log_level
+    
+    def logcfg(self):
+        if len(self.level) > 0:
+            if self.level == 'debug':
+                Level=logging.DEBUG
+            elif self.level == 'info':
+                Level=logging.INFO
+            elif self.level == 'warning':
+                Level=logging.WARNING
+            else:
+                Level=logging.ERROR
+        logging.basicConfig(filename=self.name, level=Level,format='%(asctime)s - %(levelname)s - %(message)s')
+
+    def logopt(self,*info):
+        logging.error(info)
+        logging.error(traceback.format_exc())

二进制
LIB/MIDDLE/CellStateEstimation/SOH/V1_0_0/骑享资产梳理-20210621.xlsx


+ 57 - 0
LIB/MIDDLE/CellStateEstimation/SOH/main.py

@@ -0,0 +1,57 @@
+import CloudBMSSoh
+import log
+
+#coding=utf-8
+import os
+import datetime
+import pandas as pd
+from LIB.BACKEND import DBManager, Log
+# from LIB.MIDDLE import SignalMonitor
+from sqlalchemy import create_engine
+from sqlalchemy.orm import sessionmaker
+import time, datetime
+from LIB.MIDDLE.soh import NCMSoh_20210716 as NCMSoh
+from LIB.MIDDLE.soh import LFPSoh_20210711 as LFPSoh
+
+from urllib import parse
+
+dbManager = DBManager.DBManager()
+if __name__ == "__main__":
+    SNdata_6040 = pd.read_excel('骑享资产梳理-20210621.xlsx', sheet_name='6040骑享')
+    SNdata_6060 = pd.read_excel('骑享资产梳理-20210621.xlsx', sheet_name='6060')
+    SNdata_4840 = pd.read_excel('骑享资产梳理-20210621.xlsx', sheet_name='4840骑享')
+    SNdata_7250 = pd.read_excel('骑享资产梳理-20210621.xlsx', sheet_name='7250')
+    SNnums_6060=SNdata_6060['SN号']
+    SNnums_6040=SNdata_6040['SN号']
+    SNnums_4840=SNdata_4840['SN号']
+    SNnums_7250=SNdata_7250['SN号']
+
+    SNnums=SNnums_6060.tolist()+SNnums_6040.tolist()+SNnums_4840.tolist()
+    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=30*36)
+    end_time=str(now_time)
+    start_time=str(start_time)
+
+    #log信息配置
+    mylog=log.Mylog('log.txt','error')
+    mylog.logcfg()
+
+    for sn in SNnums:
+        try:
+            dbManager = DBManager.DBManager()
+            df_data = dbManager.get_data(sn=sn, start_time=start_time, end_time=end_time, data_groups=['bms','accum'])
+            df_bms = df_data['bms']
+            df_accum=df_data['accum']
+            # df_bms.to_csv('BMS_'+sn+'.csv')
+            # df_accum.to_csv('BMS_accum_'+sn+'.csv')
+
+            Soh_cal=CloudBMSSoh.Soh(sn,df_bms,df_accum)
+            df_res=Soh_cal.soh()
+            df_res.to_csv('BMS_SOH_'+sn+'.csv',encoding='GB18030')
+        
+        
+        except IndexError as e:
+            print(repr(e))
+            mylog.logopt(sn,e)
+            pass

+ 28 - 0
LIB/MIDDLE/算法类别(模板)/算法名/V_1_0_0/core_algorithm.py

@@ -0,0 +1,28 @@
+import other_algorithm
+
+class Algo:
+
+     def __init__(self):
+          pass
+
+     # 算法内部调用的函数
+     def _fun1(self):
+          pass
+
+     # 算法内部调用的函数
+     def _fun2(self):
+          pass
+
+     # 算法对外提供的函数
+     def core_algorithm(self, data1, data2, param1, param2, ....):
+
+          #核心算法逻辑
+          _fun1();
+          _fun2();
+          data3 = other_algorithm(data1);
+          res1 = f(data1, data2, param1,...)
+          res2 = f(data1, data3, param2,...)
+
+          return [res1, res2]
+
+

+ 28 - 0
LIB/MIDDLE/算法类别(模板)/算法名/V_1_0_1/core_algorithm.py

@@ -0,0 +1,28 @@
+import other_algorithm
+
+class Algo:
+
+     def __init__(self):
+          pass
+
+     # 算法内部调用的函数
+     def _fun1(self):
+          pass
+
+     # 算法内部调用的函数
+     def _fun2(self):
+          pass
+
+     # 算法对外提供的函数
+     def core_algorithm(self, data1, data2, param1, param2, ....):
+
+          #核心算法逻辑
+          _fun1();
+          _fun2();
+          data3 = other_algorithm(data1);
+          res1 = f(data1, data2, param1,...)
+          res2 = f(data1, data3, param2,...)
+
+          return [res1, res2]
+
+

+ 38 - 0
LIB/MIDDLE/算法类别(模板)/算法名/main.py

@@ -0,0 +1,38 @@
+import get_data
+import get_data_by_sql
+import get_data_from_other_algorithm
+import data_process
+import core_algorithm
+
+# 数据库连接参数
+conn = connect(host, ......)
+# 准备算法输入参数
+parameter1 = * 
+parameter2 = *
+
+# 多次调用核心算法时,将循环写在外面
+for (i=1:n){
+     
+     # 获取数据
+     data1 = get_data(sn[i], start_time, end_time, ....) # 函数取数
+     data2 = get_data_by_sql(sn[i], start_time, end_time, ....) # sql 语句直接数据库取数
+     data3 = get_data_from_other_algorithm(data1, parameter1, ....)  # 调用其他人的算法得到数据
+
+     # 通用数据预处理 (可选,由算法说明文档说明算法输入数据是否需要预处理)
+     data1 = data_process(data1)
+     data2 = data_process(data2)
+     
+     # 调用核心算法
+     [res1, res2] = core_algorithm(data1, data2, data3, parameter1, parameter2, ....)
+
+     # 使用结果
+     res1 = res1.append(res)
+     res1.to_csv(...)
+     res1.to_sql(...)
+}
+
+# 批量使用结果
+res.to_csv(...)
+res1.to_sql(...)
+
+

+ 28 - 0
LIB/MIDDLE/算法类别(模板)/算法名2/V_1_0_0/core_algorithm.py

@@ -0,0 +1,28 @@
+import other_algorithm
+
+class Algo:
+
+     def __init__(self):
+          pass
+
+     # 算法内部调用的函数
+     def _fun1(self):
+          pass
+
+     # 算法内部调用的函数
+     def _fun2(self):
+          pass
+
+     # 算法对外提供的函数
+     def core_algorithm(self, data1, data2, param1, param2, ....):
+
+          #核心算法逻辑
+          _fun1();
+          _fun2();
+          data3 = other_algorithm(data1);
+          res1 = f(data1, data2, param1,...)
+          res2 = f(data1, data3, param2,...)
+
+          return [res1, res2]
+
+

+ 28 - 0
LIB/MIDDLE/算法类别(模板)/算法名2/V_1_0_1/core_algorithm.py

@@ -0,0 +1,28 @@
+import other_algorithm
+
+class Algo:
+
+     def __init__(self):
+          pass
+
+     # 算法内部调用的函数
+     def _fun1(self):
+          pass
+
+     # 算法内部调用的函数
+     def _fun2(self):
+          pass
+
+     # 算法对外提供的函数
+     def core_algorithm(self, data1, data2, param1, param2, ....):
+
+          #核心算法逻辑
+          _fun1();
+          _fun2();
+          data3 = other_algorithm(data1);
+          res1 = f(data1, data2, param1,...)
+          res2 = f(data1, data3, param2,...)
+
+          return [res1, res2]
+
+

+ 38 - 0
LIB/MIDDLE/算法类别(模板)/算法名2/main.py

@@ -0,0 +1,38 @@
+import get_data
+import get_data_by_sql
+import get_data_from_other_algorithm
+import data_process
+import core_algorithm
+
+# 数据库连接参数
+conn = connect(host, ......)
+# 准备算法输入参数
+parameter1 = * 
+parameter2 = *
+
+# 多次调用核心算法时,将循环写在外面
+for (i=1:n){
+     
+     # 获取数据
+     data1 = get_data(sn[i], start_time, end_time, ....) # 函数取数
+     data2 = get_data_by_sql(sn[i], start_time, end_time, ....) # sql 语句直接数据库取数
+     data3 = get_data_from_other_algorithm(data1, parameter1, ....)  # 调用其他人的算法得到数据
+
+     # 通用数据预处理 (可选,由算法说明文档说明算法输入数据是否需要预处理)
+     data1 = data_process(data1)
+     data2 = data_process(data2)
+     
+     # 调用核心算法
+     [res1, res2] = core_algorithm(data1, data2, data3, parameter1, parameter2, ....)
+
+     # 使用结果
+     res1 = res1.append(res)
+     res1.to_csv(...)
+     res1.to_sql(...)
+}
+
+# 批量使用结果
+res.to_csv(...)
+res1.to_sql(...)
+
+

+ 1 - 1
demo.py

@@ -1,3 +1,3 @@
 from LIB.BACKEND import DBManager, Log
 log = Log.Mylog(log_name='signal_monitor', log_level = 'info')
-log.set_file_hl(file_name='log/info.log', log_level='info', size=1024* 1024 * 100)
+log.set_file_hl(file_name='log/info.log', log_level='info', size=1024* 1024 * 100)